Strip _CLIENT suffix from ZHA event unique_id (#145006)

This commit is contained in:
puddly 2025-05-16 04:25:24 -04:00 committed by GitHub
parent 9bbc49e842
commit 053e5417a7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 78 additions and 1 deletions

View File

@ -419,13 +419,26 @@ class ZHADeviceProxy(EventBase):
@callback @callback
def handle_zha_event(self, zha_event: ZHAEvent) -> None: def handle_zha_event(self, zha_event: ZHAEvent) -> None:
"""Handle a ZHA event.""" """Handle a ZHA event."""
if ATTR_UNIQUE_ID in zha_event.data:
unique_id = zha_event.data[ATTR_UNIQUE_ID]
# Client cluster handler unique IDs in the ZHA lib were disambiguated by
# adding a suffix of `_CLIENT`. Unfortunately, this breaks existing
# automations that match the `unique_id` key. This can be removed in a
# future release with proper notice of a breaking change.
unique_id = unique_id.removesuffix("_CLIENT")
else:
unique_id = zha_event.unique_id
self.gateway_proxy.hass.bus.async_fire( self.gateway_proxy.hass.bus.async_fire(
ZHA_EVENT, ZHA_EVENT,
{ {
ATTR_DEVICE_IEEE: str(zha_event.device_ieee), ATTR_DEVICE_IEEE: str(zha_event.device_ieee),
ATTR_UNIQUE_ID: zha_event.unique_id,
ATTR_DEVICE_ID: self.device_id, ATTR_DEVICE_ID: self.device_id,
**zha_event.data, **zha_event.data,
# The order of these keys is intentional, `zha_event.data` can contain
# a `unique_id` key, which we explicitly replace
ATTR_UNIQUE_ID: unique_id,
}, },
) )

View File

@ -258,3 +258,67 @@ async def test_invalid_zha_event_type(
# `zha_send_event` accepts only zigpy responses, lists, and dicts # `zha_send_event` accepts only zigpy responses, lists, and dicts
with pytest.raises(TypeError): with pytest.raises(TypeError):
cluster_handler.zha_send_event(COMMAND_SINGLE, 123) cluster_handler.zha_send_event(COMMAND_SINGLE, 123)
async def test_client_unique_id_suffix_stripped(
hass: HomeAssistant, setup_zha, zigpy_device_mock
) -> None:
"""Test that the `_CLIENT_` unique ID suffix is stripped."""
assert await async_setup_component(
hass,
automation.DOMAIN,
{
automation.DOMAIN: {
"trigger": {
"platform": "event",
"event_type": "zha_event",
"event_data": {
"unique_id": "38:5b:44:ff:fe:a7:cc:69:1:0x0006", # no `_CLIENT` suffix
"endpoint_id": 1,
"cluster_id": 6,
"command": "on",
"args": [],
"params": {},
},
},
"action": {"service": "zha.test"},
}
},
)
service_calls = async_mock_service(hass, DOMAIN, "test")
await setup_zha()
gateway = get_zha_gateway(hass)
zigpy_device = zigpy_device_mock(
{
1: {
SIG_EP_INPUT: [
general.Basic.cluster_id,
security.IasZone.cluster_id,
security.IasWd.cluster_id,
],
SIG_EP_OUTPUT: [general.OnOff.cluster_id],
SIG_EP_TYPE: zha.DeviceType.ON_OFF_SWITCH,
SIG_EP_PROFILE: zha.PROFILE_ID,
}
}
)
zha_device = gateway.get_or_create_device(zigpy_device)
await gateway.async_device_initialized(zha_device.device)
zha_device.emit_zha_event(
{
"unique_id": "38:5b:44:ff:fe:a7:cc:69:1:0x0006_CLIENT",
"endpoint_id": 1,
"cluster_id": 6,
"command": "on",
"args": [],
"params": {},
}
)
await hass.async_block_till_done(wait_background_tasks=True)
assert len(service_calls) == 1