zha-device-handlers icon indicating copy to clipboard operation
zha-device-handlers copied to clipboard

[Device Support Request] TS0601 GDC311ZBQ1 Tuya Loratap Garage Switcher

Open tiagoqpinto opened this issue 2 years ago • 196 comments

Device signature:

{
  "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress|RxOnWhenIdle|MainsPowered|FullFunctionDevice: 142>, 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=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)",
  "endpoints": {
    "1": {
      "profile_id": 260,
      "device_type": "0x0051",
      "in_clusters": [
        "0x0000",
        "0x0004",
        "0x0005",
        "0xef00"
      ],
      "out_clusters": [
        "0x000a",
        "0x0019"
      ]
    },
    "242": {
      "profile_id": 41440,
      "device_type": "0x0061",
      "in_clusters": [],
      "out_clusters": [
        "0x0021"
      ]
    }
  },
  "manufacturer": "_TZE200_wfxuhoea",
  "model": "TS0601",
  "class": "zigpy.device.Device"
}

Tuya device that has no entities/controls in home assistant and its a simple Zigbee Tuya garage switcher. It has a sensor if the garage is opened or not, but it should be very similar to many other devices like this.

Thanks in advance for the support.

tiagoqpinto avatar Jan 06 '22 21:01 tiagoqpinto

I have one of these as well, happy to help anyone who is able to help integrate it in to zha, I’m not a developer but happy to help in any way I can!

EagleAdam avatar Jan 10 '22 19:01 EagleAdam

Hi! We are together in pain... Someone who have one of these working fine could help to integrate it in to ZHA?

cfnascimento avatar Jan 19 '22 12:01 cfnascimento

Device operation traces are needed to see if it is possible to implement a quirk. Each trace must be able to be identified with the action, eg: open, close, stop, etc.

If any of you can include the information, I'll see what can be done.

Regards.

javicalle avatar Jan 21 '22 20:01 javicalle

As this is a garage door opener, it doesn't send any messages until a command to open the door is received - it primarily receives messages. How can we capture traces if we can't send it messages?

Get Outlook for Androidhttps://aka.ms/AAb9ysg


