Xiaomi H1 Wired Double Rocker Switch With Neutral

Added quirk for Xiaomi H1 double rocker switche with neutral (n2aeu1)

One more thing, if anyone wants to test this: my working environment is based on the ZCLv7 update from puddly. There might be an issue with OppleCluster.attributes vs OppleCluster.manufacturer_attributes

Pull Request Test Coverage Report for Build<PHONE_NUMBER>

34 of 41 (82.93%)  changed or added relevant lines in 1 file are covered.
No unchanged relevant lines lost coverage.
Overall coverage increased (+0.01%) to 81.073%

Changes Missing Coverage
Covered Lines
Changed/Added Lines
%

zhaquirks/xiaomi/aqara/d1.py
34
41
82.93%

Totals

Change from base Build<PHONE_NUMBER>:
0.01%

Covered Lines:
4973

Relevant Lines:
6134

💛  - Coveralls

Codecov Report

Merging #1391 (d9e77f4) into dev (f9e25f4) will decrease coverage by 0.02%.
The diff coverage is 77.27%.

@@            Coverage Diff             @@
##              dev    #1391      +/-   ##
==========================================
- Coverage   81.06%   81.03%   -0.03%
==========================================
  Files         218      219       +1
  Lines        6093     6137      +44
==========================================
+ Hits         4939     4973      +34
- Misses       1154     1164      +10

Impacted Files
Coverage Δ

zhaquirks/xiaomi/aqara/d1.py
77.27% <77.27%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update f9e25f4...d9e77f4. Read the comment docs.

I have several H1 one-button WS-EUK03 lumi.switch.n1aeu1 switches, is there anything I can do to help?

Hi! Thanks for offering your help!
Could you send me the device descriptor of your switches?

Hi, I am new to world of HA and ZHA. I bought Aqara WS-EUK04. Temperature and electric doesn't work. So I have found you quirk - now I am stuck with this:
2022-05-02 17:19:16 DEBUG (MainThread) [zigpy.application] Device is initialized <Device model='lumi.switch.n2aeu1' manuf='LUMI' nwk=0x1F3F ieee=54:ef:44:10:00:36:48:53 is_initialized=True>
2022-05-02 17:19:16 DEBUG (MainThread) [zigpy.quirks.registry] Checking quirks for LUMI lumi.switch.n2aeu1 (54:ef:44:10:00:36:48:53)
2022-05-02 17:19:16 DEBUG (MainThread) [zigpy.quirks.registry] Considering <class 'opple_switch.XiaomiOpple2ButtonSwitch'>
2022-05-02 17:19:16 DEBUG (MainThread) [zigpy.quirks.registry] Fail because endpoint list mismatch: {1, 2, 41, 42, 242, 51, 21, 31} {1, 2, 242}
2022-05-02 17:19:16 DEBUG (MainThread) [zigpy.quirks.registry] Considering <class 'opple_switch.XiaomiOpple3ButtonSwitch'>
2022-05-02 17:19:16 DEBUG (MainThread) [zigpy.quirks.registry] Fail because endpoint list mismatch: {1, 2, 3, 41, 42, 43, 242, 51, 52, 21, 53, 61, 31} {1, 2, 242}

Any advice?

It seems like Xiaomi devices change their type when they are re-joined. Maybe try removing and re-joining the device a few times and check if the entities that are discovered change.
Mine for example only have the electric measurements every other time. Also sometimes they are switches sometimes lights I believe.

