Skip to content

Commit 4fcf1c1

Browse files
authored
Add Paulmann 501.34 4-button remote support (#1678)
Co-authored-by: Matthias Strauss <[email protected]>
1 parent eeaea57 commit 4fcf1c1

File tree

4 files changed

+261
-0
lines changed

4 files changed

+261
-0
lines changed

tests/test_paulmann.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
"""Tests for Paulmann quirks."""
2+
3+
import zhaquirks.paulmann.fourbtnremote
4+
5+
6+
def test_fourbtnremote_signature(assert_signature_matches_quirk):
7+
"""Test PaulmannRemote4Btn signature is matched to its quirk."""
8+
signature = {
9+
"node_descriptor": "NodeDescriptor(logical_type=<LogicalType.EndDevice: 2>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress: 128>, manufacturer_code=4644, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=True, *is_full_function_device=False, *is_mains_powered=False, *is_receiver_on_when_idle=False, *is_router=False, *is_security_capable=False)",
10+
"endpoints": {
11+
"1": {
12+
"profile_id": 260,
13+
"device_type": "0x0001",
14+
"in_clusters": ["0x0000", "0x0001", "0x0003", "0x0b05", "0x1000"],
15+
"out_clusters": [
16+
"0x0003",
17+
"0x0004",
18+
"0x0005",
19+
"0x0006",
20+
"0x0008",
21+
"0x0019",
22+
"0x0300",
23+
"0x1000",
24+
],
25+
},
26+
"2": {
27+
"profile_id": 260,
28+
"device_type": "0x0001",
29+
"in_clusters": ["0x0000", "0x0001", "0x0003", "0x0b05", "0x1000"],
30+
"out_clusters": [
31+
"0x0003",
32+
"0x0004",
33+
"0x0005",
34+
"0x0006",
35+
"0x0008",
36+
"0x0019",
37+
"0x0300",
38+
"0x1000",
39+
],
40+
},
41+
},
42+
"manufacturer": "Paulmann LichtGmbH",
43+
"model": "501.34",
44+
"class": "paulmann.fourbtnremote.PaulmannRemote4Btn",
45+
}
46+
47+
assert_signature_matches_quirk(
48+
zhaquirks.paulmann.fourbtnremote.PaulmannRemote4Btn, signature
49+
)

tests/test_quirks.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,16 @@ def test_migrated_lighting_automation_triggers(quirk: CustomDevice) -> None:
621621
(const.LONG_RELEASE, const.DIM_DOWN),
622622
]
623623
],
624+
zhaquirks.paulmann.fourbtnremote.PaulmannRemote4Btn: [
625+
[
626+
(const.LONG_RELEASE, const.BUTTON_1),
627+
(const.LONG_RELEASE, const.BUTTON_2),
628+
],
629+
[
630+
(const.LONG_RELEASE, const.BUTTON_3),
631+
(const.LONG_RELEASE, const.BUTTON_4),
632+
],
633+
],
624634
zhaquirks.thirdreality.button.Button: [
625635
[
626636
(const.LONG_PRESS, const.LONG_PRESS),

zhaquirks/paulmann/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"""Paulmann module."""
2+
3+
PAULMANN = "Paulmann LichtGmbH"
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
"""Device handler for Paulmann 4-button remote control."""
2+
from zigpy.profiles import zha
3+
from zigpy.quirks import CustomDevice
4+
from zigpy.zcl.clusters.general import (
5+
Basic,
6+
Groups,
7+
Identify,
8+
LevelControl,
9+
OnOff,
10+
Ota,
11+
PowerConfiguration,
12+
Scenes,
13+
)
14+
from zigpy.zcl.clusters.homeautomation import Diagnostic
15+
from zigpy.zcl.clusters.lighting import Color
16+
from zigpy.zcl.clusters.lightlink import LightLink
17+
18+
from zhaquirks.const import (
19+
BUTTON_1,
20+
BUTTON_2,
21+
BUTTON_3,
22+
BUTTON_4,
23+
CLUSTER_ID,
24+
COMMAND,
25+
COMMAND_MOVE_ON_OFF,
26+
COMMAND_OFF,
27+
COMMAND_ON,
28+
COMMAND_STOP_ON_OFF,
29+
DEVICE_TYPE,
30+
ENDPOINT_ID,
31+
ENDPOINTS,
32+
INPUT_CLUSTERS,
33+
LONG_PRESS,
34+
LONG_RELEASE,
35+
MODELS_INFO,
36+
OUTPUT_CLUSTERS,
37+
PARAMS,
38+
PROFILE_ID,
39+
SHORT_PRESS,
40+
)
41+
from zhaquirks.paulmann import PAULMANN
42+
43+
44+
class PaulmannRemote4Btn(CustomDevice):
45+
"""Custom device representing Paulmann 4-button 501.34 remote control."""
46+
47+
signature = {
48+
# <SimpleDescriptor endpoint=1 profile=260 device_type=1
49+
# device_version=0
50+
# input_clusters=[0, 1, 3, 2821, 4096]
51+
# output_clusters=[3, 4, 5, 6, 8, 25, 768, 4096]>
52+
MODELS_INFO: [(PAULMANN, "501.34")],
53+
ENDPOINTS: {
54+
1: {
55+
PROFILE_ID: zha.PROFILE_ID,
56+
DEVICE_TYPE: zha.DeviceType.LEVEL_CONTROL_SWITCH,
57+
INPUT_CLUSTERS: [
58+
Basic.cluster_id,
59+
Diagnostic.cluster_id,
60+
Identify.cluster_id,
61+
LightLink.cluster_id,
62+
PowerConfiguration.cluster_id,
63+
],
64+
OUTPUT_CLUSTERS: [
65+
Color.cluster_id,
66+
Groups.cluster_id,
67+
Identify.cluster_id,
68+
LevelControl.cluster_id,
69+
LightLink.cluster_id,
70+
OnOff.cluster_id,
71+
Ota.cluster_id,
72+
Scenes.cluster_id,
73+
],
74+
},
75+
2: {
76+
PROFILE_ID: zha.PROFILE_ID,
77+
DEVICE_TYPE: zha.DeviceType.LEVEL_CONTROL_SWITCH,
78+
INPUT_CLUSTERS: [
79+
Basic.cluster_id,
80+
Diagnostic.cluster_id,
81+
Identify.cluster_id,
82+
LightLink.cluster_id,
83+
PowerConfiguration.cluster_id,
84+
],
85+
OUTPUT_CLUSTERS: [
86+
Color.cluster_id,
87+
Groups.cluster_id,
88+
Identify.cluster_id,
89+
LevelControl.cluster_id,
90+
LightLink.cluster_id,
91+
OnOff.cluster_id,
92+
Ota.cluster_id,
93+
Scenes.cluster_id,
94+
],
95+
},
96+
},
97+
}
98+
99+
replacement = {
100+
ENDPOINTS: {
101+
1: {
102+
INPUT_CLUSTERS: [
103+
Basic.cluster_id,
104+
Diagnostic.cluster_id,
105+
Identify.cluster_id,
106+
LightLink.cluster_id,
107+
PowerConfiguration.cluster_id,
108+
],
109+
OUTPUT_CLUSTERS: [
110+
Color.cluster_id,
111+
Groups.cluster_id,
112+
Identify.cluster_id,
113+
LevelControl.cluster_id,
114+
LightLink.cluster_id,
115+
OnOff.cluster_id,
116+
Ota.cluster_id,
117+
Scenes.cluster_id,
118+
],
119+
},
120+
2: {
121+
INPUT_CLUSTERS: [
122+
Basic.cluster_id,
123+
Diagnostic.cluster_id,
124+
Identify.cluster_id,
125+
LightLink.cluster_id,
126+
PowerConfiguration.cluster_id,
127+
],
128+
OUTPUT_CLUSTERS: [
129+
Color.cluster_id,
130+
Groups.cluster_id,
131+
Identify.cluster_id,
132+
LevelControl.cluster_id,
133+
LightLink.cluster_id,
134+
OnOff.cluster_id,
135+
Ota.cluster_id,
136+
Scenes.cluster_id,
137+
],
138+
},
139+
}
140+
}
141+
142+
device_automation_triggers = {
143+
(SHORT_PRESS, BUTTON_1): {COMMAND: COMMAND_ON, CLUSTER_ID: 6, ENDPOINT_ID: 1},
144+
(LONG_PRESS, BUTTON_1): {
145+
COMMAND: COMMAND_MOVE_ON_OFF,
146+
CLUSTER_ID: 8,
147+
ENDPOINT_ID: 1,
148+
PARAMS: {"move_mode": 0, "rate": 50},
149+
},
150+
(LONG_RELEASE, BUTTON_1): {
151+
COMMAND: COMMAND_STOP_ON_OFF,
152+
CLUSTER_ID: 8,
153+
ENDPOINT_ID: 1,
154+
},
155+
(SHORT_PRESS, BUTTON_2): {COMMAND: COMMAND_OFF, CLUSTER_ID: 6, ENDPOINT_ID: 1},
156+
(LONG_PRESS, BUTTON_2): {
157+
COMMAND: COMMAND_MOVE_ON_OFF,
158+
CLUSTER_ID: 8,
159+
ENDPOINT_ID: 1,
160+
PARAMS: {"move_mode": 1, "rate": 50},
161+
},
162+
(LONG_RELEASE, BUTTON_2): {
163+
COMMAND: COMMAND_STOP_ON_OFF,
164+
CLUSTER_ID: 8,
165+
ENDPOINT_ID: 1,
166+
},
167+
(SHORT_PRESS, BUTTON_3): {
168+
COMMAND: COMMAND_ON,
169+
CLUSTER_ID: 6,
170+
ENDPOINT_ID: 2,
171+
},
172+
(LONG_PRESS, BUTTON_3): {
173+
COMMAND: COMMAND_MOVE_ON_OFF,
174+
CLUSTER_ID: 8,
175+
ENDPOINT_ID: 2,
176+
PARAMS: {"move_mode": 0, "rate": 50},
177+
},
178+
(LONG_RELEASE, BUTTON_3): {
179+
COMMAND: COMMAND_STOP_ON_OFF,
180+
CLUSTER_ID: 8,
181+
ENDPOINT_ID: 2,
182+
},
183+
(SHORT_PRESS, BUTTON_4): {
184+
COMMAND: COMMAND_OFF,
185+
CLUSTER_ID: 6,
186+
ENDPOINT_ID: 2,
187+
},
188+
(LONG_PRESS, BUTTON_4): {
189+
COMMAND: COMMAND_MOVE_ON_OFF,
190+
CLUSTER_ID: 8,
191+
ENDPOINT_ID: 2,
192+
PARAMS: {"move_mode": 1, "rate": 50},
193+
},
194+
(LONG_RELEASE, BUTTON_4): {
195+
COMMAND: COMMAND_STOP_ON_OFF,
196+
CLUSTER_ID: 8,
197+
ENDPOINT_ID: 2,
198+
},
199+
}

0 commit comments

Comments
 (0)