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
719 stars 664 forks source link

[Device Support Request] Tuya NEO siren #2035

Closed NdK73 closed 1 year ago

NdK73 commented 1 year ago

Is your feature request related to a problem? Please describe. Adding the Tuya siren I just bought to HA via ZHA did not expose any entity

Describe the solution you'd like I'd like to see it fully supported, with on/off switch (see following patch) and other entities to set melody/volume/duration.

Device signature ```yaml { "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=4417, 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": 260, "device_type": "0x0403", "in_clusters": [ "0x0000", "0x0004", "0x0005", "0x0006", "0xef00" ], "out_clusters": [ "0x000a", "0x0019" ] }, "242": { "profile_id": 41440, "device_type": "0x0061", "in_clusters": [], "out_clusters": [ "0x0021" ] } }, "manufacturer": "_TZE204_t1blo2bj", "model": "TS0601", "class": "zhaquirks.tuya.ts0601_siren.TuyaSirenGPP_NoSensors" } ```
Diagnostic information ```yaml { "home_assistant": { "installation_type": "Home Assistant Supervised", "version": "2022.12.8", "dev": false, "hassio": true, "virtualenv": false, "python_version": "3.10.7", "docker": true, "arch": "x86_64", "timezone": "Europe/Rome", "os_name": "Linux", "os_version": "5.10.0-19-amd64", "supervisor": "2022.11.2", "host_os": "Debian GNU/Linux 11 (bullseye)", "docker_version": "20.10.21", "chassis": "vm", "run_as_root": true }, "custom_components": { "tasmota_irhvac": { "version": "2021.12.0", "requirements": [] }, "scheduler": { "version": "v0.0.0", "requirements": [] }, "nodered": { "version": "1.1.2", "requirements": [] }, "remote_homeassistant": { "version": "3.6", "requirements": [] }, "sonoff": { "version": "3.3.1", "requirements": [ "pycryptodome>=3.6.6" ] }, "shelly": { "version": "1.0.2", "requirements": [ "pyShelly==1.0.2", "paho-mqtt==1.6.1", "websocket-client" ] }, "hacs": { "version": "1.29.0", "requirements": [ "aiogithubapi>=22.10.1" ] }, "hisense_tv": { "version": "22.05.09", "requirements": [ "wakeonlan==2.0.1" ] }, "localtuya": { "version": "4.1.1", "requirements": [] }, "dual_smart_thermostat": { "version": "0.5.5", "requirements": [] }, "zha_toolkit": { "version": "v0.8.28", "requirements": [ "packaging>=20.8", "pytz" ] }, "aquaariston": { "version": "1.0.50", "requirements": [] } }, "integration_manifest": { "domain": "zha", "name": "Zigbee Home Automation", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/zha", "requirements": [ "bellows==0.34.5", "pyserial==3.5", "pyserial-asyncio==0.6", "zha-quirks==0.0.89", "zigpy-deconz==0.19.2", "zigpy==0.52.3", "zigpy-xbee==0.16.2", "zigpy-zigate==0.10.3", "zigpy-znp==0.9.2" ], "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" ] } ], "codeowners": [ "@dmulcahey", "@adminiuga", "@puddly" ], "zeroconf": [ { "type": "_esphomelib._tcp.local.", "name": "tube*" }, { "type": "_zigate-zigbee-gateway._tcp.local.", "name": "*zigate*" }, { "type": "_zigstar_gw._tcp.local.", "name": "*zigstar*" } ], "dependencies": [ "file_upload" ], "after_dependencies": [ "onboarding", "usb", "zeroconf" ], "iot_class": "local_polling", "loggers": [ "aiosqlite", "bellows", "crccheck", "pure_pcapy3", "zhaquirks", "zigpy", "zigpy_deconz", "zigpy_xbee", "zigpy_zigate", "zigpy_znp" ], "is_built_in": true }, "data": { "ieee": "**REDACTED**", "nwk": 16470, "manufacturer": "_TZE204_t1blo2bj", "model": "TS0601", "name": "_TZE204_t1blo2bj TS0601", "quirk_applied": false, "quirk_class": "zigpy.device.Device", "manufacturer_code": 4417, "power_source": "Mains", "lqi": null, "rssi": null, "last_seen": "2022-12-25T11:08:06", "available": false, "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=4417, 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": 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" ] } } }, "active_coordinator": false, "entities": [], "neighbors": [ { "device_type": "Coordinator", "rx_on_when_idle": "On", "relationship": "Parent", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x0000", "permit_joining": "Unknown", "depth": "0", "lqi": "100" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x2F71", "permit_joining": "Unknown", "depth": "1", "lqi": "60" } ], "routes": [], "endpoint_names": [ { "name": "SMART_PLUG" }, { "name": "unknown 97 device_type of 0xa1e0 profile id" } ], "user_given_name": "Sirena", "device_reg_id": "b609f30bff4e90691663f771c0f4dc3b", "area_id": null, "cluster_details": { "1": { "device_type": { "name": "SMART_PLUG", "id": 81 }, "profile_id": 260, "in_clusters": { "0x0004": { "endpoint_attribute": "groups", "attributes": {}, "unsupported_attributes": {} }, "0x0005": { "endpoint_attribute": "scenes", "attributes": {}, "unsupported_attributes": {} }, "0xef00": { "endpoint_attribute": null, "attributes": {}, "unsupported_attributes": {} }, "0x0000": { "endpoint_attribute": "basic", "attributes": { "0x0001": { "attribute_name": "app_version", "value": 74 }, "0x0004": { "attribute_name": "manufacturer", "value": "_TZE204_t1blo2bj" }, "0x0005": { "attribute_name": "model", "value": "TS0601" } }, "unsupported_attributes": {} } }, "out_clusters": { "0x0019": { "endpoint_attribute": "ota", "attributes": {}, "unsupported_attributes": {} }, "0x000a": { "endpoint_attribute": "time", "attributes": {}, "unsupported_attributes": {} } } }, "242": { "device_type": { "name": "unknown", "id": 97 }, "profile_id": 41440, "in_clusters": {}, "out_clusters": { "0x0021": { "endpoint_attribute": "green_power", "attributes": {}, "unsupported_attributes": {} } } } } } } ```
Additional logs ``` Paste any additional debug logs here. Don't remove the extra line breaks outside the ``` marks. ```

Additional context I just added its ID to ts0601_siren.py :

--- ts0601_siren.py.dist        2022-12-21 16:52:19.000000000 +0100
+++ ts0601_siren.py     2022-12-26 19:27:05.317144827 +0100
@@ -359,7 +359,7 @@
     signature = {
         #  endpoint=1 profile=260 device_type=81 device_version=1 input_clusters=[0, 4, 5, 61184]
         #  output_clusters=[25, 10]>
-        MODELS_INFO: [("_TZE200_t1blo2bj", "TS0601")],
+        MODELS_INFO: [("_TZE200_t1blo2bj", "TS0601"), ("_TZE204_t1blo2bj", "TS0601")],
         ENDPOINTS: {
             1: {
                 PROFILE_ID: zha.PROFILE_ID,

That gave me "basic" functionality (the on/off switch) but it could be useful to have other entities for selecting melody, volume and duration w/o having to resort to scripts.

johannquerne commented 1 year ago

Does the on/off functionality work for you? I'm getting an error message when I try to switch it on or off from the HA UI. I created a custom quirk and added the model as you suggested.

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 1745, in async_call
    task.result()
  File "/usr/src/homeassistant/homeassistant/core.py", line 1782, 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 678, in entity_service_call
    future.result()  # pop exception if have
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 943, in async_request_call
    await coro
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 715, in _handle_entity_call
    await result
  File "/usr/src/homeassistant/homeassistant/components/zha/switch.py", line 91, in async_turn_on
    result = await self._on_off_channel.turn_on()
  File "/usr/src/homeassistant/homeassistant/components/zha/core/channels/general.py", line 373, in turn_on
    result = await self.on()
  File "/usr/src/homeassistant/homeassistant/components/zha/core/channels/base.py", line 78, in wrapper
    result = await command(*args, **kwds)
  File "/config/zha_quirks/TZE204_t1blo2bj.py", line 293, in command
    cluster_data = TuyaClusterData(
  File "/usr/local/lib/python3.10/site-packages/zigpy/types/struct.py", line 107, in __new__
    bound = signature.bind(*args, **kwargs)
  File "/usr/local/lib/python3.10/inspect.py", line 3179, in bind
    return self._bind(args, kwargs)
  File "/usr/local/lib/python3.10/inspect.py", line 3168, in _bind
    raise TypeError(
TypeError: got an unexpected keyword argument 'cluster_name'
johannquerne commented 1 year ago
Screenshot 2022-12-31 at 10 39 35
NdK73 commented 1 year ago

IIUC you added a different file, while I just edited the one from ZHA. In my case it works w/o errors. I usually call it via a script that changes some other parameters (melody, duration and volume) but even just switching it on makes it play using the last settings. After the given duration, switch returns automatically to off.

johannquerne commented 1 year ago

Thank you! I've just updated my custom quirk with the previous version of ts0601_siren.py and it now works.

Would you mind sharing your script that controls other parameters?

NdK73 commented 1 year ago

Sure, I just copied it from some other ticket, but don't remember which. Here it is.

alias: Set ZB siren
sequence:
  - service: zha.set_zigbee_cluster_attribute
    data:
      ieee: "{{ ieee_id }}"
      endpoint_id: 1
      cluster_id: 6
      cluster_type: in
      attribute: 1126
      value: "{{ melody | default(default_melody) }}"
  - delay:
      hours: 0
      minutes: 0
      seconds: 0
      milliseconds: 50
  - service: zha.set_zigbee_cluster_attribute
    data:
      ieee: "{{ ieee_id }}"
      endpoint_id: 1
      cluster_id: 6
      cluster_type: in
      attribute: 615
      value: "{{ duration | default(default_duration) }}"
  - delay:
      hours: 0
      minutes: 0
      seconds: 0
      milliseconds: 50
  - service: zha.set_zigbee_cluster_attribute
    data:
      ieee: "{{ ieee_id }}"
      endpoint_id: 1
      cluster_id: 6
      cluster_type: in
      attribute: 1140
      value: "{{ volume | default(default_volume) }}"
  - delay:
      hours: 0
      minutes: 0
      seconds: 0
      milliseconds: 50
  - service: zha.set_zigbee_cluster_attribute
    data:
      ieee: "{{ ieee_id }}"
      endpoint_id: 1
      cluster_id: 6
      cluster_type: in
      attribute: 0
      value: "{{ alarm | default(1) }}"
description: Tuya Siren ZHA
fields:
  ieee_id:
    description: zigbee ieee id
    example: a4:c1:38:00:12:34:56:78
  melody:
    description: melody
    example: 1-18
  duration:
    description: duration in seconds
    example: 4
  volume:
    description: volume
    example: 0, 1, 2
  alarm:
    description: alarm
    example: on or off
variables:
  default_melody: 18
  default_duration: 4
  default_volume: 1
mode: parallel
max: 10
johannquerne commented 1 year ago

Thank you very Much @NdK73

NdK73 commented 1 year ago

After last HA update (on jan, 3rd) it stopped working. Surely I'm doing something wrong, but it seems the file in /config/zha_custom_quirks/ gets ignored even if configuration.yaml contains:

zha:
  zigpy_config:
    ota:
      ikea_provider: true                        # Auto update Trådfri devices
      ledvance_provider: true                    # Auto update LEDVANCE/OSRAM devices
      salus_provider: true                       # Auto update SALUS/Computime devices
      inovelli_provider: true                    # Auto update INOVELLI devices
    custom_quirks_path: /config/zha_custom_quirks/
TheJulianJES commented 1 year ago

Should be fixed by https://github.com/zigpy/zha-device-handlers/pull/2185

donaldwpage commented 1 year ago

I also have _TZE204_t1blo2bj and from reading the code, I believe it has been assigned to the wrong entry. It should be assigned to class TuyaSiren2 as it has a profile that matches _TZE200_d0yu2xgi and not class TuyaSirenGPP_NoSensors

I tried testing this by creating a custom quirk, deleting NoSensors and adding it to TuyaSiren2 but it appears that the quirk included in the main build takes precedence and I don't know how to override it. Can someone advise how I can test it please?

TheJulianJES commented 1 year ago

Custom quirks will override the original quirks. Maybe your signature doesn't match? I'd recommend opening a new issue and filling out the issue template (provide device signature/diagnostic info).

donaldwpage commented 1 year ago

ok thanks

mupfpilou commented 7 months ago

Hello I also have a _TZE204_t1blo2bj that i integrated today It is detected as nosensors

{ "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.FullFunctionDevice|MainsPowered|RxOnWhenIdle|AllocateAddress: 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": "0x0104", "device_type": "0x0403", "input_clusters": [ "0x0000", "0x0004", "0x0005", "0x0006", "0xef00" ], "output_clusters": [ "0x000a", "0x0019" ] }, "242": { "profile_id": "0xa1e0", "device_type": "0x0061", "input_clusters": [], "output_clusters": [ "0x0021" ] } }, "manufacturer": "_TZE204_t1blo2bj", "model": "TS0601", "class": "zhaquirks.tuya.ts0601_siren.TuyaSirenGPP_NoSensors" }

Any help ?

mupfpilou commented 6 months ago

@TheJulianJES @NdK73 I am not sure to fully understand the status here My siren is available with zha with on/off support only Is there something I can help to get entities/selector for melody/volume/... Script is working but i would prefer zha integration !

NdK73 commented 6 months ago

It seems that for now there's no interest in adding entities since there's a script available :(

alex0124000 commented 5 months ago

The script (from @NdK73) works for me for a "MOES Siren Alarm" https://www.amazon.de/dp/B0B3F82M8K I also found a description of the available tunes (0-18) here: https://zigbee.blakadder.com/Neo_NAS-AB02B2.html