Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Device Support Request] Please add Support for CO2 sensor in Titan TPZRCO2TH-Z3 #792

Closed
B-Hartley opened this issue Feb 27, 2021 · 95 comments
Labels
stale Issue is inactivate and might get closed soon

Comments

@B-Hartley
Copy link

B-Hartley commented Feb 27, 2021

Is your feature request related to a problem? Please describe.
Please add support for the CO2 measurement feature of the Titan Zigbee 3.0 C02 sensor.
I seem to be able to see Humidity and Temperature already.
But the battery level doesn't report properly and I don't see the CO2 level at all.

Product Page

Device signature - this can be acquired by removing the device from ZHA and pairing it again from the add devices screen. Be sure to add the entire content of the log panel after pairing the device to a code block below this line.

{
  "node_descriptor": "NodeDescriptor(byte1=2, byte2=64, mac_capability_flags=128, manufacturer_code=4467, maximum_buffer_size=127, maximum_incoming_transfer_size=100, server_mask=11264, maximum_outgoing_transfer_size=100, descriptor_capability_field=0)",
  "endpoints": {
    "1": {
      "profile_id": 260,
      "device_type": "0x0302",
      "in_clusters": [
        "0x0000",
        "0x0001",
        "0x0003",
        "0x0020",
        "0x0402",
        "0x040d"
      ],
      "out_clusters": [
        "0x0019"
      ]
    },
    "2": {
      "profile_id": 260,
      "device_type": "0x0307",
      "in_clusters": [
        "0x0000",
        "0x0001",
        "0x0003",
        "0x0405"
      ],
      "out_clusters": []
    }
  },
  "manufacturer": "Titan Products Ltd",
  "model": "TPZRCO2HT-Z3",
  "class": "zigpy.device.Device"
}

Additional context
Add any other context or screenshots about the feature request here.

Endpoint Cluster Attribute Manual Attached

@B-Hartley B-Hartley changed the title Please add Support for CO2 sensor in Titan TPZRCO2TH-Z3 [Device Support Request] Please add Support for CO2 sensor in Titan TPZRCO2TH-Z3 Feb 27, 2021
@B-Hartley
Copy link
Author

I'm unsure which bits are needed, I think this is the whole pairing / setup sequence.

[0x0000:zdo] ZDO request ZDOCmd.Mgmt_Permit_Joining_req: [60, <Bool.false: 0>]
Device 0xa43a (00:15:8d:00:03:87:7f:49) joined the network
[0xa43a:zdo] ZDO request ZDOCmd.Device_annce: [0xA43A, 00:15:8d:00:03:87:7f:49, 128]
[0xa43a] Requesting 'Node Descriptor'
[0xa43a] Extending timeout for 0x2a request
[0xa43a] Node Descriptor: NodeDescriptor(byte1=2, byte2=64, mac_capability_flags=128, manufacturer_code=4467, maximum_buffer_size=127, maximum_incoming_transfer_size=100, server_mask=11264, maximum_outgoing_transfer_size=100, descriptor_capability_field=0)
[0xa43a] Discovering endpoints
[0xa43a] Extending timeout for 0x2c request
[0xa43a] Discovered endpoints: [1, 2]
[0xa43a:1] Discovering endpoint information
[0xa43a] Extending timeout for 0x2e request
Device 0xa43a (00:15:8d:00:03:87:7f:49) joined the network
Skip initialization for existing device 00:15:8d:00:03:87:7f:49
[0xa43a:zdo] ZDO request ZDOCmd.Device_annce: [0xA43A, 00:15:8d:00:03:87:7f:49, 128]
[0xa43a] Extending timeout for 0x42 request
[0xa43a:1] Discovered endpoint information: SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=770, device_version=1, input_clusters=[0, 1, 3, 1026, 1037, 32], output_clusters=[25])
[0xa43a] Extending timeout for 0x44 request
[0xa43a:1:0x0000] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True disable_default_response=True> manufacturer=None tsn=68 command_id=Command.Read_Attributes_rsp>
[0xa43a:1] Manufacturer: Titan Products Ltd
[0xa43a:1] Model: TPZRCO2HT-Z3
[0xa43a:2] Discovering endpoint information
[0xa43a] Extending timeout for 0x54 request
[0xa43a:2] Discovered endpoint information: SizePrefixedSimpleDescriptor(endpoint=2, profile=260, device_type=775, device_version=1, input_clusters=[0, 1, 3, 1029], output_clusters=[])
Checking quirks for Titan Products Ltd TPZRCO2HT-Z3 (00:15:8d:00:03:87:7f:49)
device - 0xA43A:00:15:8d:00:03:87:7f:49 entering async_device_initialized - is_new_join: True
device - 0xA43A:00:15:8d:00:03:87:7f:49 has joined the ZHA zigbee network
[0xA43A](TPZRCO2HT-Z3): started configuration
[0xA43A:ZDO](TPZRCO2HT-Z3): 'async_configure' stage succeeded
[0xa43a] Extending timeout for 0x58 request
[0xa43a] Extending timeout for 0x5a request
[0xa43a] Extending timeout for 0x5c request
[0xA43A:1:0x0402]: bound 'temperature' cluster: Status.SUCCESS
[0xa43a] Extending timeout for 0x5e request
[0xA43A:1:0x0001]: bound 'power' cluster: Status.SUCCESS
[0xa43a] Extending timeout for 0x60 request
[0xA43A:1:0x0000]: bound 'basic' cluster: Status.NOT_SUPPORTED
[0xA43A:1:0x0000]: finished channel configuration
[0xa43a] Extending timeout for 0x62 request
[0xa43a:1:0x0402] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True disable_default_response=True> manufacturer=None tsn=94 command_id=Command.Configure_Reporting_rsp>
[0xA43A:1:0x0402]: reporting 'measured_value' attr on 'temperature' cluster: 30/900/50: Result: '[[ConfigureReportingResponseRecord(status=0)]]'
[0xA43A:1:0x0402]: finished channel configuration
[0xa43a] Extending timeout for 0x64 request
[0xa43a:1:0x0001] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True disable_default_response=True> manufacturer=None tsn=96 command_id=Command.Configure_Reporting_rsp>
[0xA43A:1:0x0001]: reporting 'battery_voltage' attr on 'power' cluster: 3600/10800/1: Result: '[[ConfigureReportingResponseRecord(status=140, direction=0, attrid=32)]]'
[0xa43a] Extending timeout for 0x66 request
[0xA43A:1:0x0020]: bound 'poll_control' cluster: Status.SUCCESS
[0xa43a] Extending timeout for 0x68 request
[0xA43A:1:0x0019]: bound 'ota' cluster: Status.NOT_SUPPORTED
[0xA43A:1:0x0019]: finished channel configuration
[0xa43a] Extending timeout for 0x6a request
[0xa43a:1:0x0001] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True disable_default_response=True> manufacturer=None tsn=102 command_id=Command.Configure_Reporting_rsp>
[0xA43A:1:0x0001]: reporting 'battery_percentage_remaining' attr on 'power' cluster: 3600/10800/1: Result: '[[ConfigureReportingResponseRecord(status=134, direction=0, attrid=33)]]'
[0xA43A:1:0x0001]: finished channel configuration
[0xa43a] Extending timeout for 0x6c request
[0xa43a:1:0x0020] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True disable_default_response=True> manufacturer=None tsn=104 command_id=Command.Write_Attributes_rsp>
[0xA43A:1:0x0020]: 3300.0s check-in interval set: [[WriteAttributesStatusRecord(status=<Status.SUCCESS: 0>)]]
[0xA43A:1:0x0020]: finished channel configuration
[0xA43A:1:0x0402]: 'async_configure' stage succeeded
[0xA43A:1:0x0001]: 'async_configure' stage succeeded
[0xA43A:1:0x0000]: 'async_configure' stage succeeded
[0xA43A:1:0x0020]: 'async_configure' stage succeeded
[0xA43A:1:0x0019]: 'async_configure' stage succeeded
[0xA43A:2:0x0000]: bound 'basic' cluster: Status.NOT_SUPPORTED
[0xA43A:2:0x0000]: finished channel configuration
[0xA43A:2:0x0405]: bound 'humidity' cluster: Status.SUCCESS
[0xa43a] Extending timeout for 0x70 request
[0xa43a:2:0x0405] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True disable_default_response=True> manufacturer=None tsn=112 command_id=Command.Configure_Reporting_rsp>
[0xA43A:2:0x0405]: reporting 'measured_value' attr on 'humidity' cluster: 30/900/50: Result: '[[ConfigureReportingResponseRecord(status=0)]]'
[0xA43A:2:0x0405]: finished channel configuration
[0xA43A:2:0x0000]: 'async_configure' stage succeeded
[0xA43A:2:0x0405]: 'async_configure' stage succeeded
[0xA43A](TPZRCO2HT-Z3): completed configuration
[0xA43A](TPZRCO2HT-Z3): stored in registry: ZhaDeviceEntry(name='Titan Products Ltd TPZRCO2HT-Z3', ieee='00:15:8d:00:03:87:7f:49', last_seen=1614619030.758866)
[0xa43a] Extending timeout for 0x7e request
[0xa43a:1:0x0003] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True disable_default_response=True> manufacturer=None tsn=126 command_id=Command.Default_Response>
[0xA43A:1:0x0003]: executed 'trigger_effect' command with args: '(2, 0)' kwargs: '{}' result: [64, <Status.UNSUP_CLUSTER_COMMAND: 129>]
[0xA43A](TPZRCO2HT-Z3): started initialization
[0xA43A:ZDO](TPZRCO2HT-Z3): 'async_initialize' stage succeeded
[0xA43A:1:0x0402]: initializing channel: from_cache: False
[0xa43a] Extending timeout for 0x81 request
[0xA43A:1:0x0001]: initializing channel: from_cache: False
[0xa43a] Extending timeout for 0x83 request
[0xA43A:1:0x0000]: initializing channel: from_cache: False
[0xA43A:1:0x0000]: finished channel configuration
[0xA43A:1:0x0020]: initializing channel: from_cache: False
[0xA43A:1:0x0020]: finished channel configuration
[0xA43A:1:0x0019]: initializing channel: from_cache: False
[0xA43A:1:0x0019]: finished channel configuration
[0xA43A:2:0x0000]: initializing channel: from_cache: False
[0xA43A:2:0x0000]: finished channel configuration
[0xA43A:2:0x0405]: initializing channel: from_cache: False
[0xa43a] Extending timeout for 0x85 request
[0xa43a:1:0x0402] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True disable_default_response=True> manufacturer=None tsn=129 command_id=Command.Read_Attributes_rsp>
[0xA43A:1:0x0402]: finished channel configuration
[0xa43a] Delivery error for seq # 0x83, on endpoint id 1 cluster 0x0001: message send failure
[0xA43A:1:0x0001]: failed to get attributes '['battery_voltage', 'battery_percentage_remaining']' on 'power' cluster: [0xa43a:1:0x0001]: Message send failure
[0xa43a] Extending timeout for 0x88 request
[0xa43a] Delivery error for seq # 0x85, on endpoint id 2 cluster 0x0405: message send failure
[0xA43A:2:0x0405]: failed to get attributes '['measured_value']' on 'humidity' cluster: [0xa43a:2:0x0405]: Message send failure
[0xA43A:2:0x0405]: finished channel configuration
[0xA43A:2:0x0000]: 'async_initialize' stage succeeded
[0xA43A:2:0x0405]: 'async_initialize' stage succeeded
[0xa43a:1:0x0001] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True disable_default_response=True> manufacturer=None tsn=136 command_id=Command.Read_Attributes_rsp>
[0xA43A:1:0x0001]: finished channel configuration
[0xA43A:1:0x0402]: 'async_initialize' stage succeeded
[0xA43A:1:0x0001]: 'async_initialize' stage succeeded
[0xA43A:1:0x0000]: 'async_initialize' stage succeeded
[0xA43A:1:0x0020]: 'async_initialize' stage succeeded
[0xA43A:1:0x0019]: 'async_initialize' stage succeeded
[0xA43A](TPZRCO2HT-Z3): power source: Battery or Unknown
[0xA43A](TPZRCO2HT-Z3): completed initialization

