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
772 stars 702 forks source link

[Device Support Request] _TZE204_dtzziy1e TS0601 24GHz Millimeter Wave Tuya Zigbee Human Presence Sensor with switch (relay) #2457

Open Nelevit opened 1 year ago

Nelevit commented 1 year ago

Problem description

When adding to ZHA only device exists, no entities.

Solution description

Device is added with all related entities (sensor, switch). If possible add sensitivity controls.

Screenshots/Video

Screenshots/Video ![image](https://github.com/zigpy/zha-device-handlers/assets/52739692/1d5d8980-36d6-4a1b-8e0c-26707c44a7d3) ![PXL_20230704_132845009 – копія](https://github.com/zigpy/zha-device-handlers/assets/52739692/c90b5162-4668-442f-86d2-8979c6950455) ![PXL_20230704_132751715 – копія](https://github.com/zigpy/zha-device-handlers/assets/52739692/4a89b312-eaf7-4451-915a-437f1db39590) ![PXL_20230704_132816177 – копія](https://github.com/zigpy/zha-device-handlers/assets/52739692/8c63919d-8ea9-4562-9e66-a5fa712aab20) ![PXL_20230704_132827544 – копія](https://github.com/zigpy/zha-device-handlers/assets/52739692/6c36e044-db57-4401-b296-eb1c5a3badf6) ![PXL_20230704_132838648 – копія](https://github.com/zigpy/zha-device-handlers/assets/52739692/1d39b2b1-4a29-4b56-b648-2987297b833d)

Device signature

Device signature ```json { "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=4098, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, 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": "0x0051", "input_clusters": [ "0x0000", "0x0004", "0x0005", "0xef00" ], "output_clusters": [ "0x000a", "0x0019" ] } }, "manufacturer": "_TZE204_dtzziy1e", "model": "TS0601", "class": "zigpy.device.Device" } ```

Diagnostic information

Diagnostic information ```json { "home_assistant": { "installation_type": "Home Assistant OS", "version": "2023.6.3", "dev": false, "hassio": true, "virtualenv": false, "python_version": "3.11.4", "docker": true, "arch": "x86_64", "timezone": "Europe/Kiev", "os_name": "Linux", "os_version": "6.1.34", "supervisor": "2023.06.4", "host_os": "Home Assistant OS 10.3", "docker_version": "23.0.6", "chassis": "vm", "run_as_root": true }, "custom_components": { "scheduler": { "version": "v0.0.0", "requirements": [] }, "hacs": { "version": "1.32.1", "requirements": [ "aiogithubapi>=22.10.1" ] } }, "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.5", "pyserial==3.5", "pyserial-asyncio==0.6", "zha-quirks==0.0.100", "zigpy-deconz==0.21.0", "zigpy==0.55.0", "zigpy-xbee==0.18.0", "zigpy-zigate==0.11.0", "zigpy-znp==0.11.1" ], "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": 20130, "manufacturer": "_TZE204_dtzziy1e", "model": "TS0601", "name": "_TZE204_dtzziy1e TS0601", "quirk_applied": false, "quirk_class": "zigpy.device.Device", "manufacturer_code": 4098, "power_source": "Mains", "lqi": 120, "rssi": -70, "last_seen": "2023-07-04T17:06:49", "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=4098, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, 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": "0x0051", "input_clusters": [ "0x0000", "0x0004", "0x0005", "0xef00" ], "output_clusters": [ "0x000a", "0x0019" ] } }, "manufacturer": "_TZE204_dtzziy1e", "model": "TS0601" }, "active_coordinator": false, "entities": [], "neighbors": [], "routes": [], "endpoint_names": [ { "name": "SMART_PLUG" } ], "user_given_name": null, "device_reg_id": "7eaa8369d968bad6058dfa13271833d1", "area_id": null, "cluster_details": { "1": { "device_type": { "name": "SMART_PLUG", "id": 81 }, "profile_id": 260, "in_clusters": { "0x0000": { "endpoint_attribute": "basic", "attributes": { "0x0001": { "attribute_name": "app_version", "value": 70 }, "0x0004": { "attribute_name": "manufacturer", "value": "_TZE204_dtzziy1e" }, "0x0005": { "attribute_name": "model", "value": "TS0601" } }, "unsupported_attributes": {} }, "0x0004": { "endpoint_attribute": "groups", "attributes": {}, "unsupported_attributes": {} }, "0x0005": { "endpoint_attribute": "scenes", "attributes": {}, "unsupported_attributes": {} }, "0xef00": { "endpoint_attribute": null, "attributes": {}, "unsupported_attributes": {} } }, "out_clusters": { "0x0019": { "endpoint_attribute": "ota", "attributes": {}, "unsupported_attributes": {} }, "0x000a": { "endpoint_attribute": "time", "attributes": {}, "unsupported_attributes": {} } } } } } } ```

Logs

Logs ```python Logger: zigpy.zcl Source: runner.py:179 First occurred: 4:33:38 PM (126 occurrences) Last logged: 4:54:38 PM [0x4EA2:1:0xef00] Unknown cluster command 2 b'\x00G\t\x02\x00\x04\x00\x00\x00\x00' [0x4EA2:1:0xef00] Unknown cluster command 2 b'\x00H\x01\x04\x00\x01\x01' [0x4EA2:1:0xef00] Unknown cluster command 2 b'\x00I\t\x02\x00\x04\x00\x00\x01o' [0x4EA2:1:0xef00] Unknown cluster command 2 b'\x00J\t\x02\x00\x04\x00\x00\x00\x00' [0x4EA2:1:0xef00] Unknown cluster command 2 b'\x00K\x01\x04\x00\x01\x00' ```

Additional information

Successfully loaded a custom ts0601_motion.py quirk (with additional MODELS INFO in MmwRadarMotion(CustomDevice) class) but it exposes only one binary sensor and relay isn't clicking when detected/clear.

Also as you can see on the board photo it has a IR led. Why is it there? Would it be possible to use it?

javicalle commented 1 year ago

Can you attach the logs with the quirk applied? Logs from quirk would be more descriptive. Also, with the quirk applied, catch the logs from the device powerup (when wires are connected). Tuya devices usually reports its status and give to us some DPs information. Any link to vendor site or device capabilities?

Nelevit commented 1 year ago

@javicalle Thanks a lot for your reply!

Sorry it takes me so long to post those logs. I can't reproduce loading the quirk now :/

Zigpy Logs ```python Logger: zhaquirks Source: custom_zha_quirks/ts0601_motion.py:6 First occurred: 3:06:31 PM (1 occurrences) Last logged: 3:06:31 PM Unexpected exception importing custom quirk 'ts0601_motion' Traceback (most recent call last): File "/usr/local/lib/python3.11/site-packages/zhaquirks/__init__.py", line 454, in setup importer.find_module(modname).load_module(modname) File "", line 605, in _check_name_wrapper File "", line 1120, in load_module File "", line 945, in load_module File "", line 290, in _load_module_shim File "", line 721, in _load File "", line 690, in _load_unlocked File "", line 940, in exec_module File "", line 241, in _call_with_frames_removed File "/config/custom_zha_quirks/ts0601_motion.py", line 6, in from zigpy.profiles import zgp, zha ImportError: cannot import name 'zgp' from 'zigpy.profiles' (/usr/local/lib/python3.11/site-packages/zigpy/profiles/__init__.py) ```

Would you please help to figure it out?

Here is a link to device page on AliExpress

Thanks in advance! Nestor

javicalle commented 1 year ago

Take the ts0601_motion.py version from here: https://github.com/zigpy/zha-device-handlers/raw/release/0.0.74/zhaquirks/tuya/ts0601_motion.py

Add your model, save changes and restart HA.

Check here to enable the debug logs:

Nelevit commented 1 year ago

@javicalle Thanks for your help :)

