Skip to content

Commit 2a39c07

Browse files
authored
Add quirk for Schneider Electric NHROTARY/DIMMER/1 (#2955)
1 parent a4c15ef commit 2a39c07

File tree

2 files changed

+214
-0
lines changed

2 files changed

+214
-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: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
from typing import Final
2+
3+
from zigpy.profiles import zgp, 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_ID, SE_MANUF_NAME, SEBasic, 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 SEBallast(CustomCluster, Ballast):
42+
manufacturer_id_override = SE_MANUF_ID
43+
44+
class AttributeDefs(Ballast.AttributeDefs):
45+
control_mode: Final = ZCLAttributeDef(
46+
id=0xE000, type=ControlMode, is_manufacturer_specific=True
47+
)
48+
unknown_attribute_e001: Final = ZCLAttributeDef(
49+
id=0xE002, type=t.enum8, is_manufacturer_specific=True
50+
)
51+
unknown_attribute_e002: Final = ZCLAttributeDef(
52+
id=0xE002, type=t.enum8, is_manufacturer_specific=True
53+
)
54+
55+
56+
class NHRotaryDimmer1(CustomDevice):
57+
"""NHROTARY/DIMMER/1 by Schneider Electric"""
58+
59+
signature = {
60+
MODELS_INFO: [
61+
(SE_MANUF_NAME, "NHROTARY/DIMMER/1"),
62+
],
63+
ENDPOINTS: {
64+
3: {
65+
PROFILE_ID: zha.PROFILE_ID,
66+
DEVICE_TYPE: zha.DeviceType.DIMMABLE_LIGHT,
67+
INPUT_CLUSTERS: [
68+
Basic.cluster_id,
69+
Identify.cluster_id,
70+
Groups.cluster_id,
71+
Scenes.cluster_id,
72+
OnOff.cluster_id,
73+
LevelControl.cluster_id,
74+
Ballast.cluster_id,
75+
Diagnostic.cluster_id,
76+
],
77+
OUTPUT_CLUSTERS: [
78+
Ota.cluster_id,
79+
],
80+
},
81+
21: {
82+
PROFILE_ID: zha.PROFILE_ID,
83+
DEVICE_TYPE: zha.DeviceType.DIMMER_SWITCH,
84+
INPUT_CLUSTERS: [
85+
Basic.cluster_id,
86+
Identify.cluster_id,
87+
Diagnostic.cluster_id,
88+
SESpecific.cluster_id,
89+
],
90+
OUTPUT_CLUSTERS: [
91+
Identify.cluster_id,
92+
Groups.cluster_id,
93+
Scenes.cluster_id,
94+
OnOff.cluster_id,
95+
LevelControl.cluster_id,
96+
WindowCovering.cluster_id,
97+
],
98+
},
99+
242: {
100+
PROFILE_ID: zgp.PROFILE_ID,
101+
DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
102+
INPUT_CLUSTERS: [],
103+
OUTPUT_CLUSTERS: [
104+
GreenPowerProxy.cluster_id,
105+
],
106+
},
107+
},
108+
}
109+
replacement = {
110+
ENDPOINTS: {
111+
3: {
112+
PROFILE_ID: zha.PROFILE_ID,
113+
DEVICE_TYPE: zha.DeviceType.DIMMABLE_LIGHT,
114+
INPUT_CLUSTERS: [
115+
SEBasic,
116+
Identify.cluster_id,
117+
Groups.cluster_id,
118+
Scenes.cluster_id,
119+
OnOff.cluster_id,
120+
LevelControl.cluster_id,
121+
SEBallast,
122+
Diagnostic.cluster_id,
123+
],
124+
OUTPUT_CLUSTERS: [
125+
Ota.cluster_id,
126+
],
127+
},
128+
21: {
129+
PROFILE_ID: zha.PROFILE_ID,
130+
DEVICE_TYPE: zha.DeviceType.DIMMER_SWITCH,
131+
INPUT_CLUSTERS: [
132+
SEBasic,
133+
Identify.cluster_id,
134+
Diagnostic.cluster_id,
135+
SESpecific,
136+
],
137+
OUTPUT_CLUSTERS: [
138+
Identify.cluster_id,
139+
Groups.cluster_id,
140+
Scenes.cluster_id,
141+
OnOff.cluster_id,
142+
LevelControl.cluster_id,
143+
WindowCovering.cluster_id,
144+
],
145+
},
146+
242: {
147+
PROFILE_ID: zgp.PROFILE_ID,
148+
DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
149+
INPUT_CLUSTERS: [],
150+
OUTPUT_CLUSTERS: [
151+
GreenPowerProxy.cluster_id,
152+
],
153+
},
154+
}
155+
}

0 commit comments

Comments
 (0)