From: javicalle @.> Sent: Friday, January 21, 2022 9:29:04 PM To: zigpy/zha-device-handlers @.> Cc: EagleAdam @.>; Comment @.> Subject: Re: [zigpy/zha-device-handlers] [Device Support Request] TS0601 GDC311ZBQ1 Tuya Loratap Garage Switcher (Issue #1260)

Device operation traces are needed to see if it is possible to implement a quirk. Each trace must be able to be identified with the action, eg: open, close, stop, etc.

If any of you can include the information, I'll see what can be done.

Regards.

— Reply to this email directly, view it on GitHubhttps://github.com/zigpy/zha-device-handlers/issues/1260#issuecomment-1018836322, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AKTGLWAZPYRKDBMAIDTC5ILUXG6ZBANCNFSM5LNIU7LQ. Triage notifications on the go with GitHub Mobile for iOShttps://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Androidhttps://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub. You are receiving this because you commented.Message ID: @.***>

EagleAdam avatar Jan 22 '22 03:01 EagleAdam

Its have 3 function and i think its sending all of them the repower the device. https://github.com/Koenkk/zigbee-herdsman-converters/pull/3714/files You can trying "signal cable" and see if its sending that the door closed then closing the contact.

MattWestb avatar Jan 22 '22 08:01 MattWestb

In the herdsman-converter seems that the door status is not reported. The most similar device doc that I have found it's the 'curtain switch'. Maybe the status report will be the same:

  • https://developer.tuya.com/en/docs/iot-device-dev/zigbee-curtain-switch-access-standard?id=K9ik6zvra3twv#title-12-Report%20the%20open%2C%20close%2C%20and%20stop%20status

javicalle avatar Jan 22 '22 12:01 javicalle

Its not so easy saying than the device is working like one switch (its parallel with the normal installed) and can only detecting the door is closed or not closed. Bets is getting all DPs its using by having it pared in ZHA and taking the power away and reconnecting it and it shall sending al DPs is using (its still tuya).

MattWestb avatar Jan 22 '22 12:01 MattWestb

In case someone wants to try it, it seems that it has already been included as an on/off switch:

  • https://github.com/zigpy/zha-device-handlers/pull/1281/files

javicalle avatar Jan 26 '22 18:01 javicalle

There is a similar device: _TZE200_nklqjk62 "MOES Garage opener" ( supported by zigbee2mqtt) difference is that door sensor is wired instead of using RF.

Have anyone tried the changed pointed by @javicalle ?

Update: I tried changing that file locally adding my device id '_TZE200_nklqjk62' but it does not work.

juanjoSanz avatar Feb 13 '22 18:02 juanjoSanz

Without logs from device operation, nothing can be done.

Enable logs and attach the relevant information:

  zigpy: debug
  zigpy.zcl: debug
  custom_zha_quirks: debug
  zhaquirks.tuya: debug
  homeassistant.components.zha: debug

javicalle avatar Feb 13 '22 20:02 javicalle

Zigbee device signature might be useful:

{
  "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress|RxOnWhenIdle|MainsPowered|FullFunctionDevice: 142>, 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=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)",
  "endpoints": {
    "1": {
      "profile_id": 260,
      "device_type": "0x0051",
      "in_clusters": [
        "0x0000",
        "0x0004",
        "0x0005",
        "0xef00"
      ],
      "out_clusters": [
        "0x000a",
        "0x0019"
      ]
    },
    "242": {
      "profile_id": 41440,
      "device_type": "0x0061",
      "in_clusters": [],
      "out_clusters": [
        "0x0021"
      ]
    }
  },
  "manufacturer": "_TZE200_nklqjk62",
  "model": "TS0601",
  "class": "zigpy.device.Device"
}

juanjoSanz avatar Feb 14 '22 19:02 juanjoSanz

@juanjoSanz Your device is having one GPP end point so you need making one new device class and adding the GPP endpoint and your device IDs.

MattWestb avatar Feb 14 '22 20:02 MattWestb

@juanjoSanz Your device is having one GPP end point so you need making one new device class and adding the GPP endpoint and your device IDs.

Thanks for the advice, I have been trying to define my own class: https://raw.githubusercontent.com/juanjoSanz/zha-device-handlers/dev/zhaquirks/tuya/ts0601_switch_door.py

With my class the switch control is exposed, I have to figure out how to get the door sensor too.

juanjoSanz avatar Feb 14 '22 21:02 juanjoSanz

Hi! What should I do to make it work in Zigbee2MQTT?

cfnascimento avatar Feb 15 '22 02:02 cfnascimento

It was interviewed and recognized (unsupported), but doesn't exposes none of it's entities...

Smart Home ZigBee Garage Door Opener (GDC311ZBQ1) por Loratap

Zigbee2MQTT:debug 2022-02-14 23:43:07: Received Zigbee message from 'Garage door', type 'attributeReport', cluster 'genBasic', data '{"65506":48,"65508":0,"appVersion":68}' from endpoint 1 with groupID 0 Zigbee2MQTT:warn 2022-02-14 23:43:07: Received message from unsupported device with Zigbee model 'TS0601' and manufacturer name '_TZE200_wfxuhoea' Zigbee2MQTT:warn 2022-02-14 23:43:07: Please see: https://www.zigbee2mqtt.io/advanced/support-new-devices/01_support_new_devices.html

Tks...

cfnascimento avatar Feb 15 '22 02:02 cfnascimento

@juanjoSanz can you taking the power off and putting it back so the device is restarting ? If its being normal its sending the DP that is using and wee needing for fixing the missing parts. Have some extra logging for ZHA is needed as @javicalle was writing.

MattWestb avatar Feb 15 '22 06:02 MattWestb

I think that the appropriate thing would be to create a new file for cover type entities (maybe ts0601_cover.py) and implement this class inside (better than in a switch class). Currently there are already some implementations of Tuya covers, but I can try to create an implementation with the new approach and create the attributes that can be extracted from the logs.

This device is supposed to have 3 DP (garage trigger, door contact and door status): https://github.com/Koenkk/zigbee-herdsman-converters/blob/c9e6a47f0a7331a5e0548e9df0f83ccd1d7ce130/converters/fromZigbee.js#L7773-L7781

'Door status' seems to be not reliable, but maybe can get some information from logs.

javicalle avatar Feb 15 '22 09:02 javicalle

If that helps, here are additional logs.

  • Home Assistant debug logs for related components (zha, zigpy, quirks...): https://raw.githubusercontent.com/juanjoSanz/zha-device-handlers/dev/zhaquirks/tuya/ts0601_switch_door.log

  • Logs extracted when initializing device directly from ZHA interface:


[0x0000:zdo] ZDO request ZDOCmd.Mgmt_Permit_Joining_rsp: [<Status.SUCCESS: 0>]
[0x0000:zdo] No handler for ZDO request:ZDOCmd.Mgmt_Permit_Joining_rsp([<Status.SUCCESS: 0>])
[0x5a61:zdo] ZDO request ZDOCmd.Mgmt_Permit_Joining_rsp: [<Status.SUCCESS: 0>]
[0x5a61:zdo] No handler for ZDO request:ZDOCmd.Mgmt_Permit_Joining_rsp([<Status.SUCCESS: 0>])
New device 0xff96 (a4:c1:38:3b:09:ba:bb:13) joined the network
[0xff96] Scheduling initialization
Received frame on uninitialized device <Device model=None manuf=None nwk=0xFF96 ieee=a4:c1:38:3b:09:ba:bb:13 is_initialized=False> from ep 0 to ep 0, cluster 19: b'\x00\x96\xff\x13\xbb\xba\t;8\xc1\xa4\x8e'
[0xff96:zdo] ZDO request ZDOCmd.Device_annce: [0xFF96, a4:c1:38:3b:09:ba:bb:13, 142]
Tries remaining: 3
[0xff96] Requesting 'Node Descriptor'
Tries remaining: 2
[0xff96] Extending timeout for 0x1b request
Received frame on uninitialized device <Device model=None manuf=None nwk=0xFF96 ieee=a4:c1:38:3b:09:ba:bb:13 is_initialized=False> from ep 0 to ep 0, cluster 32770: b'\x1b\x00\x96\xff\x01@\x8eA\x11BB\x00\x00*B\x00\x00'
[0xff96] Got Node Descriptor: NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress|RxOnWhenIdle|MainsPowered|FullFunctionDevice: 142>, 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=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)
[0xff96] Discovering endpoints
Tries remaining: 3
Received frame on uninitialized device <Device model=None manuf=None nwk=0xFF96 ieee=a4:c1:38:3b:09:ba:bb:13 is_initialized=False> from ep 0 to ep 0, cluster 32773: b'\x1c\x00\x96\xff\x02\x01\xf2'
[0xff96] Discovered endpoints: [1, 242]
[0xff96] Initializing endpoints [<Endpoint id=1 in=[] out=[] status=<Status.NEW: 0>>, <Endpoint id=242 in=[] out=[] status=<Status.NEW: 0>>]
[0xff96:1] Discovering endpoint information
Tries remaining: 3
Received frame on uninitialized device <Device model=None manuf=None nwk=0xFF96 ieee=a4:c1:38:3b:09:ba:bb:13 is_initialized=False> from ep 0 to ep 0, cluster 32772: b'\x1d\x00\x96\xff\x14\x01\x04\x01Q\x00\x01\x04\x04\x00\x05\x00\x00\xef\x00\x00\x02\x19\x00\n\x00'
[0xff96:1] Discovered endpoint information: SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=81, device_version=1, input_clusters=[4, 5, 61184, 0], output_clusters=[25, 10])
Unknown cluster 61184
[0xff96:242] Discovering endpoint information
Tries remaining: 3
Received frame on uninitialized device <Device model=None manuf=None nwk=0xFF96 ieee=a4:c1:38:3b:09:ba:bb:13 is_initialized=False> from ep 0 to ep 0, cluster 32772: b'\x1e\x00\x96\xff\n\xf2\xe0\xa1a\x00\x00\x00\x01!\x00'
[0xff96:242] Discovered endpoint information: SizePrefixedSimpleDescriptor(endpoint=242, profile=41440, device_type=97, device_version=0, input_clusters=[], output_clusters=[33])
[0xff96: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=31 command_id=Command.Read_Attributes_rsp>
[0xff96] Read model 'TS0601' and manufacturer '_TZE200_nklqjk62' from <Endpoint id=1 in=[groups:0x0004, scenes:0x0005, None:0xEF00, basic:0x0000] out=[ota:0x0019, time:0x000A] status=<Status.ZDO_INIT: 1>>
[0xff96] Discovered basic device information for <Device model='TS0601' manuf='_TZE200_nklqjk62' nwk=0xFF96 ieee=a4:c1:38:3b:09:ba:bb:13 is_initialized=True>
Device is initialized <Device model='TS0601' manuf='_TZE200_nklqjk62' nwk=0xFF96 ieee=a4:c1:38:3b:09:ba:bb:13 is_initialized=True>
Checking quirks for _TZE200_nklqjk62 TS0601 (a4:c1:38:3b:09:ba:bb:13)
Considering <class 'zhaquirks.tuya.ts0601_switch_door.TuyaGarageSwitchTO'>
Found custom device replacement for a4:c1:38:3b:09:ba:bb:13: <class 'zhaquirks.tuya.ts0601_switch_door.TuyaGarageSwitchTO'>
'sensor' component -> 'RSSISensor' using ['basic']
'sensor' component -> 'LQISensor' using ['basic']
device - 0xFF96:a4:c1:38:3b:09:ba:bb:13 entering async_device_initialized - is_new_join: True
device - 0xFF96:a4:c1:38:3b:09:ba:bb:13 has joined the ZHA zigbee network
[0xFF96](TS0601): started configuration
[0xFF96:ZDO](TS0601): 'async_configure' stage succeeded
[0xFF96:1:0x0000]: finished channel configuration
[0xFF96:1:0x0019]: finished channel configuration
Error handling '_save_attribute' event with (a4:c1:38:3b:09:ba:bb:13, 1, 0, 4, '_TZE200_nklqjk62') params: FOREIGN KEY constraint failed
Error handling '_save_attribute' event with (a4:c1:38:3b:09:ba:bb:13, 1, 0, 5, 'TS0601') params: FOREIGN KEY constraint failed
[0xFF96:1:0x0006]: bound 'on_off' cluster: Status.INVALID_EP
[0xff96:1:0xef00] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=CLUSTER_COMMAND manufacturer_specific=False is_reply=True disable_default_response=False> manufacturer=None tsn=63 command_id=17>
[0xff96:1:0xef00] ZCL request 0x0011: [MCUVersionRsp(tsn=1280, version=64)]
[0xFF96:1:0x0006]: failed to set reporting on 'on_off' cluster for: 
[0xFF96:1:0x0006]: finished channel configuration
[0xFF96:1:0x0006]: 'async_configure' stage succeeded
[0xFF96:1:0x0000]: 'async_configure' stage succeeded
[0xFF96:1:0x0019]: 'async_configure' stage succeeded
[0xFF96](TS0601): completed configuration
[0xFF96](TS0601): stored in registry: ZhaDeviceEntry(name='_TZE200_nklqjk62 TS0601', ieee='a4:c1:38:3b:09:ba:bb:13', last_seen=1645027548.3382998)
[0xFF96](TS0601): started initialization
[0xFF96:ZDO](TS0601): 'async_initialize' stage succeeded
[0xFF96:1:0x0006]: initializing channel: from_cache: False
[0xFF96:1:0x0000]: initializing channel: from_cache: False
[0xFF96:1:0x0000]: finished channel initialization
[0xFF96:1:0x0019]: initializing channel: from_cache: False
[0xFF96:1:0x0019]: finished channel initialization
[0xff96:1:0xef00] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=CLUSTER_COMMAND manufacturer_specific=False is_reply=True disable_default_response=False> manufacturer=None tsn=63 command_id=17>
[0xff96:1:0xef00] ZCL request 0x0011: [MCUVersionRsp(tsn=1280, version=64)]
[0xff96:1:0xef00] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=CLUSTER_COMMAND manufacturer_specific=False is_reply=True disable_default_response=False> manufacturer=None tsn=64 command_id=2>
[0xff96:1:0xef00] ZCL request 0x0002: [Command(status=0, tsn=90, command_id=1036, function=0, data=[1, 2])]
[0xff96:1:0xef00] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=CLUSTER_COMMAND manufacturer_specific=False is_reply=True disable_default_response=False> manufacturer=None tsn=65 command_id=2>
[0xff96:1:0xef00] ZCL request 0x0002: [Command(status=0, tsn=91, command_id=516, function=0, data=[4, 0, 0, 0, 10])]
[0xF34C](TRADFRI bulb E27 W opal 1000lm): Attempting to checkin with device - missed checkins: 1
[0xff96:1:0xef00] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=CLUSTER_COMMAND manufacturer_specific=False is_reply=True disable_default_response=False> manufacturer=None tsn=66 command_id=2>
[0xff96:1:0xef00] ZCL request 0x0002: [Command(status=0, tsn=92, command_id=514, function=0, data=[4, 0, 0, 0, 0])]
[0xff96:1:0xef00] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=CLUSTER_COMMAND manufacturer_specific=False is_reply=True disable_default_response=False> manufacturer=None tsn=67 command_id=2>
[0xff96:1:0xef00] ZCL request 0x0002: [Command(status=0, tsn=93, command_id=517, function=0, data=[4, 0, 0, 14, 16])]
[0xff96:1:0xef00] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=CLUSTER_COMMAND manufacturer_specific=False is_reply=True disable_default_response=False> manufacturer=None tsn=68 command_id=2>
[0xff96:1:0xef00] ZCL request 0x0002: [Command(status=0, tsn=94, command_id=267, function=0, data=[1, 0])]
[0xff96:1:0xef00] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=CLUSTER_COMMAND manufacturer_specific=False is_reply=True disable_default_response=False> manufacturer=None tsn=69 command_id=2>
[0xff96:1:0xef00] ZCL request 0x0002: [Command(status=0, tsn=95, command_id=259, function=0, data=[1, 1])]
[0xff96:1:0x000a] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=False disable_default_response=False> manufacturer=None tsn=70 command_id=Command.Read_Attributes>
[0xff96:1:0x000a] ZCL request 0x0000: [[7]]
[0xE6B9](TS0601): Attempting to checkin with device - missed checkins: 1
[0xFF96:1:0x0006]: failed to get attributes '['on_off']' on 'on_off' cluster: 
[0xFF96:1:0x0006]: async_initialize: retryable request #1 failed: . Retrying in 1.1s
[0xFF96:1:0x0006]: initializing channel: from_cache: False
[0x5A61:1:0x0b04]: async_update
[0x3904:1:0x0b04]: async_update
[0xff96:1:0x0000] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True disable_default_response=False> manufacturer=None tsn=71 command_id=Command.Report_Attributes>
[0xff96:1:0x0000] ZCL request 0x000a: [[Attribute(attrid=1, value=<TypeValue type=uint8_t, value=70>), Attribute(attrid=65506, value=<TypeValue type=uint8_t, value=54>), Attribute(attrid=65508, value=<TypeValue type=uint8_t, value=1>)]]
[0xff96:1:0x0000] Attribute report received: app_version=70, 65506=54, 65508=1
[0xff96:1:0x0000] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True disable_default_response=False> manufacturer=None tsn=71 command_id=Command.Report_Attributes>
[0xff96:1:0x0000] ZCL request 0x000a: [[Attribute(attrid=1, value=<TypeValue type=uint8_t, value=70>), Attribute(attrid=65506, value=<TypeValue type=uint8_t, value=54>), Attribute(attrid=65508, value=<TypeValue type=uint8_t, value=1>)]]
[0xff96:1:0x0000] Attribute report received: app_version=70, 65506=54, 65508=1
Duplicate 71 TSN
[0xFF96:1:0x0006]: failed to get attributes '['on_off']' on 'on_off' cluster: 
[0xFF96:1:0x0006]: async_initialize: retryable request #2 failed: . Retrying in 0.8s
[0xFF96:1:0x0006]: initializing channel: from_cache: False
[0xff96:1:0xef00] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=CLUSTER_COMMAND manufacturer_specific=False is_reply=True disable_default_response=False> manufacturer=None tsn=72 command_id=2>
[0xff96:1:0xef00] ZCL request 0x0002: [Command(status=0, tsn=97, command_id=259, function=0, data=[1, 1])]

juanjoSanz avatar Feb 16 '22 16:02 juanjoSanz

Good morning all, I also have this GDC311ZBQ1 module? Were you finally able to integrate it? Do we have any leads or is it dead? Thank you

sigalou avatar Mar 26 '22 06:03 sigalou

So I saw that Zigbee2MQTT now seems to support this device. What's needed to get ZHA to support it?

https://github.com/Koenkk/zigbee2mqtt/issues/11570

EagleAdam avatar Apr 30 '22 21:04 EagleAdam

Same problem here. The device is recognized with ZHA but no entities are available. Would be very happy if there is any solution for it. 😄

BenjaminOe avatar May 25 '22 18:05 BenjaminOe

So I saw that Zigbee2MQTT now seems to support this device. What's needed to get ZHA to support it?

Koenkk/zigbee2mqtt#11570

Yeap, I saw this too, and works great, I tested it in a dev network with zigbee2mqtt and HA via mqtt. But, my real network is under ZHA integration and I'm not want this much to recreate the entire network with zb2mqtt. I tried create a qirk, but it didn't work at all.

For example, in debug of ZHA I found that the door sensor sends some commands, some bytes changes and I presume that is because it means the timestamp of the command or something like that. For the closing action the last 4 bytes are always the same, for the opening action the last 5 are the same. And always the secondish byte changes. For the closing action i can see 15 times one command then a single time other command. For the opening, it's just a 15 times the same command. Very weird indeed.

I don't know how to help, I tried to modify the @juanjoSanz file. But didn't worked very well, I had a on_off button, but it only toggles when I press the device button and when I try to switch the button on HA, I get an error saying something command error/unknown

`Closing

Test #1 15x WARNING (MainThread) [zigpy.zcl] [0x9075:1:0xef00] Unknown cluster command 2 b'\x00\x95\x03\x01\x00\x01\x00' 1x WARNING (MainThread) [zigpy.zcl] [0x9075:1:0xef00] Unknown cluster command 2 b'\x00\x96\x0c\x04\x00\x01\x02'

Test #2 15x WARNING (MainThread) [zigpy.zcl] [0x9075:1:0xef00] Unknown cluster command 2 b'\x00\x99\x03\x01\x00\x01\x00' 1x WARNING (MainThread) [zigpy.zcl] [0x9075:1:0xef00] Unknown cluster command 2 b'\x00\x9a\x0c\x04\x00\x01\x02'

Test #3 15x WARNING (MainThread) [zigpy.zcl] [0x9075:1:0xef00] Unknown cluster command 2 b'\x002\x03\x01\x00\x01\x00' 1x WARNING (MainThread) [zigpy.zcl] [0x9075:1:0xef00] Unknown cluster command 2 b'\x003\x0c\x04\x00\x01\x02'

Opening

Test #1 15x WARNING (MainThread) [zigpy.zcl] [0x9075:1:0xef00] Unknown cluster command 2 b'\x00(\x03\x01\x00\x01\x01'

Test #2 15x WARNING (MainThread) [zigpy.zcl] [0x9075:1:0xef00] Unknown cluster command 2 b'\x00\xda\x03\x01\x00\x01\x01'

Test #3 15x WARNING (MainThread) [zigpy.zcl] [0x9075:1:0xef00] Unknown cluster command 2 b'\x00\x1d\x03\x01\x00\x01\x01'

`

jeison-souza avatar May 27 '22 21:05 jeison-souza

Hi, there is my proposal for _TZE200_nklqjk62 device and maybe others:

ts0601_garage.py
"""Tuya based cover and blinds."""
from typing import Dict

from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
import zigpy.types as t
from zigpy.zcl.clusters.general import Basic, GreenPowerProxy, Groups, Ota, Scenes, Time
from zigpy.zcl.clusters.security import IasZone

from zhaquirks.const import (
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
)
from zhaquirks.tuya import TuyaLocalCluster
from zhaquirks.tuya.mcu import (
    DPToAttributeMapping,
    TuyaDPType,
    TuyaMCUCluster,
    TuyaOnOff,
    TuyaOnOffNM,
)

ZONE_TYPE = 0x0001


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 TuyaGarageManufCluster(TuyaMCUCluster):
    """Tuya garage door opener."""

    attributes = TuyaMCUCluster.attributes.copy()
    attributes.update(
        {
            # ramdom attribute IDs
            0xEF02: ("dp_2", t.uint32_t, True),
            0xEF04: ("dp_4", t.uint32_t, True),
            0xEF05: ("dp_5", t.uint32_t, True),
            0xEF0B: ("dp_11", t.Bool, True),
            0xEF0C: ("dp_12", t.enum8, True),
        }
    )

    dp_to_attribute: Dict[int, DPToAttributeMapping] = {
        # garage door trigger ¿on movement, on open, on closed?
        1: DPToAttributeMapping(
            TuyaOnOffNM.ep_attribute,
            "on_off",
            dp_type=TuyaDPType.BOOL,
        ),
        2: DPToAttributeMapping(
            TuyaMCUCluster.ep_attribute,
            "dp_2",
            dp_type=TuyaDPType.VALUE,
        ),
        3: DPToAttributeMapping(
            ContactSwitchCluster.ep_attribute,
            "zone_status",
            dp_type=TuyaDPType.BOOL,
            converter=lambda x: IasZone.ZoneStatus.Alarm_1 if x else 0,
        ),
        4: DPToAttributeMapping(
            TuyaMCUCluster.ep_attribute,
            "dp_4",
            dp_type=TuyaDPType.VALUE,
        ),
        5: DPToAttributeMapping(
            TuyaMCUCluster.ep_attribute,
            "dp_5",
            dp_type=TuyaDPType.VALUE,
        ),
        11: DPToAttributeMapping(
            TuyaMCUCluster.ep_attribute,
            "dp_11",
            dp_type=TuyaDPType.BOOL,
        ),
        # garage door status (open, closed, ...)
        12: DPToAttributeMapping(
            TuyaMCUCluster.ep_attribute,
            "dp_12",
            dp_type=TuyaDPType.ENUM,
        ),
    }

    data_point_handlers = {
        1: "_dp_2_attr_update",
        2: "_dp_2_attr_update",
        3: "_dp_2_attr_update",
        4: "_dp_2_attr_update",
        5: "_dp_2_attr_update",
        11: "_dp_2_attr_update",
        12: "_dp_2_attr_update",
    }


class TuyaGarageSwitchTO(CustomDevice):
    """Tuya Garage switch."""

    signature = {
        MODELS_INFO: [
            ("_TZE200_nklqjk62", "TS0601"),
        ],
        ENDPOINTS: {
            # <SimpleDescriptor endpoint=1 profile=260 device_type=0x0051
            # input_clusters=[0, 4, 5, 61184]
            # output_clusters=[10, 25]>
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaGarageManufCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            # <SimpleDescriptor endpoint=242 profile=41440 device_type=97
            # input_clusters=[]
            # output_clusters=[33]
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaGarageManufCluster,
                    TuyaOnOffNM,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.IAS_ZONE,
                INPUT_CLUSTERS: [
                    ContactSwitchCluster
                ],
                OUTPUT_CLUSTERS: [],
            },
            242: {
                PROFILE_ID: 0xA1E0,
                DEVICE_TYPE: 0x0061,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [0x0021],
            },
        },
    }

