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

Tuya Curtain Motor

Open tube0013 opened this issue 4 years ago • 268 comments

Is your feature request related to a problem? Please describe.

Request and placehoder for information about the Tuya Curtain motor > specfically:

https://zigbee.blakadder.com/Moes_AM43-0_45_40-ES-EB.html

z2m device: https://github.com/Koenkk/zigbee-herdsman-converters/blob/9e4c36cd79e15449830f5e09540157c0e8d686a1/devices.js#L1481

z2m fromZigbee: https://github.com/Koenkk/zigbee-herdsman-converters/blob/9e4c36cd79e15449830f5e09540157c0e8d686a1/converters/fromZigbee.js#L1490

z2m toZigbee: https://github.com/Koenkk/zigbee-herdsman-converters/blob/9e4c36cd79e15449830f5e09540157c0e8d686a1/converters/toZigbee.js#L3377

Describe the solution you'd like

ZHA support :)

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

{
  "node_descriptor": "NodeDescriptor(byte1=2, byte2=64, mac_capability_flags=128, manufacturer_code=4098, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, descriptor_capability_field=0)",
  "endpoints": {
    "1": {
      "profile_id": 260,
      "device_type": "0x0051",
      "in_clusters": [
        "0x0000",
        "0x0004",
        "0x0005",
        "0xef00"
      ],
      "out_clusters": [
        "0x000a",
        "0x0019"
      ]
    }
  },
  "manufacturer": "_TZE200_rddyvrci",
  "model": "TS0601",
  "class": "zigpy.device.Device"
}

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

For reference since the only place I found it was in the review comments on Aliexpress. to get into pairing mode, hold the set and down button simultaneously until light blinks.

tube0013 avatar Jan 23 '21 19:01 tube0013

Tuya has become just one huge PITA. Why they couldn't at least differentiate by device type? This kills the idea of using "wildcard" manufacturers quirk, because two different devices have exactly the same signature.

Adminiuga avatar Jan 23 '21 19:01 Adminiuga

As long as a direct match always wins I wouldn’t say this kills it...

dmulcahey avatar Jan 23 '21 20:01 dmulcahey

That's true. Just means that we need to pick for which devices to use a wildcard match and for which ones to use model+manufacturer specific matches. I just hate they are that lazy to change at least the device id

Adminiuga avatar Jan 23 '21 20:01 Adminiuga

all these modules come from tuya with the same TS0601 model to the manufacturing shops.

the manufactures hit up the tuya sdk site flip a couple things or follow steps from tuya to configure the module for the type of device, output a fw, and push it to the devices. they also add their code for the manufacturer possibly based on the PID or derived from it - you see this mentioned in the tuya docs and what the factory I communicated with kept mentioning.

tube0013 avatar Jan 23 '21 20:01 tube0013

I just moved to ZHA from Deconz + Phoscon and I if I'm not mistaken implementing this one will solve the integration for every QS-Zigbee-C01 curtain module? This one needs calibration upon first use, and as mentioned in this Home Assistant Community thread, this attribute isn't exposed at all currently through the clusters.

I'm just getting my feet wet with ZHA quirks and while I've been with Python for a while now, adding functionality etc...seems less intimidating in Zigbee2MQTT than in ZHA quirks. I guess it's just a matter of getting more familiar with Zigbee itself. Any pointers on where I would start to expose the relevant cluster attributes would be super appreciated.

SHxKM avatar Jan 31 '21 11:01 SHxKM

I have a curtain Zemismart ZM79E-DT (Tuya). Signature:

{
  "node_descriptor": "NodeDescriptor(byte1=1, byte2=64, mac_capability_flags=142, manufacturer_code=4098, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, descriptor_capability_field=0)",
  "endpoints": {
    "1": {
      "profile_id": 260,
      "device_type": "0x0051",
      "in_clusters": [
        "0x0000",
        "0x0004",
        "0x0005",
        "0x000a",
        "0xef00"
      ],
      "out_clusters": [
        "0x0019"
      ]
    }
  },
  "manufacturer": "_TZE200_cowvfni3",
  "model": "TS0601",
  "class": "zigpy.device.Device"
}

