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
684 stars 636 forks source link

[BUG] Curtain motor _TZE200_r0jdjrvi has no entities #1953

Open caradas opened 1 year ago

caradas commented 1 year ago

Describe the bug Curtain motor has no entities.

Expected behavior Entities for opening and closing curtain and if possible slider to set partially closed

```yaml { "node_descriptor": "NodeDescriptor(logical_type=, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=, mac_capability_flags=, manufacturer_code=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=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_r0jdjrvi", "model": "TS0601", "class": "zigpy.device.Device" } ````
```yaml { "home_assistant": { "installation_type": "Home Assistant OS", "version": "2022.11.4", "dev": false, "hassio": true, "virtualenv": false, "python_version": "3.10.7", "docker": true, "arch": "x86_64", "timezone": "Europe/Berlin", "os_name": "Linux", "os_version": "5.15.74", "supervisor": "2022.10.2", "host_os": "Home Assistant OS 9.3", "docker_version": "20.10.18", "chassis": "vm", "run_as_root": true }, "custom_components": {}, "integration_manifest": { "domain": "zha", "name": "Zigbee Home Automation", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/zha", "requirements": [ "bellows==0.34.2", "pyserial==3.5", "pyserial-asyncio==0.6", "zha-quirks==0.0.86", "zigpy-deconz==0.19.0", "zigpy==0.51.5", "zigpy-xbee==0.16.2", "zigpy-zigate==0.10.3", "zigpy-znp==0.9.1" ], "usb": [ { "vid": "10C4", "pid": "EA60", "description": "*2652*", "known_devices": [ "slae.sh cc2652rb stick" ] }, { "vid": "1A86", "pid": "55D4", "description": "*sonoff*plus*", "known_devices": [ "sonoff zigbee dongle plus v2" ] }, { "vid": "10C4", "pid": "EA60", "description": "*sonoff*plus*", "known_devices": [ "sonoff zigbee dongle plus" ] }, { "vid": "10C4", "pid": "EA60", "description": "*tubeszb*", "known_devices": [ "TubesZB Coordinator" ] }, { "vid": "1A86", "pid": "7523", "description": "*tubeszb*", "known_devices": [ "TubesZB Coordinator" ] }, { "vid": "1A86", "pid": "7523", "description": "*zigstar*", "known_devices": [ "ZigStar Coordinators" ] }, { "vid": "1CF1", "pid": "0030", "description": "*conbee*", "known_devices": [ "Conbee II" ] }, { "vid": "10C4", "pid": "8A2A", "description": "*zigbee*", "known_devices": [ "Nortek HUSBZB-1" ] }, { "vid": "0403", "pid": "6015", "description": "*zigate*", "known_devices": [ "ZiGate+" ] }, { "vid": "10C4", "pid": "EA60", "description": "*zigate*", "known_devices": [ "ZiGate" ] }, { "vid": "10C4", "pid": "8B34", "description": "*bv 2010/10*", "known_devices": [ "Bitron Video AV2010/10" ] } ], "codeowners": [ "@dmulcahey", "@adminiuga", "@puddly" ], "zeroconf": [ { "type": "_esphomelib._tcp.local.", "name": "tube*" }, { "type": "_zigate-zigbee-gateway._tcp.local.", "name": "*zigate*" }, { "type": "_zigstar_gw._tcp.local.", "name": "*zigstar*" } ], "dependencies": [ "file_upload" ], "after_dependencies": [ "onboarding", "usb", "zeroconf" ], "iot_class": "local_polling", "loggers": [ "aiosqlite", "bellows", "crccheck", "pure_pcapy3", "zhaquirks", "zigpy", "zigpy_deconz", "zigpy_xbee", "zigpy_zigate", "zigpy_znp" ], "is_built_in": true }, "data": { "ieee": "**REDACTED**", "nwk": 46434, "manufacturer": "_TZE200_r0jdjrvi", "model": "TS0601", "name": "_TZE200_r0jdjrvi TS0601", "quirk_applied": false, "quirk_class": "zigpy.device.Device", "manufacturer_code": 4417, "power_source": "Mains", "lqi": 28, "rssi": null, "last_seen": "2022-11-22T00:55:09", "available": true, "device_type": "Router", "signature": { "node_descriptor": "NodeDescriptor(logical_type=, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=, mac_capability_flags=, manufacturer_code=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=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" ] } } }, "active_coordinator": false, "entities": [], "neighbors": [], "endpoint_names": [ { "name": "SMART_PLUG" }, { "name": "unknown 97 device_type of 0xa1e0 profile id" } ], "user_given_name": null, "device_reg_id": "b43e549ed833f2c0c88589cb86a72fa1", "area_id": "schlafzimmer", "cluster_details": { "1": { "device_type": { "name": "SMART_PLUG", "id": 81 }, "profile_id": 260, "in_clusters": { "0x0004": { "endpoint_attribute": "groups", "attributes": {}, "unsupported_attributes": {} }, "0x0005": { "endpoint_attribute": "scenes", "attributes": {}, "unsupported_attributes": {} }, "0xef00": { "endpoint_attribute": null, "attributes": {}, "unsupported_attributes": {} }, "0x0000": { "endpoint_attribute": "basic", "attributes": { "0x0001": { "attribute_name": "app_version", "value": 70 }, "0x0004": { "attribute_name": "manufacturer", "value": "_TZE200_r0jdjrvi" }, "0x0005": { "attribute_name": "model", "value": "TS0601" } }, "unsupported_attributes": {} } }, "out_clusters": { "0x0019": { "endpoint_attribute": "ota", "attributes": {}, "unsupported_attributes": {} }, "0x000a": { "endpoint_attribute": "time", "attributes": {}, "unsupported_attributes": {} } } }, "242": { "device_type": { "name": "unknown", "id": 97 }, "profile_id": 41440, "in_clusters": {}, "out_clusters": { "0x0021": { "endpoint_attribute": "green_power", "attributes": {}, "unsupported_attributes": {} } } } } } } ````

According to https://github.com/zigpy/zha-device-handlers/issues/1602#issuecomment-1322763054 its already fixed.

javicalle commented 1 year ago

Sorry for closing, but not, not fixed yet.

If you don't mind, go for a fresh start and focused just in your device. I have recall all the post and it seems to be a tricky device. If I have read all the info, there must be a posible quirk but is possible that the stop button don't work.

Lets begin...

My proposed quirk:

ts0601_cover_2.py ```python """Tuya MCU based cover and blinds.""" from typing import Dict, Optional, Union from zigpy.profiles import zha import zigpy.types as t from zigpy.zcl import foundation from zigpy.zcl.clusters.closures import WindowCovering from zigpy.zcl.clusters.general import ( Basic, GreenPowerProxy, Groups, Identify, OnOff, Ota, Scenes, Time, ) from zhaquirks.const import ( DEVICE_TYPE, ENDPOINTS, INPUT_CLUSTERS, MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, ) from zhaquirks.tuya import ( NoManufacturerCluster, TUYA_MCU_COMMAND, TuyaLocalCluster, TuyaManufacturerWindowCover, TuyaManufCluster, TuyaWindowCover, TuyaWindowCoverControl, ) from zhaquirks.tuya.mcu import ( DPToAttributeMapping, TuyaClusterData, TuyaDPType, TuyaMCUCluster, TuyaOnOffNM, ) # Maps OPEN/CLOSE/STOP cover commands from Tuya to Zigbee # https://github.com/zigpy/zigpy/blob/master/zigpy/zcl/clusters/closures.py#L558 # https://developer.tuya.com/en/docs/iot-device-dev/zigbee-curtain-switch-access-standard?id=K9ik6zvra3twv#title-7-DP1%20and%20DP4%20Curtain%20switch%201%20and%202 TUYA2ZB_COMMANDS = { 0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001, } class TuyaWindowCovering(NoManufacturerCluster, WindowCovering, TuyaLocalCluster): """Tuya MCU WindowCovering cluster.""" """Add additional attributes for direction""" attributes = WindowCovering.attributes.copy() attributes.update( { 0xF000: ("curtain_switch", t.enum8, True), # 0: open, 1: stop, 2: close 0xF001: ( "accurate_calibration", t.enum8, True, ), # 0: calibration started, 1: calibration finished 0xF002: ("motor_steering", t.enum8, True), # 0: default, 1: reverse 0xF003: ("travel", t.uint16_t, True), # 30 to 9000 (units of 0.1 seconds) } ) async def command( self, command_id: Union[foundation.GeneralCommand, int, t.uint8_t], *args, manufacturer: Optional[Union[int, t.uint16_t]] = None, expect_reply: bool = True, tsn: Optional[Union[int, t.uint8_t]] = None, ): """Override the default Cluster command.""" # if manufacturer is None: # manufacturer = self.endpoint.device.manufacturer self.debug( "Sending Tuya Cluster Command. Cluster Command is %x, Arguments are %s", command_id, args, ) # (upopen, downclose, stop) if command_id in (0x0002): # ¿0x0003: continue? cluster_data = TuyaClusterData( endpoint_id=self.endpoint.endpoint_id, cluster_attr="curtain_switch", attr_value=TUYA2ZB_COMMANDS[command_id], # convert tuya2zigbee command expect_reply=expect_reply, manufacturer=manufacturer, ) self.endpoint.device.command_bus.listener_event( TUYA_MCU_COMMAND, cluster_data, ) return foundation.GENERAL_COMMANDS[ foundation.GeneralCommand.Default_Response ].schema(command_id=command_id, status=foundation.Status.SUCCESS) # (go_to_lift_percentage) elif command_id in (0x0000, 0x0001, 0x0005): if command_id == 0x0000: lift_value = 100 elif command_id == 0x0001: lift_value = 0 elif command_id == 0x0005: lift_value = args[0] cluster_data = TuyaClusterData( endpoint_id=self.endpoint.endpoint_id, cluster_attr="current_position_lift_percentage", attr_value=lift_value, expect_reply=expect_reply, manufacturer=manufacturer, ) self.endpoint.device.command_bus.listener_event( TUYA_MCU_COMMAND, cluster_data, ) return foundation.GENERAL_COMMANDS[ foundation.GeneralCommand.Default_Response ].schema(command_id=command_id, status=foundation.Status.SUCCESS) # # Custom Command # elif command_id == 0x0006: # ¿doc reference? # tuya_payload.status = args[0] # tuya_payload.tsn = args[1] # tuya_payload.command_id = args[2] # tuya_payload.function = args[3] # tuya_payload.data = args[4] self.warning("Unsupported command_id: %s", command_id) return foundation.GENERAL_COMMANDS[ foundation.GeneralCommand.Default_Response ].schema(command_id=command_id, status=foundation.Status.UNSUP_CLUSTER_COMMAND) class TuyaWindowCoverManufCluster(TuyaMCUCluster): """Tuya with WindowCover data points.""" attributes = TuyaMCUCluster.attributes.copy() attributes.update( { 0x5000: ("backlight_mode", t.enum8, True), # 0: off, 1: on 0x8001: ( "indicator_status", t.enum8, True, ), # 0: status, 1: position, 2: off (¿backlight_mode?) } ) dp_to_attribute: Dict[int, DPToAttributeMapping] = { 1: DPToAttributeMapping( TuyaWindowCovering.ep_attribute, "on_off", dp_type=TuyaDPType.ENUM, ), 2: DPToAttributeMapping( TuyaWindowCovering.ep_attribute, "current_position_lift_percentage", dp_type=TuyaDPType.VALUE, ), 3: DPToAttributeMapping( TuyaWindowCovering.ep_attribute, "accurate_calibration", dp_type=TuyaDPType.ENUM, ), 4: DPToAttributeMapping( TuyaWindowCovering.ep_attribute, "on_off", dp_type=TuyaDPType.ENUM, endpoint_id=2, ), 5: DPToAttributeMapping( TuyaWindowCovering.ep_attribute, "current_position_lift_percentage", dp_type=TuyaDPType.VALUE, endpoint_id=2, ), 6: DPToAttributeMapping( TuyaWindowCovering.ep_attribute, "accurate_calibration", dp_type=TuyaDPType.ENUM, endpoint_id=2, ), 7: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "backlight_mode", dp_type=TuyaDPType.ENUM, ), 8: DPToAttributeMapping( TuyaWindowCovering.ep_attribute, "motor_steering", dp_type=TuyaDPType.ENUM, ), 9: DPToAttributeMapping( TuyaWindowCovering.ep_attribute, "motor_steering", dp_type=TuyaDPType.ENUM, endpoint_id=2, ), 10: DPToAttributeMapping( TuyaWindowCovering.ep_attribute, "quick_calibration", dp_type=TuyaDPType.ENUM, ), 11: DPToAttributeMapping( TuyaWindowCovering.ep_attribute, "quick_calibration", dp_type=TuyaDPType.ENUM, endpoint_id=2, ), 14: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "indicator_status", 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", 6: "_dp_2_attr_update", 7: "_dp_2_attr_update", 8: "_dp_2_attr_update", 9: "_dp_2_attr_update", 10: "_dp_2_attr_update", 11: "_dp_2_attr_update", 14: "_dp_2_attr_update", } class TuyaCover0601_GP(TuyaWindowCover): """Tuya blind controller device.""" signature = { MODELS_INFO: [ ("_TZE200_r0jdjrvi", "TS0601"), ], ENDPOINTS: { 1: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.SMART_PLUG, INPUT_CLUSTERS: [ Basic.cluster_id, Groups.cluster_id, Scenes.cluster_id, TuyaWindowCoverManufCluster.cluster_id, ], OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id], }, 242: { PROFILE_ID: 41440, DEVICE_TYPE: 97, INPUT_CLUSTERS: [], OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id], }, }, } replacement = { ENDPOINTS: { 1: { DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE, INPUT_CLUSTERS: [ Basic.cluster_id, Groups.cluster_id, Scenes.cluster_id, TuyaWindowCoverManufCluster, TuyaOnOffNM, TuyaWindowCovering, ], OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id], }, 242: { PROFILE_ID: 41440, DEVICE_TYPE: 97, INPUT_CLUSTERS: [], OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id], }, } } ```

There is a good guide to create your local quirk:

Just create inside your local quirk folder a new file (ie: ts0601_cover_2.py) and put the code inside.

After any future changes to the quirk you will need to remove any __pycache__ folder, restart HA and repair the device.

I will try to help as much as I can, but it will take a lot of tests and a lot of patience (my time is limited). It will also be necessary to activate the logs for the integration and collect the relevant information. Instructions here:

If you have a remote control for the cover, it will also be useful to obtain information on the commands.

One last request, please, put the logs and code examples between ``` marks like this:

Any code o logs requested

caradas commented 1 year ago

Thanks for your time and help :) I have changed the if in line 88 to:

        # (upopen, downclose, stop)
        if command_id == (0x0002):  # ¿0x0003: continue?
            cluster_data = TuyaClusterData(

After that i noticed that the dasboard buttons aren't working.

Also shortened the log to the only thing thats happening while the motor is active:

Remote: Open + Stop:

2022-11-23 22:15:16.598 DEBUG (MainThread) [zigpy_znp.api] Received command: ZDO.SrcRtgInd.Callback(DstAddr=0xB562, Relays=[0x7929])
2022-11-23 22:15:16.604 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=61184, SrcAddr=0xB562, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=<Bool.false: 0>, LQI=49, SecurityUse=<Bool.false: 0>, TimeStamp=15684090, TSN=0, Data=b'\x19\xC0\x01\x00\x01\x03\x02\x00\x04\x00\x00\x00\x51', MacSrcAddr=0x7929, MsgResultRadius=28)
2022-11-23 22:15:16.605 DEBUG (MainThread) [zigpy.application] Received a packet: ZigbeePacket(src=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0xB562), src_ep=1, dst=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x0000), dst_ep=1, source_route=None, extended_timeout=False, tsn=0, profile_id=260, cluster_id=61184, data=Serialized[b'\x19\xc0\x01\x00\x01\x03\x02\x00\x04\x00\x00\x00Q'], tx_options=<TransmitOptions.NONE: 0>, radius=28, non_member_radius=0, lqi=49, rssi=None)
2022-11-23 22:15:16.605 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Received ZCL frame: b'\x19\xc0\x01\x00\x01\x03\x02\x00\x04\x00\x00\x00Q'
2022-11-23 22:15:16.606 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 1>, disable_default_response=1, reserved=0, *is_cluster=True, *is_general=False, *is_reply=True), tsn=192, command_id=1, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2022-11-23 22:15:16.607 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Decoded ZCL frame: TuyaWindowCoverManufCluster:get_data(data=TuyaCommand(status=0, tsn=1, datapoints=[TuyaDatapointData(dp=3, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'Q\x00\x00\x00', *payload=81))]))
2022-11-23 22:15:16.608 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Received command 0x01 (TSN 192): get_data(data=TuyaCommand(status=0, tsn=1, datapoints=[TuyaDatapointData(dp=3, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'Q\x00\x00\x00', *payload=81))]))
2022-11-23 22:15:16.609 DEBUG (MainThread) [homeassistant.components.zha.core.channels.base] [0xB562:1:0x0102]: Attribute report 'Window Covering'[accurate_calibration] = 81

Remote Open without stop till fully open:

2022-11-23 22:18:30.401 DEBUG (MainThread) [zigpy_znp.api] Received command: ZDO.SrcRtgInd.Callback(DstAddr=0xB562, Relays=[0x7929])
2022-11-23 22:18:30.407 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=61184, SrcAddr=0xB562, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=<Bool.false: 0>, LQI=47, SecurityUse=<Bool.false: 0>, TimeStamp=16289752, TSN=0, Data=b'\x19\xC7\x01\x00\x01\x03\x02\x00\x04\x00\x00\x00\x00', MacSrcAddr=0x7929, MsgResultRadius=28)
2022-11-23 22:18:30.408 DEBUG (MainThread) [zigpy.application] Received a packet: ZigbeePacket(src=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0xB562), src_ep=1, dst=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x0000), dst_ep=1, source_route=None, extended_timeout=False, tsn=0, profile_id=260, cluster_id=61184, data=Serialized[b'\x19\xc7\x01\x00\x01\x03\x02\x00\x04\x00\x00\x00\x00'], tx_options=<TransmitOptions.NONE: 0>, radius=28, non_member_radius=0, lqi=47, rssi=None)
2022-11-23 22:18:30.408 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Received ZCL frame: b'\x19\xc7\x01\x00\x01\x03\x02\x00\x04\x00\x00\x00\x00'
2022-11-23 22:18:30.409 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 1>, disable_default_response=1, reserved=0, *is_cluster=True, *is_general=False, *is_reply=True), tsn=199, command_id=1, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2022-11-23 22:18:30.409 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Decoded ZCL frame: TuyaWindowCoverManufCluster:get_data(data=TuyaCommand(status=0, tsn=1, datapoints=[TuyaDatapointData(dp=3, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x00\x00\x00\x00', *payload=0))]))
2022-11-23 22:18:30.409 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Received command 0x01 (TSN 199): get_data(data=TuyaCommand(status=0, tsn=1, datapoints=[TuyaDatapointData(dp=3, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x00\x00\x00\x00', *payload=0))]))
2022-11-23 22:18:30.410 DEBUG (MainThread) [homeassistant.components.zha.core.channels.base] [0xB562:1:0x0102]: Attribute report 'Window Covering'[accurate_calibration] = 0

Remote Close + Stop:

Open till completly open:
2022-11-23 22:18:30.401 DEBUG (MainThread) [zigpy_znp.api] Received command: ZDO.SrcRtgInd.Callback(DstAddr=0xB562, Relays=[0x7929])
2022-11-23 22:18:30.407 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=61184, SrcAddr=0xB562, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=<Bool.false: 0>, LQI=47, SecurityUse=<Bool.false: 0>, TimeStamp=16289752, TSN=0, Data=b'\x19\xC7\x01\x00\x01\x03\x02\x00\x04\x00\x00\x00\x00', MacSrcAddr=0x7929, MsgResultRadius=28)
2022-11-23 22:18:30.408 DEBUG (MainThread) [zigpy.application] Received a packet: ZigbeePacket(src=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0xB562), src_ep=1, dst=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x0000), dst_ep=1, source_route=None, extended_timeout=False, tsn=0, profile_id=260, cluster_id=61184, data=Serialized[b'\x19\xc7\x01\x00\x01\x03\x02\x00\x04\x00\x00\x00\x00'], tx_options=<TransmitOptions.NONE: 0>, radius=28, non_member_radius=0, lqi=47, rssi=None)
2022-11-23 22:18:30.408 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Received ZCL frame: b'\x19\xc7\x01\x00\x01\x03\x02\x00\x04\x00\x00\x00\x00'
2022-11-23 22:18:30.409 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 1>, disable_default_response=1, reserved=0, *is_cluster=True, *is_general=False, *is_reply=True), tsn=199, command_id=1, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2022-11-23 22:18:30.409 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Decoded ZCL frame: TuyaWindowCoverManufCluster:get_data(data=TuyaCommand(status=0, tsn=1, datapoints=[TuyaDatapointData(dp=3, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x00\x00\x00\x00', *payload=0))]))
2022-11-23 22:18:30.409 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Received command 0x01 (TSN 199): get_data(data=TuyaCommand(status=0, tsn=1, datapoints=[TuyaDatapointData(dp=3, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x00\x00\x00\x00', *payload=0))]))
2022-11-23 22:18:30.410 DEBUG (MainThread) [homeassistant.components.zha.core.channels.base] [0xB562:1:0x0102]: Attribute report 'Window Covering'[accurate_calibration] = 0

Remote Close till fully closed:

2022-11-23 22:17:08.010 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=61184, SrcAddr=0xB562, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=<Bool.false: 0>, LQI=47, SecurityUse=<Bool.false: 0>, TimeStamp=16032248, TSN=0, Data=b'\x19\xC6\x01\x00\x01\x03\x02\x00\x04\x00\x00\x00\x64', MacSrcAddr=0x7929, MsgResultRadius=28)
2022-11-23 22:17:08.010 DEBUG (MainThread) [zigpy.application] Received a packet: ZigbeePacket(src=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0xB562), src_ep=1, dst=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x0000), dst_ep=1, source_route=None, extended_timeout=False, tsn=0, profile_id=260, cluster_id=61184, data=Serialized[b'\x19\xc6\x01\x00\x01\x03\x02\x00\x04\x00\x00\x00d'], tx_options=<TransmitOptions.NONE: 0>, radius=28, non_member_radius=0, lqi=47, rssi=None)
2022-11-23 22:17:08.010 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Received ZCL frame: b'\x19\xc6\x01\x00\x01\x03\x02\x00\x04\x00\x00\x00d'
2022-11-23 22:17:08.011 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 1>, disable_default_response=1, reserved=0, *is_cluster=True, *is_general=False, *is_reply=True), tsn=198, command_id=1, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2022-11-23 22:17:08.011 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Decoded ZCL frame: TuyaWindowCoverManufCluster:get_data(data=TuyaCommand(status=0, tsn=1, datapoints=[TuyaDatapointData(dp=3, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'd\x00\x00\x00', *payload=100))]))
2022-11-23 22:17:08.012 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Received command 0x01 (TSN 198): get_data(data=TuyaCommand(status=0, tsn=1, datapoints=[TuyaDatapointData(dp=3, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'd\x00\x00\x00', *payload=100))]))
2022-11-23 22:17:08.012 DEBUG (MainThread) [homeassistant.components.zha.core.channels.base] [0xB562:1:0x0102]: Attribute report 'Window Covering'[accurate_calibration] = 100

Dashboard up button: Motor was not turning here

2022-11-23 22:36:38.857 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0x0102] Sending Tuya Cluster Command. Cluster Command is 0, Arguments are ()
2022-11-23 22:36:38.858 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] tuya_mcu_command: cluster_data=TuyaClusterData(endpoint_id=1, cluster_attr='current_position_lift_percentage', attr_value=100, expect_reply=True)
2022-11-23 22:36:38.858 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] get_dp_mapping --> found DP: 2
2022-11-23 22:36:38.858 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] from_cluster_data: 2, DPToAttributeMapping(ep_attribute='window_covering', attribute_name='current_position_lift_percentage', dp_type=<TuyaDPType.VALUE: 2>, converter=None, dp_converter=None, endpoint_id=None)
2022-11-23 22:36:38.858 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] ztype: 100
2022-11-23 22:36:38.858 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] from_value: [4, 0, 0, 0, 100]
2022-11-23 22:36:38.858 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] raw: b'\x00\x00\x00d'
2022-11-23 22:36:38.858 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] tuya_command: TuyaCommand(status=0, tsn=224, datapoints=[TuyaDatapointData(dp=2, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x00\x00\x00d', *payload=1677721600))])
2022-11-23 22:36:38.859 DEBUG (MainThread) [homeassistant.components.zha.core.channels.base] [0xB562:1:0x0102]: executed 'up_open' command with args: '()' kwargs: '{}' result: Default_Response(command_id=0, status=<Status.SUCCESS: 0>)
2022-11-23 22:36:38.859 DEBUG (MainThread) [homeassistant.components.zha.cover] state=opening
2022-11-23 22:36:38.860 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=True, direction=<Direction.Server_to_Client: 0>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False, *is_reply=False), manufacturer=4417, tsn=225, command_id=0, *direction=<Direction.Server_to_Client: 0>, *is_reply=False)
2022-11-23 22:36:38.860 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Sending request: set_data(data=TuyaCommand(status=0, tsn=224, datapoints=[TuyaDatapointData(dp=2, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x00\x00\x00d', *payload=1677721600))]))
2022-11-23 22:36:38.860 DEBUG (MainThread) [zigpy_znp.zigbee.application] Sending packet ZigbeePacket(src=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x0000), src_ep=1, dst=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0xB562), dst_ep=1, source_route=None, extended_timeout=False, tsn=225, profile_id=260, cluster_id=61184, data=Serialized[b'\x05A\x11\xe1\x00\x00\xe0\x02\x02\x00\x04\x00\x00\x00d'], tx_options=<TransmitOptions.NONE: 0>, radius=0, non_member_radius=0, lqi=None, rssi=None)
2022-11-23 22:36:38.862 DEBUG (MainThread) [zigpy_znp.api] Sending request: AF.DataRequestExt.Req(DstAddrModeAddress=AddrModeAddress(mode=<AddrMode.NWK: 2>, address=0xB562), DstEndpoint=1, DstPanId=0x0000, SrcEndpoint=1, ClusterId=61184, TSN=225, Options=<TransmitOptions.SUPPRESS_ROUTE_DISC_NETWORK: 32>, Radius=0, Data=b'\x05\x41\x11\xE1\x00\x00\xE0\x02\x02\x00\x04\x00\x00\x00\x64')
2022-11-23 22:36:38.875 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.DataRequestExt.Rsp(Status=<Status.SUCCESS: 0>)
2022-11-23 22:36:38.881 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.DataConfirm.Callback(Status=<Status.SUCCESS: 0>, Endpoint=1, TSN=225)
2022-11-23 22:36:38.902 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=61184, SrcAddr=0xB562, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=<Bool.false: 0>, LQI=47, SecurityUse=<Bool.false: 0>, TimeStamp=2979757, TSN=0, Data=b'\x18\xE1\x0B\x00\x83', MacSrcAddr=0x7929, MsgResultRadius=28)
2022-11-23 22:36:38.902 DEBUG (MainThread) [zigpy.application] Received a packet: ZigbeePacket(src=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0xB562), src_ep=1, dst=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x0000), dst_ep=1, source_route=None, extended_timeout=False, tsn=0, profile_id=260, cluster_id=61184, data=Serialized[b'\x18\xe1\x0b\x00\x83'], tx_options=<TransmitOptions.NONE: 0>, radius=28, non_member_radius=0, lqi=47, rssi=None)
2022-11-23 22:36:38.902 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Received ZCL frame: b'\x18\xe1\x0b\x00\x83'
2022-11-23 22:36:38.903 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 1>, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True, *is_reply=True), tsn=225, command_id=11, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2022-11-23 22:36:38.903 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Decoded ZCL frame: TuyaWindowCoverManufCluster:Default_Response(command_id=0, status=<Status.UNSUP_MANUF_CLUSTER_COMMAND: 131>)

Dasboard down button: Motor was not turning here

2022-11-23 22:35:24.700 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0x0102] Sending Tuya Cluster Command. Cluster Command is 1, Arguments are ()
2022-11-23 22:35:24.700 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] tuya_mcu_command: cluster_data=TuyaClusterData(endpoint_id=1, cluster_attr='current_position_lift_percentage', attr_value=0, expect_reply=True)
2022-11-23 22:35:24.700 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] get_dp_mapping --> found DP: 2
2022-11-23 22:35:24.700 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] from_cluster_data: 2, DPToAttributeMapping(ep_attribute='window_covering', attribute_name='current_position_lift_percentage', dp_type=<TuyaDPType.VALUE: 2>, converter=None, dp_converter=None, endpoint_id=None)
2022-11-23 22:35:24.701 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] ztype: 0
2022-11-23 22:35:24.701 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] from_value: [4, 0, 0, 0, 0]
2022-11-23 22:35:24.701 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] raw: b'\x00\x00\x00\x00'
2022-11-23 22:35:24.701 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] tuya_command: TuyaCommand(status=0, tsn=222, datapoints=[TuyaDatapointData(dp=2, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x00\x00\x00\x00', *payload=0))])
2022-11-23 22:35:24.701 DEBUG (MainThread) [homeassistant.components.zha.core.channels.base] [0xB562:1:0x0102]: executed 'down_close' command with args: '()' kwargs: '{}' result: Default_Response(command_id=1, status=<Status.SUCCESS: 0>)
2022-11-23 22:35:24.701 DEBUG (MainThread) [homeassistant.components.zha.cover] state=closing
2022-11-23 22:35:24.702 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=True, direction=<Direction.Server_to_Client: 0>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False, *is_reply=False), manufacturer=4417, tsn=223, command_id=0, *direction=<Direction.Server_to_Client: 0>, *is_reply=False)
2022-11-23 22:35:24.702 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Sending request: set_data(data=TuyaCommand(status=0, tsn=222, datapoints=[TuyaDatapointData(dp=2, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x00\x00\x00\x00', *payload=0))]))
2022-11-23 22:35:24.703 DEBUG (MainThread) [zigpy_znp.zigbee.application] Sending packet ZigbeePacket(src=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x0000), src_ep=1, dst=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0xB562), dst_ep=1, source_route=None, extended_timeout=False, tsn=223, profile_id=260, cluster_id=61184, data=Serialized[b'\x05A\x11\xdf\x00\x00\xde\x02\x02\x00\x04\x00\x00\x00\x00'], tx_options=<TransmitOptions.NONE: 0>, radius=0, non_member_radius=0, lqi=None, rssi=None)
2022-11-23 22:35:24.708 DEBUG (MainThread) [zigpy_znp.api] Sending request: AF.DataRequestExt.Req(DstAddrModeAddress=AddrModeAddress(mode=<AddrMode.NWK: 2>, address=0xB562), DstEndpoint=1, DstPanId=0x0000, SrcEndpoint=1, ClusterId=61184, TSN=223, Options=<TransmitOptions.SUPPRESS_ROUTE_DISC_NETWORK: 32>, Radius=0, Data=b'\x05\x41\x11\xDF\x00\x00\xDE\x02\x02\x00\x04\x00\x00\x00\x00')
2022-11-23 22:35:24.721 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.DataRequestExt.Rsp(Status=<Status.SUCCESS: 0>)
2022-11-23 22:35:24.727 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.DataConfirm.Callback(Status=<Status.SUCCESS: 0>, Endpoint=1, TSN=223)
2022-11-23 22:35:24.755 DEBUG (MainThread) [zigpy_znp.api] Received command: ZDO.SrcRtgInd.Callback(DstAddr=0xB562, Relays=[0x7929])
2022-11-23 22:35:24.761 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=61184, SrcAddr=0xB562, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=<Bool.false: 0>, LQI=47, SecurityUse=<Bool.false: 0>, TimeStamp=2748057, TSN=0, Data=b'\x18\xDF\x0B\x00\x83', MacSrcAddr=0x7929, MsgResultRadius=28)
2022-11-23 22:35:24.762 DEBUG (MainThread) [zigpy.application] Received a packet: ZigbeePacket(src=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0xB562), src_ep=1, dst=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x0000), dst_ep=1, source_route=None, extended_timeout=False, tsn=0, profile_id=260, cluster_id=61184, data=Serialized[b'\x18\xdf\x0b\x00\x83'], tx_options=<TransmitOptions.NONE: 0>, radius=28, non_member_radius=0, lqi=47, rssi=None)
2022-11-23 22:35:24.762 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Received ZCL frame: b'\x18\xdf\x0b\x00\x83'
2022-11-23 22:35:24.762 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 1>, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True, *is_reply=True), tsn=223, command_id=11, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2022-11-23 22:35:24.763 DEBUG (MainThread) [zigpy.zcl] [0xB562:1:0xef00] Decoded ZCL frame: TuyaWindowCoverManufCluster:Default_Response(command_id=0, status=<Status.UNSUP_MANUF_CLUSTER_COMMAND: 131>)
javicalle commented 1 year ago

Sorry but this seems to be a completely diferent cover from the quirk. The previous quirk was for a 2 cover device. I would need the full device description (manufacturer/vendor link).

From your logs I would say that cover reports the status position in some way. I would expect to have one report from every remote command but I only can see one from your logs.

My assumption is that the device will report the 'target status' when pushing the open/close buttons and the stop button will report the current position if stopped halfway. That could lead to a strange behavior in HA, but we'll see about that later.

Let's try with a 'classical' approach. Replace completely the local quirk with this one:

ts0601_cover_2.py ```python """Tuya based cover and blinds.""" from zigpy.profiles import zha from zigpy.zcl.clusters.general import Basic, GreenPowerProxy, Groups, Ota, Scenes, Time from zhaquirks.const import ( DEVICE_TYPE, ENDPOINTS, INPUT_CLUSTERS, MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, ) from zhaquirks.tuya import ( TuyaManufacturerWindowCover, TuyaManufCluster, TuyaWindowCover, TuyaWindowCoverControl, ) class TuyaCover0601_GP(TuyaWindowCover): """Tuya cover controller device.""" signature = { MODELS_INFO: [ ("_TZE200_r0jdjrvi", "TS0601"), ], ENDPOINTS: { 1: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.SMART_PLUG, INPUT_CLUSTERS: [ Basic.cluster_id, Groups.cluster_id, Scenes.cluster_id, TuyaManufCluster.cluster_id, ], OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id], }, 242: { PROFILE_ID: 41440, DEVICE_TYPE: 97, INPUT_CLUSTERS: [], OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id], }, }, } replacement = { ENDPOINTS: { 1: { DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE, INPUT_CLUSTERS: [ Basic.cluster_id, Groups.cluster_id, Scenes.cluster_id, TuyaManufacturerWindowCover, TuyaWindowCoverControl, ], OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id], } } } ```

Save changes, delete any __pycache__ folder, restart HA and repair the device. Double check if the device report the button press o just when it stop moving. Maybe is a RF remote? Look for any other reports from the device to see if there are other device attributes there.

caradas commented 1 year ago

It is this device: https://www.aliexpress.com/item/1005003796260309.html As EU Plug, Motor only variant. The datasheet says something like "Frequency 2.4G/433Mhz" so yes the remote should be rf, this also explains the Wire antenna hanging out of the device. It also says Product model "CMD900E" Any log output with the remote happens after the curtains stops regardless if stopped by the remote or track ends.

Pressing the stop button on the remote without the curtain moving no log output is generated.

Log for Stop in HA:


2022-11-24 21:50:48.744 DEBUG (MainThread) [zhaquirks.tuya] a4:c1:38:44:24:da:54:d3 Sending Tuya Cluster Command.. Manufacturer is _TZE200_r0jdjrvi Cluster Command is 0x0002, Arguments are ()
2022-11-24 21:50:48.745 DEBUG (MainThread) [zhaquirks.tuya] a4:c1:38:44:24:da:54:d3 Sending Tuya Command. Paylod values [endpoint_id : 1, Status : 0, TSN: 0, Command: 0x0401, Function: 0, Data: [1, 1]]
2022-11-24 21:50:48.745 DEBUG (MainThread) [zigpy.zcl] [0x6A13:1:0xef00] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=True, direction=<Direction.Server_to_Client: 0>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False, *is_reply=False), manufacturer=4417, tsn=118, command_id=0, *direction=<Direction.Server_to_Client: 0>, *is_reply=False)
2022-11-24 21:50:48.745 DEBUG (MainThread) [zigpy.zcl] [0x6A13:1:0xef00] Sending request: set_data(param=Command(status=0, tsn=0, command_id=1025, function=0, data=[1, 1]))
2022-11-24 21:50:48.746 DEBUG (MainThread) [zigpy_znp.zigbee.application] Sending packet ZigbeePacket(src=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x0000), src_ep=1, dst=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x6A13), dst_ep=1, source_route=None, extended_timeout=False, tsn=118, profile_id=260, cluster_id=61184, data=Serialized[b'\x05A\x11v\x00\x00\x00\x01\x04\x00\x01\x01'], tx_options=<TransmitOptions.NONE: 0>, radius=0, non_member_radius=0, lqi=None, rssi=None)
2022-11-24 21:50:48.747 DEBUG (MainThread) [zigpy_znp.api] Sending request: AF.DataRequestExt.Req(DstAddrModeAddress=AddrModeAddress(mode=<AddrMode.NWK: 2>, address=0x6A13), DstEndpoint=1, DstPanId=0x0000, SrcEndpoint=1, ClusterId=61184, TSN=118, Options=<TransmitOptions.SUPPRESS_ROUTE_DISC_NETWORK: 32>, Radius=0, Data=b'\x05\x41\x11\x76\x00\x00\x00\x01\x04\x00\x01\x01')
2022-11-24 21:50:48.760 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.DataRequestExt.Rsp(Status=<Status.SUCCESS: 0>)
2022-11-24 21:50:48.765 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.DataConfirm.Callback(Status=<Status.SUCCESS: 0>, Endpoint=1, TSN=118)
2022-11-24 21:50:48.786 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=61184, SrcAddr=0x6A13, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=<Bool.false: 0>, LQI=39, SecurityUse=<Bool.false: 0>, TimeStamp=3669657, TSN=0, Data=b'\x18\x76\x0B\x00\x83', MacSrcAddr=0x7929, MsgResultRadius=28)
2022-11-24 21:50:48.786 DEBUG (MainThread) [zigpy.application] Received a packet: ZigbeePacket(src=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x6A13), src_ep=1, dst=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x0000), dst_ep=1, source_route=None, extended_timeout=False, tsn=0, profile_id=260, cluster_id=61184, data=Serialized[b'\x18v\x0b\x00\x83'], tx_options=<TransmitOptions.NONE: 0>, radius=28, non_member_radius=0, lqi=39, rssi=None)
2022-11-24 21:50:48.786 DEBUG (MainThread) [zigpy.zcl] [0x6A13:1:0xef00] Received ZCL frame: b'\x18v\x0b\x00\x83'
2022-11-24 21:50:48.786 DEBUG (MainThread) [zigpy.zcl] [0x6A13:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 1>, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True, *is_reply=True), tsn=118, command_id=11, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2022-11-24 21:50:48.787 DEBUG (MainThread) [zigpy.zcl] [0x6A13:1:0xef00] Decoded ZCL frame: TuyaManufacturerWindowCover:Default_Response(command_id=0, status=<Status.UNSUP_MANUF_CLUSTER_COMMAND: 131>)

Log for UP in HA:

2022-11-24 21:53:42.314 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=1794, SrcAddr=0x2AD3, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=<Bool.false: 0>, LQI=97, SecurityUse=<Bool.false: 0>, TimeStamp=4211952, TSN=0, Data=b'\x08\x22\x0A\x00\x00\x25\x34\x0A\x00\x00\x00\x00', MacSrcAddr=0x2AD3, MsgResultRadius=29)
2022-11-24 21:53:42.314 DEBUG (MainThread) [zigpy.application] Received a packet: ZigbeePacket(src=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x2AD3), src_ep=1, dst=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x0000), dst_ep=1, source_route=None, extended_timeout=False, tsn=0, profile_id=260, cluster_id=1794, data=Serialized[b'\x08"\n\x00\x00%4\n\x00\x00\x00\x00'], tx_options=<TransmitOptions.NONE: 0>, radius=29, non_member_radius=0, lqi=97, rssi=None)
2022-11-24 21:53:42.315 DEBUG (MainThread) [zigpy.zcl] [0x2AD3:1:0x0702] Received ZCL frame: b'\x08"\n\x00\x00%4\n\x00\x00\x00\x00'
2022-11-24 21:53:42.315 DEBUG (MainThread) [zigpy.zcl] [0x2AD3:1:0x0702] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 1>, disable_default_response=0, reserved=0, *is_cluster=False, *is_general=True, *is_reply=True), tsn=34, command_id=10, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2022-11-24 21:53:42.316 DEBUG (MainThread) [zigpy.zcl] [0x2AD3:1:0x0702] Decoded ZCL frame: TuyaZBMeteringCluster:Report_Attributes(attribute_reports=[Attribute(attrid=0x0000, value=TypeValue(type=uint48_t, value=2612))])
2022-11-24 21:53:42.316 DEBUG (MainThread) [zigpy.zcl] [0x2AD3:1:0x0702] Received command 0x0A (TSN 34): Report_Attributes(attribute_reports=[Attribute(attrid=0x0000, value=TypeValue(type=uint48_t, value=2612))])
2022-11-24 21:53:42.316 DEBUG (MainThread) [zigpy.zcl] [0x2AD3:1:0x0702] Attribute report received: current_summ_delivered=2612
2022-11-24 21:53:42.320 DEBUG (MainThread) [zigpy.zcl] [0x2AD3:1:0x0702] Sending reply header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=False, direction=<Direction.Client_to_Server: 1>, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True, *is_reply=True), tsn=34, command_id=<GeneralCommand.Default_Response: 11>, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2022-11-24 21:53:42.321 DEBUG (MainThread) [zigpy.zcl] [0x2AD3:1:0x0702] Sending reply: Default_Response(command_id=10, status=<Status.SUCCESS: 0>)
2022-11-24 21:53:42.321 DEBUG (MainThread) [zigpy_znp.zigbee.application] Sending packet ZigbeePacket(src=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x0000), src_ep=1, dst=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x2AD3), dst_ep=1, source_route=None, extended_timeout=False, tsn=34, profile_id=260, cluster_id=1794, data=Serialized[b'\x18"\x0b\n\x00'], tx_options=<TransmitOptions.ACK: 1>, radius=0, non_member_radius=0, lqi=None, rssi=None)
2022-11-24 21:53:42.322 DEBUG (MainThread) [zigpy_znp.api] Sending request: AF.DataRequestExt.Req(DstAddrModeAddress=AddrModeAddress(mode=<AddrMode.NWK: 2>, address=0x2AD3), DstEndpoint=1, DstPanId=0x0000, SrcEndpoint=1, ClusterId=1794, TSN=34, Options=<TransmitOptions.SUPPRESS_ROUTE_DISC_NETWORK|ACK_REQUEST: 48>, Radius=0, Data=b'\x18\x22\x0B\x0A\x00')
2022-11-24 21:53:42.331 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.DataRequestExt.Rsp(Status=<Status.SUCCESS: 0>)
2022-11-24 21:53:42.358 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.DataConfirm.Callback(Status=<Status.SUCCESS: 0>, Endpoint=1, TSN=34)
2022-11-24 21:53:42.406 DEBUG (MainThread) [zhaquirks.tuya] a4:c1:38:44:24:da:54:d3 Sending Tuya Cluster Command.. Manufacturer is _TZE200_r0jdjrvi Cluster Command is 0x0000, Arguments are ()
2022-11-24 21:53:42.406 DEBUG (MainThread) [zhaquirks.tuya] a4:c1:38:44:24:da:54:d3 Sending Tuya Command. Paylod values [endpoint_id : 1, Status : 0, TSN: 0, Command: 0x0401, Function: 0, Data: [1, 0]]
2022-11-24 21:53:42.407 DEBUG (MainThread) [zigpy.zcl] [0x6A13:1:0xef00] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=True, direction=<Direction.Server_to_Client: 0>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False, *is_reply=False), manufacturer=4417, tsn=131, command_id=0, *direction=<Direction.Server_to_Client: 0>, *is_reply=False)
RowCZ commented 1 year ago

Hi @javicalle, I also have problem with my cover motor with same designation. :-/ I would love to assist to help you find the solution but because I am not exactly good at this I would appreciate any instruction what you need and how can I help. I was able to connect it to ZHA, I am catching LQI a RSSI Diagnostics but that is all. I have latest HA 2022.11.4 and with active built in quirks. Here is at least what I was able to dig from diagnostics about this device

  "data": {
    "ieee": "**REDACTED**",
    "nwk": 204,
    "manufacturer": "_TZE200_r0jdjrvi",
    "model": "TS0601",
    "name": "_TZE200_r0jdjrvi TS0601",
    "quirk_applied": false,
    "quirk_class": "zigpy.device.Device",
    "manufacturer_code": 4417,
    "power_source": "Mains",
    "lqi": 180,
    "rssi": -55,
    "last_seen": "2022-11-27T00:31:18",
    "available": true,
    "device_type": "Router",
    "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"
          ]
        }
      }
    },
    "active_coordinator": false,
    "entities": [
      {
        "entity_id": "sensor.tze200_r0jdjrvi_ts0601_rssi",
        "name": "_TZE200_r0jdjrvi TS0601"
      },
      {
        "entity_id": "sensor.tze200_r0jdjrvi_ts0601_lqi",
        "name": "_TZE200_r0jdjrvi TS0601"
      }
    ],
    "neighbors": [
      {
        "device_type": "Coordinator",
        "rx_on_when_idle": "On",
        "relationship": "Sibling",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0x0000",
        "permit_joining": "Unknown",
        "depth": "0",
        "lqi": "66"
      }
    ],
    "endpoint_names": [
      {
        "name": "SMART_PLUG"
      },
      {
        "name": "unknown 97 device_type of 0xa1e0 profile id"
      }
    ],
    "user_given_name": null,
    "device_reg_id": "9fd13e33b8e356d821e1b46cde802803",
    "area_id": "loznice",
    "cluster_details": {
      "1": {
        "device_type": {
          "name": "SMART_PLUG",
          "id": 81
        },
        "profile_id": 260,
        "in_clusters": {
          "0x0004": {
            "endpoint_attribute": "groups",
            "attributes": {},
            "unsupported_attributes": {
              "0xfffe": {
                "attribute_name": "attr_reporting_status"
              }
            }
          },
          "0x0005": {
            "endpoint_attribute": "scenes",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0xef00": {
            "endpoint_attribute": null,
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0000": {
            "endpoint_attribute": "basic",
            "attributes": {
              "0x0001": {
                "attribute_name": "app_version",
                "value": 70
              },
              "0x0004": {
                "attribute_name": "manufacturer",
                "value": "_TZE200_r0jdjrvi"
              },
              "0x0005": {
                "attribute_name": "model",
                "value": "TS0601"
              }
            },
            "unsupported_attributes": {}
          }
        },
        "out_clusters": {
          "0x0019": {
            "endpoint_attribute": "ota",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x000a": {
            "endpoint_attribute": "time",
            "attributes": {},
            "unsupported_attributes": {}
          }
        }
      },
      "242": {
        "device_type": {
          "name": "unknown",
          "id": 97
        },
        "profile_id": 41440,
        "in_clusters": {},
        "out_clusters": {
          "0x0021": {
            "endpoint_attribute": "green_power",
            "attributes": {},
            "unsupported_attributes": {}
          }
        }
      }
    }

With this custom quirk active https://github.com/zigpy/zha-device-handlers/issues/1953#issuecomment-1326805887 I at least have open close and stop buttons active but they do nothing. I also have an inactive Switch.

And with this one https://github.com/zigpy/zha-device-handlers/issues/1953#issuecomment-1324221269 I have same controls active as above but on a press of any of them I get "Failed to call service cover/open_cover. argument of type 'int' is not iterable" notification in HA. I also have active switch in OFF position and when I turn it ON, nothing happens and after few seconds it returns to OFF position. But when I turn it ON and OFF again (before it returns itself), motor starts spin in clockwice direction and it runs until some kind of timeout. But when it runs and I switch it to ON position again it stops. It also stops when I start to run motor manually (making few turns in one or another direction, it react to external movement of curtain and continues that direction) and switch it to ON position. But even if I am able to do something, there are still no records in device Logbook, only "No logbook events found." message. So in this case, "switch ON" is probably command to stop and "switch OFF" is probably command to open or close curtains and this quirk is close on its way to be functional. (I am almost able to make workaround in node-red :D but still missing second direction :( )

I also setup ZHA logging you mentioned before and tried to check my log but it is pretty overcrowded since I have dozens of devices connected to HA so if you specify which part is interresting for you I will try to find it or be able at least to clean it a little bit.

Thanks a lot for all your work.

javicalle commented 1 year ago

Probably we need to map the motion commands. You can look in the logs for your device NMK. It will show as [0x00cc]

javicalle commented 1 year ago

After checking it, I will return to the new implementation, so please use this quirk to test:

ts0601_cover_2.py ```python """Tuya MCU based cover and blinds.""" from typing import Dict, Optional, Union from zigpy.profiles import zha import zigpy.types as t from zigpy.zcl import foundation from zigpy.zcl.clusters.closures import WindowCovering from zigpy.zcl.clusters.general import ( Basic, GreenPowerProxy, Groups, Identify, OnOff, Ota, Scenes, Time, ) from zhaquirks.const import ( DEVICE_TYPE, ENDPOINTS, INPUT_CLUSTERS, MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, ) from zhaquirks.tuya import ( NoManufacturerCluster, TUYA_MCU_COMMAND, TuyaLocalCluster, TuyaManufacturerWindowCover, TuyaManufCluster, TuyaWindowCover, TuyaWindowCoverControl, ) from zhaquirks.tuya.mcu import ( DPToAttributeMapping, TuyaClusterData, TuyaDPType, TuyaMCUCluster, TuyaOnOffNM, ) # Maps OPEN/CLOSE/STOP cover commands from Tuya to Zigbee # https://github.com/zigpy/zigpy/blob/master/zigpy/zcl/clusters/closures.py#L558 # https://developer.tuya.com/en/docs/iot-device-dev/zigbee-curtain-switch-access-standard?id=K9ik6zvra3twv#title-7-DP1%20and%20DP4%20Curtain%20switch%201%20and%202 TUYA2ZB_COMMANDS = { 0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001, } class TuyaWindowCovering(NoManufacturerCluster, WindowCovering, TuyaLocalCluster): """Tuya MCU WindowCovering cluster.""" """Add additional attributes for direction""" attributes = WindowCovering.attributes.copy() attributes.update( { 0xF000: ("curtain_switch", t.enum8, True), # 0: open, 1: stop, 2: close 0xF001: ( "accurate_calibration", t.enum8, True, ), # 0: calibration started, 1: calibration finished 0xF002: ("motor_steering", t.enum8, True), # 0: default, 1: reverse 0xF003: ("travel", t.uint16_t, True), # 30 to 9000 (units of 0.1 seconds) } ) async def command( self, command_id: Union[foundation.GeneralCommand, int, t.uint8_t], *args, manufacturer: Optional[Union[int, t.uint16_t]] = None, expect_reply: bool = True, tsn: Optional[Union[int, t.uint8_t]] = None, ): """Override the default Cluster command.""" # if manufacturer is None: # manufacturer = self.endpoint.device.manufacturer self.debug( "Sending Tuya Cluster Command. Cluster Command is %x, Arguments are %s", command_id, args, ) # (upopen, downclose, stop) if command_id == 0x0002: # ¿0x0003: continue? cluster_data = TuyaClusterData( endpoint_id=self.endpoint.endpoint_id, cluster_attr="curtain_switch", attr_value=TUYA2ZB_COMMANDS[command_id], # convert tuya2zigbee command expect_reply=expect_reply, manufacturer=manufacturer, ) self.endpoint.device.command_bus.listener_event( TUYA_MCU_COMMAND, cluster_data, ) return foundation.GENERAL_COMMANDS[ foundation.GeneralCommand.Default_Response ].schema(command_id=command_id, status=foundation.Status.SUCCESS) # (go_to_lift_percentage) elif command_id in (0x0000, 0x0001, 0x0005): if command_id == 0x0000: lift_value = 100 elif command_id == 0x0001: lift_value = 0 elif command_id == 0x0005: lift_value = args[0] cluster_data = TuyaClusterData( endpoint_id=self.endpoint.endpoint_id, cluster_attr="current_position_lift_percentage", attr_value=lift_value, expect_reply=expect_reply, manufacturer=manufacturer, ) self.endpoint.device.command_bus.listener_event( TUYA_MCU_COMMAND, cluster_data, ) return foundation.GENERAL_COMMANDS[ foundation.GeneralCommand.Default_Response ].schema(command_id=command_id, status=foundation.Status.SUCCESS) # # Custom Command # elif command_id == 0x0006: # ¿doc reference? # tuya_payload.status = args[0] # tuya_payload.tsn = args[1] # tuya_payload.command_id = args[2] # tuya_payload.function = args[3] # tuya_payload.data = args[4] self.warning("Unsupported command_id: %s", command_id) return foundation.GENERAL_COMMANDS[ foundation.GeneralCommand.Default_Response ].schema(command_id=command_id, status=foundation.Status.UNSUP_CLUSTER_COMMAND) class TuyaWindowCoverManufCluster(TuyaMCUCluster): """Tuya with WindowCover data points.""" attributes = TuyaMCUCluster.attributes.copy() attributes.update( { 0x5000: ("backlight_mode", t.enum8, True), # 0: off, 1: on 0x8001: ( "indicator_status", t.enum8, True, ), # 0: status, 1: position, 2: off (¿backlight_mode?) } ) dp_to_attribute: Dict[int, DPToAttributeMapping] = { 1: DPToAttributeMapping( TuyaWindowCovering.ep_attribute, "on_off", dp_type=TuyaDPType.ENUM, ), 3: DPToAttributeMapping( TuyaWindowCovering.ep_attribute, "current_position_lift_percentage", dp_type=TuyaDPType.VALUE, ), # 3: DPToAttributeMapping( # TuyaWindowCovering.ep_attribute, # "accurate_calibration", # dp_type=TuyaDPType.ENUM, # ), # 4: DPToAttributeMapping( # TuyaWindowCovering.ep_attribute, # "on_off", # dp_type=TuyaDPType.ENUM, # endpoint_id=2, # ), # 5: DPToAttributeMapping( # TuyaWindowCovering.ep_attribute, # "current_position_lift_percentage", # dp_type=TuyaDPType.VALUE, # endpoint_id=2, # ), # 6: DPToAttributeMapping( # TuyaWindowCovering.ep_attribute, # "accurate_calibration", # dp_type=TuyaDPType.ENUM, # endpoint_id=2, # ), # 7: DPToAttributeMapping( # TuyaMCUCluster.ep_attribute, # "backlight_mode", # dp_type=TuyaDPType.ENUM, # ), # 8: DPToAttributeMapping( # TuyaWindowCovering.ep_attribute, # "motor_steering", # dp_type=TuyaDPType.ENUM, # ), # 9: DPToAttributeMapping( # TuyaWindowCovering.ep_attribute, # "motor_steering", # dp_type=TuyaDPType.ENUM, # endpoint_id=2, # ), # 10: DPToAttributeMapping( # TuyaWindowCovering.ep_attribute, # "quick_calibration", # dp_type=TuyaDPType.ENUM, # ), # 11: DPToAttributeMapping( # TuyaWindowCovering.ep_attribute, # "quick_calibration", # dp_type=TuyaDPType.ENUM, # endpoint_id=2, # ), # 14: DPToAttributeMapping( # TuyaMCUCluster.ep_attribute, # "indicator_status", # 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", 6: "_dp_2_attr_update", 7: "_dp_2_attr_update", 8: "_dp_2_attr_update", 9: "_dp_2_attr_update", 10: "_dp_2_attr_update", 11: "_dp_2_attr_update", 14: "_dp_2_attr_update", } class TuyaCover0601_GP(TuyaWindowCover): """Tuya blind controller 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=False, # *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False # ) MODELS_INFO: [ ("_TZE200_r0jdjrvi", "TS0601"), ], ENDPOINTS: { 1: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.SMART_PLUG, INPUT_CLUSTERS: [ Basic.cluster_id, Groups.cluster_id, Scenes.cluster_id, TuyaWindowCoverManufCluster.cluster_id, ], OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id], }, 242: { PROFILE_ID: 41440, DEVICE_TYPE: 97, INPUT_CLUSTERS: [], OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id], }, }, } replacement = { ENDPOINTS: { 1: { DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE, INPUT_CLUSTERS: [ Basic.cluster_id, Groups.cluster_id, Scenes.cluster_id, TuyaWindowCoverManufCluster, TuyaOnOffNM, TuyaWindowCovering, ], OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id], }, 242: { PROFILE_ID: 41440, DEVICE_TYPE: 97, INPUT_CLUSTERS: [], OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id], }, } } ```

