TUYA TS0601 Zigbee garage door opener

Hey all,

So… I consider myself a decently sophisticated with HA. I saw this garage door opener device on Ali Express, and am maybe more naïve than I thought. Of course I’ve had success with other sensors and devices being part of other platforms (like Philips Hue, for example), where I don’t even need to have other gateways running, and just connect it natively through my Zigbee antenna, and the ZHA integration.

I was assuming (hoping, admittedly) that this zigbee garage door opener would be the same, because a review or two on Ali Express said that it worked great with Home Assistant. So… my question is… has anyone else had experience with this? If so, did it work because you were running a Tuya gateway already, or did you somehow get it to work with ZHA natively?

It recognizes the device immediately in ZHA, but I only end up with this device…

Any input/advice is appreciated!

Thanks!

(Edited for spelling error.)

1 Like

Looks like ZHA will need a quirk added. Almost all Tuya devices need one. If you have the time to provide the devs with requested info, open a ticket at Issues · zigpy/zha-device-handlers · GitHub.

If its a simple variation of an already supported device, it may be pretty quick.

My guess is any “works with HA” comments were referring to zigbee2mqtt.

Thank you for the pointer to request development, jerrm!! Much appreciated, and I’ve submitted. I wouldn’t have known were to go with that.

I’m having the exact same issue here. Did you receive any updates on this?

Sure thing @kimme1024! I should have come back and posted here (all in one place) anyway! So… to be clear, this would need to be the exact same device, as quirks depend on the Zigbee signature. My device shows up as:
Manufacturer: _TZE200_nklqjk62
Model: TS0601

  • In your Home Assistant /config folder, create a subfolder named zhaquirks.
  • In your configuration.yaml file, insert the following two lines somewhere below the “default_config” line in the file, and save.
zha:
  custom_quirks_path: /config/zhaquirks
  • Copy and paste the following code, exactly as it is, into a text file, and name that file “ts0601_garage.py” (no quotation marks).
"""Tuya based cover and blinds."""
from typing import Dict

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

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

from zhaquirks.tuya.ts0601_dimmer import TuyaOnOffNM


ZONE_TYPE = 0x0001


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

    _CONSTANT_ATTRIBUTES = {ZONE_TYPE: IasZone.ZoneType.Contact_Switch}

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


class TuyaGarageManufCluster(TuyaMCUCluster):
    """Tuya garage door opener."""

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

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

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


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

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

    replacement = {
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaGarageManufCluster,
                    TuyaOnOffNM,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.IAS_ZONE,
                INPUT_CLUSTERS: [
                    ContactSwitchCluster
                ],
                OUTPUT_CLUSTERS: [],
            },
            242: {
                PROFILE_ID: 0xA1E0,
                DEVICE_TYPE: 0x0061,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [0x0021],
            },
        },
    }
  • Save the .py file into the /config/zhaquirks folder you created in the earlier step.
  • If you haven’t already, delete the garage door opener device from Home Assistant.
  • Restart Home Assistant.
  • Re-discover the garage door opener.
  • If you did it all perfectly, you can go into the device and see that it has a control and a sensor (they’re not named “switch” and “sensor”… I did that, and cannot recall what they were named at first. I also chose new icons for them.

You can also expand the Zigbee properties with the down arrow and you should see that it used the newly created quirk (.py file) to define the device (bottom line)

So… you have a switch, which is really just supposed to act like a button. You press it, and the garage door opens. You press it again, and it closes. You have a sensor that tells you if the door is opened or closed, but it’s NOT like the normal sensors for doors… just need to make that clear… a door sensor is almost immediate, but you can press the switch control for this, and because garage doors close slowly, the sensor might not say closed for ten seconds or so. It just takes some getting used to is all.

Now the only other thing to know is that the quirk defines it as a switch because I think it has to. But I told you that it really is supposed to act like a button. The only shortcoming of the quirk is that when you activate the switch, it stays on… if you were to go back and turn it off a half-hour later, it doesn’t close the door. It just turns the switch off. So… the unglamorous solution to this is to create an automation to make it act more like a button… I don’t need to post the yaml… here’s the gist:

Hope that all makes sense. In the end, I put it in the dashboard like this, using an Entities card:

When you click click the switch on the card, the automation immediately sees that the switch has been hit, and immediately turns it off, so it only ever “blips” when you tap it. But the sensor shows me current state.

From there, I created three automations (you do you, of course):

  • If garage door was open at time of sunset, wait ten minutes and close it, if not closed already.
  • If garage door was opened while sun is under horizon (dark hours), wait ten minutes and close it, if not closed already.
  • If garage door is opened during daylight hours, and stays open for more than an hour, send a notification asking if I want to close it.

I think there’s probably a way to combine if/else stuff for the first two, but I couldn’t get it and decided to just split them.

I hope this helps! Ask other questions if needed!

-C

3 Likes

Thanks I’ll take a look at it when I find the time.
I’m having this version:
TS0601

door _TZE200_wfxuhoea

Let’s hope it’ll work as well…

@Illinoid Sadly it didn’t work out for me.
Probably because the signature doesn’t match. Do you have any idea on how to tweak this?
Maybe important: after pairing it doesn’t show that it uses the quirk. Maybe something is wrong there as well. Any help would be more than welcome!

EDIT: Got it working by changing the signature in the code.
Thanks for helping me out!

1 Like

So… I would begin by visting the GitHub link that @jerrm provided above. (Issues · zigpy/zha-device-handlers · GitHub). Search for your exact device information in those development requests, and if you don’t see one, fill out a development request for your device.

I filled out a development request, and was informed pretty quickly that it looked like the issue was already resolved, and was given a link to the GitHub request/discussion where I got all the information I needed to resolve.

I would imagine your experience will be the same… it’s a bit to fill out the request, but it’s not impossible or overly difficult.

You are correct by the way… it didn’t work because the signatures don’t match… and that’s exactly why it doesn’t list as having the quirk applied to the device… the quirk code very literally contains the signature.

JUST SAW YOUR EDIT as I typed this… perfect!!!

@Illinoid yeah, pretty lucky that all the rest works exactly the same!
I’m only a bit stuck on the fact that HA treats it as a light switch. It’s no problem when I’m using it with a button but I’m trying to make this work for when we want to open the garage from the car via CarPlay or bike via Siri on our Apple Watch. At this point we’ll have to say “turn on the garagedoor”, instead of “Open the garagedoor”. I guess it’ll be very simple to fix, but it’s late and I guess I’ll have to come back to it tomorrow when I’ve had some sleep…

The most important work is done now so thanks again!

@Illinoid I had a strange issue overnight.
Every hour HA triggers the garage to open without any automations active that would cause this.
Did you run into the same issues?

Schermafbeelding 2022-10-14 om 11.19.44

I was lucky that I was still somehow awake when it happened the first time so I could disconnect it from mains power, however after that it kept on trying for as long as HA didn’t notice the device was unavailable.

Little contribution from my part:

As for opening and closing, viewing the status and make it show up in homekit as a garage door you can make the following template:

#Light as Cover voor Garagepoort
cover:
  - platform: template
    covers:
      garage_door:
        device_class: garage
        friendly_name: "Garagepoort"
        value_template: >-
          {% if is_state('binary_sensor.garagepoort','off') %}closed
          {% else %}open
          {% endif %}
        open_cover:
          - condition: state
            entity_id: binary_sensor.garagepoort
            state: "off"
          - service: light.turn_on
            target:
              entity_id: light.garagepoort
        close_cover:
          - condition: state
            entity_id: binary_sensor.garagepoort
            state: "on"
          - service: light.turn_on
            target:
              entity_id: light.garagepoort
        stop_cover:
          service: light.turn_on
          target:
            entity_id: light.garagepoort
        icon_template: >-
          {% if states('binary_sensor.garagepoort') == "on" %}
            mdi:garage-open-variant
          {% else %}
            mdi:garage-variant
          {% endif %}

Now let’s hope the garage door won’t suddenly open anymore as it did last night. Also, when I plugged it back in today, the garage door opened. I hope that won’t happen when it reboots after a power outage.

EDIT: Sadly it still opens every hour… There’s no automation that causes it so I think it’s the garage door opener itself that closes the relay every hour. It’s so extremely annoying that this happens! It makes it totally unusable… @Illinoid Do you have that issue as well?

EDIT2: it seems to be HA after all as it triggers the relay even when it’s disconnected from the power source… very weird… can’t see how or why it gets triggered. Maybe something in the quirk?

Im almost sorry to tell you that I don’t have this problem at all. The only thing I can think of is that the quirk really wasn’t written for your exact version of the device. If you look back in the posts to the reference to go to The HA development forums GitHub, it’s actually not hard to 1) search to see if anyone has already written a quirk for your exact model and/or 2) turn in a quirk development request as I did at first.