Its alive! :D

I've experimented with it and 2 classes were able to load:

Single entity - human presence sensor which works ok

MmwRadarMotion_NAS-PD07 Diagnostics ```json { "home_assistant": { "installation_type": "Home Assistant OS", "version": "2023.7.0", "dev": false, "hassio": true, "virtualenv": false, "python_version": "3.11.4", "docker": true, "arch": "x86_64", "timezone": "Europe/Kiev", "os_name": "Linux", "os_version": "6.1.34", "supervisor": "2023.07.1", "host_os": "Home Assistant OS 10.3", "docker_version": "23.0.6", "chassis": "vm", "run_as_root": true }, "custom_components": { "scheduler": { "version": "v0.0.0", "requirements": [] }, "hacs": { "version": "1.32.1", "requirements": [ "aiogithubapi>=22.10.1" ] } }, "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.1", "zigpy-xbee==0.18.1", "zigpy-zigate==0.11.0", "zigpy-znp==0.11.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" ] } ], "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": 7788, "manufacturer": "_TZE204_dtzziy1e", "model": "TS0601", "name": "_TZE204_dtzziy1e TS0601", "quirk_applied": true, "quirk_class": "ts0601_customMotion.MmwRadarMotion", "manufacturer_code": 4098, "power_source": "Mains", "lqi": 192, "rssi": -52, "last_seen": "2023-07-05T23:14:19", "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=4098, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, 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": "0x0107", "input_clusters": [ "0x0000", "0x0004", "0x0005", "0x000c", "0x0400", "0x0406", "0xef00" ], "output_clusters": [ "0x000a", "0x0019" ] } }, "manufacturer": "_TZE204_dtzziy1e", "model": "TS0601" }, "active_coordinator": false, "entities": [ { "entity_id": "binary_sensor.tze204_dtzziy1e_ts0601_occupancy", "name": "_TZE204_dtzziy1e TS0601" } ], "neighbors": [], "routes": [], "endpoint_names": [ { "name": "OCCUPANCY_SENSOR" } ], "user_given_name": null, "device_reg_id": "7eaa8369d968bad6058dfa13271833d1", "area_id": null, "cluster_details": { "1": { "device_type": { "name": "OCCUPANCY_SENSOR", "id": 263 }, "profile_id": 260, "in_clusters": { "0x0000": { "endpoint_attribute": "basic", "attributes": { "0x0001": { "attribute_name": "app_version", "value": 70 } }, "unsupported_attributes": {} }, "0x0004": { "endpoint_attribute": "groups", "attributes": {}, "unsupported_attributes": {} }, "0x0005": { "endpoint_attribute": "scenes", "attributes": {}, "unsupported_attributes": {} }, "0xef00": { "endpoint_attribute": "tuya_manufacturer", "attributes": { "0xef65": { "attribute_name": "dp_101", "value": 10 }, "0xef66": { "attribute_name": "dp_102", "value": 30 }, "0xef67": { "attribute_name": "dp_103", "value": "" }, "0xef69": { "attribute_name": "dp_105", "value": 5 }, "0xef6a": { "attribute_name": "dp_106", "value": 60 }, "0xef6b": { "attribute_name": "dp_107", "value": 0 }, "0xef6c": { "attribute_name": "dp_108", "value": 0 }, "0xef02": { "attribute_name": "dp_2", "value": 7 }, "0xef03": { "attribute_name": "dp_3", "value": 60 }, "0xef04": { "attribute_name": "dp_4", "value": 600 }, "0xef06": { "attribute_name": "dp_6", "value": 1 }, "0xef00": { "attribute_name": "mcu_version", "value": "1.0.0" } }, "unsupported_attributes": {} }, "0x0406": { "endpoint_attribute": "occupancy", "attributes": { "0x0000": { "attribute_name": "occupancy", "value": 0 } }, "unsupported_attributes": { "0x0000": { "attribute_name": "occupancy" } } }, "0x000c": { "endpoint_attribute": "analog_input", "attributes": { "0x0055": { "attribute_name": "present_value", "value": 0.0 } }, "unsupported_attributes": {} }, "0x0400": { "endpoint_attribute": "illuminance", "attributes": { "0x0000": { "attribute_name": "measured_value", "value": 36429.600525844915 } }, "unsupported_attributes": { "0x0000": { "attribute_name": "measured_value" } } } }, "out_clusters": { "0x000a": { "endpoint_attribute": "time", "attributes": {}, "unsupported_attributes": {} }, "0x0019": { "endpoint_attribute": "ota", "attributes": {}, "unsupported_attributes": {} } } } } } } ```

MmwRadarMotion_NAS-PD07.txt

image

NeoMotion_NAS-PD07 Diagnostics ```json { "home_assistant": { "installation_type": "Home Assistant OS", "version": "2023.7.0", "dev": false, "hassio": true, "virtualenv": false, "python_version": "3.11.4", "docker": true, "arch": "x86_64", "timezone": "Europe/Kiev", "os_name": "Linux", "os_version": "6.1.34", "supervisor": "2023.07.1", "host_os": "Home Assistant OS 10.3", "docker_version": "23.0.6", "chassis": "vm", "run_as_root": true }, "custom_components": { "scheduler": { "version": "v0.0.0", "requirements": [] }, "hacs": { "version": "1.32.1", "requirements": [ "aiogithubapi>=22.10.1" ] } }, "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.1", "zigpy-xbee==0.18.1", "zigpy-zigate==0.11.0", "zigpy-znp==0.11.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" ] } ], "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": 2112, "manufacturer": "_TZE204_dtzziy1e", "model": "TS0601", "name": "_TZE204_dtzziy1e TS0601", "quirk_applied": true, "quirk_class": "ts0601_customMotion.NeoMotion", "manufacturer_code": 4098, "power_source": "Mains", "lqi": 192, "rssi": -52, "last_seen": "2023-07-05T23:38:30", "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=4098, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, 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": "0x0107", "input_clusters": [ "0x0000", "0x0004", "0x0005", "0x0402", "0x0405", "0x0406", "0xef00" ], "output_clusters": [ "0x000a", "0x0019" ] } }, "manufacturer": "_TZE204_dtzziy1e", "model": "TS0601" }, "active_coordinator": false, "entities": [ { "entity_id": "binary_sensor.tze204_dtzziy1e_ts0601_occupancy", "name": "_TZE204_dtzziy1e TS0601" }, { "entity_id": "sensor.tze204_dtzziy1e_ts0601_temperature", "name": "_TZE204_dtzziy1e TS0601" }, { "entity_id": "sensor.tze204_dtzziy1e_ts0601_humidity", "name": "_TZE204_dtzziy1e TS0601" } ], "neighbors": [], "routes": [], "endpoint_names": [ { "name": "OCCUPANCY_SENSOR" } ], "user_given_name": null, "device_reg_id": "7eaa8369d968bad6058dfa13271833d1", "area_id": null, "cluster_details": { "1": { "device_type": { "name": "OCCUPANCY_SENSOR", "id": 263 }, "profile_id": 260, "in_clusters": { "0x0000": { "endpoint_attribute": "basic", "attributes": { "0x0001": { "attribute_name": "app_version", "value": 70 }, "0x0004": { "attribute_name": "manufacturer", "value": "_TZE204_dtzziy1e" }, "0x0005": { "attribute_name": "model", "value": "TS0601" } }, "unsupported_attributes": {} }, "0x0004": { "endpoint_attribute": "groups", "attributes": {}, "unsupported_attributes": {} }, "0x0005": { "endpoint_attribute": "scenes", "attributes": {}, "unsupported_attributes": {} }, "0xef00": { "endpoint_attribute": "tuya_manufacturer", "attributes": {}, "unsupported_attributes": {} }, "0x0406": { "endpoint_attribute": "occupancy", "attributes": { "0x0000": { "attribute_name": "occupancy", "value": 10 } }, "unsupported_attributes": {} }, "0x0402": { "endpoint_attribute": "temperature", "attributes": { "0x0000": { "attribute_name": "measured_value", "value": 43940 } }, "unsupported_attributes": {} }, "0x0405": { "endpoint_attribute": "humidity", "attributes": { "0x0000": { "attribute_name": "measured_value", "value": 500 } }, "unsupported_attributes": {} } }, "out_clusters": { "0x000a": { "endpoint_attribute": "time", "attributes": {}, "unsupported_attributes": {} }, "0x0019": { "endpoint_attribute": "ota", "attributes": {}, "unsupported_attributes": {} } } } } } } ```

