11"""Module to handle quirks of the Sinopé Technologies switches.
22
33Supported devices, SP2600ZB, SP2610ZB, RM3250ZB, RM3500ZB,
4- VA4200WZ, VA4201WZ, VA4200ZB, VA4201ZB, VA4220ZB, VA4221ZB and MC3100ZB.
4+ VA4200WZ, VA4201WZ, VA4200ZB, VA4201ZB, VA4220ZB, VA4221ZB and MC3100ZB,
5+ 2nd gen VA4220ZB, VA4221ZB with flow meeter FS4220, FS4221.
56"""
67
78import zigpy .profiles .zha as zha_p
2223)
2324from zigpy .zcl .clusters .homeautomation import Diagnostic , ElectricalMeasurement
2425from zigpy .zcl .clusters .lightlink import LightLink
25- from zigpy .zcl .clusters .measurement import RelativeHumidity , TemperatureMeasurement
26+ from zigpy .zcl .clusters .measurement import RelativeHumidity , TemperatureMeasurement , FlowMeasurement
2627from zigpy .zcl .clusters .security import IasZone
2728from zigpy .zcl .clusters .smartenergy import Metering
2829
30+ from zigpy .zcl .foundation import Array
31+
2932from zhaquirks .const import (
3033 DEVICE_TYPE ,
3134 ENDPOINTS ,
3841
3942SINOPE_MANUFACTURER_CLUSTER_ID = 0xFF01
4043CURTEMP = 0x0000
44+ FLOWMETER = 0x0000
4145
4246
4347class SinopeManufacturerCluster (CustomCluster ):
@@ -49,6 +53,41 @@ class KeypadLock(t.enum8):
4953 Unlocked = 0x00
5054 Locked = 0x01
5155
56+ class FlowAlarm (t .enum8 ):
57+ """Alarm abnormal flow."""
58+
59+ Off = 0x00
60+ On = 0x01
61+
62+ class AlarmAction (t .enum8 ):
63+ """Flow alarm action."""
64+
65+ Nothing = 0x00
66+ Notify = 0x01
67+ Close = 0x02
68+ Close_notify = 0x03
69+
70+ class PowerSource (t .uint32_t ):
71+ """Valve power souce types."""
72+
73+ Battery = 0x00000000
74+ ACUPS_01 = 0x00000001
75+ DC_power = 0x0001d4c0
76+
77+ class EmergencyPower (t .uint32_t ):
78+ """Valve emergency power souce types."""
79+
80+ Battery = 0x00000000
81+ ACUPS_01 = 0x00000001
82+ Battery_ACUPS_01 = 0x0000003c
83+
84+ class AbnormalAction (t .bitmap16 ):
85+ """Action in case of abnormal flow detected."""
86+
87+ Nothing = 0x0000
88+ Notify = 0x0001
89+ Close_notify = 0x0003
90+
5291 class ColdStatus (t .enum8 ):
5392 """cold_load_pickup_status values."""
5493
@@ -63,6 +102,20 @@ class TankSize(t.enum8):
63102 Gal_60 = 0x03
64103 Gal_80 = 0x04
65104
105+ class FlowDuration (t .uint32_t ):
106+ """tank_size values."""
107+
108+ M_15 = 0x0384
109+ M_30 = 0x0708
110+ M_45 = 0x0A8C
111+ M_60 = 0x0E10
112+ M_75 = 0x1194
113+ M_90 = 0x1518
114+ H_3 = 0x2A30
115+ H_6 = 0x5460
116+ H_12 = 0xA8C0
117+ H_24 = 0x15180
118+
66119 cluster_id = SINOPE_MANUFACTURER_CLUSTER_ID
67120 name = "Sinopé Manufacturer specific"
68121 ep_attribute = "sinope_manufacturer_specific"
@@ -71,27 +124,97 @@ class TankSize(t.enum8):
71124 0x0002 : ("keypad_lockout" , KeypadLock , True ),
72125 0x0003 : ("firmware_number" , t .uint16_t , True ),
73126 0x0004 : ("firmware_version" , t .CharacterString , True ),
127+ 0x0010 : ("outdoor_temp" , t .int16s , True ),
74128 0x0013 : ("tank_size" , TankSize , True ),
75129 0x0030 : ("unknown_attr_2" , t .uint8_t , True ),
76130 0x0060 : ("connected_load" , t .uint16_t , True ),
77- 0x0070 : ("currentLoad " , t .bitmap8 , True ),
131+ 0x0070 : ("current_load " , t .bitmap8 , True ),
78132 0x0076 : ("dr_config_water_temp_min" , t .uint8_t , True ),
79133 0x0077 : ("dr_config_water_temp_time" , t .uint8_t , True ),
80134 0x0078 : ("dr_wt_time_on" , t .uint16_t , True ),
135+ 0x0080 : ("unknown_attr_4" , t .uint32_t , True ),
136+ 0x0090 : ("current_summation_delivered" , t .uint32_t , True ),
81137 0x00A0 : ("timer" , t .uint32_t , True ),
82138 0x00A1 : ("timer_countdown" , t .uint32_t , True ),
139+ 0x0101 : ("unknown_attr_9" , Array , True ),
83140 0x0200 : ("status" , t .bitmap32 , True ),
141+ 0x0221 : ("unknown_attr_3" , t .bitmap16 , True ),
142+ 0x0230 : ("alarm_flow_threshold" , FlowAlarm , True ),
143+ 0x0231 : ("alarm_options" , AlarmAction , True ),
144+ 0x0240 : ("flow_meter_config" , Array , True ),
145+ 0x0241 : ("countdown" , t .uint32_t , True ),
146+ 0x0250 : ("power_source" , PowerSource , True ),
147+ 0x0251 : ("emergency_power_source" , EmergencyPower , True ),
148+ 0x0252 : ("abnormal_flow_duration" , FlowDuration , True ),
149+ 0x0253 : ("abnormal_flow_action" , AbnormalAction , True ),
84150 0x0283 : ("cold_load_pickup_status" , ColdStatus , True ),
85151 0xFFFD : ("cluster_revision" , t .uint16_t , True ),
86152 }
87153
88154
155+ class CustomBasicCluster (CustomCluster , Basic ):
156+ """Custom Basic Cluster."""
157+
158+ class PowerSource (t .enum8 ):
159+ """Power source."""
160+
161+ Unknown = 0x0000
162+ Battery = 0x0003
163+ DC_source = 0x0004
164+ ACUPS_01 = 0x0081
165+ ACUPS01 = 0x0082
166+
167+ attributes = Basic .attributes .copy ()
168+ attributes .update (
169+ {
170+ 0x0007 : ("power_source" , PowerSource , True ),
171+ }
172+ )
173+
174+
89175class CustomMeteringCluster (CustomCluster , Metering ):
90176 """Custom Metering Cluster."""
91177
178+ class ValveStatus (t .bitmap8 ):
179+ """valve_status."""
180+
181+ Off = 0x00
182+ Off_armed = 0x01
183+ On = 0x02
184+
185+ class UnitOfMeasure (t .enum8 ):
186+ """unit_of_measure."""
187+
188+ KWh = 0x00
189+ Lh = 0x07
190+
92191 DIVISOR = 0x0302
93192 _CONSTANT_ATTRIBUTES = {DIVISOR : 1000 }
94193
194+ attributes = Metering .attributes .copy ()
195+ attributes .update (
196+ {
197+ 0x0200 : ("status" , ValveStatus , True ),
198+ 0x0300 : ("unit_of_measure" , UnitOfMeasure , True ),
199+ }
200+ )
201+
202+
203+ class CustomDeviceTemperatureCluster (CustomCluster , DeviceTemperature ):
204+ """Custom DeviceTemperature Cluster."""
205+
206+ def _update_attribute (self , attrid , value ):
207+ if attrid == CURTEMP :
208+ super ()._update_attribute (attrid , value * 100 )
209+
210+
211+ class CustomFlowMeasurementCluster (CustomCluster , FlowMeasurement ):
212+ """Custom FlowMeasurement Cluster."""
213+
214+ def _update_attribute (self , attrid , value ):
215+ if attrid == FLOWMETER :
216+ super ()._update_attribute (attrid , value / 10 )
217+
95218
96219class CustomDeviceTemperatureCluster (CustomCluster , DeviceTemperature ):
97220 """Custom DeviceTemperature Cluster."""
@@ -248,6 +371,42 @@ class SinopeTechnologiesValve(CustomDevice):
248371 replacement = {
249372 ENDPOINTS : {
250373 1 : {
374+ INPUT_CLUSTERS : [
375+ CustomBasicCluster ,
376+ PowerConfiguration .cluster_id ,
377+ Identify .cluster_id ,
378+ Groups .cluster_id ,
379+ Scenes .cluster_id ,
380+ OnOff .cluster_id ,
381+ LevelControl .cluster_id ,
382+ Diagnostic .cluster_id ,
383+ SinopeManufacturerCluster ,
384+ ],
385+ OUTPUT_CLUSTERS : [
386+ Identify .cluster_id ,
387+ Ota .cluster_id ,
388+ ],
389+ }
390+ }
391+ }
392+
393+
394+ class SinopeTechnologiesValveG2 (CustomDevice ):
395+ """SinopeTechnologiesValveG2 custom device."""
396+
397+ signature = {
398+ # <SimpleDescriptor(endpoint=1, profile=260,
399+ # device_type=3, device_version=0,
400+ # input_clusters=[0, 1, 3, 4, 5, 6, 8, 1026, 1280, 1794, 2821, 65281]
401+ # output_clusters=[3, 6, 25]>
402+ MODELS_INFO : [
403+ (SINOPE , "VA4220ZB" ),
404+ (SINOPE , "VA4221ZB" ),
405+ ],
406+ ENDPOINTS : {
407+ 1 : {
408+ PROFILE_ID : zha_p .PROFILE_ID ,
409+ DEVICE_TYPE : zha_p .DeviceType .LEVEL_CONTROLLABLE_OUTPUT ,
251410 INPUT_CLUSTERS : [
252411 Basic .cluster_id ,
253412 PowerConfiguration .cluster_id ,
@@ -256,11 +415,42 @@ class SinopeTechnologiesValve(CustomDevice):
256415 Scenes .cluster_id ,
257416 OnOff .cluster_id ,
258417 LevelControl .cluster_id ,
418+ TemperatureMeasurement .cluster_id ,
419+ IasZone .cluster_id ,
420+ Metering .cluster_id ,
421+ Diagnostic .cluster_id ,
422+ SINOPE_MANUFACTURER_CLUSTER_ID ,
423+ ],
424+ OUTPUT_CLUSTERS : [
425+ Identify .cluster_id ,
426+ OnOff .cluster_id ,
427+ Ota .cluster_id ,
428+ ],
429+ }
430+ },
431+ }
432+
433+ replacement = {
434+ ENDPOINTS : {
435+ 1 : {
436+ INPUT_CLUSTERS : [
437+ CustomBasicCluster ,
438+ PowerConfiguration .cluster_id ,
439+ Identify .cluster_id ,
440+ Groups .cluster_id ,
441+ Scenes .cluster_id ,
442+ OnOff .cluster_id ,
443+ LevelControl .cluster_id ,
444+ TemperatureMeasurement .cluster_id ,
445+ CustomFlowMeasurementCluster ,
446+ IasZone .cluster_id ,
447+ CustomMeteringCluster ,
259448 Diagnostic .cluster_id ,
260449 SinopeManufacturerCluster ,
261450 ],
262451 OUTPUT_CLUSTERS : [
263452 Identify .cluster_id ,
453+ OnOff .cluster_id ,
264454 Ota .cluster_id ,
265455 ],
266456 }
0 commit comments