Skip to content

Commit 6b90d19

Browse files
committed
Refactor modules
- Add CH2AX/SWITCH/1 signature
1 parent e01b590 commit 6b90d19

File tree

6 files changed

+249
-187
lines changed

6 files changed

+249
-187
lines changed

tests/test_schneiderelectric.py

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
from zigpy.zcl import foundation
44

5-
import zhaquirks.schneiderelectric.shutters
6-
import zhaquirks.schneiderelectric.switches
5+
import zhaquirks.schneiderelectric.devices.shutters
6+
import zhaquirks.schneiderelectric.devices.switches
77

88
zhaquirks.setup()
99

@@ -121,7 +121,53 @@ async def test_fls_air_link_4_signature(assert_signature_matches_quirk):
121121
"class": "zigpy.device.Device",
122122
}
123123
assert_signature_matches_quirk(
124-
zhaquirks.schneiderelectric.switches.FLSAirlink4, signature
124+
zhaquirks.schneiderelectric.devices.switches.FLSAirlink4, signature
125+
)
126+
127+
128+
async def test_ch2ax_switch_1_signature(assert_signature_matches_quirk):
129+
signature = {
130+
"node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress|RxOnWhenIdle|MainsPowered|FullFunctionDevice: 142>, manufacturer_code=4190, 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=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)",
131+
"endpoints": {
132+
"1": {
133+
"profile_id": 260,
134+
"device_type": "0x0100",
135+
"in_clusters": [
136+
"0x0000",
137+
"0x0003",
138+
"0x0004",
139+
"0x0005",
140+
"0x0006",
141+
"0x0b05",
142+
],
143+
"out_clusters": ["0x0019"],
144+
},
145+
"21": {
146+
"profile_id": 260,
147+
"device_type": "0x0104",
148+
"in_clusters": ["0x0000", "0x0003", "0x0b05", "0xff17"],
149+
"out_clusters": [
150+
"0x0003",
151+
"0x0004",
152+
"0x0005",
153+
"0x0006",
154+
"0x0008",
155+
"0x0102",
156+
],
157+
},
158+
"242": {
159+
"profile_id": 41440,
160+
"device_type": "0x0061",
161+
"in_clusters": [],
162+
"out_clusters": ["0x0021"],
163+
},
164+
},
165+
"manufacturer": "Schneider Electric",
166+
"model": "CH2AX/SWITCH/1",
167+
"class": "zigpy.device.Device",
168+
}
169+
assert_signature_matches_quirk(
170+
zhaquirks.schneiderelectric.devices.switches.CHxAXSwitch1, signature
125171
)
126172

127173

@@ -167,5 +213,5 @@ async def test_ch10ax_switch_1_signature(assert_signature_matches_quirk):
167213
"class": "zigpy.device.Device",
168214
}
169215
assert_signature_matches_quirk(
170-
zhaquirks.schneiderelectric.switches.CH10AXSwitch1, signature
216+
zhaquirks.schneiderelectric.devices.switches.CHxAXSwitch1, signature
171217
)