NeoMotion_NAS-PD07.txt

txt files files contain logs while resetting.

Hope it helps, Nestor

Nelevit commented 1 year ago

Hi, @TheJulianJES I've noticed you tagged a custom quirk but can't find it 😕 Could you please help? Would be happy to test it out and report back. Thanks in advance, Nestor

JeroenVanOort commented 1 year ago

I think the label just concerns adding _TZE204_dtzziy1e to the existing MmwRadarMotion cluster. That's what I did and it does work for the basic function of detecting occupancy and illuminance, but I can't control the relay or the parameters that should make the relay switch.

Does anybody know where to get started on this? There is some information available from another project: https://github.com/Koenkk/zigbee-herdsman-converters/issues/5930

evgenln commented 1 year ago

@JeroenVanOort I did quirk for it's brother _TZE204_clrdrnya, it's same options device. But it probably will not really usable for you as I running zha as component and exposed all options/target distance sensor in it's bundles. Anyway it contains all datapoints so at least you will be able to change values of options via Mange ZigBee device.

evgenln commented 1 year ago

ts0601_presence.zip

But add your signature 1st

JeroenVanOort commented 1 year ago

Thank you very much!

Have you been able to get the relay working? For me, the relay never switches, neither automatic nor manual. Maybe my unit is just broken, but I don't know.

evgenln commented 1 year ago

Yes @JeroenVanOort , it is working.

I have the full UI due to custom changes I did in ZHA, with default ZHA you will not see controls but you can try to do it manually from the device page via the Manage Zigbee device.

Open Manage Zigbee device and select MmwRadarV3ManufCluster Select breaker_mode attribute and write 0 to it (it will set the device to Standart mode with the ability to manipulate relay) then select the breaker_status attribute and write 0 to set it off or 1 to set it on (polarity depends on one more attribute breaker_polarity but I am not sure if it is implemented in your device)

RiRomain commented 11 months ago

I tried with the attached zip file by replacing the device info, but I only have occupancy showed, does someone know how to correct it and have the .py file that fit the _TZE204_dtzziy1e ?

ts0601_presence.py.txt

RiRomain commented 10 months ago

Working fine with the following:

import math
from typing import Dict

from zigpy.profiles import zgp, zha
from zigpy.quirks import CustomDevice
import zigpy.types as t
from zigpy.zcl.clusters.general import (
    AnalogInput,
    AnalogOutput,
    Basic,
    GreenPowerProxy,
    Groups,
    Ota,
    Scenes,
    Time,
)
from zigpy.zcl.clusters.measurement import IlluminanceMeasurement, OccupancySensing

from zhaquirks.const import (
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
)
from zhaquirks.tuya import NoManufacturerCluster, TuyaLocalCluster, TuyaNewManufCluster
from zhaquirks.tuya.mcu import (
    DPToAttributeMapping,
    TuyaAttributesCluster,
    TuyaMCUCluster,
)

ZONE_TYPE = 0x0001

class TuyaMmwRadarSelfTest(t.enum8):
    """Mmw radar self test values."""

    TESTING = 0
    TEST_SUCCESS = 1
    TEST_FAILURE = 2
    OTHER = 3
    COMM_FAULT = 4
    RADAR_FAULT = 5

class TuyaOccupancySensing(OccupancySensing, TuyaLocalCluster):
    """Tuya local OccupancySensing cluster."""

class TuyaAnalogInput(AnalogInput, TuyaLocalCluster):
    """Tuya local AnalogInput cluster."""

class TuyaIlluminanceMeasurement(IlluminanceMeasurement, TuyaLocalCluster):
    """Tuya local IlluminanceMeasurement cluster."""

class TuyaMmwRadarSensitivity(TuyaAttributesCluster, AnalogOutput):
    """AnalogOutput cluster for sensitivity."""

    def __init__(self, *args, **kwargs):
        """Init."""
        super().__init__(*args, **kwargs)
        self._update_attribute(self.attributes_by_name["description"].id, "Sensitivity")
        self._update_attribute(self.attributes_by_name["min_present_value"].id, 1)
        self._update_attribute(self.attributes_by_name["max_present_value"].id, 9)
        self._update_attribute(self.attributes_by_name["resolution"].id, 1)

class TuyaMmwRadarMinRange(TuyaAttributesCluster, AnalogOutput):
    """AnalogOutput cluster for min range."""

    def __init__(self, *args, **kwargs):
        """Init."""
        super().__init__(*args, **kwargs)
        self._update_attribute(self.attributes_by_name["description"].id, "Min range")
        self._update_attribute(self.attributes_by_name["min_present_value"].id, 0)
        self._update_attribute(self.attributes_by_name["max_present_value"].id, 950)
        self._update_attribute(self.attributes_by_name["resolution"].id, 10)
        self._update_attribute(
            self.attributes_by_name["engineering_units"].id, 118
        ) # 31: meters

class TuyaMmwRadarMaxRange(TuyaAttributesCluster, AnalogOutput):
    """AnalogOutput cluster for max range."""

    def __init__(self, *args, **kwargs):
        """Init."""
        super().__init__(*args, **kwargs)
        self._update_attribute(self.attributes_by_name["description"].id, "Max range")
        self._update_attribute(self.attributes_by_name["min_present_value"].id, 10)
        self._update_attribute(self.attributes_by_name["max_present_value"].id, 950)
        self._update_attribute(self.attributes_by_name["resolution"].id, 10)
        self._update_attribute(
            self.attributes_by_name["engineering_units"].id, 118
        ) # 31: meters

