Skip to content

Commit eadd1bd

Browse files
authored
Globally allow Aqara devices to handle swapped ZCL header direction (#4223)
* Globally allow Aqara devices to handle swapped ZCL header direction * Use exceptions instead of verbose logic * Add a test
1 parent 81e543a commit eadd1bd

File tree

3 files changed

+46
-17
lines changed

3 files changed

+46
-17
lines changed

tests/test_xiaomi.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2257,3 +2257,24 @@ def test_t1m_ceiling_light(zigpy_device_from_v2_quirk, endpoint):
22572257
== AqaraLightT1M.AttributeDefs.power_on_state.id
22582258
)
22592259
assert cluster_listener.attribute_updates[1][1] == LumiPowerOnStateMode.Off
2260+
2261+
2262+
async def test_lumi_magnet_sensor_aq2_bad_direction(zigpy_device_from_quirk):
2263+
"""Test Aqara Magnet Sensor AQ2 quirk dealing with bad ZCL command direction."""
2264+
2265+
device = zigpy_device_from_quirk(zhaquirks.xiaomi.aqara.magnet_aq2.MagnetAQ2)
2266+
listener = ClusterListener(device.endpoints[1].out_clusters[OnOff.cluster_id])
2267+
2268+
# The device has a bad ZCL header and reports the incorrect direction for commands
2269+
device.packet_received(
2270+
t.ZigbeePacket(
2271+
profile_id=260,
2272+
cluster_id=6,
2273+
src_ep=1,
2274+
dst_ep=1,
2275+
data=t.SerializableBytes(bytes.fromhex("18930A00001001")),
2276+
)
2277+
)
2278+
2279+
# Our matching logic should be forgiving
2280+
assert listener.attribute_updates == [(0, t.Bool.true)]

zhaquirks/xiaomi/__init__.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from zigpy.profiles import zha
1313
from zigpy.quirks import CustomCluster, CustomDevice
1414
from zigpy.typing import AddressingMode
15-
from zigpy.zcl import foundation
15+
from zigpy.zcl import Cluster, foundation
1616
from zigpy.zcl.clusters.general import (
1717
AnalogInput,
1818
Basic,
@@ -122,6 +122,30 @@ def __init__(self, *args, **kwargs):
122122
self.battery_size = BatterySize.CR2032
123123
super().__init__(*args, **kwargs)
124124

125+
def _find_zcl_cluster(
126+
self, hdr: foundation.ZCLHeader, packet: t.ZigbeePacket
127+
) -> Cluster:
128+
"""Find a cluster for the packet."""
129+
130+
# Aqara devices seem to be very lax with their ZCL header's `direction` field,
131+
# we should try "flipping" it if matching doesn't work normally.
132+
try:
133+
return super()._find_zcl_cluster(hdr, packet)
134+
except KeyError:
135+
_LOGGER.debug(
136+
"Packet is coming in the wrong direction for cluster %s on endpoint %s,"
137+
" swapping direction and trying again"
138+
)
139+
140+
return super()._find_zcl_cluster(
141+
hdr.replace(
142+
frame_control=hdr.frame_control.replace(
143+
direction=hdr.frame_control.direction.flip()
144+
)
145+
),
146+
packet,
147+
)
148+
125149

126150
class XiaomiQuickInitDevice(XiaomiCustomDevice, QuickInitDevice):
127151
"""Xiaomi devices eligible for QuickInit."""

zhaquirks/xiaomi/aqara/magnet_agl02.py

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
"""Quirk for Aqara T1 door sensor lumi.magnet.agl02."""
22

33
from zigpy.profiles import zha
4-
import zigpy.types as t
5-
from zigpy.zcl import Cluster, foundation
64
from zigpy.zcl.clusters.general import Basic, Identify, OnOff, Ota, PowerConfiguration
75
from zigpy.zcl.clusters.security import IasZone
86

@@ -31,20 +29,6 @@ def __init__(self, *args, **kwargs):
3129
self.battery_size = BatterySize.CR1632
3230
super().__init__(*args, **kwargs)
3331

34-
def _find_zcl_cluster(
35-
self, hdr: foundation.ZCLHeader, packet: t.ZigbeePacket
36-
) -> Cluster:
37-
"""Find a cluster for the packet."""
38-
assert packet.src_ep is not None
39-
endpoint = self.endpoints[packet.src_ep]
40-
41-
# The `direction` field is incorrectly set, we should always route the packet
42-
# to client `OnOff` cluster
43-
if packet.cluster_id == OnOff.cluster_id:
44-
return endpoint.out_clusters[packet.cluster_id]
45-
46-
return super()._find_zcl_cluster(hdr, packet)
47-
4832
signature = {
4933
MODELS_INFO: [("LUMI", "lumi.magnet.agl02")],
5034
ENDPOINTS: {

0 commit comments

Comments
 (0)