I'm going to read through the docs on this site and have a go, but if anyone else can do this, it would be great !

@Adminiuga
Copy link
Contributor

The only non standard cluster is 0x040d cluster. I wonder if that one is the co2 measurement.

@B-Hartley
Copy link
Author

B-Hartley commented Mar 1, 2021

Yes it is. It’s linked in the docs as a concentration cluster.
In the zigbee spec they use co2 as an example of something that would be stored in a concentration cluster. And that it would built in a structure within that cluster.
but doesn’t explain how.
as the cluster doesn’t bind I can’t see what it is sending.
hoping to experiment with this quirks file sometime tomorrow. But I’m a bit lost at the moment.

I think the battery one must me a bit non standard too as it doesn’t report the battery level properly. That’s not as big a deal.

@Adminiuga
Copy link
Contributor

ah, missed that on the mobile. Kudos to the vendor for providing that information.
So this would need a quirk and a modification to the ZHA.
For concentration custom cluster would be something like

class GasConcentration(CustomCluster):
    cluster_id = 0x040D
    name = "Gas Concentration Measurement"
    ep_attribute = "gas_concentration"
    vendor_attributes = {
        0x0000: ("measured_value", t.Single),
        0x0001: ("min_measured_value", t.Single),
        0x0002: ("max_measured_value", t.Single),
        0xFFFD: ("cluster_revision", t.uint16_t),
    }
    server_commands = {}
    client_commands = {}

and then a custom device with a replacement for 0x040D cluster_ID using the GacConcentration class. See https://github.com/zigpy/zha-device-handlers#what-the-heck-is-a-quirk for more info

@B-Hartley
Copy link
Author

That’s great. I’ll take a look
Tomorrow and see if I can understand.

@B-Hartley
Copy link
Author

B-Hartley commented Mar 2, 2021 via email

@B-Hartley
Copy link
Author

I've raised an issue on Zigpy itself as I'm unsure if the ConcentrationCluster should be added into measurement.py to make products such as this work ?

Is that the right thing to do, or should it just be handled as a quirk ?

@Adminiuga
Copy link
Contributor

No, zigpy only contains standard clusters included in ZCL specification. So unless it was included in ZCL revision 7 it does not belong to zigpy

@B-Hartley
Copy link
Author

ok, I've hacked this together..............
I really am shooting in the dark here.
I'm unsure what cluster to output my GasConcentration on?
Do I need to change it from a Float to something else?

Thanks in advance........

__init__.py

"""Titan quirks."""

TITAN= "Titan Products Ltd"
TPZRC02THZ3.py

"""Device handler for Titan TPZRC02TH-Z3 Environment Sensor."""
from zigpy.profiles import zha
from zigpy.quirks import CustomDevice, CustomCluster
from zigpy.zcl.clusters.general import Basic, Identify, Ota, PollControl
from zigpy.zcl.clusters.measurement import TemperatureMeasurement, RelativeHumidity

from . import TITAN
from ..const import (
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
)

class GasConcentration(CustomCluster):
    cluster_id = 0x040D
    name = "Gas Concentration Measurement"
    ep_attribute = "gas_concentration"
    vendor_attributes = {
        0x0000: ("measured_value", t.Single),
        0x0001: ("min_measured_value", t.Single),
        0x0002: ("max_measured_value", t.Single),
        0xFFFD: ("cluster_revision", t.uint16_t),
    }
    server_commands = {}
    client_commands = {}


class TPZRC02THZ3(CustomDevice):
    """Custom device representing Bosch TPZRC02TH-Z3 environment sensor."""

    signature = {
        #  <SimpleDescriptor endpoint=1 profile=260 device_type=770
        #  device_version=0
        #  input_clusters=[0, 1, 3, 32, 1026, 1037]
        #  output_clusters=[25]>
        MODELS_INFO: [(TITAN, "TPZRCO2HT-Z3")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.xxxxxxxxxx,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    PowerConfigurationCluster.cluster_id,
                    Identify.cluster_id,
                    PollControl.cluster_id,
                    TemperatureMeasurement.cluster_id,
                    RelativeHumidity.cluster_id,
                    GasConcentration.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Ota.cluster_id],
            }
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    PowerConfigurationCluster.cluster_id,
                    Identify.cluster_id,
                    PollControl.cluster_id,
                    TemperatureMeasurement.cluster_id,
                    RelativeHumidity.cluster_id,
                    GasConcentration.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Ota.cluster_id],
            }
        }
    }

@B-Hartley
Copy link
Author

No, zigpy only contains standard clusters included in ZCL specification. So unless it was included in ZCL revision 7 it does not belong to zigpy

Thanks.
I've closed the issue on Zigpy and I'll see if I can get to the answer through this Quirk issue.

@Adminiuga
Copy link
Contributor

for the signature, the ENDPOINTS key must match the zigbee device signature:
For device Types enums, reference https://github.com/zigpy/zigpy/blob/dev/zigpy/profiles/zha.py

    signature = {
        # UPDATE THIS COMMENTS TO MATCH the posted zigbee signature
        #  <SimpleDescriptor endpoint=1 profile=260 device_type=770
        #  device_version=0
        #  input_clusters=[0, 1, 3, 32, 1026, 1037]
        #  output_clusters=[25]>
        MODELS_INFO: [(TITAN, "TPZRCO2HT-Z3")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.TEMPERATURE_SENSOR,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    PowerConfigurationCluster.cluster_id,
                    Identify.cluster_id,
                    PollControl.cluster_id,
                    TemperatureMeasurement.cluster_id,
                    GasConcentration.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Ota.cluster_id],
            },
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.MINI_SPLIT_AC,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    PowerConfigurationCluster.cluster_id,
                    Identify.cluster_id,
                    RelativeHumidity.cluster_id,
                ],
                OUTPUT_CLUSTERS: [],
            }
        },
    }

The replacements, in your case is going to match the signature mostly exactly, with the exception of the gas cluster only. Since you want to replace it with your copy, you have to reference it by the "class" instead of a cluster id:

    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.TEMPERATURE_SENSOR,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    PowerConfigurationCluster.cluster_id,
                    Identify.cluster_id,
                    PollControl.cluster_id,
                    TemperatureMeasurement.cluster_id,
                    GasConcentration,
                ],
                OUTPUT_CLUSTERS: [Ota.cluster_id],
            },
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.MINI_SPLIT_AC,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    PowerConfigurationCluster.cluster_id,
                    Identify.cluster_id,
                    RelativeHumidity.cluster_id,
                ],
                OUTPUT_CLUSTERS: [],
            }
        },
    }

@Adminiuga
Copy link
Contributor

Adminiuga commented Mar 2, 2021

Do I need to change it from a Float to something else?

t.Single is the float type, matching the docs for the cluster. Enable zigpy debug and with your custom quirk, on restart, if everything is configured correctly you should see zigpy finding a quirk for your CO2 sensor. That would be the 1st step.

BTW, where did you get it? link?
Dang that thing is expensive. But last I've checked CO2 sensor were expensive. I'd love to know what kind of sensor they've used that it works from a battery.

@B-Hartley
Copy link
Author

This is the inside of the sensor.
It is running on a lithium battery, so I guess it needs the max power it can get from an AA cell.

sensor

@B-Hartley
Copy link
Author

Is the order of this line important.......

        #  input_clusters=[0, 1, 3, 1026, 1037, 32]     

In the log it shows them in this order, rather than in numerical order.

@Adminiuga
Copy link
Contributor

