Skip to content

Commit 14de93c

Browse files
committed
zhaquirks SINOPE SW2500ZB: Added support for both press and release button events in order to properly support short and long press events.
Also added the pressed button in the event arguments to simplify automations processing it.
1 parent fff11ff commit 14de93c

File tree

6 files changed

+152
-46
lines changed

6 files changed

+152
-46
lines changed

tests/test_sinope.py

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,14 @@
1111

1212
from tests.common import ClusterListener
1313
import zhaquirks
14-
from zhaquirks.const import COMMAND_BUTTON_DOUBLE, COMMAND_BUTTON_HOLD
14+
from zhaquirks.const import (
15+
COMMAND_M_INITIAL_PRESS,
16+
COMMAND_M_LONG_RELEASE,
17+
COMMAND_M_MULTI_PRESS_COMPLETE,
18+
COMMAND_M_SHORT_RELEASE,
19+
TURN_OFF,
20+
TURN_ON,
21+
)
1522
from zhaquirks.sinope import SINOPE_MANUFACTURER_CLUSTER_ID
1623
from zhaquirks.sinope.light import (
1724
SinopeTechnologieslight,
@@ -92,20 +99,22 @@ def _get_packet_data(
9299

93100
@pytest.mark.parametrize("quirk", (SinopeTechnologieslight,))
94101
@pytest.mark.parametrize(
95-
"press_type,exp_event",
102+
"press_type,button,exp_event",
96103
(
97-
(ButtonAction.Single_off, None),
98-
(ButtonAction.Single_on, None),
99-
(ButtonAction.Double_on, COMMAND_BUTTON_DOUBLE),
100-
(ButtonAction.Double_off, COMMAND_BUTTON_DOUBLE),
101-
(ButtonAction.Long_on, COMMAND_BUTTON_HOLD),
102-
(ButtonAction.Long_off, COMMAND_BUTTON_HOLD),
104+
(ButtonAction.Single_off, TURN_OFF, COMMAND_M_INITIAL_PRESS),
105+
(ButtonAction.Single_on, TURN_ON, COMMAND_M_INITIAL_PRESS),
106+
(ButtonAction.Single_release_off, TURN_OFF, COMMAND_M_SHORT_RELEASE),
107+
(ButtonAction.Single_release_on, TURN_ON, COMMAND_M_SHORT_RELEASE),
108+
(ButtonAction.Double_on, TURN_ON, COMMAND_M_MULTI_PRESS_COMPLETE),
109+
(ButtonAction.Double_off, TURN_OFF, COMMAND_M_MULTI_PRESS_COMPLETE),
110+
(ButtonAction.Long_on, TURN_ON, COMMAND_M_LONG_RELEASE),
111+
(ButtonAction.Long_off, TURN_OFF, COMMAND_M_LONG_RELEASE),
103112
# Should gracefully handle broken actions.
104-
(t.uint8_t(0x00), None),
113+
(t.uint8_t(0x00), None, None),
105114
),
106115
)
107116
async def test_sinope_light_switch(
108-
zigpy_device_from_quirk, quirk, press_type, exp_event
117+
zigpy_device_from_quirk, quirk, press_type, button, exp_event
109118
):
110119
"""Test that button presses are sent as events."""
111120
device: Device = zigpy_device_from_quirk(quirk)
@@ -137,6 +146,7 @@ class Listener:
137146
{
138147
"attribute_id": 84,
139148
"attribute_name": "action_report",
149+
"button": button,
140150
"value": press_type.value,
141151
},
142152
)

zhaquirks/sinope/__init__.py

Lines changed: 73 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,18 @@
77
ARGS,
88
ATTRIBUTE_ID,
99
ATTRIBUTE_NAME,
10+
BUTTON,
1011
CLUSTER_ID,
1112
COMMAND,
12-
COMMAND_BUTTON_DOUBLE,
13-
COMMAND_BUTTON_HOLD,
14-
COMMAND_BUTTON_SINGLE,
13+
COMMAND_M_INITIAL_PRESS,
14+
COMMAND_M_LONG_RELEASE,
15+
COMMAND_M_MULTI_PRESS_COMPLETE,
16+
COMMAND_M_SHORT_RELEASE,
1517
DOUBLE_PRESS,
1618
ENDPOINT_ID,
17-
LONG_PRESS,
19+
LONG_RELEASE,
1820
SHORT_PRESS,
21+
SHORT_RELEASE,
1922
TURN_OFF,
2023
TURN_ON,
2124
VALUE,
@@ -29,38 +32,90 @@
2932
(SHORT_PRESS, TURN_ON): {
3033
ENDPOINT_ID: 1,
3134
CLUSTER_ID: 65281,
32-
COMMAND: COMMAND_BUTTON_SINGLE,
33-
ARGS: {ATTRIBUTE_ID: 84, ATTRIBUTE_NAME: ATTRIBUTE_ACTION, VALUE: 2},
35+
COMMAND: COMMAND_M_INITIAL_PRESS,
36+
ARGS: {
37+
ATTRIBUTE_ID: 84,
38+
ATTRIBUTE_NAME: ATTRIBUTE_ACTION,
39+
BUTTON: TURN_ON,
40+
VALUE: 1,
41+
},
3442
},
3543
(SHORT_PRESS, TURN_OFF): {
3644
ENDPOINT_ID: 1,
3745
CLUSTER_ID: 65281,
38-
COMMAND: COMMAND_BUTTON_SINGLE,
39-
ARGS: {ATTRIBUTE_ID: 84, ATTRIBUTE_NAME: ATTRIBUTE_ACTION, VALUE: 18},
46+
COMMAND: COMMAND_M_INITIAL_PRESS,
47+
ARGS: {
48+
ATTRIBUTE_ID: 84,
49+
ATTRIBUTE_NAME: ATTRIBUTE_ACTION,
50+
BUTTON: TURN_OFF,
51+
VALUE: 17,
52+
},
53+
},
54+
(SHORT_RELEASE, TURN_ON): {
55+
ENDPOINT_ID: 1,
56+
CLUSTER_ID: 65281,
57+
COMMAND: COMMAND_M_SHORT_RELEASE,
58+
ARGS: {
59+
ATTRIBUTE_ID: 84,
60+
ATTRIBUTE_NAME: ATTRIBUTE_ACTION,
61+
BUTTON: TURN_ON,
62+
VALUE: 2,
63+
},
64+
},
65+
(SHORT_RELEASE, TURN_OFF): {
66+
ENDPOINT_ID: 1,
67+
CLUSTER_ID: 65281,
68+
COMMAND: COMMAND_M_SHORT_RELEASE,
69+
ARGS: {
70+
ATTRIBUTE_ID: 84,
71+
ATTRIBUTE_NAME: ATTRIBUTE_ACTION,
72+
BUTTON: TURN_OFF,
73+
VALUE: 18,
74+
},
4075
},
4176
(DOUBLE_PRESS, TURN_ON): {
4277
ENDPOINT_ID: 1,
4378
CLUSTER_ID: 65281,
44-
COMMAND: COMMAND_BUTTON_DOUBLE,
45-
ARGS: {ATTRIBUTE_ID: 84, ATTRIBUTE_NAME: ATTRIBUTE_ACTION, VALUE: 4},
79+
COMMAND: COMMAND_M_MULTI_PRESS_COMPLETE,
80+
ARGS: {
81+
ATTRIBUTE_ID: 84,
82+
ATTRIBUTE_NAME: ATTRIBUTE_ACTION,
83+
BUTTON: TURN_ON,
84+
VALUE: 4,
85+
},
4686
},
4787
(DOUBLE_PRESS, TURN_OFF): {
4888
ENDPOINT_ID: 1,
4989
CLUSTER_ID: 65281,
50-
COMMAND: COMMAND_BUTTON_DOUBLE,
51-
ARGS: {ATTRIBUTE_ID: 84, ATTRIBUTE_NAME: ATTRIBUTE_ACTION, VALUE: 20},
90+
COMMAND: COMMAND_M_MULTI_PRESS_COMPLETE,
91+
ARGS: {
92+
ATTRIBUTE_ID: 84,
93+
ATTRIBUTE_NAME: ATTRIBUTE_ACTION,
94+
BUTTON: TURN_OFF,
95+
VALUE: 20,
96+
},
5297
},
53-
(LONG_PRESS, TURN_ON): {
98+
(LONG_RELEASE, TURN_ON): {
5499
ENDPOINT_ID: 1,
55100
CLUSTER_ID: 65281,
56-
COMMAND: COMMAND_BUTTON_HOLD,
57-
ARGS: {ATTRIBUTE_ID: 84, ATTRIBUTE_NAME: ATTRIBUTE_ACTION, VALUE: 3},
101+
COMMAND: COMMAND_M_LONG_RELEASE,
102+
ARGS: {
103+
ATTRIBUTE_ID: 84,
104+
ATTRIBUTE_NAME: ATTRIBUTE_ACTION,
105+
BUTTON: TURN_ON,
106+
VALUE: 3,
107+
},
58108
},
59-
(LONG_PRESS, TURN_OFF): {
109+
(LONG_RELEASE, TURN_OFF): {
60110
ENDPOINT_ID: 1,
61111
CLUSTER_ID: 65281,
62-
COMMAND: COMMAND_BUTTON_HOLD,
63-
ARGS: {ATTRIBUTE_ID: 84, ATTRIBUTE_NAME: ATTRIBUTE_ACTION, VALUE: 19},
112+
COMMAND: COMMAND_M_LONG_RELEASE,
113+
ARGS: {
114+
ATTRIBUTE_ID: 84,
115+
ATTRIBUTE_NAME: ATTRIBUTE_ACTION,
116+
BUTTON: TURN_OFF,
117+
VALUE: 19,
118+
},
64119
},
65120
}
66121

zhaquirks/sinope/light.py

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,24 @@
2929
from zhaquirks.const import (
3030
ATTRIBUTE_ID,
3131
ATTRIBUTE_NAME,
32-
COMMAND_BUTTON_DOUBLE,
33-
COMMAND_BUTTON_HOLD,
32+
BUTTON,
33+
COMMAND_M_INITIAL_PRESS,
34+
COMMAND_M_LONG_RELEASE,
35+
COMMAND_M_MULTI_PRESS_COMPLETE,
36+
COMMAND_M_SHORT_RELEASE,
3437
DEVICE_TYPE,
3538
ENDPOINTS,
3639
INPUT_CLUSTERS,
3740
MODELS_INFO,
3841
OUTPUT_CLUSTERS,
3942
PROFILE_ID,
43+
TURN_OFF,
44+
TURN_ON,
4045
VALUE,
4146
ZHA_SEND_EVENT,
4247
)
43-
from zhaquirks.sinope import (
48+
49+
from . import (
4450
ATTRIBUTE_ACTION,
4551
LIGHT_DEVICE_TRIGGERS,
4652
SINOPE,
@@ -192,27 +198,63 @@ def handle_cluster_general_request(
192198
)
193199

194200
value = attr.value.value
201+
202+
action = self._get_command_from_action(self.Action(value))
203+
button = self._get_button_from_action(self.Action(value))
204+
if not action or not button:
205+
return
206+
195207
event_args = {
196208
ATTRIBUTE_ID: 84,
197209
ATTRIBUTE_NAME: ATTRIBUTE_ACTION,
210+
BUTTON: button,
198211
VALUE: value.value,
199212
}
200-
action = self._get_command_from_action(self.Action(value))
201-
if not action:
202-
return
213+
214+
self.debug(
215+
"SINOPE ZHA_SEND_EVENT action: '%s' event_args: %s",
216+
self.Action(value),
217+
event_args,
218+
)
219+
203220
self.listener_event(ZHA_SEND_EVENT, action, event_args)
204221

205222
def _get_command_from_action(self, action: ButtonAction) -> str | None:
206-
# const lookup = {2: 'up_single', 3: 'up_hold', 4: 'up_double',
207-
# 18: 'down_single', 19: 'down_hold', 20: 'down_double'};
223+
# const lookup = {1: 'up_single', 2: 'up_single_released', 3: 'up_hold', 4: 'up_double',
224+
# 17: 'down_single, 18: 'down_single_released', 19: 'down_hold', 20: 'down_double'};
208225
match action:
209226
case self.Action.Single_off | self.Action.Single_on:
210-
return None
227+
return COMMAND_M_INITIAL_PRESS
228+
case self.Action.Single_release_off | self.Action.Single_release_on:
229+
return COMMAND_M_SHORT_RELEASE
211230
case self.Action.Double_off | self.Action.Double_on:
212-
return COMMAND_BUTTON_DOUBLE
231+
return COMMAND_M_MULTI_PRESS_COMPLETE
213232
case self.Action.Long_off | self.Action.Long_on:
214-
return COMMAND_BUTTON_HOLD
233+
return COMMAND_M_LONG_RELEASE
234+
case _:
235+
self.debug("SINOPE unhandled action: %s", action)
236+
return None
237+
238+
def _get_button_from_action(self, action: ButtonAction) -> str | None:
239+
# const lookup = {1: 'up_single', 2: 'up_single_released', 3: 'up_hold', 4: 'up_double',
240+
# 17: 'down_single, 18: 'down_single_released', 19: 'down_hold', 20: 'down_double'};
241+
match action:
242+
case (
243+
self.Action.Single_off
244+
| self.Action.Single_release_off
245+
| self.Action.Double_off
246+
| self.Action.Long_off
247+
):
248+
return TURN_OFF
249+
case (
250+
self.Action.Single_on
251+
| self.Action.Single_release_on
252+
| self.Action.Double_on
253+
| self.Action.Long_on
254+
):
255+
return TURN_ON
215256
case _:
257+
self.debug("SINOPE unhandled action: %s", action)
216258
return None
217259

218260

zhaquirks/sinope/sensor.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@
3030
OUTPUT_CLUSTERS,
3131
PROFILE_ID,
3232
)
33-
from zhaquirks.sinope import SINOPE, SINOPE_MANUFACTURER_CLUSTER_ID
33+
34+
from . import SINOPE, SINOPE_MANUFACTURER_CLUSTER_ID
3435

3536

3637
class LeakStatus(t.enum8):

zhaquirks/sinope/switch.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,8 @@
4343
OUTPUT_CLUSTERS,
4444
PROFILE_ID,
4545
)
46-
from zhaquirks.sinope import (
47-
SINOPE,
48-
SINOPE_MANUFACTURER_CLUSTER_ID,
49-
CustomDeviceTemperatureCluster,
50-
)
46+
47+
from . import SINOPE, SINOPE_MANUFACTURER_CLUSTER_ID, CustomDeviceTemperatureCluster
5148

5249

5350
class KeypadLock(t.enum8):

zhaquirks/sinope/thermostat.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333
OUTPUT_CLUSTERS,
3434
PROFILE_ID,
3535
)
36-
from zhaquirks.sinope import SINOPE, SINOPE_MANUFACTURER_CLUSTER_ID
36+
37+
from . import SINOPE, SINOPE_MANUFACTURER_CLUSTER_ID
3738

3839

3940
class KeypadLock(t.enum8):

0 commit comments

Comments
 (0)