Implementation must give a switch for open/close (already implemented and working) Added the contact sensor (DP3). It may not work, but the traces can provide information on its use. And all the other reported DPs as TuyaGarageManufCluster attributes:

  • dp_2 (numeric value: 0) unknown function
  • dp_4 (numeric value: 10) unknown function
  • dp_5 (numeric value: ¿4110?) unknown function
  • dp_11 (boolean: 0) unknown function
  • dp_12 (enum: 2) garage door status (open, closed, ...)

For anyone who wants to test on another device, add your signature to the MODELS_INFO:

        MODELS_INFO: [
            ("_TZE200_nklqjk62", "TS0601"),
        ],

javicalle avatar May 28 '22 12:05 javicalle

Probably a WindowCovering device would be more appropriate, but not sure how cluster status is updated. I suppose that device doesn't have any 'door position', and WindowCovering seems that only have current_position but not a 'window status'.

I have a question? This door can be stopped alfway? If yes, how is it? It seems that only accepts open and close buttons (no stop button).

javicalle avatar May 28 '22 16:05 javicalle

Probably a WindowCovering device would be more appropriate, but not sure how cluster status is updated. I suppose that device doesn't have any 'door position', and WindowCovering seems that only have current_position but not a 'window status'.

I have a question? This door can be stopped halfway? If yes, how is it? It seems that only accepts open and close buttons (no stop button).