class TuyaMmwRadarDetectionDelay(TuyaAttributesCluster, AnalogOutput):
    """AnalogOutput cluster for detection delay."""

    def __init__(self, *args, **kwargs):
        """Init."""
        super().__init__(*args, **kwargs)
        self._update_attribute(
            self.attributes_by_name["description"].id, "Detection delay"
        )
        self._update_attribute(self.attributes_by_name["min_present_value"].id, 000)
        self._update_attribute(self.attributes_by_name["max_present_value"].id, 20000)
        self._update_attribute(self.attributes_by_name["resolution"].id, 100)
        self._update_attribute(
            self.attributes_by_name["engineering_units"].id, 159
        ) # 73: seconds

class TuyaMmwRadarFadingTime(TuyaAttributesCluster, AnalogOutput):
    """AnalogOutput cluster for fading time."""

    def __init__(self, *args, **kwargs):
        """Init."""
        super().__init__(*args, **kwargs)
        self._update_attribute(self.attributes_by_name["description"].id, "Fading time")
        self._update_attribute(self.attributes_by_name["min_present_value"].id, 2000)
        self._update_attribute(self.attributes_by_name["max_present_value"].id, 200000)
        self._update_attribute(self.attributes_by_name["resolution"].id, 1000)
        self._update_attribute(
            self.attributes_by_name["engineering_units"].id, 159
        ) # 73: seconds

class TuyaMmwRadarTargetDistance(TuyaAttributesCluster, AnalogInput):
    """AnalogInput cluster for target distance."""

    def __init__(self, *args, **kwargs):
        """Init."""
        super().__init__(*args, **kwargs)
        self._update_attribute(
            self.attributes_by_name["description"].id, "Target distance"
        )
        self._update_attribute(
            self.attributes_by_name["engineering_units"].id, 31
        ) # 31: meters

class TuyaMmwRadarClusterBase(NoManufacturerCluster, TuyaMCUCluster):
    """Mmw radar cluster, base class."""

    attributes = TuyaMCUCluster.attributes.copy()
    attributes.update(
        {
            # ramdom attribute IDs
            0xEF01: ("occupancy", t.uint32_t, True),
            0xEF02: ("sensitivity", t.uint32_t, True),
            0xEF03: ("min_range", t.uint32_t, True),
            0xEF04: ("max_range", t.uint32_t, True),
            0xEF06: ("self_test", TuyaMmwRadarSelfTest, True),
            0xEF09: ("target_distance", t.uint32_t, True),
            0xEF65: ("detection_delay", t.uint32_t, True),
            0xEF66: ("fading_time", t.uint32_t, True),
            0xEF67: ("cli", t.CharacterString, True),
            0xEF68: ("illuminance", t.uint32_t, True),
        }
    )

class TuyaMmwRadarClusterVariant1(TuyaMmwRadarClusterBase):
    """Mmw radar cluster, variant 1."""

    dp_to_attribute: Dict[int, DPToAttributeMapping] = {
        1: DPToAttributeMapping(
            TuyaOccupancySensing.ep_attribute,
            "occupancy",
        ),
        2: DPToAttributeMapping(
            TuyaMmwRadarSensitivity.ep_attribute,
            "present_value",
        ),
        3: DPToAttributeMapping(
            TuyaMmwRadarMinRange.ep_attribute,
            "present_value",
            endpoint_id=2,
        ),
        4: DPToAttributeMapping(
            TuyaMmwRadarMaxRange.ep_attribute,
            "present_value",
            endpoint_id=3,
        ),
        6: DPToAttributeMapping(
            TuyaMCUCluster.ep_attribute,
            "self_test",
        ),
        9: DPToAttributeMapping(
            TuyaMmwRadarTargetDistance.ep_attribute,
            "present_value",
            lambda x: x / 100,
        ),
        101: DPToAttributeMapping(
            TuyaMmwRadarDetectionDelay.ep_attribute,
            "present_value",
            converter=lambda x: x * 100,
            dp_converter=lambda x: x // 100,
            endpoint_id=4,
        ),
        102: DPToAttributeMapping(
            TuyaMmwRadarFadingTime.ep_attribute,
            "present_value",
            converter=lambda x: x * 100,
            dp_converter=lambda x: x // 100,
            endpoint_id=5,
        ),
        103: DPToAttributeMapping(
            TuyaMCUCluster.ep_attribute,
            "cli",
        ),
        104: DPToAttributeMapping(
            TuyaIlluminanceMeasurement.ep_attribute,
            "measured_value",
            converter=lambda x: int(math.log10(x) * 10000 + 1) if x > 0 else int(0),
        ),
    }

    data_point_handlers = {
        1: "_dp_2_attr_update",
        2: "_dp_2_attr_update",
        3: "_dp_2_attr_update",
        4: "_dp_2_attr_update",
        6: "_dp_2_attr_update",
        9: "_dp_2_attr_update",
        101: "_dp_2_attr_update",
        102: "_dp_2_attr_update",
        103: "_dp_2_attr_update",
        104: "_dp_2_attr_update",
    }

class TuyaMmwRadarOccupancyVariant1(CustomDevice):
    """Millimeter wave occupancy sensor, variant 1."""

    signature = {
        # endpoint=1, profile=260, device_type=81, device_version=1,
        # input_clusters=[0, 4, 5, 61184], output_clusters=[25, 10]
        MODELS_INFO: [
     ("_TZE204_dtzziy1e", "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,
                    TuyaNewManufCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.OCCUPANCY_SENSOR,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaMmwRadarClusterVariant1,
                    TuyaIlluminanceMeasurement,
                    TuyaOccupancySensing,
                    TuyaMmwRadarTargetDistance,
                    TuyaMmwRadarSensitivity,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    TuyaMmwRadarMinRange,
                ],
                OUTPUT_CLUSTERS: [],
            },
            3: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    TuyaMmwRadarMaxRange,
                ],
                OUTPUT_CLUSTERS: [],
            },
            4: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    TuyaMmwRadarDetectionDelay,
                ],
                OUTPUT_CLUSTERS: [],
            },
            5: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    TuyaMmwRadarFadingTime,
                ],
                OUTPUT_CLUSTERS: [],
            },
        }
    }

class TuyaMmwRadarOccupancyVariant1GPP(CustomDevice):
    """Millimeter wave occupancy sensor, variant 1 with GPP."""

    signature = {
        # endpoint=1, profile=260, device_type=81, device_version=1,
        # input_clusters=[0, 4, 5, 61184], output_clusters=[25, 10])
        MODELS_INFO: [
     ("_TZE204_dtzziy1e", "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,
                    TuyaNewManufCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            242: {
                # <SimpleDescriptor endpoint=242 profile=41440 device_type=97
                # input_clusters=[]
                # output_clusters=[33]
                PROFILE_ID: zgp.PROFILE_ID,
                DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.OCCUPANCY_SENSOR,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaMmwRadarClusterVariant1,
                    TuyaIlluminanceMeasurement,
                    TuyaOccupancySensing,
                    TuyaMmwRadarTargetDistance,
                    TuyaMmwRadarSensitivity,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    TuyaMmwRadarMinRange,
                ],
                OUTPUT_CLUSTERS: [],
            },
            3: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    TuyaMmwRadarMaxRange,
                ],
                OUTPUT_CLUSTERS: [],
            },
            4: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    TuyaMmwRadarDetectionDelay,
                ],
                OUTPUT_CLUSTERS: [],
            },
            5: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    TuyaMmwRadarFadingTime,
                ],
                OUTPUT_CLUSTERS: [],
            },
            242: {
                PROFILE_ID: zgp.PROFILE_ID,
                DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        }
    }