Most of the functionallity has been commented, I will enable it later.

Is expected that lift_percentage would be updated.

I don't know what switch is this that you refer, any info will be welcomed. Please, enable the debug logs and attach the related ones:

@RowCZ if you can attach the logs related to the switch operation will be helpfull.

RowCZ commented 1 year ago

@javicalle thanks for quick response I used your new quirk and tried to catch relevant logs while tried:

switch ON - switch OFF (motor starts runnik CW) switch OFF - (motor stops) Up - error occurs Stop - error occurs Down - error occurs

rowcz__TZE200_r0jdjrvi_home-assistant.log

With new quirk I also noticed that I have finally some messages in Logbook on device page but there are only messages from yesterday (about 15 hours ago and older) so something in past worked at least that much that made some records there and new quirk was at least able to load that records but wasn't able to made new one.

I hope this info will help. Thanks again

caradas commented 1 year ago

Is expected that lift_percentage would be updated.

I can confirm that lift_percantage is now showing up and updating correctly after the curtain moved.

switch ON - switch OFF (motor starts runnik CW) switch OFF - (motor stops) Up - error occurs Stop - error occurs Down - error occurs

I can't confirm that. The Switch entity does nothing for me.

javicalle commented 1 year ago

I have uppdated this part of the code:

        # (upopen, downclose, stop)
        if command_id == 0x0002:  # ¿0x0003: continue?
            cluster_data = TuyaClusterData(
                endpoint_id=self.endpoint.endpoint_id,
                cluster_attr="curtain_switch",
                attr_value=TUYA2ZB_COMMANDS[command_id],  # convert tuya2zigbee command
                expect_reply=expect_reply,
                manufacturer=manufacturer,
            )