Protocol description: https://github.com/Koenkk/zigbee-herdsman-converters/issues/1159#issuecomment-614659802

hertznsk avatar Feb 07 '21 21:02 hertznsk

I have Moeshouse one from here: https://zigbee.blakadder.com/Moes_AM43-0_45_40-ES-EB.html

Paired to ZHA but doesn't show any entities or services..

Below signature: { "node_descriptor": "NodeDescriptor(byte1=2, byte2=64, mac_capability_flags=128, manufacturer_code=4098, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, descriptor_capability_field=0)", "endpoints": { "1": { "profile_id": 260, "device_type": "0x0051", "in_clusters": [ "0x0000", "0x0004", "0x0005", "0xef00" ], "out_clusters": [ "0x000a", "0x0019" ] } }, "manufacturer": "_TZE200_zah67ekd", "model": "TS0601", "class": "zigpy.device.Device" }

rednus avatar Feb 19 '21 10:02 rednus

Zemismart here https://zigbee.blakadder.com/Zemismart_M515EGB.html

{ "node_descriptor": "NodeDescriptor(byte1=1, byte2=64, mac_capability_flags=142, manufacturer_code=4098, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, descriptor_capability_field=0)", "endpoints": { "1": { "profile_id": 260, "device_type": "0x0051", "in_clusters": [ "0x0000", "0x0004", "0x0005", "0xef00" ], "out_clusters": [ "0x000a", "0x0019" ] } }, "manufacturer": "_TZE200_xuzcvlku", "model": "TS0601", "class": "zigpy.device.Device" }

alekslyse avatar Feb 21 '21 13:02 alekslyse

It seems like if someone make a quirk for one we can just copy them. They seem like the same product, just different manufacturer

alekslyse avatar Feb 21 '21 13:02 alekslyse

I've also got roller blinds motor AM43-0.45/40-ES-EB.

Recognized by ZHA as _TZE200_zah67ekd TS0601.

Signature:

{
  "node_descriptor": "NodeDescriptor(byte1=2, byte2=64, mac_capability_flags=128, manufacturer_code=4098, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, descriptor_capability_field=0)",
  "endpoints": {
    "1": {
      "profile_id": 260,
      "device_type": "0x0051",
      "in_clusters": [
        "0x0000",
        "0x0004",
        "0x0005",
        "0xef00"
      ],
      "out_clusters": [
        "0x000a",
        "0x0019"
      ]
    }
  },
  "manufacturer": "_TZE200_zah67ekd",
  "model": "TS0601",
  "class": "zigpy.device.Device"
}

I've got some Python experience, but I'm new to the ecosystem. Will be ready to help if someone guides me from where to start.

rdhlb avatar Feb 23 '21 20:02 rdhlb

I am not an expert but managed to do some copy+paste magic and at least make the first step towards working quirk..

So ZHA recognises my quirk and assigns Up/Down/Stop buttons.. but commands are not in right order clicking Up works, but Stop and Down seems to be swapped..

image

Any advice highly appreciated.. below my code..

Add below code to the end of /usr/local/lib/python3.8/site-packages/zhaquirks/tuya/init.py

########################################################################################

from zigpy.zcl.clusters.closures import WindowCovering