No luck - logs shows the same error, so I am trying to provide some useful info.
"data": {     "ieee": "**REDACTED**",     "nwk": 2824,     "manufacturer": "LUMI",     "model": "lumi.switch.n2aeu1",     "name": "LUMI lumi.switch.n2aeu1",     "quirk_applied": false,     "quirk_class": "zigpy.device.Device",     "manufacturer_code": 4447,     "power_source": "Mains",     "lqi": 100,     "rssi": -75,     "last_seen": "2022-05-02T18:23:49",     "available": true,     "device_type": "Router",     "signature": {       "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress|RxOnWhenIdle|MainsPowered|FullFunctionDevice: 142>, manufacturer_code=4447, maximum_buffer_size=127, maximum_incoming_transfer_size=100, server_mask=11264, maximum_outgoing_transfer_size=100, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)",       "endpoints": {         "1": {           "profile_id": 260,           "device_type": "0x0100",           "in_clusters": [             "0x0000",             "0x0002",             "0x0003",             "0x0004",             "0x0005",             "0x0006",             "0x0009",             "0x0702",             "0x0b04"           ],           "out_clusters": [             "0x000a",             "0x0019"           ]         },         "2": {           "profile_id": 260,           "device_type": "0x0100",           "in_clusters": [             "0x0000",             "0x0003",             "0x0004",             "0x0005",             "0x0006",             "0x0012",             "0xfcc0"           ],           "out_clusters": []         },         "242": {           "profile_id": 41440,           "device_type": "0x0061",           "in_clusters": [],           "out_clusters": [             "0x0021"           ]         }       }     }

You alwas get the same 3 clusters?
Does it make a difference if you reset it on the device or click "remove device" on the device page?

If clusters means keys in endpoints ("1", "2", "242") - yes they are always the same

Yes, sorry, that is what I meant. Do you have debugging turned on for zigpy? My best guess is that some of the endpoints somewhere get lost because they do not get matched or so. Maybe there ist just a slight difference in the actual device descriptor. Also what software versions are you using?

Debugging turned on - unfortunately I dont know what should I look for....
2022-05-02 20:32:39 DEBUG (MainThread) [zigpy.appdb] Error handling '_save_attribute' event with (54:ef:44:10:00:36:48:53, 1, 0, 4, 'LUMI') params: FOREIGN KEY constraint failed
I can provide full log if you want.
{
  "home_assistant": {
    "installation_type": "Home Assistant OS",
    "version": "2022.4.7",
    "dev": false,
    "hassio": true,
    "virtualenv": false,
    "python_version": "3.9.9",
    "docker": true,
    "arch": "x86_64",
    "timezone": "Europe/Prague",
    "os_name": "Linux",
    "os_version": "5.10.108",
    "supervisor": "2022.04.0",
    "host_os": "Home Assistant OS 7.6",
    "docker_version": "20.10.9",
    "chassis": "vm",
    "run_as_root": true
  },
  "custom_components": {},
  "integration_manifest": {
    "domain": "zha",
    "name": "Zigbee Home Automation",
    "config_flow": true,
    "documentation": "https://www.home-assistant.io/integrations/zha",
    "requirements": [
      "bellows==0.29.0",
      "pyserial==3.5",
      "pyserial-asyncio==0.6",
      "zha-quirks==0.0.72",
      "zigpy-deconz==0.14.0",
      "zigpy==0.44.2",
      "zigpy-xbee==0.14.0",
      "zigpy-zigate==0.7.4",
      "zigpy-znp==0.7.0"
    ],
    "usb": [
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*2652*",
        "known_devices": [
          "slae.sh cc2652rb stick"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*sonoff*plus*",
        "known_devices": [
          "sonoff zigbee dongle plus"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*tubeszb*",
        "known_devices": [
          "TubesZB Coordinator"
        ]
      },
      {
        "vid": "1A86",
        "pid": "7523",
        "description": "*tubeszb*",
        "known_devices": [
          "TubesZB Coordinator"
        ]
      },
      {
        "vid": "1A86",
        "pid": "7523",
        "description": "*zigstar*",
        "known_devices": [
          "ZigStar Coordinators"
        ]
      },
      {
        "vid": "1CF1",
        "pid": "0030",
        "description": "*conbee*",
        "known_devices": [
          "Conbee II"
        ]
      },
      {
        "vid": "10C4",
        "pid": "8A2A",
        "description": "*zigbee*",
        "known_devices": [
          "Nortek HUSBZB-1"
        ]
      },
      {
        "vid": "10C4",
        "pid": "8B34",
        "description": "*bv 2010/10*",
        "known_devices": [
          "Bitron Video AV2010/10"
        ]
      }
    ],
    "codeowners": [
      "@dmulcahey",
      "@adminiuga"
    ],
    "zeroconf": [
      {
        "type": "_esphomelib._tcp.local.",
        "name": "tube*"
      }
    ],
    "after_dependencies": [
      "usb",
      "zeroconf"
    ],
    "iot_class": "local_polling",
    "loggers": [
      "aiosqlite",
      "bellows",
      "crccheck",
      "pure_pcapy3",
      "zhaquirks",
      "zigpy",
      "zigpy_deconz",
      "zigpy_xbee",
      "zigpy_zigate",
      "zigpy_znp"
    ],
    "is_built_in": true
  },
  "data": {
    "ieee": "**REDACTED**",
    "nwk": 2824,
    "manufacturer": "LUMI",
    "model": "lumi.switch.n2aeu1",
    "name": "LUMI lumi.switch.n2aeu1",
    "quirk_applied": false,
    "quirk_class": "zigpy.device.Device",
    "manufacturer_code": 4447,
    "power_source": "Mains",
    "lqi": 100,
    "rssi": -75,
    "last_seen": "2022-05-02T18:23:49",
    "available": true,
    "device_type": "Router",
    "signature": {
      "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress|RxOnWhenIdle|MainsPowered|FullFunctionDevice: 142>, manufacturer_code=4447, maximum_buffer_size=127, maximum_incoming_transfer_size=100, server_mask=11264, maximum_outgoing_transfer_size=100, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)",
      "endpoints": {
        "1": {
          "profile_id": 260,
          "device_type": "0x0100",
          "in_clusters": [
            "0x0000",
            "0x0002",
            "0x0003",
            "0x0004",
            "0x0005",
            "0x0006",
            "0x0009",
            "0x0702",
            "0x0b04"
          ],
          "out_clusters": [
            "0x000a",
            "0x0019"
          ]
        },
        "2": {
          "profile_id": 260,
          "device_type": "0x0100",
          "in_clusters": [
            "0x0000",
            "0x0003",
            "0x0004",
            "0x0005",
            "0x0006",
            "0x0012",
            "0xfcc0"
          ],
          "out_clusters": []
        },
        "242": {
          "profile_id": 41440,
          "device_type": "0x0061",
          "in_clusters": [],
          "out_clusters": [
            "0x0021"
          ]
        }
      }
    },
    "entities": [
      {
        "entity_id": "sensor.lumi_lumi_switch_n2aeu1_53483600_electrical_measurement",
        "name": "LUMI lumi.switch.n2aeu1"
      },
      {
        "entity_id": "sensor.lumi_lumi_switch_n2aeu1_53483600_smartenergy_metering_summation_delivered",
        "name": "LUMI lumi.switch.n2aeu1"
      },
      {
        "entity_id": "sensor.lumi_lumi_switch_n2aeu1_53483600_device_temperature",
        "name": "LUMI lumi.switch.n2aeu1"
      },
      {
        "entity_id": "button.lumi_lumi_switch_n2aeu1_53483600_identify",
        "name": "LUMI lumi.switch.n2aeu1"
      },
      {
        "entity_id": "light.lumi_lumi_switch_n2aeu1_53483600_on_off",
        "name": "LUMI lumi.switch.n2aeu1"
      },
      {
        "entity_id": "light.lumi_lumi_switch_n2aeu1_53483600_on_off_2",
        "name": "LUMI lumi.switch.n2aeu1"
      }
    ],
    "neighbors": [],
    "endpoint_names": [
      {
        "name": "ON_OFF_LIGHT"
      },
      {
        "name": "ON_OFF_LIGHT"
      },
      {
        "name": "unknown 97 device_type of 0xa1e0 profile id"
      }
    ],
    "user_given_name": null,
    "device_reg_id": "5b25e9c57b587746227f68578ef537ff",
    "area_id": "obyvak"
  }
}

I'm seeing similar results from my n1aeu1 (the one button version of the same switch):
lumi.switch.n1aeu1 pairing log.txt
config_entry-zha-ae2ff7273e2c33dc8e1309fc9adb9a93.json.txt

Two things:

The quirk is only for the 2 button switch. I was unable to get a device descriptor of a one button switch so far.
I see you have the ConBee II and am not sure if this might make a difference.

Could you send the same log for your two button device? I have a bunch of those working so I believe it should be easier to get those started

Two things:

The quirk is only for the 2 button switch. I was unable to get a device descriptor of a one button switch so far.
I see you have the ConBee II and am not sure if this might make a difference.

Could you send the same log for your two button device? I have a bunch of those working so I believe it should be easier to get those started

How do I get the device descriptor?

It is in the logs. If you send me the same log you sent for the 1 button join but for the two button switch it should be in thete

It is in the logs. If you send me the same log you sent for the 1 button join but for the two button switch it should be in thete

Oh sorry, I thought you were saying you still needed one for the 1 button.

I have no idea if device descriptor is in there
2022-05-03 16:05:00 DEBUG (MainThread) [bellows.zigbee.application] Received incomingMessageHandler frame with [<EmberIncomingMessageType.INCOMING_UNICAST: 0>, EmberApsFrame(profileId=260, clusterId=0, sourceEndpoint=1, destinationEndpoint=1, options=<EmberApsOption.APS_OPTION_ENABLE_ROUTE_DISCOVERY: 256>, groupId=0, sequence=19), 152, -62, 0x811c, 255, 255, b'\x18\x13\x01\x04\x00\x00B\x04LUMI\x05\x00\x00B\x12lumi.switch.n2aeu1']
2022-05-03 16:05:00 DEBUG (MainThread) [zigpy.zcl] [0x811C:1:0x0000] Received ZCL frame: b'\x18\x13\x01\x04\x00\x00B\x04LUMI\x05\x00\x00B\x12lumi.switch.n2aeu1'
2022-05-03 16:05:00 DEBUG (MainThread) [zigpy.zcl] [0x811C:1:0x0000] Decoded ZCL frame: Basic:Read_Attributes_rsp(status_records=[ReadAttributeRecord(attrid=0x0004, status=<Status.SUCCESS: 0>, value=TypeValue(type=CharacterString, value='LUMI')), ReadAttributeRecord(attrid=0x0005, status=<Status.SUCCESS: 0>, value=TypeValue(type=CharacterString, value='lumi.switch.n2aeu1'))])
2022-05-03 16:05:00 DEBUG (MainThread) [bellows.zigbee.application] Received incomingMessageHandler frame with [<EmberIncomingMessageType.INCOMING_UNICAST: 0>, EmberApsFrame(profileId=260, clusterId=0, sourceEndpoint=1, destinationEndpoint=1, options=<EmberApsOption.APS_OPTION_ENABLE_ROUTE_DISCOVERY: 256>, groupId=0, sequence=20), 116, -71, 0x811c, 255, 255, b'\x18\x15\x01\x04\x00\x00B\x04LUMI\x05\x00\x00B\x12lumi.switch.n2aeu1']
2022-05-03 16:05:00 DEBUG (MainThread) [zigpy.zcl] [0x811C:1:0x0000] Received ZCL frame: b'\x18\x15\x01\x04\x00\x00B\x04LUMI\x05\x00\x00B\x12lumi.switch.n2aeu1'
2022-05-03 16:05:00 DEBUG (MainThread) [zigpy.zcl] [0x811C:1:0x0000] Decoded ZCL frame: Basic:Read_Attributes_rsp(status_records=[ReadAttributeRecord(attrid=0x0004, status=<Status.SUCCESS: 0>, value=TypeValue(type=CharacterString, value='LUMI')), ReadAttributeRecord(attrid=0x0005, status=<Status.SUCCESS: 0>, value=TypeValue(type=CharacterString, value='lumi.switch.n2aeu1'))])
2022-05-03 16:05:00 DEBUG (MainThread) [homeassistant.components.websocket_api.http.connection] [140003618063696] Sending {"id":98,"type":"event","event":{"type":"log_output","log_entry":{"name":"zigpy.zcl","message":["[0x811C:1:0x0000] Received ZCL frame: b'\\x18\\x13\\x01\\x04\\x00\\x00B\\x04LUMI\\x05\\x00\\x00B\\x12lumi.switch.n2aeu1'"],"level":"DEBUG","source":["/usr/local/lib/python3.9/site-packages/zigpy/zcl/__init__.py",217],"timestamp":1651586700.562102,"exception":"","count":1,"first_occurred":1651586700.562102}}}
2022-05-03 16:05:00 DEBUG (MainThread) [homeassistant.components.websocket_api.http.connection] [140003618063696] Sending {"id":98,"type":"event","event":{"type":"log_output","log_entry":{"name":"zigpy.zcl","message":["[0x811C:1:0x0000] Decoded ZCL frame: Basic:Read_Attributes_rsp(status_records=[ReadAttributeRecord(attrid=0x0004, status=<Status.SUCCESS: 0>, value=TypeValue(type=CharacterString, value='LUMI')), ReadAttributeRecord(attrid=0x0005, status=<Status.SUCCESS: 0>, value=TypeValue(type=CharacterString, value='lumi.switch.n2aeu1'))])"],"level":"DEBUG","source":["/usr/local/lib/python3.9/site-packages/zigpy/zcl/__init__.py",245],"timestamp":1651586700.5645945,"exception":"","count":1,"first_occurred":1651586700.5645945}}}
2022-05-03 16:05:00 DEBUG (MainThread) [homeassistant.components.websocket_api.http.connection] [140003618063696] Sending {"id":98,"type":"event","event":{"type":"log_output","log_entry":{"name":"zigpy.zcl","message":["[0x811C:1:0x0000] Received ZCL frame: b'\\x18\\x15\\x01\\x04\\x00\\x00B\\x04LUMI\\x05\\x00\\x00B\\x12lumi.switch.n2aeu1'"],"level":"DEBUG","source":["/usr/local/lib/python3.9/site-packages/zigpy/zcl/__init__.py",217],"timestamp":1651586700.5685225,"exception":"","count":1,"first_occurred":1651586700.5685225}}}
2022-05-03 16:05:00 DEBUG (MainThread) [homeassistant.components.websocket_api.http.connection] [140003618063696] Sending {"id":98,"type":"event","event":{"type":"log_output","log_entry":{"name":"zigpy.zcl","message":["[0x811C:1:0x0000] Decoded ZCL frame: Basic:Read_Attributes_rsp(status_records=[ReadAttributeRecord(attrid=0x0004, status=<Status.SUCCESS: 0>, value=TypeValue(type=CharacterString, value='LUMI')), ReadAttributeRecord(attrid=0x0005, status=<Status.SUCCESS: 0>, value=TypeValue(type=CharacterString, value='lumi.switch.n2aeu1'))])"],"level":"DEBUG","source":["/usr/local/lib/python3.9/site-packages/zigpy/zcl/__init__.py",245],"timestamp":1651586700.5705557,"exception":"","count":1,"first_occurred":1651586700.5705557}}}
2022-05-03 16:05:00 INFO (MainThread) [zigpy.device] [0x811c] Read model 'lumi.switch.n2aeu1' and manufacturer 'LUMI' from <Endpoint id=1 in=[basic:0x0000, device_temperature:0x0002, identify:0x0003, groups:0x0004, scenes:0x0005, on_off:0x0006, alarms:0x0009, smartenergy_metering:0x0702, electrical_measurement:0x0B04] out=[time:0x000A, ota:0x0019] status=<Status.ZDO_INIT: 1>>
2022-05-03 16:05:00 INFO (MainThread) [zigpy.device] [0x811c] Discovered basic device information for <Device model='lumi.switch.n2aeu1' manuf='LUMI' nwk=0x811C ieee=54:ef:44:10:00:36:48:53 is_initialized=True>
2022-05-03 16:05:00 DEBUG (MainThread) [zigpy.application] Device is initialized <Device model='lumi.switch.n2aeu1' manuf='LUMI' nwk=0x811C ieee=54:ef:44:10:00:36:48:53 is_initialized=True>
2022-05-03 16:05:00 DEBUG (MainThread) [zigpy.quirks.registry] Checking quirks for LUMI lumi.switch.n2aeu1 (54:ef:44:10:00:36:48:53)
2022-05-03 16:05:00 DEBUG (Thread-4) [aiosqlite] executing functools.partial(<built-in method execute of sqlite3.Connection object at 0x7f551f761d50>, 'INSERT INTO attributes_cache_v7 VALUES (?, ?, ?, ?, ?)\n ON CONFLICT (ieee, endpoint_id, cluster, attrid)\n DO UPDATE SET\n value=excluded.value', (54:ef:44:10:00:36:48:53, 1, 0, 4, 'LUMI'))
2022-05-03 16:05:00 DEBUG (MainThread) [homeassistant.components.zha.core.device] [0x811C](lumi.switch.n2aeu1): started configuration
2022-05-03 16:05:00 DEBUG (MainThread) [homeassistant.components.zha.core.channels.base] [0x811C:ZDO](lumi.switch.n2aeu1): 'async_configure' stage succeeded
2022-05-03 16:05:00 DEBUG (MainThread) [homeassistant.components.websocket_api.http.connection] [140003618063696] Sending {"id":98,"type":"event","event":{"type":"log_output","log_entry":{"name":"zigpy.device","message":["[0x811c] Read model 'lumi.switch.n2aeu1' and manufacturer 'LUMI' from <Endpoint id=1 in=[basic:0x0000, device_temperature:0x0002, identify:0x0003, groups:0x0004, scenes:0x0005, on_off:0x0006, alarms:0x0009, smartenergy_metering:0x0702, electrical_measurement:0x0B04] out=[time:0x000A, ota:0x0019] status=<Status.ZDO_INIT: 1>>"],"level":"INFO","source":["/usr/local/lib/python3.9/site-packages/zigpy/device.py",225],"timestamp":1651586700.5776188,"exception":"","count":1,"first_occurred":1651586700.5776188}}}
2022-05-03 16:05:00 DEBUG (MainThread) [homeassistant.components.websocket_api.http.connection] [140003618063696] Sending {"id":98,"type":"event","event":{"type":"log_output","log_entry":{"name":"zigpy.device","message":["[0x811c] Discovered basic device information for <Device model='lumi.switch.n2aeu1' manuf='LUMI' nwk=0x811C ieee=54:ef:44:10:00:36:48:53 is_initialized=True>"],"level":"INFO","source":["/usr/local/lib/python3.9/site-packages/zigpy/device.py",240],"timestamp":1651586700.578121,"exception":"","count":1,"first_occurred":1651586700.578121}}}
2022-05-03 16:05:00 DEBUG (MainThread) [homeassistant.components.websocket_api.http.connection] [140003618063696] Sending {"id":98,"type":"event","event":{"type":"log_output","log_entry":{"name":"zigpy.application","message":["Device is initialized <Device model='lumi.switch.n2aeu1' manuf='LUMI' nwk=0x811C ieee=54:ef:44:10:00:36:48:53 is_initialized=True>"],"level":"DEBUG","source":["/usr/local/lib/python3.9/site-packages/zigpy/application.py",134],"timestamp":1651586700.5784872,"exception":"","count":1,"first_occurred":1651586700.5784872}}}
2022-05-03 16:05:00 DEBUG (MainThread) [homeassistant.components.websocket_api.http.connection] [140003618063696] Sending {"id":98,"type":"event","event":{"type":"raw_device_initialized","device_info":{"nwk":33052,"ieee":"54:ef:44:10:00:36:48:53","pairing_status":"INTERVIEW_COMPLETE","model":"lumi.switch.n2aeu1","manufacturer":"LUMI","signature":{"manufacturer":"LUMI","model":"lumi.switch.n2aeu1","node_desc":{"logical_type":1,"complex_descriptor_available":0,"user_descriptor_available":0,"reserved":0,"aps_flags":0,"frequency_band":8,"mac_capability_flags":142,"manufacturer_code":4447,"maximum_buffer_size":127,"maximum_incoming_transfer_size":100,"server_mask":11264,"maximum_outgoing_transfer_size":100,"descriptor_capability_field":0},"endpoints":{"1":{"profile_id":260,"device_type":256,"input_clusters":[0,2,3,4,5,6,9,1794,2820],"output_clusters":[10,25]},"2":{"profile_id":260,"device_type":256,"input_clusters":[0,3,4,5,6,18,64704],"output_clusters":[]},"242":{"profile_id":41440,"device_type":97,"input_clusters":[],"output_clusters":[33]}}}}}}
2022-05-03 16:05:00 DEBUG (MainThread) [homeassistant.components.websocket_api.http.connection] [140003618063696] Sending {"id":98,"type":"event","event":{"type":"log_output","log_entry":{"name":"zigpy.quirks.registry","message":["Checking quirks for LUMI lumi.switch.n2aeu1 (54:ef:44:10:00:36:48:53)"],"level":"DEBUG","source":["/usr/local/lib/python3.9/site-packages/zigpy/quirks/registry.py",59],"timestamp":1651586700.579955,"exception":"","count":1,"first_occurred":1651586700.579955}}}
2022-05-03 16:05:00 INFO (MainThread) [zigpy.device] [0x811c] Read model 'lumi.switch.n2aeu1' and manufacturer 'LUMI' from <Endpoint id=1 in=[basic:0x0000, device_temperature:0x0002, identify:0x0003, groups:0x0004, scenes:0x0005, on_off:0x0006, alarms:0x0009, smartenergy_metering:0x0702, electrical_measurement:0x0B04] out=[time:0x000A, ota:0x0019] status=<Status.ZDO_INIT: 1>>
2022-05-03 16:05:00 INFO (MainThread) [zigpy.device] [0x811c] Discovered basic device information for <Device model='lumi.switch.n2aeu1' manuf='LUMI' nwk=0x811C ieee=54:ef:44:10:00:36:48:53 is_initialized=True>
2022-05-03 16:05:00 DEBUG (MainThread) [zigpy.application] Device is initialized <Device model='lumi.switch.n2aeu1' manuf='LUMI' nwk=0x811C ieee=54:ef:44:10:00:36:48:53 is_initialized=True>
2022-05-03 16:05:00 DEBUG (MainThread) [zigpy.quirks.registry] Checking quirks for LUMI lumi.switch.n2aeu1 (54:ef:44:10:00:36:48:53)

I have no idea why your device looks so differently..
Could you send me a debug log while pressing a few buttons? Maybe I can recognize a pattern

Log should include turning on and off one button with few seconds delay
2022-05-07 11:22:11 DEBUG (bellows.thread_0) [bellows.uart] Sending: b'83401b7e'
2022-05-07 11:22:11 DEBUG (MainThread) [bellows.ezsp.protocol] Application frame 241 (readCounters) received: b'1d000c001a000a000000000000000000100008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
2022-05-07 11:22:11 DEBUG (MainThread) [bellows.ezsp.protocol] Send command getValue: (<EzspValueId.VALUE_FREE_BUFFERS: 3>,)
2022-05-07 11:22:11 DEBUG (bellows.thread_0) [bellows.uart] Sending: b'7d338a21a9fe2a1694787e'
2022-05-07 11:22:11 DEBUG (bellows.thread_0) [bellows.uart] Data frame: b'328aa1a9fe2a15b3abda197e'
2022-05-07 11:22:11 DEBUG (bellows.thread_0) [bellows.uart] Sending: b'8430fc7e'
2022-05-07 11:22:11 DEBUG (MainThread) [bellows.ezsp.protocol] Application frame 170 (getValue) received: b'0001f2'
2022-05-07 11:22:11 DEBUG (MainThread) [bellows.zigbee.application] Free buffers status EzspStatus.SUCCESS, value: 242
2022-05-07 11:22:11 DEBUG (MainThread) [bellows.zigbee.application] ezsp_counters: [MAC_RX_BROADCAST = 854, MAC_TX_BROADCAST = 516, MAC_RX_UNICAST = 1524, MAC_TX_UNICAST_SUCCESS = 756, MAC_TX_UNICAST_RETRY = 64, MAC_TX_UNICAST_FAILED = 2, APS_DATA_RX_BROADCAST = 7, APS_DATA_TX_BROADCAST = 7, APS_DATA_RX_UNICAST = 437, APS_DATA_TX_UNICAST_SUCCESS = 365, APS_DATA_TX_UNICAST_RETRY = 13, APS_DATA_TX_UNICAST_FAILED = 3, ROUTE_DISCOVERY_INITIATED = 6, NEIGHBOR_ADDED = 2, NEIGHBOR_REMOVED = 0, NEIGHBOR_STALE = 3, JOIN_INDICATION = 0, CHILD_REMOVED = 0, ASH_OVERFLOW_ERROR = 0, ASH_FRAMING_ERROR = 0, ASH_OVERRUN_ERROR = 0, NWK_FRAME_COUNTER_FAILURE = 0, APS_FRAME_COUNTER_FAILURE = 0, UTILITY = 0, APS_LINK_KEY_NOT_AUTHORIZED = 0, NWK_DECRYPTION_FAILURE = 0, APS_DECRYPTION_FAILURE = 0, ALLOCATE_PACKET_BUFFER_FAILURE = 0, RELAYED_UNICAST = 0, PHY_TO_MAC_QUEUE_LIMIT_REACHED = 0, PACKET_VALIDATE_LIBRARY_DROPPED_COUNT = 0, TYPE_NWK_RETRY_OVERFLOW = 0, PHY_CCA_FAIL_COUNT = 0, BROADCAST_TABLE_FULL = 0, PTA_LO_PRI_REQUESTED = 0, PTA_HI_PRI_REQUESTED = 0, PTA_LO_PRI_DENIED = 0, PTA_HI_PRI_DENIED = 0, PTA_LO_PRI_TX_ABORTED = 0, PTA_HI_PRI_TX_ABORTED = 0, ADDRESS_CONFLICT_SENT = 0, EZSP_FREE_BUFFERS = 242]
2022-05-07 11:22:18 DEBUG (bellows.thread_0) [bellows.uart] Data frame: b'428ab1a9112a15b658984a30ab5593499c3f5b10f14f9874f1da3c9807746aa7d2cdde6f8ffd72db7e'
2022-05-07 11:22:18 DEBUG (bellows.thread_0) [bellows.uart] Sending: b'8520dd7e'
2022-05-07 11:22:18 DEBUG (MainThread) [bellows.ezsp.protocol] Application frame 69 (incomingMessageHandler) received: b'0004010c00150100010000717cbb1c81ffff0c1c5f11fb0a5500390000000002'
2022-05-07 11:22:18 DEBUG (MainThread) [bellows.zigbee.application] Received incomingMessageHandler frame with [<EmberIncomingMessageType.INCOMING_UNICAST: 0>, EmberApsFrame(profileId=260, clusterId=12, sourceEndpoint=21, destinationEndpoint=1, options=<EmberApsOption.APS_OPTION_ENABLE_ROUTE_DISCOVERY: 256>, groupId=0, sequence=113), 124, -69, 0x811c, 255, 255, b'\x1c_\x11\xfb\nU\x009\x00\x00\x00\x00']
2022-05-07 11:22:18 DEBUG (MainThread) [zigpy.device] Ignoring message (b'1c5f11fb0a55003900000000') on cluster 12: unknown endpoint or cluster id: 21
2022-05-07 11:22:21 DEBUG (MainThread) [bellows.ezsp.protocol] Send command readCounters: ()
2022-05-07 11:22:21 DEBUG (bellows.thread_0) [bellows.uart] Sending: b'258b21a9a52ab3627e'
2022-05-07 11:22:21 DEBUG (bellows.thread_0) [bellows.uart] Data frame: b'538ba1a9a52a0bb254945125a05592499c4e27abedce768bf5c66389fc7e3fa7ebcdde6f8fffc7dbd5d2698c4623a9ec763ba5ea758241984c2613b1e070381c0e07bbe5ca658a459a4d9e4f9ff7c3d9d46a35a25190482486537e'
2022-05-07 11:22:21 DEBUG (bellows.thread_0) [bellows.uart] Sending: b'8610be7e'
2022-05-07 11:22:21 DEBUG (MainThread) [bellows.ezsp.protocol] Application frame 241 (readCounters) received: b'1e000d001b000a000000000000000000110008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
2022-05-07 11:22:21 DEBUG (MainThread) [bellows.ezsp.protocol] Send command getValue: (<EzspValueId.VALUE_FREE_BUFFERS: 3>,)
2022-05-07 11:22:21 DEBUG (bellows.thread_0) [bellows.uart] Sending: b'368821a9fe2a1608697e'
2022-05-07 11:22:21 DEBUG (bellows.thread_0) [bellows.uart] Data frame: b'6488a1a9fe2a15b3ab03107e'
2022-05-07 11:22:21 DEBUG (bellows.thread_0) [bellows.uart] Sending: b'87009f7e'
2022-05-07 11:22:21 DEBUG (MainThread) [bellows.ezsp.protocol] Application frame 170 (getValue) received: b'0001f2'
2022-05-07 11:22:21 DEBUG (MainThread) [bellows.zigbee.application] Free buffers status EzspStatus.SUCCESS, value: 242
2022-05-07 11:22:21 DEBUG (MainThread) [bellows.zigbee.application] ezsp_counters: [MAC_RX_BROADCAST = 855, MAC_TX_BROADCAST = 517, MAC_RX_UNICAST = 1525, MAC_TX_UNICAST_SUCCESS = 756, MAC_TX_UNICAST_RETRY = 64, MAC_TX_UNICAST_FAILED = 2, APS_DATA_RX_BROADCAST = 7, APS_DATA_TX_BROADCAST = 7, APS_DATA_RX_UNICAST = 438, APS_DATA_TX_UNICAST_SUCCESS = 365, APS_DATA_TX_UNICAST_RETRY = 13, APS_DATA_TX_UNICAST_FAILED = 3, ROUTE_DISCOVERY_INITIATED = 6, NEIGHBOR_ADDED = 2, NEIGHBOR_REMOVED = 0, NEIGHBOR_STALE = 3, JOIN_INDICATION = 0, CHILD_REMOVED = 0, ASH_OVERFLOW_ERROR = 0, ASH_FRAMING_ERROR = 0, ASH_OVERRUN_ERROR = 0, NWK_FRAME_COUNTER_FAILURE = 0, APS_FRAME_COUNTER_FAILURE = 0, UTILITY = 0, APS_LINK_KEY_NOT_AUTHORIZED = 0, NWK_DECRYPTION_FAILURE = 0, APS_DECRYPTION_FAILURE = 0, ALLOCATE_PACKET_BUFFER_FAILURE = 0, RELAYED_UNICAST = 0, PHY_TO_MAC_QUEUE_LIMIT_REACHED = 0, PACKET_VALIDATE_LIBRARY_DROPPED_COUNT = 0, TYPE_NWK_RETRY_OVERFLOW = 0, PHY_CCA_FAIL_COUNT = 0, BROADCAST_TABLE_FULL = 0, PTA_LO_PRI_REQUESTED = 0, PTA_HI_PRI_REQUESTED = 0, PTA_LO_PRI_DENIED = 0, PTA_HI_PRI_DENIED = 0, PTA_LO_PRI_TX_ABORTED = 0, PTA_HI_PRI_TX_ABORTED = 0, ADDRESS_CONFLICT_SENT = 0, EZSP_FREE_BUFFERS = 242]
2022-05-07 11:22:24 DEBUG (MainThread) [homeassistant.components.zha.core.device] [0xBAE4](TS0502A): Device seen - marking the device available and resetting counter
2022-05-07 11:22:24 DEBUG (MainThread) [homeassistant.components.zha.core.device] [0xBAE4](TS0502A): Update device availability -  device available: True - new availability: True - changed: False
2022-05-07 11:22:31 DEBUG (MainThread) [bellows.ezsp.protocol] Send command readCounters: ()
2022-05-07 11:22:31 DEBUG (bellows.thread_0) [bellows.uart] Sending: b'478921a9a52a23b97e'
2022-05-07 11:22:31 DEBUG (bellows.thread_0) [bellows.uart] Data frame: b'7589a1a9a52a0ab257945125a05592499c4e27abedce768bf5c66389fc7e3fa7ebcdde6f8fffc7dbd5d2698c4623a9ec763ba5ea758241984c2613b1e070381c0e07bbe5ca658a459a4d9e4f9ff7c3d9d46a35a25190482431917e'
2022-05-07 11:22:31 DEBUG (bellows.thread_0) [bellows.uart] Sending: b'8070787e'
2022-05-07 11:22:31 DEBUG (MainThread) [bellows.ezsp.protocol] Application frame 241 (readCounters) received: b'1f000e001b000a000000000000000000110008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
2022-05-07 11:22:31 DEBUG (MainThread) [bellows.ezsp.protocol] Send command getValue: (<EzspValueId.VALUE_FREE_BUFFERS: 3>,)
2022-05-07 11:22:31 DEBUG (bellows.thread_0) [bellows.uart] Sending: b'508e21a9fe2a1697b77e'
2022-05-07 11:22:31 DEBUG (bellows.thread_0) [bellows.uart] Data frame: b'068ea1a9fe2a15b3abbd997e'
2022-05-07 11:22:31 DEBUG (bellows.thread_0) [bellows.uart] Sending: b'8160597e'
2022-05-07 11:22:31 DEBUG (MainThread) [bellows.ezsp.protocol] Application frame 170 (getValue) received: b'0001f2'
2022-05-07 11:22:31 DEBUG (MainThread) [bellows.zigbee.application] Free buffers status EzspStatus.SUCCESS, value: 242
2022-05-07 11:22:31 DEBUG (MainThread) [bellows.zigbee.application] ezsp_counters: [MAC_RX_BROADCAST = 856, MAC_TX_BROADCAST = 518, MAC_RX_UNICAST = 1525, MAC_TX_UNICAST_SUCCESS = 756, MAC_TX_UNICAST_RETRY = 64, MAC_TX_UNICAST_FAILED = 2, APS_DATA_RX_BROADCAST = 7, APS_DATA_TX_BROADCAST = 7, APS_DATA_RX_UNICAST = 438, APS_DATA_TX_UNICAST_SUCCESS = 365, APS_DATA_TX_UNICAST_RETRY = 13, APS_DATA_TX_UNICAST_FAILED = 3, ROUTE_DISCOVERY_INITIATED = 6, NEIGHBOR_ADDED = 2, NEIGHBOR_REMOVED = 0, NEIGHBOR_STALE = 3, JOIN_INDICATION = 0, CHILD_REMOVED = 0, ASH_OVERFLOW_ERROR = 0, ASH_FRAMING_ERROR = 0, ASH_OVERRUN_ERROR = 0, NWK_FRAME_COUNTER_FAILURE = 0, APS_FRAME_COUNTER_FAILURE = 0, UTILITY = 0, APS_LINK_KEY_NOT_AUTHORIZED = 0, NWK_DECRYPTION_FAILURE = 0, APS_DECRYPTION_FAILURE = 0, ALLOCATE_PACKET_BUFFER_FAILURE = 0, RELAYED_UNICAST = 0, PHY_TO_MAC_QUEUE_LIMIT_REACHED = 0, PACKET_VALIDATE_LIBRARY_DROPPED_COUNT = 0, TYPE_NWK_RETRY_OVERFLOW = 0, PHY_CCA_FAIL_COUNT = 0, BROADCAST_TABLE_FULL = 0, PTA_LO_PRI_REQUESTED = 0, PTA_HI_PRI_REQUESTED = 0, PTA_LO_PRI_DENIED = 0, PTA_HI_PRI_DENIED = 0, PTA_LO_PRI_TX_ABORTED = 0, PTA_HI_PRI_TX_ABORTED = 0, ADDRESS_CONFLICT_SENT = 0, EZSP_FREE_BUFFERS = 242]
2022-05-07 11:22:37 DEBUG (MainThread) [homeassistant.components.zha.core.channels.base] [0x811C:1:0x0b04]: async_update
2022-05-07 11:22:37 DEBUG (MainThread) [homeassistant.components.zha.core.channels.base] [0x811C:1:0x0b04]: Reading attributes in chunks: ['active_power']
2022-05-07 11:22:37 DEBUG (MainThread) [zigpy.zcl] [0x811C:1:0x0b04] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=False, is_reply=0, disable_default_response=0, reserved=0, *is_cluster=False, *is_general=True), tsn=222, command_id=<GeneralCommand.Read_Attributes: 0>, *is_reply=False)
2022-05-07 11:22:37 DEBUG (MainThread) [zigpy.zcl] [0x811C:1:0x0b04] Sending request: Read_Attributes(attribute_ids=[1291])
2022-05-07 11:22:37 DEBUG (MainThread) [bellows.ezsp.protocol] Send command sendUnicast: (<EmberOutgoingMessageType.OUTGOING_DIRECT: 0>, 0x811C, EmberApsFrame(profileId=260, clusterId=2820, sourceEndpoint=1, destinationEndpoint=1, options=<EmberApsOption.APS_OPTION_ENABLE_ROUTE_DISCOVERY|APS_OPTION_RETRY: 320>, groupId=0, sequence=222), 223, b'\x00\xde\x00\x0b\x05')
2022-05-07 11:22:37 DEBUG (bellows.thread_0) [bellows.uart] Sending: b'618f21a9602a15aed8904b21a15493099d4e277532cb6755fdcd668c4c7e'
2022-05-07 11:22:37 DEBUG (bellows.thread_0) [bellows.uart] Data frame: b'178fa1a9602a15b80e927e'
2022-05-07 11:22:37 DEBUG (bellows.thread_0) [bellows.uart] Sending: b'82503a7e'
2022-05-07 11:22:37 DEBUG (MainThread) [bellows.ezsp.protocol] Application frame 52 (sendUnicast) received: b'000a'
2022-05-07 11:22:37 DEBUG (bellows.thread_0) [bellows.uart] Data frame: b'278fb1a96b2a15aed8904b21a15493099d4e27a132ce67f97d7e'
2022-05-07 11:22:37 DEBUG (bellows.thread_0) [bellows.uart] Sending: b'83401b7e'
2022-05-07 11:22:37 DEBUG (MainThread) [bellows.ezsp.protocol] Application frame 63 (messageSentHandler) received: b'001c810401040b0101400100000adf0000'
2022-05-07 11:22:37 DEBUG (MainThread) [bellows.zigbee.application] Received messageSentHandler frame with [<EmberOutgoingMessageType.OUTGOING_DIRECT: 0>, 33052, EmberApsFrame(profileId=260, clusterId=2820, sourceEndpoint=1, destinationEndpoint=1, options=<EmberApsOption.APS_OPTION_ENABLE_ROUTE_DISCOVERY|APS_OPTION_RETRY: 320>, groupId=0, sequence=10), 223, <EmberStatus.SUCCESS: 0>, b'']
2022-05-07 11:22:37 DEBUG (bellows.thread_0) [bellows.uart] Data frame: b'378fb1a9112a15b658904124ab5593499c3c5b10f14f9874f4debd88f77b3f8eebcddc04037e'
2022-05-07 11:22:37 DEBUG (bellows.thread_0) [bellows.uart] Sending: b'8430fc7e'
2022-05-07 11:22:37 DEBUG (MainThread) [bellows.ezsp.protocol] Application frame 69 (incomingMessageHandler) received: b'000401040b010100010000727cbb1c81ffff0918de010b050029000002'
2022-05-07 11:22:37 DEBUG (MainThread) [bellows.zigbee.application] Received incomingMessageHandler frame with [<EmberIncomingMessageType.INCOMING_UNICAST: 0>, EmberApsFrame(profileId=260, clusterId=2820, sourceEndpoint=1, destinationEndpoint=1, options=<EmberApsOption.APS_OPTION_ENABLE_ROUTE_DISCOVERY: 256>, groupId=0, sequence=114), 124, -69, 0x811c, 255, 255, b'\x18\xde\x01\x0b\x05\x00)\x00\x00']
2022-05-07 11:22:37 DEBUG (MainThread) [zigpy.zcl] [0x811C:1:0x0b04] Received ZCL frame: b'\x18\xde\x01\x0b\x05\x00)\x00\x00'
2022-05-07 11:22:37 DEBUG (MainThread) [zigpy.zcl] [0x811C:1:0x0b04] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, is_reply=1, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True), tsn=222, command_id=1, *is_reply=True)
2022-05-07 11:22:37 DEBUG (MainThread) [zigpy.zcl] [0x811C:1:0x0b04] Decoded ZCL frame: ElectricalMeasurement:Read_Attributes_rsp(status_records=[ReadAttributeRecord(attrid=0x050B, status=<Status.SUCCESS: 0>, value=TypeValue(type=int16s, value=0))])
2022-05-07 11:22:41 DEBUG (MainThread) [bellows.ezsp.protocol] Send command readCounters: ()
2022-05-07 11:22:41 DEBUG (bellows.thread_0) [bellows.uart] Sending: b'748c21a9a52ae1827e'
2022-05-07 11:22:41 DEBUG (bellows.thread_0) [bellows.uart] Data frame: b'408ca1a9a52a34b257945725a15592499c4e27abedce758bf4c66389fc7e3fa7ebcdde6f8fffc7dbd5d2698c4623a9ec763ba5ea758241984c2613b1e070381c0e07bbe5ca658a459a4d9e4f9ff7c3d9d46a35a251904824cd567e'
2022-05-07 11:22:41 DEBUG (bellows.thread_0) [bellows.uart] Sending: b'8520dd7e'
2022-05-07 11:22:41 DEBUG (MainThread) [bellows.ezsp.protocol] Application frame 241 (readCounters) received: b'21000e001d000b000000000000000000120009000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
2022-05-07 11:22:41 DEBUG (MainThread) [bellows.ezsp.protocol] Send command getValue: (<EzspValueId.VALUE_FREE_BUFFERS: 3>,)
2022-05-07 11:22:41 DEBUG (bellows.thread_0) [bellows.uart] Sending: b'058d21a9fe2a16ca677e'
2022-05-07 11:22:41 DEBUG (bellows.thread_0) [bellows.uart] Data frame: b'518da1a9fe2a15b3abc8607e'
2022-05-07 11:22:41 DEBUG (bellows.thread_0) [bellows.uart] Sending: b'8610be7e'
2022-05-07 11:22:41 DEBUG (MainThread) [bellows.ezsp.protocol] Application frame 170 (getValue) received: b'0001f2'
2022-05-07 11:22:41 DEBUG (MainThread) [bellows.zigbee.application] Free buffers status EzspStatus.SUCCESS, value: 242
2022-05-07 11:22:41 DEBUG (MainThread) [bellows.zigbee.application] ezsp_counters: [MAC_RX_BROADCAST = 858, MAC_TX_BROADCAST = 518, MAC_RX_UNICAST = 1527, MAC_TX_UNICAST_SUCCESS = 757, MAC_TX_UNICAST_RETRY = 64, MAC_TX_UNICAST_FAILED = 2, APS_DATA_RX_BROADCAST = 7, APS_DATA_TX_BROADCAST = 7, APS_DATA_RX_UNICAST = 439, APS_DATA_TX_UNICAST_SUCCESS = 366, APS_DATA_TX_UNICAST_RETRY = 13, APS_DATA_TX_UNICAST_FAILED = 3, ROUTE_DISCOVERY_INITIATED = 6, NEIGHBOR_ADDED = 2, NEIGHBOR_REMOVED = 0, NEIGHBOR_STALE = 3, JOIN_INDICATION = 0, CHILD_REMOVED = 0, ASH_OVERFLOW_ERROR = 0, ASH_FRAMING_ERROR = 0, ASH_OVERRUN_ERROR = 0, NWK_FRAME_COUNTER_FAILURE = 0, APS_FRAME_COUNTER_FAILURE = 0, UTILITY = 0, APS_LINK_KEY_NOT_AUTHORIZED = 0, NWK_DECRYPTION_FAILURE = 0, APS_DECRYPTION_FAILURE = 0, ALLOCATE_PACKET_BUFFER_FAILURE = 0, RELAYED_UNICAST = 0, PHY_TO_MAC_QUEUE_LIMIT_REACHED = 0, PACKET_VALIDATE_LIBRARY_DROPPED_COUNT = 0, TYPE_NWK_RETRY_OVERFLOW = 0, PHY_CCA_FAIL_COUNT = 0, BROADCAST_TABLE_FULL = 0, PTA_LO_PRI_REQUESTED = 0, PTA_HI_PRI_REQUESTED = 0, PTA_LO_PRI_DENIED = 0, PTA_HI_PRI_DENIED = 0, PTA_LO_PRI_TX_ABORTED = 0, PTA_HI_PRI_TX_ABORTED = 0, ADDRESS_CONFLICT_SENT = 0, EZSP_FREE_BUFFERS = 242]

