Open Manx-Nostromo opened 1 year ago
Your quirk signature doesn't match with yours device's one. It lacks the GPP endpoint.
Maybe the MmwRadarMotionGPP
would match yours device signature:
https://github.com/zigpy/zha-device-handlers/blob/e9099ed26eb129e960934965cf5f0b1273b38e4f/zhaquirks/tuya/ts0601_motion.py#L391C7-L391C24
Or maybe you just could add the GPP endpoint in the signature and in the replacement part. It would depend on the device capabilities.
@javicalle I have also tried the option you have suggested, but still doesn't see the quirk.
I am very new to this and have no python experience, could you please help? Screen shots show my current setup. Do I need to be adding more than just the product ID to the quirk file?
Replace your ts0601_motion.py
with the current version from:
https://github.com/zigpy/zha-device-handlers/blob/dev/zhaquirks/tuya/ts0601_motion.py
(Make a backup if you have any other local quirk from this file!!!!)
Search for the MmwRadarMotionGPP
class and add there your device. It would be something like:
class MmwRadarMotionGPP(CustomDevice):
"""Millimeter wave occupancy sensor."""
signature = {
# endpoint=1, profile=260, device_type=81, device_version=1,
# input_clusters=[4, 5, 61184, 0], output_clusters=[25, 10])
MODELS_INFO: [
("_TZE200_ar0slwnd", "TS0601"),
("_TZE200_sfiy5tfs", "TS0601"),
("_TZE200_mrf6vtua", "TS0601"),
("_TZE204_sxm7l9xa", "TS0601"),
],
.../...
Save changes, restart HA and pair the device again.
Thanks, I'll give this a try.
The Presence senors are now recognised, two elements are also available, Presence and luminance. Which is a big step forward. Only problem is they aren't sensing any movement, oh well back to a PIR sensor.
they aren't sensing any movement
This is ts0601_motion.py I used for my _TZE204_sxm7l9xa and it's sensing 'presence' just fine:
I'm not sure of any differences to the one that @javicalle linked above - there seems to be a LOT of variations on ts0601_motion.py, but the one I've posted the link for works & even exposes some config sliders (although I'm not sure they actually work as they just 'reset' to defaults if you try changing them).
@smithbill17 Thanks, will give that quirk a try, althouth it looks to be the same as the previous link, yours has around another 200 lines so hoping this will work.
@smithbill17 Thank you that has worked, had to do a reboot of HA for Lux to appear. But all good. Not quite sure how both links appear to go to the same repo but are different?
@Manx-Nostromo none of the quirks seem to work, could you please list the exact steps taken that worked, did you remove/repair the device, restart or reboot HA, etc?
I think you'll find the link I posted above works, although there are a few issues with some of the additional features.
My mistake, I have the device _TZE204_ztc6ggyl
for which the custom quirk appears to be here: https://github.com/zigpy/zha-device-handlers/issues/1645
I don't think you need a custom quirk for _TZE204_ztc6ggyl it works 'right out of the box'.
It's _TZE204_sxm7l9xa that needs the custom quirk.
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.
If anyone got all functions working (occupation, illuminance, configs), could you please create a PR so we can get it merged to main? That could also help track what needs to be added to the main even if something have changed.
Problem description
Presence sensor always shows up as a router with no parameters, even when adding to a custom quirk.
Solution description
I have had these working easily in Hubitat, They are very good, would like to be able to easily add them into HA.
Screenshots/Video
Screenshots/Video
[Paste/upload your media here]Device signature
Device signature
```json { "node_descriptor": "NodeDescriptor(logical_type=Diagnostic information
Diagnostic information
```json { "home_assistant": { "installation_type": "Home Assistant OS", "version": "2023.8.4", "dev": false, "hassio": true, "virtualenv": false, "python_version": "3.11.4", "docker": true, "arch": "aarch64", "timezone": "Europe/London", "os_name": "Linux", "os_version": "6.1.21-v8", "supervisor": "2023.08.1", "host_os": "Home Assistant OS 10.5", "docker_version": "23.0.6", "chassis": "embedded", "run_as_root": true }, "custom_components": { "localtuya": { "version": "5.2.1", "requirements": [] }, "xiaomi_gateway3": { "version": "3.3.2", "requirements": [ "zigpy>=0.44.1" ] }, "hacs": { "version": "1.32.1", "requirements": [ "aiogithubapi>=22.10.1" ] }, "tuya_local": { "version": "2023.8.2", "requirements": [ "pycryptodome~=3.18", "tinytuya==1.12.10" ] }, "fusion_solar": { "version": "2.6.0", "requirements": [] }, "adaptive_lighting": { "version": "1.19.0", "requirements": [ "ulid-transform" ] }, "solarman": { "version": "1.0.0", "requirements": [ "pyyaml" ] }, "openweathermap_all": { "version": "0.0.1", "requirements": [ "owm2json==0.1.89" ] }, "truenas": { "version": "0.0.0", "requirements": [] }, "entity_controller": { "version": "9.6.1", "requirements": [ "transitions==0.8.8" ] }, "rct_power": { "version": "0.10.0", "requirements": [ "rctclient==0.0.3" ] } }, "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.9", "pyserial==3.5", "pyserial-asyncio==0.6", "zha-quirks==0.0.102", "zigpy-deconz==0.21.0", "zigpy==0.56.4", "zigpy-xbee==0.18.1", "zigpy-zigate==0.11.0", "zigpy-znp==0.11.4" ], "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": 28996, "manufacturer": "_TZE204_sxm7l9xa", "model": "TS0601", "name": "_TZE204_sxm7l9xa TS0601", "quirk_applied": false, "quirk_class": "zigpy.device.Device", "manufacturer_code": 4417, "power_source": "Mains", "lqi": 148, "rssi": -63, "last_seen": "2023-08-26T10:26:41", "available": true, "device_type": "Router", "signature": { "node_descriptor": "NodeDescriptor(logical_type=Logs
Logs
```python [Paste the logs here] ```Custom quirk
Custom quirk
```python """Tuya mmw radar occupancy sensor.""" import math from typing import Dict from zigpy.profiles import zha from zigpy.quirks import CustomDevice import zigpy.types as t from zigpy.zcl.clusters.general import ( AnalogInput, AnalogOutput, Basic, Groups, Ota, Scenes, Time, ) from zigpy.zcl.clusters.measurement import IlluminanceMeasurement, OccupancySensing from zhaquirks.const import ( DEVICE_TYPE, ENDPOINTS, INPUT_CLUSTERS, OUTPUT_CLUSTERS, PROFILE_ID, ) from zhaquirks.tuya import NoManufacturerCluster, TuyaLocalCluster, TuyaNewManufCluster from zhaquirks.tuya.mcu import ( DPToAttributeMapping, TuyaAttributesCluster, TuyaMCUCluster, ) 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 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, 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 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, 100) 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, 1000) 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 TuyaMmwRadarCluster(NoManufacturerCluster, TuyaMCUCluster): """Mmw radar cluster.""" 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), } ) 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, # converter=lambda x: x / 100, # dp_converter=lambda x: x * 100, ), 4: DPToAttributeMapping( TuyaMmwRadarMaxRange.ep_attribute, "present_value", endpoint_id=3, # converter=lambda x: x / 100, # dp_converter=lambda x: x * 100, ), 6: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "self_test", ), 9: DPToAttributeMapping( TuyaMmwRadarTargetDistance.ep_attribute, "present_value", # converter=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: math.log10(x) * 10000 + 1, ), } 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 TuyaMmwRadarOccupancy(CustomDevice): """Millimeter wave occupancy sensor.""" 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_ikvncluo", "TS0601"), ("_TZE204_sxm719xa", "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, TuyaMmwRadarCluster, 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: [], }, } } ```Additional information
No response