Can you fix it and repeat the tests?

caradas commented 1 year ago

Thanks for the update.

Percentage update is still working. None of the Buttons do anything.

UP:

2022-12-07 22:44:45.632 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] tuya_mcu_command: cluster_data=TuyaClusterData(endpoint_id=1, cluster_attr='current_position_lift_percentage', attr_value=100, expect_reply=True)
2022-12-07 22:44:45.632 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] get_dp_mapping --> found DP: 3
2022-12-07 22:44:45.632 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] from_cluster_data: 3, DPToAttributeMapping(ep_attribute='window_covering', attribute_name='current_position_lift_percentage', dp_type=<TuyaDPType.VALUE: 2>, converter=None, dp_converter=None, endpoint_id=None)
2022-12-07 22:44:45.632 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] ztype: 100
2022-12-07 22:44:45.632 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] from_value: [4, 0, 0, 0, 100]
2022-12-07 22:44:45.632 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] raw: b'\x00\x00\x00d'
2022-12-07 22:44:45.632 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] tuya_command: TuyaCommand(status=0, tsn=79, datapoints=[TuyaDatapointData(dp=3, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x00\x00\x00d', *payload=1677721600))])
2022-12-07 22:44:45.633 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=True, direction=<Direction.Server_to_Client: 0>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False, *is_reply=False), manufacturer=4417, tsn=80, command_id=0, *direction=<Direction.Server_to_Client: 0>, *is_reply=False)
2022-12-07 22:44:45.633 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Sending request: set_data(data=TuyaCommand(status=0, tsn=79, datapoints=[TuyaDatapointData(dp=3, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x00\x00\x00d', *payload=1677721600))]))
2022-12-07 22:44:45.693 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Received ZCL frame: b'\x18P\x0b\x00\x83'
2022-12-07 22:44:45.693 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 1>, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True, *is_reply=True), tsn=80, command_id=11, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2022-12-07 22:44:45.694 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Decoded ZCL frame: TuyaWindowCoverManufCluster:Default_Response(command_id=0, status=<Status.UNSUP_MANUF_CLUSTER_COMMAND: 131>)

Down:

2022-12-07 22:49:00.991 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] tuya_mcu_command: cluster_data=TuyaClusterData(endpoint_id=1, cluster_attr='current_position_lift_percentage', attr_value=0, expect_reply=True)
2022-12-07 22:49:00.991 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] get_dp_mapping --> found DP: 3
2022-12-07 22:49:00.991 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] from_cluster_data: 3, DPToAttributeMapping(ep_attribute='window_covering', attribute_name='current_position_lift_percentage', dp_type=<TuyaDPType.VALUE: 2>, converter=None, dp_converter=None, endpoint_id=None)
2022-12-07 22:49:00.992 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] ztype: 0
2022-12-07 22:49:00.992 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] from_value: [4, 0, 0, 0, 0]
2022-12-07 22:49:00.992 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] raw: b'\x00\x00\x00\x00'
2022-12-07 22:49:00.992 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] tuya_command: TuyaCommand(status=0, tsn=101, datapoints=[TuyaDatapointData(dp=3, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x00\x00\x00\x00', *payload=0))])
2022-12-07 22:49:00.993 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=True, direction=<Direction.Server_to_Client: 0>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False, *is_reply=False), manufacturer=4417, tsn=102, command_id=0, *direction=<Direction.Server_to_Client: 0>, *is_reply=False)
2022-12-07 22:49:00.993 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Sending request: set_data(data=TuyaCommand(status=0, tsn=101, datapoints=[TuyaDatapointData(dp=3, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x00\x00\x00\x00', *payload=0))]))
2022-12-07 22:49:01.058 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Received ZCL frame: b'\x18f\x0b\x00\x83'
2022-12-07 22:49:01.058 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 1>, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True, *is_reply=True), tsn=102, command_id=11, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2022-12-07 22:49:01.058 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Decoded ZCL frame: TuyaWindowCoverManufCluster:Default_Response(command_id=0, status=<Status.UNSUP_MANUF_CLUSTER_COMMAND: 131>)

Stop:

2022-12-07 22:49:52.003 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] tuya_mcu_command: cluster_data=TuyaClusterData(endpoint_id=1, cluster_attr='curtain_switch', attr_value=1, expect_reply=True)
2022-12-07 22:49:52.003 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] from_cluster_data: None, None
2022-12-07 22:49:52.003 WARNING (MainThread) [zigpy.zcl] [0xB579:1:0xef00] No cluster_dp found for 1, curtain_switch
2022-12-07 22:49:52.005 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] tuya_command: None
2022-12-07 22:49:52.005 WARNING (MainThread) [zigpy.zcl] [0xB579:1:0xef00] no MCU command for data TuyaClusterData(endpoint_id=1, cluster_attr='curtain_switch', attr_value=1, expect_reply=True)

EDIT:

Switch On (Rotating CW):

2022-12-07 23:21:45.637 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] tuya_mcu_command: cluster_data=TuyaClusterData(endpoint_id=1, cluster_attr='on_off', attr_value=1, expect_reply=True, manufacturer=-1)
2022-12-07 23:21:45.637 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] get_dp_mapping --> found DP: 1
2022-12-07 23:21:45.638 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] from_cluster_data: {1: DPToAttributeMapping(ep_attribute='window_covering', attribute_name='on_off', dp_type=<TuyaDPType.ENUM: 4>, converter=None, dp_converter=None, endpoint_id=None)}
2022-12-07 23:21:45.638 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] ztype: enum8.undefined_0x01
2022-12-07 23:21:45.638 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] from_value: [1, 1]
2022-12-07 23:21:45.638 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] raw: b'\x01'
2022-12-07 23:21:45.638 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] tuya_commands: [TuyaCommand(status=0, tsn=78, datapoints=[TuyaDatapointData(dp=1, data=TuyaData(dp_type=<TuyaDPType.ENUM: 4>, function=0, raw=b'\x01', *payload=<enum8.undefined_0x01: 1>))])]
2022-12-07 23:21:45.639 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=False, direction=<Direction.Server_to_Client: 0>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False, *is_reply=False), tsn=79, command_id=0, *direction=<Direction.Server_to_Client: 0>, *is_reply=False)
2022-12-07 23:21:45.639 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Sending request: set_data(data=TuyaCommand(status=0, tsn=78, datapoints=[TuyaDatapointData(dp=1, data=TuyaData(dp_type=<TuyaDPType.ENUM: 4>, function=0, raw=b'\x01', *payload=<enum8.undefined_0x01: 1>))]))
2022-12-07 23:21:45.682 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Received ZCL frame: b'\x18O\x0b\x00\x00'
2022-12-07 23:21:45.683 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 1>, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True, *is_reply=True), tsn=79, command_id=11, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2022-12-07 23:21:45.683 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Decoded ZCL frame: TuyaWindowCoverManufCluster:Default_Response(command_id=0, status=<Status.SUCCESS: 0>)
2022-12-07 23:21:45.725 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Received ZCL frame: b'\x19\xe6\x01\x00N\x01\x04\x00\x01\x01'
2022-12-07 23:21:45.725 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 1>, disable_default_response=1, reserved=0, *is_cluster=True, *is_general=False, *is_reply=True), tsn=230, command_id=1, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2022-12-07 23:21:45.726 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Decoded ZCL frame: TuyaWindowCoverManufCluster:get_data(data=TuyaCommand(status=0, tsn=78, datapoints=[TuyaDatapointData(dp=1, data=TuyaData(dp_type=<TuyaDPType.ENUM: 4>, function=0, raw=b'\x01', *payload=<enum8.undefined_0x01: 1>))]))
2022-12-07 23:21:45.726 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Received command 0x01 (TSN 230): get_data(data=TuyaCommand(status=0, tsn=78, datapoints=[TuyaDatapointData(dp=1, data=TuyaData(dp_type=<TuyaDPType.ENUM: 4>, function=0, raw=b'\x01', *payload=<enum8.undefined_0x01: 1>))]))