I have no idea why your device looks so differently..
Could you send me a debug log while pressing a few buttons? Maybe I can recognize a pattern

Hi,
I'm new to quirks but from your discussion i think i have the same problem with only 3 endpoints (1, 2, 242) being shown when i add this device to ZHA. I added your custom quirk but it doesn't recognise it.
I have 2 of these H1 double rocker switches and really want to be able to decouple the button from the relay...
Anything i can do to help?

I am kind of clueless why they are so different. You could try:

Disconnect the device from power
remove the device from ZHA
Restart HA
Join the device

Maybe retry this a couple of times and check whether the device changes it's endpoints

Thanks will do.
Could it be the firmware being different? In the device page i see:
Device info
lumi.switch.n2aeu1
by LUMI
Connected via [Zigbee Coordinator]
Firmware: 0x00000b16
Is your firmware the same?

I do not see a firmware version on the device page

Any success?

Sorry for the wait.
I tried but still no luck. Endpoints always stay the same.
I took a copy of the log when the switch was pairing. Is that helpful?

What coordinator and firmware are you on. Maybe there is a pattern here..?

Coordinator: Texas_Instruments_TI_CC2531
Firmware: do you mean for the coordinator or the switch? I cant find a firmware version for the coordinator. switch firmware shows up as 0x00000b16.
When I pair the switch, it includes this line in the log:
OTA query_next_image handler for 'LUMI lumi.switch.n2aeu1': field_control=FieldControl.0, manufacture_id=4447, image_type=5532, current_file_version=2838, hardware_version=None, model=lumi.switch.n2aeu1
No OTA image is available
Is that enough info or do you need anything else?