class TuyaMmwRadarClusterVariant2(TuyaMmwRadarClusterBase):
    """Tuya MMW radar cluster, variant 2."""

    dp_to_attribute: Dict[int, DPToAttributeMapping] = {
        103: DPToAttributeMapping(
            TuyaMCUCluster.ep_attribute,
            "cli",
        ),
        104: DPToAttributeMapping(
            TuyaIlluminanceMeasurement.ep_attribute,
            "measured_value",
            converter=lambda x: int(math.log10(x) * 10000 + 1) if x > 0 else int(0),
        ),
        105: DPToAttributeMapping(
            TuyaOccupancySensing.ep_attribute,
            "occupancy",
        ),
        106: DPToAttributeMapping(
            TuyaMmwRadarSensitivity.ep_attribute,
            "present_value",
        ),
        107: DPToAttributeMapping(
            TuyaMmwRadarMaxRange.ep_attribute,
            "present_value",
            endpoint_id=3,
        ),
        108: DPToAttributeMapping(
            TuyaMmwRadarMinRange.ep_attribute,
            "present_value",
            endpoint_id=2,
        ),
        109: DPToAttributeMapping(
            TuyaMmwRadarTargetDistance.ep_attribute,
            "present_value",
        ),
        110: DPToAttributeMapping(
            TuyaMmwRadarFadingTime.ep_attribute,
            "present_value",
            converter=lambda x: x * 100,
            dp_converter=lambda x: x // 100,
            endpoint_id=5,
        ),
        111: DPToAttributeMapping(
            TuyaMmwRadarDetectionDelay.ep_attribute,
            "present_value",
            converter=lambda x: x * 100,
            dp_converter=lambda x: x // 100,
            endpoint_id=4,
        ),
    }

    data_point_handlers = {
        103: "_dp_2_attr_update",
        104: "_dp_2_attr_update",
        105: "_dp_2_attr_update",
        106: "_dp_2_attr_update",
        107: "_dp_2_attr_update",
        108: "_dp_2_attr_update",
        109: "_dp_2_attr_update",
        110: "_dp_2_attr_update",
        111: "_dp_2_attr_update",
    }

class TuyaMmwRadarOccupancyVariant2(CustomDevice):
    """Millimeter wave occupancy sensor, variant 2."""

    signature = {
        # endpoint=1, profile=260, device_type=81, device_version=1,
        # input_clusters=[0, 4, 5, 61184], output_clusters=[25, 10])
        MODELS_INFO: [
                 ("_TZE204_dtzziy1e", "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,
                    TuyaNewManufCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            242: {
                # <SimpleDescriptor endpoint=242 profile=41440 device_type=97
                # input_clusters=[]
                # output_clusters=[33]
                PROFILE_ID: zgp.PROFILE_ID,
                DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.OCCUPANCY_SENSOR,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaMmwRadarClusterVariant2,
                    TuyaIlluminanceMeasurement,
                    TuyaOccupancySensing,
                    TuyaMmwRadarTargetDistance,
                    TuyaMmwRadarSensitivity,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    TuyaMmwRadarMinRange,
                ],
                OUTPUT_CLUSTERS: [],
            },
            3: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    TuyaMmwRadarMaxRange,
                ],
                OUTPUT_CLUSTERS: [],
            },
            4: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    TuyaMmwRadarDetectionDelay,
                ],
                OUTPUT_CLUSTERS: [],
            },
            5: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    TuyaMmwRadarFadingTime,
                ],
                OUTPUT_CLUSTERS: [],
            },
            242: {
                PROFILE_ID: zgp.PROFILE_ID,
                DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        }
    }
bouboun59 commented 10 months ago

Thanks a lot, it's work fine with my TS060 _TZE204_clrdrnya, but I don't understand why i don't see the radar target distance in my sensors image so i see in the advanced parameters image

could you explain why ? And you, you can see the radar target distance

tommetje commented 10 months ago

I tried with the attached zip file by replacing the device info, but I only have occupancy showed, does someone know how to correct it and have the .py file that fit the _TZE204_dtzziy1e ?

ts0601_presence.py.txt

@RiRomain Do you see more than Illuminance and Occupancy in ZHA?

RiRomain commented 10 months ago

I only see illuminance and occupancy, but didn't think that the sensor can handle anything more (appart from the settings). And I didn't use the zip, but the code in the comment. Screenshot_20240116_220607_Home Assistant

tommetje commented 10 months ago

Wow nice, GUI controls woohoo! :) I tried it and it works!

My detectors are picking up movements of neighbors so for me the entry controls are essential. Currently, Entry Sensitivity and Entry Distance Indentation are sadly missing in the quirk update. I currently have no time nor knowledge (yet :) ) to adjust your quirk, so I will revert back and keep an eye out for possible updates in this thread.

Thanks for sharing your quirk @RiRomain !

mariovw commented 9 months ago

Hi @evgenln ,

I have _TZE204_clrdrnya. I load the quirk ts0601_presence.py.txt but I only get the presence and iluminance but not the Controls to adjust the parametres.

Do you know what could be the issue?

Many thanks!

image

tommetje commented 9 months ago

Sometimes it helps to reload the ZHA integration, just in case you have not tried this. You can also try to remove the devices and add them again. I had the same problem and this fixed things for me. image

mariovw commented 9 months ago

thanks @tommetje for your quick answer.

Unfortunally I followed your instructions several times with no results. Any other idea?

Many thanks!

PD: just to say I have the last firmware version

tommetje commented 9 months ago

thanks @tommetje for your quick answer.

Unfortunally I followed your instructions several times with no results. Any other idea?

Many thanks!

I updated the existing quirk, after this I did not see the changes.

From what I remember, I also tried removing removing the affected devices + removing the quirk folder + HA restart + ZHA reload. After this I added the folder of the updated quirk and gave it a different name, again HA restart + adding devices again + ZHA reload (if needed) .

Not sure if all the steps are needed but this is what I tried. Eventually I got the updated quirk working.

mariovw commented 9 months ago

thks @tommetje,

I'll try to play more the weekend!

Best,

matsjrosenberg commented 8 months ago

Hello, I have a _TZE204_sbyx0lm6 (the 5.8G version as opposed to the 2.4G) and have tried all quirks above, changing the device specs in the code, and only randomly gotten only the illuminance and presence to work. I am not a coder so can't unfortunately contribute to this, but would really appreciate if somebody could continue developing this quirk further. Many thanks!

frawau commented 8 months ago

I have a _TZE204_clrdrnya device and with @RiRomain python script, I get the occupancy to work fine ... Yeah! Thank you.

