Custom ZHA Quirks: Aqara H1 EU + Sonoff ZBM5 — Decoupled/Detach Relay Mode

Two custom quirks that add decoupled/detach relay mode to the Aqara Smart Wall Switch H1 EU (lumi.switch.l2aeu1) and Sonoff ZBM5 series (1/2/3-gang) in ZHA. Both tested on HA 2026.3.1.

The Problem

If you have smart bulbs (Philips Hue, IKEA, etc.) wired to an in-wall switch, you know the issue: toggling the switch cuts power to the bulb, making it unavailable in ZHA/Z2M and breaking automations. The solution is decoupled/detach relay mode — the button fires Zigbee events without toggling the relay, so power stays on and the smart bulb stays reachable.

Both devices support this feature, but ZHA doesn’t expose it out of the box. These quirks fix that.


Quirk 1 — Aqara H1 EU (lumi.switch.l2aeu1, no-neutral, 2-gang)

What it fixes: ZHA’s built-in AqaraH1DoubleRockerSwitchNoNeutral quirk handles relays and power metering, but has two gaps:

  1. No UI to set decoupled mode per button
  2. In decoupled mode, button presses are silently dropped — no zha_event fires at all

How it works:

  • OppleSwitchClusterWithInit — subclasses OppleSwitchCluster (0xFCC0) and overrides async_initialize_cluster_handler_specific() to explicitly read operation_mode (attr 0x0200) from the device. Without this, QuirkBuilder.enum() creates the select entity but it stays unavailable forever because EndDevices don’t self-report manufacturer-specific clusters.
  • MultistateInputEventCluster — subclasses MultistateInput on EP41 (button 1) and EP42 (button 2), intercepts _update_attribute() for present_value (attr 0x0055), and fires it as a zha_event via listener_event("zha_send_event", ...). This is what makes decoupled button presses visible to automations.

What you get:

  • select.<device>_operation_mode (EP1) — button 1: Coupled / Decoupled
  • select.<device>_operation_mode_2 (EP2) — button 2: Coupled / Decoupled

ZHA events fired (decoupled mode):

yaml

event_type: zha_event
event_data:
  device_ieee: "xx:xx:xx:xx:xx:xx:xx:xx"
  endpoint_id: 41   # button 1 (left/top)
  endpoint_id: 42   # button 2 (right/bottom)
  cluster_id: 18    # 0x0012 MultistateInput
  command: attribute_updated
  args:
    attribute_id: 85
    attribute_name: present_value
    value: 1   # 1=single press, 2=double press, 3=hold

Automation trigger:

yaml

trigger:
  - platform: event
    event_type: zha_event
    event_data:
      device_ieee: "xx:xx:xx:xx:xx:xx:xx:xx"
      endpoint_id: 42        # 41=button1, 42=button2
      command: attribute_updated
      args:
        value: 1             # 1=single, 2=double, 3=hold
action:
  - action: light.toggle
    target:
      entity_id: light.your_smart_bulb

Important: When a button is set to Decoupled, its relay must stay ON (power to the smart bulb). The relay entity (light.<device>_swiatlo_2) should be hidden from the UI to prevent accidentally switching it off.

Installation:

  1. Copy quirk to /config/custom_zha_quirks/aqara_h1_l2aeu1.py
  2. Full HA restart
  3. Device page → Reconfigure
  4. Set desired button to “Decoupled”
    HomeAssistant/zha_custom_quirks/aqara_h1_l2aeu1.py at 4fb176978d1c50c0c16eac4d59f19deb58e75771 · jrfigura/HomeAssistant · GitHub

Quirk 2 — Sonoff ZBM5 series (1/2/3-gang)

Supported models: ZBM5-1C-80/86, ZBM5-2C-80/86, ZBM5-3C-80/86

Requirements: Neutral wire connected. Without neutral, detach relay is firmware-locked on this device.

Cluster layout (confirmed from ZHA diagnostics on both 2C and 3C):

  • EP1 only has 0xfc11 (Sonoff private cluster) — this is by design
  • EP2 and EP3 have only standard clusters + 0xfc57 (purpose unknown)
  • All per-channel detach relay settings live in 0xfc11 on EP1 as separate attributes

Attribute IDs in 0xfc11:

  • 0x0001 — channel 1 detach relay (confirmed)
  • 0x0002 — channel 2 detach relay (inferred — needs community confirmation with neutral wire)
  • 0x0003 — channel 3 detach relay (inferred — needs community confirmation with neutral wire)
  • Values: 0x00 = Attached (default), 0x01 = Detached

Key difference from Aqara: In detach mode, the Sonoff ZBM5 fires a standard ZCL OnOff toggle command (cluster 0x0006) on the corresponding endpoint — no custom event cluster needed. This means it automatically appears as a proper ZHA device trigger in the HA automation UI.

ZHA events fired (detach mode):

yaml

event_type: zha_event
event_data:
  device_ieee: "xx:xx:xx:xx:xx:xx:xx:xx"
  endpoint_id: 1   # channel 1
  endpoint_id: 2   # channel 2
  endpoint_id: 3   # channel 3
  cluster_id: 6    # OnOff
  command: toggle

Installation: Same as above — copy to /config/custom_zha_quirks/sonoff_zbm5.py, full restart, Reconfigure.

For the Sonoff ZBM5: Attribute IDs 0x0002 and 0x0003 for channels 2 and 3 are inferred based on the pattern from other Sonoff devices. If you have a ZBM5-2C or ZBM5-3C with neutral wire connected, please test and report back whether setting ch2/ch3 to Detached works. If those attribute IDs are wrong, please share your ZHA diagnostics JSON (device page → three dots → Download diagnostics) and I’ll update the quirk.

For the Aqara H1: Works confirmed on lumi.switch.l2aeu1 (WS-EUK02, no-neutral). If you have the neutral version or the single-gang EU model, please share your diagnostics — the model string might differ and a separate QuirkBuilder entry would be needed.

For the Sonoff ZBM5 series at least, there is already a better quirk available here: https://github.com/zigpy/zha-device-handlers/blob/380135de45afec4ec34a7d1572d4d9de668d0206/zhaquirks/sonoff/zbm5.py.

Also - it appears that this was somewhat of a vibe-coding attempt with a clear Claude.ai fingerprint. While I appreciate the attempt, code written either by or with the assistance of AI, should come with a description flagging it as such.

Regarding the quirk itself, the async_initialize_cluster_handler_specific method is being used when the proper one would be apply_custom_configuration - that is just what I noticed after a quick review - possibly there is more that is broken with this that I missed.