Hi, regarding the different endpoints:
I have three of the H1 double rocker switches with neutral.  The other two (likely newer, since the shop had only one switch in stock when i ordered) expose three endpoints as mentioned by nclapham01.
However... all work the same, so by adding a new signature and leaving the replace / trigger part it functions like the other version.
This is what I appended to opple_switch.py:

class XiaomiOpple2ButtonSwitch2(XiaomiCustomDevice):
    """Xiaomi Opple 2 Button Switch."""

    manufacturer_id_override = 0x115F

    signature = {
        ENDPOINTS: {
            # input_clusters=[0, 2, 3, 4, 5, 6, 18, 64704], output_clusters=[10, 25]
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,  # 0
                    DeviceTemperature.cluster_id,  # 2
                    Identify.cluster_id,  # 3
                    Groups.cluster_id,  # 4
                    Scenes.cluster_id,  # 5
                    OnOff.cluster_id,  # 6
                    Alarms.cluster_id, # 9
                    Metering.cluster_id, # 0x0702
                    0x0b04,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            # input_clusters=[0, 3, 4, 5, 6, 18, 64704], output_clusters=[]
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,  # 0
                    Identify.cluster_id,  # 3
                    Groups.cluster_id,  # 4
                    Scenes.cluster_id,  # 5
                    OnOff.cluster_id,  # 6
                ],
                OUTPUT_CLUSTERS: [],
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 0x0061,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    DeviceTemperatureCluster,  # 2
                    Identify.cluster_id,  # 3
                    Groups.cluster_id,  # 4
                    Scenes.cluster_id,  # 5
                    OnOffCluster,  # 6
                    #MultistateInputCluster,  # 18
                    OppleSwitchCluster,  # 0xFCC0 / 64704
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            2: {
                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    Identify.cluster_id,  # 3
                    Groups.cluster_id,  # 4
                    Scenes.cluster_id,  # 5
                    OnOffCluster,  # 6
                    #MultistateInputCluster,  # 18
                    OppleSwitchCluster,  # 0xFCC0 / 64704
                ],
                OUTPUT_CLUSTERS: [],
            },
            # input_clusters=[12], output_clusters=[]
            21: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    AnalogInput.cluster_id,  # 12
                ],
                OUTPUT_CLUSTERS: [],
            },
            # input_clusters=[12], output_clusters=[]
            31: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    AnalogInput.cluster_id,  # 12
                ],
                OUTPUT_CLUSTERS: [],
            },
            # input_clusters=[18], output_clusters=[]
            41: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    MultistateInputCluster,  # 18
                ],
                OUTPUT_CLUSTERS: [],
            },
            # input_clusters=[18], output_clusters=[]
            42: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    MultistateInputCluster,  # 18
                ],
                OUTPUT_CLUSTERS: [],
            },
            # input_clusters=[18], output_clusters=[]
            51: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    MultistateInputCluster,  # 18
                ],
                OUTPUT_CLUSTERS: [],
            },
            # input_clusters=[18], output_clusters=[]
            61: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    MultistateInputCluster,  # 18
                ],
                OUTPUT_CLUSTERS: [],
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        }
    }

    device_automation_triggers = {
        (COMMAND_BUTTON_SINGLE, BUTTON_1): {
            ENDPOINT_ID: 41,
            CLUSTER_ID: 18,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x0055, PRESS_TYPE: COMMAND_SINGLE, VALUE: 1},
        },
        (COMMAND_BUTTON_DOUBLE, BUTTON_1): {
            ENDPOINT_ID: 41,
            CLUSTER_ID: 18,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x0055, PRESS_TYPE: COMMAND_DOUBLE, VALUE: 2},
        },
        (COMMAND_BUTTON_HOLD, BUTTON_1): {
            ENDPOINT_ID: 1,
            CLUSTER_ID: 0xFCC0,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x00FC, VALUE: False},
        },
        (COMMAND_BUTTON_SINGLE, BUTTON_2): {
            ENDPOINT_ID: 42,
            CLUSTER_ID: 18,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x0055, PRESS_TYPE: COMMAND_SINGLE, VALUE: 1},
        },
        (COMMAND_BUTTON_DOUBLE, BUTTON_2): {
            ENDPOINT_ID: 42,
            CLUSTER_ID: 18,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x0055, PRESS_TYPE: COMMAND_DOUBLE, VALUE: 2},
        },
        (COMMAND_BUTTON_HOLD, BUTTON_2): {
            ENDPOINT_ID: 1,
            CLUSTER_ID: 0xFCC0,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x00FC, VALUE: False},
        },
        (COMMAND_BUTTON_SINGLE, BOTH_BUTTONS): {
            ENDPOINT_ID: 51,
            CLUSTER_ID: 18,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x0055, PRESS_TYPE: COMMAND_SINGLE, VALUE: 1},
        },
        (COMMAND_BUTTON_DOUBLE, BOTH_BUTTONS): {
            ENDPOINT_ID: 51,
            CLUSTER_ID: 18,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x0055, PRESS_TYPE: COMMAND_DOUBLE, VALUE: 2},
        },
        (COMMAND_BUTTON_HOLD, BOTH_BUTTONS): {
            ENDPOINT_ID: 1,
            CLUSTER_ID: 0xFCC0,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x00FC, VALUE: 0},
        },
    }