In reality, physically the device it only has a "Action button" momentary switch, that activate a relay for 2 seconds then turn it off. And also a wireless contact switch for door status detection. (Closed or not closed, but with no way to determine the position)

The garage door itself, start a movement if it isn't moving ou stops if it's moving. If you press it again, it inverts the direction, but I guess it will change from depending on the garage motor vendor.

Looking at the zb2mqtt converter code, we can see this:

           switch (dpValue.dp) {
           case tuya.dataPoints.garageDoorTrigger: // dp 1
               result.action = 'trigger';
               break;
           case tuya.dataPoints.garageDoorContact: // dp 3
               result.garage_door_contact = Boolean(!value);
               break;
           case tuya.dataPoints.garageDoorStatus: // dp 12
               // This reports a garage door status (open, closed), but it is very naive and misleading
               break;
           default:
               meta.logger.debug("zigbee-herdsman-converters:matsee_garage_door_opener: NOT RECOGNIZED " +
                   "DP #${dpValue.dp} with data ${JSON.stringify(dpValue)}");
           }

They don't use the dp 12 for statut as you can see above, they use the 3 (wireless contact switch).

My device model is a little bit different than yours, but I'll give your code a shoot then I'll let you know the results. "_TZE200_wfxuhoea", "TS0601"

Thanks a lot. !