Off (Stop Rotating CW):

2022-12-07 23:21:45.637 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] tuya_mcu_command: cluster_data=TuyaClusterData(endpoint_id=1, cluster_attr='on_off', attr_value=1, expect_reply=True, manufacturer=-1)
2022-12-07 23:21:45.637 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] get_dp_mapping --> found DP: 1
2022-12-07 23:21:45.638 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] from_cluster_data: {1: DPToAttributeMapping(ep_attribute='window_covering', attribute_name='on_off', dp_type=<TuyaDPType.ENUM: 4>, converter=None, dp_converter=None, endpoint_id=None)}
2022-12-07 23:21:45.638 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] ztype: enum8.undefined_0x01
2022-12-07 23:21:45.638 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] from_value: [1, 1]
2022-12-07 23:21:45.638 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] raw: b'\x01'
2022-12-07 23:21:45.638 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] tuya_commands: [TuyaCommand(status=0, tsn=78, datapoints=[TuyaDatapointData(dp=1, data=TuyaData(dp_type=<TuyaDPType.ENUM: 4>, function=0, raw=b'\x01', *payload=<enum8.undefined_0x01: 1>))])]
2022-12-07 23:21:45.639 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=False, direction=<Direction.Server_to_Client: 0>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False, *is_reply=False), tsn=79, command_id=0, *direction=<Direction.Server_to_Client: 0>, *is_reply=False)
2022-12-07 23:21:45.639 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Sending request: set_data(data=TuyaCommand(status=0, tsn=78, datapoints=[TuyaDatapointData(dp=1, data=TuyaData(dp_type=<TuyaDPType.ENUM: 4>, function=0, raw=b'\x01', *payload=<enum8.undefined_0x01: 1>))]))
2022-12-07 23:21:45.682 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Received ZCL frame: b'\x18O\x0b\x00\x00'
2022-12-07 23:21:45.683 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 1>, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True, *is_reply=True), tsn=79, command_id=11, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2022-12-07 23:21:45.683 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Decoded ZCL frame: TuyaWindowCoverManufCluster:Default_Response(command_id=0, status=<Status.SUCCESS: 0>)
2022-12-07 23:21:45.725 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Received ZCL frame: b'\x19\xe6\x01\x00N\x01\x04\x00\x01\x01'
2022-12-07 23:21:45.725 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 1>, disable_default_response=1, reserved=0, *is_cluster=True, *is_general=False, *is_reply=True), tsn=230, command_id=1, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2022-12-07 23:21:45.726 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Decoded ZCL frame: TuyaWindowCoverManufCluster:get_data(data=TuyaCommand(status=0, tsn=78, datapoints=[TuyaDatapointData(dp=1, data=TuyaData(dp_type=<TuyaDPType.ENUM: 4>, function=0, raw=b'\x01', *payload=<enum8.undefined_0x01: 1>))]))
2022-12-07 23:21:45.726 DEBUG (MainThread) [zigpy.zcl] [0xB579:1:0xef00] Received command 0x01 (TSN 230): get_data(data=TuyaCommand(status=0, tsn=78, datapoints=[TuyaDatapointData(dp=1, data=TuyaData(dp_type=<TuyaDPType.ENUM: 4>, function=0, raw=b'\x01', *payload=<enum8.undefined_0x01: 1>))]))
RowCZ commented 1 year ago

@javicalle hi and thanks for the update I modified the quirk and here is the results

switch is without any change switch ON - switch OFF (motor starts runnig CW) switch OFF - (motor stops)

Up - no error this time, in log book I can see message that Cover is opening but no movement on motor (button change to inactive state) Stop - failed to call service error occurs as before Up - no error this time, in log book I can see message that Cover is closing but no movement on motor (button change to inactive state)

log: rowcz__TZE200_r0jdjrvi_home-assistant_2022-12-07.log

Here is a also a part of the screen with controls and logbook image

caradas commented 1 year ago

Good News i got the arrows working with the following:

"""Tuya MCU based cover and blinds."""
from typing import Dict, Optional, Union

from zigpy.profiles import zha
import zigpy.types as t
from zigpy.zcl import foundation
from zigpy.zcl.clusters.closures import WindowCovering
from zigpy.zcl.clusters.general import (
    Basic,
    GreenPowerProxy,
    Groups,
    Identify,
    Ota,
    Scenes,
    Time,
)

from zhaquirks.const import (
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
)
from zhaquirks.tuya import (
    NoManufacturerCluster,
    TUYA_MCU_COMMAND,
    TuyaLocalCluster,
    TuyaManufacturerWindowCover,
    TuyaManufCluster,
    TuyaWindowCover,
    TuyaWindowCoverControl,
)
from zhaquirks.tuya.mcu import (
    DPToAttributeMapping,
    TuyaClusterData,
    TuyaDPType,
    TuyaMCUCluster,
)

# Maps OPEN/CLOSE/STOP cover commands from Tuya to Zigbee
# https://github.com/zigpy/zigpy/blob/master/zigpy/zcl/clusters/closures.py#L558
# https://developer.tuya.com/en/docs/iot-device-dev/zigbee-curtain-switch-access-standard?id=K9ik6zvra3twv#title-7-DP1%20and%20DP4%20Curtain%20switch%201%20and%202
TUYA2ZB_COMMANDS = {
    0x0000: 0x0000,
    0x0001: 0x0002,
    0x0002: 0x0001,
}

class TuyaWindowCovering(NoManufacturerCluster, WindowCovering, TuyaLocalCluster):
    """Tuya MCU WindowCovering cluster."""

    """Add additional attributes for direction"""
    attributes = WindowCovering.attributes.copy()
    attributes.update(
        {
            0xF000: ("curtain_switch", t.enum8, True),  # 0: open, 1: stop, 2: close
            0xF001: ("accurate_calibration", t.enum8, True),  # 0: calibration started, 1: calibration finished
            0xF002: ("motor_steering", t.enum8, True),  # 0: default, 1: reverse
            0xF003: ("travel", t.uint16_t, True),  # 30 to 9000 (units of 0.1 seconds)
        }
    )

    async def command(
        self,
        command_id: Union[foundation.GeneralCommand, int, t.uint8_t],
        *args,
        manufacturer: Optional[Union[int, t.uint16_t]] = None,
        expect_reply: bool = True,
        tsn: Optional[Union[int, t.uint8_t]] = None,
    ):
        """Override the default Cluster command."""

        # if manufacturer is None:
        #     manufacturer = self.endpoint.device.manufacturer

        self.debug(
            "Sending Tuya Cluster Command. Cluster Command is %x, Arguments are %s",
            command_id,
            args,
        )

        # (upopen, downclose, stop)
        if command_id in (0x0002, 0x0000, 0x0001):  # ¿0x0003: continue?
            cluster_data = TuyaClusterData(
                endpoint_id=self.endpoint.endpoint_id,
                cluster_attr="curtain_switch",
                attr_value=TUYA2ZB_COMMANDS[command_id],  # convert tuya2zigbee command
                expect_reply=expect_reply,
                manufacturer=-1,
            )
            self.endpoint.device.command_bus.listener_event(
                TUYA_MCU_COMMAND,
                cluster_data,
            )
            return foundation.GENERAL_COMMANDS[
                foundation.GeneralCommand.Default_Response
            ].schema(command_id=command_id, status=foundation.Status.SUCCESS)

        # (go_to_lift_percentage)
        elif command_id == 0x0005:
            lift_value = args[0]

            cluster_data = TuyaClusterData(
                endpoint_id=self.endpoint.endpoint_id,
                cluster_attr="current_position_lift_percentage",
                attr_value=lift_value,
                expect_reply=expect_reply,
                manufacturer=-1,
            )
            self.endpoint.device.command_bus.listener_event(
                TUYA_MCU_COMMAND,
                cluster_data,
            )
            return foundation.GENERAL_COMMANDS[
                foundation.GeneralCommand.Default_Response
            ].schema(command_id=command_id, status=foundation.Status.SUCCESS)

        # # Custom Command
        # elif command_id == 0x0006:  # ¿doc reference?
        #     tuya_payload.status = args[0]
        #     tuya_payload.tsn = args[1]
        #     tuya_payload.command_id = args[2]
        #     tuya_payload.function = args[3]
        #     tuya_payload.data = args[4]

        self.warning("Unsupported command_id: %s", command_id)
        return foundation.GENERAL_COMMANDS[
            foundation.GeneralCommand.Default_Response
        ].schema(command_id=command_id, status=foundation.Status.UNSUP_CLUSTER_COMMAND)

class TuyaWindowCoverManufCluster(TuyaMCUCluster):
    """Tuya with WindowCover data points."""

    attributes = TuyaMCUCluster.attributes.copy()
    attributes.update(
        {
            0x5000: ("backlight_mode", t.enum8, True),  # 0: off, 1: on
            0x8001: ("indicator_status", t.enum8, True),  # 0: status, 1: position, 2: off (¿backlight_mode?)
        }
    )

    dp_to_attribute: Dict[int, DPToAttributeMapping] = {
        1: DPToAttributeMapping(
            TuyaWindowCovering.ep_attribute,
            "curtain_switch",
            dp_type=TuyaDPType.ENUM,
        ),
        3: DPToAttributeMapping(
            TuyaWindowCovering.ep_attribute,
            "current_position_lift_percentage",
            dp_type=TuyaDPType.VALUE,
        ),
        # 3: DPToAttributeMapping(
        #     TuyaWindowCovering.ep_attribute,
        #     "accurate_calibration",
        #     dp_type=TuyaDPType.ENUM,
        # ),
        # 4: DPToAttributeMapping(
        #     TuyaWindowCovering.ep_attribute,
        #     "on_off",
        #     dp_type=TuyaDPType.ENUM,
        #     endpoint_id=2,
        # ),
        # 5: DPToAttributeMapping(
        #     TuyaWindowCovering.ep_attribute,
        #     "current_position_lift_percentage",
        #     dp_type=TuyaDPType.VALUE,
        #     endpoint_id=2,
        # ),
        # 6: DPToAttributeMapping(
        #     TuyaWindowCovering.ep_attribute,
        #     "accurate_calibration",
        #     dp_type=TuyaDPType.ENUM,
        #     endpoint_id=2,
        # ),
        # 7: DPToAttributeMapping(
        #     TuyaMCUCluster.ep_attribute,
        #     "backlight_mode",
        #     dp_type=TuyaDPType.ENUM,
        # ),
        # 8: DPToAttributeMapping(
        #     TuyaWindowCovering.ep_attribute,
        #     "motor_steering",
        #     dp_type=TuyaDPType.ENUM,
        # ),
        # 9: DPToAttributeMapping(
        #     TuyaWindowCovering.ep_attribute,
        #     "motor_steering",
        #     dp_type=TuyaDPType.ENUM,
        #     endpoint_id=2,
        # ),
        # 10: DPToAttributeMapping(
        #     TuyaWindowCovering.ep_attribute,
        #     "quick_calibration",
        #     dp_type=TuyaDPType.ENUM,
        # ),
        # 11: DPToAttributeMapping(
        #     TuyaWindowCovering.ep_attribute,
        #     "quick_calibration",
        #     dp_type=TuyaDPType.ENUM,
        #     endpoint_id=2,
        # ),
        # 14: DPToAttributeMapping(
        #     TuyaMCUCluster.ep_attribute,
        #     "indicator_status",
        #     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",
        6: "_dp_2_attr_update",
        7: "_dp_2_attr_update",
        8: "_dp_2_attr_update",
        9: "_dp_2_attr_update",
        10: "_dp_2_attr_update",
        11: "_dp_2_attr_update",
        14: "_dp_2_attr_update",
    }

class TuyaCover0601_GP(TuyaWindowCover):
    """Tuya blind controller device."""
    signature = {
        # "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
        # )
        MODELS_INFO: [
            ("_TZE200_r0jdjrvi", "TS0601"),
        ],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaWindowCoverManufCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaWindowCoverManufCluster,
                    TuyaWindowCovering,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        }
    }

Key was to set following in commands:

manufacturer=-1,

Unfortunally the percentage slider is only a display but doesn't turn the motor: Log:

2022-12-08 00:48:27.526 DEBUG (MainThread) [zigpy.zcl] [0x50CE:1:0xef00] tuya_mcu_command: cluster_data=TuyaClusterData(endpoint_id=1, cluster_attr='current_position_lift_percentage', attr_value=75, expect_reply=True, manufacturer=-1)
2022-12-08 00:48:27.526 DEBUG (MainThread) [zigpy.zcl] [0x50CE:1:0xef00] get_dp_mapping --> found DP: 3
2022-12-08 00:48:27.526 DEBUG (MainThread) [zigpy.zcl] [0x50CE:1:0xef00] from_cluster_data: {3: DPToAttributeMapping(ep_attribute='window_covering', attribute_name='current_position_lift_percentage', dp_type=<TuyaDPType.VALUE: 2>, converter=None, dp_converter=None, endpoint_id=None)}
2022-12-08 00:48:27.527 DEBUG (MainThread) [zigpy.zcl] [0x50CE:1:0xef00] ztype: 75
2022-12-08 00:48:27.527 DEBUG (MainThread) [zigpy.zcl] [0x50CE:1:0xef00] from_value: [4, 0, 0, 0, 75]
2022-12-08 00:48:27.527 DEBUG (MainThread) [zigpy.zcl] [0x50CE:1:0xef00] raw: b'K\x00\x00\x00'
2022-12-08 00:48:27.527 DEBUG (MainThread) [zigpy.zcl] [0x50CE:1:0xef00] tuya_commands: [TuyaCommand(status=0, tsn=72, datapoints=[TuyaDatapointData(dp=3, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'K\x00\x00\x00', *payload=75))])]
2022-12-08 00:48:27.529 DEBUG (MainThread) [zigpy.zcl] [0x50CE:1:0xef00] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=False, direction=<Direction.Server_to_Client: 0>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False, *is_reply=False), tsn=73, command_id=0, *direction=<Direction.Server_to_Client: 0>, *is_reply=False)
2022-12-08 00:48:27.529 DEBUG (MainThread) [zigpy.zcl] [0x50CE:1:0xef00] Sending request: set_data(data=TuyaCommand(status=0, tsn=72, datapoints=[TuyaDatapointData(dp=3, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'K\x00\x00\x00', *payload=75))]))
2022-12-08 00:48:27.596 DEBUG (MainThread) [zigpy.zcl] [0x50CE:1:0xef00] Received ZCL frame: b'\x18I\x0b\x00\x00'
2022-12-08 00:48:27.596 DEBUG (MainThread) [zigpy.zcl] [0x50CE:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 1>, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True, *is_reply=True), tsn=73, command_id=11, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2022-12-08 00:48:27.597 DEBUG (MainThread) [zigpy.zcl] [0x50CE:1:0xef00] Decoded ZCL frame: TuyaWindowCoverManufCluster:Default_Response(command_id=0, status=<Status.SUCCESS: 0>)
RowCZ commented 1 year ago