Some features that dont work right now:

device temperature shows 0.3 in home assistant
power / energy reporting sensors in home assistant

Hi, regarding the different endpoints: I have three of the H1 double rocker switches with neutral.  The other two (likely newer, since the shop had only one switch in stock when i ordered) expose three endpoints as mentioned by nclapham01. However... all work the same, so by adding a new signature and leaving the replace / trigger part it functions like the other version. This is what I appended to opple_switch.py:
Some features that dont work right now:

device temperature shows 0.3 in home assistant
power / energy reporting sensors in home assistant

Thanks @wRieDen that sounds great! Unfortunately when i tried creating a custom quirk including what you've added, i get this error after restarting:
File "/config/custom_zha_quirks/opple_switch(test).py", line 781, in XiaomiOpple2ButtonSwitch2
Alarms.cluster_id, # 9
NameError: name 'Alarms' is not defined
I'm a novice when it comes to creating these quirks, so forgive me if I'm missing something obvious, but I cant see where "Alarms" is defined... can you help me fix this?
Thanks.

Nothing obvious, the snippet was just to show dumpfheimer a config for the other switch type. About your issue, i'm using some additional imports for the new clusters that the 3 endpoint device reports. So here is a the full quirk file that i currently use:

"""Xiaomi aqara single key wall switch devices."""
import copy

from zigpy import types as t
from zigpy.profiles import zha
from zigpy.zcl.clusters.general import (
    AnalogInput,
    Basic,
    DeviceTemperature,
    GreenPowerProxy,
    Groups,
    Identify,
    OnOff,
    Ota,
    Scenes,
    Time,
    Alarms,
)

from zigpy.zcl.clusters.smartenergy import (
    Metering,
)

from zhaquirks.const import (
    ARGS,
    ATTR_ID,
    BUTTON,
    BUTTON_1,
    BUTTON_2,
    BUTTON_3,
    CLUSTER_ID,
    COMMAND_BUTTON_DOUBLE,
    COMMAND_BUTTON_HOLD,
    COMMAND_BUTTON_SINGLE,
    COMMAND_DOUBLE,
    COMMAND_SINGLE,
    COMMAND_TRIPLE,
    DEVICE_TYPE,
    ENDPOINT_ID,
    ENDPOINTS,
    INPUT_CLUSTERS,
    OUTPUT_CLUSTERS,
    PRESS_TYPE,
    PROFILE_ID,
    VALUE,
    ZHA_SEND_EVENT,
)
from zhaquirks.xiaomi import (
    BasicCluster,
    DeviceTemperatureCluster,
    OnOffCluster,
    XiaomiCustomDevice,
)

from zhaquirks.xiaomi.aqara.opple_remote import MultistateInputCluster, OppleCluster

BOTH_BUTTONS = "both_buttons"
PRESS_TYPES = {0: "hold", 1: "single", 2: "double", 3: "triple", 255: "release"}

class OppleOperationMode(t.uint8_t):
    """Opple operation_mode enum."""

    Decoupled = 0x00
    Coupled = 0x01

class OppleSwitchMode(t.uint8_t):
    """Opple switch_mode enum."""

    Fast = 0x01
    Multi = 0x02

class OppleSwitchType(t.uint8_t):
    """Opple switch_type enum."""

    Toggle = 0x01
    Momentary = 0x02

class OppleIndicatorLight(t.uint8_t):
    """Opple indicator light enum."""

    Normal = 0x00
    Reverse = 0x01

class OppleSwitchCluster(OppleCluster):
    """Xiaomi mfg cluster implementation."""

    if hasattr(OppleCluster, "attributes"):
        attributes = copy.deepcopy(OppleCluster.attributes)
    elif hasattr(OppleCluster, "manufacturer_attributes"):
        attributes = copy.deepcopy(OppleCluster.manufacturer_attributes)
    else:
        attributes = {}

    attributes.update(
        {
            0x0002: ("power_outage_count", t.uint8_t),
            0x000A: ("switch_type", OppleSwitchType),
            0x00F0: ("reverse_indicator_light", OppleIndicatorLight),
            0x0125: ("switch_mode", OppleSwitchMode),
            0x0200: ("operation_mode", OppleOperationMode),
            0x0201: ("power_outage_memory", t.Bool),
            0x0202: ("auto_off", t.Bool),
            0x0203: ("do_not_disturb", t.Bool),
        }
    )

    def _update_attribute(self, attrid, value):
        super()._update_attribute(attrid, value)
        if attrid == 0x00FC:
            self._current_state = PRESS_TYPES.get(value)
            event_args = {
                BUTTON: self.endpoint.endpoint_id,
                PRESS_TYPE: self._current_state,
                ATTR_ID: attrid,
                VALUE: value,
            }
            action = "{}_{}".format(self.endpoint.endpoint_id, self._current_state)
            self.listener_event(ZHA_SEND_EVENT, action, event_args)
            # show something in the sensor in HA
            super()._update_attribute(0, action)

