Open G4LLY opened 1 month ago
Was able to make it work by adapting an existing quirks fro T601: Probably not the most optimal code as this is a first for me, but it work ^^
Don't hesitate to correct / advice !
"""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, Identify, 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,
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",
),
2: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"dp_2",
),
3: DPToAttributeMapping(
ContactSwitchCluster.ep_attribute,
"zone_status",
converter=lambda x: IasZone.ZoneStatus.Alarm_1 if x else 0,
endpoint_id=2,
),
4: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"dp_4",
),
5: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"dp_5",
),
11: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"dp_11",
),
# garage door status (open, closed, ...)
12: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"dp_12",
),
}
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: [
("_TZE608_c75zqghm", "TS0603"),
],
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,
Identify.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.SMART_PLUG,
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],
},
},
}
I used your quirk for HA ZHA, and it worked nicely, but only for the switch to short the garage engine to send an open/stop/close signal. Unfortunately, it didn't work for the sensor. I'm not sure if I have a broken device or need additional adaptation. My devices is similar, but somehow a little bit different. Different Manufacturer, for sure. Device: TS0603 Man: _TZE608_fmemczv1
Hi,
for me it appear with 2 entities for the devices, The fact it is presented as a "smart plug" andnot a door opener, the smart plug status is not linked to the sensor status, to work around this I have set 2 cards in the frontend and hide the smart plug status:
Lovelace cards:
ZHA device
I see two entities, but the state doesn't change whether I close the sensor. That's why I wonder whether I have a broken device or installed it the wrong way.
Works for me, the door sensor is properly plug on the S1 and S2 plugs ?
Yep. When I put the magnetic sensor parts together, nothing happens. I have other similar sensors, and they work very snappy, like in an instant.
seems to be S3 and S4 at your side.
I remember I had to restart HA couple of time to make it work.
You wouldn't believe how many restarts I'm after. I wonder if this is a matter of broken sensor/device or just the converter/quirk matter in ZHA. I'll try to short the sensor entry (by a simple wire) and see if the state changes.
EDIT: Okay, I confirm that my sensor is busted. I shorted the S3 and S4, which popped up properly in the HA entity view. It could just come broken already. 💩 happens 😂
Sorry for bothering you. Good job with the quirk! It is sufficient for all the automations I wanted with the garage gate.
Happy you figured it out !
Cheers
Hi all. I've just added your quirk and working (only changing signature).
The problem is the presentation of the icon... it apears as a on/off icon and I'd love have it as my other garage door opener (wifi) that has an arrow to open or close (see pics)
ZB TS0603 with G4LLY quirk
Loratap Tuya wifi connected garage opener:
Any clues of how to represent this as the second one?
Problem description
Hello, I get this garage door opener from Aliexpress and once connected to ZHA, is does not show the proper command / informations.
Solution description
As a door opener it should have an open-close command and a sensor to show the door state (open / close)
Screenshots/Video
Screenshots/Video
![image](https://github.com/user-attachments/assets/51b5a8d0-2a9a-4fac-94ae-0ce4dbab62c6)Device signature
Device signature
```json { "node_descriptor": "NodeDescriptor(logical_type=Diagnostic information
Diagnostic information
```json { "home_assistant": { "installation_type": "Home Assistant OS", "version": "2024.7.2", "dev": false, "hassio": true, "virtualenv": false, "python_version": "3.12.4", "docker": true, "arch": "x86_64", "timezone": "Europe/Brussels", "os_name": "Linux", "os_version": "6.6.33-haos", "supervisor": "2024.06.2", "host_os": "Home Assistant OS 12.4", "docker_version": "26.1.4", "chassis": "vm", "run_as_root": true }, "custom_components": { "hacs": { "documentation": "https://hacs.xyz/docs/configuration/start", "version": "1.34.0", "requirements": [ "aiogithubapi>=22.10.1" ] }, "tapo": { "documentation": "https://github.com/petretiandrea/home-assistant-tapo-p100", "version": "3.1.2", "requirements": [ "plugp100==5.1.3" ] }, "easee": { "documentation": "https://github.com/nordicopen/easee_hass", "version": "0.9.59", "requirements": [ "pyeasee==0.8.1" ] }, "tapo_control": { "documentation": "https://github.com/JurajNyiri/HomeAssistant-Tapo-Control", "version": "5.4.26", "requirements": [ "pytapo==3.3.23" ] }, "aarlo": { "documentation": "https://github.com/twrecked/hass-aarlo/blob/master/README.md", "version": "0.8.1.4", "requirements": [ "unidecode", "pyaarlo>=0.8.0.7" ] } }, "integration_manifest": { "domain": "zha", "name": "Zigbee Home Automation", "after_dependencies": [ "onboarding", "usb" ], "codeowners": [ "dmulcahey", "adminiuga", "puddly", "TheJulianJES" ], "config_flow": true, "dependencies": [ "file_upload" ], "documentation": "https://www.home-assistant.io/integrations/zha", "iot_class": "local_polling", "loggers": [ "aiosqlite", "bellows", "crccheck", "pure_pcapy3", "zhaquirks", "zigpy", "zigpy_deconz", "zigpy_xbee", "zigpy_zigate", "zigpy_znp", "universal_silabs_flasher" ], "requirements": [ "bellows==0.39.1", "pyserial==3.5", "zha-quirks==0.0.117", "zigpy-deconz==0.23.2", "zigpy==0.64.1", "zigpy-xbee==0.20.1", "zigpy-zigate==0.12.1", "zigpy-znp==0.12.2", "universal-silabs-flasher==0.0.20", "pyserial-asyncio-fast==0.11" ], "usb": [ { "vid": "10C4", "pid": "EA60", "description": "*2652*", "known_devices": [ "slae.sh cc2652rb stick" ] }, { "vid": "10C4", "pid": "EA60", "description": "*slzb-07*", "known_devices": [ "smlight slzb-07" ] }, { "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": "0403", "pid": "6015", "description": "*conbee*", "known_devices": [ "Conbee III" ] }, { "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" ] } ], "zeroconf": [ { "type": "_esphomelib._tcp.local.", "name": "tube*" }, { "type": "_zigate-zigbee-gateway._tcp.local.", "name": "*zigate*" }, { "type": "_zigstar_gw._tcp.local.", "name": "*zigstar*" }, { "type": "_uzg-01._tcp.local.", "name": "uzg-01*" }, { "type": "_slzb-06._tcp.local.", "name": "slzb-06*" }, { "type": "_xzg._tcp.local.", "name": "xzg*" }, { "type": "_czc._tcp.local.", "name": "czc*" } ], "is_built_in": true }, "setup_times": { "null": { "setup": 0.00010956400001305155 }, "01J2VYW0Q4CK22WV107ZBJ5FJZ": { "wait_import_platforms": -0.0002739289993769489, "config_entry_setup": 15.528421514998627 } }, "data": { "ieee": "**REDACTED**", "nwk": 10239, "manufacturer": "_TZE608_c75zqghm", "model": "TS0603", "name": "_TZE608_c75zqghm TS0603", "quirk_applied": false, "quirk_class": "zigpy.device.Device", "quirk_id": null, "manufacturer_code": 4417, "power_source": "Mains", "lqi": 255, "rssi": -36, "last_seen": "2024-07-18T14:08:40", "available": true, "device_type": "Router", "signature": { "node_descriptor": "NodeDescriptor(logical_type=Logs
Logs
```python [Paste the logs here] ```Custom quirk
Custom quirk
```python """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, Identify, 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, 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", ), 2: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "dp_2", ), 3: DPToAttributeMapping( ContactSwitchCluster.ep_attribute, "zone_status", converter=lambda x: IasZone.ZoneStatus.Alarm_1 if x else 0, endpoint_id=2, ), 4: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "dp_4", ), 5: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "dp_5", ), 11: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "dp_11", ), # garage door status (open, closed, ...) 12: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "dp_12", ), } 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: [ ("_TZE608_c75zqghm", "TS0603"), ], ENDPOINTS: { #Additional information
I'm new to HA and Zigbee, still on the learning path, any help is welcom :)
link to the device: https://fr.aliexpress.com/item/1005007082676496.html?spm=a2g0o.order_list.order_list_main.17.2a035e5bCYzg5r&gatewayAdapt=glo2fra