jeison-souza avatar May 28 '22 20:05 jeison-souza

Hi @javicalle , unfortunately it didn't work, on the on_off dp_1, I have a "toggle" when I press the button, but when I toggle in HA, nothing is sent to the device, no relay click sound. The sensor doesn't work as a IAS_Zone, always shows off. But if I put it as TuyaOnOff cluster, it reports the state of the sensor, but in form of a switch. Not ideal, but it is something already.

I'll try to change some bits in your code to see if I can have the command sent to the device at least.

jeison-souza avatar May 28 '22 21:05 jeison-souza

So, from your comments (thanks for that) it would be more appropiate represent in HA as a button, isn't it? I am going to see how a button can be defined in Zigpy. The dp_1 was not already working? or am I confused? The logs from the HA interaction could give to us some clues about whats happening here.

Can you try with another iteration for the sensor? Just add the converter as:


        3: DPToAttributeMapping(
            ContactSwitchCluster.ep_attribute,
            "zone_status",
            dp_type=TuyaDPType.BOOL,
            endpoint_id=2,
            converter=lambda x: IasZone.ZoneStatus.Alarm_1 if x else 0,
        ),

Can you also check if (with the IasZone cluster) the zone_status is updating its value?

EDIT: the DP converter is needed: https://github.com/zigpy/zha-device-handlers/issues/1502#issuecomment-1140495827