Sorry there’s not a better answer on my side!

Oops, didn’t receive a notification on your reply so sorry for my late reaction.
I’ll check on github for a solution as you’ve suggested. Thanks for the assistance!

Did you find a solution to this @kimme1024? I have the exact same device.

Will try the quirk anyway and let you know if I have the “open every hour” bug.

Sadly at this point there’s not yet a solution.
Weirdly since testing it again, the hourly openings haven’t occured anymore. However I still don’t trust the system to leave it active at night. As I’ve been very busy last week I didn’t have time to test it a lot. I hope to do a 24h test next week.
Feel free to share your findings and to comment on the following issues. I guess the more people that ask for it, the more likely they will try to find a stable solution.

I installed the quirk yesterday, no problems so far. Only changed the device identifier, like @kimme1024 .

Only thing I don’t like is the automation to make the switch act like a button, but I was unable to find any documentation on the zha.DeviceType enum to try and modify the quirk. I’ll probably try and look into it if nobody on Github does (who knows when).

I’ve been having the same issues. I bought it thinking it would work out of the box but alas I was wrong. I have tried many different things from this thread and others and I can’t seem to get it to work.

I tried installing the quirk but it won’t pick it up even though everything should be fine. I was wondering if anyone would be able to give me a hand?

I don’t know if I was just one of the lucky ones… but it seem to me that the quirk code was written for a very specific version of the hardware. I’ve seen/heard of 1-2 people with exact same as I have working well after doing the quirk thing, but others that can’t get it working. It seems like it SHOULD work, but doesn’t… but the only thing I can tell is that the “by_xxxxxx-xxxxxx” line in your device info is not the same as mine…

image

I’m soooooo not an expert, but assuming you followed the steps I posted that gave me success, I don’t know what else it would be. Sorry I can’t be of more help.

I got this working with the quirk and templated cover entity. One other thing I needed to do is create a short automation to turn the “light” back off after 500ms delay to emulate the button press.

alias: fix - garage door switch toggle
description: ""
trigger:
  - platform: state
    entity_id:
      - light.garage_door_toggle
    from: "off"
    to: "on"
condition: []
action:
  - wait_for_trigger: []
    timeout:
      hours: 0
      minutes: 0
      seconds: 0
      milliseconds: 500
  - service: light.turn_off
    data: {}
    target:
      entity_id: light.garage_door_toggle
mode: single

I did that as well, however my issue is that the garage door opens by itself sporadically and also when it receives power after an outage.