Order is not important. Usually quirks have clusters in numeri orders and constant names following the numeric order.

Thanks for the picture. Looks like this one https://sstsensing.com/product/cozir-lp2-ambient-air-co2-sensor/
Yeah, CO2 sensors seem to draw more power than any other sensors and most of the time have to run continuously and dont't go to low power mode. No chance of running it on C3202 or even an AA battery would not last long

@B-Hartley
Copy link
Author

ok, so more stupid questions.
I've got the class and the quirk.

I've enabled zigpy debug.

So where do I put the quirk file ?

I'm running....

Version | core-2021.2.3
Installation Type | Home Assistant OS

Thanks very much for your help.
I would never have even got this far without you !

@B-Hartley
Copy link
Author

Thanks for the picture. Looks like this one https://sstsensing.com/product/cozir-lp2-ambient-air-co2-sensor/

Agreed, it looks exactly like that.

@B-Hartley
Copy link
Author

B-Hartley commented Mar 2, 2021

This is the whole file I've got........

TPZRCO2THZ3.py

"""Device handler for Titan TPZRCO2TH-Z3 Environment Sensor."""
from zigpy.profiles import zha
from zigpy.quirks import CustomDevice, CustomCluster
from zigpy.zcl.clusters.general import Basic, Identify, Ota, PollControl
from zigpy.zcl.clusters.measurement import TemperatureMeasurement, RelativeHumidity

from . import TITAN
from ..const import (
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
)

class GasConcentration(CustomCluster):
    cluster_id = 0x040D
    name = "Gas Concentration Measurement"
    ep_attribute = "gas_concentration"
    vendor_attributes = {
        0x0000: ("measured_value", t.Single),
        0x0001: ("min_measured_value", t.Single),
        0x0002: ("max_measured_value", t.Single),
        0xFFFD: ("cluster_revision", t.uint16_t),
    }
    server_commands = {}
    client_commands = {}


class TPZRCO2THZ3(CustomDevice):
    """Custom device representing Titan TPZRCO2TH-Z3 environment sensor."""

    signature = {
        #  <SimpleDescriptor endpoint=1 profile=260 device_type=770
        #  device_version=1
        #  input_clusters=[0, 1, 3, 32, 1026, 1037]        
        #  output_clusters=[25]>
        MODELS_INFO: [(TITAN, "TPZRCO2HT-Z3")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.TEMPERATURE_SENSOR,   
                INPUT_CLUSTERS: [
                    Basic.cluster_id,                    
                    PowerConfigurationCluster.cluster_id,  
                    Identify.cluster_id,                   
                    PollControl.cluster_id,                
                    TemperatureMeasurement.cluster_id,     
                    GasConcentration.cluster_id,                      
                ],
                OUTPUT_CLUSTERS: [Ota.cluster_id],         
            },
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.MINI_SPLIT_AC, 
                INPUT_CLUSTERS: [
                    Basic.cluster_id,                      
                    PowerConfigurationCluster.cluster_id,  
                    Identify.cluster_id,                   
                    RelativeHumidity.cluster_id,           
                ],
                OUTPUT_CLUSTERS: [],         
            }            
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.TEMPERATURE_SENSOR,   
                INPUT_CLUSTERS: [
                    Basic.cluster_id,                    
                    PowerConfigurationCluster.cluster_id,  
                    Identify.cluster_id,                   
                    PollControl.cluster_id,                
                    TemperatureMeasurement.cluster_id,     
                    GasConcentration,                      
                ],
                OUTPUT_CLUSTERS: [Ota.cluster_id],      
            },
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.MINI_SPLIT_AC, 
                INPUT_CLUSTERS: [
                    Basic.cluster_id,                      
                    PowerConfigurationCluster.cluster_id,  
                    Identify.cluster_id,                   
                    RelativeHumidity.cluster_id,          
                ],
                OUTPUT_CLUSTERS: [],         
            }            
        },    
    }

and

init.py

"""Titan quirks."""

TITAN = "Titan Products Ltd"

@B-Hartley
Copy link
Author

Hang on, I might have found it, let my fight with it for a bit before you give me the answer !

:-)

@Adminiuga
Copy link
Contributor

If running HassOS, try https://github.com/zigpy/zha-device-handlers#testing-quirks-in-development-in-docker-based-install

Usually I just get access to HassOS dev console (not the ssh add-on one), gives you access to the docker. From there inside the home assistant container docker exec -ti homeassistant /bin/bash gives the shell inside the container and the quirks are in 0.113: /usr/local/lib/python3.8/site-packages/zhaquirks/ folder

@B-Hartley
Copy link
Author

Thanks, I did it through portainer add-on.
I was stumped at first by the fact that home-assistant containers were hidden.
I've copied the files over and I'm doing a restart.
Can't imagine it will work first time.

Fingers crossed !!

@Adminiuga
Copy link
Contributor

the first step is getting the quirk recognized. Second would require some mods to ZHA

@B-Hartley
Copy link
Author

I've run out of home automation time tonight.
Will have to get back to this tomorrow.

The suspense !!

@B-Hartley
Copy link
Author

B-Hartley commented Mar 3, 2021

Ok, I have progress.
But I still can't see the 0x040d cluster being bound.
I had to make a few tweaks to the quirk due to syntax errors, or missing imports.

I ended up with..............

"""Device handler for Titan TPZRCO2TH-Z3 Environment Sensor."""
import logging

from zigpy.profiles import zha
from zigpy.quirks import CustomDevice, CustomCluster
from zigpy.zcl.clusters.general import Basic, Identify, Ota, PollControl, PowerConfiguration
from zigpy.zcl.clusters.measurement import TemperatureMeasurement, RelativeHumidity

from zhaquirks import PowerConfigurationCluster
import zigpy.types as t

from zhaquirks.const import (
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
)

class GasConcentration(CustomCluster):
    cluster_id = 0x040D
    name = "Gas Concentration Measurement"
    ep_attribute = "gas_concentration"
    vendor_attributes = {
        0x0000: ("measured_value", t.Single),
        0x0001: ("min_measured_value", t.Single),
        0x0002: ("max_measured_value", t.Single),
        0xFFFD: ("cluster_revision", t.uint16_t),
    }
    server_commands = {}
    client_commands = {}

_LOGGER = logging.getLogger(__name__)

class TPZRCO2THZ3(CustomDevice):
    """Custom device representing Titan TPZRCO2TH-Z3 environment sensor."""

    signature = {
        MODELS_INFO: [("Titan Products Ltd", "TPZRCO2HT-Z3")],
        ENDPOINTS: {
        #  <SimpleDescriptor endpoint=1 profile=260 device_type=770
        #  device_version=1
        #  input_clusters=[0, 1, 3, 32, 1026, 1037]        
        #  output_clusters=[25]>
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.TEMPERATURE_SENSOR,   
                INPUT_CLUSTERS: [
                    Basic.cluster_id,                    
                    PowerConfigurationCluster.cluster_id,  
                    Identify.cluster_id,                   
                    PollControl.cluster_id,                
                    TemperatureMeasurement.cluster_id,     
                    GasConcentration.cluster_id,                      
                ],
                OUTPUT_CLUSTERS: [Ota.cluster_id],         
            },
        #  <SimpleDescriptor endpoint=2 profile=260, device_type=775
        #  device_version=1
        #  input_clusters=[0, 1, 3, 1029]
        #  output_clusters=[]>
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.MINI_SPLIT_AC, 
                INPUT_CLUSTERS: [
                    Basic.cluster_id,                      
                    PowerConfigurationCluster.cluster_id,  
                    Identify.cluster_id,                   
                    RelativeHumidity.cluster_id,           
                ],
                OUTPUT_CLUSTERS: [],         
            }            
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.TEMPERATURE_SENSOR,   
                INPUT_CLUSTERS: [
                    Basic.cluster_id,                    
                    PowerConfigurationCluster.cluster_id,  
                    Identify.cluster_id,                   
                    PollControl.cluster_id,                
                    TemperatureMeasurement.cluster_id,     
                    GasConcentration,                      
                ],
                OUTPUT_CLUSTERS: [Ota.cluster_id],      
            },
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.MINI_SPLIT_AC, 
                INPUT_CLUSTERS: [
                    Basic.cluster_id,                      
                    PowerConfigurationCluster.cluster_id,  
                    Identify.cluster_id,                   
                    RelativeHumidity.cluster_id,          
                ],
                OUTPUT_CLUSTERS: [],         
            }            
        },    
    }

The log when I pair the product now says...............


