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
696 stars 641 forks source link

[Device Support Request] TS130F ZemiSmart no applying quirk #2490

Closed jfisbein closed 4 months ago

jfisbein commented 1 year ago

Problem description

I have a TS130F from ZemiSmart not covered by the existing TS130F quirk, so it's detected by HA but I cannot calibrate it, making it unuseful.

Here is the zigbee info from HA

Solution description

Add support for this model/manufacturer in the quirk

Screenshots/Video

Screenshots/Video ![image](https://github.com/zigpy/zha-device-handlers/assets/272565/7da57298-b2cb-49af-8511-62c7d3a971ee)

Device signature

Device signature ```json { "home_assistant": { "installation_type": "Home Assistant OS", "version": "2023.7.3", "dev": false, "hassio": true, "virtualenv": false, "python_version": "3.11.4", "docker": true, "arch": "aarch64", "timezone": "Europe/Madrid", "os_name": "Linux", "os_version": "6.1.21-v8", "supervisor": "2023.07.1", "host_os": "Home Assistant OS 10.3", "docker_version": "23.0.6", "chassis": "embedded", "run_as_root": true }, "custom_components": { "sonoff": { "version": "3.5.1", "requirements": [ "pycryptodome>=3.6.6" ] }, "spotcast": { "version": "v3.6.30", "requirements": [] }, "plant": { "version": "2.1.1", "requirements": [] }, "hacs": { "version": "1.32.1", "requirements": [ "aiogithubapi>=22.10.1" ] }, "fglair_heatpump_controller": { "version": "0.2.7", "requirements": [ "pyfujitsugeneral==1.0.1" ] }, "nodered": { "version": "2.1.0", "requirements": [] }, "xiaomi_cloud_map_extractor": { "version": "v2.2.0", "requirements": [ "pillow", "pybase64", "python-miio", "requests", "pycryptodome" ] }, "localtuya": { "version": "5.2.1", "requirements": [] }, "meross_lan": { "version": "4.2.0", "requirements": [] }, "ble_monitor": { "version": "12.3.2", "requirements": [ "pycryptodomex>=3.14.1", "janus>=1.0.0", "aioblescan>=0.2.14", "btsocket>=0.2.0", "pyric>=0.1.6.3" ] }, "edata": { "version": "2023.06.3", "requirements": [ "e-data==1.1.5", "python-dateutil>=2.8.2" ] }, "ideenergy": { "version": "2.0.2", "requirements": [ "ideenergy==1.0.0", "homeassistant-historical-sensor==2.0.0rc1" ] }, "tapo_control": { "version": "5.1.0", "requirements": [ "pytapo==3.1.18" ] }, "kia_uvo": { "version": "2.10.6", "requirements": [ "hyundai_kia_connect_api==3.3.13" ] }, "scheduler": { "version": "v0.0.0", "requirements": [] } }, "integration_manifest": { "domain": "zha", "name": "Zigbee Home Automation", "after_dependencies": [ "onboarding", "usb" ], "codeowners": [ "@dmulcahey", "@adminiuga", "@puddly" ], "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" ], "requirements": [ "bellows==0.35.8", "pyserial==3.5", "pyserial-asyncio==0.6", "zha-quirks==0.0.101", "zigpy-deconz==0.21.0", "zigpy==0.56.2", "zigpy-xbee==0.18.1", "zigpy-zigate==0.11.0", "zigpy-znp==0.11.3" ], "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" ] } ], "zeroconf": [ { "type": "_esphomelib._tcp.local.", "name": "tube*" }, { "type": "_zigate-zigbee-gateway._tcp.local.", "name": "*zigate*" }, { "type": "_zigstar_gw._tcp.local.", "name": "*zigstar*" }, { "type": "_slzb-06._tcp.local.", "name": "slzb-06*" } ], "is_built_in": true }, "data": { "ieee": "**REDACTED**", "nwk": 366, "manufacturer": "_TZ3000_qqdbccb3", "model": "TS130F", "name": "_TZ3000_qqdbccb3 TS130F", "quirk_applied": false, "quirk_class": "zigpy.device.Device", "manufacturer_code": 4107, "power_source": "Mains", "lqi": 72, "rssi": null, "last_seen": "2023-07-26T18:48:07", "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=4107, 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": "0x0104", "device_type": "0x0202", "input_clusters": [ "0x0000", "0x0003", "0x0004", "0x0005", "0x0102" ], "output_clusters": [ "0x0019" ] } }, "manufacturer": "_TZ3000_qqdbccb3", "model": "TS130F" }, "active_coordinator": false, "entities": [ { "entity_id": "cover.toldo_cocina_cover", "name": "_TZ3000_qqdbccb3 TS130F" }, { "entity_id": "button.toldo_cocina_identify", "name": "_TZ3000_qqdbccb3 TS130F" } ], "neighbors": [ { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Parent", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0xAE19", "permit_joining": "Unknown", "depth": "1", "lqi": "179" }, { "device_type": "Coordinator", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x0000", "permit_joining": "Unknown", "depth": "0", "lqi": "149" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x96E3", "permit_joining": "Unknown", "depth": "0", "lqi": "136" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x074E", "permit_joining": "Unknown", "depth": "0", "lqi": "106" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x23CE", "permit_joining": "Unknown", "depth": "0", "lqi": "144" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0xE9E1", "permit_joining": "Unknown", "depth": "0", "lqi": "141" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x4866", "permit_joining": "Unknown", "depth": "0", "lqi": "94" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0xE57D", "permit_joining": "Unknown", "depth": "0", "lqi": "99" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x795E", "permit_joining": "Unknown", "depth": "0", "lqi": "90" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x2F61", "permit_joining": "Unknown", "depth": "0", "lqi": "127" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x4F92", "permit_joining": "Unknown", "depth": "0", "lqi": "135" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0xB39B", "permit_joining": "Unknown", "depth": "0", "lqi": "148" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x67D5", "permit_joining": "Unknown", "depth": "0", "lqi": "108" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0xF2D3", "permit_joining": "Unknown", "depth": "0", "lqi": "154" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x884E", "permit_joining": "Unknown", "depth": "0", "lqi": "123" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x4AC2", "permit_joining": "Unknown", "depth": "0", "lqi": "106" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x7E8A", "permit_joining": "Unknown", "depth": "0", "lqi": "100" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0xCCBF", "permit_joining": "Unknown", "depth": "0", "lqi": "101" } ], "routes": [], "endpoint_names": [ { "name": "WINDOW_COVERING_DEVICE" } ], "user_given_name": "Toldo Cocina", "device_reg_id": "b20ba919dc6ae3f0281bdb732a75ad03", "area_id": "cocina", "cluster_details": { "1": { "device_type": { "name": "WINDOW_COVERING_DEVICE", "id": 514 }, "profile_id": 260, "in_clusters": { "0x0000": { "endpoint_attribute": "basic", "attributes": { "0x0004": { "attribute_name": "manufacturer", "value": "_TZ3000_qqdbccb3" }, "0x0005": { "attribute_name": "model", "value": "TS130F" } }, "unsupported_attributes": {} }, "0x0003": { "endpoint_attribute": "identify", "attributes": {}, "unsupported_attributes": {} }, "0x0004": { "endpoint_attribute": "groups", "attributes": {}, "unsupported_attributes": {} }, "0x0005": { "endpoint_attribute": "scenes", "attributes": {}, "unsupported_attributes": {} }, "0x0102": { "endpoint_attribute": "window_covering", "attributes": { "0x0007": { "attribute_name": "config_status", "value": 3 }, "0x0008": { "attribute_name": "current_position_lift_percentage", "value": 0 }, "0x0017": { "attribute_name": "window_covering_mode", "value": 4 }, "0x0000": { "attribute_name": "window_covering_type", "value": 4 } }, "unsupported_attributes": { "0x0001": { "attribute_name": "physical_closed_limit_lift" }, "0x0003": { "attribute_name": "current_position_lift" }, "0x0004": { "attribute_name": "current_position_tilt" }, "0x0005": { "attribute_name": "number_of_actuations_lift" }, "0x0014": { "attribute_name": "velocity_lift" }, "0x0012": { "attribute_name": "installed_open_limit_tilt" }, "0x0010": { "attribute_name": "installed_open_limit_lift" }, "0x0011": { "attribute_name": "installed_closed_limit_lift" }, "0x0013": { "attribute_name": "installed_closed_limit_tilt" }, "0x0015": { "attribute_name": "acceleration_time_lift" }, "0x0018": { "attribute_name": "intermediate_setpoints_lift" } } } }, "out_clusters": { "0x0019": { "endpoint_attribute": "ota", "attributes": {}, "unsupported_attributes": {} } } } } } } ```

Diagnostic information

Diagnostic information ```json ```

Logs

No response

Custom quirk

No response

Additional information

No response

javicalle commented 1 year ago

A new TS130F signature. Maybe this quirk can do the job

TuyaTS130F_var08 ```python class TuyaTS130F_var08(CustomDevice): """Tuya smart curtain TS130F (variation 08).""" signature = { # SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=0x0202, device_version=1, input_clusters=[0, 4, 5, 6, 10, 0x0102], output_clusters=[25])) MODEL: "TS130F", ENDPOINTS: { 1: { # "profile_id": "0x0104", # "device_type": "0x0202", # "input_clusters": ["0x0000","0x0003","0x0004","0x0005","0x0102"], # "output_clusters": ["0x0019"] PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE, INPUT_CLUSTERS: [ Basic.cluster_id, Identify.cluster_id, Groups.cluster_id, Scenes.cluster_id, WindowCovering.cluster_id, ], OUTPUT_CLUSTERS: [Ota.cluster_id], }, }, } replacement = { ENDPOINTS: { 1: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE, INPUT_CLUSTERS: [ Basic.cluster_id, Identify.cluster_id, Groups.cluster_id, Scenes.cluster_id, TuyaCoveringCluster, ], OUTPUT_CLUSTERS: [Ota.cluster_id], }, }, } ```

You would need to add the new Identify import to the current ts130f.py quirk:

from zigpy.zcl.clusters.general import (
    Basic,
    GreenPowerProxy,
    Groups,
    Identify,
    OnOff,
    Ota,
    Scenes,
    Time,
)
gilbertorconde commented 11 months ago

I have a TS130F ZemiSmart module (ZN-LC1E) but for the quirk to work had to be like this:

class ZemismartTS130F(CustomDevice):
    """ZemiSmart smart curtain roller shutter."""

    signature = {
        # SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=0x0202, device_version=1, input_clusters=[0x0000, 0x0004, 0x00>
        MODEL: "TS130F",
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Identify.cluster_id,
                    Scenes.cluster_id,
                    WindowCovering.cluster_id,
                ],
                OUTPUT_CLUSTERS: [
                    Ota.cluster_id,
                ],
            },
        },
    }
    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Identify.cluster_id,
                    Scenes.cluster_id,
                    TuyaCoveringCluster,
                ],
                OUTPUT_CLUSTERS: [
                    Ota.cluster_id,
                ],
            },
        },
    }

Tip: The order of the clusters is different

github-actions[bot] commented 5 months ago

There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates. Please make sure to update to the latest version and check if that solves the issue. Let us know if that works for you by adding a comment 👍 This issue has now been marked as stale and will be closed if no further activity occurs. Thank you for your contributions.