@caradas Nice! It works for me as well even Stop button works now (but still causes error). Switch become inactive (but is not needed anymore) And I have no percentage slider at all 😮 is there way how to add it?

image

Here is log from version that cardas provided: rowcz__TZE200_r0jdjrvi_home-assistant_2022-12-07-2.log

caradas commented 1 year ago

@RowCZ my usual way after changing the quirk was:

  1. Delete Device from Zigbee network.
  2. Delete pychache folder from qirk location
  3. Restart HA
  4. Add Device again

The slider is "hidden" in the details of the controls: grafik

RowCZ commented 1 year ago

weird, I removed device, delete pycache, restarted HA and paired again but I still don't have a progress bar (that mysterious switch is gone now)

image image

javicalle commented 1 year ago

A lot of updates here.

The switch wasn't really necessary, just an attempt to understand things. Once resolved it is not necessary and should not return.

That manufacturer=-1 is the same that would try with the NoManufacturerCluster not sure why isn't working. You can get the same with manufacturer=foundation.ZCLHeader.NO_MANUFACTURER_ID.

The lift percentage is mapped against the DP_3. The device don't complain about it but it can be that is not the good one. According to Z2M it could be the DP_2, so I would try to replace the dp_to_attribute mapping from 3 to 2.

Let's see if we can fix the cover functions and then I try to see what happens to the missing slider.

RowCZ commented 1 year ago

@javicalle I am bit confused, I am not sure if I uderstand it right, I changed it here from 3 to 2 but with no effect