class TuyaOpenClose(CustomCluster, WindowCovering):
    """Tuya Open/Close cluster for Blind Controller device."""

    def __init__(self, *args, **kwargs):
        """Init."""
        super().__init__(*args, **kwargs)
        self.endpoint.device.blind_bus.add_listener(self)

    def switch_event(self, channel, state):
        """Switch event."""
        _LOGGER.info(
            "%s - -----------------Received blind event message, channel: %d, state: %d",
            self.endpoint.device.ieee,
            channel,
            state,
        )
        self._update_attribute(ATTR_ON_OFF, state)

    def command(
        self,
        command_id: Union[foundation.Command, 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 command_id in (0x0000, 0x0001, 0x0002):
            cmd_payload = TuyaManufCluster.Command()
            cmd_payload.status = 0
            cmd_payload.tsn = 0
            cmd_payload.command_id = TUYA_CMD_BASE + self.endpoint.endpoint_id
            cmd_payload.function = 0
            cmd_payload.data = [1, command_id]

            return self.endpoint.tuya_manufacturer.command(
                TUYA_SET_DATA, cmd_payload, expect_reply=True
            )

        return foundation.Status.UNSUP_CLUSTER_COMMAND


class TuyaManufacturerClusterOpenClose(TuyaManufCluster):
    """Manufacturer Specific Cluster of Open/Close device."""

    def handle_cluster_request(
        self,
        hdr: foundation.ZCLHeader,
        args: Tuple[TuyaManufCluster.Command],
        *,
        dst_addressing: Optional[
            Union[t.Addressing.Group, t.Addressing.IEEE, t.Addressing.NWK]
        ] = None,
    ) -> None:
        """Handle cluster request."""

        tuya_payload = args[0]
        if hdr.command_id in (0x0002, 0x0001, 0x0000):
            self.endpoint.device.blind_bus.listener_event(
                SWITCH_EVENT,
                tuya_payload.command_id - TUYA_CMD_BASE,
                tuya_payload.data[1],
            )

class TuyaBlinds(CustomDevice):
    """Generic Tuya thermostat device."""

    def __init__(self, *args, **kwargs):
        """Init device."""
        self.blind_bus = Bus()
        self.ui_bus = Bus()
        self.battery_bus = Bus()
        super().__init__(*args, **kwargs)

Then create a new file called /usr/local/lib/python3.8/site-packages/zhaquirks/tuya/blinds.py with code below:

"""Tuya based blind controller."""
from zigpy.profiles import zha
from zigpy.zcl.clusters.general import Basic, Groups, Ota, Scenes, Time

from ..const import (
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
)
from ..tuya import TuyaManufacturerClusterOnOff, TuyaManufCluster, TuyaOnOff, TuyaSwitch, TuyaBlinds, TuyaManufacturerClusterOpenClose, TuyaOpenClose

class MoesBlindController(TuyaBlinds):
    """Tuya blind controller device."""

    signature = {
		#"node_descriptor": "NodeDescriptor(byte1=2, byte2=64, mac_capability_flags=128, manufacturer_code=4098, 
		#                    maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, 
		#                    maximum_outgoing_transfer_size=82, descriptor_capability_field=0)",
		# "endpoints": {
		# "1": {
		# "profile_id": 260,
		# "device_type": "0x0051",
		# "in_clusters": [
		#	"0x0000",
        #	"0x0004",
        #	"0x0005",
        #	"0xef00"
		# ],
		# "out_clusters": [
        # 	"0x000a",
        #	"0x0019"
		# ]
		# }
		# },
		# "manufacturer": "_TZE200_zah67ekd",
		# "model": "TS0601",
		# "class": "zigpy.device.Device"
		# }
        MODELS_INFO: [("_TZE200_zah67ekd", "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],
            }
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaManufacturerClusterOpenClose,
                    TuyaOpenClose,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            }
        }
    }

rednus avatar Feb 28 '21 02:02 rednus

I made a quirks which is working with my Zemismart ZM25TQ. It's here.

If you look at the implementation in mqtt2zigbee there are quite few differences but it should be possible to support all the various devices listed here

blauret avatar Mar 03 '21 20:03 blauret

I made a quirks which is working with my Zemismart ZM25TQ. It's here.

If you look at the implementation in mqtt2zigbee there are quite few differences but it should be possible to support all the various devices listed here

Thank you!

I gave this a shot with my MOES based one after adjusting the signature to match it, it functions however the buttons are not triggering correctly.

Down: motor turns counter clockwise Stop: motor turns clockwise Up: motor stops

I saw the mapping in init.py for the command but not picking up on how it's done. if you point me in the right direction I can hopefully add support for the moes as well.

tube0013 avatar Mar 04 '21 02:03 tube0013

The quirks receives from HA:

    0x0000: ("up_open", (), False),
    0x0001: ("down_close", (), False),
    0x0002: ("stop", (), False),

The motor I tested wants:

  • up: 0
  • stop : 1
  • down : 2

To control properly I map:

1 -> 2 2 -> 1

In your case I guess the right mapping should be

TUYA_COVER_COMMAND = {0x0000: 0x0001, 0x0001: 0x0002, 0x0002: 0x0000}

blauret avatar Mar 04 '21 07:03 blauret

I made a quirks which is working with my Zemismart ZM25TQ. It's here.

If you look at the implementation in mqtt2zigbee there are quite few differences but it should be possible to support all the various devices listed here

Could you add my model "manufacturer": "_TZE200_xuzcvlku","model": "TS0601" to your PR - From what I can see they are identical, and you can add several models to your quirk (same vendor)

alekslyse avatar Mar 04 '21 16:03 alekslyse

Excuse my ignorance, as I am no expert, but how do we make these changes work for everyone?

Based on the observations from @tube0013 it seems as though each device might have slightly different control mapping. Reviewing the changes, it looks like the mapping is included in the __init__.py file. Would we have to add a new line like this for every different device?

TUYA_COVER_COMMAND = {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001}
TUYA_COVER_COMMAND_2 = {0x0000: 0x0001, 0x0001: 0x0002, 0x0002: 0x0000}

And then somehow reference that line in the manufacturer specific quirk file TS0601.py? Or do we create another class in the __init__.py file and then reference that in the manufacturer specific file?

Again, sorry if this sounds dumb I'm just trying to wrap my head around this.

ScottEgan avatar Mar 04 '21 16:03 ScottEgan

Again, sorry if this sounds dumb I'm just trying to wrap my head around this.

I don't claim to have known what I was doing when I wrote this code ;)

It's the first Tuya cover quirks. looking at zigbee2mqtt there are lots of variation. I did not think about how the code would scale for other devices.

blauret avatar Mar 04 '21 17:03 blauret

Could you add my model "manufacturer": "_TZE200_xuzcvlku","model": "TS0601" to your PR - From what I can see they are identical, and you can add several models to your quirk (same vendor)

Done

blauret avatar Mar 04 '21 17:03 blauret

I don't claim to have known what I was doing when I wrote this code ;)

You got farther than I did! Thank you for getting us this far!

Maybe someone with some more experience can chime in on what the typical procedure is for handling multiple devices with small differences?

ScottEgan avatar Mar 04 '21 18:03 ScottEgan

@blauret could you please add the below code to ts0601.py The In and out clusters are different on Moes.

PS: I have tested it and it works..

class TuyaMoesCover0601(TuyaWindowCover):
    """Tuya blind controller device."""

    signature = {
        #"node_descriptor": "NodeDescriptor(byte1=2, byte2=64, mac_capability_flags=128, manufacturer_code=4098, 
        #                    maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, 
        #                    maximum_outgoing_transfer_size=82, descriptor_capability_field=0)",
        # "endpoints": {
        # "1": { "profile_id": 260, "device_type": "0x0051", "in_clusters": [ "0x0000", "0x0004","0x0005","0xef00"], "out_clusters": ["0x000a","0x0019"] }
        # },
        # "manufacturer": "_TZE200_zah67ekd",
        # "model": "TS0601",
        # "class": "zigpy.device.Device"
        # }
        MODELS_INFO: [("_TZE200_zah67ekd", "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],
            }
        },
    }

    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],
            }
        }
    }

