diff --git a/README.md b/README.md index 07f047a..b0286f9 100644 --- a/README.md +++ b/README.md @@ -39,58 +39,66 @@ You can edit the files as you like and restart HA to test your changes. Don't fo I'll list here all the custom cluster attribute with explanation about how to use them in your automation. - Thermostats: -|Cluster|Attributes|Data type|Fonction |Value -| --- | --- | --- | --- | --- -|0xff01|0x0010|t.int16s|outdoor_temp|celcius*100 -|0xff01|0x0011|t.uint16_t|outdoor_temp_timeout| Delay in seconds before reverting to setpoint display if no more outdoor temp is received -|0xff01|0x0012|t.enum8|config2ndDisplay| 0 = auto, 1 = setpoint, 2 = outside temperature. -|0xff01|0x0020|t.uint32_t|secs_since_2k| second since year 2000 -|0xff01|0x0070|t.bitmap8|currentLoad| watt/hr -|0xff01|0x0071|t.int8s|ecoMode| default:-128, -100-0-100% -|0xff01|0x0072|t.uint8_t|ecoMode1| default:255, 0-99 -|0xff01|0x0073|t.uint8_t|ecoMode2| default 255, 0-100 -|0xff01|0x0105|t.enum8|airFloorMode|Air: 1, floor: 2 -|0xff01|0x0106|t.enum8|auxOutputMode|0=off, 1=expantion module -|0xff01|0x0108|t.int16s|airMaxLimit|temp: celcius*100, valid only if floor mode is selected -|0xff01|0x0109|t.int16s|floorMinSetpoint| off: -32768, temp: temp*100 -|0xff01|0x010A|t.int16s|floorMaxSetpoint| off: -32768, temp: temp*100 -|0xff01|0x010B|t.enum8|tempSensorType| 0=10k, 1=12k -|0xff01|0x010C|t.uint8_t|floorLimitStatus|0=ok, 1=floorLimitLowReached, 2=floorLimitMaxReached, 3=floorAirLimitMaxReached -|0xff01|0x0114|t.enum8|timeFormat|0=24h, 1=12h -|0xff01|0x0115|t.enum8|gfciStatus|0=ok, 1=error -|0xff01|0x0118|t.uint16_t|auxConnectedLoad| watt/hr, 0xffff=off -|0xff01|0x0119|t.uint16_t|connectedLoad|None: 0xffff -|0xff01|0x0128|t.uint8_t|pumpProtection| Off: 0xff, On: 0x1 -|0xff01|0x012D|t.int16s|reportLocalTemperature| Celcius * 100 -|0xff01|0x0200|t.bitmap32|Unknown| ? -| --- | --- | --- | --- | --- -|0x0201|0x0400|t.enum8|SetOccupancy| Home: 0, away:1 -|0x0201|0x0401|t.uint16_t|MainCycleOutput| Number of second -|0x0201|0x0402|t.enum8|BacklightAutoDimParam| OnDemand: 0, Always: 1 -|0x0201|0x0404|t.uint16_t|AuxCycleOutput| Number of second -| --- | --- | --- | --- | --- -|0x0b04|0x050f|t.uint16_t|Apparent_Power|watt/hr -|0x0b04|0x050b|t.uint16_t|Active_Power|watt/hr +|Cluster|Attributes|Data type|Fonction |Value|Access +| --- | --- | --- | --- | --- |--- +|0xff01|0x0010|t.int16s|outdoor_temp|celcius*100|read/write +|0xff01|0x0002|t.enum8|keypadLockout|0 = unlocked, 1 = locked|read/write +|0xff01|0x0004|t.CharacterString|firmware_version| |read +|0xff01|0x0010|t.int16s|outdoor_temp|temp*100|read/write +|0xff01|0x0011|t.uint16_t|outdoor_temp_timeout| Delay in seconds before reverting to setpoint display if no more outdoor temp is received|read/write +|0xff01|0x0012|t.enum8|config2ndDisplay| 0 = auto, 1 = setpoint, 2 = outside temperature.|read/write +|0xff01|0x0020|t.uint32_t|secs_since_2k| second since year 2000|read/write +|0xff01|0x0070|t.bitmap8|currentLoad| watt/hr| +|0xff01|0x0071|t.int8s|ecoMode| default:-128, -100-0-100%| +|0xff01|0x0072|t.uint8_t|ecoMode1| default:255, 0-99| +|0xff01|0x0073|t.uint8_t|ecoMode2| default 255, 0-100| +|0xff01|0x0105|t.enum8|airFloorMode|Air: 1, floor: 2|read/write +|0xff01|0x0106|t.enum8|auxOutputMode|0=off, 1=expantion module|read/write +|0xff01|0x0107|t.int16s|FloorTemperature|temp: celcius*100|read +|0xff01|0x0108|t.int16s|airMaxLimit|temp: celcius*100, valid only if floor mode is selected|read/write +|0xff01|0x0109|t.int16s|floorMinSetpoint| off: -32768, temp: temp*100|read/write +|0xff01|0x010A|t.int16s|floorMaxSetpoint| off: -32768, temp: temp*100|read/write +|0xff01|0x010B|t.enum8|tempSensorType| 0=10k, 1=12k|read/write +|0xff01|0x010C|t.uint8_t|floorLimitStatus|0=ok, 1=floorLimitLowReached, 2=floorLimitMaxReached, 3=floorAirLimitMaxReached|report/read +|0xff01|0x010D|t.int16s|RoomTemperature|temp: celcius*100|read +|0xff01|0x0114|t.enum8|timeFormat|0=24h, 1=12h|read/write +|0xff01|0x0115|t.enum8|gfciStatus|0=ok, 1=error|report/read +|0xff01|0x0118|t.uint16_t|auxConnectedLoad| watt/hr, 0xffff=off|read/write +|0xff01|0x0119|t.uint16_t|connectedLoad|None: 0xffff| +|0xff01|0x0128|t.uint8_t|pumpProtection| Off: 0xff, On: 0x1|read/write +|0xff01|0x012D|t.int16s|reportLocalTemperature| Celcius * 100|read +|0xff01|0x0200|t.bitmap32|Unknown| ?| +|0xff01|0xFFFD|t.uint16_t|cluster_revision| |read +| --- | --- | --- | --- | --- | --- +|0x0201|0x0400|t.enum8|SetOccupancy| Home: 0, away:1|read/write +|0x0201|0x0401|t.uint16_t|MainCycleOutput| Number of second|read/write +|0x0201|0x0402|t.enum8|BacklightAutoDimParam| OnDemand: 0, Always: 1|read/write +|0x0201|0x0404|t.uint16_t|AuxCycleOutput| Number of second|read/write +| --- | --- | --- | --- | --- | --- +|0x0b04|0x050f|t.uint16_t|Apparent_Power|watt/hr|report/read +|0x0b04|0x050b|t.uint16_t|Active_Power|watt/hr|report/read/write | --- | --- | --- | --- | --- -|0x0204|0x0000|t.enum8|TemperatureDisplayMode|0=celcius, 1=farenheight -|0x0204|0x0001|t.enum8|keypadLockout|0=no lock, 1=lock +|0x0204|0x0000|t.enum8|TemperatureDisplayMode|0=celcius, 1=farenheight|read/write +|0x0204|0x0001|t.enum8|keypadLockout|0=no lock, 1=lock|read/write | --- | --- | --- | --- -|0x0702|0x0000|t.uint48_t|CurrentSummationDelivered|watt/hr +|0x0702|0x0000|t.uint48_t|CurrentSummationDelivered|watt/hr |report/read - lights and dimmer: -|Cluster|Attributes|Data type|Fonction |Value -| --- | --- | --- | --- | --- -|0xff01|0x0002|t.enum8|KeypadLock| Locked: 1, Unlocked: 0 +|Cluster|Attributes|Data type|Fonction |Value|Access +| --- | --- | --- | --- | --- | --- +|0xff01|0x0002|t.enum8|KeypadLock| Locked: 1, Unlocked: 0|read/write +|0xff01|0x0004|t.CharacterString|firmware_version| |read |0xff01|0x0050|t.uint24_t|onLedColor| 0x0affdc - Lim, 0x000a4b - Amber, 0x0100a5 - Fushia, 0x64ffff - Perle, 0xffff00 - Blue |0xff01|0x0051|t.uint24_t|offLedColor| 0x0affdc - Lim, 0x000a4b - Amber, 0x0100a5 - Fushia, 0x64ffff - Perle, 0xffff00 - Blue |0xff01|0x0052|t.uint8_t|onLedIntensity| Percent |0xff01|0x0053|t.uint8_t|offLedIntensity| Percent -|0xff01|0x0054|t.enum8|actionReport| singleTapUp: 1,2, doubleTapUp: 1,4, singleTapDown: 17,18, doubleTapDown: 17,20 +|0xff01|0x0054|t.enum8|actionReport| singleTapUp: 2, doubleTapUp: 4, singleTapDown: 18, doubleTapDown: 20|read/repport |0xff01|0x0055|t.uint16_t|minIntensity| 0 to 3000 |0xff01|0x00A0|t.uint32_t|Timer| Number of seconds |0xff01|0x0119|t.uint16_t|ConnectedLoad| None: 0, watt |0xff01|0x0200|t.bitmap32|Unknown| ? +|0xff01|0xFFFD|t.uint16_t|cluster_revision| |read | --- | --- | --- | --- | --- |0x0702|0x0000|t.uint48_t|CurrentSummationDelivered| Sum of delivered watt/hr |0x0006|0x0000|t.Bool|OnOff| 1=on, 0=off @@ -100,6 +108,8 @@ I'll list here all the custom cluster attribute with explanation about how to us |Cluster|Attributes|Data type|Fonction |Value | --- | --- | --- | --- | --- +|0xff01|0x0004|t.CharacterString|firmware_version| |read +|0xff01|0xFFFD|t.uint16_t|cluster_revision| |read |0x0702|0x0000|t.uint48_t|CurrentSummationDelivered|watt/hr |0x0b04|0x050B|t.uint16_t|Active_Power|watt/hr |0x0b04|0x0605|t.uint16_t|ACPowerDivisor| 10 @@ -110,11 +120,14 @@ I'll list here all the custom cluster attribute with explanation about how to us |Cluster|Attributes|Data type|Fonction |Value | --- | --- | --- | --- | --- +|0xff01|0x0002|t.enum8|keypadLockout|0 = unlocked, 1 = locked|read/write +|0xff01|0x0004|t.CharacterString|firmware_version| |read |0xff01|0x0060|t.uint16_t|ConnectedLoad| watt/hr |0xff01|0x00A0|t.uint32_t|Timer| Seconds |0xff01|0x0002|t.enum8|KeyboardLock| on=1, off=0 |0xff01|0x0070|t.bitmap8|CurrentLoad| watt/hr |0xff01|0x0200|t.bitmap32|Unknown| ? +|0xff01|0xFFFD|t.uint16_t|cluster_revision| |read |0x0006|0x0000|t.Bool|OnOff| 1=on, 0=off |0x0b04|0x050B|t.uint16_t|Active_Power| watt/hr |0x0b04|0x0605|t.uint16_t|AC_Power_Divisor| 1 @@ -125,6 +138,8 @@ I'll list here all the custom cluster attribute with explanation about how to us |Cluster|Attributes|Data type|Fonction |Value | --- | --- | --- | --- | --- +|0xff01|0x0002|t.enum8|keypadLockout|0 = unlocked, 1 = locked|read/write +|0xff01|0x0004|t.CharacterString|firmware_version| |read |0xff01|0x0060|t.uint16_t|ConnectedLoad| watt/hr |0xff01|0x0070|t.bitmap8|CurrentLoad| watt/hr |0xff01|0x0076|t.uint8_t|drConfigWaterTempMin| 45 or 0 @@ -133,6 +148,7 @@ I'll list here all the custom cluster attribute with explanation about how to us |0xff01|0x0079|t.bitmap8|unknown| 0 |0xff01|0x0200|t.bitmap32|unknown| 0 |0xff01|0x0283|t.uint8_t|ColdLoadPickupStatus| 1 +|0xff01|0xFFFD|t.uint16_t|cluster_revision| |read |0x0500|0x0030|t.uint16_t|ZoneStatus| 0=no leak, 1=leak |0x0006|0x0000|t.Bool|OnOff| 1=on, 0=off |0x0b04|0x050B|t.uint16_t|Active_Power| watt/hr @@ -146,6 +162,7 @@ I'll list here all the custom cluster attribute with explanation about how to us |Cluster|Attributes|Data type|Fonction |Value | --- | --- | --- | --- | --- |0xff01|0x00A0|t.uint32_t|Timer| second, on endpoint 1 and 2 +|0xff01|0xFFFD|t.uint16_t|cluster_revision| |read |0x0001|0x003E|t.bitmap32|BatteryAlarmState| 0=no alarm, 1=alarn |0x0006|0x0000|t.Bool|OnOff| 1=on, 0=off, on endpoint 1 and 2 @@ -164,6 +181,128 @@ I'll list here all the custom cluster attribute with explanation about how to us |0x0402|0x0000|t.uint16_t|MeasuredValueTemperature| celcius*100 |0x0500|0x0030|t.uint16_t|ZoneStatus| 0=no leak, 1=leak +# Devices reporting + +Device reporting allow device to report any changes that occur on some cluster attributes. If your device was connected to Neviweb before you don't need to activate reporting, except for light and dimmer double tap and long press reporting. If your device is bran new then it should be necessary to implement device reporting. To proceed you can do it by installing ZHA Toolkit (https://github.com/mdeweerd/zha-toolkit) **v0.8.31** or higher, and following example below: + +Following are the cluster/attributes set for reproting in Neviweb: + +- Thermostat: + +|Data|Cluster|Attribute|format|min time|max time|minimum change| +| --- | --- | --- | --- | --- | --- | --- | +|Occupancy|0x0003|0x0400|0x10|1|65000|1| +|local temperature|0x0201|0x0000|0x29|19|300|25| +|heating demand|0x0201|0x0008|0x0020|11|301|10| +|occupied heating setpoint|0x0201|0x0012|0x0029|8|302|40| +|report gfci status|0xFF01|0x0115|0x30|10|3600|1| +|floor limit status|0xFF01|0x010C|0x30|10|3600|1| + +- Light and dimmer + +|Data|Cluster|Attribute|format|min time|max time|minimum change| +| --- | --- | --- | --- | --- | --- | --- | +|onOff|0x0006|0x0000|0x10|0|599|null| +|CurrentLevel|0x0008|0x0000|0x20|3|602|0x01| +|double click|0xff01|0x0054|0x10|0|0|1| + +- load control + +|Data|Cluster|Attribute|format|min time|max time|minimum change| +| --- | --- | --- | --- | --- | --- | --- | +|onOff|0x0006|0x0000|0x10|0|600|null| +|ActivePower|0x0B04|0x050B|0x29|60|599|0x64| + +- Valve + +|Data|Cluster|Attribute|format|min time|max time|minimum change| +| --- | --- | --- | --- | --- | --- | --- | +|Battery %|(0x0001|0x0020|0x20|60|60*60|1| + +- Leak sensors + +|Data|Cluster|Attribute|format|min time|max time|minimum change| +| --- | --- | --- | --- | --- | --- | --- | +|battery percentage|0x0001|0x0021|0x20|30|43200|1| +|temperature min|0x0402|0x0000|0x29|30|3600|300| +|battery Alarm State|0x0001|0x003E|0x1b|30|3600|1| + +## Light switch and dimmer double tap, long press reporting : +Sinopé light switches (SW2500ZB), dimmer (DM2500ZB and DM2550ZB) supports single, double and long click, but requires to enable device reporting on attribute 0x0054, cluster 0xff01 to get the action fired in ZHA. To proceed use zha_toolkit services and follow the example bellow : + +The action done on the light switch and dimmer is defined in the cluster: 0xff01 attribut: 0x0054. +|Description|Attribute|Value received| +| --- | --- | --- | +|Single Tap UP|0x0054|2| +|Single Tap DOWN|0x0054|18| +|Double Tap UP|0x0054|4| +|Double Tap DOWN|0x0054|20| +|Long press UP|0x0054|3| +|Long press DOWN|0x0054|19| + +### a) create the reporting : +Here is an exemple of how to proceed. +In this exemple : +- 50:0b:91:40:00:03:db:c2 is your light switch +- 00:12:4b:00:24:c0:c1:e0 is your Zigbee Coordinator + +``` +service: zha_toolkit.conf_report +data: + ieee: 50:0b:91:40:00:03:db:c2 + cluster: 0xff01 + attribute: 0x0054 + manf: 4508 + min_interval: 0 + max_interval: 0 + reportable_change: 1 + tries: 3 + event_success: zha_report_success_trigger_event + event_fail: zha_report_fail_trigger_event + event_done: zha_done +``` + +### b) Specify the bind to your coordinator : +``` +service: zha_toolkit.bind_ieee +data: + ieee: 50:0b:91:40:00:03:db:c2 + command_data: 00:12:4b:00:24:c0:c1:e0 + cluster: 65281 + event_done: zha_done +``` + +### c) Automation example : +``` +alias: Enable desk light when double tap on light switch +description: "" +trigger: + - platform: event + event_type: zha_event + event_data: + device_ieee: 50:0b:91:40:00:03:db:c2 + cluster_id: 65281 + args: + attribute_id: 84 + attribute_name: actionReport + value: 4 +condition: [] +action: + - type: toggle + device_id: 8b11765575b04f899d9867165fa16069 + entity_id: light.interrupteur_lumiere_bureau_light_2 + domain: light +mode: single +``` +For automations you will have acces to those events in the UI for device triggers: +- "Turn on" pressed +- "Turn off" pressed +- "Turn on" double clicked +- "Turn off" double clicked +- "Turn on" continuously pressed +- "Turn off" continuously pressed + + # Automation examples: - Sending outside temperature to thermostats: - Celcius: @@ -209,7 +348,7 @@ action: {{ (((state_attr('weather.home', 'temperature' ) - 32) * 5/9)|float*100)|int }} mode: single ``` -You can use either 0xff01 or 65281 in automation. You can send temperature on regular timely basis or when the outside temperature change. Do not pass over 60 minte or thermostat display will go back to setpoint display. +You can use either 0xff01 or 65281 in automation. You can send temperature on regular timely basis or when the outside temperature change. Do not pass over 60 minutes or thermostat display will go back to setpoint display. - setting the outside temperature sensor: @@ -223,6 +362,6 @@ You can use any temperature source, local or remote. ``` ## Buy me a coffee -If you want to make donation as appreciation of my work, you can do so via PayPal (preferred) or buy me a coffee. Thank you! +If you want to make donation as appreciation of my work, you can do so via PayPal (preferred), or Buy me a coffee. Thank you! - [![Support via PayPal](https://cdn.rawgit.com/twolfson/paypal-github-button/1.0.0/dist/button.svg)](https://www.paypal.me/phytoressources/) - Buy Me A Coffee diff --git a/light.py b/light.py index 161c5c6..5b3e3fa 100644 --- a/light.py +++ b/light.py @@ -21,37 +21,76 @@ from zigpy.zcl.clusters.homeautomation import Diagnostic, ElectricalMeasurement from zigpy.zcl.clusters.smartenergy import Metering +from zhaquirks import EventableCluster from zhaquirks.const import ( + ARGS, + ATTRIBUTE_ID, + ATTRIBUTE_NAME, + CLUSTER_ID, + COMMAND, + COMMAND_BUTTON_DOUBLE, + COMMAND_BUTTON_HOLD, + COMMAND_BUTTON_SINGLE, DEVICE_TYPE, + DOUBLE_PRESS, + ENDPOINT_ID, ENDPOINTS, INPUT_CLUSTERS, + LONG_PRESS, MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, + SHORT_PRESS, + TURN_OFF, + TURN_ON, + VALUE, ) from zhaquirks.sinope import SINOPE +ATTRIBUTE_ACTION = "actionReport" SINOPE_MANUFACTURER_CLUSTER_ID = 0xFF01 class SinopeTechnologiesManufacturerCluster(CustomCluster): """SinopeTechnologiesManufacturerCluster manufacturer cluster.""" + class keypadLock(t.enum8): + Unlocked = 0x00 + Locked = 0x01 + + class action(t.enum8): + single_on = 0x01 + single_release_on = 0x02 + long_on = 0x03 + double_on = 0x04 + single_off = 0x11 + single_release_off = 0x12 + long_off = 0x13 + double_off = 0x14 + cluster_id = SINOPE_MANUFACTURER_CLUSTER_ID name = "Sinopé Technologies Manufacturer specific" ep_attribute = "sinope_manufacturer_specific" attributes = { - 0x0002: ("KeypadLock", t.enum8, True), + 0x0002: ("keypadLockout", keypadLock, True), + 0x0004: ("firmware_version", t.CharacterString, True), 0x0050: ("onLedColor", t.uint24_t, True), 0x0051: ("offLedColor", t.uint24_t, True), 0x0052: ("onLedIntensity", t.uint8_t, True), 0x0053: ("offLedIntensity", t.uint8_t, True), + 0x0054: ("actionReport", action, True), 0x0055: ("minIntensity", t.uint16_t, True), 0x00A0: ("Timer", t.uint32_t, True), 0x0119: ("ConnectedLoad", t.uint16_t, True), + 0x0200: ("Unknown", t.bitmap32, True), + 0xFFFD: ("cluster_revision", t.uint16_t, True), } +class LightManufacturerCluster(EventableCluster, SinopeTechnologiesManufacturerCluster): + """LightManufacturerCluster: fire events corresponding to press type.""" + + class SinopeTechnologieslight(CustomDevice): """SinopeTechnologiesLight custom device.""" @@ -98,7 +137,7 @@ class SinopeTechnologieslight(CustomDevice): OnOff.cluster_id, Metering.cluster_id, Diagnostic.cluster_id, - SinopeTechnologiesManufacturerCluster, + LightManufacturerCluster, ], OUTPUT_CLUSTERS: [ Identify.cluster_id, @@ -110,6 +149,46 @@ class SinopeTechnologieslight(CustomDevice): } + device_automation_triggers = { + (SHORT_PRESS, TURN_ON): { + ENDPOINT_ID: 1, + CLUSTER_ID: 65281, + COMMAND: COMMAND_BUTTON_SINGLE, + ARGS: {ATTRIBUTE_ID: 84, ATTRIBUTE_NAME: ATTRIBUTE_ACTION, VALUE: 2}, + }, + (SHORT_PRESS, TURN_OFF): { + ENDPOINT_ID: 1, + CLUSTER_ID: 65281, + COMMAND: COMMAND_BUTTON_SINGLE, + ARGS: {ATTRIBUTE_ID: 84, ATTRIBUTE_NAME: ATTRIBUTE_ACTION, VALUE: 18}, + }, + (DOUBLE_PRESS, TURN_ON): { + ENDPOINT_ID: 1, + CLUSTER_ID: 65281, + COMMAND: COMMAND_BUTTON_DOUBLE, + ARGS: {ATTRIBUTE_ID: 84, ATTRIBUTE_NAME: ATTRIBUTE_ACTION, VALUE: 4}, + }, + (DOUBLE_PRESS, TURN_OFF): { + ENDPOINT_ID: 1, + CLUSTER_ID: 65281, + COMMAND: COMMAND_BUTTON_DOUBLE, + ARGS: {ATTRIBUTE_ID: 84, ATTRIBUTE_NAME: ATTRIBUTE_ACTION, VALUE: 20}, + }, + (LONG_PRESS, TURN_ON): { + ENDPOINT_ID: 1, + CLUSTER_ID: 65281, + COMMAND: COMMAND_BUTTON_HOLD, + ARGS: {ATTRIBUTE_ID: 84, ATTRIBUTE_NAME: ATTRIBUTE_ACTION, VALUE: 3}, + }, + (LONG_PRESS, TURN_OFF): { + ENDPOINT_ID: 1, + CLUSTER_ID: 65281, + COMMAND: COMMAND_BUTTON_HOLD, + ARGS: {ATTRIBUTE_ID: 84, ATTRIBUTE_NAME: ATTRIBUTE_ACTION, VALUE: 19}, + }, + } + + class SinopeDM2500ZB(SinopeTechnologieslight): """DM2500ZB Dimmer.""" @@ -158,7 +237,7 @@ class SinopeDM2500ZB(SinopeTechnologieslight): LevelControl.cluster_id, Metering.cluster_id, Diagnostic.cluster_id, - SinopeTechnologiesManufacturerCluster, + LightManufacturerCluster, ], OUTPUT_CLUSTERS: [ Identify.cluster_id, @@ -170,6 +249,46 @@ class SinopeDM2500ZB(SinopeTechnologieslight): } + device_automation_triggers = { + (SHORT_PRESS, TURN_ON): { + ENDPOINT_ID: 1, + CLUSTER_ID: 65281, + COMMAND: COMMAND_BUTTON_SINGLE, + ARGS: {ATTRIBUTE_ID: 84, ATTRIBUTE_NAME: ATTRIBUTE_ACTION, VALUE: 2}, + }, + (SHORT_PRESS, TURN_OFF): { + ENDPOINT_ID: 1, + CLUSTER_ID: 65281, + COMMAND: COMMAND_BUTTON_SINGLE, + ARGS: {ATTRIBUTE_ID: 84, ATTRIBUTE_NAME: ATTRIBUTE_ACTION, VALUE: 18}, + }, + (DOUBLE_PRESS, TURN_ON): { + ENDPOINT_ID: 1, + CLUSTER_ID: 65281, + COMMAND: COMMAND_BUTTON_DOUBLE, + ARGS: {ATTRIBUTE_ID: 84, ATTRIBUTE_NAME: ATTRIBUTE_ACTION, VALUE: 4}, + }, + (DOUBLE_PRESS, TURN_OFF): { + ENDPOINT_ID: 1, + CLUSTER_ID: 65281, + COMMAND: COMMAND_BUTTON_DOUBLE, + ARGS: {ATTRIBUTE_ID: 84, ATTRIBUTE_NAME: ATTRIBUTE_ACTION, VALUE: 20}, + }, + (LONG_PRESS, TURN_ON): { + ENDPOINT_ID: 1, + CLUSTER_ID: 65281, + COMMAND: COMMAND_BUTTON_HOLD, + ARGS: {ATTRIBUTE_ID: 84, ATTRIBUTE_NAME: ATTRIBUTE_ACTION, VALUE: 3}, + }, + (LONG_PRESS, TURN_OFF): { + ENDPOINT_ID: 1, + CLUSTER_ID: 65281, + COMMAND: COMMAND_BUTTON_HOLD, + ARGS: {ATTRIBUTE_ID: 84, ATTRIBUTE_NAME: ATTRIBUTE_ACTION, VALUE: 19}, + }, + } + + class SinopeDM2550ZB(SinopeTechnologieslight): """DM2550ZB Dimmer.""" @@ -221,7 +340,7 @@ class SinopeDM2550ZB(SinopeTechnologieslight): Metering.cluster_id, ElectricalMeasurement.cluster_id, Diagnostic.cluster_id, - SinopeTechnologiesManufacturerCluster, + LightManufacturerCluster, ], OUTPUT_CLUSTERS: [ Identify.cluster_id, @@ -232,3 +351,43 @@ class SinopeDM2550ZB(SinopeTechnologieslight): } } } + + + device_automation_triggers = { + (SHORT_PRESS, TURN_ON): { + ENDPOINT_ID: 1, + CLUSTER_ID: 65281, + COMMAND: COMMAND_BUTTON_SINGLE, + ARGS: {ATTRIBUTE_ID: 84, ATTRIBUTE_NAME: ATTRIBUTE_ACTION, VALUE: 2}, + }, + (SHORT_PRESS, TURN_OFF): { + ENDPOINT_ID: 1, + CLUSTER_ID: 65281, + COMMAND: COMMAND_BUTTON_SINGLE, + ARGS: {ATTRIBUTE_ID: 84, ATTRIBUTE_NAME: ATTRIBUTE_ACTION, VALUE: 18}, + }, + (DOUBLE_PRESS, TURN_ON): { + ENDPOINT_ID: 1, + CLUSTER_ID: 65281, + COMMAND: COMMAND_BUTTON_DOUBLE, + ARGS: {ATTRIBUTE_ID: 84, ATTRIBUTE_NAME: ATTRIBUTE_ACTION, VALUE: 4}, + }, + (DOUBLE_PRESS, TURN_OFF): { + ENDPOINT_ID: 1, + CLUSTER_ID: 65281, + COMMAND: COMMAND_BUTTON_DOUBLE, + ARGS: {ATTRIBUTE_ID: 84, ATTRIBUTE_NAME: ATTRIBUTE_ACTION, VALUE: 20}, + }, + (LONG_PRESS, TURN_ON): { + ENDPOINT_ID: 1, + CLUSTER_ID: 65281, + COMMAND: COMMAND_BUTTON_HOLD, + ARGS: {ATTRIBUTE_ID: 84, ATTRIBUTE_NAME: ATTRIBUTE_ACTION, VALUE: 3}, + }, + (LONG_PRESS, TURN_OFF): { + ENDPOINT_ID: 1, + CLUSTER_ID: 65281, + COMMAND: COMMAND_BUTTON_HOLD, + ARGS: {ATTRIBUTE_ID: 84, ATTRIBUTE_NAME: ATTRIBUTE_ACTION, VALUE: 19}, + }, + } diff --git a/sensor.py b/sensor.py index bec5fe4..27e30ff 100644 --- a/sensor.py +++ b/sensor.py @@ -30,13 +30,29 @@ SINOPE_MANUFACTURER_CLUSTER_ID = 0xFF01 +class SinopeManufacturerCluster(CustomCluster): + """SinopeManufacturerCluster manufacturer cluster.""" + + cluster_id = SINOPE_MANUFACTURER_CLUSTER_ID + name = "Sinopé Manufacturer specific" + ep_attribute = "sinope_manufacturer_specific" + attributes = { + 0x0004: ("firmware_version", t.CharacterString, True), + 0xFFFD: ("cluster_revision", t.uint16_t, True), + } + + class SinopeTechnologiesIasZoneCluster(CustomCluster, IasZone): """SinopeTechnologiesIasZoneCluster custom cluster.""" + class zoneStatus(t.enum8): + dry = 0x00 + leak = 0x01 + attributes = IasZone.attributes.copy() attributes.update( { - 0x0030: ("zoneStatus", t.enum8, True), + 0x0030: ("zoneStatus", zoneStatus, True), } ) @@ -85,7 +101,7 @@ class SinopeTechnologiesSensor(CustomDevice): TemperatureMeasurement.cluster_id, SinopeTechnologiesIasZoneCluster, Diagnostic.cluster_id, - SINOPE_MANUFACTURER_CLUSTER_ID, + SinopeManufacturerCluster, ], OUTPUT_CLUSTERS: [ Identify.cluster_id, @@ -142,7 +158,7 @@ class SinopeTechnologiesSensor2(CustomDevice): TemperatureMeasurement.cluster_id, SinopeTechnologiesIasZoneCluster, Diagnostic.cluster_id, - SINOPE_MANUFACTURER_CLUSTER_ID, + SinopeManufacturerCluster, ], OUTPUT_CLUSTERS: [ Identify.cluster_id, diff --git a/switch.py b/switch.py index 66910b6..d87a9d8 100644 --- a/switch.py +++ b/switch.py @@ -42,18 +42,25 @@ class SinopeManufacturerCluster(CustomCluster): """SinopeManufacturerCluster manufacturer cluster.""" + class keypadLock(t.enum8): + Unlocked = 0x00 + Locked = 0x01 + cluster_id = SINOPE_MANUFACTURER_CLUSTER_ID name = "Sinopé Manufacturer specific" ep_attribute = "sinope_manufacturer_specific" attributes = { - 0x0002: ("KeyboardLock", t.enum8, True), + 0x0002: ("KeyboardLock", keypadLock, True), + 0x0004: ("firmware_version", t.CharacterString, True), 0x0060: ("ConnectedLoad", t.uint16_t, True), 0x0070: ("CurrentLoad", t.bitmap8, True), 0x0076: ("drConfigWaterTempMin", t.uint8_t, True), 0x0077: ("drConfigWaterTempTime", t.uint8_t, True), 0x0078: ("drWTTimeOn", t.uint16_t, True), 0x00A0: ("Timer", t.uint32_t, True), + 0x0200: ("Unknown", t.bitmap32, True), 0x0283: ("ColdLoadPickupStatus", t.uint8_t, True), + 0xFFFD: ("cluster_revision", t.uint16_t, True), } @@ -102,7 +109,7 @@ class SinopeTechnologiesSwitch(CustomDevice): OnOff.cluster_id, CustomMeteringCluster, ElectricalMeasurement.cluster_id, - SINOPE_MANUFACTURER_CLUSTER_ID, + SinopeManufacturerCluster, ], OUTPUT_CLUSTERS: [Ota.cluster_id], } @@ -220,7 +227,7 @@ class SinopeTechnologiesValve(CustomDevice): OnOff.cluster_id, LevelControl.cluster_id, Diagnostic.cluster_id, - SINOPE_MANUFACTURER_CLUSTER_ID, + SinopeManufacturerCluster, ], OUTPUT_CLUSTERS: [ Identify.cluster_id, @@ -432,7 +439,7 @@ class SinopeTechnologiesNewSwitch(CustomDevice): CustomMeteringCluster, ElectricalMeasurement.cluster_id, LightLink.cluster_id, - SINOPE_MANUFACTURER_CLUSTER_ID, + SinopeManufacturerCluster, ], OUTPUT_CLUSTERS: [ Ota.cluster_id, diff --git a/thermostat.py b/thermostat.py index b5f190c..3e1822f 100644 --- a/thermostat.py +++ b/thermostat.py @@ -37,44 +37,93 @@ class SinopeTechnologiesManufacturerCluster(CustomCluster): """SinopeTechnologiesManufacturerCluster manufacturer cluster.""" + class keypadLock(t.enum8): + Unlocked = 0x00 + Locked = 0x01 + + class display(t.enum8): + Auto = 0x00 + OutsideTemperature = 0x01 + Setpoint = 0x02 + + class floorMode(t.enum8): + airByFloor = 0x01 + Floor = 0x02 + + class auxMode(t.enum8): + off = 0x00 + on = 0x01 + + class sensorType(t.enum8): + Ten_k = 0x00 + Twelve_k = 0x01 + + class timeFormat(t.enum8): + Twenty_four_h = 0x00 + Twelve_h = 0x01 + + class gfciStatus(t.enum8): + ok = 0x00 + error = 0x01 + + class mode(t.enum8): + off = 0x00 + heat = 0x04 + cluster_id = SINOPE_MANUFACTURER_CLUSTER_ID name = "Sinopé Technologies Manufacturer specific" ep_attribute = "sinope_manufacturer_specific" attributes = { + 0x0002: ("keypadLockout", keypadLock, True), + 0x0004: ("firmware_version", t.CharacterString, True), 0x0010: ("outdoor_temp", t.int16s, True), 0x0011: ("outdoor_temp_timeout", t.uint16_t, True), - 0x0012: ("config2ndDisplay", t.enum8, True), + 0x0012: ("config2ndDisplay", display, True), 0x0020: ("secs_since_2k", t.uint32_t, True), 0x0070: ("currentLoad", t.bitmap8, True), 0x0071: ("ecoMode", t.int8s, True), 0x0072: ("ecoMode1", t.uint8_t, True), 0x0073: ("ecoMode2", t.uint8_t, True), - 0x0105: ("airFloorMode", t.enum8, True), - 0x0106: ("auxOutputMode", t.enum8, True), + 0x0104: ("setpoint", t.int16s, True), + 0x0105: ("airFloorMode", floorMode, True), + 0x0106: ("auxOutputMode", auxMode, True), + 0x0107: ("FloorTemperature", t.int16s, True), 0x0108: ("airMaxLimit", t.int16s, True), 0x0109: ("floorMinSetpoint", t.int16s, True), 0x010A: ("floorMaxSetpoint", t.int16s, True), - 0x010B: ("tempSensorType", t.enum8, True), + 0x010B: ("FloorSensorTypeParam", sensorType, True), 0x010C: ("floorLimitStatus", t.uint8_t, True), - 0x0114: ("timeFormat", t.enum8, True), - 0x0115: ("gfciStatus", t.enum8, True), + 0x010D: ("RoomTemperature", t.int16s, True), + 0x0114: ("timeFormat", timeFormat, True), + 0x0115: ("gfciStatus", gfciStatus, True), 0x0118: ("auxConnectedLoad", t.uint16_t, True), 0x0119: ("ConnectedLoad", t.uint16_t, True), 0x0128: ("pumpProtection", t.uint8_t, True), 0x012D: ("reportLocalTemperature", t.int16s, True), + 0x0200: ("Unknown", t.bitmap32, True), + 0xFFFD: ("ClusterRevision", t.uint16_t, True), } class SinopeTechnologiesThermostatCluster(CustomCluster, Thermostat): """SinopeTechnologiesThermostatCluster custom cluster.""" + class occupancy(t.enum8): + away = 0x01 + home = 0x02 + + class backlight(t.enum8): + on_demand = 0x00 + always_on = 0x01 + attributes = Thermostat.attributes.copy() attributes.update( { - 0x0400: ("set_occupancy", t.enum8, True), + 0x0400: ("set_occupancy", occupancy, True), 0x0401: ("mainCycleOutput", t.uint16_t, True), - 0x0402: ("backlightAutoDimParam", t.enum8, True), + 0x0402: ("backlightAutoDimParam", backlight, True), 0x0404: ("auxCycleOutput", t.uint16_t, True), + 0xFFFD: ("cluster_revision", t.uint16_t, True), } )