Device 0x1baa   (00:15:8d:00:03:87:7f:49) joined the network
--
[0x1baa:zdo] ZDO request   ZDOCmd.Device_annce: [0x1BAA, 00:15:8d:00:03:87:7f:49, 128]
[0x1baa] Requesting 'Node Descriptor'
[0x1baa] Node Descriptor:   NodeDescriptor(byte1=2, byte2=64, mac_capability_flags=128,   manufacturer_code=4467, maximum_buffer_size=127,   maximum_incoming_transfer_size=100, server_mask=11264,   maximum_outgoing_transfer_size=100, descriptor_capability_field=0)
[0x1baa] Discovering endpoints
[0x1baa] Discovered endpoints: [1, 2]
[0x1baa:1] Discovering endpoint   information
[0x1baa:1] Discovered endpoint   information: SizePrefixedSimpleDescriptor(endpoint=1, profile=260,   device_type=770, device_version=1, input_clusters=[0, 1, 3, 1026, 1037, 32],   output_clusters=[25])
Unknown cluster 1037
[0x1baa:1:0x0000] ZCL deserialize:   <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND   manufacturer_specific=False is_reply=True disable_default_response=True>   manufacturer=None tsn=215 command_id=Command.Read_Attributes_rsp>
[0x1baa:1] Manufacturer: Titan Products   Ltd
[0x1baa:1] Model: TPZRCO2HT-Z3
[0x1baa:2] Discovering endpoint   information
[0x1baa:2] Discovered endpoint   information: SizePrefixedSimpleDescriptor(endpoint=2, profile=260,   device_type=775, device_version=1, input_clusters=[0, 1, 3, 1029],   output_clusters=[])
Checking quirks for Titan Products Ltd   TPZRCO2HT-Z3 (00:15:8d:00:03:87:7f:49)
Considering <class   'zhaquirks.titan.TPZRCO2THZ3.TPZRCO2THZ3'>
Found custom device replacement for   00:15:8d:00:03:87:7f:49: <class   'zhaquirks.titan.TPZRCO2THZ3.TPZRCO2THZ3'>
device - 0x1BAA:00:15:8d:00:03:87:7f:49   entering async_device_initialized - is_new_join: True
device - 0x1BAA:00:15:8d:00:03:87:7f:49   has joined the ZHA zigbee network
[0x1BAA](TPZRCO2HT-Z3): started   configuration
[0x1BAA:ZDO](TPZRCO2HT-Z3):   'async_configure' stage succeeded
[0x1BAA:1:0x0402]: bound 'temperature'   cluster: Status.SUCCESS
[0x1BAA:1:0x0001]: bound 'power' cluster:   Status.SUCCESS
[0x1BAA:1:0x0000]: bound 'basic' cluster:   Status.NOT_SUPPORTED
[0x1BAA:1:0x0000]: finished channel   configuration
[0x1baa:1:0x0402] ZCL deserialize:   <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND   manufacturer_specific=False is_reply=True disable_default_response=True>   manufacturer=None tsn=229 command_id=Command.Configure_Reporting_rsp>
[0x1BAA:1:0x0402]: reporting   'measured_value' attr on 'temperature' cluster: 30/900/50: Result:   '[[ConfigureReportingResponseRecord(status=0)]]'
[0x1BAA:1:0x0402]: finished channel   configuration
[0x1baa:1:0x0001] ZCL deserialize:   <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND   manufacturer_specific=False is_reply=True disable_default_response=True>   manufacturer=None tsn=231 command_id=Command.Configure_Reporting_rsp>
[0x1BAA:1:0x0001]: reporting   'battery_voltage' attr on 'power' cluster: 3600/10800/1: Result:   '[[ConfigureReportingResponseRecord(status=140, direction=0, attrid=32)]]'
[0x1BAA:1:0x0020]: bound 'poll_control'   cluster: Status.SUCCESS
[0x1baa:1:0x0001] ZCL deserialize:   <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND   manufacturer_specific=False is_reply=True disable_default_response=True>   manufacturer=None tsn=237 command_id=Command.Configure_Reporting_rsp>
[0x1BAA:1:0x0001]: reporting   'battery_percentage_remaining' attr on 'power' cluster: 3600/10800/1: Result:   '[[ConfigureReportingResponseRecord(status=134, direction=0, attrid=33)]]'
[0x1BAA:1:0x0001]: finished channel   configuration
[0x1BAA:1:0x0019]: bound 'ota' cluster:   Status.NOT_SUPPORTED
[0x1BAA:1:0x0019]: finished channel   configuration
[0x1baa:1:0x0020] ZCL deserialize:   <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND   manufacturer_specific=False is_reply=True disable_default_response=True>   manufacturer=None tsn=239 command_id=Command.Write_Attributes_rsp>
[0x1BAA:1:0x0020]: 3300.0s check-in   interval set: [[WriteAttributesStatusRecord(status=<Status.SUCCESS:   0>)]]
[0x1BAA:1:0x0020]: finished channel   configuration
[0x1BAA:1:0x0402]: 'async_configure'   stage succeeded
[0x1BAA:1:0x0001]: 'async_configure'   stage succeeded
[0x1BAA:1:0x0000]: 'async_configure'   stage succeeded
[0x1BAA:1:0x0020]: 'async_configure'   stage succeeded
[0x1BAA:1:0x0019]: 'async_configure'   stage succeeded
[0x1BAA:2:0x0000]: bound 'basic' cluster:   Status.NOT_SUPPORTED
[0x1BAA:2:0x0000]: finished channel   configuration
[0x1BAA:2:0x0405]: bound 'humidity'   cluster: Status.SUCCESS
[0x1baa:2:0x0405] ZCL deserialize:   <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND   manufacturer_specific=False is_reply=True disable_default_response=True>   manufacturer=None tsn=245 command_id=Command.Configure_Reporting_rsp>
[0x1BAA:2:0x0405]: reporting   'measured_value' attr on 'humidity' cluster: 30/900/50: Result:   '[[ConfigureReportingResponseRecord(status=0)]]'
[0x1BAA:2:0x0405]: finished channel   configuration
[0x1BAA:2:0x0000]: 'async_configure'   stage succeeded
[0x1BAA:2:0x0405]: 'async_configure'   stage succeeded
[0x1BAA](TPZRCO2HT-Z3): completed   configuration
[0x1BAA](TPZRCO2HT-Z3): stored in   registry: ZhaDeviceEntry(name='Titan Products Ltd TPZRCO2HT-Z3',   ieee='00:15:8d:00:03:87:7f:49', last_seen=1614778648.3336341)
[0x1baa:1:0x0003] ZCL deserialize:   <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND   manufacturer_specific=False is_reply=True disable_default_response=True>   manufacturer=None tsn=249 command_id=Command.Default_Response>
[0x1BAA:1:0x0003]: executed   'trigger_effect' command with args: '(2, 0)' kwargs: '{}' result: [64,   <Status.UNSUP_CLUSTER_COMMAND: 129>]
[0x1BAA](TPZRCO2HT-Z3): started   initialization
[0x1BAA:ZDO](TPZRCO2HT-Z3):   'async_initialize' stage succeeded
[0x1BAA:1:0x0402]: initializing channel:   from_cache: False
[0x1BAA:1:0x0001]: initializing channel:   from_cache: False
[0x1BAA:1:0x0000]: initializing channel:   from_cache: False
[0x1BAA:1:0x0000]: finished channel   configuration
[0x1BAA:1:0x0020]: initializing channel:   from_cache: False
[0x1BAA:1:0x0020]: finished channel   configuration
[0x1BAA:1:0x0019]: initializing channel:   from_cache: False
[0x1BAA:1:0x0019]: finished channel   configuration
[0x1BAA:2:0x0000]: initializing channel:   from_cache: False
[0x1BAA:2:0x0000]: finished channel   configuration
[0x1BAA:2:0x0405]: initializing channel:   from_cache: False
[0x1baa:1:0x0402] ZCL deserialize:   <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND   manufacturer_specific=False is_reply=True disable_default_response=True>   manufacturer=None tsn=255 command_id=Command.Read_Attributes_rsp>
[0x1BAA:1:0x0402]: finished channel   configuration
[0x1baa:1:0x0001] ZCL deserialize:   <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND   manufacturer_specific=False is_reply=True disable_default_response=True>   manufacturer=None tsn=1 command_id=Command.Read_Attributes_rsp>
[0x1baa:2:0x0405] ZCL deserialize:   <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND   manufacturer_specific=False is_reply=True disable_default_response=True>   manufacturer=None tsn=3 command_id=Command.Read_Attributes_rsp>
[0x1BAA:2:0x0405]: finished channel   configuration
[0x1BAA:2:0x0000]: 'async_initialize'   stage succeeded
[0x1BAA:2:0x0405]: 'async_initialize'   stage succeeded
[0x1baa:1:0x0001] ZCL deserialize:   <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND   manufacturer_specific=False is_reply=True disable_default_response=True>   manufacturer=None tsn=7 command_id=Command.Read_Attributes_rsp>
[0x1BAA:1:0x0001]: finished channel   configuration
[0x1BAA:1:0x0402]: 'async_initialize'   stage succeeded
[0x1BAA:1:0x0001]: 'async_initialize'   stage succeeded
[0x1BAA:1:0x0000]: 'async_initialize'   stage succeeded
[0x1BAA:1:0x0020]: 'async_initialize'   stage succeeded
[0x1BAA:1:0x0019]: 'async_initialize'   stage succeeded
[0x1BAA](TPZRCO2HT-Z3): power source:   Battery or Unknown
[0x1BAA](TPZRCO2HT-Z3): completed   initialization

Thoughts ?

Thanks

@Adminiuga
Copy link
Contributor

go to device page, pick the device -> Manage Clusters, Pick GasConcentration and then get value for the "measured_value" attribute. What do you get?

@B-Hartley
Copy link
Author

You mean:

integration -> Zigbee -> devices -> titan device.
Manage Clusters:

Choose GasConcentration
There are no Cluster Attributes to choose?

If I try the same for the Temperature Measurement Cluster, I can get the measured_value.

screenshot-github

@Adminiuga
Copy link
Contributor

Is the drop down empty?

@B-Hartley
Copy link
Author

Yes, drop down empty.

Other quirk files say:
manufacturer_attributes

Whereas, ours says vendor_attributes

should I change this ?

@Adminiuga
Copy link
Contributor

were you able to read battery_percent_remaining attribute? what did you get?

@B-Hartley
Copy link
Author

battery_percentage_remaining (0x0021) - None
on endpoint 1 and 2

@B-Hartley
Copy link
Author