rednus avatar Mar 04 '21 18:03 rednus

Thanks @rednus, I have the same model and confirm that this works for me too. (Even the buttons are correct!)

daniel-sanche avatar Mar 04 '21 19:03 daniel-sanche

Thanks @rednus, I have the same model and confirm that this works for me too. (Even the buttons are correct!)

Added

blauret avatar Mar 05 '21 08:03 blauret

Thank you @blauret

rednus avatar Mar 05 '21 08:03 rednus

I used a quirk https://github.com/zigpy/zha-device-handlers/pull/801 for my Zemismart ZM79E-DT, adding "_TZE200_cowvfni3", but the correct operation of the buttons is provided with the following line: TUYA_COVER_COMMAND = {0x0000: 0x0002, 0x0001: 0x0000, 0x0002: 0x0001}

hertznsk avatar Mar 07 '21 11:03 hertznsk

@blauret - is your device working with "SET COVER POSITION"???

For me full open and full close working.. but using slider to open to a set position does not.

I am getting below error:

  File "/usr/src/homeassistant/homeassistant/components/zha/core/channels/base.py", line 49, in wrapper,
    result = await command(*args, **kwds),
    res = await self._cover_channel.go_to_lift_percentage(100 - new_pos),
  File "/usr/src/homeassistant/homeassistant/components/zha/cover.py", line 138, in async_set_cover_position,
