Switch Zigbee TZE200 TS0601 paired but without entities

Was there a solution to this?

I have a zigbee blinds motor showing as “TS0601 by _TZE200_pw7mji0l” via ZHA. No entities appearing.

You will need to add a line for ("_TZE200_pw7mji0l", "TS0601") to existing quirk if there already is another Tuya device that only has a different Zigbee device signature, if not then it needs a new quirk.

Either add a custom quirk and submit code or submit a device feature request to the respective project.

https://github.com/zigpy/zha-device-handlers/issues/new/choose

https://github.com/Koenkk/zigbee2mqtt/issues/new/choose

ZHA needs a quirk/handler for zha-quirks just as Zigbee2MQTT need a converter for zigbee-herdsman:

https://www.home-assistant.io/integrations/zha#zha-exception-and-deviation-handling

(https://github.com/zigpy/zha-device-handlers)

respectively

https://www.zigbee2mqtt.io/advanced/support-new-devices/01_support_new_devices.html

(https://github.com/Koenkk/zigbee-herdsman-converters)

The reason why is explained here:

https://www.home-assistant.io/integrations/zha#knowing-which-devices-are-supported

and

https://www.home-assistant.io/integrations/zha#zha-exception-and-deviation-handling

Both of those are custom quirks implementations that add translations for deviations from standards.

2 Likes

Hi,

I have the same issue with blinds switch.
I am running Home Assistant on a container on Raspberry Pi 4, with the Sonoff Zigbee Dongle.
The signature of the device is

{
  "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress|RxOnWhenIdle|MainsPowered|FullFunctionDevice: 142>, manufacturer_code=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)",
  "endpoints": {
    "1": {
      "profile_id": 260,
      "device_type": "0x0051",
      "in_clusters": [
        "0x0000",
        "0x0004",
        "0x0005",
        "0xef00"
      ],
      "out_clusters": [
        "0x000a",
        "0x0019"
      ]
    },
    "242": {
      "profile_id": 41440,
      "device_type": "0x0061",
      "in_clusters": [],
      "out_clusters": [
        "0x0021"
      ]
    }
  },
  "manufacturer": "_TZE200_jhkttplm",
  "model": "TS0601",
  "class": "zigpy.device.Device"
}

Any idea how to solve it?

Hello - I have a similar situation with a temp and humidity sensor. Can we get this added to the ZHA? It is adopted but no values.

TS0601

by _TZE200_qoy0ekbd

Connected via Zigbee Coordinator

Zigbee info

IEEE: a4:c1:38:a2:9d:1a:12:50

Nwk: 0x7a78

Device Type: EndDevice

LQI: 80

RSSI: Unknown

Last Seen: 2022-09-08T09:02:10

Power Source: Battery or Unknown

Can anyone help me make a custom quirk for this? Supposed to report temp, humidity, and battery level.
{
“node_descriptor”: “NodeDescriptor(logical_type=<LogicalType.EndDevice: 2>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress: 128>, manufacturer_code=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=True, *is_full_function_device=False, *is_mains_powered=False, *is_receiver_on_when_idle=False, *is_router=False, *is_security_capable=False)”,
“endpoints”: {
“1”: {
“profile_id”: 260,
“device_type”: “0x0302”,
“in_clusters”: [
“0x0000”,
“0x0001”,
“0x0402”,
“0x0405”
],
“out_clusters”: [
“0x000a”,
“0x0019”
]
}
},
“manufacturer”: “_TZE200_qoy0ekbd”,
“model”: “TS0601”,
“class”: “zigpy.device.Device”
}

Hi.
I have the same problem in ZHA: Tuya Smart Zigbee Dimmer model EDM-1ZBB-EU shown as Light with Device info: TS0601 by _TZE200_dfxkcots not as a Dimmer.
Is there a solution for ZHA?
The only solution is ZIGBEE2MQTT ?

Looks like it’s already been worked.

The forum IS NOT the best place for ZHA device support. Devs don’t look here.

With Tuya, best to search for the manufacturer ID ( _TZE200_dfxkcots ) at:

1 Like

ZIGBEE2MQTT seems like the best that I have seen to date. ZHA didn’t work for me so I integrated an MQTT broker, added ZIGBEE2MQTT, and haven’t had any issues since. Works well for me. Good luck!

As mentioned, for ZHA device issues start by submitting a new device support request with signature and debug logs to ZHA Device Handlers → https://github.com/zigpy/zha-device-handlers/issues

ZHA will need a quirk/handler for zha-quirks if devices do not fully follow standard Zigbee specifcations, see → https://www.home-assistant.io/integrations/zha#zha-exception-and-deviation-handling

Similar issue here.

I bought a Beca smart thermostat for gas boiler, which identifies itself as being manufactured by “_TZE200_u9bfwha0”. Works fine with Zigbee2MQTT. Detected by ZHA but no entities shown.

I can see that the signature for this device was addedd in this commit 9 days ago, so I presume the support is already on place but the code didn’t reach the public yet.

Does anyone know how much time can take a fix to propagate to a HA stable version?

Thanks.

Generally new quirks will be in the next monthly release. So most likely it will be in 2022.10 if there wasn’t anything else going on with ZHA to delay it.

Looks like If you follow the links in the commit, you’ll find a custom quirk version of the fix you can install off cycle.

It depends so best is to compare closed bump ZHA quirk dependencies → Pull requests · home-assistant/core · GitHub with zha-device-handlers releases changelog → Releases · zigpy/zha-device-handlers · GitHub

Anyway, Home Assistant 2022.10.0 release does contain * zha-quirks 0.0.81 and Home Assistant 2022.10.1 release will likley contain zha-quirks 0.0.82

Hi.
I have two of this thermostats and after migrating to z2m I can see all the settings. Plus, it improved connectivity with ikea plugs… Once you move from zha, never watch back!

1 Like

Hi All, I also ave a zigbee curtain controller. I managed to get it working with one of the proposed quirks here. Opening en closing the curtain works. Stopping the curtain works as well, but If I stop the curtain in the middle of opening/closing I cannot continue in that same direction since the button for either opening or closing is disabled. I also see an error popping up when I hit the stop button.
Could it be that the error is causing the button to stay disabled?

So what happens: I close the curtain, half-way I hit ‘stop’. Now the button for closing the curtain stays disabled, so I cannot continue in that direction. I have to click the ‘open’ button, and only then ‘close’ becomes enabled again.

2023-03-12 15:23:50.319 WARNING (MainThread) [zigpy.util] Error calling listener <bound method TuyaMCUCluster.tuya_mcu_command of <ts0601_cover_custom2.TuyaWindowCoverManufCluster object at 0x7f4965bb4130>> with args (TuyaClusterData(endpoint_id=1, cluster_attr='curtain_switch', attr_value=1, expect_reply=True, manufacturer=-1),): TypeError('getattr(): attribute name must be string')
2023-03-12 15:23:50.323 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection] [139953102519264] '>' not supported between instances of 'NoneType' and 'int'
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 200, in handle_call_service
    await hass.services.async_call(
  File "/usr/src/homeassistant/homeassistant/core.py", line 1787, in async_call
    task.result()
  File "/usr/src/homeassistant/homeassistant/core.py", line 1824, in _execute_service
    await cast(Callable[[ServiceCall], Awaitable[None]], handler.job.target)(
  File "/usr/src/homeassistant/homeassistant/helpers/entity_component.py", line 213, in handle_service
    await service.entity_service_call(
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 680, in entity_service_call
    future.result()  # pop exception if have
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 968, in async_request_call
    await coro
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 720, in _handle_entity_call
    await result
  File "/usr/src/homeassistant/homeassistant/components/zha/cover.py", line 162, 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 quirk I'm using:
"""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/537ad639891c81083e2bc5a114fe428f171b69bd/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,
        ),
        #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 = {
        # "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],
            },
        }
    }

I think I need an additional model added. Can we address it here or should I open a new issue?
My model is TS0601 and manufacturer is _TZE200_bv1jcqqu. The product is ZM25RZ01, a battery powered roller blind.

I bought this TZE200_mgxy2d9f TS0601

https://www.aliexpress.com/item/1005004889704535.html?spm=a2g0o.order_list.order_list_main.17.3e7f1802XsznfN

It seems to be an interesting sensor but so far no entities while adding to ZHA. How or can it be added to ZHA?