dp_to_attribute: Dict[int, DPToAttributeMapping] = {
        1: DPToAttributeMapping(
            TuyaWindowCovering.ep_attribute,
            "curtain_switch",
            dp_type=TuyaDPType.ENUM,
        ),
        2: DPToAttributeMapping(
            TuyaWindowCovering.ep_attribute,
            "current_position_lift_percentage",
            dp_type=TuyaDPType.VALUE,
        ),
bezmi commented 1 year ago

I've only just started with the zigbee stuff, but upon testing zigbee2mqtt, it appears that all of the buttons as well as position control work pretty well. For position control to work, I had to first set endstop positions by letting the motor move in one direction and physically stopping rotation to signal the end of the track. Repeat for the other direction and the position slider starts working.

Is there any way to bring the config from zigbee2mqtt into the custom quirk here so we can get all of the info required to get this working with zha?

RowCZ commented 1 year ago

... I had to first set endstop positions by letting the motor move in one direction and physically stopping rotation to signal the end of the track. Repeat for the other direction and the position slider starts working...

That can be the reason why I have no slider, I didn't bother with instalation since I was unable to make it work at all. :D

bezmi commented 1 year ago

clarification: this was position control with zigbee2mqtt. ~Haven't been able to reliably get the slider to show up in zha.~

Edit: using the quirk by cardas, the slider does indeed show up once the endstops have been configured. To do this:

  1. Manually spin the motor so it starts moving
  2. Force it to stop, as if the curtain is hitting the end of the track
  3. repeat steps 1 and 2 for the other rotational direction

The position of the slider will update if you stop the motor, but there is no control via the slider yet.

sid12345678910 commented 1 year ago

Good News i got the arrows working with the following:

so i have this model _TZE200_65moe6rh

This code works strangely with mine. Mine came with a remote. It seems the code works only if the motor doesn't hit its "endstops" Once is it hits the endstop HA stops responding. But if its in the middle I can control the motor in HA. All the commands work Up, Down and stop but only if its in-between both endstops. Once it hits the endstop nothing responds...

Also the slider reports the correct position but I cant move it around.

Edit: I think i need to switch the command directions in the code. Anyone have any idea how to do that?

EDIT2 lol Fixed changed code to TUYA2ZB_COMMANDS = { 0x0000: 0x0002, 0x0001: 0x0000, 0x0002: 0x0001, }

kolmakova commented 1 year ago

@javicalle Hi, I've got another Tuya curtain motor with the same signature, tried the quirk here, buttons work, but state and controls are inverted. Slider doesn't work. Using latest HA and this quirk. Here is the log of slider:

2023-01-30 20:28:41.799 DEBUG (MainThread) [zigpy.zcl] [0x23F6:1:0x0102] Sending Tuya Cluster Command. Cluster Command is 5, Arguments are (48,)
2023-01-30 20:28:41.800 DEBUG (MainThread) [zigpy.zcl] [0x23F6:1:0xef00] tuya_mcu_command: cluster_data=TuyaClusterData(endpoint_id=1, cluster_attr='current_position_lift_percentage', attr_value=48, expect_reply=True)
2023-01-30 20:28:41.801 DEBUG (MainThread) [zigpy.zcl] [0x23F6:1:0xef00] get_dp_mapping --> found DP: 3
2023-01-30 20:28:41.801 DEBUG (MainThread) [zigpy.zcl] [0x23F6:1:0xef00] from_cluster_data: {3: DPToAttributeMapping(ep_attribute='window_covering', attribute_name='current_position_lift_percentage', dp_type=<TuyaDPType.VALUE: 2>, converter=None, dp_converter=None, endpoint_id=None)}
2023-01-30 20:28:41.802 DEBUG (MainThread) [zigpy.zcl] [0x23F6:1:0xef00] value: 48
2023-01-30 20:28:41.803 DEBUG (MainThread) [zigpy.zcl] [0x23F6:1:0xef00] raw: b'\x00\x00\x000'
2023-01-30 20:28:41.803 DEBUG (MainThread) [zigpy.zcl] [0x23F6:1:0xef00] tuya_commands: [TuyaCommand(status=0, tsn=10, datapoints=[TuyaDatapointData(dp=3, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x00\x00\x000', *payload=48))])]
2023-01-30 20:28:41.809 WARNING (MainThread) [zigpy.util] Error calling listener <bound method TuyaMCUCluster.tuya_mcu_command of <ts0601_cover.TuyaWindowCoverManufCluster object at 0xa3fb6c10>> with args (TuyaClusterData(endpoint_id=1, cluster_attr='current_position_lift_percentage', attr_value=48, expect_reply=True),): TypeError('getattr(): attribute name must be string')
2023-01-30 20:28:41.812 DEBUG (MainThread) [zigpy.util] Error calling listener <bound method TuyaMCUCluster.tuya_mcu_command of <ts0601_cover.TuyaWindowCoverManufCluster object at 0xa3fb6c10>> with args (TuyaClusterData(endpoint_id=1, cluster_attr='current_position_lift_percentage', attr_value=48, expect_reply=True),)
Traceback (most recent call last):
File "/usr/local/lib/python3.10/site-packages/zigpy/util.py", line 55, in listener_event
result.append(method(*args))
File "/usr/local/lib/python3.10/site-packages/zhaquirks/tuya/mcu/__init__.py", line 289, in tuya_mcu_command
cluster = getattr(endpoint, cluster_data.cluster_name)
TypeError: getattr(): attribute name must be string
javicalle commented 1 year ago

That quirk is a little old now. You can try adding the cluster_name in the TuyaClusterData, more or less like this:

        # (upopen, downclose, stop)
        if command_id in (0x0002, 0x0000, 0x0001):  # ¿0x0003: continue?
            cluster_data = TuyaClusterData(
                endpoint_id=self.endpoint.endpoint_id,
                cluster_name=TuyaMCUCluster.ep_attribute,
                cluster_attr="curtain_switch",
                attr_value=TUYA2ZB_COMMANDS[command_id],  # convert tuya2zigbee command
                expect_reply=expect_reply,
                manufacturer=-1,
            )

and

        # (go_to_lift_percentage)
        elif command_id == 0x0005:
            lift_value = args[0]

            cluster_data = TuyaClusterData(
                endpoint_id=self.endpoint.endpoint_id,
                cluster_name=TuyaMCUCluster.ep_attribute,
                cluster_attr="current_position_lift_percentage",
                attr_value=lift_value,
                expect_reply=expect_reply,
                manufacturer=-1,
            )

IIRC that quirk is very incomplete

kolmakova commented 1 year ago

@javicalle Thanks! I've fixed a slider control by changing current_position_lift_percentage DP from 3 to 2 as in Tuya documentation and added your solution to fix TypeError: getattr(): attribute name must be string, so slider is working now. Here's the quirk (for my _TZE200_nogaemzt). Don't forget to add another model name to the MODELS_INFO.

ts0601_cover.py ```py """Tuya MCU based cover and blinds.""" from typing import Dict, Optional, Union from zigpy.profiles import zha import zigpy.types as t from zigpy.zcl import foundation from zigpy.zcl.clusters.closures import WindowCovering from zigpy.zcl.clusters.general import ( Basic, GreenPowerProxy, Groups, Identify, Ota, Scenes, Time, ) from zhaquirks.const import ( DEVICE_TYPE, ENDPOINTS, INPUT_CLUSTERS, MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, ) from zhaquirks.tuya import ( NoManufacturerCluster, TUYA_MCU_COMMAND, TuyaLocalCluster, TuyaManufacturerWindowCover, TuyaManufCluster, TuyaWindowCover, TuyaWindowCoverControl, ) from zhaquirks.tuya.mcu import ( DPToAttributeMapping, TuyaClusterData, TuyaDPType, TuyaMCUCluster, ) # Maps OPEN/CLOSE/STOP cover commands from Tuya to Zigbee # https://github.com/zigpy/zigpy/blob/master/zigpy/zcl/clusters/closures.py#L558 # https://developer.tuya.com/en/docs/iot-device-dev/zigbee-curtain-switch-access-standard?id=K9ik6zvra3twv#title-7-DP1%20and%20DP4%20Curtain%20switch%201%20and%202 TUYA2ZB_COMMANDS = { 0x0000: 0x0002, 0x0001: 0x0000, 0x0002: 0x0001, } class TuyaWindowCovering(NoManufacturerCluster, WindowCovering, TuyaLocalCluster): """Tuya MCU WindowCovering cluster.""" """Add additional attributes for direction""" attributes = WindowCovering.attributes.copy() attributes.update( { 0xF000: ("curtain_switch", t.enum8, True), # 0: open, 1: stop, 2: close 0xF001: ("accurate_calibration", t.enum8, True), # 0: calibration started, 1: calibration finished 0xF002: ("motor_steering", t.enum8, True), # 0: default, 1: reverse 0xF003: ("travel", t.uint16_t, True), # 30 to 9000 (units of 0.1 seconds) } ) async def command( self, command_id: Union[foundation.GeneralCommand, int, t.uint8_t], *args, manufacturer: Optional[Union[int, t.uint16_t]] = None, expect_reply: bool = True, tsn: Optional[Union[int, t.uint8_t]] = None, ): """Override the default Cluster command.""" # if manufacturer is None: # manufacturer = self.endpoint.device.manufacturer self.debug( "Sending Tuya Cluster Command. Cluster Command is %x, Arguments are %s", command_id, args, ) # (upopen, downclose, stop) if command_id in (0x0002, 0x0000, 0x0001): # ¿0x0003: continue? cluster_data = TuyaClusterData( endpoint_id=self.endpoint.endpoint_id, cluster_name=TuyaMCUCluster.ep_attribute, cluster_attr="curtain_switch", attr_value=TUYA2ZB_COMMANDS[command_id], # convert tuya2zigbee command expect_reply=expect_reply, manufacturer=-1, ) self.endpoint.device.command_bus.listener_event( TUYA_MCU_COMMAND, cluster_data, ) return foundation.GENERAL_COMMANDS[ foundation.GeneralCommand.Default_Response ].schema(command_id=command_id, status=foundation.Status.SUCCESS) # (go_to_lift_percentage) elif command_id == 0x0005: lift_value = args[0] cluster_data = TuyaClusterData( endpoint_id=self.endpoint.endpoint_id, cluster_name=TuyaMCUCluster.ep_attribute, cluster_attr="current_position_lift_percentage", attr_value=lift_value, expect_reply=expect_reply, manufacturer=-1, ) self.endpoint.device.command_bus.listener_event( TUYA_MCU_COMMAND, cluster_data, ) return foundation.GENERAL_COMMANDS[ foundation.GeneralCommand.Default_Response ].schema(command_id=command_id, status=foundation.Status.SUCCESS) # # Custom Command # elif command_id == 0x0006: # ¿doc reference? # tuya_payload.status = args[0] # tuya_payload.tsn = args[1] # tuya_payload.command_id = args[2] # tuya_payload.function = args[3] # tuya_payload.data = args[4] self.warning("Unsupported command_id: %s", command_id) return foundation.GENERAL_COMMANDS[ foundation.GeneralCommand.Default_Response ].schema(command_id=command_id, status=foundation.Status.UNSUP_CLUSTER_COMMAND) class TuyaWindowCoverManufCluster(TuyaMCUCluster): """Tuya with WindowCover data points.""" attributes = TuyaMCUCluster.attributes.copy() attributes.update( { 0x5000: ("backlight_mode", t.enum8, True), # 0: off, 1: on 0x8001: ("indicator_status", t.enum8, True), # 0: status, 1: position, 2: off (¿backlight_mode?) } ) dp_to_attribute: Dict[int, DPToAttributeMapping] = { 1: DPToAttributeMapping( TuyaWindowCovering.ep_attribute, "curtain_switch", dp_type=TuyaDPType.ENUM, ), 2: DPToAttributeMapping( TuyaWindowCovering.ep_attribute, "current_position_lift_percentage", dp_type=TuyaDPType.VALUE, ), # 3: DPToAttributeMapping( # TuyaWindowCovering.ep_attribute, # "accurate_calibration", # dp_type=TuyaDPType.ENUM, # ), # 4: DPToAttributeMapping( # TuyaWindowCovering.ep_attribute, # "on_off", # dp_type=TuyaDPType.ENUM, # endpoint_id=2, # ), # 5: DPToAttributeMapping( # TuyaWindowCovering.ep_attribute, # "current_position_lift_percentage", # dp_type=TuyaDPType.VALUE, # endpoint_id=2, # ), # 6: DPToAttributeMapping( # TuyaWindowCovering.ep_attribute, # "accurate_calibration", # dp_type=TuyaDPType.ENUM, # endpoint_id=2, # ), # 7: DPToAttributeMapping( # TuyaMCUCluster.ep_attribute, # "backlight_mode", # dp_type=TuyaDPType.ENUM, # ), # 8: DPToAttributeMapping( # TuyaWindowCovering.ep_attribute, # "motor_steering", # dp_type=TuyaDPType.ENUM, # ), # 9: DPToAttributeMapping( # TuyaWindowCovering.ep_attribute, # "motor_steering", # dp_type=TuyaDPType.ENUM, # endpoint_id=2, # ), # 10: DPToAttributeMapping( # TuyaWindowCovering.ep_attribute, # "quick_calibration", # dp_type=TuyaDPType.ENUM, # ), # 11: DPToAttributeMapping( # TuyaWindowCovering.ep_attribute, # "quick_calibration", # dp_type=TuyaDPType.ENUM, # endpoint_id=2, # ), # 14: DPToAttributeMapping( # TuyaMCUCluster.ep_attribute, # "indicator_status", # 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", 6: "_dp_2_attr_update", 7: "_dp_2_attr_update", 8: "_dp_2_attr_update", 9: "_dp_2_attr_update", 10: "_dp_2_attr_update", 11: "_dp_2_attr_update", 14: "_dp_2_attr_update", } class TuyaCover0601_GP(TuyaWindowCover): tuya_cover_inverted_by_default = True """Tuya blind controller 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=False, # *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False # ) MODELS_INFO: [ ("_TZE200_nogaemzt", "TS0601"), ], ENDPOINTS: { 1: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.SMART_PLUG, INPUT_CLUSTERS: [ Basic.cluster_id, Groups.cluster_id, Scenes.cluster_id, TuyaWindowCoverManufCluster.cluster_id, ], OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id], }, 242: { PROFILE_ID: 41440, DEVICE_TYPE: 97, INPUT_CLUSTERS: [], OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id], }, }, } replacement = { ENDPOINTS: { 1: { DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE, INPUT_CLUSTERS: [ Basic.cluster_id, Groups.cluster_id, Scenes.cluster_id, TuyaWindowCoverManufCluster, TuyaWindowCovering, ], OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id], }, 242: { PROFILE_ID: 41440, DEVICE_TYPE: 97, INPUT_CLUSTERS: [], OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id], }, } } ```

Seems like the only problem now is that controls have the right direction, but the curtains state and slider control are inverted. To open curtains via slider, I need to move a slider to the 0 so state results in Closed (and vice versa). And if the curtain state is Closed (but it's actually Open), Close button is inactive. Also, commands (buttons) don't result in updating a slider value and curtain state (maybe this doesn't relate to the invertion).

Tried to add tuya_cover_inverted_by_default = True to the TuyaCover0601_GP but no result. Any ideas?

javicalle commented 1 year ago

If you have a physical remote for that cover try to reverse the motor spin according to the manufacturer. If don't, try updating the motor_steering attribute from the cluster TuyaWindowCovering. Switch between 0 and 1 values to test.

Drmatterpl commented 1 year ago

Hi

That can be the reason why I have no slider, I didn't bother with instalation since I was unable to make it work at all. :D

@RowCZ can you share your latest quirk code? I have spend a looooot of time and it seems that this is the only quirk that works with my motor - the one by @caradas

Dextrik commented 1 year ago

Hi, @Drmatterpl I can share mine, everything is working, but i don't think so this quirk it's optimal.

ts0601_cover.py
``` """Tuya MCU based cover and blinds.""" from typing import Dict, Optional, Union from zigpy.profiles import zha import zigpy.types as t from zigpy.zcl import foundation from zigpy.zcl.clusters.closures import WindowCovering from zigpy.zcl.clusters.general import ( Basic, GreenPowerProxy, Groups, Identify, Ota, Scenes, Time, ) from zhaquirks.const import ( DEVICE_TYPE, ENDPOINTS, INPUT_CLUSTERS, MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, ) from zhaquirks.tuya import ( NoManufacturerCluster, TUYA_MCU_COMMAND, TuyaLocalCluster, TuyaManufacturerWindowCover, TuyaManufCluster, TuyaWindowCover, TuyaWindowCoverControl, ) from zhaquirks.tuya.mcu import ( DPToAttributeMapping, TuyaClusterData, TuyaDPType, TuyaMCUCluster, ) # Maps OPEN/CLOSE/STOP cover commands from Tuya to Zigbee # https://github.com/zigpy/zigpy/blob/master/zigpy/zcl/clusters/closures.py#L558 # https://developer.tuya.com/en/docs/iot-device-dev/zigbee-curtain-switch-access-standard?id=K9ik6zvra3twv#title-7-DP1%20and%20DP4%20Curtain%20switch%201%20and%202 TUYA2ZB_COMMANDS = { 0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001, } class TuyaWindowCovering(NoManufacturerCluster, WindowCovering, TuyaLocalCluster): """Tuya MCU WindowCovering cluster.""" """Add additional attributes for direction""" attributes = WindowCovering.attributes.copy() attributes.update( { 0xF000: ("curtain_switch", t.enum8, True), # 0: open, 1: stop, 2: close 0xF001: ("accurate_calibration", t.enum8, True), # 0: calibration started, 1: calibration finished 0xF002: ("motor_steering", t.enum8, True), # 0: default, 1: reverse 0xF003: ("travel", t.uint16_t, True), # 30 to 9000 (units of 0.1 seconds) } ) async def command( self, command_id: Union[foundation.GeneralCommand, int, t.uint8_t], *args, manufacturer: Optional[Union[int, t.uint16_t]] = None, expect_reply: bool = True, tsn: Optional[Union[int, t.uint8_t]] = None, ): """Override the default Cluster command.""" # if manufacturer is None: # manufacturer = self.endpoint.device.manufacturer self.debug( "Sending Tuya Cluster Command. Cluster Command is %x, Arguments are %s", command_id, args, ) # (upopen, downclose, stop) if command_id in (0x0002, 0x0000, 0x0001): # ¿0x0003: continue? cluster_data = TuyaClusterData( endpoint_id=self.endpoint.endpoint_id, cluster_name=self.ep_attribute, cluster_attr="curtain_switch", attr_value=TUYA2ZB_COMMANDS[command_id], # convert tuya2zigbee command expect_reply=expect_reply, manufacturer=-1, ) self.endpoint.device.command_bus.listener_event( TUYA_MCU_COMMAND, cluster_data, ) return foundation.GENERAL_COMMANDS[ foundation.GeneralCommand.Default_Response ].schema(command_id=command_id, status=foundation.Status.SUCCESS) # (go_to_lift_percentage) elif command_id == 0x0005: lift_value = args[0] cluster_data = TuyaClusterData( endpoint_id=self.endpoint.endpoint_id, cluster_name=self.ep_attribute, cluster_attr="current_position_lift_percentage", attr_value=lift_value, expect_reply=expect_reply, manufacturer=-1, ) self.endpoint.device.command_bus.listener_event( TUYA_MCU_COMMAND, cluster_data, ) return foundation.GENERAL_COMMANDS[ foundation.GeneralCommand.Default_Response ].schema(command_id=command_id, status=foundation.Status.SUCCESS) # # Custom Command # elif command_id == 0x0006: # ¿doc reference? # tuya_payload.status = args[0] # tuya_payload.tsn = args[1] # tuya_payload.command_id = args[2] # tuya_payload.function = args[3] # tuya_payload.data = args[4] self.warning("Unsupported command_id: %s", command_id) return foundation.GENERAL_COMMANDS[ foundation.GeneralCommand.Default_Response ].schema(command_id=command_id, status=foundation.Status.UNSUP_CLUSTER_COMMAND) class TuyaWindowCoverManufCluster(TuyaMCUCluster): """Tuya with WindowCover data points.""" attributes = TuyaMCUCluster.attributes.copy() attributes.update( { 0x5000: ("backlight_mode", t.enum8, True), # 0: off, 1: on 0x8001: ("indicator_status", t.enum8, True), # 0: status, 1: position, 2: off (¿backlight_mode?) } ) dp_to_attribute: Dict[int, DPToAttributeMapping] = { 1: DPToAttributeMapping( TuyaWindowCovering.ep_attribute, "curtain_switch", dp_type=TuyaDPType.ENUM, ), 2: DPToAttributeMapping( TuyaWindowCovering.ep_attribute, "current_position_lift_percentage", dp_type=TuyaDPType.VALUE, ), 3: DPToAttributeMapping( TuyaWindowCovering.ep_attribute, "current_position_lift_percentage", dp_type=TuyaDPType.ENUM, ), # 4: DPToAttributeMapping( # TuyaWindowCovering.ep_attribute, # "on_off", # dp_type=TuyaDPType.ENUM, # endpoint_id=2, # ), # 5: DPToAttributeMapping( # TuyaWindowCovering.ep_attribute, # "current_position_lift_percentage", # dp_type=TuyaDPType.VALUE, # endpoint_id=2, # ), # 6: DPToAttributeMapping( # TuyaWindowCovering.ep_attribute, # "accurate_calibration", # dp_type=TuyaDPType.ENUM, # endpoint_id=2, # ), # 7: DPToAttributeMapping( # TuyaMCUCluster.ep_attribute, # "backlight_mode", # dp_type=TuyaDPType.ENUM, # ), # 8: DPToAttributeMapping( # TuyaWindowCovering.ep_attribute, # "motor_steering", # dp_type=TuyaDPType.ENUM, # ), # 9: DPToAttributeMapping( # TuyaWindowCovering.ep_attribute, # "motor_steering", # dp_type=TuyaDPType.ENUM, # endpoint_id=2, # ), # 10: DPToAttributeMapping( # TuyaWindowCovering.ep_attribute, # "quick_calibration", # dp_type=TuyaDPType.ENUM, # ), # 11: DPToAttributeMapping( # TuyaWindowCovering.ep_attribute, # "quick_calibration", # dp_type=TuyaDPType.ENUM, # endpoint_id=2, # ), # 14: DPToAttributeMapping( # TuyaMCUCluster.ep_attribute, # "indicator_status", # 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", 6: "_dp_2_attr_update", 7: "_dp_2_attr_update", 8: "_dp_2_attr_update", 9: "_dp_2_attr_update", 10: "_dp_2_attr_update", 11: "_dp_2_attr_update", 14: "_dp_2_attr_update", } class TuyaCover0601_GP(TuyaWindowCover): """Tuya blind controller 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=False, # *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False # ) MODELS_INFO: [ ("_TZE200_r0jdjrvi", "TS0601"), ], ENDPOINTS: { 1: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.SMART_PLUG, INPUT_CLUSTERS: [ Basic.cluster_id, Groups.cluster_id, Scenes.cluster_id, TuyaWindowCoverManufCluster.cluster_id, ], OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id], }, 242: { PROFILE_ID: 41440, DEVICE_TYPE: 97, INPUT_CLUSTERS: [], OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id], }, }, } replacement = { ENDPOINTS: { 1: { DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE, INPUT_CLUSTERS: [ Basic.cluster_id, Groups.cluster_id, Scenes.cluster_id, TuyaWindowCoverManufCluster, TuyaWindowCovering, ], OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id], }, 242: { PROFILE_ID: 41440, DEVICE_TYPE: 97, INPUT_CLUSTERS: [], OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id], }, } } ```
Drmatterpl commented 1 year ago

Thanks! it works for me. I have all I need - operating slider, no errors when hitting the buttons. Before I had some errors with stop button - Failed to call service cover/stop_cover....

javicalle commented 1 year ago

The quirk seems to be pretty incomplete:

There must be some No cluster_dp found for ... errors in the logs. They would give to us some info about capabilities and how implement it.

MattWestb commented 1 year ago

Take the power of the device and wait one minute and putting it back and look if some interesting DPs is s coning in the log.

RowCZ commented 1 year ago

Hi

That can be the reason why I have no slider, I didn't bother with instalation since I was unable to make it work at all. :D

@RowCZ can you share your latest quirk code? I have spend a looooot of time and it seems that this is the only quirk that works with my motor - the one by @caradas

This is last that worked for me TS0601_Covertest.txt

Dextrik commented 1 year ago

Take the power of the device and wait one minute and putting it back and look if some interesting DPs is s coning in the log.

@MattWestb, @javicalle this is log when i plug the device back to power and than press close, but i don't see any errors.

log
``` 2023-02-20 18:58:15.515 DEBUG (MainThread) [homeassistant.components.zha.core.device] [0x826D](TS0601): Device seen - marking the device available and resetting counter 2023-02-20 18:58:15.516 DEBUG (MainThread) [homeassistant.components.zha.core.device] [0x826D](TS0601): Update device availability - device available: True - new availability: True - changed: False 2023-02-20 18:58:16.165 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=0, SrcAddr=0x826D, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=, LQI=116, SecurityUse=, TimeStamp=6971197, TSN=0, Data=b'\x08\xBA\x0A\x01\x00\x20\x46\xE2\xFF\x20\x36\xE4\xFF\x20\x01', MacSrcAddr=0x826D, MsgResultRadius=29) 2023-02-20 18:58:16.168 DEBUG (MainThread) [zigpy.application] Received a packet: ZigbeePacket(src=AddrModeAddress(addr_mode=, address=0x826D), src_ep=1, dst=AddrModeAddress(addr_mode=, address=0x0000), dst_ep=1, source_route=None, extended_timeout=False, tsn=0, profile_id=260, cluster_id=0, data=Serialized[b'\x08\xba\n\x01\x00 F\xe2\xff 6\xe4\xff \x01'], tx_options=, radius=29, non_member_radius=0, lqi=116, rssi=None) 2023-02-20 18:58:16.168 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0x0000] Received ZCL frame: b'\x08\xba\n\x01\x00 F\xe2\xff 6\xe4\xff \x01' 2023-02-20 18:58:16.169 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0x0000] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=, is_manufacturer_specific=0, direction=, disable_default_response=0, reserved=0, *is_cluster=False, *is_general=True, *is_reply=True), tsn=186, command_id=10, *direction=, *is_reply=True) 2023-02-20 18:58:16.170 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0x0000] Decoded ZCL frame: Basic:Report_Attributes(attribute_reports=[Attribute(attrid=0x0001, value=TypeValue(type=uint8_t, value=70)), Attribute(attrid=0xFFE2, value=TypeValue(type=uint8_t, value=54)), Attribute(attrid=0xFFE4, value=TypeValue(type=uint8_t, value=1))]) 2023-02-20 18:58:16.170 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0x0000] Received command 0x0A (TSN 186): Report_Attributes(attribute_reports=[Attribute(attrid=0x0001, value=TypeValue(type=uint8_t, value=70)), Attribute(attrid=0xFFE2, value=TypeValue(type=uint8_t, value=54)), Attribute(attrid=0xFFE4, value=TypeValue(type=uint8_t, value=1))]) 2023-02-20 18:58:16.170 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0x0000] Attribute report received: app_version=70, 0xFFE2=54, 0xFFE4=1 2023-02-20 18:58:16.176 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0x0000] Sending reply header: ZCLHeader(frame_control=FrameControl(frame_type=, is_manufacturer_specific=False, direction=, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True, *is_reply=True), tsn=186, command_id=, *direction=, *is_reply=True) 2023-02-20 18:58:16.176 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0x0000] Sending reply: Default_Response(command_id=10, status=) 2023-02-20 18:58:16.177 DEBUG (MainThread) [zigpy_znp.zigbee.application] Sending packet ZigbeePacket(src=AddrModeAddress(addr_mode=, address=0x0000), src_ep=1, dst=AddrModeAddress(addr_mode=, address=0x826D), dst_ep=1, source_route=None, extended_timeout=False, tsn=186, profile_id=260, cluster_id=0, data=Serialized[b'\x18\xba\x0b\n\x00'], tx_options=, radius=0, non_member_radius=0, lqi=None, rssi=None) 2023-02-20 18:58:16.182 DEBUG (MainThread) [zigpy_znp.api] Sending request: AF.DataRequestExt.Req(DstAddrModeAddress=AddrModeAddress(mode=, address=0x826D), DstEndpoint=1, DstPanId=0x0000, SrcEndpoint=1, ClusterId=0, TSN=186, Options=, Radius=0, Data=b'\x18\xBA\x0B\x0A\x00') 2023-02-20 18:58:16.203 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.DataRequestExt.Rsp(Status=) 2023-02-20 18:58:16.390 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.DataConfirm.Callback(Status=, Endpoint=1, TSN=186) 2023-02-20 18:58:17.681 DEBUG (MainThread) [homeassistant.core] Bus:Handling , new_state=> 2023-02-20 18:58:17.766 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=61184, SrcAddr=0x826D, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=, LQI=127, SecurityUse=, TimeStamp=7071309, TSN=0, Data=b'\x09\xBB\x11\x00\x03\x40', MacSrcAddr=0x826D, MsgResultRadius=29) 2023-02-20 18:58:17.768 DEBUG (MainThread) [zigpy.application] Received a packet: ZigbeePacket(src=AddrModeAddress(addr_mode=, address=0x826D), src_ep=1, dst=AddrModeAddress(addr_mode=, address=0x0000), dst_ep=1, source_route=None, extended_timeout=False, tsn=0, profile_id=260, cluster_id=61184, data=Serialized[b'\t\xbb\x11\x00\x03@'], tx_options=, radius=29, non_member_radius=0, lqi=127, rssi=None) 2023-02-20 18:58:17.769 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0xef00] Received ZCL frame: b'\t\xbb\x11\x00\x03@' 2023-02-20 18:58:17.769 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=, is_manufacturer_specific=0, direction=, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False, *is_reply=True), tsn=187, command_id=17, *direction=, *is_reply=True) 2023-02-20 18:58:17.770 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0xef00] Decoded ZCL frame: TuyaWindowCoverManufCluster:mcu_version_response(version=MCUVersion(status=0, tsn=3, version_raw=64, *version='1.0.0')) 2023-02-20 18:58:17.770 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0xef00] Received command 0x11 (TSN 187): mcu_version_response(version=MCUVersion(status=0, tsn=3, version_raw=64, *version='1.0.0')) 2023-02-20 18:58:17.771 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0xef00] MCU version: 1.0.0 2023-02-20 18:58:17.776 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0xef00] Sending reply header: ZCLHeader(frame_control=FrameControl(frame_type=, is_manufacturer_specific=False, direction=, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True, *is_reply=True), tsn=187, command_id=, *direction=, *is_reply=True) 2023-02-20 18:58:17.776 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0xef00] Sending reply: Default_Response(command_id=17, status=) 2023-02-20 18:58:17.777 DEBUG (MainThread) [zigpy_znp.zigbee.application] Sending packet ZigbeePacket(src=AddrModeAddress(addr_mode=, address=0x0000), src_ep=1, dst=AddrModeAddress(addr_mode=, address=0x826D), dst_ep=1, source_route=None, extended_timeout=False, tsn=187, profile_id=260, cluster_id=61184, data=Serialized[b'\x18\xbb\x0b\x11\x00'], tx_options=, radius=0, non_member_radius=0, lqi=None, rssi=None) 2023-02-20 18:58:17.781 DEBUG (MainThread) [zigpy_znp.api] Sending request: AF.DataRequestExt.Req(DstAddrModeAddress=AddrModeAddress(mode=, address=0x826D), DstEndpoint=1, DstPanId=0x0000, SrcEndpoint=1, ClusterId=61184, TSN=187, Options=, Radius=0, Data=b'\x18\xBB\x0B\x11\x00') 2023-02-20 18:58:17.801 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.DataRequestExt.Rsp(Status=) 2023-02-20 18:58:17.842 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.DataConfirm.Callback(Status=, Endpoint=1, TSN=187) 2023-02-20 18:58:19.014 WARNING (MainThread) [homeassistant.components.camera] Updating xiaomi_cloud_map_extractor camera took longer than the scheduled update interval 0:00:05 2023-02-20 18:58:20.249 DEBUG (MainThread) [homeassistant.core] Bus:Handling , new_state=> 2023-02-20 18:58:20.528 DEBUG (MainThread) [homeassistant.core] Bus:Handling , new_state=> 2023-02-20 18:58:20.813 DEBUG (MainThread) [homeassistant.components.zha.core.device] [0x45C0](TS0601): Device seen - marking the device available and resetting counter 2023-02-20 18:58:20.813 DEBUG (MainThread) [homeassistant.components.zha.core.device] [0x45C0](TS0601): Update device availability - device available: True - new availability: True - changed: False 2023-02-20 18:58:24.015 WARNING (MainThread) [homeassistant.components.camera] Updating xiaomi_cloud_map_extractor camera took longer than the scheduled update interval 0:00:05 2023-02-20 18:58:26.183 DEBUG (MainThread) [zigpy_znp.api] Sending request: SYS.Ping.Req() 2023-02-20 18:58:26.190 DEBUG (MainThread) [zigpy_znp.api] Received command: SYS.Ping.Rsp(Capabilities=) 2023-02-20 18:58:28.946 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=10, SrcAddr=0x826D, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=, LQI=131, SecurityUse=, TimeStamp=7770013, TSN=0, Data=b'\x00\xBC\x00\x07\x00', MacSrcAddr=0x826D, MsgResultRadius=29) 2023-02-20 18:58:28.948 DEBUG (MainThread) [zigpy.application] Received a packet: ZigbeePacket(src=AddrModeAddress(addr_mode=, address=0x826D), src_ep=1, dst=AddrModeAddress(addr_mode=, address=0x0000), dst_ep=1, source_route=None, extended_timeout=False, tsn=0, profile_id=260, cluster_id=10, data=Serialized[b'\x00\xbc\x00\x07\x00'], tx_options=, radius=29, non_member_radius=0, lqi=131, rssi=None) 2023-02-20 18:58:28.949 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0x000a] Received ZCL frame: b'\x00\xbc\x00\x07\x00' 2023-02-20 18:58:28.949 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0x000a] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=, is_manufacturer_specific=0, direction=, disable_default_response=0, reserved=0, *is_cluster=False, *is_general=True, *is_reply=False), tsn=188, command_id=0, *direction=, *is_reply=False) 2023-02-20 18:58:28.950 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0x000a] Decoded ZCL frame: Time:Read_Attributes(attribute_ids=[7]) 2023-02-20 18:58:28.950 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0x000a] Received command 0x00 (TSN 188): Read_Attributes(attribute_ids=[7]) 2023-02-20 18:58:28.955 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0x000a] Sending reply header: ZCLHeader(frame_control=FrameControl(frame_type=, is_manufacturer_specific=False, direction=, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True, *is_reply=True), tsn=188, command_id=, *direction=, *is_reply=True) 2023-02-20 18:58:28.955 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0x000a] Sending reply: Read_Attributes_rsp(status_records=[ReadAttributeRecord(attrid=0x0007, status=, value=TypeValue(type=LocalTime, value=730234708))]) 2023-02-20 18:58:28.956 DEBUG (MainThread) [zigpy_znp.zigbee.application] Sending packet ZigbeePacket(src=AddrModeAddress(addr_mode=, address=0x0000), src_ep=1, dst=AddrModeAddress(addr_mode=, address=0x826D), dst_ep=1, source_route=None, extended_timeout=False, tsn=188, profile_id=260, cluster_id=10, data=Serialized[b'\x18\xbc\x01\x07\x00\x00#T\x7f\x86+'], tx_options=, radius=0, non_member_radius=0, lqi=None, rssi=None) 2023-02-20 18:58:28.960 DEBUG (MainThread) [zigpy_znp.api] Sending request: AF.DataRequestExt.Req(DstAddrModeAddress=AddrModeAddress(mode=, address=0x826D), DstEndpoint=1, DstPanId=0x0000, SrcEndpoint=1, ClusterId=10, TSN=188, Options=, Radius=0, Data=b'\x18\xBC\x01\x07\x00\x00\x23\x54\x7F\x86\x2B') 2023-02-20 18:58:28.982 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.DataRequestExt.Rsp(Status=) 2023-02-20 18:58:29.023 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.DataConfirm.Callback(Status=, Endpoint=1, TSN=188) 2023-02-20 18:58:30.745 DEBUG (MainThread) [homeassistant.core] Bus:Handling , new_state=> 2023-02-20 18:58:34.018 WARNING (MainThread) [homeassistant.components.camera] Updating xiaomi_cloud_map_extractor camera took longer than the scheduled update interval 0:00:05 2023-02-20 18:58:36.361 INFO (SyncWorker_3) [custom_components.xiaomi_miio_cooker] Got exception while fetching the state: Unable to discover the device 192.168.0.37 2023-02-20 18:58:39.019 WARNING (MainThread) [homeassistant.helpers.entity] Update of camera.xiaomi_cloud_map_extractor is taking over 10 seconds 2023-02-20 18:58:39.021 WARNING (MainThread) [homeassistant.components.camera] Updating xiaomi_cloud_map_extractor camera took longer than the scheduled update interval 0:00:05 2023-02-20 18:58:39.712 DEBUG (MainThread) [homeassistant.core] Bus:Handling , new_state=> 2023-02-20 18:58:40.518 DEBUG (MainThread) [homeassistant.core] Bus:Handling , new_state=> 2023-02-20 18:58:40.740 DEBUG (MainThread) [homeassistant.core] Bus:Handling , new_state=> 2023-02-20 18:58:41.025 DEBUG (MainThread) [homeassistant.core] Bus:Handling , new_state=> 2023-02-20 18:58:44.021 WARNING (MainThread) [homeassistant.components.camera] Updating xiaomi_cloud_map_extractor camera took longer than the scheduled update interval 0:00:05 2023-02-20 18:58:44.736 DEBUG (MainThread) [homeassistant.core] Bus:Handling , new_state=> 2023-02-20 18:58:46.213 DEBUG (MainThread) [homeassistant.core] Bus:Handling , new_state=> 2023-02-20 18:58:47.677 DEBUG (MainThread) [homeassistant.core] Bus:Handling , new_state=> 2023-02-20 18:58:47.682 DEBUG (MainThread) [homeassistant.core] Bus:Handling , ], min_temp=7.0, max_temp=25.0, target_temp_step=0.1, preset_modes=['none', 'away'], current_temperature=24.7, temperature=25.0, hvac_action=heating, preset_mode=none, friendly_name=Kotel, supported_features=ClimateEntityFeature.PRESET_MODE|TARGET_TEMPERATURE @ 2023-02-20T02:14:26.857124+01:00>, new_state=, ], min_temp=7.0, max_temp=25.0, target_temp_step=0.1, preset_modes=['none', 'away'], current_temperature=24.6, temperature=25.0, hvac_action=heating, preset_mode=none, friendly_name=Kotel, supported_features=ClimateEntityFeature.PRESET_MODE|TARGET_TEMPERATURE @ 2023-02-20T02:14:26.857124+01:00>> 2023-02-20 18:58:48.355 DEBUG (MainThread) [homeassistant.core] Bus:Handling , new_state=> 2023-02-20 18:58:48.418 DEBUG (MainThread) [homeassistant.core] Bus:Handling , new_state=> 2023-02-20 18:58:48.720 DEBUG (MainThread) [homeassistant.core] Bus:Handling , new_state=> 2023-02-20 18:58:49.022 WARNING (MainThread) [homeassistant.components.camera] Updating xiaomi_cloud_map_extractor camera took longer than the scheduled update interval 0:00:05 2023-02-20 18:58:50.249 DEBUG (MainThread) [homeassistant.core] Bus:Handling , new_state=> 2023-02-20 18:58:50.741 DEBUG (MainThread) [homeassistant.core] Bus:Handling , new_state=> 2023-02-20 18:58:51.761 DEBUG (MainThread) [homeassistant.core] Bus:Handling 2023-02-20 18:58:51.764 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0x0102] Sending Tuya Cluster Command. Cluster Command is 1, Arguments are () 2023-02-20 18:58:51.765 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0xef00] tuya_mcu_command: cluster_data=TuyaClusterData(endpoint_id=1, cluster_name='window_covering', cluster_attr='curtain_switch', attr_value=2, expect_reply=True, manufacturer=-1) 2023-02-20 18:58:51.765 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0xef00] get_dp_mapping --> found DP: 1 2023-02-20 18:58:51.765 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0xef00] from_cluster_data: {1: DPToAttributeMapping(ep_attribute='window_covering', attribute_name='curtain_switch', dp_type=, converter=None, dp_converter=None, endpoint_id=None)} 2023-02-20 18:58:51.765 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0xef00] value: 2 2023-02-20 18:58:51.766 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0xef00] raw: b'\x02' 2023-02-20 18:58:51.766 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0xef00] tuya_commands: [TuyaCommand(status=0, tsn=118, datapoints=[TuyaDatapointData(dp=1, data=TuyaData(dp_type=, function=0, raw=b'\x02', *payload=))])] 2023-02-20 18:58:51.766 DEBUG (MainThread) [homeassistant.components.zha.core.channels.base] [0x826D:1:0x0102]: Attribute report 'Window Covering'[curtain_switch] = 2 2023-02-20 18:58:51.766 DEBUG (MainThread) [homeassistant.components.zha.core.channels.base] [0x826D:1:0x0102]: executed 'down_close' command with args: '()' kwargs: '{}' result: Default_Response(command_id=1, status=) 2023-02-20 18:58:51.767 DEBUG (MainThread) [homeassistant.components.zha.cover] state=closing 2023-02-20 18:58:51.767 DEBUG (MainThread) [homeassistant.core] Bus:Handling , new_state=> 2023-02-20 18:58:51.776 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0xef00] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=, is_manufacturer_specific=False, direction=, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False, *is_reply=False), tsn=119, command_id=0, *direction=, *is_reply=False) 2023-02-20 18:58:51.777 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0xef00] Sending request: set_data(data=TuyaCommand(status=0, tsn=118, datapoints=[TuyaDatapointData(dp=1, data=TuyaData(dp_type=, function=0, raw=b'\x02', *payload=))])) 2023-02-20 18:58:51.778 DEBUG (MainThread) [zigpy_znp.zigbee.application] Sending packet ZigbeePacket(src=AddrModeAddress(addr_mode=, address=0x0000), src_ep=1, dst=AddrModeAddress(addr_mode=, address=0x826D), dst_ep=1, source_route=None, extended_timeout=False, tsn=119, profile_id=260, cluster_id=61184, data=Serialized[b'\x01w\x00\x00v\x01\x04\x00\x01\x02'], tx_options=, radius=0, non_member_radius=0, lqi=None, rssi=None) 2023-02-20 18:58:51.783 DEBUG (MainThread) [zigpy_znp.api] Sending request: AF.DataRequestExt.Req(DstAddrModeAddress=AddrModeAddress(mode=, address=0x826D), DstEndpoint=1, DstPanId=0x0000, SrcEndpoint=1, ClusterId=61184, TSN=119, Options=, Radius=0, Data=b'\x01\x77\x00\x00\x76\x01\x04\x00\x01\x02') 2023-02-20 18:58:51.805 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.DataRequestExt.Rsp(Status=) 2023-02-20 18:58:51.809 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.DataConfirm.Callback(Status=, Endpoint=1, TSN=119) 2023-02-20 18:58:51.831 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=61184, SrcAddr=0x826D, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=, LQI=127, SecurityUse=, TimeStamp=9200458, TSN=0, Data=b'\x18\x77\x0B\x00\x00', MacSrcAddr=0x826D, MsgResultRadius=29) 2023-02-20 18:58:51.833 DEBUG (MainThread) [zigpy.application] Received a packet: ZigbeePacket(src=AddrModeAddress(addr_mode=, address=0x826D), src_ep=1, dst=AddrModeAddress(addr_mode=, address=0x0000), dst_ep=1, source_route=None, extended_timeout=False, tsn=0, profile_id=260, cluster_id=61184, data=Serialized[b'\x18w\x0b\x00\x00'], tx_options=, radius=29, non_member_radius=0, lqi=127, rssi=None) 2023-02-20 18:58:51.834 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0xef00] Received ZCL frame: b'\x18w\x0b\x00\x00' 2023-02-20 18:58:51.834 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=, is_manufacturer_specific=0, direction=, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True, *is_reply=True), tsn=119, command_id=11, *direction=, *is_reply=True) 2023-02-20 18:58:51.835 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0xef00] Decoded ZCL frame: TuyaWindowCoverManufCluster:Default_Response(command_id=0, status=) 2023-02-20 18:58:51.874 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=61184, SrcAddr=0x826D, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=, LQI=127, SecurityUse=, TimeStamp=9203045, TSN=0, Data=b'\x19\xBD\x01\x00\x76\x01\x04\x00\x01\x02', MacSrcAddr=0x826D, MsgResultRadius=29) 2023-02-20 18:58:51.877 DEBUG (MainThread) [zigpy.application] Received a packet: ZigbeePacket(src=AddrModeAddress(addr_mode=, address=0x826D), src_ep=1, dst=AddrModeAddress(addr_mode=, address=0x0000), dst_ep=1, source_route=None, extended_timeout=False, tsn=0, profile_id=260, cluster_id=61184, data=Serialized[b'\x19\xbd\x01\x00v\x01\x04\x00\x01\x02'], tx_options=, radius=29, non_member_radius=0, lqi=127, rssi=None) 2023-02-20 18:58:51.877 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0xef00] Received ZCL frame: b'\x19\xbd\x01\x00v\x01\x04\x00\x01\x02' 2023-02-20 18:58:51.878 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=, is_manufacturer_specific=0, direction=, disable_default_response=1, reserved=0, *is_cluster=True, *is_general=False, *is_reply=True), tsn=189, command_id=1, *direction=, *is_reply=True) 2023-02-20 18:58:51.879 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0xef00] Decoded ZCL frame: TuyaWindowCoverManufCluster:get_data(data=TuyaCommand(status=0, tsn=118, datapoints=[TuyaDatapointData(dp=1, data=TuyaData(dp_type=, function=0, raw=b'\x02', *payload=))])) 2023-02-20 18:58:51.879 DEBUG (MainThread) [zigpy.zcl] [0x826D:1:0xef00] Received command 0x01 (TSN 189): get_data(data=TuyaCommand(status=0, tsn=118, datapoints=[TuyaDatapointData(dp=1, data=TuyaData(dp_type=, function=0, raw=b'\x02', *payload=))])) 2023-02-20 18:58:51.880 DEBUG (MainThread) [homeassistant.components.zha.core.channels.base] [0x826D:1:0x0102]: Attribute report 'Window Covering'[curtain_switch] = enum8.undefined_0x02 2023-02-20 18:58:54.024 WARNING (MainThread) [homeassistant.components.camera] Updating xiaomi_cloud_map_extractor camera took longer than the scheduled update interval 0:00:05 2023-02-20 18:58:54.824 DEBUG (MainThread) [homeassistant.core] Bus:Handling , new_state=> 2023-02-20 18:58:54.979 DEBUG (MainThread) [homeassistant.core] Bus:Handling , new_state=> 2023-02-20 18:58:55.511 DEBUG (MainThread) [homeassistant.core] Bus:Handling , new_state=> 2023-02-20 18:58:55.658 DEBUG (MainThread) [homeassistant.core] Bus:Handling , new_state=> 2023-02-20 18:58:56.195 DEBUG (MainThread) [zigpy_znp.api] Sending request: SYS.Ping.Req() 2023-02-20 18:58:56.201 DEBUG (MainThread) [zigpy_znp.api] Received command: SYS.Ping.Rsp(Capabilities=) 2023-02-20 18:58:56.697 DEBUG (MainThread) [homeassistant.core] Bus:Handling , new_state=> 2023-02-20 18:58:56.947 DEBUG (MainThread) [homeassistant.components.zha.core.device] [0xDA58](TS0601): Device seen - marking the device available and resetting counter 2023-02-20 18:58:56.948 DEBUG (MainThread) [homeassistant.components.zha.core.device] [0xDA58](TS0601): Update device availability - device available: True - new availability: True - changed: False ```
Drmatterpl commented 1 year ago

after the HA update to 2023.3 it is not working anymore, need to remove the quirk - zha did not start

2023-03-03 17:20:48.301 ERROR (MainThread) [homeassistant.config_entries] Error setting up entry socket://192.168.1.98:8888 for zha File "/usr/src/homeassistant/homeassistant/components/zha/init.py", line 100, in async_setup_entry File "/usr/local/lib/python3.10/site-packages/zhaquirks/init.py", line 409, in setup File "/config/custom_zha_quirks/ts601_from_Dextrik.py", line 35, in from zhaquirks.tuya.mcu import ( ImportError: cannot import name 'TuyaDPType' from 'zhaquirks.tuya.mcu' (/usr/local/lib/python3.10/site-packages/zhaquirks/tuya/mcu/init.py)

javicalle commented 1 year ago

@Drmatterpl, check here: https://github.com/zigpy/zha-device-handlers/issues/2250#issuecomment-1453978417

Drmatterpl commented 1 year ago

@Drmatterpl, check here: #2250 (comment)

Thank YOU!!! works like a harm, added # to few lines and all is fine.

Line  38: #    TuyaDPType,
Line 152: #            dp_type=TuyaDPType.ENUM,
Line 157: #            dp_type=TuyaDPType.VALUE,
Line 162: #            dp_type=TuyaDPType.ENUM,
caradas commented 1 year ago

With Quirk from https://github.com/zigpy/zha-device-handlers/issues/1953#issuecomment-1436692003 and fix from https://github.com/zigpy/zha-device-handlers/issues/1953#issuecomment-1454294551 the Slider is working fine but the buttons are always open the curtain.

Stop (Motor is turning CW):

2023-03-09 17:39:07.703 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0x0102] Sending Tuya Cluster Command. Cluster Command is 2, Arguments are ()
2023-03-09 17:39:07.703 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] tuya_mcu_command: cluster_data=TuyaClusterData(endpoint_id=1, cluster_name='window_covering', cluster_attr='curtain_switch', attr_value=1, expect_reply=True, manufacturer=-1)
2023-03-09 17:39:07.703 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] get_dp_mapping --> found DP: 1
2023-03-09 17:39:07.704 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] from_cluster_data: {1: DPToAttributeMapping(ep_attribute='window_covering', attribute_name='curtain_switch', converter=None, dp_converter=None, endpoint_id=None)}
2023-03-09 17:39:07.704 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] value: 1
2023-03-09 17:39:07.704 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] raw: b'\x00\x00\x00\x01'
2023-03-09 17:39:07.704 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] tuya_commands: [TuyaCommand(status=0, tsn=49, datapoints=[TuyaDatapointData(dp=1, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x00\x00\x00\x01', *payload=1))])]
2023-03-09 17:39:07.706 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=False, direction=<Direction.Server_to_Client: 0>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False, *is_reply=False), tsn=50, command_id=0, *direction=<Direction.Server_to_Client: 0>, *is_reply=False)
2023-03-09 17:39:07.707 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] Sending request: set_data(data=TuyaCommand(status=0, tsn=49, datapoints=[TuyaDatapointData(dp=1, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x00\x00\x00\x01', *payload=1))]))
2023-03-09 17:39:07.708 DEBUG (MainThread) [zigpy_znp.zigbee.application] Sending packet ZigbeePacket(src=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x0000), src_ep=1, dst=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x3F47), dst_ep=1, source_route=None, extended_timeout=False, tsn=50, profile_id=260, cluster_id=61184, data=Serialized[b'\x012\x00\x001\x01\x02\x00\x04\x00\x00\x00\x01'], tx_options=<TransmitOptions.NONE: 0>, radius=0, non_member_radius=0, lqi=None, rssi=None)
2023-03-09 17:39:07.711 DEBUG (MainThread) [zigpy_znp.api] Sending request: AF.DataRequestExt.Req(DstAddrModeAddress=AddrModeAddress(mode=<AddrMode.NWK: 2>, address=0x3F47), DstEndpoint=1, DstPanId=0x0000, SrcEndpoint=1, ClusterId=61184, TSN=50, Options=<TransmitOptions.SUPPRESS_ROUTE_DISC_NETWORK: 32>, Radius=0, Data=b'\x01\x32\x00\x00\x31\x01\x02\x00\x04\x00\x00\x00\x01')
2023-03-09 17:39:07.744 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=61184, SrcAddr=0x3F47, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=<Bool.false: 0>, LQI=78, SecurityUse=<Bool.false: 0>, TimeStamp=287179, TSN=0, Data=b'\x18\x32\x0B\x00\x00', MacSrcAddr=0x3F47, MsgResultRadius=29)
2023-03-09 17:39:07.745 DEBUG (MainThread) [zigpy.application] Received a packet: ZigbeePacket(src=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x3F47), src_ep=1, dst=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x0000), dst_ep=1, source_route=None, extended_timeout=False, tsn=0, profile_id=260, cluster_id=61184, data=Serialized[b'\x182\x0b\x00\x00'], tx_options=<TransmitOptions.NONE: 0>, radius=29, non_member_radius=0, lqi=78, rssi=None)
2023-03-09 17:39:07.745 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] Received ZCL frame: b'\x182\x0b\x00\x00'
2023-03-09 17:39:07.745 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 1>, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True, *is_reply=True), tsn=50, command_id=11, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2023-03-09 17:39:07.746 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] Decoded ZCL frame: TuyaWindowCoverManufCluster:Default_Response(command_id=0, status=<Status.SUCCESS: 0>)

