From 50b26b9c1c0600a0f7ec2b710ee90beb25da5ed6 Mon Sep 17 00:00:00 2001 From: Felix Kwan Date: Fri, 11 Apr 2025 21:08:44 +0800 Subject: [PATCH 01/17] initial draft for aqara z1 pro single rocker support --- zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py | 151 ++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py new file mode 100644 index 0000000000..3ea5ea25a9 --- /dev/null +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py @@ -0,0 +1,151 @@ +"""Aqara Z1 Pro single rocker switch quirks.""" + +from zigpy.profiles import zha +from zigpy.quirks import CustomDevice +from zigpy.zcl.clusters.general import ( + AnalogInput, + Basic, + Groups, + Identify, + MultistateInput, + OnOff, + Ota, + Scenes, + Time, +) + +from zhaquirks.const import ( + DEVICE_TYPE, + ENDPOINTS, + INPUT_CLUSTERS, + MODELS_INFO, + OUTPUT_CLUSTERS, + PROFILE_ID, +) +from zhaquirks.xiaomi import ( + LUMI, + AnalogInputCluster, + BasicCluster, + ElectricalMeasurementCluster, + MeteringCluster, + OnOffCluster, +) +from zhaquirks.xiaomi.aqara.opple_remote import MultistateInputCluster + +MANUFACTURER_SPECIFIC_CLUSTER_ID = "0xfcc0" + +class AqaraZ1ProSingleRockerSwitch(CustomDevice): + """Aqara Z1 Pro Single Rocker Switch""" + + signature = { + MODELS_INFO: [(LUMI, "lumi.switch.acn056")], + ENDPOINTS: { + 1: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT, + INPUT_CLUSTERS: [ + Basic.cluster_id, + Identify.cluster_id, + Groups.cluster_id, + Scenes.cluster_id, + OnOff.cluster_id, + MultistateInput.cluster_id, + MeteringCluster.cluster_id, + ElectricalMeasurementCluster.cluster_id, + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [ + Time.cluster_id, + Ota.cluster_id, + ], + }, + 2: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT, + INPUT_CLUSTERS: [ + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [], + }, + 3: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT, + INPUT_CLUSTERS: [ + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [], + }, + 4: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT, + INPUT_CLUSTERS: [ + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [], + }, + 21: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT, + INPUT_CLUSTERS: [ + AnalogInput.cluster_id, + ], + OUTPUT_CLUSTERS: [], + }, + }, + } + + replacement = { + ENDPOINTS: { + 1: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + BasicCluster, + Identify.cluster_id, + Groups.cluster_id, + Scenes.cluster_id, + OnOffCluster, + MultistateInputCluster, + MeteringCluster, + ElectricalMeasurementCluster, + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [ + Time.cluster_id, + Ota.cluster_id, + ], + }, + 2: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [], + }, + 3: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [], + }, + 4: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [], + }, + 21: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + AnalogInputCluster, + ], + OUTPUT_CLUSTERS: [], + }, + }, + } \ No newline at end of file From 66a87ece4cb4ac27ef0c580a4a531587078d1ff3 Mon Sep 17 00:00:00 2001 From: Felix Kwan Date: Sat, 12 Apr 2025 17:12:57 +0800 Subject: [PATCH 02/17] add temporary logs; fix inherit class and model info --- zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py | 122 ++++++++++++++++-- 1 file changed, 113 insertions(+), 9 deletions(-) diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py index 3ea5ea25a9..14ce0ddaa7 100644 --- a/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py @@ -1,7 +1,9 @@ """Aqara Z1 Pro single rocker switch quirks.""" +import logging +import sys from zigpy.profiles import zha -from zigpy.quirks import CustomDevice +from zigpy.quirks import CustomDevice, CustomCluster from zigpy.zcl.clusters.general import ( AnalogInput, Basic, @@ -29,20 +31,122 @@ ElectricalMeasurementCluster, MeteringCluster, OnOffCluster, + XiaomiCustomDevice, ) from zhaquirks.xiaomi.aqara.opple_remote import MultistateInputCluster -MANUFACTURER_SPECIFIC_CLUSTER_ID = "0xfcc0" +# Set up logging with a more visible format +_LOGGER = logging.getLogger(__name__) +_LOGGER.setLevel(logging.DEBUG) -class AqaraZ1ProSingleRockerSwitch(CustomDevice): +# Add a console handler to ensure logs go to stdout +console_handler = logging.StreamHandler(sys.stdout) +console_handler.setLevel(logging.DEBUG) +formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +console_handler.setFormatter(formatter) +_LOGGER.addHandler(console_handler) + +# Log at module level to verify the file is being loaded +_LOGGER.debug("AqaraZ1ProSingleRockerSwitch quirk module is being loaded! ZHA Profile ID: 0x%04x, Device Type: 0x%04x", zha.PROFILE_ID, zha.DeviceType.ON_OFF_SWITCH) + +class AqaraZ1ProSliderCluster(CustomCluster): + """Custom cluster for Aqara Z1 Pro slider events.""" + + cluster_id = 0xfcc0 + + # Attribute IDs + ATTR_SLIDER_ACTION = 0x028C # 652 + ATTR_SLIDE_TIME = 0x0231 # 561 + ATTR_SLIDE_SPEED = 0x0232 # 562 + ATTR_SLIDE_RELATIVE_DISPLACEMENT = 0x0233 # 563 + ATTR_SLIDE_TIME_DELTA = 0x0301 # 769 + + # Action mapping + ACTION_MAPPING = { + 1: "slider_single", + 2: "slider_double", + 3: "slider_hold", + 4: "slider_up", + 5: "slider_down", + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._attr_id = self.ATTR_SLIDER_ACTION + _LOGGER.critical("AqaraZ1ProSliderCluster initialized for device %s", self._endpoint.device.ieee) + + async def _update_attribute(self, attrid, value): + """Handle attribute updates.""" + _LOGGER.critical("AqaraZ1ProSliderCluster attribute update: attrid=0x%04x, value=%s", attrid, value) + super()._update_attribute(attrid, value) + + # Store all attributes for the event + if not hasattr(self, "_slider_attrs"): + self._slider_attrs = {} + + # Update the attribute value + self._slider_attrs[attrid] = value + + # If this is the slider action attribute, send the event + if attrid == self.ATTR_SLIDER_ACTION: + # Get the action name from the mapping + action = self.ACTION_MAPPING.get(value, f"slider_unknown_{value}") + _LOGGER.critical("AqaraZ1ProSliderCluster detected action: %s (value: %s)", action, value) + + # Prepare the event data + event_data = { + "device_ieee": str(self._endpoint.device.ieee), + "endpoint_id": self._endpoint.endpoint_id, + "cluster_id": self.cluster_id, + "command": action, + "args": { + "action": action, + "value": value, + "slide_time": self._slider_attrs.get(self.ATTR_SLIDE_TIME), + "slide_speed": self._slider_attrs.get(self.ATTR_SLIDE_SPEED), + "slide_relative_displacement": self._slider_attrs.get(self.ATTR_SLIDE_RELATIVE_DISPLACEMENT), + "slide_time_delta": self._slider_attrs.get(self.ATTR_SLIDE_TIME_DELTA), + }, + } + + _LOGGER.critical("AqaraZ1ProSliderCluster sending event data: %s", event_data) + + # Send the event + self.listener_event( + "zha_send_event", + action, + event_data, + ) + + # Also send a generic slider event for easier automation + self.listener_event( + "zha_send_event", + "slider_event", + event_data, + ) + _LOGGER.critical("AqaraZ1ProSliderCluster events sent successfully") + + async def test_logging(self): + """Test method to verify logging is working.""" + _LOGGER.critical("AqaraZ1ProSliderCluster TEST LOGGING - This should appear in Home Assistant logs") + return True + + +class AqaraZ1ProSingleRockerSwitch(XiaomiCustomDevice): """Aqara Z1 Pro Single Rocker Switch""" + MANUFACTURER_SPECIFIC_CLUSTER_ID = 0xfcc0 + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + _LOGGER.debug("AqaraZ1ProSingleRockerSwitch device initialized with IEEE: %s", self.ieee) + signature = { - MODELS_INFO: [(LUMI, "lumi.switch.acn056")], + MODELS_INFO: [("Aqara", "lumi.switch.acn056")], ENDPOINTS: { 1: { PROFILE_ID: zha.PROFILE_ID, - DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, INPUT_CLUSTERS: [ Basic.cluster_id, Identify.cluster_id, @@ -61,7 +165,7 @@ class AqaraZ1ProSingleRockerSwitch(CustomDevice): }, 2: { PROFILE_ID: zha.PROFILE_ID, - DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, INPUT_CLUSTERS: [ MANUFACTURER_SPECIFIC_CLUSTER_ID, ], @@ -69,7 +173,7 @@ class AqaraZ1ProSingleRockerSwitch(CustomDevice): }, 3: { PROFILE_ID: zha.PROFILE_ID, - DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, INPUT_CLUSTERS: [ MANUFACTURER_SPECIFIC_CLUSTER_ID, ], @@ -77,7 +181,7 @@ class AqaraZ1ProSingleRockerSwitch(CustomDevice): }, 4: { PROFILE_ID: zha.PROFILE_ID, - DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, INPUT_CLUSTERS: [ MANUFACTURER_SPECIFIC_CLUSTER_ID, ], @@ -85,7 +189,7 @@ class AqaraZ1ProSingleRockerSwitch(CustomDevice): }, 21: { PROFILE_ID: zha.PROFILE_ID, - DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, INPUT_CLUSTERS: [ AnalogInput.cluster_id, ], From 9c45924122b429b03efb95165fbb15b55e5ce248 Mon Sep 17 00:00:00 2001 From: Felix Kwan Date: Sat, 12 Apr 2025 18:21:21 +0800 Subject: [PATCH 03/17] add AqaraZ1ProSliderCluster to replacement; update log level to debug --- zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py index 14ce0ddaa7..adf968b121 100644 --- a/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py @@ -73,11 +73,11 @@ class AqaraZ1ProSliderCluster(CustomCluster): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._attr_id = self.ATTR_SLIDER_ACTION - _LOGGER.critical("AqaraZ1ProSliderCluster initialized for device %s", self._endpoint.device.ieee) + _LOGGER.debug("AqaraZ1ProSliderCluster initialized for device %s", self._endpoint.device.ieee) async def _update_attribute(self, attrid, value): """Handle attribute updates.""" - _LOGGER.critical("AqaraZ1ProSliderCluster attribute update: attrid=0x%04x, value=%s", attrid, value) + _LOGGER.debug("AqaraZ1ProSliderCluster attribute update: attrid=0x%04x, value=%s", attrid, value) super()._update_attribute(attrid, value) # Store all attributes for the event @@ -91,7 +91,7 @@ async def _update_attribute(self, attrid, value): if attrid == self.ATTR_SLIDER_ACTION: # Get the action name from the mapping action = self.ACTION_MAPPING.get(value, f"slider_unknown_{value}") - _LOGGER.critical("AqaraZ1ProSliderCluster detected action: %s (value: %s)", action, value) + _LOGGER.debug("AqaraZ1ProSliderCluster detected action: %s (value: %s)", action, value) # Prepare the event data event_data = { @@ -109,7 +109,7 @@ async def _update_attribute(self, attrid, value): }, } - _LOGGER.critical("AqaraZ1ProSliderCluster sending event data: %s", event_data) + _LOGGER.debug("AqaraZ1ProSliderCluster sending event data: %s", event_data) # Send the event self.listener_event( @@ -124,12 +124,7 @@ async def _update_attribute(self, attrid, value): "slider_event", event_data, ) - _LOGGER.critical("AqaraZ1ProSliderCluster events sent successfully") - - async def test_logging(self): - """Test method to verify logging is working.""" - _LOGGER.critical("AqaraZ1ProSliderCluster TEST LOGGING - This should appear in Home Assistant logs") - return True + _LOGGER.debug("AqaraZ1ProSliderCluster events sent successfully") class AqaraZ1ProSingleRockerSwitch(XiaomiCustomDevice): @@ -212,7 +207,7 @@ def __init__(self, *args, **kwargs): MultistateInputCluster, MeteringCluster, ElectricalMeasurementCluster, - MANUFACTURER_SPECIFIC_CLUSTER_ID, + AqaraZ1ProSliderCluster, ], OUTPUT_CLUSTERS: [ Time.cluster_id, From 9b6a6ddf86299933fd708f2ff76ce4444f7aa2df Mon Sep 17 00:00:00 2001 From: Felix Kwan Date: Sat, 12 Apr 2025 18:50:09 +0800 Subject: [PATCH 04/17] fix update attribute bug --- zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py index adf968b121..163e32bc59 100644 --- a/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py @@ -75,7 +75,7 @@ def __init__(self, *args, **kwargs): self._attr_id = self.ATTR_SLIDER_ACTION _LOGGER.debug("AqaraZ1ProSliderCluster initialized for device %s", self._endpoint.device.ieee) - async def _update_attribute(self, attrid, value): + def _update_attribute(self, attrid, value): """Handle attribute updates.""" _LOGGER.debug("AqaraZ1ProSliderCluster attribute update: attrid=0x%04x, value=%s", attrid, value) super()._update_attribute(attrid, value) From d209a9c9635b2a38c7bbd300f44333c64f922583 Mon Sep 17 00:00:00 2001 From: Felix Kwan Date: Sat, 12 Apr 2025 19:14:21 +0800 Subject: [PATCH 05/17] rename cluster --- zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py index 163e32bc59..9b927ba0e3 100644 --- a/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py @@ -49,8 +49,8 @@ # Log at module level to verify the file is being loaded _LOGGER.debug("AqaraZ1ProSingleRockerSwitch quirk module is being loaded! ZHA Profile ID: 0x%04x, Device Type: 0x%04x", zha.PROFILE_ID, zha.DeviceType.ON_OFF_SWITCH) -class AqaraZ1ProSliderCluster(CustomCluster): - """Custom cluster for Aqara Z1 Pro slider events.""" +class AqaraZ1ProManufacturerSpecificCluster(CustomCluster): + """Custom cluster for Aqara Z1 Pro manufacturer specific events.""" cluster_id = 0xfcc0 @@ -73,25 +73,25 @@ class AqaraZ1ProSliderCluster(CustomCluster): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._attr_id = self.ATTR_SLIDER_ACTION - _LOGGER.debug("AqaraZ1ProSliderCluster initialized for device %s", self._endpoint.device.ieee) + _LOGGER.debug("AqaraZ1ProManufacturerSpecificCluster initialized for device %s", self._endpoint.device.ieee) def _update_attribute(self, attrid, value): """Handle attribute updates.""" - _LOGGER.debug("AqaraZ1ProSliderCluster attribute update: attrid=0x%04x, value=%s", attrid, value) + _LOGGER.debug("AqaraZ1ProManufacturerSpecificCluster attribute update: attrid=0x%04x, value=%s", attrid, value) super()._update_attribute(attrid, value) # Store all attributes for the event - if not hasattr(self, "_slider_attrs"): - self._slider_attrs = {} + if not hasattr(self, "_manufacturer_attrs"): + self._manufacturer_attrs = {} # Update the attribute value - self._slider_attrs[attrid] = value + self._manufacturer_attrs[attrid] = value # If this is the slider action attribute, send the event if attrid == self.ATTR_SLIDER_ACTION: # Get the action name from the mapping action = self.ACTION_MAPPING.get(value, f"slider_unknown_{value}") - _LOGGER.debug("AqaraZ1ProSliderCluster detected action: %s (value: %s)", action, value) + _LOGGER.debug("AqaraZ1ProManufacturerSpecificCluster detected action: %s (value: %s)", action, value) # Prepare the event data event_data = { @@ -102,14 +102,14 @@ def _update_attribute(self, attrid, value): "args": { "action": action, "value": value, - "slide_time": self._slider_attrs.get(self.ATTR_SLIDE_TIME), - "slide_speed": self._slider_attrs.get(self.ATTR_SLIDE_SPEED), - "slide_relative_displacement": self._slider_attrs.get(self.ATTR_SLIDE_RELATIVE_DISPLACEMENT), - "slide_time_delta": self._slider_attrs.get(self.ATTR_SLIDE_TIME_DELTA), + "slide_time": self._manufacturer_attrs.get(self.ATTR_SLIDE_TIME), + "slide_speed": self._manufacturer_attrs.get(self.ATTR_SLIDE_SPEED), + "slide_relative_displacement": self._manufacturer_attrs.get(self.ATTR_SLIDE_RELATIVE_DISPLACEMENT), + "slide_time_delta": self._manufacturer_attrs.get(self.ATTR_SLIDE_TIME_DELTA), }, } - _LOGGER.debug("AqaraZ1ProSliderCluster sending event data: %s", event_data) + _LOGGER.debug("AqaraZ1ProManufacturerSpecificCluster sending event data: %s", event_data) # Send the event self.listener_event( @@ -124,7 +124,7 @@ def _update_attribute(self, attrid, value): "slider_event", event_data, ) - _LOGGER.debug("AqaraZ1ProSliderCluster events sent successfully") + _LOGGER.debug("AqaraZ1ProManufacturerSpecificCluster events sent successfully") class AqaraZ1ProSingleRockerSwitch(XiaomiCustomDevice): @@ -207,7 +207,7 @@ def __init__(self, *args, **kwargs): MultistateInputCluster, MeteringCluster, ElectricalMeasurementCluster, - AqaraZ1ProSliderCluster, + AqaraZ1ProManufacturerSpecificCluster, ], OUTPUT_CLUSTERS: [ Time.cluster_id, From 0ce97f446cdeffc627379cc13ff31c701d8f03df Mon Sep 17 00:00:00 2001 From: Felix Kwan Date: Sat, 12 Apr 2025 19:42:21 +0800 Subject: [PATCH 06/17] add discovered attributes ID --- zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py index 9b927ba0e3..4efe0d1710 100644 --- a/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py @@ -60,6 +60,12 @@ class AqaraZ1ProManufacturerSpecificCluster(CustomCluster): ATTR_SLIDE_SPEED = 0x0232 # 562 ATTR_SLIDE_RELATIVE_DISPLACEMENT = 0x0233 # 563 ATTR_SLIDE_TIME_DELTA = 0x0301 # 769 + + # ATTR_DEVICE_ID_SHADE = 0x0200 # 512 + # ATTR_LOCK_RELAY = 0x0285 # 645 + # ATTR_SWITCH_MODE = 0x0004 # 4 + # ATTR_POWER_ON_BEHAVIOR = 0x0517 # 1303 + # ATTR_CLICK_MODE = 0x0125 # 293 # Action mapping ACTION_MAPPING = { From 14b9d02263731068006315e2758c301636e3a3da Mon Sep 17 00:00:00 2001 From: Felix Kwan Date: Fri, 18 Apr 2025 22:43:10 +0800 Subject: [PATCH 07/17] minor fix in custom cluster --- zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py index 4efe0d1710..220faa464c 100644 --- a/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py @@ -23,6 +23,7 @@ MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, + ZHA_SEND_EVENT, ) from zhaquirks.xiaomi import ( LUMI, @@ -83,8 +84,6 @@ def __init__(self, *args, **kwargs): def _update_attribute(self, attrid, value): """Handle attribute updates.""" - _LOGGER.debug("AqaraZ1ProManufacturerSpecificCluster attribute update: attrid=0x%04x, value=%s", attrid, value) - super()._update_attribute(attrid, value) # Store all attributes for the event if not hasattr(self, "_manufacturer_attrs"): @@ -119,19 +118,21 @@ def _update_attribute(self, attrid, value): # Send the event self.listener_event( - "zha_send_event", + ZHA_SEND_EVENT, action, event_data, ) # Also send a generic slider event for easier automation self.listener_event( - "zha_send_event", + ZHA_SEND_EVENT, "slider_event", event_data, ) _LOGGER.debug("AqaraZ1ProManufacturerSpecificCluster events sent successfully") + _LOGGER.debug("AqaraZ1ProManufacturerSpecificCluster attribute update: attrid=0x%04x, value=%s", attrid, value) + super()._update_attribute(attrid, value) class AqaraZ1ProSingleRockerSwitch(XiaomiCustomDevice): """Aqara Z1 Pro Single Rocker Switch""" From a37cff58d79a935718469ba2f54da2ee73490f6c Mon Sep 17 00:00:00 2001 From: Felix Kwan Date: Fri, 18 Apr 2025 22:56:00 +0800 Subject: [PATCH 08/17] update event structure --- zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py index 220faa464c..d50b521c4c 100644 --- a/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py @@ -100,18 +100,12 @@ def _update_attribute(self, attrid, value): # Prepare the event data event_data = { - "device_ieee": str(self._endpoint.device.ieee), - "endpoint_id": self._endpoint.endpoint_id, - "cluster_id": self.cluster_id, - "command": action, - "args": { - "action": action, - "value": value, - "slide_time": self._manufacturer_attrs.get(self.ATTR_SLIDE_TIME), - "slide_speed": self._manufacturer_attrs.get(self.ATTR_SLIDE_SPEED), - "slide_relative_displacement": self._manufacturer_attrs.get(self.ATTR_SLIDE_RELATIVE_DISPLACEMENT), - "slide_time_delta": self._manufacturer_attrs.get(self.ATTR_SLIDE_TIME_DELTA), - }, + "action": action, + "value": value, + "slide_time": self._manufacturer_attrs.get(self.ATTR_SLIDE_TIME), + "slide_speed": self._manufacturer_attrs.get(self.ATTR_SLIDE_SPEED), + "slide_relative_displacement": self._manufacturer_attrs.get(self.ATTR_SLIDE_RELATIVE_DISPLACEMENT), + "slide_time_delta": self._manufacturer_attrs.get(self.ATTR_SLIDE_TIME_DELTA), } _LOGGER.debug("AqaraZ1ProManufacturerSpecificCluster sending event data: %s", event_data) From b8bb6e9786ea7ba4e7dbc643edefdc492e228c3e Mon Sep 17 00:00:00 2001 From: Felix Kwan Date: Fri, 18 Apr 2025 23:14:24 +0800 Subject: [PATCH 09/17] separate custom cluster into __init__ --- zhaquirks/xiaomi/__init__.py | 78 ++++++++++++++++++ zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py | 81 +------------------ 2 files changed, 79 insertions(+), 80 deletions(-) diff --git a/zhaquirks/xiaomi/__init__.py b/zhaquirks/xiaomi/__init__.py index 4d2f53670a..034b587722 100644 --- a/zhaquirks/xiaomi/__init__.py +++ b/zhaquirks/xiaomi/__init__.py @@ -731,6 +731,84 @@ def command( bytes([src_ep, tsn, command_id]), expect_reply=expect_reply, ) + +class AqaraZ1ProManufacturerSpecificCluster(CustomCluster): + """Custom cluster for Aqara Z1 Pro manufacturer specific events.""" + + cluster_id = 0xfcc0 + + # Attribute IDs + ATTR_SLIDER_ACTION = 0x028C # 652 + ATTR_SLIDE_TIME = 0x0231 # 561 + ATTR_SLIDE_SPEED = 0x0232 # 562 + ATTR_SLIDE_RELATIVE_DISPLACEMENT = 0x0233 # 563 + ATTR_SLIDE_TIME_DELTA = 0x0301 # 769 + + # ATTR_DEVICE_ID_SHADE = 0x0200 # 512 + # ATTR_LOCK_RELAY = 0x0285 # 645 + # ATTR_SWITCH_MODE = 0x0004 # 4 + # ATTR_POWER_ON_BEHAVIOR = 0x0517 # 1303 + # ATTR_CLICK_MODE = 0x0125 # 293 + + # Action mapping + ACTION_MAPPING = { + 1: "slider_single", + 2: "slider_double", + 3: "slider_hold", + 4: "slider_up", + 5: "slider_down", + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._attr_id = self.ATTR_SLIDER_ACTION + _LOGGER.debug("AqaraZ1ProManufacturerSpecificCluster initialized for device %s", self._endpoint.device.ieee) + + def _update_attribute(self, attrid, value): + """Handle attribute updates.""" + + # Store all attributes for the event + if not hasattr(self, "_manufacturer_attrs"): + self._manufacturer_attrs = {} + + # Update the attribute value + self._manufacturer_attrs[attrid] = value + + # If this is the slider action attribute, send the event + if attrid == self.ATTR_SLIDER_ACTION: + # Get the action name from the mapping + action = self.ACTION_MAPPING.get(value, f"slider_unknown_{value}") + _LOGGER.debug("AqaraZ1ProManufacturerSpecificCluster detected action: %s (value: %s)", action, value) + + # Prepare the event data + event_data = { + "action": action, + "value": value, + "slide_time": self._manufacturer_attrs.get(self.ATTR_SLIDE_TIME), + "slide_speed": self._manufacturer_attrs.get(self.ATTR_SLIDE_SPEED), + "slide_relative_displacement": self._manufacturer_attrs.get(self.ATTR_SLIDE_RELATIVE_DISPLACEMENT), + "slide_time_delta": self._manufacturer_attrs.get(self.ATTR_SLIDE_TIME_DELTA), + } + + _LOGGER.debug("AqaraZ1ProManufacturerSpecificCluster sending event data: %s", event_data) + + # Send the event + self.listener_event( + ZHA_SEND_EVENT, + action, + event_data, + ) + + # Also send a generic slider event for easier automation + self.listener_event( + ZHA_SEND_EVENT, + "slider_event", + event_data, + ) + _LOGGER.debug("AqaraZ1ProManufacturerSpecificCluster events sent successfully") + + _LOGGER.debug("AqaraZ1ProManufacturerSpecificCluster attribute update: attrid=0x%04x, value=%s", attrid, value) + super()._update_attribute(attrid, value) def handle_quick_init( diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py index d50b521c4c..d9bdb32681 100644 --- a/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py @@ -3,7 +3,6 @@ import logging import sys from zigpy.profiles import zha -from zigpy.quirks import CustomDevice, CustomCluster from zigpy.zcl.clusters.general import ( AnalogInput, Basic, @@ -23,7 +22,6 @@ MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, - ZHA_SEND_EVENT, ) from zhaquirks.xiaomi import ( LUMI, @@ -33,6 +31,7 @@ MeteringCluster, OnOffCluster, XiaomiCustomDevice, + AqaraZ1ProManufacturerSpecificCluster ) from zhaquirks.xiaomi.aqara.opple_remote import MultistateInputCluster @@ -50,84 +49,6 @@ # Log at module level to verify the file is being loaded _LOGGER.debug("AqaraZ1ProSingleRockerSwitch quirk module is being loaded! ZHA Profile ID: 0x%04x, Device Type: 0x%04x", zha.PROFILE_ID, zha.DeviceType.ON_OFF_SWITCH) -class AqaraZ1ProManufacturerSpecificCluster(CustomCluster): - """Custom cluster for Aqara Z1 Pro manufacturer specific events.""" - - cluster_id = 0xfcc0 - - # Attribute IDs - ATTR_SLIDER_ACTION = 0x028C # 652 - ATTR_SLIDE_TIME = 0x0231 # 561 - ATTR_SLIDE_SPEED = 0x0232 # 562 - ATTR_SLIDE_RELATIVE_DISPLACEMENT = 0x0233 # 563 - ATTR_SLIDE_TIME_DELTA = 0x0301 # 769 - - # ATTR_DEVICE_ID_SHADE = 0x0200 # 512 - # ATTR_LOCK_RELAY = 0x0285 # 645 - # ATTR_SWITCH_MODE = 0x0004 # 4 - # ATTR_POWER_ON_BEHAVIOR = 0x0517 # 1303 - # ATTR_CLICK_MODE = 0x0125 # 293 - - # Action mapping - ACTION_MAPPING = { - 1: "slider_single", - 2: "slider_double", - 3: "slider_hold", - 4: "slider_up", - 5: "slider_down", - } - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._attr_id = self.ATTR_SLIDER_ACTION - _LOGGER.debug("AqaraZ1ProManufacturerSpecificCluster initialized for device %s", self._endpoint.device.ieee) - - def _update_attribute(self, attrid, value): - """Handle attribute updates.""" - - # Store all attributes for the event - if not hasattr(self, "_manufacturer_attrs"): - self._manufacturer_attrs = {} - - # Update the attribute value - self._manufacturer_attrs[attrid] = value - - # If this is the slider action attribute, send the event - if attrid == self.ATTR_SLIDER_ACTION: - # Get the action name from the mapping - action = self.ACTION_MAPPING.get(value, f"slider_unknown_{value}") - _LOGGER.debug("AqaraZ1ProManufacturerSpecificCluster detected action: %s (value: %s)", action, value) - - # Prepare the event data - event_data = { - "action": action, - "value": value, - "slide_time": self._manufacturer_attrs.get(self.ATTR_SLIDE_TIME), - "slide_speed": self._manufacturer_attrs.get(self.ATTR_SLIDE_SPEED), - "slide_relative_displacement": self._manufacturer_attrs.get(self.ATTR_SLIDE_RELATIVE_DISPLACEMENT), - "slide_time_delta": self._manufacturer_attrs.get(self.ATTR_SLIDE_TIME_DELTA), - } - - _LOGGER.debug("AqaraZ1ProManufacturerSpecificCluster sending event data: %s", event_data) - - # Send the event - self.listener_event( - ZHA_SEND_EVENT, - action, - event_data, - ) - - # Also send a generic slider event for easier automation - self.listener_event( - ZHA_SEND_EVENT, - "slider_event", - event_data, - ) - _LOGGER.debug("AqaraZ1ProManufacturerSpecificCluster events sent successfully") - - _LOGGER.debug("AqaraZ1ProManufacturerSpecificCluster attribute update: attrid=0x%04x, value=%s", attrid, value) - super()._update_attribute(attrid, value) - class AqaraZ1ProSingleRockerSwitch(XiaomiCustomDevice): """Aqara Z1 Pro Single Rocker Switch""" From 7e0d3e35a9927cab4864df1ca7bd909f3baa9fae Mon Sep 17 00:00:00 2001 From: Felix Kwan Date: Fri, 18 Apr 2025 23:44:42 +0800 Subject: [PATCH 10/17] support double, triple and quadruple rocker --- zhaquirks/xiaomi/aqara/aqara_z1_pro_double.py | 180 ++++++++++++++++ .../xiaomi/aqara/aqara_z1_pro_quadruple.py | 196 ++++++++++++++++++ zhaquirks/xiaomi/aqara/aqara_z1_pro_triple.py | 188 +++++++++++++++++ 3 files changed, 564 insertions(+) create mode 100644 zhaquirks/xiaomi/aqara/aqara_z1_pro_double.py create mode 100644 zhaquirks/xiaomi/aqara/aqara_z1_pro_quadruple.py create mode 100644 zhaquirks/xiaomi/aqara/aqara_z1_pro_triple.py diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_double.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_double.py new file mode 100644 index 0000000000..759de80aa0 --- /dev/null +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_double.py @@ -0,0 +1,180 @@ +"""Aqara Z1 Pro double rocker switch quirks.""" + +import logging +import sys +from zigpy.profiles import zha +from zigpy.zcl.clusters.general import ( + AnalogInput, + Basic, + Groups, + Identify, + MultistateInput, + OnOff, + Ota, + Scenes, + Time, +) + +from zhaquirks.const import ( + DEVICE_TYPE, + ENDPOINTS, + INPUT_CLUSTERS, + MODELS_INFO, + OUTPUT_CLUSTERS, + PROFILE_ID, +) +from zhaquirks.xiaomi import ( + LUMI, + AnalogInputCluster, + BasicCluster, + ElectricalMeasurementCluster, + MeteringCluster, + OnOffCluster, + XiaomiCustomDevice, + AqaraZ1ProManufacturerSpecificCluster +) +from zhaquirks.xiaomi.aqara.opple_remote import MultistateInputCluster + +# Set up logging with a more visible format +_LOGGER = logging.getLogger(__name__) +_LOGGER.setLevel(logging.DEBUG) + +# Add a console handler to ensure logs go to stdout +console_handler = logging.StreamHandler(sys.stdout) +console_handler.setLevel(logging.DEBUG) +formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +console_handler.setFormatter(formatter) +_LOGGER.addHandler(console_handler) + +# Log at module level to verify the file is being loaded +_LOGGER.debug("AqaraZ1ProDoubleRockerSwitch quirk module is being loaded! ZHA Profile ID: 0x%04x, Device Type: 0x%04x", zha.PROFILE_ID, zha.DeviceType.ON_OFF_SWITCH) + +class AqaraZ1ProDoubleRockerSwitch(XiaomiCustomDevice): + """Aqara Z1 Pro Double Rocker Switch""" + + MANUFACTURER_SPECIFIC_CLUSTER_ID = 0xfcc0 + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + _LOGGER.debug("AqaraZ1ProDoubleRockerSwitch device initialized with IEEE: %s", self.ieee) + + signature = { + MODELS_INFO: [("Aqara", "lumi.switch.acn057")], + ENDPOINTS: { + 1: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + Basic.cluster_id, + Identify.cluster_id, + Groups.cluster_id, + Scenes.cluster_id, + OnOff.cluster_id, + MultistateInput.cluster_id, + MeteringCluster.cluster_id, + ElectricalMeasurementCluster.cluster_id, + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [ + Time.cluster_id, + Ota.cluster_id, + ], + }, + 2: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + Groups.cluster_id, + Scenes.cluster_id, + OnOff.cluster_id, + MultistateInput.cluster_id, + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [], + }, + 3: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [], + }, + 4: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [], + }, + 21: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + AnalogInput.cluster_id, + ], + OUTPUT_CLUSTERS: [], + }, + }, + } + + replacement = { + ENDPOINTS: { + 1: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + BasicCluster, + Identify.cluster_id, + Groups.cluster_id, + Scenes.cluster_id, + OnOffCluster, + MultistateInputCluster, + MeteringCluster, + ElectricalMeasurementCluster, + AqaraZ1ProManufacturerSpecificCluster, + ], + OUTPUT_CLUSTERS: [ + Time.cluster_id, + Ota.cluster_id, + ], + }, + 2: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + Groups.cluster_id, + Scenes.cluster_id, + OnOffCluster, + MultistateInputCluster, + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [], + }, + 3: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [], + }, + 4: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [], + }, + 21: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + AnalogInputCluster, + ], + OUTPUT_CLUSTERS: [], + }, + }, + } \ No newline at end of file diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_quadruple.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_quadruple.py new file mode 100644 index 0000000000..3296644255 --- /dev/null +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_quadruple.py @@ -0,0 +1,196 @@ +"""Aqara Z1 Pro quadruple rocker switch quirks.""" + +import logging +import sys +from zigpy.profiles import zha +from zigpy.zcl.clusters.general import ( + AnalogInput, + Basic, + Groups, + Identify, + MultistateInput, + OnOff, + Ota, + Scenes, + Time, +) + +from zhaquirks.const import ( + DEVICE_TYPE, + ENDPOINTS, + INPUT_CLUSTERS, + MODELS_INFO, + OUTPUT_CLUSTERS, + PROFILE_ID, +) +from zhaquirks.xiaomi import ( + LUMI, + AnalogInputCluster, + BasicCluster, + ElectricalMeasurementCluster, + MeteringCluster, + OnOffCluster, + XiaomiCustomDevice, + AqaraZ1ProManufacturerSpecificCluster +) +from zhaquirks.xiaomi.aqara.opple_remote import MultistateInputCluster + +# Set up logging with a more visible format +_LOGGER = logging.getLogger(__name__) +_LOGGER.setLevel(logging.DEBUG) + +# Add a console handler to ensure logs go to stdout +console_handler = logging.StreamHandler(sys.stdout) +console_handler.setLevel(logging.DEBUG) +formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +console_handler.setFormatter(formatter) +_LOGGER.addHandler(console_handler) + +# Log at module level to verify the file is being loaded +_LOGGER.debug("AqaraZ1ProQuadrupleRockerSwitch quirk module is being loaded! ZHA Profile ID: 0x%04x, Device Type: 0x%04x", zha.PROFILE_ID, zha.DeviceType.ON_OFF_SWITCH) + +class AqaraZ1ProQuadrupleRockerSwitch(XiaomiCustomDevice): + """Aqara Z1 Pro Quadruple Rocker Switch""" + + MANUFACTURER_SPECIFIC_CLUSTER_ID = 0xfcc0 + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + _LOGGER.debug("AqaraZ1ProQuadrupleRockerSwitch device initialized with IEEE: %s", self.ieee) + + signature = { + MODELS_INFO: [("Aqara", "lumi.switch.acn059")], + ENDPOINTS: { + 1: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + Basic.cluster_id, + Identify.cluster_id, + Groups.cluster_id, + Scenes.cluster_id, + OnOff.cluster_id, + MultistateInput.cluster_id, + MeteringCluster.cluster_id, + ElectricalMeasurementCluster.cluster_id, + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [ + Time.cluster_id, + Ota.cluster_id, + ], + }, + 2: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + Groups.cluster_id, + Scenes.cluster_id, + OnOff.cluster_id, + MultistateInput.cluster_id, + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [], + }, + 3: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + Groups.cluster_id, + Scenes.cluster_id, + OnOff.cluster_id, + MultistateInput.cluster_id, + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [], + }, + 4: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + Groups.cluster_id, + Scenes.cluster_id, + OnOff.cluster_id, + MultistateInput.cluster_id, + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [], + }, + 21: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + AnalogInput.cluster_id, + ], + OUTPUT_CLUSTERS: [], + }, + }, + } + + replacement = { + ENDPOINTS: { + 1: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + BasicCluster, + Identify.cluster_id, + Groups.cluster_id, + Scenes.cluster_id, + OnOffCluster, + MultistateInputCluster, + MeteringCluster, + ElectricalMeasurementCluster, + AqaraZ1ProManufacturerSpecificCluster, + ], + OUTPUT_CLUSTERS: [ + Time.cluster_id, + Ota.cluster_id, + ], + }, + 2: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + Groups.cluster_id, + Scenes.cluster_id, + OnOffCluster, + MultistateInputCluster, + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [], + }, + 3: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + Groups.cluster_id, + Scenes.cluster_id, + OnOffCluster, + MultistateInputCluster, + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [], + }, + 4: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + Groups.cluster_id, + Scenes.cluster_id, + OnOffCluster, + MultistateInputCluster, + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [], + }, + 21: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + AnalogInputCluster, + ], + OUTPUT_CLUSTERS: [], + }, + }, + } \ No newline at end of file diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_triple.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_triple.py new file mode 100644 index 0000000000..2b4196e83f --- /dev/null +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_triple.py @@ -0,0 +1,188 @@ +"""Aqara Z1 Pro triple rocker switch quirks.""" + +import logging +import sys +from zigpy.profiles import zha +from zigpy.zcl.clusters.general import ( + AnalogInput, + Basic, + Groups, + Identify, + MultistateInput, + OnOff, + Ota, + Scenes, + Time, +) + +from zhaquirks.const import ( + DEVICE_TYPE, + ENDPOINTS, + INPUT_CLUSTERS, + MODELS_INFO, + OUTPUT_CLUSTERS, + PROFILE_ID, +) +from zhaquirks.xiaomi import ( + LUMI, + AnalogInputCluster, + BasicCluster, + ElectricalMeasurementCluster, + MeteringCluster, + OnOffCluster, + XiaomiCustomDevice, + AqaraZ1ProManufacturerSpecificCluster +) +from zhaquirks.xiaomi.aqara.opple_remote import MultistateInputCluster + +# Set up logging with a more visible format +_LOGGER = logging.getLogger(__name__) +_LOGGER.setLevel(logging.DEBUG) + +# Add a console handler to ensure logs go to stdout +console_handler = logging.StreamHandler(sys.stdout) +console_handler.setLevel(logging.DEBUG) +formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +console_handler.setFormatter(formatter) +_LOGGER.addHandler(console_handler) + +# Log at module level to verify the file is being loaded +_LOGGER.debug("AqaraZ1ProTripleRockerSwitch quirk module is being loaded! ZHA Profile ID: 0x%04x, Device Type: 0x%04x", zha.PROFILE_ID, zha.DeviceType.ON_OFF_SWITCH) + +class AqaraZ1ProTripleRockerSwitch(XiaomiCustomDevice): + """Aqara Z1 Pro Triple Rocker Switch""" + + MANUFACTURER_SPECIFIC_CLUSTER_ID = 0xfcc0 + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + _LOGGER.debug("AqaraZ1ProTripleRockerSwitch device initialized with IEEE: %s", self.ieee) + + signature = { + MODELS_INFO: [("Aqara", "lumi.switch.acn058")], + ENDPOINTS: { + 1: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + Basic.cluster_id, + Identify.cluster_id, + Groups.cluster_id, + Scenes.cluster_id, + OnOff.cluster_id, + MultistateInput.cluster_id, + MeteringCluster.cluster_id, + ElectricalMeasurementCluster.cluster_id, + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [ + Time.cluster_id, + Ota.cluster_id, + ], + }, + 2: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + Groups.cluster_id, + Scenes.cluster_id, + OnOff.cluster_id, + MultistateInput.cluster_id, + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [], + }, + 3: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + Groups.cluster_id, + Scenes.cluster_id, + OnOff.cluster_id, + MultistateInput.cluster_id, + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [], + }, + 4: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [], + }, + 21: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + AnalogInput.cluster_id, + ], + OUTPUT_CLUSTERS: [], + }, + }, + } + + replacement = { + ENDPOINTS: { + 1: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + BasicCluster, + Identify.cluster_id, + Groups.cluster_id, + Scenes.cluster_id, + OnOffCluster, + MultistateInputCluster, + MeteringCluster, + ElectricalMeasurementCluster, + AqaraZ1ProManufacturerSpecificCluster, + ], + OUTPUT_CLUSTERS: [ + Time.cluster_id, + Ota.cluster_id, + ], + }, + 2: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + Groups.cluster_id, + Scenes.cluster_id, + OnOffCluster, + MultistateInputCluster, + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [], + }, + 3: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + Groups.cluster_id, + Scenes.cluster_id, + OnOffCluster, + MultistateInputCluster, + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [], + }, + 4: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + MANUFACTURER_SPECIFIC_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [], + }, + 21: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, + INPUT_CLUSTERS: [ + AnalogInputCluster, + ], + OUTPUT_CLUSTERS: [], + }, + }, + } \ No newline at end of file From aece005ffb3db345356d538671cbd258fc0c5918 Mon Sep 17 00:00:00 2001 From: Felix Kwan Date: Sun, 27 Apr 2025 20:11:53 +0800 Subject: [PATCH 11/17] add simple descriptor --- zhaquirks/xiaomi/aqara/aqara_z1_pro_double.py | 15 +++++++++++++++ zhaquirks/xiaomi/aqara/aqara_z1_pro_quadruple.py | 15 +++++++++++++++ zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py | 15 +++++++++++++++ zhaquirks/xiaomi/aqara/aqara_z1_pro_triple.py | 15 +++++++++++++++ 4 files changed, 60 insertions(+) diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_double.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_double.py index 759de80aa0..66feb96e07 100644 --- a/zhaquirks/xiaomi/aqara/aqara_z1_pro_double.py +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_double.py @@ -61,6 +61,9 @@ def __init__(self, *args, **kwargs): signature = { MODELS_INFO: [("Aqara", "lumi.switch.acn057")], ENDPOINTS: { + # 1: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, @@ -80,6 +83,9 @@ def __init__(self, *args, **kwargs): Ota.cluster_id, ], }, + # 2: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, @@ -92,6 +98,9 @@ def __init__(self, *args, **kwargs): ], OUTPUT_CLUSTERS: [], }, + # 3: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, @@ -100,6 +109,9 @@ def __init__(self, *args, **kwargs): ], OUTPUT_CLUSTERS: [], }, + # 4: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, @@ -108,6 +120,9 @@ def __init__(self, *args, **kwargs): ], OUTPUT_CLUSTERS: [], }, + # 21: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_quadruple.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_quadruple.py index 3296644255..effed17ed7 100644 --- a/zhaquirks/xiaomi/aqara/aqara_z1_pro_quadruple.py +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_quadruple.py @@ -61,6 +61,9 @@ def __init__(self, *args, **kwargs): signature = { MODELS_INFO: [("Aqara", "lumi.switch.acn059")], ENDPOINTS: { + # 1: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, @@ -80,6 +83,9 @@ def __init__(self, *args, **kwargs): Ota.cluster_id, ], }, + # 2: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, @@ -92,6 +98,9 @@ def __init__(self, *args, **kwargs): ], OUTPUT_CLUSTERS: [], }, + # 3: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, @@ -104,6 +113,9 @@ def __init__(self, *args, **kwargs): ], OUTPUT_CLUSTERS: [], }, + # 4: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, @@ -116,6 +128,9 @@ def __init__(self, *args, **kwargs): ], OUTPUT_CLUSTERS: [], }, + # 21: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py index d9bdb32681..685275b278 100644 --- a/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py @@ -61,6 +61,9 @@ def __init__(self, *args, **kwargs): signature = { MODELS_INFO: [("Aqara", "lumi.switch.acn056")], ENDPOINTS: { + # 1: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, @@ -80,6 +83,9 @@ def __init__(self, *args, **kwargs): Ota.cluster_id, ], }, + # 2: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, @@ -88,6 +94,9 @@ def __init__(self, *args, **kwargs): ], OUTPUT_CLUSTERS: [], }, + # 3: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, @@ -96,6 +105,9 @@ def __init__(self, *args, **kwargs): ], OUTPUT_CLUSTERS: [], }, + # 4: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, @@ -104,6 +116,9 @@ def __init__(self, *args, **kwargs): ], OUTPUT_CLUSTERS: [], }, + # 21: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_triple.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_triple.py index 2b4196e83f..6c4ba16fd0 100644 --- a/zhaquirks/xiaomi/aqara/aqara_z1_pro_triple.py +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_triple.py @@ -61,6 +61,9 @@ def __init__(self, *args, **kwargs): signature = { MODELS_INFO: [("Aqara", "lumi.switch.acn058")], ENDPOINTS: { + # 1: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, @@ -80,6 +83,9 @@ def __init__(self, *args, **kwargs): Ota.cluster_id, ], }, + # 2: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, @@ -92,6 +98,9 @@ def __init__(self, *args, **kwargs): ], OUTPUT_CLUSTERS: [], }, + # 3: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, @@ -104,6 +113,9 @@ def __init__(self, *args, **kwargs): ], OUTPUT_CLUSTERS: [], }, + # 4: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, @@ -112,6 +124,9 @@ def __init__(self, *args, **kwargs): ], OUTPUT_CLUSTERS: [], }, + # 21: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, From 69dc83291f0c4caf0ebae6f877c389bb2b80c00d Mon Sep 17 00:00:00 2001 From: Felix Kwan Date: Sun, 27 Apr 2025 20:28:47 +0800 Subject: [PATCH 12/17] format code with black --- zhaquirks/xiaomi/__init__.py | 67 ++++++++++++------- zhaquirks/xiaomi/aqara/aqara_z1_pro_double.py | 21 ++++-- .../xiaomi/aqara/aqara_z1_pro_quadruple.py | 22 ++++-- zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py | 21 ++++-- zhaquirks/xiaomi/aqara/aqara_z1_pro_triple.py | 21 ++++-- 5 files changed, 101 insertions(+), 51 deletions(-) diff --git a/zhaquirks/xiaomi/__init__.py b/zhaquirks/xiaomi/__init__.py index 034b587722..a9c431a486 100644 --- a/zhaquirks/xiaomi/__init__.py +++ b/zhaquirks/xiaomi/__init__.py @@ -731,16 +731,17 @@ def command( bytes([src_ep, tsn, command_id]), expect_reply=expect_reply, ) - + + class AqaraZ1ProManufacturerSpecificCluster(CustomCluster): """Custom cluster for Aqara Z1 Pro manufacturer specific events.""" - - cluster_id = 0xfcc0 - + + cluster_id = 0xFCC0 + # Attribute IDs ATTR_SLIDER_ACTION = 0x028C # 652 - ATTR_SLIDE_TIME = 0x0231 # 561 - ATTR_SLIDE_SPEED = 0x0232 # 562 + ATTR_SLIDE_TIME = 0x0231 # 561 + ATTR_SLIDE_SPEED = 0x0232 # 562 ATTR_SLIDE_RELATIVE_DISPLACEMENT = 0x0233 # 563 ATTR_SLIDE_TIME_DELTA = 0x0301 # 769 @@ -749,7 +750,7 @@ class AqaraZ1ProManufacturerSpecificCluster(CustomCluster): # ATTR_SWITCH_MODE = 0x0004 # 4 # ATTR_POWER_ON_BEHAVIOR = 0x0517 # 1303 # ATTR_CLICK_MODE = 0x0125 # 293 - + # Action mapping ACTION_MAPPING = { 1: "slider_single", @@ -758,56 +759,76 @@ class AqaraZ1ProManufacturerSpecificCluster(CustomCluster): 4: "slider_up", 5: "slider_down", } - + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._attr_id = self.ATTR_SLIDER_ACTION - _LOGGER.debug("AqaraZ1ProManufacturerSpecificCluster initialized for device %s", self._endpoint.device.ieee) - + _LOGGER.debug( + "AqaraZ1ProManufacturerSpecificCluster initialized for device %s", + self._endpoint.device.ieee, + ) + def _update_attribute(self, attrid, value): """Handle attribute updates.""" - + # Store all attributes for the event if not hasattr(self, "_manufacturer_attrs"): self._manufacturer_attrs = {} - + # Update the attribute value self._manufacturer_attrs[attrid] = value - + # If this is the slider action attribute, send the event if attrid == self.ATTR_SLIDER_ACTION: # Get the action name from the mapping action = self.ACTION_MAPPING.get(value, f"slider_unknown_{value}") - _LOGGER.debug("AqaraZ1ProManufacturerSpecificCluster detected action: %s (value: %s)", action, value) - + _LOGGER.debug( + "AqaraZ1ProManufacturerSpecificCluster detected action: %s (value: %s)", + action, + value, + ) + # Prepare the event data event_data = { "action": action, "value": value, "slide_time": self._manufacturer_attrs.get(self.ATTR_SLIDE_TIME), "slide_speed": self._manufacturer_attrs.get(self.ATTR_SLIDE_SPEED), - "slide_relative_displacement": self._manufacturer_attrs.get(self.ATTR_SLIDE_RELATIVE_DISPLACEMENT), - "slide_time_delta": self._manufacturer_attrs.get(self.ATTR_SLIDE_TIME_DELTA), + "slide_relative_displacement": self._manufacturer_attrs.get( + self.ATTR_SLIDE_RELATIVE_DISPLACEMENT + ), + "slide_time_delta": self._manufacturer_attrs.get( + self.ATTR_SLIDE_TIME_DELTA + ), } - - _LOGGER.debug("AqaraZ1ProManufacturerSpecificCluster sending event data: %s", event_data) - + + _LOGGER.debug( + "AqaraZ1ProManufacturerSpecificCluster sending event data: %s", + event_data, + ) + # Send the event self.listener_event( ZHA_SEND_EVENT, action, event_data, ) - + # Also send a generic slider event for easier automation self.listener_event( ZHA_SEND_EVENT, "slider_event", event_data, ) - _LOGGER.debug("AqaraZ1ProManufacturerSpecificCluster events sent successfully") + _LOGGER.debug( + "AqaraZ1ProManufacturerSpecificCluster events sent successfully" + ) - _LOGGER.debug("AqaraZ1ProManufacturerSpecificCluster attribute update: attrid=0x%04x, value=%s", attrid, value) + _LOGGER.debug( + "AqaraZ1ProManufacturerSpecificCluster attribute update: attrid=0x%04x, value=%s", + attrid, + value, + ) super()._update_attribute(attrid, value) diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_double.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_double.py index 66feb96e07..5c7f3709f5 100644 --- a/zhaquirks/xiaomi/aqara/aqara_z1_pro_double.py +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_double.py @@ -31,7 +31,7 @@ MeteringCluster, OnOffCluster, XiaomiCustomDevice, - AqaraZ1ProManufacturerSpecificCluster + AqaraZ1ProManufacturerSpecificCluster, ) from zhaquirks.xiaomi.aqara.opple_remote import MultistateInputCluster @@ -42,22 +42,29 @@ # Add a console handler to ensure logs go to stdout console_handler = logging.StreamHandler(sys.stdout) console_handler.setLevel(logging.DEBUG) -formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") console_handler.setFormatter(formatter) _LOGGER.addHandler(console_handler) # Log at module level to verify the file is being loaded -_LOGGER.debug("AqaraZ1ProDoubleRockerSwitch quirk module is being loaded! ZHA Profile ID: 0x%04x, Device Type: 0x%04x", zha.PROFILE_ID, zha.DeviceType.ON_OFF_SWITCH) +_LOGGER.debug( + "AqaraZ1ProDoubleRockerSwitch quirk module is being loaded! ZHA Profile ID: 0x%04x, Device Type: 0x%04x", + zha.PROFILE_ID, + zha.DeviceType.ON_OFF_SWITCH, +) + class AqaraZ1ProDoubleRockerSwitch(XiaomiCustomDevice): """Aqara Z1 Pro Double Rocker Switch""" - MANUFACTURER_SPECIFIC_CLUSTER_ID = 0xfcc0 + MANUFACTURER_SPECIFIC_CLUSTER_ID = 0xFCC0 def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - _LOGGER.debug("AqaraZ1ProDoubleRockerSwitch device initialized with IEEE: %s", self.ieee) - + _LOGGER.debug( + "AqaraZ1ProDoubleRockerSwitch device initialized with IEEE: %s", self.ieee + ) + signature = { MODELS_INFO: [("Aqara", "lumi.switch.acn057")], ENDPOINTS: { @@ -192,4 +199,4 @@ def __init__(self, *args, **kwargs): OUTPUT_CLUSTERS: [], }, }, - } \ No newline at end of file + } diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_quadruple.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_quadruple.py index effed17ed7..8d50653f47 100644 --- a/zhaquirks/xiaomi/aqara/aqara_z1_pro_quadruple.py +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_quadruple.py @@ -31,7 +31,7 @@ MeteringCluster, OnOffCluster, XiaomiCustomDevice, - AqaraZ1ProManufacturerSpecificCluster + AqaraZ1ProManufacturerSpecificCluster, ) from zhaquirks.xiaomi.aqara.opple_remote import MultistateInputCluster @@ -42,22 +42,30 @@ # Add a console handler to ensure logs go to stdout console_handler = logging.StreamHandler(sys.stdout) console_handler.setLevel(logging.DEBUG) -formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") console_handler.setFormatter(formatter) _LOGGER.addHandler(console_handler) # Log at module level to verify the file is being loaded -_LOGGER.debug("AqaraZ1ProQuadrupleRockerSwitch quirk module is being loaded! ZHA Profile ID: 0x%04x, Device Type: 0x%04x", zha.PROFILE_ID, zha.DeviceType.ON_OFF_SWITCH) +_LOGGER.debug( + "AqaraZ1ProQuadrupleRockerSwitch quirk module is being loaded! ZHA Profile ID: 0x%04x, Device Type: 0x%04x", + zha.PROFILE_ID, + zha.DeviceType.ON_OFF_SWITCH, +) + class AqaraZ1ProQuadrupleRockerSwitch(XiaomiCustomDevice): """Aqara Z1 Pro Quadruple Rocker Switch""" - MANUFACTURER_SPECIFIC_CLUSTER_ID = 0xfcc0 + MANUFACTURER_SPECIFIC_CLUSTER_ID = 0xFCC0 def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - _LOGGER.debug("AqaraZ1ProQuadrupleRockerSwitch device initialized with IEEE: %s", self.ieee) - + _LOGGER.debug( + "AqaraZ1ProQuadrupleRockerSwitch device initialized with IEEE: %s", + self.ieee, + ) + signature = { MODELS_INFO: [("Aqara", "lumi.switch.acn059")], ENDPOINTS: { @@ -208,4 +216,4 @@ def __init__(self, *args, **kwargs): OUTPUT_CLUSTERS: [], }, }, - } \ No newline at end of file + } diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py index 685275b278..4f0bb32b06 100644 --- a/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py @@ -31,7 +31,7 @@ MeteringCluster, OnOffCluster, XiaomiCustomDevice, - AqaraZ1ProManufacturerSpecificCluster + AqaraZ1ProManufacturerSpecificCluster, ) from zhaquirks.xiaomi.aqara.opple_remote import MultistateInputCluster @@ -42,22 +42,29 @@ # Add a console handler to ensure logs go to stdout console_handler = logging.StreamHandler(sys.stdout) console_handler.setLevel(logging.DEBUG) -formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") console_handler.setFormatter(formatter) _LOGGER.addHandler(console_handler) # Log at module level to verify the file is being loaded -_LOGGER.debug("AqaraZ1ProSingleRockerSwitch quirk module is being loaded! ZHA Profile ID: 0x%04x, Device Type: 0x%04x", zha.PROFILE_ID, zha.DeviceType.ON_OFF_SWITCH) +_LOGGER.debug( + "AqaraZ1ProSingleRockerSwitch quirk module is being loaded! ZHA Profile ID: 0x%04x, Device Type: 0x%04x", + zha.PROFILE_ID, + zha.DeviceType.ON_OFF_SWITCH, +) + class AqaraZ1ProSingleRockerSwitch(XiaomiCustomDevice): """Aqara Z1 Pro Single Rocker Switch""" - MANUFACTURER_SPECIFIC_CLUSTER_ID = 0xfcc0 + MANUFACTURER_SPECIFIC_CLUSTER_ID = 0xFCC0 def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - _LOGGER.debug("AqaraZ1ProSingleRockerSwitch device initialized with IEEE: %s", self.ieee) - + _LOGGER.debug( + "AqaraZ1ProSingleRockerSwitch device initialized with IEEE: %s", self.ieee + ) + signature = { MODELS_INFO: [("Aqara", "lumi.switch.acn056")], ENDPOINTS: { @@ -184,4 +191,4 @@ def __init__(self, *args, **kwargs): OUTPUT_CLUSTERS: [], }, }, - } \ No newline at end of file + } diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_triple.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_triple.py index 6c4ba16fd0..e7ccda8836 100644 --- a/zhaquirks/xiaomi/aqara/aqara_z1_pro_triple.py +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_triple.py @@ -31,7 +31,7 @@ MeteringCluster, OnOffCluster, XiaomiCustomDevice, - AqaraZ1ProManufacturerSpecificCluster + AqaraZ1ProManufacturerSpecificCluster, ) from zhaquirks.xiaomi.aqara.opple_remote import MultistateInputCluster @@ -42,22 +42,29 @@ # Add a console handler to ensure logs go to stdout console_handler = logging.StreamHandler(sys.stdout) console_handler.setLevel(logging.DEBUG) -formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") console_handler.setFormatter(formatter) _LOGGER.addHandler(console_handler) # Log at module level to verify the file is being loaded -_LOGGER.debug("AqaraZ1ProTripleRockerSwitch quirk module is being loaded! ZHA Profile ID: 0x%04x, Device Type: 0x%04x", zha.PROFILE_ID, zha.DeviceType.ON_OFF_SWITCH) +_LOGGER.debug( + "AqaraZ1ProTripleRockerSwitch quirk module is being loaded! ZHA Profile ID: 0x%04x, Device Type: 0x%04x", + zha.PROFILE_ID, + zha.DeviceType.ON_OFF_SWITCH, +) + class AqaraZ1ProTripleRockerSwitch(XiaomiCustomDevice): """Aqara Z1 Pro Triple Rocker Switch""" - MANUFACTURER_SPECIFIC_CLUSTER_ID = 0xfcc0 + MANUFACTURER_SPECIFIC_CLUSTER_ID = 0xFCC0 def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - _LOGGER.debug("AqaraZ1ProTripleRockerSwitch device initialized with IEEE: %s", self.ieee) - + _LOGGER.debug( + "AqaraZ1ProTripleRockerSwitch device initialized with IEEE: %s", self.ieee + ) + signature = { MODELS_INFO: [("Aqara", "lumi.switch.acn058")], ENDPOINTS: { @@ -200,4 +207,4 @@ def __init__(self, *args, **kwargs): OUTPUT_CLUSTERS: [], }, }, - } \ No newline at end of file + } From 7dc9148e03947e9cf4d7755050d75364130469d7 Mon Sep 17 00:00:00 2001 From: Felix Kwan Date: Sun, 27 Apr 2025 22:48:34 +0800 Subject: [PATCH 13/17] add device automation trigger for single rocker --- zhaquirks/const.py | 8 +++ zhaquirks/xiaomi/__init__.py | 15 +++-- zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py | 60 +++++++++++++++++++ 3 files changed, 78 insertions(+), 5 deletions(-) diff --git a/zhaquirks/const.py b/zhaquirks/const.py index 5d0d81480f..d7568a12ce 100644 --- a/zhaquirks/const.py +++ b/zhaquirks/const.py @@ -14,6 +14,7 @@ ) import zigpy.types as t +ACTION="action" ARGS = "args" ATTR_ID = "attr_id" ATTRIBUTE_ID = "attribute_id" @@ -73,6 +74,7 @@ COMMAND_TILT = "Tilt" COMMAND_TOGGLE = "toggle" COMMAND_TRIPLE = "triple" +COMMAND_SLIDER_EVENT = "slider_event" DESCRIPTION = "description" DEVICE_TYPE = SIG_EP_TYPE DIM_DOWN = "dim_down" @@ -116,9 +118,15 @@ SKIP_CONFIGURATION = SIG_SKIP_CONFIG SHORT_RELEASE = "remote_button_short_release" TOGGLE = "toggle" +SLIDER = "slider" TRIPLE_PRESS = "remote_button_triple_press" TURN_OFF = "turn_off" TURN_ON = "turn_on" +SLIDER_SINGLE = "slider_single" +SLIDER_DOUBLE = "slider_double" +SLIDER_HOLD = "slider_hold" +SLIDER_UP = "slider_up" +SLIDER_DOWN = "slider_down" UNKNOWN = "Unknown" VALUE = "value" ZHA_SEND_EVENT = "zha_send_event" diff --git a/zhaquirks/xiaomi/__init__.py b/zhaquirks/xiaomi/__init__.py index a9c431a486..04ce189abc 100644 --- a/zhaquirks/xiaomi/__init__.py +++ b/zhaquirks/xiaomi/__init__.py @@ -48,6 +48,11 @@ UNKNOWN, VALUE, ZHA_SEND_EVENT, + SLIDER_DOUBLE, + SLIDER_DOWN, + SLIDER_HOLD, + SLIDER_SINGLE, + SLIDER_UP, BatterySize, ) @@ -753,11 +758,11 @@ class AqaraZ1ProManufacturerSpecificCluster(CustomCluster): # Action mapping ACTION_MAPPING = { - 1: "slider_single", - 2: "slider_double", - 3: "slider_hold", - 4: "slider_up", - 5: "slider_down", + 1: SLIDER_SINGLE, + 2: SLIDER_DOUBLE, + 3: SLIDER_HOLD, + 4: SLIDER_UP, + 5: SLIDER_DOWN, } def __init__(self, *args, **kwargs): diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py index 4f0bb32b06..5b2b191d32 100644 --- a/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py @@ -16,12 +16,32 @@ ) from zhaquirks.const import ( + ACTION, + ARGS, + ATTRIBUTE_ID, + BUTTON, + COMMAND, + COMMAND_SLIDER_EVENT, + CLUSTER_ID, DEVICE_TYPE, + DOUBLE_PRESS, + DIM_UP, + DIM_DOWN, ENDPOINTS, + ENDPOINT_ID, INPUT_CLUSTERS, + LONG_PRESS, MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, + SHORT_PRESS, + SLIDER, + SLIDER_DOUBLE, + SLIDER_DOWN, + SLIDER_HOLD, + SLIDER_SINGLE, + SLIDER_UP, + VALUE, ) from zhaquirks.xiaomi import ( LUMI, @@ -58,6 +78,7 @@ class AqaraZ1ProSingleRockerSwitch(XiaomiCustomDevice): """Aqara Z1 Pro Single Rocker Switch""" MANUFACTURER_SPECIFIC_CLUSTER_ID = 0xFCC0 + XIAOMI_COMMAND_SINGLE = "1_single" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -192,3 +213,42 @@ def __init__(self, *args, **kwargs): }, }, } + + device_automation_triggers = { + (SHORT_PRESS, BUTTON): { + COMMAND: XIAOMI_COMMAND_SINGLE, + CLUSTER_ID: 18, + ENDPOINT_ID: 1, + ARGS: {ATTRIBUTE_ID: 85, VALUE: 1}, + }, + (SHORT_PRESS, SLIDER): { + COMMAND: COMMAND_SLIDER_EVENT, + CLUSTER_ID: 64704, + ENDPOINT_ID: 1, + ARGS: {ACTION: SLIDER_SINGLE, VALUE: 1}, + }, + (DOUBLE_PRESS, SLIDER): { + COMMAND: COMMAND_SLIDER_EVENT, + CLUSTER_ID: 64704, + ENDPOINT_ID: 1, + ARGS: {ACTION: SLIDER_DOUBLE, VALUE: 2}, + }, + (LONG_PRESS, SLIDER): { + COMMAND: COMMAND_SLIDER_EVENT, + CLUSTER_ID: 64704, + ENDPOINT_ID: 1, + ARGS: {ACTION: SLIDER_HOLD, VALUE: 3}, + }, + (DIM_UP, SLIDER): { + COMMAND: COMMAND_SLIDER_EVENT, + CLUSTER_ID: 64704, + ENDPOINT_ID: 1, + ARGS: {ACTION: SLIDER_UP, VALUE: 4}, + }, + (DIM_DOWN, SLIDER): { + COMMAND: COMMAND_SLIDER_EVENT, + CLUSTER_ID: 64704, + ENDPOINT_ID: 1, + ARGS: {ACTION: SLIDER_DOWN, VALUE: 5}, + }, + } From 6e36c844c9f352b88dae3be5fae7c7e75f15ae1c Mon Sep 17 00:00:00 2001 From: Felix Kwan Date: Sun, 27 Apr 2025 23:18:09 +0800 Subject: [PATCH 14/17] add device automation trigger for other types --- zhaquirks/xiaomi/aqara/aqara_z1_pro_double.py | 68 +++++++++++++++ .../xiaomi/aqara/aqara_z1_pro_quadruple.py | 84 +++++++++++++++++++ zhaquirks/xiaomi/aqara/aqara_z1_pro_triple.py | 76 +++++++++++++++++ 3 files changed, 228 insertions(+) diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_double.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_double.py index 5c7f3709f5..435b4f42b9 100644 --- a/zhaquirks/xiaomi/aqara/aqara_z1_pro_double.py +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_double.py @@ -16,12 +16,33 @@ ) from zhaquirks.const import ( + ACTION, + ARGS, + ATTRIBUTE_ID, + BUTTON_1, + BUTTON_2, + COMMAND, + COMMAND_SLIDER_EVENT, + CLUSTER_ID, DEVICE_TYPE, + DOUBLE_PRESS, + DIM_UP, + DIM_DOWN, ENDPOINTS, + ENDPOINT_ID, INPUT_CLUSTERS, + LONG_PRESS, MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, + SHORT_PRESS, + SLIDER, + SLIDER_DOUBLE, + SLIDER_DOWN, + SLIDER_HOLD, + SLIDER_SINGLE, + SLIDER_UP, + VALUE, ) from zhaquirks.xiaomi import ( LUMI, @@ -58,6 +79,8 @@ class AqaraZ1ProDoubleRockerSwitch(XiaomiCustomDevice): """Aqara Z1 Pro Double Rocker Switch""" MANUFACTURER_SPECIFIC_CLUSTER_ID = 0xFCC0 + XIAOMI_COMMAND_SINGLE_1 = "1_single" + XIAOMI_COMMAND_SINGLE_2 = "2_single" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -200,3 +223,48 @@ def __init__(self, *args, **kwargs): }, }, } + + device_automation_triggers = { + (SHORT_PRESS, BUTTON_1): { + COMMAND: XIAOMI_COMMAND_SINGLE_1, + CLUSTER_ID: 18, + ENDPOINT_ID: 1, + ARGS: {ATTRIBUTE_ID: 85, VALUE: 1}, + }, + (SHORT_PRESS, BUTTON_2): { + COMMAND: XIAOMI_COMMAND_SINGLE_2, + CLUSTER_ID: 18, + ENDPOINT_ID: 2, + ARGS: {ATTRIBUTE_ID: 85, VALUE: 1}, + }, + (SHORT_PRESS, SLIDER): { + COMMAND: COMMAND_SLIDER_EVENT, + CLUSTER_ID: 64704, + ENDPOINT_ID: 1, + ARGS: {ACTION: SLIDER_SINGLE, VALUE: 1}, + }, + (DOUBLE_PRESS, SLIDER): { + COMMAND: COMMAND_SLIDER_EVENT, + CLUSTER_ID: 64704, + ENDPOINT_ID: 1, + ARGS: {ACTION: SLIDER_DOUBLE, VALUE: 2}, + }, + (LONG_PRESS, SLIDER): { + COMMAND: COMMAND_SLIDER_EVENT, + CLUSTER_ID: 64704, + ENDPOINT_ID: 1, + ARGS: {ACTION: SLIDER_HOLD, VALUE: 3}, + }, + (DIM_UP, SLIDER): { + COMMAND: COMMAND_SLIDER_EVENT, + CLUSTER_ID: 64704, + ENDPOINT_ID: 1, + ARGS: {ACTION: SLIDER_UP, VALUE: 4}, + }, + (DIM_DOWN, SLIDER): { + COMMAND: COMMAND_SLIDER_EVENT, + CLUSTER_ID: 64704, + ENDPOINT_ID: 1, + ARGS: {ACTION: SLIDER_DOWN, VALUE: 5}, + }, + } diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_quadruple.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_quadruple.py index 8d50653f47..ce8ec23652 100644 --- a/zhaquirks/xiaomi/aqara/aqara_z1_pro_quadruple.py +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_quadruple.py @@ -16,12 +16,35 @@ ) from zhaquirks.const import ( + ACTION, + ARGS, + ATTRIBUTE_ID, + BUTTON_1, + BUTTON_2, + BUTTON_3, + BUTTON_4, + COMMAND, + COMMAND_SLIDER_EVENT, + CLUSTER_ID, DEVICE_TYPE, + DOUBLE_PRESS, + DIM_UP, + DIM_DOWN, ENDPOINTS, + ENDPOINT_ID, INPUT_CLUSTERS, + LONG_PRESS, MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, + SHORT_PRESS, + SLIDER, + SLIDER_DOUBLE, + SLIDER_DOWN, + SLIDER_HOLD, + SLIDER_SINGLE, + SLIDER_UP, + VALUE, ) from zhaquirks.xiaomi import ( LUMI, @@ -58,6 +81,10 @@ class AqaraZ1ProQuadrupleRockerSwitch(XiaomiCustomDevice): """Aqara Z1 Pro Quadruple Rocker Switch""" MANUFACTURER_SPECIFIC_CLUSTER_ID = 0xFCC0 + XIAOMI_COMMAND_SINGLE_1 = "1_single" + XIAOMI_COMMAND_SINGLE_2 = "2_single" + XIAOMI_COMMAND_SINGLE_3 = "3_single" + XIAOMI_COMMAND_SINGLE_4 = "4_single" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -217,3 +244,60 @@ def __init__(self, *args, **kwargs): }, }, } + + device_automation_triggers = { + (SHORT_PRESS, BUTTON_1): { + COMMAND: XIAOMI_COMMAND_SINGLE_1, + CLUSTER_ID: 18, + ENDPOINT_ID: 1, + ARGS: {ATTRIBUTE_ID: 85, VALUE: 1}, + }, + (SHORT_PRESS, BUTTON_2): { + COMMAND: XIAOMI_COMMAND_SINGLE_2, + CLUSTER_ID: 18, + ENDPOINT_ID: 2, + ARGS: {ATTRIBUTE_ID: 85, VALUE: 1}, + }, + (SHORT_PRESS, BUTTON_3): { + COMMAND: XIAOMI_COMMAND_SINGLE_3, + CLUSTER_ID: 18, + ENDPOINT_ID: 3, + ARGS: {ATTRIBUTE_ID: 85, VALUE: 1}, + }, + (SHORT_PRESS, BUTTON_4): { + COMMAND: XIAOMI_COMMAND_SINGLE_4, + CLUSTER_ID: 18, + ENDPOINT_ID: 4, + ARGS: {ATTRIBUTE_ID: 85, VALUE: 1}, + }, + (SHORT_PRESS, SLIDER): { + COMMAND: COMMAND_SLIDER_EVENT, + CLUSTER_ID: 64704, + ENDPOINT_ID: 1, + ARGS: {ACTION: SLIDER_SINGLE, VALUE: 1}, + }, + (DOUBLE_PRESS, SLIDER): { + COMMAND: COMMAND_SLIDER_EVENT, + CLUSTER_ID: 64704, + ENDPOINT_ID: 1, + ARGS: {ACTION: SLIDER_DOUBLE, VALUE: 2}, + }, + (LONG_PRESS, SLIDER): { + COMMAND: COMMAND_SLIDER_EVENT, + CLUSTER_ID: 64704, + ENDPOINT_ID: 1, + ARGS: {ACTION: SLIDER_HOLD, VALUE: 3}, + }, + (DIM_UP, SLIDER): { + COMMAND: COMMAND_SLIDER_EVENT, + CLUSTER_ID: 64704, + ENDPOINT_ID: 1, + ARGS: {ACTION: SLIDER_UP, VALUE: 4}, + }, + (DIM_DOWN, SLIDER): { + COMMAND: COMMAND_SLIDER_EVENT, + CLUSTER_ID: 64704, + ENDPOINT_ID: 1, + ARGS: {ACTION: SLIDER_DOWN, VALUE: 5}, + }, + } diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_triple.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_triple.py index e7ccda8836..5951c9b786 100644 --- a/zhaquirks/xiaomi/aqara/aqara_z1_pro_triple.py +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_triple.py @@ -16,12 +16,34 @@ ) from zhaquirks.const import ( + ACTION, + ARGS, + ATTRIBUTE_ID, + BUTTON_1, + BUTTON_2, + BUTTON_3, + COMMAND, + COMMAND_SLIDER_EVENT, + CLUSTER_ID, DEVICE_TYPE, + DOUBLE_PRESS, + DIM_UP, + DIM_DOWN, ENDPOINTS, + ENDPOINT_ID, INPUT_CLUSTERS, + LONG_PRESS, MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, + SHORT_PRESS, + SLIDER, + SLIDER_DOUBLE, + SLIDER_DOWN, + SLIDER_HOLD, + SLIDER_SINGLE, + SLIDER_UP, + VALUE, ) from zhaquirks.xiaomi import ( LUMI, @@ -58,6 +80,9 @@ class AqaraZ1ProTripleRockerSwitch(XiaomiCustomDevice): """Aqara Z1 Pro Triple Rocker Switch""" MANUFACTURER_SPECIFIC_CLUSTER_ID = 0xFCC0 + XIAOMI_COMMAND_SINGLE_1 = "1_single" + XIAOMI_COMMAND_SINGLE_2 = "2_single" + XIAOMI_COMMAND_SINGLE_3 = "3_single" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -208,3 +233,54 @@ def __init__(self, *args, **kwargs): }, }, } + + device_automation_triggers = { + (SHORT_PRESS, BUTTON_1): { + COMMAND: XIAOMI_COMMAND_SINGLE_1, + CLUSTER_ID: 18, + ENDPOINT_ID: 1, + ARGS: {ATTRIBUTE_ID: 85, VALUE: 1}, + }, + (SHORT_PRESS, BUTTON_2): { + COMMAND: XIAOMI_COMMAND_SINGLE_2, + CLUSTER_ID: 18, + ENDPOINT_ID: 2, + ARGS: {ATTRIBUTE_ID: 85, VALUE: 1}, + }, + (SHORT_PRESS, BUTTON_3): { + COMMAND: XIAOMI_COMMAND_SINGLE_3, + CLUSTER_ID: 18, + ENDPOINT_ID: 3, + ARGS: {ATTRIBUTE_ID: 85, VALUE: 1}, + }, + (SHORT_PRESS, SLIDER): { + COMMAND: COMMAND_SLIDER_EVENT, + CLUSTER_ID: 64704, + ENDPOINT_ID: 1, + ARGS: {ACTION: SLIDER_SINGLE, VALUE: 1}, + }, + (DOUBLE_PRESS, SLIDER): { + COMMAND: COMMAND_SLIDER_EVENT, + CLUSTER_ID: 64704, + ENDPOINT_ID: 1, + ARGS: {ACTION: SLIDER_DOUBLE, VALUE: 2}, + }, + (LONG_PRESS, SLIDER): { + COMMAND: COMMAND_SLIDER_EVENT, + CLUSTER_ID: 64704, + ENDPOINT_ID: 1, + ARGS: {ACTION: SLIDER_HOLD, VALUE: 3}, + }, + (DIM_UP, SLIDER): { + COMMAND: COMMAND_SLIDER_EVENT, + CLUSTER_ID: 64704, + ENDPOINT_ID: 1, + ARGS: {ACTION: SLIDER_UP, VALUE: 4}, + }, + (DIM_DOWN, SLIDER): { + COMMAND: COMMAND_SLIDER_EVENT, + CLUSTER_ID: 64704, + ENDPOINT_ID: 1, + ARGS: {ACTION: SLIDER_DOWN, VALUE: 5}, + }, + } From ea5179f5d1ce94090eb5815d2d328c0e794c8860 Mon Sep 17 00:00:00 2001 From: Felix Kwan Date: Sun, 27 Apr 2025 23:20:56 +0800 Subject: [PATCH 15/17] format code with black --- zhaquirks/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zhaquirks/const.py b/zhaquirks/const.py index d7568a12ce..502f482fe6 100644 --- a/zhaquirks/const.py +++ b/zhaquirks/const.py @@ -14,7 +14,7 @@ ) import zigpy.types as t -ACTION="action" +ACTION = "action" ARGS = "args" ATTR_ID = "attr_id" ATTRIBUTE_ID = "attribute_id" From 1131499b4d60ab95d66e7363eeb897a30d98ceea Mon Sep 17 00:00:00 2001 From: Felix Kwan Date: Sun, 27 Apr 2025 23:29:37 +0800 Subject: [PATCH 16/17] add command_slider_event const --- zhaquirks/xiaomi/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zhaquirks/xiaomi/__init__.py b/zhaquirks/xiaomi/__init__.py index 04ce189abc..cd97dcc2a5 100644 --- a/zhaquirks/xiaomi/__init__.py +++ b/zhaquirks/xiaomi/__init__.py @@ -44,6 +44,7 @@ ATTRIBUTE_ID, ATTRIBUTE_NAME, COMMAND_ATTRIBUTE_UPDATED, + COMMAND_SLIDER_EVENT, COMMAND_TRIPLE, UNKNOWN, VALUE, @@ -822,7 +823,7 @@ def _update_attribute(self, attrid, value): # Also send a generic slider event for easier automation self.listener_event( ZHA_SEND_EVENT, - "slider_event", + COMMAND_SLIDER_EVENT, event_data, ) _LOGGER.debug( From 88f86121b89f27a97518c45742a84fb25a182761 Mon Sep 17 00:00:00 2001 From: Felix Kwan Date: Sat, 3 May 2025 17:20:11 +0800 Subject: [PATCH 17/17] pre-commit fix --- zhaquirks/xiaomi/__init__.py | 7 ++++--- zhaquirks/xiaomi/aqara/aqara_z1_pro_double.py | 15 ++++++++------- zhaquirks/xiaomi/aqara/aqara_z1_pro_quadruple.py | 15 ++++++++------- zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py | 15 ++++++++------- zhaquirks/xiaomi/aqara/aqara_z1_pro_triple.py | 15 ++++++++------- 5 files changed, 36 insertions(+), 31 deletions(-) diff --git a/zhaquirks/xiaomi/__init__.py b/zhaquirks/xiaomi/__init__.py index cd97dcc2a5..41a34aaa59 100644 --- a/zhaquirks/xiaomi/__init__.py +++ b/zhaquirks/xiaomi/__init__.py @@ -46,14 +46,14 @@ COMMAND_ATTRIBUTE_UPDATED, COMMAND_SLIDER_EVENT, COMMAND_TRIPLE, - UNKNOWN, - VALUE, - ZHA_SEND_EVENT, SLIDER_DOUBLE, SLIDER_DOWN, SLIDER_HOLD, SLIDER_SINGLE, SLIDER_UP, + UNKNOWN, + VALUE, + ZHA_SEND_EVENT, BatterySize, ) @@ -767,6 +767,7 @@ class AqaraZ1ProManufacturerSpecificCluster(CustomCluster): } def __init__(self, *args, **kwargs): + """Init.""" super().__init__(*args, **kwargs) self._attr_id = self.ATTR_SLIDER_ACTION _LOGGER.debug( diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_double.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_double.py index 435b4f42b9..708c09bd36 100644 --- a/zhaquirks/xiaomi/aqara/aqara_z1_pro_double.py +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_double.py @@ -2,6 +2,7 @@ import logging import sys + from zigpy.profiles import zha from zigpy.zcl.clusters.general import ( AnalogInput, @@ -21,15 +22,15 @@ ATTRIBUTE_ID, BUTTON_1, BUTTON_2, + CLUSTER_ID, COMMAND, COMMAND_SLIDER_EVENT, - CLUSTER_ID, DEVICE_TYPE, - DOUBLE_PRESS, - DIM_UP, DIM_DOWN, - ENDPOINTS, + DIM_UP, + DOUBLE_PRESS, ENDPOINT_ID, + ENDPOINTS, INPUT_CLUSTERS, LONG_PRESS, MODELS_INFO, @@ -45,14 +46,13 @@ VALUE, ) from zhaquirks.xiaomi import ( - LUMI, AnalogInputCluster, + AqaraZ1ProManufacturerSpecificCluster, BasicCluster, ElectricalMeasurementCluster, MeteringCluster, OnOffCluster, XiaomiCustomDevice, - AqaraZ1ProManufacturerSpecificCluster, ) from zhaquirks.xiaomi.aqara.opple_remote import MultistateInputCluster @@ -76,13 +76,14 @@ class AqaraZ1ProDoubleRockerSwitch(XiaomiCustomDevice): - """Aqara Z1 Pro Double Rocker Switch""" + """Aqara Z1 Pro Double Rocker Switch.""" MANUFACTURER_SPECIFIC_CLUSTER_ID = 0xFCC0 XIAOMI_COMMAND_SINGLE_1 = "1_single" XIAOMI_COMMAND_SINGLE_2 = "2_single" def __init__(self, *args, **kwargs): + """Init.""" super().__init__(*args, **kwargs) _LOGGER.debug( "AqaraZ1ProDoubleRockerSwitch device initialized with IEEE: %s", self.ieee diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_quadruple.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_quadruple.py index ce8ec23652..e5ff1e2e40 100644 --- a/zhaquirks/xiaomi/aqara/aqara_z1_pro_quadruple.py +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_quadruple.py @@ -2,6 +2,7 @@ import logging import sys + from zigpy.profiles import zha from zigpy.zcl.clusters.general import ( AnalogInput, @@ -23,15 +24,15 @@ BUTTON_2, BUTTON_3, BUTTON_4, + CLUSTER_ID, COMMAND, COMMAND_SLIDER_EVENT, - CLUSTER_ID, DEVICE_TYPE, - DOUBLE_PRESS, - DIM_UP, DIM_DOWN, - ENDPOINTS, + DIM_UP, + DOUBLE_PRESS, ENDPOINT_ID, + ENDPOINTS, INPUT_CLUSTERS, LONG_PRESS, MODELS_INFO, @@ -47,14 +48,13 @@ VALUE, ) from zhaquirks.xiaomi import ( - LUMI, AnalogInputCluster, + AqaraZ1ProManufacturerSpecificCluster, BasicCluster, ElectricalMeasurementCluster, MeteringCluster, OnOffCluster, XiaomiCustomDevice, - AqaraZ1ProManufacturerSpecificCluster, ) from zhaquirks.xiaomi.aqara.opple_remote import MultistateInputCluster @@ -78,7 +78,7 @@ class AqaraZ1ProQuadrupleRockerSwitch(XiaomiCustomDevice): - """Aqara Z1 Pro Quadruple Rocker Switch""" + """Aqara Z1 Pro Quadruple Rocker Switch.""" MANUFACTURER_SPECIFIC_CLUSTER_ID = 0xFCC0 XIAOMI_COMMAND_SINGLE_1 = "1_single" @@ -87,6 +87,7 @@ class AqaraZ1ProQuadrupleRockerSwitch(XiaomiCustomDevice): XIAOMI_COMMAND_SINGLE_4 = "4_single" def __init__(self, *args, **kwargs): + """Init.""" super().__init__(*args, **kwargs) _LOGGER.debug( "AqaraZ1ProQuadrupleRockerSwitch device initialized with IEEE: %s", diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py index 5b2b191d32..b871887d00 100644 --- a/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_single.py @@ -2,6 +2,7 @@ import logging import sys + from zigpy.profiles import zha from zigpy.zcl.clusters.general import ( AnalogInput, @@ -20,15 +21,15 @@ ARGS, ATTRIBUTE_ID, BUTTON, + CLUSTER_ID, COMMAND, COMMAND_SLIDER_EVENT, - CLUSTER_ID, DEVICE_TYPE, - DOUBLE_PRESS, - DIM_UP, DIM_DOWN, - ENDPOINTS, + DIM_UP, + DOUBLE_PRESS, ENDPOINT_ID, + ENDPOINTS, INPUT_CLUSTERS, LONG_PRESS, MODELS_INFO, @@ -44,14 +45,13 @@ VALUE, ) from zhaquirks.xiaomi import ( - LUMI, AnalogInputCluster, + AqaraZ1ProManufacturerSpecificCluster, BasicCluster, ElectricalMeasurementCluster, MeteringCluster, OnOffCluster, XiaomiCustomDevice, - AqaraZ1ProManufacturerSpecificCluster, ) from zhaquirks.xiaomi.aqara.opple_remote import MultistateInputCluster @@ -75,12 +75,13 @@ class AqaraZ1ProSingleRockerSwitch(XiaomiCustomDevice): - """Aqara Z1 Pro Single Rocker Switch""" + """Aqara Z1 Pro Single Rocker Switch.""" MANUFACTURER_SPECIFIC_CLUSTER_ID = 0xFCC0 XIAOMI_COMMAND_SINGLE = "1_single" def __init__(self, *args, **kwargs): + """Init.""" super().__init__(*args, **kwargs) _LOGGER.debug( "AqaraZ1ProSingleRockerSwitch device initialized with IEEE: %s", self.ieee diff --git a/zhaquirks/xiaomi/aqara/aqara_z1_pro_triple.py b/zhaquirks/xiaomi/aqara/aqara_z1_pro_triple.py index 5951c9b786..8ab598052a 100644 --- a/zhaquirks/xiaomi/aqara/aqara_z1_pro_triple.py +++ b/zhaquirks/xiaomi/aqara/aqara_z1_pro_triple.py @@ -2,6 +2,7 @@ import logging import sys + from zigpy.profiles import zha from zigpy.zcl.clusters.general import ( AnalogInput, @@ -22,15 +23,15 @@ BUTTON_1, BUTTON_2, BUTTON_3, + CLUSTER_ID, COMMAND, COMMAND_SLIDER_EVENT, - CLUSTER_ID, DEVICE_TYPE, - DOUBLE_PRESS, - DIM_UP, DIM_DOWN, - ENDPOINTS, + DIM_UP, + DOUBLE_PRESS, ENDPOINT_ID, + ENDPOINTS, INPUT_CLUSTERS, LONG_PRESS, MODELS_INFO, @@ -46,14 +47,13 @@ VALUE, ) from zhaquirks.xiaomi import ( - LUMI, AnalogInputCluster, + AqaraZ1ProManufacturerSpecificCluster, BasicCluster, ElectricalMeasurementCluster, MeteringCluster, OnOffCluster, XiaomiCustomDevice, - AqaraZ1ProManufacturerSpecificCluster, ) from zhaquirks.xiaomi.aqara.opple_remote import MultistateInputCluster @@ -77,7 +77,7 @@ class AqaraZ1ProTripleRockerSwitch(XiaomiCustomDevice): - """Aqara Z1 Pro Triple Rocker Switch""" + """Aqara Z1 Pro Triple Rocker Switch.""" MANUFACTURER_SPECIFIC_CLUSTER_ID = 0xFCC0 XIAOMI_COMMAND_SINGLE_1 = "1_single" @@ -85,6 +85,7 @@ class AqaraZ1ProTripleRockerSwitch(XiaomiCustomDevice): XIAOMI_COMMAND_SINGLE_3 = "3_single" def __init__(self, *args, **kwargs): + """Init.""" super().__init__(*args, **kwargs) _LOGGER.debug( "AqaraZ1ProTripleRockerSwitch device initialized with IEEE: %s", self.ieee