Skip to content

Intercept IKEA BILRESA triggers and replace ZHA events - #4991

Draft
MacBassett wants to merge 3 commits into
zigpy:devfrom
MacBassett:dev
Draft

Intercept IKEA BILRESA triggers and replace ZHA events#4991
MacBassett wants to merge 3 commits into
zigpy:devfrom
MacBassett:dev

Conversation

@MacBassett

@MacBassett MacBassett commented May 11, 2026

Copy link
Copy Markdown

Proposed change

Fix remote_button_long_press and remote_button_double_press device triggers for the IKEA BILRESA 2-button remote (09B9) — both never fired, only long_release worked.

long_press fix (IkeaBilresaLevelControl in zhaquirks/ikea/__init__.py):
The cluster was intercepting move/move_with_on_off commands and storing direction state, but never emitting a ZHA event. Added move_up_press / move_down_press synthetic event emission in the move handler. Trigger map in bilresa2btn.py updated to match the new named commands (removing PARAMS).

double_press fix (IkeaBilresaScenesCluster in zhaquirks/ikea/__init__.py):
ZHA's device trigger layer cannot match triggers that require PARAMS due to a bug in HA core: CommandSchema.as_dict() includes an inherited command field not present in the quirk's PARAMS definition, causing voluptuous PREVENT_EXTRA to reject the event. A fix has been submitted to HA core in home-assistant/core#170483.

As a workaround (and to support HA versions before that fix ships), IkeaBilresaScenesCluster emits double_press_dim_up / double_press_dim_down as param-free named events — the same no-PARAMS pattern already used by long_release. Once the core fix is merged and released, this class can be removed and bilresa2btn.py reverted to use COMMAND_PRESS + PARAMS.

Additional information

Tested on real hardware (IKEA BILRESA 09B9, HA 2026.5.x, ZHA). All 8 device trigger types verified working after the fix.

Device diagnostics

Not included — this PR fixes existing clusters for an existing quirk, no new device registration.

Checklist

  • The changes are tested and work correctly
  • pre-commit checks pass / the code has been formatted using Black
  • Tests have been added to verify that the new code works
  • Device diagnostics data has been attached

long_press (DIM_UP/DIM_DOWN):
- IkeaBilresaLevelControl was intercepting move/move_with_on_off commands
  without emitting any ZHA event, so the device trigger never fired.
  Now emits move_up_press / move_down_press synthetic events.
- Trigger map updated to match the new named commands (no PARAMS).

double_press (DIM_UP/DIM_DOWN):
- ZHA's device trigger layer cannot match events that require PARAMS
  (broken in HA 2026.5.x). Added IkeaBilresaScenesCluster which intercepts
  the press command (0x0007) and emits double_press_dim_up /
  double_press_dim_down as param-free named events.
- Trigger map updated to match the new named commands (no PARAMS).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@codecov

codecov Bot commented May 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.08%. Comparing base (69bdc15) to head (b22e2f3).
⚠️ Report is 31 commits behind head on dev.

Additional details and impacted files
@@           Coverage Diff           @@
##              dev    #4991   +/-   ##
=======================================
  Coverage   93.07%   93.08%           
=======================================
  Files         401      401           
  Lines       13306    13317   +11     
=======================================
+ Hits        12385    12396   +11     
  Misses        921      921           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Mac Bassett and others added 2 commits May 11, 2026 19:15
@MattWestb

Copy link
Copy Markdown
Contributor

I have seen the error but have not digging in it then have testing firmware update of IKEAs gen 4 devices also Bilresa Dual looks working OK only the errors then adding automation and they have fixing one bug that was making commands not working OK from button 1 in the test and latest firmware in Thread mode.

Do you have getting one scroll wheel ?
Have testing getting the group (2 and 3) selecting working in Zigbee mode then Z2M is having it working with toushlink but was not having luck with it.

Great work done !!!

@MacBassett

Copy link
Copy Markdown
Author

@MattWestb IKEA E2490 BILRESA Scroll Wheel — Home Assistant Blueprint https://gist.github.com/MacBassett/76c3e64287c3b58720639b04915abc7e