class XiaomiOpple2ButtonSwitch(XiaomiCustomDevice):
    """Xiaomi Opple 2 Button Switch."""

    manufacturer_id_override = 0x115F

    signature = {
        ENDPOINTS: {
            # input_clusters=[0, 2, 3, 4, 5, 6, 18, 64704], output_clusters=[10, 25]
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,  # 0
                    DeviceTemperature.cluster_id,  # 2
                    Identify.cluster_id,  # 3
                    Groups.cluster_id,  # 4
                    Scenes.cluster_id,  # 5
                    OnOff.cluster_id,  # 6
                    MultistateInputCluster.cluster_id,  # 18
                    OppleSwitchCluster.cluster_id,  # 0xFCC0 / 64704
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            # input_clusters=[0, 3, 4, 5, 6, 18, 64704], output_clusters=[]
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,  # 0
                    Identify.cluster_id,  # 3
                    Groups.cluster_id,  # 4
                    Scenes.cluster_id,  # 5
                    OnOff.cluster_id,  # 6
                    MultistateInputCluster.cluster_id,  # 18
                    OppleSwitchCluster.cluster_id,  # 0xFCC0 / 64704
                ],
                OUTPUT_CLUSTERS: [],
            },
            # input_clusters=[12], output_clusters=[]
            21: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    AnalogInput.cluster_id,  # 12
                ],
                OUTPUT_CLUSTERS: [],
            },
            # input_clusters=[12], output_clusters=[]
            31: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    AnalogInput.cluster_id,  # 12
                ],
                OUTPUT_CLUSTERS: [],
            },
            # input_clusters=[18], output_clusters=[]
            41: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    MultistateInputCluster.cluster_id,  # 18
                ],
                OUTPUT_CLUSTERS: [],
            },
            # input_clusters=[18], output_clusters=[]
            42: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    MultistateInputCluster.cluster_id,  # 18
                ],
                OUTPUT_CLUSTERS: [],
            },
            # input_clusters=[18], output_clusters=[]
            51: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    MultistateInputCluster.cluster_id,  # 18
                ],
                OUTPUT_CLUSTERS: [],
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    DeviceTemperatureCluster,  # 2
                    Identify.cluster_id,  # 3
                    Groups.cluster_id,  # 4
                    Scenes.cluster_id,  # 5
                    OnOffCluster,  # 6
                    MultistateInputCluster,  # 18
                    OppleSwitchCluster,  # 0xFCC0 / 64704
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            2: {
                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    Identify.cluster_id,  # 3
                    Groups.cluster_id,  # 4
                    Scenes.cluster_id,  # 5
                    OnOffCluster,  # 6
                    MultistateInputCluster,  # 18
                    OppleSwitchCluster,  # 0xFCC0 / 64704
                ],
                OUTPUT_CLUSTERS: [],
            },
            # input_clusters=[12], output_clusters=[]
            21: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    AnalogInput.cluster_id,  # 12
                ],
                OUTPUT_CLUSTERS: [],
            },
            # input_clusters=[12], output_clusters=[]
            31: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    AnalogInput.cluster_id,  # 12
                ],
                OUTPUT_CLUSTERS: [],
            },
            # input_clusters=[18], output_clusters=[]
            41: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    MultistateInputCluster,  # 18
                ],
                OUTPUT_CLUSTERS: [],
            },
            # input_clusters=[18], output_clusters=[]
            42: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    MultistateInputCluster,  # 18
                ],
                OUTPUT_CLUSTERS: [],
            },
            # input_clusters=[18], output_clusters=[]
            51: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    MultistateInputCluster,  # 18
                ],
                OUTPUT_CLUSTERS: [],
            },
            # input_clusters=[18], output_clusters=[]
            61: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    MultistateInputCluster,  # 18
                ],
                OUTPUT_CLUSTERS: [],
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }

    device_automation_triggers = {
        (COMMAND_BUTTON_SINGLE, BUTTON_1): {
            ENDPOINT_ID: 41,
            CLUSTER_ID: 18,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x0055, PRESS_TYPE: COMMAND_SINGLE, VALUE: 1},
        },
        (COMMAND_BUTTON_DOUBLE, BUTTON_1): {
            ENDPOINT_ID: 41,
            CLUSTER_ID: 18,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x0055, PRESS_TYPE: COMMAND_DOUBLE, VALUE: 2},
        },
        (COMMAND_BUTTON_HOLD, BUTTON_1): {
            ENDPOINT_ID: 1,
            CLUSTER_ID: 0xFCC0,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x00FC, VALUE: False},
        },
        (COMMAND_BUTTON_SINGLE, BUTTON_2): {
            ENDPOINT_ID: 42,
            CLUSTER_ID: 18,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x0055, PRESS_TYPE: COMMAND_SINGLE, VALUE: 1},
        },
        (COMMAND_BUTTON_DOUBLE, BUTTON_2): {
            ENDPOINT_ID: 42,
            CLUSTER_ID: 18,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x0055, PRESS_TYPE: COMMAND_DOUBLE, VALUE: 2},
        },
        (COMMAND_BUTTON_HOLD, BUTTON_2): {
            ENDPOINT_ID: 1,
            CLUSTER_ID: 0xFCC0,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x00FC, VALUE: False},
        },
        (COMMAND_BUTTON_SINGLE, BOTH_BUTTONS): {
            ENDPOINT_ID: 51,
            CLUSTER_ID: 18,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x0055, PRESS_TYPE: COMMAND_SINGLE, VALUE: 1},
        },
        (COMMAND_BUTTON_DOUBLE, BOTH_BUTTONS): {
            ENDPOINT_ID: 51,
            CLUSTER_ID: 18,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x0055, PRESS_TYPE: COMMAND_DOUBLE, VALUE: 2},
        },
        (COMMAND_BUTTON_HOLD, BOTH_BUTTONS): {
            ENDPOINT_ID: 1,
            CLUSTER_ID: 0xFCC0,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x00FC, VALUE: 0},
        },
    }

class XiaomiOpple2ButtonSwitch2(XiaomiCustomDevice):
    """Xiaomi Opple 2 Button Switch."""

    manufacturer_id_override = 0x115F

    signature = {
        ENDPOINTS: {
            # input_clusters=[0, 2, 3, 4, 5, 6, 18, 64704], output_clusters=[10, 25]
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,  # 0
                    DeviceTemperature.cluster_id,  # 2
                    Identify.cluster_id,  # 3
                    Groups.cluster_id,  # 4
                    Scenes.cluster_id,  # 5
                    OnOff.cluster_id,  # 6
                    Alarms.cluster_id, # 9
                    Metering.cluster_id, # 0x0702
                    0x0b04,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            # input_clusters=[0, 3, 4, 5, 6, 18, 64704], output_clusters=[]
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,  # 0
                    Identify.cluster_id,  # 3
                    Groups.cluster_id,  # 4
                    Scenes.cluster_id,  # 5
                    OnOff.cluster_id,  # 6
                ],
                OUTPUT_CLUSTERS: [],
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 0x0061,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    DeviceTemperatureCluster,  # 2
                    Identify.cluster_id,  # 3
                    Groups.cluster_id,  # 4
                    Scenes.cluster_id,  # 5
                    OnOffCluster,  # 6
                    #MultistateInputCluster,  # 18
                    OppleSwitchCluster,  # 0xFCC0 / 64704
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            2: {
                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    Identify.cluster_id,  # 3
                    Groups.cluster_id,  # 4
                    Scenes.cluster_id,  # 5
                    OnOffCluster,  # 6
                    #MultistateInputCluster,  # 18
                    OppleSwitchCluster,  # 0xFCC0 / 64704
                ],
                OUTPUT_CLUSTERS: [],
            },
            # input_clusters=[12], output_clusters=[]
            21: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    AnalogInput.cluster_id,  # 12
                ],
                OUTPUT_CLUSTERS: [],
            },
            # input_clusters=[12], output_clusters=[]
            31: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    AnalogInput.cluster_id,  # 12
                ],
                OUTPUT_CLUSTERS: [],
            },
            # input_clusters=[18], output_clusters=[]
            41: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    MultistateInputCluster,  # 18
                ],
                OUTPUT_CLUSTERS: [],
            },
            # input_clusters=[18], output_clusters=[]
            42: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    MultistateInputCluster,  # 18
                ],
                OUTPUT_CLUSTERS: [],
            },
            # input_clusters=[18], output_clusters=[]
            51: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    MultistateInputCluster,  # 18
                ],
                OUTPUT_CLUSTERS: [],
            },
            # input_clusters=[18], output_clusters=[]
            61: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    MultistateInputCluster,  # 18
                ],
                OUTPUT_CLUSTERS: [],
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        }
    }

    device_automation_triggers = {
        (COMMAND_BUTTON_SINGLE, BUTTON_1): {
            ENDPOINT_ID: 41,
            CLUSTER_ID: 18,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x0055, PRESS_TYPE: COMMAND_SINGLE, VALUE: 1},
        },
        (COMMAND_BUTTON_DOUBLE, BUTTON_1): {
            ENDPOINT_ID: 41,
            CLUSTER_ID: 18,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x0055, PRESS_TYPE: COMMAND_DOUBLE, VALUE: 2},
        },
        (COMMAND_BUTTON_HOLD, BUTTON_1): {
            ENDPOINT_ID: 1,
            CLUSTER_ID: 0xFCC0,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x00FC, VALUE: False},
        },
        (COMMAND_BUTTON_SINGLE, BUTTON_2): {
            ENDPOINT_ID: 42,
            CLUSTER_ID: 18,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x0055, PRESS_TYPE: COMMAND_SINGLE, VALUE: 1},
        },
        (COMMAND_BUTTON_DOUBLE, BUTTON_2): {
            ENDPOINT_ID: 42,
            CLUSTER_ID: 18,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x0055, PRESS_TYPE: COMMAND_DOUBLE, VALUE: 2},
        },
        (COMMAND_BUTTON_HOLD, BUTTON_2): {
            ENDPOINT_ID: 1,
            CLUSTER_ID: 0xFCC0,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x00FC, VALUE: False},
        },
        (COMMAND_BUTTON_SINGLE, BOTH_BUTTONS): {
            ENDPOINT_ID: 51,
            CLUSTER_ID: 18,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x0055, PRESS_TYPE: COMMAND_SINGLE, VALUE: 1},
        },
        (COMMAND_BUTTON_DOUBLE, BOTH_BUTTONS): {
            ENDPOINT_ID: 51,
            CLUSTER_ID: 18,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x0055, PRESS_TYPE: COMMAND_DOUBLE, VALUE: 2},
        },
        (COMMAND_BUTTON_HOLD, BOTH_BUTTONS): {
            ENDPOINT_ID: 1,
            CLUSTER_ID: 0xFCC0,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x00FC, VALUE: 0},
        },
    }

Thanks!
I copied yours and it loaded OK, and is used by the device:
"Quirk: opple_switch(new).XiaomiOpple2ButtonSwitch2"
Device now shows up as a switch, but:

I don't have any configuration option to de-couple the switch from the relay. Is this available for you as an entity?
Firmware version has now disappeared.
Device temperature and power consumption have also disappeared (not bothered about temperature as it was always showing as 0.3deg without the quirk, but was wanting to use the power consumption info which seemed to work correctly before adding this quirk).

Are you having the same issues and how can I fix them?

@nclapham01

go to the device page and click "manage clusters" in the burger menu.
select the OppleSwitchCluster Endpoint 1 or Endpoint 2 (left and right button?)
select attribute operation_mode
enter 0 for decoupled mode or 1 for coupled mode
click "set zigbee attribute"

Regarding the temperature and power consumption, both of them don't work for me right now  (temperature being at 0.3 and power at 0), they likely need some more attention to be useful. Can you confirm that power did work for you at some point?

I think I need help with the test =/
@Adminiuga @dmulcahey
If you have time on your hands could you point me in the right direction with the failing test_quirk_device_automation_triggers_unique test?
Why is this test in place? How can I reuse the device_automation_triggers correctly?
Thanks

Regarding the temperature and power consumption, both of them don't work for me right now (temperature being at 0.3 and power at 0), they likely need some more attention to be useful. Can you confirm that power did work for you at some point?

Yes, power did seem to work before I added the custom quirk. This is a screenshot I took before I added it.

with your custom quirk, I now don't get those entities:

Interesting, seems that the energy summation also gave me value now. Anyway, both switch types are included in the pull request and also the power cluster is added. So you can just use the opple_switch.py file again. To run it as a custom quirk replace
from .opple_remote import MultistateInputCluster, OppleCluster with
from zhaquirks.xiaomi.aqara.opple_remote import MultistateInputCluster, OppleCluster
@dumpfheimer Thanks for your work!

No idea how you got the device temerpature or the current electrical measurement =/ I'll keep playing around