javicalle avatar May 29 '22 18:05 javicalle

Another random test that can be done is to replace the TuyaOnOff cluster:

  1. add the TuyaOnOffNM import:
from zhaquirks.tuya.mcu import (
    DPToAttributeMapping,
    TuyaDPType,
    TuyaMCUCluster,
    TuyaOnOff,
    TuyaOnOffNM,
)
  1. replace the class (in the replacement part):
            1: {
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaGarageManufCluster,
                    TuyaOnOffNM,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },

javicalle avatar May 29 '22 18:05 javicalle

I'll try that @javicalle , I'll keep you informed. Thanks

jeison-souza avatar May 30 '22 12:05 jeison-souza

Hummmm, I don't have the NonManufacturer versions in my HomeAssistant instalation, weird, My home assistant is up to date 2022.5.5, but the zhaquirks files are not.

image

It seems that I'm at v 0.0.73 of zha-quirks.
I think I need to check how to update the quirks version before continuing debugging.

I create a Repo to help share the files https://github.com/jeison-souza/Debug_Loratap But my debugs are very polluted with all other devices, I'll move this to my dev clean instance with a controller that has nothing but this device.

image

The control only changes status if I press physically the device button, but doesn't trigger the device if I switch in HA The sensor doesn't report the statut at all, but it does if I change the config from IAS_Zone to OnOff for dp_3

Il commit the logs latter. Thanks again

jeison-souza avatar May 30 '22 13:05 jeison-souza