Up (Motor is turning CW):

2023-03-09 17:40:49.315 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0x0102] Sending Tuya Cluster Command. Cluster Command is 0, Arguments are ()
2023-03-09 17:40:49.315 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] tuya_mcu_command: cluster_data=TuyaClusterData(endpoint_id=1, cluster_name='window_covering', cluster_attr='curtain_switch', attr_value=0, expect_reply=True, manufacturer=-1)
2023-03-09 17:40:49.315 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] get_dp_mapping --> found DP: 1
2023-03-09 17:40:49.315 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] from_cluster_data: {1: DPToAttributeMapping(ep_attribute='window_covering', attribute_name='curtain_switch', converter=None, dp_converter=None, endpoint_id=None)}
2023-03-09 17:40:49.316 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] value: 0
2023-03-09 17:40:49.316 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] raw: b'\x00\x00\x00\x00'
2023-03-09 17:40:49.316 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] tuya_commands: [TuyaCommand(status=0, tsn=65, datapoints=[TuyaDatapointData(dp=1, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x00\x00\x00\x00', *payload=0))])]
2023-03-09 17:40:49.318 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=False, direction=<Direction.Server_to_Client: 0>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False, *is_reply=False), tsn=66, command_id=0, *direction=<Direction.Server_to_Client: 0>, *is_reply=False)
2023-03-09 17:40:49.318 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] Sending request: set_data(data=TuyaCommand(status=0, tsn=65, datapoints=[TuyaDatapointData(dp=1, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x00\x00\x00\x00', *payload=0))]))
2023-03-09 17:40:49.319 DEBUG (MainThread) [zigpy_znp.zigbee.application] Sending packet ZigbeePacket(src=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x0000), src_ep=1, dst=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x3F47), dst_ep=1, source_route=None, extended_timeout=False, tsn=66, profile_id=260, cluster_id=61184, data=Serialized[b'\x01B\x00\x00A\x01\x02\x00\x04\x00\x00\x00\x00'], tx_options=<TransmitOptions.NONE: 0>, radius=0, non_member_radius=0, lqi=None, rssi=None)
2023-03-09 17:40:49.323 DEBUG (MainThread) [zigpy_znp.api] Sending request: AF.DataRequestExt.Req(DstAddrModeAddress=AddrModeAddress(mode=<AddrMode.NWK: 2>, address=0x3F47), DstEndpoint=1, DstPanId=0x0000, SrcEndpoint=1, ClusterId=61184, TSN=66, Options=<TransmitOptions.SUPPRESS_ROUTE_DISC_NETWORK: 32>, Radius=0, Data=b'\x01\x42\x00\x00\x41\x01\x02\x00\x04\x00\x00\x00\x00')
2023-03-09 17:40:49.356 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=61184, SrcAddr=0x3F47, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=<Bool.false: 0>, LQI=84, SecurityUse=<Bool.false: 0>, TimeStamp=604735, TSN=0, Data=b'\x18\x42\x0B\x00\x00', MacSrcAddr=0x3F47, MsgResultRadius=29)
2023-03-09 17:40:49.357 DEBUG (MainThread) [zigpy.application] Received a packet: ZigbeePacket(src=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x3F47), src_ep=1, dst=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x0000), dst_ep=1, source_route=None, extended_timeout=False, tsn=0, profile_id=260, cluster_id=61184, data=Serialized[b'\x18B\x0b\x00\x00'], tx_options=<TransmitOptions.NONE: 0>, radius=29, non_member_radius=0, lqi=84, rssi=None)
2023-03-09 17:40:49.357 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] Received ZCL frame: b'\x18B\x0b\x00\x00'
2023-03-09 17:40:49.358 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 1>, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True, *is_reply=True), tsn=66, command_id=11, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2023-03-09 17:40:49.358 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] Decoded ZCL frame: TuyaWindowCoverManufCluster:Default_Response(command_id=0, status=<Status.SUCCESS: 0>)

Down (Motor is turning CW):