Possibly related to https://github.com/zigpy/zha-device-handlers/issues/1655 and https://github.com/zigpy/zha-device-handlers/pull/1656.
(Different coordinator firmware requires a different quirk.)

Should that patch be included in the latest development firmware from koenkk?

How do I know if my coordinator sends out xiaomi manufacturer specific stuff during pairing?

Configuration entities are in the pipeline. But they must be made in ZHA/Home Assistant  so I think this PR must be merged first (and possibly a dependency update too)

Hi,
Any info on whether this PR will be merged soon as is or if the energy consumption will be fixed first?
I can try take some logs for the energy consumption with and without the quirk if that helps?

It's not my decision when the PR is merged. I'm not sure if and when I will get around to check the current power. The sum in kWh however works fine.
Personally I would merge sooner than later to make it easier for further contributions to be made (similar devices e.g.). It seems like quite a few people could appreciate the "decoupled mode"

I think I need help with the test =/

The test complains because the trigger for 'hold' button 1 and 2 is the same:
(COMMAND_BUTTON_HOLD, BUTTON_2): {
            ENDPOINT_ID: 1,
            CLUSTER_ID: 0xFCC0,
            # COMMAND: COMMAND_ATTRIBUTE_UPDATED,
            ARGS: {ATTR_ID: 0x00FC, VALUE: False},
        },

The quirk needs to know which event have to trigger but if the attributes are the same, don't know which one have to trigger.
There must be some different between events of both buttons.

Thanks, @javicalle !! That makes sence...
This is strange.
Both buttons seem to send the same commands.
Also, while testing my device disconnected. I was multiple times long pressing one of the two buttons. Now it is blinking red.

This is strange.
Both buttons seem to send the same commands.

Have you tried to listen to the zha_events from the developers tools view?
There you will see what's the device sending.

Also, while testing my device disconnected. I was multiple times long pressing one of the two buttons. Now it is blinking red.

If you keep pushing the button to much, the device will reset and goes to the pairing mode.
Just pair it again from HA.

I was looking at zigpy debug log: I see no difference except the counter incrementing (these are button 1 / button 2 / button 1 / button 2:
Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=64704, SrcAddr=0x89B8, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=<Bool.false: 0>, LQI=116, SecurityUse=<Bool.false: 0>, TimeStamp=12607088, TSN=0, Data=b'\x1C\x5F\x11\x0B\x0A\xFC\x00\x10\x00', MacSrcAddr=0x2F80, MsgResultRadius=28)
Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=64704, SrcAddr=0x89B8, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=<Bool.false: 0>, LQI=120, SecurityUse=<Bool.false: 0>, TimeStamp=12821455, TSN=0, Data=b'\x1C\x5F\x11\x0C\x0A\xFC\x00\x10\x00', MacSrcAddr=0x2F80, MsgResultRadius=28)
Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=64704, SrcAddr=0x89B8, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=<Bool.false: 0>, LQI=120, SecurityUse=<Bool.false: 0>, TimeStamp=13029949, TSN=0, Data=b'\x1C\x5F\x11\x0D\x0A\xFC\x00\x10\x00', MacSrcAddr=0x2F80, MsgResultRadius=28)
Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=64704, SrcAddr=0x89B8, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=<Bool.false: 0>, LQI=120, SecurityUse=<Bool.false: 0>, TimeStamp=13260380, TSN=0, Data=b'\x1C\x5F\x11\x0E\x0A\xFC\x00\x10\x00', MacSrcAddr=0x2F80, MsgResultRadius=28)

So I guess the solution would be to only have one long press trigger..?

We could check if z2m can differentiate  between the buttons.. and if so, how they do it.

z2m seems to have no long click / hold:
https://www.zigbee2mqtt.io/devices/WS-EUK04.html
So I guess it is fine to have only one - or we remove it completely. I like it the way it is now (single command for either button)

I haven't review the code in detail, but from what I have seen there are some events from endpoints 41, 42 and 51. These are the 'normal' events for this device.
Then there are the 'hold' events. All from endpoint 1. But these are created by your new code (the _update_attribute part), and it seems that always come from endpoint 1 (and not from 1 and 2). That seems to be the reason that we can't diference the events.
Maybe you can add some debug log in the _update_attribute method to see what is coming from device but my guess is that these aren't real 'hold' events and there are just some 'faked' events from some report from device.

@javicalle I think I see what you mean. I'm out of time for now but will look into it eventually.
Thanks for your help

If I look at the raw data they still seem indistinguishable to me:
button 1 / button 2:
Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=64704, SrcAddr=0x89B8, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=<Bool.false: 0>, LQI=94, SecurityUse=<Bool.false: 0>, TimeStamp=12250024, TSN=0, Data=b'\x1C\x5F\x11\xA3\x0A\xFC\x00\x10\x00', MacSrcAddr=0x89B8, MsgResultRadius=29)
Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=64704, SrcAddr=0x89B8, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=<Bool.false: 0>, LQI=87, SecurityUse=<Bool.false: 0>, TimeStamp=12706746, TSN=0, Data=b'\x1C\x5F\x11\xA4\x0A\xFC\x00\x10\x00', MacSrcAddr=0x89B8, MsgResultRadius=29)

The A3/A4 part seems to increment with every command so is no "real difference"
I am not knowledgeable enough in Zigbee to know whether there could be another way to keep the two apart.

If I look at the raw data they still seem indistinguishable to me: button 1 / button 2:
Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=64704, SrcAddr=0x89B8, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=<Bool.false: 0>, LQI=94, SecurityUse=<Bool.false: 0>, TimeStamp=12250024, TSN=0, Data=b'\x1C\x5F\x11\xA3\x0A\xFC\x00\x10\x00', MacSrcAddr=0x89B8, MsgResultRadius=29)
Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=64704, SrcAddr=0x89B8, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=<Bool.false: 0>, LQI=87, SecurityUse=<Bool.false: 0>, TimeStamp=12706746, TSN=0, Data=b'\x1C\x5F\x11\xA4\x0A\xFC\x00\x10\x00', MacSrcAddr=0x89B8, MsgResultRadius=29)

The A3/A4 part seems to increment with every command

Just wild guess - what about one button has only odd numbers and the other even numbers?

I looked at that too, also within the timestamp.. nothing relatively obvious

Does someone have the Xiaomi gateway? Are there distinguishable long press events in the Xiaomi ecosystem?

Does anyone knows what is the 0x00FC atribute?
It is not n OppleCluster attribute.
It must be triggering errors in this part because that attribute doesn't exists:
    def _update_attribute(self, attrid, value):
        super()._update_attribute(attrid, value)
        if attrid == 0x00FC:
            self._current_state = PRESS_TYPES.get(value)
            .../...

I'm not sure where I copied that from.. should take another look and see if it's even necessary..

Well, turns out it's needed 💪and still, the buttons seem indistinguishable :-/

@dumpfheimer Sorry for the late comment, but is there a reason MODELS_INFO isn't used?
So manufacturer and model aren't matched at all? (only the endpoints are)
If there's no particular reason, would you mind adding them?
Should just be something like this in the signature:
MODELS_INFO: [(LUMI, "lumi.switch.n2aeu1")],

(or are there further models?)

There are multiple models that seem to work the same way.  I do not know if they are matched this quirk, though. What are you after?

@dumpfheimer You have some of these devices, right? Can you provide the device signature(s) for all your Xiaomi H1 switches?
I'm after the ones that match your added XiaomiOpple2ButtonSwitchFace1, XiaomiOpple2ButtonSwitchFace2 quirks.
We want to whitelist those quirks to only apply to the correct manufacturer / models. It's there for almost all other quirks, but missing for these two quirks. (MODELS_INFO is missing from those quirks -- see linked issues/PRs/comments between this and my last comment for reference)

I think there are multiple models that should use this quirk and that is why the model was omitted, not 100% sure, though.
My model is lumi.switch.n2aeu1

This is the signature, copied from the debug json

{
      "node_descriptor": "NodeDescriptor(logical_type=, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=, mac_capability_flags=, manufacturer_code=4447, maximum_buffer_size=127, maximum_incoming_transfer_size=100, server_mask=11264, maximum_outgoing_transfer_size=100, descriptor_capability_field=, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)",
      "endpoints": {
        "1": {
          "profile_id": "0x0104",
          "device_type": "0x0000",
          "input_clusters": [
            "0x0000",
            "0x0002",
            "0x0003",
            "0x0004",
            "0x0005",
            "0x0006",
            "0x0009",
            "0x0012",
            "0x0702",
            "0xfcc0"
          ],
          "output_clusters": [
            "0x000a",
            "0x0019"
          ]
        },
        "2": {
          "profile_id": "0x0104",
          "device_type": "0x0000",
          "input_clusters": [
            "0x0000",
            "0x0003",
            "0x0004",
            "0x0005",
            "0x0006",
            "0x0012",
            "0xfcc0"
          ],
          "output_clusters": []
        },
        "21": {
          "profile_id": "0x0104",
          "device_type": "0x0100",
          "input_clusters": [
            "0x000c"
          ],
          "output_clusters": []
        },
        "31": {
          "profile_id": "0x0104",
          "device_type": "0x0100",
          "input_clusters": [
            "0x000c"
          ],
          "output_clusters": []
        },
        "41": {
          "profile_id": "0x0104",
          "device_type": "0x0100",
          "input_clusters": [
            "0x0012"
          ],
          "output_clusters": []
        },
        "42": {
          "profile_id": "0x0104",
          "device_type": "0x0100",
          "input_clusters": [
            "0x0012"
          ],
          "output_clusters": []
        },
        "51": {
          "profile_id": "0x0104",
          "device_type": "0x0100",
          "input_clusters": [
            "0x0012"
          ],
          "output_clusters": []
        },
        "61": {
          "profile_id": "0x0104",
          "device_type": "0x0100",
          "input_clusters": [
            "0x0012"
          ],
          "output_clusters": []
        },
        "242": {
          "profile_id": "0xa1e0",
          "device_type": "0x0061",
          "input_clusters": [],
          "output_clusters": [
            "0x0021"
          ]
        }
      },
      "manufacturer": "LUMI",
      "model": "lumi.switch.n2aeu1"
    }


⚠ ClamAV has degraded performance