class IkeaBilresaScenesCluster(ScenesCluster):
"""Scenes cluster for BILRESA: emits distinct events for double-press up/down.

Replaces PARAMS-based matching (broken in ZHA's device trigger layer) with

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is really broken in ZHA or HA, we should fix that, instead of working around it here and sending different events.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed — fix is now in HA core: home-assistant/core#170483. See the comment above for the full analysis of why PARAMS matching fails (extra fields from CommandSchema.as_dict() cause PREVENT_EXTRA to reject the event).

IkeaBilresaScenesCluster is explicitly marked as a workaround in the PR description and can be removed once the core fix ships. IkeaBilresaLevelControl is a separate quirk bug (move commands were swallowed without emitting any event) and needs to stay.

@TheJulianJES TheJulianJES changed the title fix(ikea): fix BILRESA long_press and double_press device triggers Intercept IKEA BILRESA triggers and replace ZHA events May 12, 2026
@TheJulianJES

Copy link
Copy Markdown
Collaborator

Can you listen to zha_event in HA Settings -> Developer tools -> Events -> Subscribe to zha_event?
Without the custom quirk installed, trigger the (long) button presses and post the zha_event output here.

@TheJulianJES
TheJulianJES marked this pull request as draft May 12, 2026 03:58
@MattWestb

Copy link
Copy Markdown
Contributor

Without custom quirk but with latest ZHA:
3 times then holding

event_type: zha_event
data:
  device_ieee: 10:35:97:00:00:18:65:a6
  device_id: c0d1b0a87314c4998cf21fb2a650097a
  unique_id: 10:35:97:00:00:18:65:a6:1:0x0008
  endpoint_id: 1
  cluster_id: 8
  command: move
  args:
    - 0
    - 83
  params:
    move_mode: 0
    rate: 83
    options_mask: null
    options_override: null
origin: LOCAL
time_fired: "2026-05-12T10:38:05.120164+00:00"
context:
  id: 01KRDW7TT0989P3VMTQSJEDMCV
  parent_id: null
  user_id: null

@MacBassett

Copy link
Copy Markdown
Author

@TheJulianJES @MattWestb — MattWestb's raw event confirms the root cause.

The trigger's PARAMS definition for long_press is {move_mode: 0}, but CommandSchema.as_dict() returns every field in the struct including inherited ones: {move_mode: 0, rate: 83, options_mask: null, options_override: null}. HA core passes this dict as a nested value in the event-data filter, which triggers a voluptuous sub-schema with PREVENT_EXTRA. The extra fields (rate, options_mask, options_override) are not in the quirk's PARAMS definition, so the event is rejected before the action fires.

I've submitted a fix to HA core: home-assistant/core#170483. It strips PARAMS from the voluptuous filter and applies subset matching instead, so extra fields in the emitted event are ignored.

On the two changes in this PR:

  • IkeaBilresaLevelControl is still needed regardless of the core fix. The cluster was correctly intercepting move/move_with_on_off to track direction state, but never calling zha_send_event on those commands — only on stop. No ZHA event was ever emitted, so there was nothing for a device trigger to match. This is a quirk bug, not a core bug.

  • IkeaBilresaScenesCluster is the workaround for the core bug, as noted in the PR description. Once Fix ZHA PARAMS-based device trigger matching home-assistant/core#170483 ships, this class can be removed and the trigger map reverted to use COMMAND_PRESS + PARAMS.

@TheJulianJES TheJulianJES left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry, but most of what your AI seems to be writing is completely false.

I think this is just an issue with cluster_id being a zigpy type and not a plain int. But that only causes an issue with voluptuous if PARAMS is also provided, as we only build a schema in Core here then: https://github.com/home-assistant/core/blob/2e738e22d2475aa0d905f97bdd76bc276067a5f2/homeassistant/components/homeassistant/triggers/event.py#L77-L88 (where voluptuous is strict)

To verify this, please replace CLUSTER_ID: LevelControl.cluster_id with CLUSTER_ID: 8, and see if the device triggers start working then.

If that's the case, we'd just need to convert the zigpy types to primitive ones. I guess we could either do that in ZHA (zha.zigbee.device:get_device_automation_triggers), in HA Core (homeassistant.components.zha.device_trigger), or possibly even in zigpy for v2 quirks only in zigpy.quirks.v2:recursive_freeze – I think one of the first options is better though.)

@zigpy-review-bot zigpy-review-bot added the bot: unclear LLM is unsure about PR state label Jul 17, 2026
@zigpy-review-bot zigpy-review-bot added bot: needs changes PR needs changes per LLM bot: 2.0 migration needed PR needs ZHA/quirks 2.0.0 migration per LLM bugfix This PR fixes a bug bot: needs maintainer PR does something questionable that needs a maintainer decision per LLM and removed bot: unclear LLM is unsure about PR state labels Jul 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot: needs changes PR needs changes per LLM bot: needs maintainer PR does something questionable that needs a maintainer decision per LLM bot: 2.0 migration needed PR needs ZHA/quirks 2.0.0 migration per LLM bugfix This PR fixes a bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants