zigpy / zha-device-handlers

ZHA device handlers bridge the functionality gap created when manufacturers deviate from the ZCL specification, handling deviations and exceptions by parsing custom messages to and from Zigbee devices.
Apache License 2.0
717 stars 665 forks source link

[Device Support Request] Tuya ZG-102ZL / _TZE200_pay2byax #1502

Open centershock opened 2 years ago

centershock commented 2 years ago

Is your feature request related to a problem? Please describe. The device is not supported, I request a full support of this device.

Describe the solution you'd like Full support for the device, primarily to check "open" and "close" of a window / door.

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(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=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, 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",
        "0x0500"
      ],
      "out_clusters": [
        "0x000a",
        "0x0019"
      ]
    }
  },
  "manufacturer": "_TZE200_pay2byax",
  "model": "TS0601",
  "class": "zigpy.device.Device"
}

Join logs:

New device 0x0df7 (a4:c1:38:4d:82:df:a6:b0) joined the network
[0x0df7] Scheduling initialization
Received frame on uninitialized device <Device model=None manuf=None nwk=0x0DF7 ieee=a4:c1:38:4d:82:df:a6:b0 is_initialized=False> from ep 0 to ep 0, cluster 19: b'\x00\xf7\r\xb0\xa6\xdf\x82M8\xc1\xa4\x80'
[0x0df7:zdo] ZDO request ZDOCmd.Device_annce: [0x0DF7, a4:c1:38:4d:82:df:a6:b0, 128]
Tries remaining: 3
[0x0df7] Requesting 'Node Descriptor'
Tries remaining: 2
[0x0df7] Extending timeout for 0x77 request
Received frame on uninitialized device <Device model=None manuf=None nwk=0x0DF7 ieee=a4:c1:38:4d:82:df:a6:b0 is_initialized=False> from ep 0 to ep 0, cluster 32770: b'w\x00\xf7\r\x02@\x80A\x11BB\x00\x00*B\x00\x00'
[0x0df7] Got 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=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, 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)
[0x0df7] Discovering endpoints
Tries remaining: 3
[0x0df7] Extending timeout for 0x79 request
light.hue_runner_spot_1_1: polling current state
[0x3808:11:0x0006] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=False, is_reply=0, disable_default_response=0, reserved=0, *is_cluster=False, *is_general=True), tsn=123, command_id=<GeneralCommand.Read_Attributes: 0>, *is_reply=False)
[0x3808:11:0x0006] Sending request: Read_Attributes(attribute_ids=[0])
Received frame on uninitialized device <Device model=None manuf=None nwk=0x0DF7 ieee=a4:c1:38:4d:82:df:a6:b0 is_initialized=False> from ep 0 to ep 0, cluster 32773: b'y\x00\xf7\r\x01\x01'
[0x0df7] Discovered endpoints: [1]
[0x0df7] Initializing endpoints [<Endpoint id=1 in=[] out=[] status=<Status.NEW: 0>>]
[0x0df7:1] Discovering endpoint information
Tries remaining: 3
[0x0df7] Extending timeout for 0x7d request
[0x3808:11:0x0006] Received ZCL frame: b'\x18{\x01\x00\x00\x00\x10\x00'
[0x3808:11:0x0006] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, is_reply=1, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True), tsn=123, command_id=1, *is_reply=True)
[0x3808:11:0x0006] Decoded ZCL frame: OnOff:Read_Attributes_rsp(status_records=[ReadAttributeRecord(attrid=0x0000, status=<Status.SUCCESS: 0>, value=TypeValue(type=Bool, value=<Bool.false: 0>))])
[0x3808:11:0x0008] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=False, is_reply=0, disable_default_response=0, reserved=0, *is_cluster=False, *is_general=True), tsn=127, command_id=<GeneralCommand.Read_Attributes: 0>, *is_reply=False)
[0x3808:11:0x0008] Sending request: Read_Attributes(attribute_ids=[0])
[0x3808:11:0x0008] Received ZCL frame: b'\x18\x7f\x01\x00\x00\x00 \xfe'
[0x3808:11:0x0008] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, is_reply=1, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True), tsn=127, command_id=1, *is_reply=True)
[0x3808:11:0x0008] Decoded ZCL frame: LevelControl:Read_Attributes_rsp(status_records=[ReadAttributeRecord(attrid=0x0000, status=<Status.SUCCESS: 0>, value=TypeValue(type=uint8_t, value=254))])
[0x3808:11:0x0008]: received attribute: 0 update with value: 254
[0x3808:11:0x0300] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=False, is_reply=0, disable_default_response=0, reserved=0, *is_cluster=False, *is_general=True), tsn=129, command_id=<GeneralCommand.Read_Attributes: 0>, *is_reply=False)
[0x3808:11:0x0300] Sending request: Read_Attributes(attribute_ids=[8, 7, 3, 4, 16386])
Received frame on uninitialized device <Device model=None manuf=None nwk=0x0DF7 ieee=a4:c1:38:4d:82:df:a6:b0 is_initialized=False> from ep 0 to ep 0, cluster 32772: b'}\x00\xf7\r\x12\x01\x04\x01\x02\x04\x01\x03\x01\x00\x00\x05\x00\x00\x02\x19\x00\n\x00'
[0x0df7:1] Discovered endpoint information: SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=1026, device_version=1, input_clusters=[1, 1280, 0], output_clusters=[25, 10])
[0x0DF7:1:0x0000] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=False, is_reply=0, disable_default_response=0, reserved=0, *is_cluster=False, *is_general=True), tsn=131, command_id=<GeneralCommand.Read_Attributes: 0>, *is_reply=False)
[0x0DF7:1:0x0000] Sending request: Read_Attributes(attribute_ids=[4, 5])
[0x0df7] Extending timeout for 0x83 request
[0x3808:11:0x0300] Received ZCL frame: b'\x18\x81\x01\x08\x00\x000\x02\x07\x00\x00!n\x01\x03\x00\x00!\x0fu\x04\x00\x00!\xf5h\x02@\x86'
[0x3808:11:0x0300] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, is_reply=1, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True), tsn=129, command_id=1, *is_reply=True)
[0x3808:11:0x0300] Decoded ZCL frame: Color:Read_Attributes_rsp(status_records=[ReadAttributeRecord(attrid=0x0008, status=<Status.SUCCESS: 0>, value=TypeValue(type=enum8, value=<enum8.undefined_0x02: 2>)), ReadAttributeRecord(attrid=0x0007, status=<Status.SUCCESS: 0>, value=TypeValue(type=uint16_t, value=366)), ReadAttributeRecord(attrid=0x0003, status=<Status.SUCCESS: 0>, value=TypeValue(type=uint16_t, value=29967)), ReadAttributeRecord(attrid=0x0004, status=<Status.SUCCESS: 0>, value=TypeValue(type=uint16_t, value=26869)), ReadAttributeRecord(attrid=0x4002, status=<Status.UNSUPPORTED_ATTRIBUTE: 134>)])
[0x0DF7:1:0x0000] Received ZCL frame: b'\x18\x83\x01\x04\x00\x00B\x10_TZE200_pay2byax\x05\x00\x00B\x06TS0601'
[0x0DF7:1:0x0000] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, is_reply=1, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True), tsn=131, command_id=1, *is_reply=True)
[0x0DF7:1:0x0000] Decoded ZCL frame: Basic:Read_Attributes_rsp(status_records=[ReadAttributeRecord(attrid=0x0004, status=<Status.SUCCESS: 0>, value=TypeValue(type=CharacterString, value='_TZE200_pay2byax')), ReadAttributeRecord(attrid=0x0005, status=<Status.SUCCESS: 0>, value=TypeValue(type=CharacterString, value='TS0601'))])
[0x0df7] Read model 'TS0601' and manufacturer '_TZE200_pay2byax' from <Endpoint id=1 in=[power:0x0001, ias_zone:0x0500, basic:0x0000] out=[ota:0x0019, time:0x000A] status=<Status.ZDO_INIT: 1>>
[0x0df7] Discovered basic device information for <Device model='TS0601' manuf='_TZE200_pay2byax' nwk=0x0DF7 ieee=a4:c1:38:4d:82:df:a6:b0 is_initialized=True>
Device is initialized <Device model='TS0601' manuf='_TZE200_pay2byax' nwk=0x0DF7 ieee=a4:c1:38:4d:82:df:a6:b0 is_initialized=True>
Checking quirks for _TZE200_pay2byax TS0601 (a4:c1:38:4d:82:df:a6:b0)
Considering <class 'zhaquirks.xbee.xbee_io.XBeeSensor'>
Fail because endpoint list mismatch: {232, 230} {1}
Considering <class 'zhaquirks.xbee.xbee3_io.XBee3Sensor'>
Fail because endpoint list mismatch: {232, 230} {1}
Considering <class 'zhaquirks.smartthings.tag_v4.SmartThingsTagV4'>
Fail because device_type mismatch on at least one endpoint
Considering <class 'zhaquirks.smartthings.multi.SmartthingsMultiPurposeSensor'>
Fail because input cluster mismatch on at least one endpoint
Considering <class 'zhaquirks.netvox.z308e3ed.Z308E3ED'>
Fail because input cluster mismatch on at least one endpoint
Considering <class 'zhaquirks.gledopto.soposhgu10.SoposhGU10'>
Fail because endpoint list mismatch: {11, 13} {1}
Considering <class 'bellows.zigbee.application.EZSPCoordinator'>
Fail because device_type mismatch on at least one endpoint
'binary_sensor' component -> 'IASZone' using ['ias_zone']
'sensor' component -> 'Battery' using ['power']
'sensor' component -> 'RSSISensor' using ['basic']
'sensor' component -> 'LQISensor' using ['basic']
device - 0x0DF7:a4:c1:38:4d:82:df:a6:b0 entering async_device_initialized - is_new_join: True
device - 0x0DF7:a4:c1:38:4d:82:df:a6:b0 has joined the ZHA zigbee network
[0x0DF7](TS0601): started configuration
[0x0DF7:ZDO](TS0601): 'async_configure' stage succeeded
[0x0DF7:1:0x0500] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=False, is_reply=0, disable_default_response=0, reserved=0, *is_cluster=False, *is_general=True), tsn=133, command_id=<GeneralCommand.Read_Attributes: 0>, *is_reply=False)
[0x0DF7:1:0x0500] Sending request: Read_Attributes(attribute_ids=[1])
[0x0df7] Extending timeout for 0x85 request
[0x0DF7:1:0x0000]: finished channel configuration
[0x0df7] Extending timeout for 0x87 request
[0x0DF7:1:0x0019]: finished channel configuration
Error handling '_save_attribute' event with (a4:c1:38:4d:82:df:a6:b0, 1, 0, 4, '_TZE200_pay2byax') params: FOREIGN KEY constraint failed
Error handling '_save_attribute' event with (a4:c1:38:4d:82:df:a6:b0, 1, 0, 5, 'TS0601') params: FOREIGN KEY constraint failed
Ignoring message (b'09940200020101000101') on cluster 61184: unknown endpoint or cluster id: 'No cluster ID 0xef00 on (a4:c1:38:4d:82:df:a6:b0, 1)'
[0x0DF7:1:0x0500] Received ZCL frame: b'\x18\x85\x01\x01\x00\x001(\x00'
[0x0DF7:1:0x0500] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, is_reply=1, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True), tsn=133, command_id=1, *is_reply=True)
[0x0DF7:1:0x0500] Decoded ZCL frame: IasZone:Read_Attributes_rsp(status_records=[ReadAttributeRecord(attrid=0x0001, status=<Status.SUCCESS: 0>, value=TypeValue(type=enum16, value=<enum16.undefined_0x0028: 40>))])
[0x0DF7:1:0x0500]: started IASZoneChannel configuration
[0x0df7] Extending timeout for 0x89 request
[0x0DF7:1:0x0001]: bound 'power' cluster: Status.SUCCESS
[0x0DF7:1:0x0001] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=False, is_reply=0, disable_default_response=0, reserved=0, *is_cluster=False, *is_general=True), tsn=139, command_id=<GeneralCommand.Configure_Reporting: 6>, *is_reply=False)
[0x0DF7:1:0x0001] Sending request: Configure_Reporting(config_records=[AttributeReportingConfig(direction=0, attrid=0x0020, datatype=32, min_interval=3600, max_interval=10800, reportable_change=1), AttributeReportingConfig(direction=0, attrid=0x0021, datatype=32, min_interval=3600, max_interval=10800, reportable_change=1)])
[0x0df7] Extending timeout for 0x8b request
Ignoring message (b'09940200020101000101') on cluster 61184: unknown endpoint or cluster id: 'No cluster ID 0xef00 on (a4:c1:38:4d:82:df:a6:b0, 1)'
[0x0DF7:1:0x0500]: bound 'ias_zone' cluster: Status.SUCCESS
[0x0DF7:1:0x0500] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=False, is_reply=0, disable_default_response=0, reserved=0, *is_cluster=False, *is_general=True), tsn=141, command_id=<GeneralCommand.Write_Attributes: 2>, *is_reply=False)
[0x0DF7:1:0x0500] Sending request: Write_Attributes(attributes=[Attribute(attrid=0x0010, value=TypeValue(type=EUI64, value=00:21:2e:ff:ff:07:79:3e))])
[0x0df7] Extending timeout for 0x8d request
Ignoring message (b'09940200020101000101') on cluster 61184: unknown endpoint or cluster id: 'No cluster ID 0xef00 on (a4:c1:38:4d:82:df:a6:b0, 1)'
[0x0DF7:1:0x0001] Received ZCL frame: b'\x18\x8b\x07\x00\x00 \x00\x00\x00!\x00'
[0x0DF7:1:0x0001] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, is_reply=1, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True), tsn=139, command_id=7, *is_reply=True)
[0x0DF7:1:0x0001] Decoded ZCL frame: PowerConfiguration:Configure_Reporting_rsp(status_records=[ConfigureReportingResponseRecord(status=0), ConfigureReportingResponseRecord(status=0)])
[0x0DF7:1:0x0001]: Successfully configured reporting for '{'battery_voltage', 'battery_percentage_remaining'}' on 'power' cluster
[0x0DF7:1:0x0001]: Failed to configure reporting for '[]' on 'power' cluster: [ConfigureReportingResponseRecord(status=0), ConfigureReportingResponseRecord(status=0)]
[0x0DF7:1:0x0001]: finished channel configuration
[0x0DF7:1:0x0500] Received ZCL frame: b'\x18\x8d\x04\x00'
[0x0DF7:1:0x0500] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, is_reply=1, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True), tsn=141, command_id=4, *is_reply=True)
[0x0DF7:1:0x0500] Decoded ZCL frame: IasZone:Write_Attributes_rsp(status_records=[WriteAttributesStatusRecord(status=<Status.SUCCESS: 0>)])
[0x0DF7:1:0x0500]: wrote cie_addr: 00:21:2e:ff:ff:07:79:3e to 'ias_zone' cluster: [WriteAttributesStatusRecord(status=<Status.SUCCESS: 0>)]
[0x0DF7:1:0x0500]: Sending pro-active IAS enroll response
[0x0DF7:1:0x0500] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=False, is_reply=0, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False), tsn=143, command_id=0, *is_reply=False)
[0x0DF7:1:0x0500] Sending request: enroll_response(enroll_response_code=<EnrollResponse.Success: 0>, zone_id=0)
[0x0DF7:1:0x0500]: finished IASZoneChannel configuration
[0x0df7] Extending timeout for 0x8f request
[0x0DF7:1:0x0500]: 'async_configure' stage succeeded
[0x0DF7:1:0x0000]: 'async_configure' stage succeeded
[0x0DF7:1:0x0001]: 'async_configure' stage succeeded
[0x0DF7:1:0x0019]: 'async_configure' stage succeeded
[0x0DF7](TS0601): completed configuration
[0x0DF7](TS0601): stored in registry: ZhaDeviceEntry(name='_TZE200_pay2byax TS0601', ieee='a4:c1:38:4d:82:df:a6:b0', last_seen=1650114287.8170516)
[0x0DF7](TS0601): started initialization
[0x0DF7:ZDO](TS0601): 'async_initialize' stage succeeded
[0x0DF7:1:0x0500]: initializing channel: from_cache: False
[0x0DF7:1:0x0500] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=False, is_reply=0, disable_default_response=0, reserved=0, *is_cluster=False, *is_general=True), tsn=145, command_id=<GeneralCommand.Read_Attributes: 0>, *is_reply=False)
[0x0DF7:1:0x0500] Sending request: Read_Attributes(attribute_ids=[0])
[0x0df7] Extending timeout for 0x91 request
[0x0DF7:1:0x0000]: initializing channel: from_cache: False
[0x0DF7:1:0x0000]: finished channel initialization
[0x0DF7:1:0x0001]: initializing channel: from_cache: False
[0x0DF7:1:0x0001] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=False, is_reply=0, disable_default_response=0, reserved=0, *is_cluster=False, *is_general=True), tsn=147, command_id=<GeneralCommand.Read_Attributes: 0>, *is_reply=False)
[0x0DF7:1:0x0001] Sending request: Read_Attributes(attribute_ids=[32, 33])
[0x0df7] Extending timeout for 0x93 request
[0x0DF7:1:0x0019]: initializing channel: from_cache: False
[0x0DF7:1:0x0019]: finished channel initialization
[0x0DF7:1:0x0500] Received ZCL frame: b'\x18\x8f\x0b\x00\x00'
[0x0DF7:1:0x0500] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, is_reply=1, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True), tsn=143, command_id=11, *is_reply=True)
[0x0DF7:1:0x0500] Decoded ZCL frame: IasZone:Default_Response(command_id=0, status=<Status.SUCCESS: 0>)
[0x0DF7:1:0x0500] Received ZCL frame: b'\x18\x91\x01\x00\x00\x000\x00'
[0x0DF7:1:0x0500] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, is_reply=1, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True), tsn=145, command_id=1, *is_reply=True)
[0x0DF7:1:0x0500] Decoded ZCL frame: IasZone:Read_Attributes_rsp(status_records=[ReadAttributeRecord(attrid=0x0000, status=<Status.SUCCESS: 0>, value=TypeValue(type=enum8, value=<enum8.undefined_0x00: 0>))])
[0x0DF7:1:0x0500]: finished channel initialization
[0x0DF7:1:0x0001] Received ZCL frame: b'\x18\x93\x01 \x00\x00 \x00!\x00\x00 \x00'
[0x0DF7:1:0x0001] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, is_reply=1, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True), tsn=147, command_id=1, *is_reply=True)
[0x0DF7:1:0x0001] Decoded ZCL frame: PowerConfiguration:Read_Attributes_rsp(status_records=[ReadAttributeRecord(attrid=0x0020, status=<Status.SUCCESS: 0>, value=TypeValue(type=uint8_t, value=0)), ReadAttributeRecord(attrid=0x0021, status=<Status.SUCCESS: 0>, value=TypeValue(type=uint8_t, value=0))])
[0x0DF7:1:0x0001] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=False, is_reply=0, disable_default_response=0, reserved=0, *is_cluster=False, *is_general=True), tsn=149, command_id=<GeneralCommand.Read_Attributes: 0>, *is_reply=False)
[0x0DF7:1:0x0001] Sending request: Read_Attributes(attribute_ids=[49, 51])
[0x0df7] Extending timeout for 0x95 request
[0x0DF7:1:0x000a] Received ZCL frame: b'\x00\x95\x00\x07\x00'
[0x0DF7:1:0x000a] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, is_reply=0, disable_default_response=0, reserved=0, *is_cluster=False, *is_general=True), tsn=149, command_id=0, *is_reply=False)
[0x0DF7:1:0x000a] Decoded ZCL frame: Time:Read_Attributes(attribute_ids=[7])
[0x0DF7:1:0x000a] Received command 0x00 (TSN 149): Read_Attributes(attribute_ids=[7])
[0x0DF7:1:0x000a] Sending reply header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=False, is_reply=1, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True), tsn=149, command_id=<GeneralCommand.Read_Attributes_rsp: 1>, *is_reply=True)
[0x0DF7:1:0x000a] Sending reply: Read_Attributes_rsp(status_records=[ReadAttributeRecord(attrid=0x0007, status=<Status.SUCCESS: 0>, value=TypeValue(type=LocalTime, value=703436690))])
Duplicate 149 TSN
[0x0DF7:1:0x0001] Received ZCL frame: b'\x18\x95\x011\x00\x863\x00\x86'
[0x0DF7:1:0x0001] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, is_reply=1, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True), tsn=149, command_id=1, *is_reply=True)
[0x0DF7:1:0x0001] Decoded ZCL frame: PowerConfiguration:Read_Attributes_rsp(status_records=[ReadAttributeRecord(attrid=0x0031, status=<Status.UNSUPPORTED_ATTRIBUTE: 134>), ReadAttributeRecord(attrid=0x0033, status=<Status.UNSUPPORTED_ATTRIBUTE: 134>)])
[0x0DF7:1:0x0001]: finished channel initialization
[0x0DF7:1:0x0500]: 'async_initialize' stage succeeded
[0x0DF7:1:0x0000]: 'async_initialize' stage succeeded
[0x0DF7:1:0x0001]: 'async_initialize' stage succeeded
[0x0DF7:1:0x0019]: 'async_initialize' stage succeeded
[0x0DF7](TS0601): power source: Battery or Unknown
[0x0DF7](TS0601): completed initialization
[0x0DF7:1:0x000a] Received ZCL frame: b'\x00\x95\x00\x07\x00'
[0x0DF7:1:0x000a] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, is_reply=0, disable_default_response=0, reserved=0, *is_cluster=False, *is_general=True), tsn=149, command_id=0, *is_reply=False)
[0x0DF7:1:0x000a] Decoded ZCL frame: Time:Read_Attributes(attribute_ids=[7])
[0x0DF7:1:0x000a] Received command 0x00 (TSN 149): Read_Attributes(attribute_ids=[7])
[0x0DF7:1:0x000a] Sending reply header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=False, is_reply=1, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True), tsn=149, command_id=<GeneralCommand.Read_Attributes_rsp: 1>, *is_reply=True)
[0x0DF7:1:0x000a] Sending reply: Read_Attributes_rsp(status_records=[ReadAttributeRecord(attrid=0x0007, status=<Status.SUCCESS: 0>, value=TypeValue(type=LocalTime, value=703436691))])
Ignoring message (b'09960200020101000101') on cluster 61184: unknown endpoint or cluster id: 'No cluster ID 0xef00 on (a4:c1:38:4d:82:df:a6:b0, 1)'
Ignoring message (b'09960200020101000101') on cluster 61184: unknown endpoint or cluster id: 'No cluster ID 0xef00 on (a4:c1:38:4d:82:df:a6:b0, 1)'
Ignoring message (b'09960200020101000101') on cluster 61184: unknown endpoint or cluster id: 'No cluster ID 0xef00 on (a4:c1:38:4d:82:df:a6:b0, 1)'
[0x3808:11:0x0300] Received ZCL frame: b'\x18y\n\x04\x00!\xf5h\x03\x00!\x0fu\x07\x00!n\x01'
[0x3808:11:0x0300] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, is_reply=1, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True), tsn=121, command_id=10, *is_reply=True)
[0x3808:11:0x0300] Decoded ZCL frame: Color:Report_Attributes(attribute_reports=[Attribute(attrid=0x0004, value=TypeValue(type=uint16_t, value=26869)), Attribute(attrid=0x0003, value=TypeValue(type=uint16_t, value=29967)), Attribute(attrid=0x0007, value=TypeValue(type=uint16_t, value=366))])
[0x3808:11:0x0300] Received command 0x0A (TSN 121): Report_Attributes(attribute_reports=[Attribute(attrid=0x0004, value=TypeValue(type=uint16_t, value=26869)), Attribute(attrid=0x0003, value=TypeValue(type=uint16_t, value=29967)), Attribute(attrid=0x0007, value=TypeValue(type=uint16_t, value=366))])
[0x3808:11:0x0300] Attribute report received: current_y=26869, current_x=29967, color_temperature=366
Ignoring message (b'09970200020101000101') on cluster 61184: unknown endpoint or cluster id: 'No cluster ID 0xef00 on (a4:c1:38:4d:82:df:a6:b0, 1)'
Ignoring message (b'09970200020101000101') on cluster 61184: unknown endpoint or cluster id: 'No cluster ID 0xef00 on (a4:c1:38:4d:82:df:a6:b0, 1)'
Ignoring message (b'09970200020101000101') on cluster 61184: unknown endpoint or cluster id: 'No cluster ID 0xef00 on (a4:c1:38:4d:82:df:a6:b0, 1)'
Ignoring message (b'09980200090202000400000064') on cluster 61184: unknown endpoint or cluster id: 'No cluster ID 0xef00 on (a4:c1:38:4d:82:df:a6:b0, 1)'
Ignoring message (b'09980200090202000400000064') on cluster 61184: unknown endpoint or cluster id: 'No cluster ID 0xef00 on (a4:c1:38:4d:82:df:a6:b0, 1)'
Ignoring message (b'09980200090202000400000064') on cluster 61184: unknown endpoint or cluster id: 'No cluster ID 0xef00 on (a4:c1:38:4d:82:df:a6:b0, 1)'

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

javicalle commented 1 year ago

Can you try with this formula?

converter=lambda x: 10000 * math.log10(x + 1)
domusonline commented 1 year ago

Can you try with this formula?

converter=lambda x: 10000 * math.log10(x + 1)

Sorry... I should have updated the thread, but I finished this yesterday too late... I managed to solve it/workaround it by using this (I got it from another issue): converter=lambda x: (10000.0 * math.log10(x) + 1.0 if x != 0 else 0),

not sure which one would be better. The problem is that in fact the sensor returns 0 in dark conditions. And math.log10(0) raises an error. So I'm sure your suggestion would work. Which one would be better? I was doing some tests and apparently the range of values I get are not between 1-1000 (max I've seen was 960).

Thank you!

domusonline commented 1 year ago

I was doing some tests and apparently the range of values I get are not between 1-1000 (max I've seen was 960).

Thank you!

Sorry... (again). I meant that the values I get ARE between 1-1000 which sound reasonable...

javicalle commented 1 year ago

I was doing some tests and apparently the range of values I get are not between 1-1000 (max I've seen was 960). Thank you!

Sorry... (again). I meant that the values I get ARE between 1-1000 which sound reasonable...

But you are getting 0 values, if not this wouldn't be needed:

if x != 0 else 0
domusonline commented 1 year ago

I was doing some tests and apparently the range of values I get are not between 1-1000 (max I've seen was 960). Thank you!

Sorry... (again). I meant that the values I get ARE between 1-1000 which sound reasonable...

But you are getting 0 values, if not this wouldn't be needed:

if x != 0 else 0

I'm not making myself clear... what I intended to say was that yes, the "x" receives 0 (I assume this is the value returned by the sensor). And math.log10(0) raises an error. But with the formula:

converter=lambda x: (10000.0 * math.log10(x) + 1.0 if x != 0 else 0),

what I get in HA when I check the entity are values between 1 and ~1000 (if I point a mobile phone flash light I get for example 960 or 980). And it responds to different light conditions with values somewhere inside this range. I was wondering which formula you would think it would be better (I'd say they would give ver similar values) and also if you think this range of values is reasonable.

Thanks for your support.

javicalle commented 1 year ago

also if you think this range of values is reasonable

I can't say it because these are not familiar to me. I'm sure that both formulas would give a similar values/behavior. But the one I suggest wouldn't give negative values for illumination when 0<x<1 🤷🏻‍♂️

Anyone can create the PR with the proposed quirk and I'm sure that would be accepted as is.

GillesMattioli commented 1 year ago

https://github.com/zigpy/zha-device-handlers/issues/1502#issuecomment-1378743535 Cette solution fonctionne avec un _TZE200_pay2byax Merci de votre travail

MattWestb commented 1 year ago

https://github.com/zigpy/zha-device-handlers/issues/1502#issuecomment-1378743535 This solution works with a _TZE200_pay2byax Thank you for your work

antoweb commented 1 year ago

Hello, after last update HA to 2023.3 this quirks generate error and all Zigbee Integration cannot load. i have to remove from custom_zha_quirks any solution?

domusonline commented 1 year ago

Hello, after last update HA to 2023.3 this quirks generate error and all Zigbee Integration cannot load. i have to remove from custom_zha_quirks any solution?

I had issues with the quirk also and then some errors in some automations based on Zigbee buttons. I didn't try to remove the quirk to understand if the other issues were related.... I just restored the backup... meanwhile I see version 2023.3.1 but HA insists that the latest one is 2023.3.0.... I'll get back to this when 3.1 is possible to install... The error complains about an import of some Tuya classes....

antoweb commented 1 year ago

Solution is

https://github.com/zigpy/zha-device-handlers/issues/2241#issuecomment-1452487362

zmc commented 1 year ago

I cleaned up some of the examples above and made sure to include illuminance. Battery percentage is still always 0%, though.

This works for me with HA 2023.3.1. ``` """Tuya contact sensor device.""" import math from typing import Dict from zigpy.profiles import zha from zigpy.quirks import CustomDevice from zigpy.zcl.clusters.general import Basic, Ota, PowerConfiguration, Time from zigpy.zcl.clusters.measurement import IlluminanceMeasurement from zigpy.zcl.clusters.security import IasZone from zhaquirks import DoublingPowerConfigurationCluster from zhaquirks.const import ( DEVICE_TYPE, ENDPOINTS, INPUT_CLUSTERS, MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, ZONE_TYPE, ) from zhaquirks.tuya import TuyaLocalCluster from zhaquirks.tuya.mcu import ( DPToAttributeMapping, TuyaMCUCluster, ) IASZONE_ZONE_STATUS_ATTR = 0x0002 class ContactSwitchCluster(TuyaLocalCluster, IasZone): """Tuya ContactSwitch Sensor.""" _CONSTANT_ATTRIBUTES = {ZONE_TYPE: IasZone.ZoneType.Contact_Switch} def _update_attribute(self, attrid, value): self.debug("_update_attribute '%s': %s", attrid, value) super()._update_attribute(attrid, value) class TuyaIlluminanceMeasurement(IlluminanceMeasurement, TuyaLocalCluster): """Tuya local IlluminanceMeasurement cluster.""" class ContactSwitchManufCluster(TuyaMCUCluster): """Tuya Manufacturer Cluster with ContactSwitch Sensor data points.""" dp_to_attribute: Dict[int, DPToAttributeMapping] = { 1: DPToAttributeMapping( ContactSwitchCluster.ep_attribute, "zone_status", converter=lambda x: IasZone.ZoneStatus.Alarm_1 if x else 0, ), 2: DPToAttributeMapping( DoublingPowerConfigurationCluster.ep_attribute, "battery_percentage_remaining", # 0x0021 ), 101: DPToAttributeMapping( TuyaIlluminanceMeasurement.ep_attribute, "measured_value", converter=lambda x: 10000.0 * math.log10(x + 1.0), ), } data_point_handlers = { 1: "_dp_2_attr_update", 2: "_dp_2_attr_update", 101: "_dp_2_attr_update", } class TuyaContactSensor(CustomDevice): """Tuya contact sensor device.""" signature = { # NodeDescriptor(logical_type=, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=, mac_capability_flags=, manufacturer_code=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, 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)] # device_version=1 # SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=1026, device_version=1, # input_clusters=[0, 1, 1280], # output_clusters=[10, 25]) MODELS_INFO: [("_TZE200_pay2byax", "TS0601")], ENDPOINTS: { 1: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.IAS_ZONE, INPUT_CLUSTERS: [ Basic.cluster_id, PowerConfiguration.cluster_id, IasZone.cluster_id, ], OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id], } }, } replacement = { ENDPOINTS: { 1: { INPUT_CLUSTERS: [ Basic.cluster_id, DoublingPowerConfigurationCluster, ContactSwitchCluster, ContactSwitchManufCluster, TuyaIlluminanceMeasurement, ], OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id], } } } ```
javicalle commented 1 year ago

Check the logs for any No 'handle_set_data_response' tuya handler found... error. Battery can get some time to report. You can enable the debug logs and trigger the contact sensor (open/close) to see what is reporting.

antoweb commented 1 year ago

Hello where i can download the definitve editions of this quirk?

GillesMattioli commented 1 year ago

Bonjour, où puis-je télécharger les éditions définitives de cette bizarrerie ?

il faut corriger comme ceci , en tous cas pour moi ca fonctionne ! https://github.com/zigpy/zha-device-handlers/issues/2241#issuecomment-1453079929

elmystico commented 1 year ago

Guys I don't have battery readout with this quirk. I've recklessly replaced DoublingPowerConfigurationCluster with TuyaPowerConfigurationCluster in the code of this quirk and now I'm having 100% but no idea if this is correct (of course if % changes I'll report back.

schnudeldudel commented 11 months ago

Guys I don't have battery readout with this quirk. I've recklessly replaced DoublingPowerConfigurationCluster with TuyaPowerConfigurationCluster in the code of this quirk and now I'm having 100% but no idea if this is correct (of course if % changes I'll report back.

@elmystico any update on your battery reading modification ? thanks.

elmystico commented 11 months ago

@elmystico any update on your battery reading modification ? thanks. @schnudeldudel Unfortunately I had a crash in HA recently so i removed all additional code, historical data got lost, no idea if % changed

basdelouw78 commented 9 months ago

Still not getting it to work.

{ "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=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, 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": "0x0104", "device_type": "0x0402", "input_clusters": [ "0x0000", "0x0001", "0x0003", "0x0400", "0x0500", "0xe002", "0xef00" ], "output_clusters": [] } }, "manufacturer": "_TZE200_pay2byax", "model": "TS0601", "class": "zigpy.device.Device" }

It dont update at all. I've try all the custom quirk's in this topic but no working device.

elmystico commented 9 months ago

@schnudeldudel hello again. i've got this back and running. Battery state uncofirmed unfortunatelly. I can tell that it gets reported 100% but no change. Contact switch and luminance works flawlessly thou. Heres the quirk

"""Tuya contact sensor device."""

import math

from typing import Dict

from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
from zigpy.zcl.clusters.general import Basic, Groups, Ota, PowerConfiguration, Time
from zigpy.zcl.clusters.measurement import IlluminanceMeasurement
from zigpy.zcl.clusters.security import IasZone

#from zhaquirks import DoublingPowerConfigurationCluster

from zhaquirks.const import (
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
    ZONE_TYPE,
)
from zhaquirks.tuya import TuyaLocalCluster
from zhaquirks.tuya.mcu import (
    DPToAttributeMapping,
    TuyaMCUCluster,
    TuyaPowerConfigurationCluster,
)

IASZONE_ZONE_STATUS_ATTR = 0x0002

class ContactSwitchCluster(TuyaLocalCluster, IasZone):
    """Tuya ContactSwitch Sensor."""

    _CONSTANT_ATTRIBUTES = {ZONE_TYPE: IasZone.ZoneType.Contact_Switch}

    def _update_attribute(self, attrid, value):
        self.debug("_update_attribute '%s': %s", attrid, value)
        super()._update_attribute(attrid, value)

class TuyaIlluminanceMeasurement(IlluminanceMeasurement, TuyaLocalCluster):
    """Tuya local IlluminanceMeasurement cluster."""

class ContactSwitchManufCluster(TuyaMCUCluster):
    """Tuya Manufacturer Cluster with ContactSwitch Sensor data points."""

    dp_to_attribute: Dict[int, DPToAttributeMapping] = {
        1: DPToAttributeMapping(
            ContactSwitchCluster.ep_attribute,
            "zone_status",
            converter=lambda x: IasZone.ZoneStatus.Alarm_1 if x else 0,
        ),
        2: DPToAttributeMapping(
            TuyaPowerConfigurationCluster.ep_attribute,
            "battery_percentage_remaining",  # 0x0021
        ),
        101: DPToAttributeMapping(
            TuyaIlluminanceMeasurement.ep_attribute,
            "measured_value",
            #converter=lambda x: 10000.0 * math.log10(x + 1.0),
            converter=lambda x: (10000.0 * math.log10(x) + 1.0 if x != 0 else 0),

        ),
    }

    data_point_handlers = {
        1: "_dp_2_attr_update",
        2: "_dp_2_attr_update",
        101: "_dp_2_attr_update",
    }

class TuyaContactSensor(CustomDevice):
    """Tuya contact sensor device."""

    signature = {
        # 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=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, 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)]
        # device_version=1
        # SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=1026, device_version=1,
        # input_clusters=[0, 1, 1280],
        # output_clusters=[10, 25])
        MODELS_INFO: [("_TZE200_pay2byax", "TS0601")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.IAS_ZONE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    PowerConfiguration.cluster_id,
                    IasZone.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            }
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
#                    DoublingPowerConfigurationCluster,
                    TuyaPowerConfigurationCluster,
                    ContactSwitchCluster,
                    ContactSwitchManufCluster,
                    TuyaIlluminanceMeasurement,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            }
        }
    }
elmystico commented 8 months ago

@schnudeldudel battery indicator started to change but this is just 100/500% values only. Something is not right Zrzut ekranu (189)

antoweb commented 8 months ago

@schnudeldudel hello again. i've got this back and running. Battery state uncofirmed unfortunatelly. I can tell that it gets reported 100% but no change. Contact switch and luminance works flawlessly thou. Heres the quirk

"""Tuya contact sensor device."""

import math

from typing import Dict

from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
from zigpy.zcl.clusters.general import Basic, Groups, Ota, PowerConfiguration, Time
from zigpy.zcl.clusters.measurement import IlluminanceMeasurement
from zigpy.zcl.clusters.security import IasZone

#from zhaquirks import DoublingPowerConfigurationCluster

from zhaquirks.const import (
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
    ZONE_TYPE,
)
from zhaquirks.tuya import TuyaLocalCluster
from zhaquirks.tuya.mcu import (
    DPToAttributeMapping,
    TuyaMCUCluster,
    TuyaPowerConfigurationCluster,
)

IASZONE_ZONE_STATUS_ATTR = 0x0002

class ContactSwitchCluster(TuyaLocalCluster, IasZone):
    """Tuya ContactSwitch Sensor."""

    _CONSTANT_ATTRIBUTES = {ZONE_TYPE: IasZone.ZoneType.Contact_Switch}

    def _update_attribute(self, attrid, value):
        self.debug("_update_attribute '%s': %s", attrid, value)
        super()._update_attribute(attrid, value)

class TuyaIlluminanceMeasurement(IlluminanceMeasurement, TuyaLocalCluster):
    """Tuya local IlluminanceMeasurement cluster."""

class ContactSwitchManufCluster(TuyaMCUCluster):
    """Tuya Manufacturer Cluster with ContactSwitch Sensor data points."""

    dp_to_attribute: Dict[int, DPToAttributeMapping] = {
        1: DPToAttributeMapping(
            ContactSwitchCluster.ep_attribute,
            "zone_status",
            converter=lambda x: IasZone.ZoneStatus.Alarm_1 if x else 0,
        ),
        2: DPToAttributeMapping(
            TuyaPowerConfigurationCluster.ep_attribute,
            "battery_percentage_remaining",  # 0x0021
        ),
        101: DPToAttributeMapping(
            TuyaIlluminanceMeasurement.ep_attribute,
            "measured_value",
            #converter=lambda x: 10000.0 * math.log10(x + 1.0),
            converter=lambda x: (10000.0 * math.log10(x) + 1.0 if x != 0 else 0),

        ),
    }

    data_point_handlers = {
        1: "_dp_2_attr_update",
        2: "_dp_2_attr_update",
        101: "_dp_2_attr_update",
    }

class TuyaContactSensor(CustomDevice):
    """Tuya contact sensor device."""

    signature = {
        # 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=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, 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)]
        # device_version=1
        # SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=1026, device_version=1,
        # input_clusters=[0, 1, 1280],
        # output_clusters=[10, 25])
        MODELS_INFO: [("_TZE200_pay2byax", "TS0601")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.IAS_ZONE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    PowerConfiguration.cluster_id,
                    IasZone.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            }
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
#                    DoublingPowerConfigurationCluster,
                    TuyaPowerConfigurationCluster,
                    ContactSwitchCluster,
                    ContactSwitchManufCluster,
                    TuyaIlluminanceMeasurement,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            }
        }
    }

Hello with this quirks battery working for me

bluezclouds commented 3 months ago

This quirk works perfectly with a TZE200_fwoorn8y TS0601 door and window sensor.