TypeError: object Status can't be used in 'await' expression,
    await result,
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 679, in _handle_entity_call,
    await coro,
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 681, in async_request_call,
    future.result()  # pop exception if have,
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 642, in entity_service_call,
    await self.hass.helpers.service.entity_service_call(,
  File "/usr/src/homeassistant/homeassistant/helpers/entity_component.py", line 204, in handle_service,
    await handler.job.target(service_call),
  File "/usr/src/homeassistant/homeassistant/core.py", line 1523, in _execute_service,
    task.result(),
  File "/usr/src/homeassistant/homeassistant/core.py", line 1488, in async_call,
    await hass.services.async_call(,
  File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 137, in handle_call_service,
Traceback (most recent call last):,
2021-03-07 23:42:54 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection] [140254504932400] object Status can't be used in 'await' expression

rednus avatar Mar 07 '21 23:03 rednus

It won't work. the mapping ("TUYA_COVER_COMMAND") is used for all command ids. Command id 2 should get, I believe a 4 bytes data with the percentage in the lowest byte.

the code should look something like that:

@@ -608,12 +608,13 @@ class TuyaWindowCoverControl(LocalDataCluster, WindowCovering):
     ):
         """Override the default Cluster command."""
 
-        if command_id in (0x0000, 0x0001, 0x0002):
-            cmd_payload = TuyaManufCluster.Command()
-            cmd_payload.status = 0
-            cmd_payload.tsn = 0
-            cmd_payload.command_id = TUYA_CMD_BASE + self.endpoint.endpoint_id
-            cmd_payload.function = 0
+        cmd_payload = TuyaManufCluster.Command()
+        cmd_payload.status = 0
+        cmd_payload.tsn = 0
+        cmd_payload.command_id = TUYA_CMD_BASE + self.endpoint.endpoint_id
+        cmd_payload.function = 0
+
+        if command_id == 0x0001:
             cmd_payload.data = [
                 1,
                 TUYA_COVER_COMMAND[command_id],
@@ -622,6 +623,16 @@ class TuyaWindowCoverControl(LocalDataCluster, WindowCovering):
             return self.endpoint.tuya_manufacturer.command(
                 TUYA_SET_DATA, cmd_payload, expect_reply=True
             )
+        elif command_id == 0x0002:
+            cmd_payload.data = [
+                4,
+                100 - position,
+            ]  # remap the command to the Tuya command
+
+            return self.endpoint.tuya_manufacturer.command(
+                TUYA_SET_DATA, cmd_payload, expect_reply=True
+            )
+            
 
         return foundation.Status.UNSUP_CLUSTER_COMMAND

To be honnest, I never used that so I'm not really looking at implementing. Also, I cannot test it at the moment. If you confirm you have something working and I can test, I'll add it to the PR

blauret avatar Mar 08 '21 08:03 blauret

Will this work with this motor, seems very similar to others here ?

{
  "node_descriptor": "NodeDescriptor(byte1=1, byte2=64, mac_capability_flags=142, manufacturer_code=4098, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, descriptor_capability_field=0)",
  "endpoints": {
    "1": {
      "profile_id": 260,
      "device_type": "0x0051",
      "in_clusters": [
        "0x0000",
        "0x0004",
        "0x0005",
        "0x000a",
        "0xef00"
      ],
      "out_clusters": [
        "0x0019"
      ]
    }
  },
  "manufacturer": "_TZE200_3i3exuay",
  "model": "TS0601",
  "class": "zigpy.device.Device"
}

holdestmade avatar Mar 08 '21 13:03 holdestmade

It won't work. the mapping ("TUYA_COVER_COMMAND") is used for all command ids. Command id 2 should get, I believe a 4 bytes data with the percentage in the lowest byte.

@blauret I figured it out..

  • The cluster command for Set position is 0x0005
  • Then we need a right value for cmd_payload.command_id (which i figured is 0x02 based on z2mqtt code)
  • Finally data array needs to be [4,0,0,0,position]

Below code works perfectly on my moeshouse roller.. test your device..

class TuyaWindowCoverControl(LocalDataCluster, WindowCovering):
    """Manufacturer Specific Cluster of Device cover."""

    def __init__(self, *args, **kwargs):
        """Initialize instance."""
        super().__init__(*args, **kwargs)
        self.endpoint.device.cover_bus.add_listener(self)

    def cover_event(self, command, value):
        """Cover event. update the position."""
        self._update_attribute(ATTR_COVER_POSITION, 100 - value[4])

    def command(
        self,
        command_id: Union[foundation.Command, 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."""
        _LOGGER.info( "--------------- Sending Tuya Cluster Command..." )
        _LOGGER.info( "--------------- Cluster Command is %x", command_id)
        _LOGGER.info( "--------------- Arugments are %s", args)
        if command_id in (0x0000, 0x0001, 0x0002):
            cmd_payload = TuyaManufCluster.Command()
            cmd_payload.status = 0
            cmd_payload.tsn = 0
            cmd_payload.command_id = TUYA_CMD_BASE + self.endpoint.endpoint_id
            cmd_payload.function = 0
            cmd_payload.data = [
                1,
                TUYA_COVER_COMMAND[command_id],
            ]  # remap the command to the Tuya command
            _LOGGER.info( "--------------- Payload Tuya Command is %x", cmd_payload.command_id)
            return self.endpoint.tuya_manufacturer.command(
                TUYA_SET_DATA, cmd_payload, expect_reply=True
            )
            
        elif command_id == 0x0005:
            cmd_payload = TuyaManufCluster.Command()
            cmd_payload.status = 0
            cmd_payload.tsn = 0
            cmd_payload.command_id = 0x02
            cmd_payload.function = 0
            position = args[0]
            cmd_payload.data = [
                4, 0, 0,
                100 - position,
            ]  

            _LOGGER.info( "--------------- Payload Tuya Command is %x", cmd_payload.command_id)
            _LOGGER.info( "--------------- Payload data is %s", cmd_payload.data)

            return self.endpoint.tuya_manufacturer.command(
                TUYA_SET_DATA, cmd_payload, expect_reply=True
            )
        elif command_id == 0x0006:
            cmd_payload = TuyaManufCluster.Command()
            cmd_payload.status = args[0]
            cmd_payload.tsn = args[1]
            cmd_payload.command_id = args[2]
            cmd_payload.function = args[3]
            cmd_payload.data = args[4]

            _LOGGER.info( "--------------- Sending Custom Command ----------------------------------")

            return self.endpoint.tuya_manufacturer.command(
                TUYA_SET_DATA, cmd_payload, expect_reply=True
            )
        return foundation.Status.UNSUP_CLUSTER_COMMAND

The last one, 0x0006 you can use to debug from Dev Tools -> Services -> zha.issue_cluser_command with below data. This is useful rather than changing the code everytime to see if it works or not..

service: zha.issue_zigbee_cluster_command
data:
  ieee: 'xx:xx:xx:xx:xx'
  endpoint_id: 1
  cluster_id: 258
  cluster_type: in
  command_type: server
  command: 6
  args:
    - 0
    - 0
    - 2
    - 0
    - - 4
      - 0
      - 0
      - 0
      - 90

rednus avatar Mar 08 '21 13:03 rednus

@rednus, I updated the PR

blauret avatar Mar 08 '21 14:03 blauret

@rednus, I updated the PR

Did it work for you?

rednus avatar Mar 08 '21 14:03 rednus