CO2 still reporting nan :-(

@B-Hartley
Copy link
Author

2021-03-03 18:37:15 DEBUG (MainThread) [zigpy_deconz.api] 'aps_data_indication' response from <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0xc227>, ep: 1, profile: 0x0104, cluster_id: 0x040d, data: b'182001000000390000c07f'

@Adminiuga
Copy link
Contributor

well, apparently they do not support the battery_percent_remaining attribute, so two options are available

  1. Contact the manufacturer and ask them to update firmware adding support for that attribute
  2. Update the quirk to derive battery_percent_reamining based on battery_voltage updates. An example https://github.com/zigpy/zha-device-handlers/blob/dev/zhaquirks/zen/__init__.py

@Adminiuga
Copy link
Contributor

CO2 still reporting nan :-(

May want trying to get any one technical from the vendor and ask them if anything special needs to be done.

@B-Hartley
Copy link
Author

I had emailed the vendor already, this was their response.....
(It is still showing nan this morning)

The sensor will return 0x7fc00000 if the 0x040d cluster is not bound. Can you confirm that you have you bound the CO2 cluster?
Once you send valid bind request for the CO2 cluster, the sensor will reply with Bind Response of SUCCESS.

We use Single-precision floating-point because this is the type specified by Zigbee Cluster Library specification for the concertation cluster.

I've asked if they would expect it to return the max and min values in this situation.
Did the logs show it binding successfully or not ?

Thanks

@B-Hartley
Copy link
Author

If I ask it to bind from the UI, I get this in the log....
What do I need to do, to get it to sucessfully bind ?


2021-03-04   09:03:18 INFO (MainThread) [custom_components.zha.api] Devices bound:   source_ieee: [00:15:8d:00:03:87:7f:49] target_ieee: [00:21:2e:ff:ff:05:df:d0]
--
2021-03-04   09:03:19 DEBUG (MainThread) [zigpy_deconz.api] Device state changed response:   [<DeviceState.128\|APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|APSDE_DATA_INDICATION\|2:   170>, 0]
2021-03-04   09:03:19 DEBUG (MainThread) [zigpy_deconz.api] Command   Command.aps_data_indication (1, 1)
2021-03-04   09:03:19 DEBUG (MainThread) [zigpy_deconz.api] APS data indication response:   [31, <DeviceState.APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|2: 34>,   <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x0000>, 1,   <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0xc227>, 1, 260,   1026, b'\x18\x0b\n\x00\x00)\x96\x07', 0, 175, 255, 9, 84, 62, 0, -55]
2021-03-04   09:03:19 DEBUG (MainThread) [zigpy.zcl] [0xc227:1:0x0402] ZCL deserialize:   <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND   manufacturer_specific=False is_reply=True disable_default_response=True>   manufacturer=None tsn=11 command_id=Command.Report_Attributes>
2021-03-04   09:03:19 DEBUG (MainThread) [zigpy.zcl] [0xc227:1:0x0402] ZCL request 0x000a:   [[Attribute(attrid=0, value=<TypeValue type=int16s, value=1942>)]]
2021-03-04   09:03:19 DEBUG (MainThread) [zigpy.zcl] [0xc227:1:0x0402] Attribute report   received: measured_value=1942
2021-03-04   09:03:19 DEBUG (MainThread) [zigpy_deconz.api] 'aps_data_indication' response   from <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0xc227>, ep:   1, profile: 0x0104, cluster_id: 0x0402, data: b'180b0a0000299607'
2021-03-04   09:03:20 DEBUG (MainThread) [zigpy_deconz.api] Device state changed response:   [<DeviceState.128\|APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|APSDE_DATA_INDICATION\|2:   170>, 0]
2021-03-04   09:03:20 DEBUG (MainThread) [zigpy_deconz.api] Command   Command.aps_data_indication (1, 1)
2021-03-04   09:03:20 DEBUG (MainThread) [zigpy_deconz.api] APS data indication response:   [30, <DeviceState.APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|2: 34>,   <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x0000>, 1,   <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x4c8f>, 1, 260,   6, b'\x08\r\n\x00\x00\x10\x00', 0, 175, 255, 9, 84, 62, 0, -54]
2021-03-04   09:03:20 DEBUG (MainThread) [zigpy.zcl] [0x4c8f:1:0x0006] ZCL deserialize:   <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND   manufacturer_specific=False is_reply=True disable_default_response=False>   manufacturer=None tsn=13 command_id=Command.Report_Attributes>
2021-03-04   09:03:20 DEBUG (MainThread) [zigpy.zcl] [0x4c8f:1:0x0006] ZCL request 0x000a:   [[Attribute(attrid=0, value=<TypeValue type=Bool, value=Bool.false>)]]
2021-03-04   09:03:20 DEBUG (MainThread) [zigpy.zcl] [0x4c8f:1:0x0006] Attribute report   received: on_off=0
2021-03-04   09:03:20 DEBUG (MainThread) [zigpy_deconz.zigbee.application] Sending Zigbee   request with tsn 13 under 218 request id, data: b'180d0b0a00'
2021-03-04   09:03:20 DEBUG (MainThread) [zigpy_deconz.api] 'aps_data_indication' response   from <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x4c8f>, ep:   1, profile: 0x0104, cluster_id: 0x0006, data: b'080d0a00001000'
2021-03-04   09:03:20 DEBUG (MainThread) [zigpy_deconz.api] Command   Command.aps_data_request (20, 218, 0, <DeconzAddressEndpoint   address_mode=2 address=0x4C8F endpoint=1>, 260, 6, 1, b'\x18\r\x0b\n\x00',   2, 0)
2021-03-04   09:03:20 DEBUG (MainThread) [zigpy_deconz.api] APS data request response: [2,   <DeviceState.APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|2: 34>, 218]
2021-03-04   09:03:20 DEBUG (MainThread) [zigpy_deconz.api] Device state changed response:   [<DeviceState.128\|APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|APSDE_DATA_CONFIRM\|2:   166>, 0]
2021-03-04   09:03:20 DEBUG (MainThread) [zigpy_deconz.api] Command   Command.aps_data_confirm (0,)
2021-03-04   09:03:20 DEBUG (MainThread) [zigpy_deconz.api] APS data confirm response for   request with id 218: 00
2021-03-04   09:03:20 DEBUG (MainThread) [zigpy_deconz.api] Request id: 0xda   'aps_data_confirm' for <DeconzAddressEndpoint   address_mode=ADDRESS_MODE.NWK address=0x4c8f endpoint=1>, status: 0x00
2021-03-04   09:03:20 DEBUG (MainThread) [zigpy_deconz.api] APS data indication response:   [35, <DeviceState.APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|2: 34>,   <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x0000>, 1,   <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0xe918>, 11, 260,   25, b'\x01\xef\x01\x00~\x11\x00\x00\x01\x00\x00\x00', 0, 175, 255, 9, 84, 62,   0, -54]
2021-03-04   09:03:20 DEBUG (MainThread) [zigpy.zcl] [0xe918:11:0x0019] ZCL deserialize:   <ZCLHeader frame_control=<FrameControl frame_type=CLUSTER_COMMAND   manufacturer_specific=False is_reply=False disable_default_response=False>   manufacturer=None tsn=239 command_id=1>
2021-03-04   09:03:20 DEBUG (MainThread) [zigpy.zcl] [0xe918:11:0x0019] ZCL request   0x0001: [0, 4478, 0, 1, None]
2021-03-04   09:03:20 DEBUG (MainThread) [zigpy.zcl] [0xe918:11:0x0019] OTA   query_next_image handler for '3A SMart Home DE LXN56-LC27LX1.1':   field_control=0, manufacture_id=4478, image_type=0, current_file_version=1,   hardware_version=None
2021-03-04   09:03:20 DEBUG (MainThread) [zigpy.zcl] [0xe918:11:0x0019] No OTA image is   available
2021-03-04   09:03:20 DEBUG (MainThread) [zigpy_deconz.zigbee.application] Sending Zigbee   request with tsn 239 under 219 request id, data: b'19ef0298'
2021-03-04   09:03:20 DEBUG (MainThread) [zigpy_deconz.api] 'aps_data_indication' response   from <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0xe918>, ep:   11, profile: 0x0104, cluster_id: 0x0019, data: b'01ef01007e11000001000000'
2021-03-04   09:03:20 DEBUG (MainThread) [zigpy_deconz.api] Command   Command.aps_data_request (19, 219, 0, <DeconzAddressEndpoint   address_mode=2 address=0xE918 endpoint=11>, 260, 25, 1,   b'\x19\xef\x02\x98', 2, 0)
2021-03-04   09:03:20 DEBUG (MainThread) [zigpy_deconz.api] APS data request response: [2,   <DeviceState.APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|2: 34>, 219]
2021-03-04   09:03:20 DEBUG (MainThread) [zigpy_deconz.api] APS data confirm response for   request with id 219: 00
2021-03-04   09:03:20 DEBUG (MainThread) [zigpy_deconz.api] Request id: 0xdb   'aps_data_confirm' for <DeconzAddressEndpoint   address_mode=ADDRESS_MODE.NWK address=0xe918 endpoint=11>, status: 0x00
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy_deconz.zigbee.application] Sending Zigbee   request with tsn 220 under 221 request id, data: b'00dc000000'
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy_deconz.api] Command   Command.aps_data_request (20, 221, 0, <DeconzAddressEndpoint   address_mode=2 address=0xE19D endpoint=11>, 260, 6, 1,   b'\x00\xdc\x00\x00\x00', 2, 0)
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy_deconz.api] APS data request response: [2,   <DeviceState.APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|2: 34>, 221]
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy_deconz.api] Device state changed response:   [<DeviceState.128\|APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|APSDE_DATA_CONFIRM\|2:   166>, 0]
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy_deconz.api] Command   Command.aps_data_confirm (0,)
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy_deconz.api] APS data confirm response for   request with id 221: 00
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy_deconz.api] Request id: 0xdd   'aps_data_confirm' for <DeconzAddressEndpoint   address_mode=ADDRESS_MODE.NWK address=0xe19d endpoint=11>, status: 0x00
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy_deconz.api] Device state changed response:   [<DeviceState.128\|APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|APSDE_DATA_INDICATION\|2:   170>, 0]
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy_deconz.api] Command   Command.aps_data_indication (1, 1)
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy_deconz.api] APS data indication response:   [31, <DeviceState.APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|2: 34>,   <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x0000>, 1,   <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0xe19d>, 11, 260,   6, b'\x18\xdc\x01\x00\x00\x00\x10\x00', 0, 175, 255, 9, 84, 62, 0, -54]
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy.zcl] [0xe19d:11:0x0006] ZCL deserialize:   <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND   manufacturer_specific=False is_reply=True disable_default_response=True>   manufacturer=None tsn=220 command_id=Command.Read_Attributes_rsp>
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy_deconz.api] 'aps_data_indication' response   from <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0xe19d>, ep:   11, profile: 0x0104, cluster_id: 0x0006, data: b'18dc010000001000'
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy_deconz.zigbee.application] Sending Zigbee   request with tsn 222 under 223 request id, data: b'00de000000'
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy_deconz.api] Command   Command.aps_data_request (20, 223, 0, <DeconzAddressEndpoint   address_mode=2 address=0xE19D endpoint=11>, 260, 8, 1,   b'\x00\xde\x00\x00\x00', 2, 0)
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy_deconz.api] APS data request response: [2,   <DeviceState.APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|2: 34>, 223]
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy_deconz.api] APS data confirm response for   request with id 223: 00
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy_deconz.api] Request id: 0xdf   'aps_data_confirm' for <DeconzAddressEndpoint   address_mode=ADDRESS_MODE.NWK address=0xe19d endpoint=11>, status: 0x00
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy_deconz.api] APS data indication response:   [31, <DeviceState.APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|2: 34>,   <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x0000>, 1,   <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0xe19d>, 11, 260,   8, b'\x18\xde\x01\x00\x00\x00 \xfe', 0, 175, 255, 9, 84, 62, 0, -53]
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy.zcl] [0xe19d:11:0x0008] ZCL deserialize:   <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND   manufacturer_specific=False is_reply=True disable_default_response=True>   manufacturer=None tsn=222 command_id=Command.Read_Attributes_rsp>
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy_deconz.api] 'aps_data_indication' response   from <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0xe19d>, ep:   11, profile: 0x0104, cluster_id: 0x0008, data: b'18de0100000020fe'
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy_deconz.zigbee.application] Sending Zigbee   request with tsn 224 under 225 request id, data:   b'00e00008000700030004000240'
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy_deconz.api] Command   Command.aps_data_request (28, 225, 0, <DeconzAddressEndpoint   address_mode=2 address=0xE19D endpoint=11>, 260, 768, 1,   b'\x00\xe0\x00\x08\x00\x07\x00\x03\x00\x04\x00\x02@', 2, 0)
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy_deconz.api] APS data request response: [2,   <DeviceState.APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|2: 34>, 225]
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy_deconz.api] APS data confirm response for   request with id 225: 00
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy_deconz.api] Request id: 0xe1   'aps_data_confirm' for <DeconzAddressEndpoint   address_mode=ADDRESS_MODE.NWK address=0xe19d endpoint=11>, status: 0x00
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy_deconz.api] APS data indication response:   [52, <DeviceState.APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|2: 34>,   <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x0000>, 1,   <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0xe19d>, 11, 260,   768,   b'\x18\xe0\x01\x08\x00\x000\x02\x07\x00\x00!n\x01\x03\x00\x00!\x14u\x04\x00\x00!\xf7h\x02@\x86',   0, 175, 255, 9, 84, 62, 0, -54]
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy.zcl] [0xe19d:11:0x0300] ZCL deserialize:   <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND   manufacturer_specific=False is_reply=True disable_default_response=True>   manufacturer=None tsn=224 command_id=Command.Read_Attributes_rsp>
2021-03-04   09:03:26 DEBUG (MainThread) [zigpy_deconz.api] 'aps_data_indication' response   from <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0xe19d>, ep:   11, profile: 0x0104, cluster_id: 0x0300, data:   b'18e0010800003002070000216e0103000021147504000021f768024086'
2021-03-04   09:03:33 DEBUG (MainThread) [zigpy.device] [0xc227] Extending timeout for   0xe2 request
2021-03-04   09:03:33 DEBUG (MainThread) [zigpy_deconz.zigbee.application] Sending Zigbee   request with tsn 226 under 227 request id, data: b'00e2000000'
2021-03-04   09:03:33 DEBUG (MainThread) [zigpy_deconz.api] Command   Command.aps_data_request (20, 227, 0, <DeconzAddressEndpoint   address_mode=2 address=0xC227 endpoint=1>, 260, 1037, 1,   b'\x00\xe2\x00\x00\x00', 2, 0)
2021-03-04   09:03:33 DEBUG (MainThread) [zigpy_deconz.api] APS data request response: [2,   <DeviceState.APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|2: 34>, 227]
2021-03-04   09:03:33 DEBUG (MainThread) [zigpy_deconz.api] Device state changed response:   [<DeviceState.128\|APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|APSDE_DATA_CONFIRM\|2:   166>, 0]
2021-03-04   09:03:33 DEBUG (MainThread) [zigpy_deconz.api] Command   Command.aps_data_confirm (0,)
2021-03-04   09:03:33 DEBUG (MainThread) [zigpy_deconz.api] APS data confirm response for   request with id 227: 00
2021-03-04   09:03:33 DEBUG (MainThread) [zigpy_deconz.api] Request id: 0xe3   'aps_data_confirm' for <DeconzAddressEndpoint   address_mode=ADDRESS_MODE.NWK address=0xc227 endpoint=1>, status: 0x00
2021-03-04   09:03:38 DEBUG (MainThread) [zigpy_deconz.api] Device state changed response:   [<DeviceState.128\|APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|APSDE_DATA_INDICATION\|2:   170>, 0]
2021-03-04   09:03:38 DEBUG (MainThread) [zigpy_deconz.api] Command   Command.aps_data_indication (1, 1)
2021-03-04   09:03:38 DEBUG (MainThread) [zigpy_deconz.api] APS data indication response:   [34, <DeviceState.APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|2: 34>,   <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x0000>, 1,   <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0xc227>, 1, 260,   1037, b'\x18\xe2\x01\x00\x00\x009\x00\x00\xc0\x7f', 0, 175, 255, 18, 84, 62,   0, -55]
2021-03-04   09:03:38 DEBUG (MainThread) [zigpy.zcl] [0xc227:1:0x040d] ZCL deserialize:   <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND   manufacturer_specific=False is_reply=True disable_default_response=True>   manufacturer=None tsn=226 command_id=Command.Read_Attributes_rsp>
2021-03-04   09:03:38 DEBUG (MainThread) [zigpy_deconz.api] 'aps_data_indication' response   from <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0xc227>, ep:   1, profile: 0x0104, cluster_id: 0x040d, data: b'18e201000000390000c07f'
2021-03-04   09:03:38 DEBUG (MainThread) [zigpy_deconz.api] APS data indication response:   [31, <DeviceState.APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|2: 34>,   <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x0000>, 1,   <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x2fca>, 2, 260,   1024, b'\x08\xcf\n\x00\x00!y\x1f', 0, 175, 239, 18, 84, 62, 0, -64]
2021-03-04   09:03:38 DEBUG (MainThread) [zigpy.zcl] [0x2fca:2:0x0400] ZCL deserialize:   <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND   manufacturer_specific=False is_reply=True disable_default_response=False>   manufacturer=None tsn=207 command_id=Command.Report_Attributes>
2021-03-04   09:03:38 DEBUG (MainThread) [zigpy.zcl] [0x2fca:2:0x0400] ZCL request 0x000a:   [[Attribute(attrid=0, value=<TypeValue type=uint16_t, value=8057>)]]
2021-03-04   09:03:38 DEBUG (MainThread) [zigpy.zcl] [0x2fca:2:0x0400] Attribute report   received: measured_value=8057
2021-03-04   09:03:38 DEBUG (MainThread) [zigpy_deconz.zigbee.application] Sending Zigbee   request with tsn 207 under 228 request id, data: b'18cf0b0a00'
2021-03-04   09:03:38 DEBUG (MainThread) [zigpy_deconz.api] 'aps_data_indication' response   from <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x2fca>, ep:   2, profile: 0x0104, cluster_id: 0x0400, data: b'08cf0a000021791f'
2021-03-04   09:03:38 DEBUG (MainThread) [zigpy_deconz.api] Command   Command.aps_data_request (20, 228, 0, <DeconzAddressEndpoint   address_mode=2 address=0x2FCA endpoint=2>, 260, 1024, 1,   b'\x18\xcf\x0b\n\x00', 2, 0)
2021-03-04   09:03:38 DEBUG (MainThread) [zigpy_deconz.api] APS data request response: [2,   <DeviceState.APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|2: 34>, 228]
2021-03-04   09:03:38 DEBUG (MainThread) [zigpy_deconz.api] Device state changed response:   [<DeviceState.128\|APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|APSDE_DATA_CONFIRM\|2:   166>, 0]
2021-03-04   09:03:38 DEBUG (MainThread) [zigpy_deconz.api] Command   Command.aps_data_confirm (0,)
2021-03-04   09:03:38 DEBUG (MainThread) [zigpy_deconz.api] APS data confirm response for   request with id 228: 00
2021-03-04   09:03:38 DEBUG (MainThread) [zigpy_deconz.api] Request id: 0xe4   'aps_data_confirm' for <DeconzAddressEndpoint   address_mode=ADDRESS_MODE.NWK address=0x2fca endpoint=2>, status: 0x00
2021-03-04   09:03:42 DEBUG (MainThread) [zigpy_deconz.zigbee.application] Sending Zigbee   request with tsn 229 under 230 request id, data: b'00e5000b05'
2021-03-04   09:03:42 DEBUG (MainThread) [zigpy_deconz.api] Command   Command.aps_data_request (20, 230, 0, <DeconzAddressEndpoint   address_mode=2 address=0x0F66 endpoint=1>, 260, 2820, 1,   b'\x00\xe5\x00\x0b\x05', 2, 0)
2021-03-04   09:03:42 DEBUG (MainThread) [zigpy_deconz.zigbee.application] Sending Zigbee   request with tsn 231 under 232 request id, data: b'00e7000b05'
2021-03-04   09:03:42 DEBUG (MainThread) [zigpy_deconz.api] APS data request response: [2,   <DeviceState.APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|2: 34>, 230]
2021-03-04   09:03:42 DEBUG (MainThread) [zigpy_deconz.api] Command   Command.aps_data_request (20, 232, 0, <DeconzAddressEndpoint   address_mode=2 address=0x0163 endpoint=1>, 260, 2820, 1,   b'\x00\xe7\x00\x0b\x05', 2, 0)
2021-03-04   09:03:42 DEBUG (MainThread) [zigpy_deconz.api] Device state changed response:   [<DeviceState.128\|APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|APSDE_DATA_CONFIRM\|2:   166>, 0]
2021-03-04   09:03:42 DEBUG (MainThread) [zigpy_deconz.api] APS data request response: [2,   <DeviceState.APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|APSDE_DATA_CONFIRM\|2:   38>, 232]
2021-03-04   09:03:42 DEBUG (MainThread) [zigpy_deconz.api] Command   Command.aps_data_confirm (0,)
2021-03-04   09:03:42 DEBUG (MainThread) [zigpy_deconz.api] APS data confirm response for   request with id 230: 00
2021-03-04   09:03:42 DEBUG (MainThread) [zigpy_deconz.api] Request id: 0xe6   'aps_data_confirm' for <DeconzAddressEndpoint   address_mode=ADDRESS_MODE.NWK address=0x0f66 endpoint=1>, status: 0x00
2021-03-04   09:03:42 DEBUG (MainThread) [zigpy_deconz.api] Device state changed response:   [<DeviceState.128\|APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|APSDE_DATA_INDICATION\|APSDE_DATA_CONFIRM\|2:   174>, 0]
2021-03-04   09:03:42 DEBUG (MainThread) [zigpy_deconz.api] APS data confirm response for   request with id 232: 00
2021-03-04   09:03:42 DEBUG (MainThread) [zigpy_deconz.api] Request id: 0xe8   'aps_data_confirm' for <DeconzAddressEndpoint   address_mode=ADDRESS_MODE.NWK address=0x0163 endpoint=1>, status: 0x00
2021-03-04   09:03:42 DEBUG (MainThread) [zigpy_deconz.api] Command   Command.aps_data_indication (1, 1)
2021-03-04   09:03:42 DEBUG (MainThread) [zigpy_deconz.api] APS data indication response:   [32,   <DeviceState.APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|APSDE_DATA_INDICATION\|2:   42>, <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x0000>,   1, <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x0f66>, 1,   260, 2820, b'\x18\xe5\x01\x0b\x05\x00)\x00\x00', 0, 175, 255, 18, 84, 62, 0,   -54]
2021-03-04   09:03:42 DEBUG (MainThread) [zigpy.zcl] [0x0f66:1:0x0b04] ZCL deserialize:   <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND   manufacturer_specific=False is_reply=True disable_default_response=True>   manufacturer=None tsn=229 command_id=Command.Read_Attributes_rsp>
2021-03-04   09:03:42 DEBUG (MainThread) [zigpy_deconz.api] 'aps_data_indication' response   from <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x0f66>, ep:   1, profile: 0x0104, cluster_id: 0x0b04, data: b'18e5010b0500290000'
2021-03-04   09:03:42 DEBUG (MainThread) [zigpy_deconz.api] APS data indication response:   [32, <DeviceState.APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|2: 34>,   <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x0000>, 1,   <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x0163>, 1, 260,   2820, b'\x18\xe7\x01\x0b\x05\x00)\x00\x00', 0, 175, 255, 90, 81, 62, 0, -34]
2021-03-04   09:03:42 DEBUG (MainThread) [zigpy.zcl] [0x0163:1:0x0b04] ZCL deserialize:   <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND   manufacturer_specific=False is_reply=True disable_default_response=True>   manufacturer=None tsn=231 command_id=Command.Read_Attributes_rsp>
2021-03-04   09:03:42 DEBUG (MainThread) [zigpy_deconz.api] 'aps_data_indication' response   from <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x0163>, ep:   1, profile: 0x0104, cluster_id: 0x0b04, data: b'18e7010b0500290000'
2021-03-04   09:03:43 DEBUG (MainThread) [zigpy_deconz.api] Device state changed response:   [<DeviceState.128\|APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|APSDE_DATA_INDICATION\|2:   170>, 0]
2021-03-04   09:03:43 DEBUG (MainThread) [zigpy_deconz.api] Command   Command.aps_data_indication (1, 1)
2021-03-04   09:03:43 DEBUG (MainThread) [zigpy_deconz.api] APS data indication response:   [35, <DeviceState.APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|2: 34>,   <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x0000>, 1,   <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0xa4bd>, 2, 260,   25, b'\x01\xb9\x01\x00\x0b\x10\r\x01\xb7k\x00B', 0, 175, 199, 18, 84, 62, 0,   -69]
2021-03-04   09:03:43 DEBUG (MainThread) [zigpy.zcl] [0xa4bd:2:0x0019] ZCL deserialize:   <ZCLHeader frame_control=<FrameControl frame_type=CLUSTER_COMMAND   manufacturer_specific=False is_reply=False disable_default_response=False>   manufacturer=None tsn=185 command_id=1>
2021-03-04   09:03:43 DEBUG (MainThread) [zigpy.zcl] [0xa4bd:2:0x0019] ZCL request 0x0001:   [0, 4107, 269, 1107323831, None]
2021-03-04   09:03:43 DEBUG (MainThread) [zigpy.zcl] [0xa4bd:2:0x0019] OTA   query_next_image handler for 'Philips SML001': field_control=0,   manufacture_id=4107, image_type=269, current_file_version=1107323831,   hardware_version=None
2021-03-04   09:03:43 DEBUG (MainThread) [zigpy.zcl] [0xa4bd:2:0x0019] No OTA image is   available
2021-03-04   09:03:43 DEBUG (MainThread) [zigpy_deconz.zigbee.application] Sending Zigbee   request with tsn 185 under 233 request id, data: b'19b90298'
2021-03-04   09:03:43 DEBUG (MainThread) [zigpy_deconz.api] 'aps_data_indication' response   from <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0xa4bd>, ep:   2, profile: 0x0104, cluster_id: 0x0019, data: b'01b901000b100d01b76b0042'
2021-03-04   09:03:43 DEBUG (MainThread) [zigpy_deconz.api] Command   Command.aps_data_request (19, 233, 0, <DeconzAddressEndpoint   address_mode=2 address=0xA4BD endpoint=2>, 260, 25, 1,   b'\x19\xb9\x02\x98', 2, 0)
2021-03-04   09:03:43 DEBUG (MainThread) [zigpy_deconz.api] APS data request response: [2,   <DeviceState.APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|2: 34>, 233]
2021-03-04   09:03:43 DEBUG (MainThread) [zigpy_deconz.api] Device state changed response:   [<DeviceState.128\|APSDE_DATA_REQUEST_SLOTS_AVAILABLE\|APSDE_DATA_CONFIRM\|2:   166>, 0]
2021-03-04   09:03:43 DEBUG (MainThread) [zigpy_deconz.api] Command   Command.aps_data_confirm (0,)
2021-03-04   09:03:43 DEBUG (MainThread) [zigpy_deconz.api] APS data confirm response for   request with id 233: 00
2021-03-04   09:03:43 DEBUG (MainThread) [zigpy_deconz.api] Request id: 0xe9   'aps_data_confirm' for <DeconzAddressEndpoint   address_mode=ADDRESS_MODE.NWK address=0xa4bd endpoint=2>, status: 0x00


@MattWestb
Copy link
Contributor

Perhaps trying binding from the device card to the coordinator. or if its not working thee cluster to group 0x000 (coordinator group) ?

Is the sensor sleeping or do it listening and executing the command ?

@B-Hartley
Copy link
Author

Sorry, you've lost me a bit.
Is pairing and binding different?

I can forget the device, then discover it.
Everything sets up for temp and humidity, but it doesn't seem to bind the GasConcentration that I've created the quirk for.

When you bind from the UI are you binding a device? or a cluster?

On my bindable devices list I just see my conbee USB stick.

On the clusters list I see all clusters incl. the gas concentration one.
I can call attributes from the max and min on the concentration cluster, but because it is not bound I can't get the measured value.

Sorry if I'm being a bit thick, but what do I do to bind it or to diagnose it ?

Thanks

@MattWestb
Copy link
Contributor

Binding is not pairing the device.
Some devices is ZHA automatically clusters they knowing need being bonded then pairing it like power cluster on IKEA remotes for getting the battery status reported to the coordinator.

I think ZHA is not doing any binding on your device then the devs have not "knowing its needs" so you need binding it manually.

Try binding it to your coordinator and look in the log if you can see its being bonded.
Sensors normally bonded to the coordinator (0x0000) but remote is normally bonded to groups.

