From dc91f5fd733f1f34ab6961a10312a3a1a8a66e89 Mon Sep 17 00:00:00 2001 From: tube0013 Date: Fri, 3 Jun 2022 10:55:56 -0400 Subject: [PATCH 1/2] update aqara airmonitor for 0.0.0_0029 FW Updated my sensor to the latest firmware: https://github.com/Koenkk/zigbee-OTA/pull/86 It totally changed the device signature (makes little sense): ``` { "node_descriptor": "NodeDescriptor(logical_type=, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=, mac_capability_flags=, manufacturer_code=4447, maximum_buffer_size=127, maximum_incoming_transfer_size=100, server_mask=11264, maximum_outgoing_transfer_size=100, descriptor_capability_field=, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=True, *is_full_function_device=False, *is_mains_powered=False, *is_receiver_on_when_idle=False, *is_router=False, *is_security_capable=False)", "endpoints": { "1": { "profile_id": 260, "device_type": "0x0402", "in_clusters": [ "0x0000", "0x0001", "0x0003", "0x0500" ], "out_clusters": [ "0x0019" ] } }, "manufacturer": "LUMI", "model": "lumi.airmonitor.acn01", "class": "zigpy.device.Device" } ``` PR adds a new class to match the new signature - tested and wokring. --- zhaquirks/xiaomi/aqara/tvoc.py | 125 +++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/zhaquirks/xiaomi/aqara/tvoc.py b/zhaquirks/xiaomi/aqara/tvoc.py index 73f1e31324..46c3567b38 100644 --- a/zhaquirks/xiaomi/aqara/tvoc.py +++ b/zhaquirks/xiaomi/aqara/tvoc.py @@ -5,6 +5,7 @@ import zigpy.types as t from zigpy.zcl.clusters.general import AnalogInput, Basic, Identify, Ota from zigpy.zcl.clusters.measurement import RelativeHumidity, TemperatureMeasurement +from zigpy.zcl.clusters.security import IasZone from zigpy.zdo.types import NodeDescriptor from zhaquirks import Bus, LocalDataCluster, PowerConfigurationCluster @@ -119,3 +120,127 @@ def __init__(self, *args, **kwargs): } }, } + + +"""Quirk for lumi.airmonitor.acn01 tvoc air monitor.""" + +from zigpy.profiles import zha +from zigpy.quirks import CustomCluster +import zigpy.types as t +from zigpy.zcl.clusters.general import AnalogInput, Basic, Identify, Ota +from zigpy.zcl.clusters.measurement import RelativeHumidity, TemperatureMeasurement +from zigpy.zdo.types import NodeDescriptor + +from zhaquirks import Bus, LocalDataCluster, PowerConfigurationCluster +from zhaquirks.const import ( + DEVICE_TYPE, + ENDPOINTS, + INPUT_CLUSTERS, + MODELS_INFO, + NODE_DESCRIPTOR, + OUTPUT_CLUSTERS, + PROFILE_ID, +) +from zhaquirks.xiaomi import ( + LUMI, + BasicCluster, + RelativeHumidityCluster, + TemperatureMeasurementCluster, + XiaomiAqaraE1Cluster, + XiaomiCustomDevice, +) + +MEASURED_VALUE = 0x0000 + + +class TVOCMonitor2(XiaomiCustomDevice): + """Aqara LUMI lumi.airmonitor.acn01.""" + + def __init__(self, *args, **kwargs): + """Init.""" + self.temperature_bus = Bus() + self.humidity_bus = Bus() + super().__init__(*args, **kwargs) + + signature = { + # + MODELS_INFO: [(LUMI, "lumi.airmonitor.acn01")], + ENDPOINTS: { + 1: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.IAS_ZONE, + INPUT_CLUSTERS: [ + Basic.cluster_id, + Identify.cluster_id, + IasZone.cluster_id, + PowerConfigurationCluster.cluster_id, + ], + OUTPUT_CLUSTERS: [Ota.cluster_id], + } + }, + } + + replacement = { + NODE_DESCRIPTOR: NodeDescriptor( + 0x02, 0x40, 0x80, 0x115F, 0x7F, 0x0064, 0x2C00, 0x0064, 0x00 + ), + ENDPOINTS: { + 1: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.TEMPERATURE_SENSOR, + INPUT_CLUSTERS: [ + BasicCluster, + Identify.cluster_id, + TemperatureMeasurementCluster, + PowerConfigurationCluster, + RelativeHumidityCluster, + AnalogInputCluster, + EmulatedTVOCMeasurement, + XiaomiAqaraE1Cluster, + ], + OUTPUT_CLUSTERS: [Ota.cluster_id], + } + }, + } + + +MEASURED_VALUE = 0x0000 + + +class AnalogInputCluster(CustomCluster, AnalogInput): + """Analog input cluster, relay tvoc to the correct cluster.""" + + def _update_attribute(self, attrid, value): + super()._update_attribute(attrid, value) + self.endpoint.voc_level.update_attribute(MEASURED_VALUE, value) + + +class EmulatedTVOCMeasurement(LocalDataCluster): + """TVOC measurement cluster to receive reports from the AnalogInput cluster.""" + + PRESENT_VALUE = 0x0055 + ONE_HOUR = 3600 + MIN_CHANGE = 5 + TEN_SECONDS = 10 + + cluster_id = 0x042E + name = "VOC Level" + ep_attribute = "voc_level" + + attributes = { + MEASURED_VALUE: ("measured_value", t.Single), + } + + async def bind(self): + """Bind cluster.""" + result = await self.endpoint.analog_input.bind() + await self.endpoint.analog_input.configure_reporting( + self.PRESENT_VALUE, + self.TEN_SECONDS, + self.ONE_HOUR, + self.MIN_CHANGE, + ) + return result From dd7e09087fd5de0c5ca4548541da3e65a4f65025 Mon Sep 17 00:00:00 2001 From: tube0013 Date: Fri, 3 Jun 2022 12:32:57 -0400 Subject: [PATCH 2/2] Update tvoc.py Whoops - Big clean up from that first try. --- zhaquirks/xiaomi/aqara/tvoc.py | 93 +--------------------------------- 1 file changed, 1 insertion(+), 92 deletions(-) diff --git a/zhaquirks/xiaomi/aqara/tvoc.py b/zhaquirks/xiaomi/aqara/tvoc.py index 46c3567b38..52609f67ce 100644 --- a/zhaquirks/xiaomi/aqara/tvoc.py +++ b/zhaquirks/xiaomi/aqara/tvoc.py @@ -122,37 +122,6 @@ def __init__(self, *args, **kwargs): } -"""Quirk for lumi.airmonitor.acn01 tvoc air monitor.""" - -from zigpy.profiles import zha -from zigpy.quirks import CustomCluster -import zigpy.types as t -from zigpy.zcl.clusters.general import AnalogInput, Basic, Identify, Ota -from zigpy.zcl.clusters.measurement import RelativeHumidity, TemperatureMeasurement -from zigpy.zdo.types import NodeDescriptor - -from zhaquirks import Bus, LocalDataCluster, PowerConfigurationCluster -from zhaquirks.const import ( - DEVICE_TYPE, - ENDPOINTS, - INPUT_CLUSTERS, - MODELS_INFO, - NODE_DESCRIPTOR, - OUTPUT_CLUSTERS, - PROFILE_ID, -) -from zhaquirks.xiaomi import ( - LUMI, - BasicCluster, - RelativeHumidityCluster, - TemperatureMeasurementCluster, - XiaomiAqaraE1Cluster, - XiaomiCustomDevice, -) - -MEASURED_VALUE = 0x0000 - - class TVOCMonitor2(XiaomiCustomDevice): """Aqara LUMI lumi.airmonitor.acn01.""" @@ -183,64 +152,4 @@ def __init__(self, *args, **kwargs): }, } - replacement = { - NODE_DESCRIPTOR: NodeDescriptor( - 0x02, 0x40, 0x80, 0x115F, 0x7F, 0x0064, 0x2C00, 0x0064, 0x00 - ), - ENDPOINTS: { - 1: { - PROFILE_ID: zha.PROFILE_ID, - DEVICE_TYPE: zha.DeviceType.TEMPERATURE_SENSOR, - INPUT_CLUSTERS: [ - BasicCluster, - Identify.cluster_id, - TemperatureMeasurementCluster, - PowerConfigurationCluster, - RelativeHumidityCluster, - AnalogInputCluster, - EmulatedTVOCMeasurement, - XiaomiAqaraE1Cluster, - ], - OUTPUT_CLUSTERS: [Ota.cluster_id], - } - }, - } - - -MEASURED_VALUE = 0x0000 - - -class AnalogInputCluster(CustomCluster, AnalogInput): - """Analog input cluster, relay tvoc to the correct cluster.""" - - def _update_attribute(self, attrid, value): - super()._update_attribute(attrid, value) - self.endpoint.voc_level.update_attribute(MEASURED_VALUE, value) - - -class EmulatedTVOCMeasurement(LocalDataCluster): - """TVOC measurement cluster to receive reports from the AnalogInput cluster.""" - - PRESENT_VALUE = 0x0055 - ONE_HOUR = 3600 - MIN_CHANGE = 5 - TEN_SECONDS = 10 - - cluster_id = 0x042E - name = "VOC Level" - ep_attribute = "voc_level" - - attributes = { - MEASURED_VALUE: ("measured_value", t.Single), - } - - async def bind(self): - """Bind cluster.""" - result = await self.endpoint.analog_input.bind() - await self.endpoint.analog_input.configure_reporting( - self.PRESENT_VALUE, - self.TEN_SECONDS, - self.ONE_HOUR, - self.MIN_CHANGE, - ) - return result + replacement = TVOCMonitor.replacement