2023-03-09 17:41:54.629 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0x0102] Sending Tuya Cluster Command. Cluster Command is 1, Arguments are ()
2023-03-09 17:41:54.629 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] tuya_mcu_command: cluster_data=TuyaClusterData(endpoint_id=1, cluster_name='window_covering', cluster_attr='curtain_switch', attr_value=2, expect_reply=True, manufacturer=-1)
2023-03-09 17:41:54.630 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] get_dp_mapping --> found DP: 1
2023-03-09 17:41:54.630 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] from_cluster_data: {1: DPToAttributeMapping(ep_attribute='window_covering', attribute_name='curtain_switch', converter=None, dp_converter=None, endpoint_id=None)}
2023-03-09 17:41:54.630 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] value: 2
2023-03-09 17:41:54.630 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] raw: b'\x00\x00\x00\x02'
2023-03-09 17:41:54.630 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] tuya_commands: [TuyaCommand(status=0, tsn=77, datapoints=[TuyaDatapointData(dp=1, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x00\x00\x00\x02', *payload=2))])]
2023-03-09 17:41:54.632 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=False, direction=<Direction.Server_to_Client: 0>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False, *is_reply=False), tsn=78, command_id=0, *direction=<Direction.Server_to_Client: 0>, *is_reply=False)
2023-03-09 17:41:54.632 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] Sending request: set_data(data=TuyaCommand(status=0, tsn=77, datapoints=[TuyaDatapointData(dp=1, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x00\x00\x00\x02', *payload=2))]))
2023-03-09 17:41:54.633 DEBUG (MainThread) [zigpy_znp.zigbee.application] Sending packet ZigbeePacket(src=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x0000), src_ep=1, dst=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x3F47), dst_ep=1, source_route=None, extended_timeout=False, tsn=78, profile_id=260, cluster_id=61184, data=Serialized[b'\x01N\x00\x00M\x01\x02\x00\x04\x00\x00\x00\x02'], tx_options=<TransmitOptions.NONE: 0>, radius=0, non_member_radius=0, lqi=None, rssi=None)
2023-03-09 17:41:54.639 DEBUG (MainThread) [zigpy_znp.api] Sending request: AF.DataRequestExt.Req(DstAddrModeAddress=AddrModeAddress(mode=<AddrMode.NWK: 2>, address=0x3F47), DstEndpoint=1, DstPanId=0x0000, SrcEndpoint=1, ClusterId=61184, TSN=78, Options=<TransmitOptions.SUPPRESS_ROUTE_DISC_NETWORK: 32>, Radius=0, Data=b'\x01\x4E\x00\x00\x4D\x01\x02\x00\x04\x00\x00\x00\x02')
2023-03-09 17:41:54.673 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=61184, SrcAddr=0x3F47, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=<Bool.false: 0>, LQI=78, SecurityUse=<Bool.false: 0>, TimeStamp=808854, TSN=0, Data=b'\x18\x4E\x0B\x00\x00', MacSrcAddr=0x3F47, MsgResultRadius=29)
2023-03-09 17:41:54.674 DEBUG (MainThread) [zigpy.application] Received a packet: ZigbeePacket(src=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x3F47), src_ep=1, dst=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x0000), dst_ep=1, source_route=None, extended_timeout=False, tsn=0, profile_id=260, cluster_id=61184, data=Serialized[b'\x18N\x0b\x00\x00'], tx_options=<TransmitOptions.NONE: 0>, radius=29, non_member_radius=0, lqi=78, rssi=None)
2023-03-09 17:41:54.674 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] Received ZCL frame: b'\x18N\x0b\x00\x00'
2023-03-09 17:41:54.675 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 1>, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True, *is_reply=True), tsn=78, command_id=11, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2023-03-09 17:41:54.675 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] Decoded ZCL frame: TuyaWindowCoverManufCluster:Default_Response(command_id=0, status=<Status.SUCCESS: 0>)

Is it maybe because: data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x00\x00\x00\x02', *payload=2) Shouldn't it be TuyaDPType.ENUM?

javicalle commented 1 year ago

but the buttons are always open the curtain.

Not sure which the problem is. Can you elaborate?

Is it maybe because: data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x00\x00\x00\x02', *payload=2) Shouldn't it be TuyaDPType.ENUM?

No, it shouldn't. But...

Maybe you can try with that change in your code:

            cluster_data = TuyaClusterData(
                endpoint_id=self.endpoint.endpoint_id,
                cluster_name=self.ep_attribute,
                cluster_attr="curtain_switch",
                attr_value=int(TUYA2ZB_COMMANDS[command_id]),  # convert tuya2zigbee command
                expect_reply=expect_reply,
                manufacturer=-1,
            )

(just wrap TUYA2ZB_COMMANDS[command_id] with the int()).

Save changes, delete any __pycache__ folder in your local quirk folder and restart HA.

caradas commented 1 year ago

Thank you for your help.

grafik The problem is that pressing any of the 3 buttons result in an up/open motion of the curtain.

Your suggestion to add int() did not change the behaviour.

Log for Stop (curtain was inactive and started to move in up/open direction):

2023-03-15 10:11:57.940 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0x0102] Sending Tuya Cluster Command. Cluster Command is 2, Arguments are ()
2023-03-15 10:11:57.940 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] tuya_mcu_command: cluster_data=TuyaClusterData(endpoint_id=1, cluster_name='window_covering', cluster_attr='curtain_switch', attr_value=1, expect_reply=True, manufacturer=-1)
2023-03-15 10:11:57.941 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] get_dp_mapping --> found DP: 1
2023-03-15 10:11:57.941 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] from_cluster_data: {1: DPToAttributeMapping(ep_attribute='window_covering', attribute_name='curtain_switch', converter=None, dp_converter=None, endpoint_id=None)}
2023-03-15 10:11:57.941 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] value: 1
2023-03-15 10:11:57.941 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] raw: b'\x00\x00\x00\x01'
2023-03-15 10:11:57.941 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] tuya_commands: [TuyaCommand(status=0, tsn=133, datapoints=[TuyaDatapointData(dp=1, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x00\x00\x00\x01', *payload=1))])]
2023-03-15 10:11:57.943 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=False, direction=<Direction.Server_to_Client: 0>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False, *is_reply=False), tsn=134, command_id=0, *direction=<Direction.Server_to_Client: 0>, *is_reply=False)
2023-03-15 10:11:57.944 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] Sending request: set_data(data=TuyaCommand(status=0, tsn=133, datapoints=[TuyaDatapointData(dp=1, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x00\x00\x00\x01', *payload=1))]))
2023-03-15 10:11:57.945 DEBUG (MainThread) [zigpy_znp.zigbee.application] Sending packet ZigbeePacket(src=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x0000), src_ep=1, dst=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x3F47), dst_ep=1, source_route=None, extended_timeout=False, tsn=134, profile_id=260, cluster_id=61184, data=Serialized[b'\x01\x86\x00\x00\x85\x01\x02\x00\x04\x00\x00\x00\x01'], tx_options=<TransmitOptions.NONE: 0>, radius=0, non_member_radius=0, lqi=None, rssi=None)
2023-03-15 10:11:57.948 DEBUG (MainThread) [zigpy_znp.api] Sending request: AF.DataRequestExt.Req(DstAddrModeAddress=AddrModeAddress(mode=<AddrMode.NWK: 2>, address=0x3F47), DstEndpoint=1, DstPanId=0x0000, SrcEndpoint=1, ClusterId=61184, TSN=134, Options=<TransmitOptions.SUPPRESS_ROUTE_DISC_NETWORK: 32>, Radius=0, Data=b'\x01\x86\x00\x00\x85\x01\x02\x00\x04\x00\x00\x00\x01')
2023-03-15 10:11:57.961 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.DataRequestExt.Rsp(Status=<Status.SUCCESS: 0>)
2023-03-15 10:11:57.967 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.DataConfirm.Callback(Status=<Status.SUCCESS: 0>, Endpoint=1, TSN=134)
2023-03-15 10:11:58.016 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=61184, SrcAddr=0x3F47, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=<Bool.false: 0>, LQI=120, SecurityUse=<Bool.false: 0>, TimeStamp=3184480, TSN=0, Data=b'\x18\x86\x0B\x00\x00', MacSrcAddr=0x09BC, MsgResultRadius=27)
2023-03-15 10:11:58.017 DEBUG (MainThread) [zigpy.application] Received a packet: ZigbeePacket(src=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x3F47), src_ep=1, dst=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x0000), dst_ep=1, source_route=None, extended_timeout=False, tsn=0, profile_id=260, cluster_id=61184, data=Serialized[b'\x18\x86\x0b\x00\x00'], tx_options=<TransmitOptions.NONE: 0>, radius=27, non_member_radius=0, lqi=120, rssi=None)
2023-03-15 10:11:58.017 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] Received ZCL frame: b'\x18\x86\x0b\x00\x00'
2023-03-15 10:11:58.018 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 1>, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True, *is_reply=True), tsn=134, command_id=11, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2023-03-15 10:11:58.018 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] Decoded ZCL frame: TuyaWindowCoverManufCluster:Default_Response(command_id=0, status=<Status.SUCCESS: 0>)
2023-03-15 10:11:58.294 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=61184, SrcAddr=0x5EF4, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=<Bool.false: 0>, LQI=65, SecurityUse=<Bool.false: 0>, TimeStamp=3185349, TSN=0, Data=b'\x09\x8C\x02\x00\x09\x05\x02\x00\x04\x00\x00\x00\xD2', MacSrcAddr=0x5EF4, MsgResultRadius=29)
2023-03-15 10:11:58.295 DEBUG (MainThread) [zigpy.application] Received a packet: ZigbeePacket(src=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x5EF4), src_ep=1, dst=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x0000), dst_ep=1, source_route=None, extended_timeout=False, tsn=0, profile_id=260, cluster_id=61184, data=Serialized[b'\t\x8c\x02\x00\t\x05\x02\x00\x04\x00\x00\x00\xd2'], tx_options=<TransmitOptions.NONE: 0>, radius=29, non_member_radius=0, lqi=65, rssi=None)
2023-03-15 10:11:58.296 DEBUG (MainThread) [zigpy.zcl] [0x5EF4:1:0xef00] Received ZCL frame: b'\t\x8c\x02\x00\t\x05\x02\x00\x04\x00\x00\x00\xd2'
2023-03-15 10:11:58.296 DEBUG (MainThread) [zigpy.zcl] [0x5EF4:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 1>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False, *is_reply=True), tsn=140, command_id=2, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2023-03-15 10:11:58.297 DEBUG (MainThread) [zigpy.zcl] [0x5EF4:1:0xef00] Decoded ZCL frame: ME167ManufCluster:set_data_response(param=Command(status=0, tsn=9, command_id=517, function=0, data=[4, 0, 0, 0, 210]))
2023-03-15 10:11:58.297 DEBUG (MainThread) [zigpy.zcl] [0x5EF4:1:0xef00] Received command 0x02 (TSN 140): set_data_response(param=Command(status=0, tsn=9, command_id=517, function=0, data=[4, 0, 0, 0, 210]))
2023-03-15 10:11:58.298 DEBUG (MainThread) [zhaquirks.tuya] [0x5ef4:1:0xef00] Received value [0, 0, 0, 210] for attribute 0x0205 (command 0x0002)
2023-03-15 10:11:58.299 DEBUG (MainThread) [zigpy.zcl] [0x5EF4:1:0xef00] Sending reply header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=False, direction=<Direction.Client_to_Server: 1>, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True, *is_reply=True), tsn=140, command_id=<GeneralCommand.Default_Response: 11>, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2023-03-15 10:11:58.300 DEBUG (MainThread) [zigpy.zcl] [0x5EF4:1:0xef00] Sending reply: Default_Response(command_id=2, status=<Status.SUCCESS: 0>)
2023-03-15 10:11:58.300 DEBUG (MainThread) [zigpy_znp.zigbee.application] Sending packet ZigbeePacket(src=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x0000), src_ep=1, dst=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x5EF4), dst_ep=1, source_route=None, extended_timeout=False, tsn=140, profile_id=260, cluster_id=61184, data=Serialized[b'\x18\x8c\x0b\x02\x00'], tx_options=<TransmitOptions.ACK: 1>, radius=0, non_member_radius=0, lqi=None, rssi=None)
2023-03-15 10:11:58.303 DEBUG (MainThread) [zigpy_znp.api] Sending request: AF.DataRequestExt.Req(DstAddrModeAddress=AddrModeAddress(mode=<AddrMode.NWK: 2>, address=0x5EF4), DstEndpoint=1, DstPanId=0x0000, SrcEndpoint=1, ClusterId=61184, TSN=140, Options=<TransmitOptions.SUPPRESS_ROUTE_DISC_NETWORK|ACK_REQUEST: 48>, Radius=0, Data=b'\x18\x8C\x0B\x02\x00')
2023-03-15 10:11:58.315 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.DataRequestExt.Rsp(Status=<Status.SUCCESS: 0>)
2023-03-15 10:11:58.406 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.DataConfirm.Callback(Status=<Status.SUCCESS: 0>, Endpoint=1, TSN=140)

Current quirk file: ts601_cover.txt

caradas commented 1 year ago

Got it working again. By comparing the old Logs with new ones i found that with the removal of specified "TuyaDPType.ENUM" commands are now 4 byte(int32) instead of 1 byte and the motor is ignoring the trailing bytes to the command. As i did not find a way to shorten the command to 1 byte, i simply moved the command in the first byte of the int32.

I would call this a hackfix:

TUYA2ZB_COMMANDS = {
    0x0000: 0x00000000, #Open
    0x0001: 0x02000000, #Close
    0x0002: 0x01000000, #Stop
}

Is there a simple way to reverse the displayed lift percentage?

javicalle commented 1 year ago

The implementation needs to be fixed to handle the TuyaDPType.ENUM types. I will take a look in the weekend.

About the percentage behavior, does the cover have a remote? Is the control from remote fine? My first suggestion would be to invert the motor movement (to fix the percentage) and then (if they are wrong) invert the TUYA2ZB_COMMANDS.

caradas commented 1 year ago

Yes i have a remote, up arrow on the remote opens, same goes for up arrow in ha. Only the percentage is not intuitive as 100% is fully open

javicalle commented 1 year ago

First of all, you were right:

Shouldn't it be TuyaDPType.ENUM?

Yes it should, and maybe is the reason of the behavior.

Let's see if this can fix something

My proposal is add and replace this definitions:

class TuyaCC(t.enum8):
    """Tuya cover commands."""

    OPEN = 0x00
    STOP = 0x01
    CLOSE = 0x02

class ZclCC(t.enum8):
    """ZCL cover commands."""

    OPEN = 0x00
    CLOSE = 0x01
    STOP = 0x02

TUYA2ZB_COMMANDS = {
    ZclCC.OPEN: TuyaCC.OPEN,
    ZclCC.CLOSE: TuyaCC.CLOSE,
    ZclCC.STOP: TuyaCC.STOP,
}

Also, remove the int() wrap from https://github.com/zigpy/zha-device-handlers/issues/1953#issuecomment-1462707698

            cluster_data = TuyaClusterData(
                endpoint_id=self.endpoint.endpoint_id,
                cluster_name=self.ep_attribute,
                cluster_attr="curtain_switch",
                attr_value=TUYA2ZB_COMMANDS[command_id],  # convert tuya2zigbee command
                expect_reply=expect_reply,
                manufacturer=-1,
            )

Save changes, remove any __pycache__ folder and restart.

javicalle commented 1 year ago

BTW, do you have any motor_steering (0xF002) attribute in the TuyaWindowCovering cluster? Can you read the value and try to check setting 0/1 values?

caradas commented 1 year ago

Your Code proposal is working as expected. Thank you.

2023-03-20 13:50:02.029 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0xef00] raw: b'\x01'

BTW, do you have any motor_steering (0xF002) attribute in the TuyaWindowCovering cluster? Can you read the value and try to check setting 0/1 values?

grafik Log:

2023-03-20 13:55:32.972 DEBUG (MainThread) [zigpy.zcl] [0x3F47:1:0x0102] Couldn't normalize 61442 attribute with enum8.undefined_0x00 value
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/zigpy/zcl/__init__.py", line 481, in read_attributes
    value = self.attributes[record.attrid].type(record.value.value)
  File "/usr/local/lib/python3.10/site-packages/zigpy/types/basic.py", line 368, in __call__
    value = int(value)
ValueError: invalid literal for int() with base 10: 'enum8.undefined_0x00'
danidask commented 11 months ago

It works. Let me sum up all the steps and the updated quirk file: You'll need the HA File editor, can be installed via settings->add-ons in the file editor, open config/configuration.yaml an add:

zha:
  custom_quirks_path: /config/custom_zha_quirks/

This will look for quirks in that folder, so create the folder custom_zha_quirks inside config (can be also done with File editor) and inside create a file named TZE200_r0jdjrvi.py and copy the content of this file: TZE200_r0jdjrvi.py.txt Restart Home Assistant

P.D for pairing mode, press the button in the base of the motor 3 times and then keep it pressed for the forth time for like two seconds. green led will start blinking

utech-git commented 9 months ago

Hello, guys.

I was having problem pairing and using a similar model curtain motor. But the the quirk file that @danidask posted on his last comment worked like a charm. I just had to change TZE200 to TZE204 on line 261, because my motor model is _TZE204_r0jdjrvi.

The one thing that still isn't working is the curtain state whenever i use the set_position service (either by calling it manually or by selecting the appropriate position on the scroller in the UI).

If click on the half of the bar (50%) and the curtain goes to that position, the state of the curtain keeps on "Opening" forever. I have to click the Stop button for the state to change to Open. The same thing happens with the Closing state.

Is there a way to fix this?

tbhova commented 9 months ago

You might need to reverse the motor direction reporting. IIRC, this is an option in the quirk.

On Sat, Sep 23, 2023, 4:43 PM utech-git @.***> wrote:

Hello, guys.

I was having problem pairing and using a similar model curtain motor. But the the quirk file that @danidask https://github.com/danidask posted on his last comment worked like a charm. I just had to change TZE200 to TZE204 on line 261, because my motor model is _TZE204_r0jdjrvi.

The one thing that still isn't working is the curtain state whenever i use the set_position service (either by calling it manually or by selecting the appropriate position on the scroller in the UI).

If click on the half of the bar (50%) and the curtain goes to that position, the state of the curtain keeps on "Opening" forever. I have to click the Stop button for the state to change to Open. The same thing happens with the Closing state.

Is there a way to fix this?

— Reply to this email directly, view it on GitHub https://github.com/zigpy/zha-device-handlers/issues/1953#issuecomment-1732405616, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACFFMXQUSUNHURUSRSGBOGDX35CY7ANCNFSM6AAAAAASHGFG3Q . You are receiving this because you are subscribed to this thread.Message ID: @.***>

javicalle commented 9 months ago

Is there a way to fix this?

https://github.com/home-assistant/core/pull/99646

Onepamopa commented 9 months ago

It works. Let me sum up all the steps and the updated quirk file: You'll need the HA File editor, can be installed via settings->add-ons in the file editor, open config/configuration.yaml an add:

zha:
  custom_quirks_path: /config/custom_zha_quirks/

This will look for quirks in that folder, so create the folder custom_zha_quirks inside config (can be also done with File editor) and inside create a file named TZE200_r0jdjrvi.py and copy the content of this file: TZE200_r0jdjrvi.py.txt Restart Home Assistant

P.D for pairing mode, press the button in the base of the motor 3 times and then keep it pressed for the forth time for like two seconds. green led will start blinking

_TZE200_r0jdjrvi TS0601 -- Added as described, but there is no slider? Latest ha version...

IEEE: a4:c1:38:3e:e4:4e:76:90 Nwk: 0x431e Device Type: Router LQI: 255 RSSI: -75 Power source: Mains Quirk: TZE200_r0jdjrvi.TuyaCover0601_GP

The motor is currently sitting on my desk (was never installed on the curtain track, was never calibrated (I've no idea how to calibrate it)).

Open / Close do rotate the motor, but when Stop is pressed - Failed to call service cover/stop_cover. '>' not supported between instances of 'NoneType' and 'int':

2023-10-07 22:13:07.392 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection] [546958404032] '>' not supported between instances of 'NoneType' and 'int' Traceback (most recent call last): File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 226, in handle_call_service await hass.services.async_call( File "/usr/src/homeassistant/homeassistant/core.py", line 2012, in async_call response_data = await coro ^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/core.py", line 2049, in _execute_service return await target(service_call) ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/helpers/entity_component.py", line 235, in handle_service return await service.entity_service_call( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 876, in entity_service_call response_data = await _handle_entity_call( ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 948, in _handle_entity_call result = await task ^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/components/zha/cover.py", line 170, in async_stop_cover self._state = STATE_OPEN if self._current_position > 0 else STATE_CLOSED ^^^^^^^^^^^^^^^^^^^^^^^^^^ TypeError: '>' not supported between instances of 'NoneType' and 'int'

The curtain motor is this one: IMG_6154 IMG_6155