And if you is waiting little is normally Adminiuga coming back after his night rest (US TZ) and hi is knowing all the best.

I still finding it very interesting getting your CO2 sensor being supported !!

@Adminiuga
Copy link
Contributor

Do you get an extra entity for this device for the 0x040D cluster?

  1. remove device from ZHA and wait 30s
  2. make sure debug log is enabled
  3. re-pair the device
  4. post the pairing log

For ZHA to bind that cluster, ZHA needs to have a "sensor" mapping. zha/sensor.py maps a cluster to a channel, and channel does the binding.

@Adminiuga
Copy link
Contributor

We use Single-precision floating-point because this is the type specified by Zigbee Cluster Library specification for the concertation cluster.

Turns out ZCL revision 7 does specify a bunch of Gas Concentration clusters

@Adminiuga
Copy link
Contributor

Would need to add those to zigpy then. Maybe next release

@Adminiuga
Copy link
Contributor

Don't try the binding from UI, as I'm not positive it would work correctly for these types of clusters. ZHA binds measurement clusters on device join or on clicking the "reconfigure button". Although some devices don't really like to be configured multiple times, so for now just reset the device and re-pair it, assuming you do get the sensor entity for 0x040d cluster

@B-Hartley
Copy link
Author

B-Hartley commented Mar 5, 2021