But

Luminance is not working, and neither Ota nor Time are working. Then there is the the question of the relay.

According to @LuisAlbertoFB in this thead it is possible to get it all working. I tried a few things, but so far no luck... Anyone has a clue on how to port this?

OakfieldDrive commented 7 months ago

Hi all, I got it to work on _TZE204_clrdrnya using the quirk shared in the zip file above. however, the illuminance figures are not within the expected range. e.g, I am currently in a room, in a cloudy day; would expect to have something between 15 to 30 lx but instead, it shows 1,522lx. Anyone else has the same problem?

macf0x commented 6 months ago

Was there any luck getting the relay to work?

cHeeSaW commented 6 months ago

I got it working for _TZE204_dtzziy1e with the code from @RiRomain's comment. The illuminance value does not show up at first, i have to restart HA every time i add a new device of this type, then it shows up. Anyone working on the missing values and relay?

macf0x commented 5 months ago

Same. I get following controls and Occupancy Sensor. No lux.

Detection Delay Fading Time Max Range Min Range Sensitivity

Firmware Update is also visible

Relay isn't exposed and doesn't align to Occupancy. That all I really need.

nnae06 commented 3 months ago

I got everything working except the relay. In my case, I don't use the relay function.

Can this be added to ZHA. This ZHA quirks prevent me from updating to 2024.08 ->. Many of my automations at home use these devices to function.

"""Tuya mmw radar occupancy sensor."""

import math from typing import Dict

from zigpy.profiles import zgp, zha from zigpy.quirks import CustomDevice import zigpy.types as t from zigpy.zcl.clusters.general import ( AnalogInput, AnalogOutput, Basic, GreenPowerProxy, Groups, Ota, Scenes, Time, ) from zigpy.zcl.clusters.measurement import IlluminanceMeasurement, OccupancySensing

from zhaquirks.const import ( DEVICE_TYPE, ENDPOINTS, INPUT_CLUSTERS, MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, ) from zhaquirks.tuya import NoManufacturerCluster, TuyaLocalCluster, TuyaNewManufCluster from zhaquirks.tuya.mcu import ( DPToAttributeMapping, TuyaAttributesCluster, TuyaMCUCluster, )

ZONE_TYPE = 0x0001

class TuyaMmwRadarSelfTest(t.enum8): """Mmw radar self test values."""

TESTING = 0
TEST_SUCCESS = 1
TEST_FAILURE = 2
OTHER = 3
COMM_FAULT = 4
RADAR_FAULT = 5

class TuyaOccupancySensing(OccupancySensing, TuyaLocalCluster): """Tuya local OccupancySensing cluster."""

class TuyaAnalogInput(AnalogInput, TuyaLocalCluster): """Tuya local AnalogInput cluster."""

class TuyaIlluminanceMeasurement(IlluminanceMeasurement, TuyaLocalCluster): """Tuya local IlluminanceMeasurement cluster."""

class TuyaMmwRadarSensitivity(TuyaAttributesCluster, AnalogOutput): """AnalogOutput cluster for sensitivity."""

def __init__(self, *args, **kwargs):
    """Init."""
    super().__init__(*args, **kwargs)
    self._update_attribute(self.attributes_by_name["description"].id, "Sensitivity")
    self._update_attribute(self.attributes_by_name["min_present_value"].id, 1)
    self._update_attribute(self.attributes_by_name["max_present_value"].id, 9)
    self._update_attribute(self.attributes_by_name["resolution"].id, 1)

class TuyaMmwRadarMinRange(TuyaAttributesCluster, AnalogOutput): """AnalogOutput cluster for min range."""

def __init__(self, *args, **kwargs):
    """Init."""
    super().__init__(*args, **kwargs)
    self._update_attribute(self.attributes_by_name["description"].id, "Min range")
    self._update_attribute(self.attributes_by_name["min_present_value"].id, 0)
    self._update_attribute(self.attributes_by_name["max_present_value"].id, 950)
    self._update_attribute(self.attributes_by_name["resolution"].id, 10)
    self._update_attribute(
        self.attributes_by_name["engineering_units"].id, 118
    )  # 31: meters

class TuyaMmwRadarMaxRange(TuyaAttributesCluster, AnalogOutput): """AnalogOutput cluster for max range."""

def __init__(self, *args, **kwargs):
    """Init."""
    super().__init__(*args, **kwargs)
    self._update_attribute(self.attributes_by_name["description"].id, "Max range")
    self._update_attribute(self.attributes_by_name["min_present_value"].id, 10)
    self._update_attribute(self.attributes_by_name["max_present_value"].id, 950)
    self._update_attribute(self.attributes_by_name["resolution"].id, 10)
    self._update_attribute(
        self.attributes_by_name["engineering_units"].id, 118
    )  # 31: meters

class TuyaMmwRadarDetectionDelay(TuyaAttributesCluster, AnalogOutput): """AnalogOutput cluster for detection delay."""

def __init__(self, *args, **kwargs):
    """Init."""
    super().__init__(*args, **kwargs)
    self._update_attribute(
        self.attributes_by_name["description"].id, "Detection delay"
    )
    self._update_attribute(self.attributes_by_name["min_present_value"].id, 000)
    self._update_attribute(self.attributes_by_name["max_present_value"].id, 20000)
    self._update_attribute(self.attributes_by_name["resolution"].id, 100)
    self._update_attribute(
        self.attributes_by_name["engineering_units"].id, 159
    )  # 73: seconds

class TuyaMmwRadarFadingTime(TuyaAttributesCluster, AnalogOutput): """AnalogOutput cluster for fading time."""

def __init__(self, *args, **kwargs):
    """Init."""
    super().__init__(*args, **kwargs)
    self._update_attribute(self.attributes_by_name["description"].id, "Fading time")
    self._update_attribute(self.attributes_by_name["min_present_value"].id, 2000)
    self._update_attribute(self.attributes_by_name["max_present_value"].id, 200000)
    self._update_attribute(self.attributes_by_name["resolution"].id, 1000)
    self._update_attribute(
        self.attributes_by_name["engineering_units"].id, 159
    )  # 73: seconds

class TuyaMmwRadarTargetDistance(TuyaAttributesCluster, AnalogInput): """AnalogInput cluster for target distance."""

def __init__(self, *args, **kwargs):
    """Init."""
    super().__init__(*args, **kwargs)
    self._update_attribute(
        self.attributes_by_name["description"].id, "Target distance"
    )
    self._update_attribute(
        self.attributes_by_name["engineering_units"].id, 31
    )  # 31: meters

class TuyaMmwRadarClusterBase(NoManufacturerCluster, TuyaMCUCluster): """Mmw radar cluster, base class."""

attributes = TuyaMCUCluster.attributes.copy()
attributes.update(
    {
        # ramdom attribute IDs
        0xEF01: ("occupancy", t.uint32_t, True),
        0xEF02: ("sensitivity", t.uint32_t, True),
        0xEF03: ("min_range", t.uint32_t, True),
        0xEF04: ("max_range", t.uint32_t, True),
        0xEF06: ("self_test", TuyaMmwRadarSelfTest, True),
        0xEF09: ("target_distance", t.uint32_t, True),
        0xEF65: ("detection_delay", t.uint32_t, True),
        0xEF66: ("fading_time", t.uint32_t, True),
        0xEF67: ("cli", t.CharacterString, True),
        0xEF68: ("illuminance", t.uint32_t, True),
    }
)

