Skip to content

Commit

Permalink
update aqara airmonitor for 0.0.0_0029 FW
Browse files Browse the repository at this point in the history
Updated my sensor to the latest firmware: Koenkk/zigbee-OTA#86

It totally changed the device signature (makes little sense):
```
{
  "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.EndDevice: 2>,
  complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0,
  frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress: 128>,
  manufacturer_code=4447, maximum_buffer_size=127, maximum_incoming_transfer_size=100, server_mask=11264,
  maximum_outgoing_transfer_size=100, descriptor_capability_field=<DescriptorCapability.NONE: 0>,
  *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.
  • Loading branch information
tube0013 committed Jun 3, 2022
1 parent a55235f commit dc91f5f
Showing 1 changed file with 125 additions and 0 deletions.
125 changes: 125 additions & 0 deletions zhaquirks/xiaomi/aqara/tvoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 = {
# <SimpleDescriptor endpoint=1 profile=260 device_type=1026
# device_version=1
# input_clusters=[0, 1, 3, 1280]
# output_clusters=[19]>
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

0 comments on commit dc91f5f

Please sign in to comment.