zhaquirks/schneiderelectric/README.md

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
- [Helpers](#helpers)
66
- [Devices](#devices)
77
- [Shutter](#shutter)
8-
- [NHPB/SHUTTER/1 ](#nhpbshutter1-)
8+
- [NHPB/SHUTTER/1 ](#nhpbshutter1-)
99
- [PUCK/SHUTTER/1 ❌](#puckshutter1-)
1010
- [1GANG/SHUTTER/1 ❔](#1gangshutter1-)
1111
- [Switch](#switch)
12-
- [CH2AX/SWITCH/1 ](#ch2axswitch1-)
12+
- [CH2AX/SWITCH/1 ](#ch2axswitch1-)
1313
- [CH10AX/SWITCH/1 ❌](#ch10axswitch1-)
1414
- [FLS/AIRLINK/4 ❌](#flsairlink4-)
1515
- [FLS/SYSTEM-M/4 ❔](#flssystem-m4-)
@@ -53,7 +53,7 @@ The purpose of this file is to list all Zigbee capable device from Schneider Ele
5353

5454
All devices are listed alphabetically based on the Zigbee `model (0x0005)` attribute from `Basic (0x0000)` cluster.
5555

56-
All quirk infos should remain in basecode.
56+
All quirk infos should remain in basecode.
5757

5858
Status :
5959

@@ -79,7 +79,7 @@ Sources :
7979

8080
Lift percentage is reversed
8181

82-
#### NHPB/SHUTTER/1
82+
#### NHPB/SHUTTER/1
8383

8484
<details>
8585
<summary>Device signature</summary>
@@ -2015,7 +2015,7 @@ From [Jeedom community](https://community.jeedom.com/t/plugin-zigbee-beta-blabla
20152015

20162016
### Switch
20172017

2018-
#### CH2AX/SWITCH/1
2018+
#### CH2AX/SWITCH/1
20192019

20202020
<details>
20212021
<summary>Signature</summary>
@@ -4245,6 +4245,14 @@ From [Jeedom community](https://community.jeedom.com/t/plugin-zigbee-beta-blabla
42454245

42464246
#### FLS/AIRLINK/4 ❌
42474247

4248+
[zigbee2mqtt](https://www.zigbee2mqtt.io/devices/550D6001.html)
4249+
4250+
> Depending on the firmware version the device may support both 1-channel and 2-channel mode. In 1-channel mode both the upper and lower buttons works as the upper buttons. On some firmware versions (incl. those sold as Elko EKO07117) the device starts out in 1-channel mode and must be switched into 2-channel mode either by using the Elko / Wiser gateway or by holding down button 1 and 4 (upper left and lower right) for approx. 10 seconds - the led will flash red and the become green once successfull.
4251+
4252+
[zigbee-herdsman-converters](https://github.com/Koenkk/zigbee-herdsman-converters/blob/d1f00202a79a5cd4b6548dd1d15057895a3e6666/devices/schneider_electric.js#L292-L311)
4253+
4254+
> When in 2-gang operation mode, unit operates out of endpoints 21 and 22, otherwise just 21
4255+
42484256
<details>
42494257
<summary>Signature</summary>
42504258

Lines changed: 0 additions & 170 deletions
Original file line numberDiff line numberDiff line change
@@ -1,177 +1,7 @@
11
"""Module for Schneider Electric devices quirks."""
22
import logging
33

4-
from zigpy.quirks import CustomCluster
5-
import zigpy.types as t
6-
from zigpy.zcl.clusters.closures import WindowCovering
7-
from zigpy.zcl.clusters.general import Basic, OnOff
8-
from zigpy.zcl.clusters.homeautomation import Diagnostic
9-
from zigpy.zcl.foundation import ZCLAttributeDef
10-
114
_LOGGER = logging.getLogger(__name__)
125

136
SE_MANUF_NAME = "Schneider Electric"
147
SE_MANUF_ID = 0x4190
15-
16-
# Attribute IDs
17-
ATTR_CURRENT_POSITION_LIFT_PERCENTAGE = 0x0008
18-
19-
# Command IDs
20-
CMD_GO_TO_LIFT_PERCENTAGE = 0x0005
21-
22-
23-
class SEManufCluster(CustomCluster):
24-
"""Schneider Electric manufacturer specific cluster."""
25-
26-
name = "Schneider Electric Manufacturer Specicific"
27-
ep_attribute = "schneider_electric_manufacturer"
28-
29-
30-
class SEBasicCluster(SEManufCluster, Basic):
31-
32-
attributes: dict[int, ZCLAttributeDef] = Basic.attributes.copy()
33-
34-
attributes.update(
35-
{
36-
0xE001: (
37-
"se_sw_build_id",
38-
t.CharacterString,
39-
), # value: "002.004.016 R
40-
0xE002: (
41-
"unknown_attribute_57346",
42-
t.CharacterString,
43-
), # value: "001.000.000"
44-
0xE004: (
45-
"unknown_attribute_57348",
46-
t.CharacterString,
47-
), # value: "213249FEFF5ECFD"
48-
0xE007: ("unknown_attribute_57351", t.enum16),
49-
0xE008: (
50-
"se_device_type",
51-
t.CharacterString,
52-
), # value: "Wiser Light"
53-
0xE009: (
54-
"se_model",
55-
t.CharacterString,
56-
), # value: "NHPB/SHUTTER/1"
57-
0xE00A: (
58-
"se_realm",
59-
t.CharacterString,
60-
), # value: "Wiser Home"
61-
0xE00B: (
62-
"unknown_attribute_57355",
63-
t.CharacterString,
64-
),
65-
}
66-
)
67-
68-
69-
class SEOnOff(SEManufCluster, OnOff):
70-
attributes = OnOff.attributes.copy()
71-
attributes.update(
72-
{
73-
0xE000: ("unknown_attribute_57344", t.uint16_t),
74-
0xE001: ("unknown_attribute_57345", t.uint32_t),
75-
0xE002: ("unknown_attribute_57346", t.bitmap8),
76-
0xE003: ("unknown_attribute_57347", t.uint32_t),
77-
}
78-
)
79-
80-
81-
class SEWindowCovering(SEManufCluster, WindowCovering):
82-
"""Manufacturer Specific Cluster of cover device."""
83-
84-
attributes: dict[int, ZCLAttributeDef] = WindowCovering.attributes.copy()
85-
86-
attributes.update(
87-
{
88-
0xFFFD: ("unknown_attribute_65533", t.uint16_t),
89-
0xE000: ("lift_duration", t.uint16_t),
90-
0xE010: ("unknown_attribute_57360", t.bitmap8),
91-
0xE012: ("unknown_attribute_57362", t.uint16_t),
92-
0xE013: ("unknown_attribute_57363", t.bitmap8),
93-
0xE014: ("unknown_attribute_57364", t.uint16_t),
94-
0xE015: ("unknown_attribute_57365", t.uint16_t),
95-
0xE016: ("unknown_attribute_57366", t.uint16_t),
96-
0xE017: ("unknown_attribute_57367", t.uint8_t),
97-
}
98-
)
99-
100-
def _update_attribute(self, attrid, value):
101-
if attrid == ATTR_CURRENT_POSITION_LIFT_PERCENTAGE:
102-
# Invert the percentage value
103-
value = 100 - value
104-
super()._update_attribute(attrid, value)
105-
106-
async def command(
107-
self, command_id, *args, manufacturer=None, expect_reply=True, tsn=None
108-
):
109-
"""Override default command to invert percent lift value."""
110-
if command_id == CMD_GO_TO_LIFT_PERCENTAGE:
111-
percent = args[0]
112-
percent = 100 - percent
113-
v = (percent,)
114-
return await super().command(command_id, *v)
115-
return await super().command(
116-
command_id,
117-
*args,
118-
manufacturer=manufacturer,
119-
expect_reply=expect_reply,
120-
tsn=tsn
121-
)
122-
123-
124-
class SEDiagnostic(CustomCluster, Diagnostic):
125-
126-
attributes: dict[int, ZCLAttributeDef] = Diagnostic.attributes.copy()
127-
128-
# TODO: Check -> this attr don't seems to be manufacturer related (no "manf_id")
129-
attributes.update(
130-
{
131-
0xFFFD: ("unknown_attribute_65533", t.uint16_t),
132-
}
133-
)
134-
135-
136-
class SESpecificCluster(SEManufCluster):
137-
cluster_id = 0xFF17
138-
139-
attributes = {
140-
0x0000: ("unknown_attribute_0", t.enum8),
141-
0x0001: ("unknown_attribute_1", t.enum8),
142-
0x0010: ("unknown_attribute_16", t.uint8_t),
143-
0x0011: ("unknown_attribute_17", t.uint16_t),
144-
0x0020: ("unknown_attribute_32", t.uint8_t),
145-
0x0021: ("unknown_attribute_33", t.uint16_t),
146-
0xFFFD: ("unknown_attribute_65533", t.uint16_t),
147-
}
148-
149-
150-
class SEPiloteMode(int):
151-
'''
152-
Might be useful for :
153-
- CCTFR6700 (manufacturerCode seems diff: 0x105e)
154-
'''
155-
Contactor=1
156-
Pilot=3
157-
158-
class WiserDimmerMode(int):
159-
'''
160-
Might be useful for :
161-
- PUCK/DIMMER/
162-
- NHROTARY/DIMMER/1
163-
'''
164-
Auto = 0
165-
RC = 1
166-
RL = 2
167-
RL_LED = 3
168-
169-
170-
class SEDimmerMode():
171-
'''
172-
Might be useful for :
173-
- LK Dimmer (manufacturerCode seems diff: 0x105e)
174-
'''
175-
RC = 1
176-
RL = 2
177-

0 commit comments

Comments
 (0)