class TuyaMmwRadarClusterVariant1(TuyaMmwRadarClusterBase): """Mmw radar cluster, variant 1."""

dp_to_attribute: Dict[int, DPToAttributeMapping] = {
    1: DPToAttributeMapping(
        TuyaOccupancySensing.ep_attribute,
        "occupancy",
    ),
    2: DPToAttributeMapping(
        TuyaMmwRadarSensitivity.ep_attribute,
        "present_value",
    ),
    3: DPToAttributeMapping(
        TuyaMmwRadarMinRange.ep_attribute,
        "present_value",
        endpoint_id=2,
    ),
    4: DPToAttributeMapping(
        TuyaMmwRadarMaxRange.ep_attribute,
        "present_value",
        endpoint_id=3,
    ),
    6: DPToAttributeMapping(
        TuyaMCUCluster.ep_attribute,
        "self_test",
    ),
    9: DPToAttributeMapping(
        TuyaMmwRadarTargetDistance.ep_attribute,
        "present_value",
        lambda x: x / 100,
    ),
    101: DPToAttributeMapping(
        TuyaMmwRadarDetectionDelay.ep_attribute,
        "present_value",
        converter=lambda x: x * 100,
        dp_converter=lambda x: x // 100,
        endpoint_id=4,
    ),
    102: DPToAttributeMapping(
        TuyaMmwRadarFadingTime.ep_attribute,
        "present_value",
        converter=lambda x: x * 100,
        dp_converter=lambda x: x // 100,
        endpoint_id=5,
    ),
    103: DPToAttributeMapping(
        TuyaMCUCluster.ep_attribute,
        "cli",
    ),
    104: DPToAttributeMapping(
        TuyaIlluminanceMeasurement.ep_attribute,
        "measured_value",
        converter=lambda x: int(math.log10(x) * 10000 + 1) if x > 0 else int(0),
    ),
}

data_point_handlers = {
    1: "_dp_2_attr_update",
    2: "_dp_2_attr_update",
    3: "_dp_2_attr_update",
    4: "_dp_2_attr_update",
    6: "_dp_2_attr_update",
    9: "_dp_2_attr_update",
    101: "_dp_2_attr_update",
    102: "_dp_2_attr_update",
    103: "_dp_2_attr_update",
    104: "_dp_2_attr_update",
}

class TuyaMmwRadarOccupancyVariant1(CustomDevice): """Millimeter wave occupancy sensor, variant 1."""

signature = {
    #  endpoint=1, profile=260, device_type=81, device_version=1,
    #  input_clusters=[0, 4, 5, 61184], output_clusters=[25, 10]
    MODELS_INFO: [
        ("_TZE200_ar0slwnd", "TS0601"),
        ("_TZE200_sfiy5tfs", "TS0601"),
        ("_TZE200_mrf6vtua", "TS0601"),
        ("_TZE200_ztc6ggyl", "TS0601"),
        ("_TZE204_ztc6ggyl", "TS0601"),
        ("_TZE200_wukb7rhc", "TS0601"),
        ("_TZE204_qasjif9e", "TS0601"),
        ("_TZE204_dtzziy1e", "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,
                TuyaNewManufCluster.cluster_id,
            ],
            OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
        },
    },
}

replacement = {
    ENDPOINTS: {
        1: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.OCCUPANCY_SENSOR,
            INPUT_CLUSTERS: [
                Basic.cluster_id,
                Groups.cluster_id,
                Scenes.cluster_id,
                TuyaMmwRadarClusterVariant1,
                TuyaIlluminanceMeasurement,
                TuyaOccupancySensing,
                TuyaMmwRadarTargetDistance,
                TuyaMmwRadarSensitivity,
            ],
            OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
        },
        2: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarMinRange,
            ],
            OUTPUT_CLUSTERS: [],
        },
        3: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarMaxRange,
            ],
            OUTPUT_CLUSTERS: [],
        },
        4: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarDetectionDelay,
            ],
            OUTPUT_CLUSTERS: [],
        },
        5: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarFadingTime,
            ],
            OUTPUT_CLUSTERS: [],
        },
    }
}

class TuyaMmwRadarOccupancyVariant1GPP(CustomDevice): """Millimeter wave occupancy sensor, variant 1 with GPP."""

signature = {
    #  endpoint=1, profile=260, device_type=81, device_version=1,
    #  input_clusters=[0, 4, 5, 61184], output_clusters=[25, 10])
    MODELS_INFO: [
        ("_TZE200_ar0slwnd", "TS0601"),
        ("_TZE200_sfiy5tfs", "TS0601"),
        ("_TZE200_mrf6vtua", "TS0601"),
        ("_TZE204_qasjif9e", "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,
                TuyaNewManufCluster.cluster_id,
            ],
            OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
        },
        242: {
            # <SimpleDescriptor endpoint=242 profile=41440 device_type=97
            # input_clusters=[]
            # output_clusters=[33]
            PROFILE_ID: zgp.PROFILE_ID,
            DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
            INPUT_CLUSTERS: [],
            OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
        },
    },
}

replacement = {
    ENDPOINTS: {
        1: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.OCCUPANCY_SENSOR,
            INPUT_CLUSTERS: [
                Basic.cluster_id,
                Groups.cluster_id,
                Scenes.cluster_id,
                TuyaMmwRadarClusterVariant1,
                TuyaIlluminanceMeasurement,
                TuyaOccupancySensing,
                TuyaMmwRadarTargetDistance,
                TuyaMmwRadarSensitivity,
            ],
            OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
        },
        2: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarMinRange,
            ],
            OUTPUT_CLUSTERS: [],
        },
        3: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarMaxRange,
            ],
            OUTPUT_CLUSTERS: [],
        },
        4: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarDetectionDelay,
            ],
            OUTPUT_CLUSTERS: [],
        },
        5: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarFadingTime,
            ],
            OUTPUT_CLUSTERS: [],
        },
        242: {
            PROFILE_ID: zgp.PROFILE_ID,
            DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
            INPUT_CLUSTERS: [],
            OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
        },
    }
}

class TuyaMmwRadarClusterVariant2(TuyaMmwRadarClusterBase): """Tuya MMW radar cluster, variant 2."""

dp_to_attribute: Dict[int, DPToAttributeMapping] = {
    103: DPToAttributeMapping(
        TuyaMCUCluster.ep_attribute,
        "cli",
    ),
    104: DPToAttributeMapping(
        TuyaIlluminanceMeasurement.ep_attribute,
        "measured_value",
        converter=lambda x: int(math.log10(x) * 10000 + 1) if x > 0 else int(0),
    ),
    105: DPToAttributeMapping(
        TuyaOccupancySensing.ep_attribute,
        "occupancy",
    ),
    106: DPToAttributeMapping(
        TuyaMmwRadarSensitivity.ep_attribute,
        "present_value",
    ),
    107: DPToAttributeMapping(
        TuyaMmwRadarMaxRange.ep_attribute,
        "present_value",
        endpoint_id=3,
    ),
    108: DPToAttributeMapping(
        TuyaMmwRadarMinRange.ep_attribute,
        "present_value",
        endpoint_id=2,
    ),
    109: DPToAttributeMapping(
        TuyaMmwRadarTargetDistance.ep_attribute,
        "present_value",
    ),
    110: DPToAttributeMapping(
        TuyaMmwRadarFadingTime.ep_attribute,
        "present_value",
        converter=lambda x: x * 100,
        dp_converter=lambda x: x // 100,
        endpoint_id=5,
    ),
    111: DPToAttributeMapping(
        TuyaMmwRadarDetectionDelay.ep_attribute,
        "present_value",
        converter=lambda x: x * 100,
        dp_converter=lambda x: x // 100,
        endpoint_id=4,
    ),
}