In bd485a3, ClamAV (https://spamassassin.apache.org/) experienced degraded performance:

HTTP code: 200
Response time: 477 ms

Resolved: ClamAV performance has improved in 720cecc.


SARAALERT-539/540/592/621 offer Kor, Vie, Rus, Ara to monitorees

Description
Jira Tickets: SARAALERT-539, SARAALERT-540, SARAALERT-592, SARAALERT-621
Translations can be found here: https://mitre.sharepoint.com/:x:/r/sites/CoVDT/_layouts/15/doc2.aspx?sourcedoc={b7fec298-550c-43cc-8fb4-1f79abc432a1}&cid=edaeb2d5-5bd7-41a7-a17c-bf8d018717fe
TODO:

[ ] get missing translations

(Feature) Demo/Screenshots

Important Changes
Please list important files (meaning substantial or integral to the PR) along with a list of the general changes that should be highlighted for reviewers.
app/mailers/patient_mailer.rb

Update structure of contents due to language grammar/syntax

config/locales/ara.yml, config/locales/kor.yml, config/locales/rus.yml, config/locales/vie.yml

Add new locale files

config/locales/eng.yml, config/locales/fra.yml, config/locales/som.yml, config/locales/spa-pr.yml, config/locales/spa.yml

Update structure of existing locale files

lib/tasks/demo.rake

Better language distribution

Testing Recommendations
Please list any recommendations regarding what reviewers should test and if there is any specific guidance on how to test certain aspects of the PR. Be sure to mention edge cases that should be tried, particularly in the UI.
Checklists
Submitter:

[x] This PR describes why these changes were made.
[x] This PR is into the correct branch.
[x] This PR includes the correct JIRA ticket reference.
[x] Comment added to the relevant JIRA ticket(s) with a link to this PR
[x] Code diff has been reviewed (it does not contain: additional white space, not applicable code changes, debug statements, etc.)
[ ] If UI changes have been made, Chrome Dev Tools Lighthouse accessibility test has been executed to ensure no 508 issues were introduced.
[x] Tests are included and test edge cases
[x] Tests have been run locally and pass (remember to update Gemfile when applicable)
[x] Test fixtures updated and documented as necessary

@tstrass :

[ ] Code is maintainable and reusable, reuses existing code and infrastructure where appropriate, and accomplishes the task’s purpose
[ ] The tests appropriately test the new code, including edge cases
[ ] You have tried to break the code
[ ] If applicable, you have tested changes against a large database, and considered possible performance regressions
[ ] Tested all recommendations listed in the "Testing Recommendations" section. The application behaves as expected with this PR.

@holmesie :

[ ] Code is maintainable and reusable, reuses existing code and infrastructure where appropriate, and accomplishes the task’s purpose
[ ] The tests appropriately test the new code, including edge cases
[ ] You have tried to break the code
[ ] If applicable, you have tested changes against a large database, and considered possible performance regressions
[ ] Tested all recommendations listed in the "Testing Recommendations" section. The application behaves as expected with this PR.

@Bialogs :

[ ] Code is maintainable and reusable, reuses existing code and infrastructure where appropriate, and accomplishes the task’s purpose
[ ] The tests appropriately test the new code, including edge cases
[ ] You have tried to break the code
[ ] If applicable, you have tested changes against a large database, and considered possible performance regressions
[ ] Tested all recommendations listed in the "Testing Recommendations" section. The application behaves as expected with this PR.

Made some updates to tests and fixed an issue with spa-pr in https://github.com/SaraAlert/SaraAlert/pull/1044

This PR needs to be rebased off of the 1.35.2 tag that changed the spa-pr file

This PR needs to be rebased off of the 1.35.2 tag that changed the spa-pr file

@tstrass is 1.36.0 going to be rebased off the 1.35.2 tag? I was planning to just wait for that to happen and then rebase this branch off 1.36.0 again

This PR needs to be rebased off of the 1.35.2 tag that changed the spa-pr file

@tstrass is 1.36.0 going to be rebased off the 1.35.2 tag? I was planning to just wait for that to happen and then rebase this branch off 1.36.0 again

Rebased!


feat: support accelerator key strings , - . Space Tab and F13-F24

What kind of change does this PR introduce? (check at least one)

[ ] Bugfix
[x] Feature
[ ] Code style update
[ ] Refactor
[ ] Documentation
[ ] Build-related changes
[ ] Other, please describe:

Does this PR introduce a breaking change? (check one)

[ ] Yes. Issue #___
[x] No

The PR fulfills these requirements:

[ ] When resolving a specific issue, it's referenced in the PR's title (e.g. fix: #xxx[,#xxx], where "xxx" is the issue number)
[x] A change file is added if any packages will require a version bump due to this PR per the instructions in the readme.

If adding a new feature, the PR's description includes:

[ ] A convincing reason for adding this feature (to avoid wasting your time, it's best to open a suggestion issue first and wait for approval before working on it)

Other information:
Add support for more macOS accelerator key strings: ` \ [ ] , . ' ; / Tab and F13-F35
Don't know how support is for these on Linux/Windows, might be bad if these are inconsistently supported.
Add support for more accelerator keys: , - . Space Tab and F13-F24

You can add these also to other platforms.

Windows - format_hotkey() function in src/platform_impl/windows/menu.rs
Linux - register_accelerator() function in src/platform_impl/linux/menu.rs and key_to_raw_key() function in src/platform_impl/linux/keyboard.rs, (this one is using the gdk keys from here)

Support here is already inconsistent between platforms. Tab and Esc are already supported on Windows, but weren't on macOS. You might think specifying unsupported keys is ok because nothing happens on macOS, but on Windows it actually panics.
On Windows, the format_hotkey() function already works fine, but key_to_vk() in keyboard.rs is what's lacking support. A bunch of keys in winapi don't have an obvious one corresponding to macOS.
The following are keys I didn't manage to add, so I've removed them from the PR:

`
\
[
]
=
'
;
/
F25-F35

Brought Linux up to speed as well. Esc was already supported.
Tab is supposed to already be supported, but it's not working for me (even though it shows up correctly in the menu, and doesn't panic). Not something I'll tackle in this PR tho.

the missing vkeys on windows can be obtained by VkKeyScanW(']' as u16) in key_to_vk function. check how KeyCode::Digit1 is mapped in that function for reference.

Tab and Esc are not necessary imo so you can ignore them.

I think tab is important for keyboard navigation for visually impaired. Right @parker-codes ?

Keyboard navigation using Tab will still work, this PR addresses custom menu Accelerators and possibly global hotkeys.

Yeah, as long as keys like Tab (or Shift + Tab) and Space are usable in general, as in they aren't being overridden, we're good.
It sounds like this is for combinations and shortcuts which doesn't seem like an issue to me. In fact, that can increase accessibility by allowing apps to offer quicker access!

the missing vkeys on windows can be obtained by VkKeyScanW(']' as u16) in key_to_vk function. check how KeyCode::Digit1 is mapped in that function for reference.

Will try that out, thanks!
About Tab, it's just on Linux that it's not working. Windows already supports it fine, and macOS support is added in this PR. Opened issue #242 for it.

All good now!


Feat: Skip Block SDK

https://github.com/neutron-org/neutron-tests/actions/runs/7727350803

https://github.com/neutron-org/neutron-tests/actions/runs/7727350803


Conditional color fill not supported in BarChart

Hi,
I'm trying to reproduce a similar bar chart like the following figure:

Here is the data:
data = [
    {"dmu": "dmu1", "Efficiency score": 100, "Status": "Efficient" },
    {"dmu": "dmu2", "Efficiency score": 78, "Status": "InEfficient" },
    {"dmu": "dmu3", "Efficiency score": 100, "Status": "Efficient" },
    {"dmu": "dmu4", "Efficiency score": 100, "Status": "Efficient" },
    {"dmu": "dmu5", "Efficiency score": 89, "Status": "InEfficient" },
    {"dmu": "dmu6", "Efficiency score": 95, "Status": "InEfficient" }
]

I ended up in the following piece of code (I'm getting errors):
html.Div(
    [
        dmc.BarChart(
            h=400,
            dataKey="dmu",
            data=data,
            xAxisProps={"padding": {"left": 5, "right": 5}},
            yAxisProps={"padding": {"top": 30, "buttom": 30}},
            gridAxis='y',
            tickLine=None,
            withLegend=True,
            unit="%",
            barProps={
                "radius": 5,
                "isAnimationActive": True,
            },
            orientation="vertical",
            series=[
                {"name": "Status", "color": "violet.6"},
            ],
        )
    ]
)

Tbh, I have no idea how to reproduce the above figure using barChart of dmc!

Hi @AnnMarieW
Ok, I'll ask the question on DMC Discord, too. Thanks for reminding me.
Here is the working example using only recharts in JS:
import React from 'react';
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, Cell } from 'recharts';

const data = [
  { dmu: "dmu1", "Efficiency score": 100, Status: "Efficient" },
  { dmu: "dmu2", "Efficiency score": 78, Status: "InEfficient" },
  { dmu: "dmu3", "Efficiency score": 100, Status: "Efficient" },
  { dmu: "dmu4", "Efficiency score": 100, Status: "Efficient" },
  { dmu: "dmu5", "Efficiency score": 89, Status: "InEfficient" },
  { dmu: "dmu6", "Efficiency score": 95, Status: "InEfficient" },
];

const CustomBarChart = () => (
  <BarChart
    width={600}
    height={400}
    data={data}
    margin={{ top: 20, right: 30, left: 20, bottom: 5 }}
  >
    <CartesianGrid strokeDasharray="3 3" />
    <XAxis dataKey="dmu" />
    <YAxis />
    <Tooltip />

    {/* Custom Legend */}
    <Legend
      payload={[
        { value: "Efficient", type: "square", id: "ID01", color: "#FFA500" }, // Orange for Efficient
        { value: "InEfficient", type: "square", id: "ID02", color: "#32CD32" }, // Green for InEfficient
      ]}
    />

    <Bar dataKey="Efficiency score">
      {data.map((entry, index) => (
        <Cell
          key={`cell-${index}`}
          fill={entry.Status === "Efficient" ? "#FFA500" : "#32CD32"} // Orange for Efficient, Green for InEfficient
        />
      ))}
    </Bar>
  </BarChart>
);

export default CustomBarChart;

(At this moment a horizontal or vertical bar chart is not important for me)

That's helpful - in dash, you can't pass functions as props, so it's knot possible to do something like this in dmc right now:
 fill={entry.Status === "Efficient" ? "#FFA500" : "#32CD32"} // Orange for Efficient, Green for InEfficient

There are some workarounds for this, but it will be a big change and might take a while.  It's on the wish list here #356

I tried different settings and finally found the solution with the current capabilities of the DMC:

First I changed the dataset into this by adding a color item:
data = [
    {"dmu": "dmu1", "Efficiency score": 100,
        "Status": "Efficient", "color": "#32CD32"},
    {"dmu": "dmu2", "Efficiency score": 78,
        "Status": "InEfficient", "color": "#FFA500"},
    {"dmu": "dmu3", "Efficiency score": 100,
        "Status": "Efficient", "color": "#32CD32"},
    {"dmu": "dmu4", "Efficiency score": 100,
        "Status": "Efficient", "color": "#32CD32"},
    {"dmu": "dmu5", "Efficiency score": 89,
        "Status": "InEfficient", "color": "#FFA500"},
    {"dmu": "dmu6", "Efficiency score": 95,
        "Status": "InEfficient", "color": "#FFA500"},
]

Then, I removed the color property from the series. Next, I passed the payload item on to legendProps for legend customization.
html.Div(
    [

        dmc.BarChart(
            h=400,
            dataKey="dmu",
            data=data,
            xAxisProps={"padding": {"left": 5, "right": 5}},
            yAxisProps={"padding": {"top": 30, "buttom": 30}},
            gridAxis='y',
            tickLine=None,
            withLegend=True,
            legendProps={"payload":
                            [
                             {"dataKey": "Efficient", "type": "square",
                                 "id": "ID01", "color": "#32CD32"},
                             {"dataKey": "InEfficient", "type": "square",
                                 "id": "ID02", "color": "#FFA500"},
                         ],
                         },
            unit="%",
            barProps={
                "radius": 5,
                "isAnimationActive": True,
            },
            orientation="vertical",
            series=[
                {"name": "Efficiency score"},
            ],
        )
    ],
)


Use the same actor systems in production and testing

Removes the need to manually align test harness whenever actor systems get
expanded.
Soon actor systems will be storing remote handles as well, and they will not be
public.

Need this for debugging.
bors r+


Add cascade animation/staggered entrance for tiles in example app

In the example app, create an animation so that the tiles fade from opacity: 0 to opacity: 1 in a staggered fashion when the page loads. I'm envisioning having them fade in one row at a time from top to bottom (this will require calculating how many tiles are in a row based on the width of grid at various screen sizes), but open to trying anything that looks good!

@lizisawizard I've been meaning to get to this but haven't yet... feel free to assign yourself if you want to work on it 😄

For reference, if it's helpful: https://codepen.io/kristastarr/pen/xxqgrdM/e666a5493f68754ef05cb181b0af875a


Update infra-mirror-bucket Terraform version from 0.11.15 to 0.13.6

This is blocking #1689 - we cannot upgrade the lambda's Node version without upgrading the AWS terraform provider, and we can't do that without upgrading Terraform itself to at least v1.1, and we can't jump straight to 1.1 without doing the 'major' upgrade to 0.13 first. Hence this PR.
Trello: https://trello.com/c/PMsAXSoT/3029-review-govuks-usage-of-node-2

I've split this PR into two: #1691 and #1692


In-place update of Service Account permissions once IAM Policy changes

What would you like to be added:
Service Account permissions should be updated in place once IAM Policies associated with Service Account-bound IAM Role change. That'd probably mean resetting Pod's access token if I'm not mistaken?
Why is this needed:
Currently we need to restart the Pod once there are changes to relevant IAM Policies. That'd be great if this change was picked up automatically. As a side question - are there any workarounds other than restarting Pods? One more solution I can think of is making the token expiration time shorter. Anything else that I've missed?

AFAIK the token being injected does not contain any permissions. It is only used to obtain role credentials from IAM. This means that changing the role's permissions should work as usual. (Based on experience it may take a few minutes for the change to fully apply.)