ok, I've manually patched zigpy on my installation.

I've added......

class _ConcentrationMixin:
    """Mixin for the common attributes of the concentration measurement clusters"""

    attributes = {
        0x0000: ("measured_value", t.Single),  # fraction of 1 (one)
        0x0001: ("min_measured_value", t.Single),
        0x0002: ("max_measured_value", t.Single),
        0x0003: ("tolerance", t.Single),
    }

    server_commands = {}
    client_commands = {}

class CarbonDioxideConcentration(_ConcentrationMixin, Cluster):
    cluster_id = 0x040D
    name = "Carbon Dioxide (CO2) Concentration"
    ep_attribute = "carbon_dioxide_concentration"

I'm on core-2021.3.1
Home Assistant OS
supervisor-2021.03.4

I've dropped the quirk for now, as I'm not sure if it is required now zigpy has been updated.
I've got my custom component version of zha and in sensor.py I have added:

@STRICT_MATCH(channel_names="carbon_dioxide_concentration")
class CarbonDioxideConcentration(Sensor):
    """Carbon Dioxide Concentration sensor."""

    SENSOR_ATTR = "measured_value"
    _decimals = 0
    _multiplier = 1e6
    _unit = "ppm"

in measurement.py I have added:

@registries.ZIGBEE_CHANNEL_REGISTRY.register(
    measurement.CarbonDioxideConcentration.cluster_id
)
class CarbonDioxideConcentration(ZigbeeChannel):
    """Gas Concentration measurement channel."""

    REPORT_CONFIG = [
        {
            "attr": "measured_value",
            "config": (REPORT_CONFIG_MIN_INT, REPORT_CONFIG_MAX_INT, 0.000001),
        }
    ]

Pairing Log is now.........

[0x0000:zdo]   ZDO request ZDOCmd.Mgmt_Permit_Joining_req: [60, <Bool.false: 0>]
[0x0f66:1:0x0000] ZCL request 0x000a:   [[Attribute(attrid=1, value=<TypeValue type=uint8_t, value=67>)]]
[0x0f66:1:0x0000] Attribute report   received: app_version=67
Device 0x0dd9   (00:15:8d:00:03:87:7f:49) joined the network
[0x0dd9:zdo] ZDO request   ZDOCmd.Device_annce: [0x0DD9, 00:15:8d:00:03:87:7f:49, 128]
[0x0dd9] Requesting 'Node   Descriptor'
[0x0dd9] Extending timeout for   0xd9 request
[0x0dd9] Node Descriptor:   NodeDescriptor(byte1=2, byte2=64, mac_capability_flags=128,   manufacturer_code=4467, maximum_buffer_size=127,   maximum_incoming_transfer_size=100, server_mask=11264,   maximum_outgoing_transfer_size=100, descriptor_capability_field=0)
[0x0dd9] Discovering endpoints
[0x0dd9] Extending timeout for   0xdb request
[0x0dd9] Discovered endpoints:   [1, 2]
[0x0dd9:1] Discovering   endpoint information
[0x0dd9] Extending timeout for   0xdd request
[0x0dd9:1] Discovered endpoint   information: SizePrefixedSimpleDescriptor(endpoint=1, profile=260,   device_type=770, device_version=1, input_clusters=[0, 1, 3, 1026, 1037, 32],   output_clusters=[25])
[0x0dd9] Extending timeout for   0xdf request
[0x0dd9:1:0x0000] ZCL   deserialize: <ZCLHeader frame_control=<FrameControl   frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True   disable_default_response=True> manufacturer=None tsn=223   command_id=Command.Read_Attributes_rsp>
[0x0dd9:1] Manufacturer: Titan   Products Ltd
[0x0dd9:1] Model: TPZRCO2HT-Z3
[0x0dd9:2] Discovering   endpoint information
[0x0dd9] Extending timeout for   0xe1 request
[0x0dd9:2] Discovered endpoint   information: SizePrefixedSimpleDescriptor(endpoint=2, profile=260,   device_type=775, device_version=1, input_clusters=[0, 1, 3, 1029],   output_clusters=[])
Checking quirks for Titan   Products Ltd TPZRCO2HT-Z3 (00:15:8d:00:03:87:7f:49)
[0x0dd9:1:0x0402] ZCL   deserialize: <ZCLHeader frame_control=<FrameControl   frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True   disable_default_response=True> manufacturer=None tsn=240   command_id=Command.Configure_Reporting_rsp>
[0x0dd9:1:0x0001] ZCL   deserialize: <ZCLHeader frame_control=<FrameControl   frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True   disable_default_response=True> manufacturer=None tsn=242   command_id=Command.Configure_Reporting_rsp>
[0x0dd9:1:0x0001] ZCL   deserialize: <ZCLHeader frame_control=<FrameControl   frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True   disable_default_response=True> manufacturer=None tsn=251   command_id=Command.Configure_Reporting_rsp>
[0x0dd9] Extending timeout for   0x01 request
[0x0dd9:1:0x0020] ZCL   deserialize: <ZCLHeader frame_control=<FrameControl   frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True   disable_default_response=True> manufacturer=None tsn=253   command_id=Command.Write_Attributes_rsp>
[0x0dd9:2:0x0405] ZCL   deserialize: <ZCLHeader frame_control=<FrameControl   frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True   disable_default_response=True> manufacturer=None tsn=3   command_id=Command.Configure_Reporting_rsp>
[0x0dd9:1:0x0003] ZCL   deserialize: <ZCLHeader frame_control=<FrameControl   frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True   disable_default_response=True> manufacturer=None tsn=5   command_id=Command.Default_Response>
[0x0dd9:1:0x0402] ZCL   deserialize: <ZCLHeader frame_control=<FrameControl   frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True   disable_default_response=True> manufacturer=None tsn=7   command_id=Command.Read_Attributes_rsp>
[0x0dd9:1:0x0001] ZCL   deserialize: <ZCLHeader frame_control=<FrameControl   frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True   disable_default_response=True> manufacturer=None tsn=9   command_id=Command.Read_Attributes_rsp>
[0x0dd9:2:0x0405] ZCL   deserialize: <ZCLHeader frame_control=<FrameControl   frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True   disable_default_response=True> manufacturer=None tsn=11   command_id=Command.Read_Attributes_rsp>
[0x0dd9:1:0x0001] ZCL   deserialize: <ZCLHeader frame_control=<FrameControl   frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True   disable_default_response=True> manufacturer=None tsn=18   command_id=Command.Read_Attributes_rsp>

I've attached debug log.

What should I do next?

Thanks.
debug-log.txt

@Adminiuga
Copy link
Contributor

I forgot about https://github.com/home-assistant/core/blob/864380e77c277b58ab4a85f5d1d3c023b31cf4c7/homeassistant/components/zha/core/registries.py#L57-L78
Add to that dict:

zcl.cluster.measeraument.CarbonDioxideConcentration.cluster_id: SENSOR,

and you already modified the zha/sensor.py. so should get a new entity

@B-Hartley
Copy link
Author

Well I have an entity now ! yay !!

Did a remove and repair and it has a value now !

Amazing !

Thank you so much.

So how do we get all of this into a pull request ?

@B-Hartley
Copy link
Author

should it have a suitable icon ?

@Adminiuga
Copy link
Contributor

I don't think HA has defined a device class for Carbon Monoxide, so for now the icon should be overriden through customization. see home-assistant/architecture#520

@B-Hartley
Copy link
Author

I don't think HA has defined a device class for Carbon Monoxide, so for now the icon should be overriden through customization. see home-assistant/architecture#520

That's fine.
Do you want me to attempt to create a pull request for the changes.
I've never done it for anything other than a doc page once, but I'm willing to have a go.
Otherwise, what's the best way to get these changes patched in ?

@B-Hartley
Copy link
Author

titan-sensor

@B-Hartley
Copy link
Author

I've created a branch here:
https://github.com/B-Hartley/core/tree/add-zhl-concentration-clusters

with all the concentration clusters added into the various files.

zha/sensor.py
zha/core/registries.py
zha/core/channel/measurement.py

I was going to try and submit a pull request, but I'm a bit out of depth.
No idea how to do the required testing etc.

Could someone with more knowledge please look if they can be submitted.

@Adminiuga
Copy link
Contributor

So from the github, from you repo and the branch with the updates, you should be able to click on the "Pull Request" link/box and create the PR.
It looks good, but for now lets limit it to Carbon Monoxide and Carbon Dioxide sensors.

@B-Hartley
Copy link
Author

ok, I've created the Pull request, hope it's ok.

@B-Hartley
Copy link
Author

Got some validation errors on the pull request, I think I've fixed them and checked them into the branch.
Will the tests re-run at some point ?

@github-actions
Copy link

github-actions bot commented Sep 4, 2021

There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates. Please make sure to update to the latest version and check if that solves the issue. Let us know if that works for you by adding a comment 👍 This issue has now been marked as stale and will be closed if no further activity occurs. Thank you for your contributions.

@github-actions github-actions bot added the stale Issue is inactivate and might get closed soon label Sep 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stale Issue is inactivate and might get closed soon
Projects
None yet
Development

No branches or pull requests

4 participants