data_point_handlers = {
    103: "_dp_2_attr_update",
    104: "_dp_2_attr_update",
    105: "_dp_2_attr_update",
    106: "_dp_2_attr_update",
    107: "_dp_2_attr_update",
    108: "_dp_2_attr_update",
    109: "_dp_2_attr_update",
    110: "_dp_2_attr_update",
    111: "_dp_2_attr_update",
}

class TuyaMmwRadarOccupancyVariant2(CustomDevice): """Millimeter wave occupancy sensor, variant 2."""

signature = {
    #  endpoint=1, profile=260, device_type=81, device_version=1,
    #  input_clusters=[0, 4, 5, 61184], output_clusters=[25, 10])
    MODELS_INFO: [
        ("_TZE204_sxm7l9xa", "TS0601"),
        ("_TZE204_bmdsp6bs", "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,
                TuyaNewManufCluster.cluster_id,
            ],
            OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
        },
        242: {
            # <SimpleDescriptor endpoint=242 profile=41440 device_type=97
            # input_clusters=[]
            # output_clusters=[33]
            PROFILE_ID: zgp.PROFILE_ID,
            DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
            INPUT_CLUSTERS: [],
            OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
        },
    },
}

replacement = {
    ENDPOINTS: {
        1: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.OCCUPANCY_SENSOR,
            INPUT_CLUSTERS: [
                Basic.cluster_id,
                Groups.cluster_id,
                Scenes.cluster_id,
                TuyaMmwRadarClusterVariant2,
                TuyaIlluminanceMeasurement,
                TuyaOccupancySensing,
                TuyaMmwRadarTargetDistance,
                TuyaMmwRadarSensitivity,
            ],
            OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
        },
        2: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarMinRange,
            ],
            OUTPUT_CLUSTERS: [],
        },
        3: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarMaxRange,
            ],
            OUTPUT_CLUSTERS: [],
        },
        4: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarDetectionDelay,
            ],
            OUTPUT_CLUSTERS: [],
        },
        5: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarFadingTime,
            ],
            OUTPUT_CLUSTERS: [],
        },
        242: {
            PROFILE_ID: zgp.PROFILE_ID,
            DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
            INPUT_CLUSTERS: [],
            OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
        },
    }
}
nnae06 commented 3 months ago

Skärmbild från 2024-08-13 20-04-38

matsjrosenberg commented 3 months ago

Thank you for this @nnae06 . Tried to copy paste this into a new customised quirk, and then reinstalled the device. It still insists on picking up the original zhaquirks.tuya.ts0601_motion.MmwRadarMotionGPP instead of the customised one. Can anybody help explaining how I make the custom quirk override the default one? Any specific file naming convention to be followed? The hardware specs correspond to what is in the customised quirk so this should not be the issue. And all my other customised device quirks work well.

nnae06 commented 3 months ago

I will post a finished file later in the day. Maybe can help.

nnae06 commented 3 months ago

ts0601_radar.py.zip

matsjrosenberg commented 3 months ago

ts0601_radar.zip Added support for TS0601 by _TZE204_sbyx0lm6. Occupancy and Lux but no relay.

macf0x commented 2 months ago

Attempted to update latest quirk with the full DP's from zigbee2mqtt herdsmen (link)

More experimenting is required as I don't fully understand quirks, but posting this as it might help someone else.

 tuyaDatapoints: [
                [1, 'presence', tuya.valueConverter.trueFalse1],
                [2, 'radar_sensitivity', tuya.valueConverter.raw],
                [3, 'shield_range', tuya.valueConverter.divideBy100],
                [4, 'detection_range', tuya.valueConverter.divideBy100],
                [6, 'equipment_status', tuya.valueConverter.raw],
                [9, 'target_distance', tuya.valueConverter.divideBy100],
                [101, 'entry_filter_time', tuya.valueConverter.divideBy10],
                [102, 'departure_delay', tuya.valueConverter.raw],
                [103, 'cline', tuya.valueConverter.raw],
                [104, 'illuminance_lux', tuya.valueConverter.divideBy10],
                [105, 'entry_sensitivity', tuya.valueConverter.raw],
                [106, 'entry_distance_indentation', tuya.valueConverter.divideBy100],
                [107, 'breaker_mode', tuya.valueConverterBasic.lookup({'standard': tuya.enum(0), 'local': tuya.enum(1)})],
                [108, 'breaker_status', tuya.valueConverterBasic.lookup({'OFF': tuya.enum(0), 'ON': tuya.enum(1)})],
                [109, 'status_indication', tuya.valueConverterBasic.lookup({'OFF': tuya.enum(0), 'ON': tuya.enum(1)})],
                [110, 'illuminance_threshold', tuya.valueConverter.divideBy10],
                [111, 'breaker_polarity', tuya.valueConverterBasic.lookup({'NC': tuya.enum(0), 'NO': tuya.enum(1)})],
                [112, 'block_time', tuya.valueConverter.divideBy10],
                [113, 'parameter_setting_result', tuya.valueConverter.raw],
                [114, 'factory_parameters', tuya.valueConverter.raw],
                [115, 'sensor', tuya.valueConverterBasic.lookup({
                    'on': tuya.enum(0), 'off': tuya.enum(1), 'occupied': tuya.enum(2), 'unoccupied': tuya.enum(3)})],
                [116, 'distance_report', tuya.valueConverterBasic.lookup({
                    'off': tuya.enum(0), 
                    'on': tuya.enum(1)

ts0601_radar_new.py.txt

dala318 commented 1 month ago

ts0601_radar_new.py.txt

Thanks a lot! Could you please add a TS0601 "_TZE204_iaeejhvf" to TuyaMmwRadarOccupancyVariant1GPP. I have added it locally and it show up as I would think it is supposed to by the quirk. image

Looking forward to see if the breaker part of device can get solved as well. zha-10bd056a4de4cbece683ed97f85638a7-_TZE204_iaeejhvf TS0601-dac28b9c161b2bebc10f7ebf01608fb2.json

dala318 commented 1 month ago

One more improvement suggestion (I would love to contribute more actively but have yet not passed the threshold of understanding the quirks and how to debug/try/error/improve).

Currently the number-sliders for the device settings show up as "Controls" in the device in Home Assistant, I think they would be better placed under "Configuration". The small benefit that I see of that is that they would then not show up in the default dashboard in Home Assistant. (You likely don't want to change those on a daily basis).

Yes, I can make them hidden to achieve the same so no major issue, but just a proposal :-)