Skip to content

Commit fb6e9aa

Browse files
committed
Add quirk for Schneider Electric Wiser dimmer
1 parent 9843db2 commit fb6e9aa

File tree

2 files changed

+206
-0
lines changed

2 files changed

+206
-0
lines changed

tests/test_schneiderelectric.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from zigpy.zcl import foundation
55
from zigpy.zcl.clusters.closures import WindowCovering
66

7+
import zhaquirks.schneiderelectric.dimmers
78
import zhaquirks.schneiderelectric.shutters
89

910
from tests.common import ClusterListener
@@ -132,3 +133,61 @@ async def test_1gang_shutter_1_lift_percentage_updates(zigpy_device_from_quirk):
132133
23, # 100 - 77
133134
)
134135
assert len(cluster_listener.cluster_commands) == 0
136+
137+
138+
def test_nh_rotary_dimmer_1_signature(assert_signature_matches_quirk):
139+
signature = {
140+
"node_descriptor": (
141+
"NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, "
142+
"user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, "
143+
"mac_capability_flags=<MACCapabilityFlags.FullFunctionDevice|MainsPowered|RxOnWhenIdle|"
144+
"AllocateAddress: 142>, manufacturer_code=4190, maximum_buffer_size=82, maximum_incoming_transfer_size=82, "
145+
"server_mask=11264, maximum_outgoing_transfer_size=82, "
146+
"descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, "
147+
"*is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, "
148+
"*is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, "
149+
"*is_security_capable=False)"
150+
),
151+
"endpoints": {
152+
"3": {
153+
"profile_id": 0x0104,
154+
"device_type": "0x0101",
155+
"in_clusters": [
156+
"0x0000",
157+
"0x0003",
158+
"0x0004",
159+
"0x0005",
160+
"0x0006",
161+
"0x0008",
162+
"0x0301",
163+
"0x0b05",
164+
],
165+
"out_clusters": ["0x0019"],
166+
},
167+
"21": {
168+
"profile_id": 0x0104,
169+
"device_type": "0x0104",
170+
"in_clusters": ["0x0000", "0x0003", "0x0b05", "0xff17"],
171+
"out_clusters": [
172+
"0x0003",
173+
"0x0004",
174+
"0x0005",
175+
"0x0006",
176+
"0x0008",
177+
"0x0102",
178+
],
179+
},
180+
"242": {
181+
"profile_id": 0xA1E0,
182+
"device_type": "0x0061",
183+
"in_clusters": [],
184+
"out_clusters": ["0x0021"],
185+
},
186+
},
187+
"manufacturer": "Schneider Electric",
188+
"model": "NHROTARY/DIMMER/1",
189+
"class": "zigpy.device.Device",
190+
}
191+
assert_signature_matches_quirk(
192+
zhaquirks.schneiderelectric.dimmers.NHRotaryDimmer1, signature
193+
)
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
from typing import Final
2+
3+
from zigpy.profiles import zha
4+
from zigpy.quirks import CustomCluster, CustomDevice
5+
import zigpy.types as t
6+
from zigpy.zcl.clusters.closures import WindowCovering
7+
from zigpy.zcl.clusters.general import (
8+
Basic,
9+
GreenPowerProxy,
10+
Groups,
11+
Identify,
12+
LevelControl,
13+
OnOff,
14+
Ota,
15+
Scenes,
16+
)
17+
from zigpy.zcl.clusters.homeautomation import Diagnostic
18+
from zigpy.zcl.clusters.lighting import Ballast
19+
from zigpy.zcl.foundation import ZCLAttributeDef
20+
21+
from zhaquirks.const import (
22+
DEVICE_TYPE,
23+
ENDPOINTS,
24+
INPUT_CLUSTERS,
25+
MODELS_INFO,
26+
OUTPUT_CLUSTERS,
27+
PROFILE_ID,
28+
)
29+
from zhaquirks.schneiderelectric import SE_MANUF_NAME, SESpecific
30+
31+
32+
class ControlMode(t.enum8):
33+
"""Dimming mode for PUCK/DIMMER/* and NHROTARY/DIMMER/1"""
34+
35+
Auto = 0
36+
RC = 1
37+
RL = 2
38+
RL_LED = 3
39+
40+
41+
class WiserBallast(CustomCluster, Ballast):
42+
class AttributeDefs(Ballast.AttributeDefs):
43+
control_mode: Final = ZCLAttributeDef(
44+
id=0xE000, type=ControlMode, is_manufacturer_specific=True
45+
)
46+
47+
48+
class NHRotaryDimmer1(CustomDevice):
49+
"""NHROTARY/DIMMER/1 by Schneider Electric"""
50+
51+
signature = {
52+
MODELS_INFO: [
53+
(SE_MANUF_NAME, "NHROTARY/DIMMER/1"),
54+
],
55+
ENDPOINTS: {
56+
3: {
57+
PROFILE_ID: zha.PROFILE_ID,
58+
DEVICE_TYPE: zha.DeviceType.DIMMABLE_LIGHT,
59+
INPUT_CLUSTERS: [
60+
Basic.cluster_id,
61+
Identify.cluster_id,
62+
Groups.cluster_id,
63+
Scenes.cluster_id,
64+
OnOff.cluster_id,
65+
LevelControl.cluster_id,
66+
Ballast.cluster_id,
67+
Diagnostic.cluster_id,
68+
],
69+
OUTPUT_CLUSTERS: [
70+
Ota.cluster_id,
71+
],
72+
},
73+
21: {
74+
PROFILE_ID: zha.PROFILE_ID,
75+
DEVICE_TYPE: zha.DeviceType.DIMMER_SWITCH,
76+
INPUT_CLUSTERS: [
77+
Basic.cluster_id,
78+
Identify.cluster_id,
79+
Diagnostic.cluster_id,
80+
SESpecific.cluster_id,
81+
],
82+
OUTPUT_CLUSTERS: [
83+
Identify.cluster_id,
84+
Groups.cluster_id,
85+
Scenes.cluster_id,
86+
OnOff.cluster_id,
87+
LevelControl.cluster_id,
88+
WindowCovering.cluster_id,
89+
],
90+
},
91+
242: {
92+
PROFILE_ID: 0xA1E0,
93+
DEVICE_TYPE: 0x0061,
94+
INPUT_CLUSTERS: [],
95+
OUTPUT_CLUSTERS: [
96+
GreenPowerProxy.cluster_id,
97+
],
98+
},
99+
},
100+
}
101+
replacement = {
102+
ENDPOINTS: {
103+
3: {
104+
PROFILE_ID: zha.PROFILE_ID,
105+
DEVICE_TYPE: zha.DeviceType.DIMMABLE_LIGHT,
106+
INPUT_CLUSTERS: [
107+
Basic.cluster_id,
108+
Identify.cluster_id,
109+
Groups.cluster_id,
110+
Scenes.cluster_id,
111+
OnOff.cluster_id,
112+
LevelControl.cluster_id,
113+
WiserBallast,
114+
Diagnostic.cluster_id,
115+
],
116+
OUTPUT_CLUSTERS: [
117+
Ota.cluster_id,
118+
],
119+
},
120+
21: {
121+
PROFILE_ID: zha.PROFILE_ID,
122+
DEVICE_TYPE: zha.DeviceType.DIMMER_SWITCH,
123+
INPUT_CLUSTERS: [
124+
Basic.cluster_id,
125+
Identify.cluster_id,
126+
Diagnostic.cluster_id,
127+
SESpecific,
128+
],
129+
OUTPUT_CLUSTERS: [
130+
Identify.cluster_id,
131+
Groups.cluster_id,
132+
Scenes.cluster_id,
133+
OnOff.cluster_id,
134+
LevelControl.cluster_id,
135+
WindowCovering.cluster_id,
136+
],
137+
},
138+
242: {
139+
PROFILE_ID: 0xA1E0,
140+
DEVICE_TYPE: 0x0061,
141+
INPUT_CLUSTERS: [],
142+
OUTPUT_CLUSTERS: [
143+
GreenPowerProxy.cluster_id,
144+
],
145+
},
146+
}
147+
}

0 commit comments

Comments
 (0)