-
-
Save vinzent/2cd645b848fd3b6a0c3e5762956ec89f to your computer and use it in GitHub Desktop.
""" | |
* TS0601 ZG-204ZM | |
* _TZE200_kb5noeto | |
* Works with HA 2024.11 - updated by @txip (Update 2) | |
* https://de.aliexpress.com/item/1005006174074799.html ("Color": Mmwave PIR) | |
* https://github.com/13717033460/zigbee-herdsman-converters/blob/6c9cf1b0de836ec2172d569568d3c7fe75268958/src/devices/tuya.ts#L5730-L5762 | |
* https://www.zigbee2mqtt.io/devices/ZG-204ZM.html | |
* https://smarthomescene.com/reviews/zigbee-battery-powered-presence-sensor-zg-204zm-review/ | |
* https://doc.szalarm.com/zg-205ZL/cntop_zigbee_sensor.js | |
* https://github.com/Koenkk/zigbee2mqtt/issues/21919 | |
""" | |
import logging | |
from typing import Final | |
from zigpy.quirks.v2 import QuirkBuilder | |
import zigpy.types as t | |
from zigpy.zcl.foundation import ZCLAttributeDef | |
from zigpy.zcl.clusters.measurement import ( | |
IlluminanceMeasurement, | |
OccupancySensing, | |
) | |
from zigpy.zcl.clusters.security import IasZone | |
from zigpy.quirks.v2.homeassistant import EntityPlatform, EntityType | |
from zhaquirks.tuya import ( | |
TuyaLocalCluster, | |
TuyaPowerConfigurationCluster2AAA, | |
) | |
from zhaquirks.tuya.mcu import TuyaMCUCluster, DPToAttributeMapping | |
class HumanMotionState(t.enum8): | |
"""Human Motion State values""" | |
none = 0x00 | |
large_move = 0x01 | |
small_move = 0x02 | |
breathe = 0x03 | |
class MotionDetectionMode(t.enum8): | |
"""Motion detection mode values""" | |
Only_PIR = 0x00 | |
PIR_radar = 0x01 | |
Only_radar = 0x02 | |
@staticmethod | |
def converter(value): | |
"""" If value is None, Only_PIR should be returned """ | |
if value is None: | |
return MotionDetectionMode.Only_PIR | |
return value | |
class TuyaOccupancySensing(OccupancySensing, TuyaLocalCluster): | |
"""Tuya local OccupancySensing cluster.""" | |
class TuyaIlluminanceMeasurement(IlluminanceMeasurement, TuyaLocalCluster): | |
"""Tuya local IlluminanceMeasurement cluster.""" | |
class HumanPresenceSensorManufCluster(TuyaMCUCluster): | |
"""Human Presence Sensor ZG-204ZM (PIR+mmWave, battery)""" | |
# Tuya Data points | |
# "1":"Human Presence State", (presence_state, Enum, none|presence) | |
# "2":"Stationary detection sensitivity", (sensitivity, Integer, 0-10, unit=x, step=1) | |
# "3":"Minimum detection distance", (near_detection, Integer, 0-1000, unit=cm, step=1) (NOT AVAILABLE IN TUYA SMART LIFE APP) | |
# "4":"Stationary detection distance", (far_detection, Integer, 0-1000, unit=cm, step=1) | |
# "101":"Human Motion State", (human_motion_state, Enum, none|large_move|small_move|breathe) | |
# "102":"Presence Keep Time", (presence_time, 10-28800, unit=s, step=1) | |
# "106":"Illuminance Value", (illuminance_value, Integer, 0-6000, unit=lux ) | |
# "107":"Indicator", (indicator, Boolean) | |
# "112":"Reset setting", (reset_setting, Boolean) | |
# "121":"Battery", (battery, Integer, -1-100, step=1, unit=%) | |
# "122":"Motion detection ", (motion_detection_mode, Enum, Only_PIR|PIR_radar|Only_radar) (NOT AVAILABLE IN TUYA SMART LIFE APP) | |
# "123":"Motion detection sensitivity", (motion_detection_sen, Integer, 0-10, step=1, unit=x) (NOT AVAILABLE IN TUYA SMART LIFE APP) | |
# "124":"ver" (ver, Integer, 0-100, step=1) (NOT AVAILABLE IN TUYA SMART LIFE APP) | |
class AttributeDefs(TuyaMCUCluster.AttributeDefs): | |
"""Tuya DataPoints attributes""" | |
# Human presence state (mapped to the OccupancySensing cluster) | |
#presence_state: Final = ZCLAttributeDef( | |
# id=0xEF01, # DP 1 | |
# type=Occupancy, | |
# access="rp", | |
# is_manufacturer_specific=True, | |
#) | |
# Stationary detection sensitivity | |
sensitivity: Final = ZCLAttributeDef( | |
id=0x0002, # DP 2 | |
type=t.uint16_t, | |
is_manufacturer_specific=True, | |
) | |
# Minimum detection distance | |
near_detection: Final = ZCLAttributeDef( | |
id=0x0003, # DP 3 | |
type=t.uint16_t, | |
is_manufacturer_specific=True, | |
) | |
# Stationary detection distance | |
far_detection: Final = ZCLAttributeDef( | |
id=0x0004, # DP 4 | |
type=t.uint16_t, | |
is_manufacturer_specific=True, | |
) | |
# Human motion state | |
human_motion_state: Final = ZCLAttributeDef( | |
id=0x0101, # DP 101 | |
type=HumanMotionState, | |
access="rp", | |
is_manufacturer_specific=True, | |
) | |
# Presence keep time | |
presence_time: Final = ZCLAttributeDef( | |
id=0x0102, # DP 102 | |
type=t.uint16_t, | |
is_manufacturer_specific=True, | |
) | |
# Illuminance value | |
illuminance_value: Final = ZCLAttributeDef( | |
id=0x0106, # DP 106 | |
type=t.uint16_t, | |
access="rp", | |
is_manufacturer_specific=True, | |
) | |
# Indicator | |
indicator: Final = ZCLAttributeDef( | |
id=0x0107, # DP 107 | |
type=t.Bool, | |
is_manufacturer_specific=True, | |
) | |
# Reset setting | |
reset_setting: Final = ZCLAttributeDef( | |
id=0x0112, # DP 112 | |
type=t.Bool, | |
is_manufacturer_specific=True, | |
) | |
# Battery (also provided by the TuyaPowerConfigurationCluster2AAA) | |
battery: Final = ZCLAttributeDef( | |
id=0x0121, # DP 121 | |
type=t.int16s, | |
is_manufacturer_specific=True, | |
) | |
# Motion detection | |
motion_detection_mode: Final = ZCLAttributeDef( | |
id=0x0122, # DP 122 | |
type=MotionDetectionMode, | |
is_manufacturer_specific=True, | |
) | |
# Motion detection sensitivity | |
motion_detection_sen: Final = ZCLAttributeDef( | |
id=0x0123, # DP 123 | |
type=t.uint16_t, | |
is_manufacturer_specific=True, | |
) | |
# ver | |
ver: Final = ZCLAttributeDef( | |
id=0x0124, # DP 124 | |
type=t.uint16_t, | |
is_manufacturer_specific=True, | |
) | |
dp_to_attribute: dict[int, DPToAttributeMapping] = { | |
1: DPToAttributeMapping( | |
TuyaOccupancySensing.ep_attribute, | |
"occupancy", | |
), | |
2: DPToAttributeMapping( | |
TuyaMCUCluster.ep_attribute, | |
"sensitivity", | |
# Value in Tuya App after Factory reset is 6 | |
converter=lambda x: x if x is not None else 6 | |
), | |
3: DPToAttributeMapping( | |
TuyaMCUCluster.ep_attribute, | |
"near_detection", | |
# Guessing a default of 0 | |
converter=lambda x: x if x is not None else 0 | |
), | |
4: DPToAttributeMapping( | |
TuyaMCUCluster.ep_attribute, | |
"far_detection", | |
# Value in Tuya App after Factory reset is 600cm | |
converter=lambda x: x if x is not None else 600 | |
), | |
101: DPToAttributeMapping( | |
TuyaMCUCluster.ep_attribute, | |
"human_motion_state", | |
converter=HumanMotionState | |
), | |
102: DPToAttributeMapping( | |
TuyaMCUCluster.ep_attribute, | |
"presence_time", | |
# Value in Tuya App is 30 after Factory reset | |
converter=lambda x: x if x is not None else 30 | |
), | |
106: DPToAttributeMapping( | |
TuyaMCUCluster.ep_attribute, | |
"illuminance_value", | |
), | |
107: DPToAttributeMapping( | |
TuyaMCUCluster.ep_attribute, | |
"indicator", | |
), | |
112: DPToAttributeMapping( | |
TuyaMCUCluster.ep_attribute, | |
"reset_setting", | |
), | |
121: DPToAttributeMapping( | |
TuyaMCUCluster.ep_attribute, | |
"battery", | |
), | |
122: DPToAttributeMapping( | |
TuyaMCUCluster.ep_attribute, | |
"motion_detection_mode", | |
converter=MotionDetectionMode, | |
), | |
123: DPToAttributeMapping( | |
TuyaMCUCluster.ep_attribute, | |
"motion_detection_sen", | |
# Guessing a default of 10 | |
converter=lambda x: x if x is not None else 10 | |
), | |
124: DPToAttributeMapping( | |
TuyaMCUCluster.ep_attribute, | |
"ver", | |
), | |
} | |
data_point_handlers = { | |
1: "_dp_2_attr_update", | |
2: "_dp_2_attr_update", | |
3: "_dp_2_attr_update", | |
4: "_dp_2_attr_update", | |
101: "_dp_2_attr_update", | |
102: "_dp_2_attr_update", | |
106: "_dp_2_attr_update", | |
107: "_dp_2_attr_update", | |
112: "_dp_2_attr_update", | |
121: "_dp_2_attr_update", | |
122: "_dp_2_attr_update", | |
123: "_dp_2_attr_update", | |
124: "_dp_2_attr_update", | |
} | |
( | |
QuirkBuilder("_TZE200_kb5noeto", "TS0601") | |
.skip_configuration() | |
.removes(IasZone.cluster_id) | |
.adds(HumanPresenceSensorManufCluster) | |
.adds(TuyaOccupancySensing) | |
.replaces(TuyaPowerConfigurationCluster2AAA) | |
.replaces(TuyaIlluminanceMeasurement) | |
.number( | |
HumanPresenceSensorManufCluster.AttributeDefs.sensitivity.name, | |
HumanPresenceSensorManufCluster.cluster_id, | |
step=1, | |
min_value=1, | |
max_value=10, | |
fallback_name="Sensitivity", | |
translation_key="sensitivity" | |
) | |
.number( | |
HumanPresenceSensorManufCluster.AttributeDefs.near_detection.name, | |
HumanPresenceSensorManufCluster.cluster_id, | |
step=1, | |
min_value=0, | |
max_value=1000, | |
fallback_name="Near Detection", | |
translation_key="near_detection" | |
) | |
.number( | |
HumanPresenceSensorManufCluster.AttributeDefs.far_detection.name, | |
HumanPresenceSensorManufCluster.cluster_id, | |
step=1, | |
min_value=0, | |
max_value=1000, | |
fallback_name="Far Detection", | |
translation_key="far_detection" | |
) | |
.enum( | |
HumanPresenceSensorManufCluster.AttributeDefs.human_motion_state.name, | |
HumanMotionState, | |
HumanPresenceSensorManufCluster.cluster_id, | |
entity_platform=EntityPlatform.SENSOR, | |
entity_type=EntityType.STANDARD, | |
fallback_name="Human Motion State", | |
translation_key="human_motion_state" | |
) | |
.number( | |
HumanPresenceSensorManufCluster.AttributeDefs.presence_time.name, | |
HumanPresenceSensorManufCluster.cluster_id, | |
step=1, | |
min_value=10, | |
max_value=28800, | |
fallback_name="Presence Time", | |
translation_key="presence_time" | |
) | |
.switch( | |
HumanPresenceSensorManufCluster.AttributeDefs.indicator.name, | |
HumanPresenceSensorManufCluster.cluster_id, | |
fallback_name="Indicator", | |
translation_key="indicator" | |
) | |
# .binary_sensor( | |
# HumanPresenceSensorManufCluster.AttributeDefs.reset_setting.name, | |
# HumanPresenceSensorManufCluster.cluster_id | |
# ) | |
.enum( | |
HumanPresenceSensorManufCluster.AttributeDefs.motion_detection_mode.name, | |
MotionDetectionMode, | |
HumanPresenceSensorManufCluster.cluster_id, | |
fallback_name="Motion Detection Mode", | |
translation_key="motion_detection_mode" | |
) | |
.number( | |
HumanPresenceSensorManufCluster.AttributeDefs.motion_detection_sen.name, | |
HumanPresenceSensorManufCluster.cluster_id, | |
step=1, | |
min_value=0, | |
max_value=10, | |
fallback_name="Motion Detection Sensitivity", | |
translation_key="motion_detection_sen" | |
) | |
# .number( | |
# HumanPresenceSensorManufCluster.AttributeDefs.ver.name, | |
# HumanPresenceSensorManufCluster.cluster_id, | |
# step=1, | |
# min_value=0, | |
# max_value=10 | |
# ) | |
.add_to_registry() | |
) |
Rev 7:
- removed the datapoint entities that did not work out of the box
- import DPToAttributeMapping from zhaquirks.tuya.mcu instead of the probably wrong zhaquirks.tuya.
- Sensor None is the
human_motion_state
datapoint - Config first is
sensitivity
, 2ndfar_detection
, 3rdpresence_time
Filed and issue about the ZHA integration reload issue: zigpy/zigpy#1410
But the device itself is quite unreliable unfortunately (last night it stayed on presence the whole night) so it may have something to do with the unreliable cluster operation. I have another such sensor, I set it up and will be monitoring it (with my old quirk for now).
I have the same behaviour it would work "fine" changing state between "Large_move" , "breathe" and "none" couple of time that then just gets stuck on "breathe" until I remove the batteries. Not sure if it is a hardware problem, read on other posts, resoldering pins on the pcb improved reliability
See here -> Koenkk/zigbee2mqtt#21919 (comment)
But the device itself is quite unreliable unfortunately (last night it stayed on presence the whole night) so it may have something to do with the unreliable cluster operation. I have another such sensor, I set it up and will be monitoring it (with my old quirk for now).
I have the same behaviour it would work "fine" changing state between "Large_move" , "breathe" and "none" couple of time that then just gets stuck on "breathe" until I remove the batteries. Not sure if it is a hardware problem, read on other posts, resoldering pins on the pcb improved reliability
See here -> Koenkk/zigbee2mqtt#21919 (comment)
I actually only cleaned those. It was difficult to desolder from the battery terminals so I didn't bother with my second unit.
Also for mine I only need to press the pairing button to reset the device. Last time it lasted more than a week. If it becomes too bothersome I will probably give it some more soldering time.
After updating to Homeassistant 2024.08.0 they quirk stopped working for me and I got this error in my logs
add_to_registry_v2 is deprecated and will be removed in a future release. Please QuirkBuilder() instead and ensure you call add_to_registry().
I could fix it by replacing that add_to_registry_v2
call to the QuirkBulder
constructor and appending .add_to_registry()
as the last function called on the bulder.
Or as a patch:
diff --git a/zg-204zm.py b/zg-204zm.py
index db78705..dc21156 100644
--- a/zg-204zm.py
+++ b/zg-204zm.py
@@ -12,7 +12,7 @@
import logging
from typing import Final
-from zigpy.quirks.v2 import add_to_registry_v2
+from zigpy.quirks.v2 import QuirkBuilder
import zigpy.types as t
from zigpy.zcl.foundation import ZCLAttributeDef
@@ -247,7 +247,7 @@ class HumanPresenceSensorManufCluster(TuyaMCUCluster):
}
(
- add_to_registry_v2("_TZE200_kb5noeto", "TS0601")
+ QuirkBuilder("_TZE200_kb5noeto", "TS0601")
.skip_configuration()
.removes(IasZone.cluster_id)
.adds(HumanPresenceSensorManufCluster)
@@ -264,4 +264,5 @@ class HumanPresenceSensorManufCluster(TuyaMCUCluster):
#.enum(HumanPresenceSensorManufCluster.AttributeDefs.motion_detection_mode.name,MotionDetectionMode,HumanPresenceSensorManufCluster.cluster_id)
#.number(HumanPresenceSensorManufCluster.AttributeDefs.motion_detection_sen.name, HumanPresenceSensorManufCluster.cluster_id,step=1,min_value=0,max_value=10)
#.number(HumanPresenceSensorManufCluster.AttributeDefs.ver.name, HumanPresenceSensorManufCluster.cluster_id,step=1,min_value=0,max_value=10)
-)
\ No newline at end of file
+ .add_to_registry()
+)
Also sorry for the double notifications, accidentally left this comment on the wrong gist first
After updating to Homeassistant 2024.08.0 they quirk stopped working for me and I got this error in my logs
add_to_registry_v2 is deprecated and will be removed in a future release. Please QuirkBuilder() instead and ensure you call add_to_registry().
Thanks, @frod0r. This fixed it for me too!
Filed and issue about the ZHA integration reload issue: zigpy/zigpy#1410
Hi, just would like to double check: Is this issue still open?
zigpy/zigpy#1410 (comment)
I haven't found the merge into main branch yet. I'm running on HA 2024.8.3 and if i use this wonderful custom quirk v2 for this mmWave+PiR Sensor, which is absolutely working well (thanks a lot to @vinzent and @frod0r for the 2024.8.x fix), i get still that ZHA Failures on ZHA reloads or ZG restarts.
So I added the quirk, can add the device and also seeing the different options and sensors in the preview. But directly after that all switching to grey/ not available.
What could be the problem here and how to solve it? It can detect the device, add it and then after adding directly loosing it? The device led stays on all time or does never stop blinking until I remove the batteries and start again.
Using Home Assistant 2024.9.0
I've installed quirk v7 (latest) and HA 2024.9.1. I've restarted HA and the sensor a few times, but I never can get it to show anything else on Occupancy: Detected. And the 'none' sensor is either small_move or large_move. Can never get anything else. Anyone else having this issue?
I know this is not very helpful, but I had the same problem, it would get stuck on "Occupancy: Detected" for hours / days until I removed the batteries, would work again maybe for a day and then the same would happen. I gave and moved to a different Zigbee PIR sensor without occupancy and is work well enough for me.
After like 5 times removing the batteries, it now seems to work (without getting stuck). For 12 hours so far or so at least - will report back.
However, it looks like the Occupancy is not working really? It seems to be triggered purely by the motion sensor (aka 'None' in screenshot). So if the PIR doesn't detect anything for a while, it just goes to 'clear' again.
To give a proper example, I have the sensor 3 meters away from me in the living room. I enter the room, it detects it as large move. I sit down, it moves to small_move. And after about 15 seconds, while I'm sitting down in front of it, it goes to 'clear'. Its as if the mmWave sensor never actually works or gets used by the quirk?
It's as if the mmWave sensor never actually works
That's exactly what I've been experiencing. It behaves as if it's just a PIR sensor. Also, I've never gotten a BREATHING value out of it (like some others have reported). I even opened it up to confirm that I was sent the correct part device. After seeing the thread where others found that the PIR sensor wasn't soldered correctly, I wonder if there might be a batch where the mmwave sensor doesn't work and the device silently falls back to PIR-only.
or gets used by the quirk?
As far as I know, the quirk isn't what's "using" the outputs of the two sensors -- the device does that then presents the occupancy state.
With that being said, the quirk does expose the https://gist.github.com/vinzent/2cd645b848fd3b6a0c3e5762956ec89f#file-zg-204zm-py-L39, and for some reason defaults to PIR_only, though i think that's only for display purposes? I tried to set the mode to 2 (which, when the value was read back displayed as Mode.undefined_0x02
, so I'm not sure I did it correctly), but it didn't make any difference.
Try to set it to mode 1 (PIR + radar) (just write "1" with no brackets).
Some devices go with mode not set at all initially.
I'm not sure the mode 2 (radar only) is operable for the battery equipped version cos its' main idea is to turn on mmwave radar only when PIR sensor gets active.
I was using the following quirk for months and it worked quite well.
After updating HA to 2024.11.0 the device is shown as motion only. I tried to remove/add it but it doesn't seem to get the quirk profile.
"""
* TS0601 ZG-204ZM
* _TZE200_kb5noeto
* https://de.aliexpress.com/item/1005006174074799.html ("Color": Mmwave PIR)
* https://github.com/13717033460/zigbee-herdsman-converters/blob/6c9cf1b0de836ec2172d569568d3c7fe75268958/src/devices/tuya.ts#L5730-L5762
* https://www.zigbee2mqtt.io/devices/ZG-204ZM.html
* https://smarthomescene.com/reviews/zigbee-battery-powered-presence-sensor-zg-204zm-review/
* https://doc.szalarm.com/zg-205ZL/cntop_zigbee_sensor.js
* https://github.com/Koenkk/zigbee2mqtt/issues/21919
"""
import logging
from typing import Final
from zigpy.quirks.v2 import QuirkBuilder
import zigpy.types as t
from zigpy.zcl.foundation import ZCLAttributeDef
from zigpy.zcl.clusters.measurement import (
IlluminanceMeasurement,
OccupancySensing,
)
from zigpy.zcl.clusters.security import IasZone
from zigpy.quirks.v2.homeassistant import EntityPlatform, EntityType
from zhaquirks.tuya import (
TuyaLocalCluster,
TuyaPowerConfigurationCluster2AAA,
)
from zhaquirks.tuya.mcu import TuyaMCUCluster, DPToAttributeMapping
class HumanMotionState(t.enum8):
"""Human Motion State values"""
none = 0x00
large_move = 0x01
small_move = 0x02
breathe = 0x03
class MotionDetectionMode(t.enum8):
"""Motion detection mode values"""
Only_PIR: 0x00
PIR_radar: 0x01
Only_radar: 0x02
@staticmethod
def converter(value):
"""" If value is None, Only_PIR should be returned """
if value is None:
return MotionDetectionMode.Only_PIR
return value
class TuyaOccupancySensing(OccupancySensing, TuyaLocalCluster):
"""Tuya local OccupancySensing cluster."""
class TuyaIlluminanceMeasurement(IlluminanceMeasurement, TuyaLocalCluster):
"""Tuya local IlluminanceMeasurement cluster."""
class HumanPresenceSensorManufCluster(TuyaMCUCluster):
"""Human Presence Sensor ZG-204ZM (PIR+mmWave, battery)"""
# Tuya Data points
# "1":"Human Presence State", (presence_state, Enum, none|presence)
# "2":"Stationary detection sensitivity", (sensitivity, Integer, 0-10, unit=x, step=1)
# "3":"Minimum detection distance", (near_detection, Integer, 0-1000, unit=cm, step=1) (NOT AVAILABLE IN TUYA SMART LIFE APP)
# "4":"Stationary detection distance", (far_detection, Integer, 0-1000, unit=cm, step=1)
# "101":"Human Motion State", (human_motion_state, Enum, none|large_move|small_move|breathe)
# "102":"Presence Keep Time", (presence_time, 10-28800, unit=s, step=1)
# "106":"Illuminance Value", (illuminance_value, Integer, 0-6000, unit=lux )
# "107":"Indicator", (indicator, Boolean)
# "112":"Reset setting", (reset_setting, Boolean)
# "121":"Battery", (battery, Integer, -1-100, step=1, unit=%)
# "122":"Motion detection ", (motion_detection_mode, Enum, Only_PIR|PIR_radar|Only_radar) (NOT AVAILABLE IN TUYA SMART LIFE APP)
# "123":"Motion detection sensitivity", (motion_detection_sen, Integer, 0-10, step=1, unit=x) (NOT AVAILABLE IN TUYA SMART LIFE APP)
# "124":"ver" (ver, Integer, 0-100, step=1) (NOT AVAILABLE IN TUYA SMART LIFE APP)
class AttributeDefs(TuyaMCUCluster.AttributeDefs):
"""Tuya DataPoints attributes"""
# Human presence state (mapped to the OccupancySensing cluster)
#presence_state: Final = ZCLAttributeDef(
# id=0xEF01, # DP 1
# type=Occupancy,
# access="rp",
# is_manufacturer_specific=True,
#)
# Stationary detection sensitivity
sensitivity: Final = ZCLAttributeDef(
id=0x0002, # DP 2
type=t.uint16_t,
is_manufacturer_specific=True,
)
# Minimum detection distance
near_detection: Final = ZCLAttributeDef(
id=0x0003, # DP 3
type=t.uint16_t,
is_manufacturer_specific=True,
)
# Stationary detection distance
far_detection: Final = ZCLAttributeDef(
id=0x0004, # DP 4
type=t.uint16_t,
is_manufacturer_specific=True,
)
# Human motion state
human_motion_state: Final = ZCLAttributeDef(
id=0x0101, # DP 101
type=HumanMotionState,
access="rp",
is_manufacturer_specific=True,
)
# Presence keep time
presence_time: Final = ZCLAttributeDef(
id=0x0102, # DP 102
type=t.uint16_t,
is_manufacturer_specific=True,
)
# Illuminance value
illuminance_value: Final = ZCLAttributeDef(
id=0x0106, # DP 106
type=t.uint16_t,
access="rp",
is_manufacturer_specific=True,
)
# Indicator
indicator: Final = ZCLAttributeDef(
id=0x0107, # DP 107
type=t.Bool,
is_manufacturer_specific=True,
)
# Reset setting
reset_setting: Final = ZCLAttributeDef(
id=0x0112, # DP 112
type=t.Bool,
is_manufacturer_specific=True,
)
# Battery (also provided by the TuyaPowerConfigurationCluster2AAA)
battery: Final = ZCLAttributeDef(
id=0x0121, # DP 121
type=t.int16s,
is_manufacturer_specific=True,
)
# Motion detection
motion_detection_mode: Final = ZCLAttributeDef(
id=0x0122, # DP 122
type=MotionDetectionMode,
is_manufacturer_specific=True,
)
# Motion detection sensitivity
motion_detection_sen: Final = ZCLAttributeDef(
id=0x0123, # DP 123
type=t.uint16_t,
is_manufacturer_specific=True,
)
# ver
ver: Final = ZCLAttributeDef(
id=0x0124, # DP 124
type=t.uint16_t,
is_manufacturer_specific=True,
)
dp_to_attribute: dict[int, DPToAttributeMapping] = {
1: DPToAttributeMapping(
TuyaOccupancySensing.ep_attribute,
"occupancy",
),
2: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"sensitivity",
# Value in Tuya App after Factory reset is 6
converter=lambda x: x if x is not None else 6
),
3: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"near_detection",
# Guessing a default of 0
converter=lambda x: x if x is not None else 0
),
4: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"far_detection",
# Value in Tuya App after Factory reset is 600cm
converter=lambda x: x if x is not None else 600
),
101: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"human_motion_state",
converter=HumanMotionState
),
102: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"presence_time",
# Value in Tuya App is 30 after Factory reset
converter=lambda x: x if x is not None else 30
),
106: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"illuminance_value",
),
107: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"indicator",
),
112: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"reset_setting",
),
121: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"battery",
),
122: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"motion_detection_mode",
converter=MotionDetectionMode,
),
123: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"motion_detection_sen",
# Guessing a default of 10
converter=lambda x: x if x is not None else 10
),
124: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"ver",
),
}
data_point_handlers = {
1: "_dp_2_attr_update",
2: "_dp_2_attr_update",
3: "_dp_2_attr_update",
4: "_dp_2_attr_update",
101: "_dp_2_attr_update",
102: "_dp_2_attr_update",
106: "_dp_2_attr_update",
107: "_dp_2_attr_update",
112: "_dp_2_attr_update",
121: "_dp_2_attr_update",
122: "_dp_2_attr_update",
123: "_dp_2_attr_update",
124: "_dp_2_attr_update",
}
(
QuirkBuilder("_TZE200_kb5noeto", "TS0601")
.skip_configuration()
.removes(IasZone.cluster_id)
.adds(HumanPresenceSensorManufCluster)
.adds(TuyaOccupancySensing)
.replaces(TuyaPowerConfigurationCluster2AAA)
.replaces(TuyaIlluminanceMeasurement)
.number(HumanPresenceSensorManufCluster.AttributeDefs.sensitivity.name, HumanPresenceSensorManufCluster.cluster_id,step=1,min_value=1,max_value=10)
#.number(HumanPresenceSensorManufCluster.AttributeDefs.near_detection.name, HumanPresenceSensorManufCluster.cluster_id,step=1,min_value=0,max_value=1000)
.number(HumanPresenceSensorManufCluster.AttributeDefs.far_detection.name, HumanPresenceSensorManufCluster.cluster_id,step=1,min_value=0,max_value=1000)
.enum(HumanPresenceSensorManufCluster.AttributeDefs.human_motion_state.name,HumanMotionState,HumanPresenceSensorManufCluster.cluster_id,entity_platform=EntityPlatform.SENSOR, entity_type=EntityType.STANDARD)
.number(HumanPresenceSensorManufCluster.AttributeDefs.presence_time.name, HumanPresenceSensorManufCluster.cluster_id,step=1,min_value=10,max_value=28800)
#.binary_sensor(HumanPresenceSensorManufCluster.AttributeDefs.indicator.name,HumanPresenceSensorManufCluster.cluster_id)
#.binary_sensor(HumanPresenceSensorManufCluster.AttributeDefs.reset_setting.name,HumanPresenceSensorManufCluster.cluster_id)
#.enum(HumanPresenceSensorManufCluster.AttributeDefs.motion_detection_mode.name,MotionDetectionMode,HumanPresenceSensorManufCluster.cluster_id)
#.number(HumanPresenceSensorManufCluster.AttributeDefs.motion_detection_sen.name, HumanPresenceSensorManufCluster.cluster_id,step=1,min_value=0,max_value=10)
#.number(HumanPresenceSensorManufCluster.AttributeDefs.ver.name, HumanPresenceSensorManufCluster.cluster_id,step=1,min_value=0,max_value=10)
.add_to_registry()
)
Try this one
"""
* TS0601 ZG-204ZM
* _TZE200_kb5noeto
* Works with HA 2024.11
* https://de.aliexpress.com/item/1005006174074799.html ("Color": Mmwave PIR)
* https://github.com/13717033460/zigbee-herdsman-converters/blob/6c9cf1b0de836ec2172d569568d3c7fe75268958/src/devices/tuya.ts#L5730-L5762
* https://www.zigbee2mqtt.io/devices/ZG-204ZM.html
* https://smarthomescene.com/reviews/zigbee-battery-powered-presence-sensor-zg-204zm-review/
* https://doc.szalarm.com/zg-205ZL/cntop_zigbee_sensor.js
* https://github.com/Koenkk/zigbee2mqtt/issues/21919
"""
import logging
from typing import Final
from zigpy.quirks.v2 import QuirkBuilder
import zigpy.types as t
from zigpy.zcl.foundation import ZCLAttributeDef
from zigpy.zcl.clusters.measurement import (
IlluminanceMeasurement,
OccupancySensing,
)
from zigpy.zcl.clusters.security import IasZone
from zigpy.quirks.v2.homeassistant import EntityPlatform, EntityType
from zhaquirks.tuya import (
TuyaLocalCluster,
TuyaPowerConfigurationCluster2AAA,
)
from zhaquirks.tuya.mcu import TuyaMCUCluster, DPToAttributeMapping
class HumanMotionState(t.enum8):
"""Human Motion State values"""
none = 0x00
large_move = 0x01
small_move = 0x02
breathe = 0x03
class MotionDetectionMode(t.enum8):
"""Motion detection mode values"""
Only_PIR = 0x00
PIR_radar = 0x01
Only_radar = 0x02
@staticmethod
def converter(value):
"""" If value is None, Only_PIR should be returned """
if value is None:
return MotionDetectionMode.Only_PIR
return value
class TuyaOccupancySensing(OccupancySensing, TuyaLocalCluster):
"""Tuya local OccupancySensing cluster."""
class TuyaIlluminanceMeasurement(IlluminanceMeasurement, TuyaLocalCluster):
"""Tuya local IlluminanceMeasurement cluster."""
class HumanPresenceSensorManufCluster(TuyaMCUCluster):
"""Human Presence Sensor ZG-204ZM (PIR+mmWave, battery)"""
# Tuya Data points
# "1":"Human Presence State", (presence_state, Enum, none|presence)
# "2":"Stationary detection sensitivity", (sensitivity, Integer, 0-10, unit=x, step=1)
# "3":"Minimum detection distance", (near_detection, Integer, 0-1000, unit=cm, step=1) (NOT AVAILABLE IN TUYA SMART LIFE APP)
# "4":"Stationary detection distance", (far_detection, Integer, 0-1000, unit=cm, step=1)
# "101":"Human Motion State", (human_motion_state, Enum, none|large_move|small_move|breathe)
# "102":"Presence Keep Time", (presence_time, 10-28800, unit=s, step=1)
# "106":"Illuminance Value", (illuminance_value, Integer, 0-6000, unit=lux )
# "107":"Indicator", (indicator, Boolean)
# "112":"Reset setting", (reset_setting, Boolean)
# "121":"Battery", (battery, Integer, -1-100, step=1, unit=%)
# "122":"Motion detection ", (motion_detection_mode, Enum, Only_PIR|PIR_radar|Only_radar) (NOT AVAILABLE IN TUYA SMART LIFE APP)
# "123":"Motion detection sensitivity", (motion_detection_sen, Integer, 0-10, step=1, unit=x) (NOT AVAILABLE IN TUYA SMART LIFE APP)
# "124":"ver" (ver, Integer, 0-100, step=1) (NOT AVAILABLE IN TUYA SMART LIFE APP)
class AttributeDefs(TuyaMCUCluster.AttributeDefs):
"""Tuya DataPoints attributes"""
# Human presence state (mapped to the OccupancySensing cluster)
#presence_state: Final = ZCLAttributeDef(
# id=0xEF01, # DP 1
# type=Occupancy,
# access="rp",
# is_manufacturer_specific=True,
#)
# Stationary detection sensitivity
sensitivity: Final = ZCLAttributeDef(
id=0x0002, # DP 2
type=t.uint16_t,
is_manufacturer_specific=True,
)
# Minimum detection distance
near_detection: Final = ZCLAttributeDef(
id=0x0003, # DP 3
type=t.uint16_t,
is_manufacturer_specific=True,
)
# Stationary detection distance
far_detection: Final = ZCLAttributeDef(
id=0x0004, # DP 4
type=t.uint16_t,
is_manufacturer_specific=True,
)
# Human motion state
human_motion_state: Final = ZCLAttributeDef(
id=0x0101, # DP 101
type=HumanMotionState,
access="rp",
is_manufacturer_specific=True,
)
# Presence keep time
presence_time: Final = ZCLAttributeDef(
id=0x0102, # DP 102
type=t.uint16_t,
is_manufacturer_specific=True,
)
# Illuminance value
illuminance_value: Final = ZCLAttributeDef(
id=0x0106, # DP 106
type=t.uint16_t,
access="rp",
is_manufacturer_specific=True,
)
# Indicator
indicator: Final = ZCLAttributeDef(
id=0x0107, # DP 107
type=t.Bool,
is_manufacturer_specific=True,
)
# Reset setting
reset_setting: Final = ZCLAttributeDef(
id=0x0112, # DP 112
type=t.Bool,
is_manufacturer_specific=True,
)
# Battery (also provided by the TuyaPowerConfigurationCluster2AAA)
battery: Final = ZCLAttributeDef(
id=0x0121, # DP 121
type=t.int16s,
is_manufacturer_specific=True,
)
# Motion detection
motion_detection_mode: Final = ZCLAttributeDef(
id=0x0122, # DP 122
type=MotionDetectionMode,
is_manufacturer_specific=True,
)
# Motion detection sensitivity
motion_detection_sen: Final = ZCLAttributeDef(
id=0x0123, # DP 123
type=t.uint16_t,
is_manufacturer_specific=True,
)
# ver
ver: Final = ZCLAttributeDef(
id=0x0124, # DP 124
type=t.uint16_t,
is_manufacturer_specific=True,
)
dp_to_attribute: dict[int, DPToAttributeMapping] = {
1: DPToAttributeMapping(
TuyaOccupancySensing.ep_attribute,
"occupancy",
),
2: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"sensitivity",
# Value in Tuya App after Factory reset is 6
converter=lambda x: x if x is not None else 6
),
3: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"near_detection",
# Guessing a default of 0
converter=lambda x: x if x is not None else 0
),
4: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"far_detection",
# Value in Tuya App after Factory reset is 600cm
converter=lambda x: x if x is not None else 600
),
101: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"human_motion_state",
converter=HumanMotionState
),
102: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"presence_time",
# Value in Tuya App is 30 after Factory reset
converter=lambda x: x if x is not None else 30
),
106: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"illuminance_value",
),
107: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"indicator",
),
112: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"reset_setting",
),
121: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"battery",
),
122: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"motion_detection_mode",
converter=MotionDetectionMode,
),
123: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"motion_detection_sen",
# Guessing a default of 10
converter=lambda x: x if x is not None else 10
),
124: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"ver",
),
}
data_point_handlers = {
1: "_dp_2_attr_update",
2: "_dp_2_attr_update",
3: "_dp_2_attr_update",
4: "_dp_2_attr_update",
101: "_dp_2_attr_update",
102: "_dp_2_attr_update",
106: "_dp_2_attr_update",
107: "_dp_2_attr_update",
112: "_dp_2_attr_update",
121: "_dp_2_attr_update",
122: "_dp_2_attr_update",
123: "_dp_2_attr_update",
124: "_dp_2_attr_update",
}
(
QuirkBuilder("_TZE200_kb5noeto", "TS0601")
.skip_configuration()
.removes(IasZone.cluster_id)
.adds(HumanPresenceSensorManufCluster)
.adds(TuyaOccupancySensing)
.replaces(TuyaPowerConfigurationCluster2AAA)
.replaces(TuyaIlluminanceMeasurement)
.number(
HumanPresenceSensorManufCluster.AttributeDefs.sensitivity.name,
HumanPresenceSensorManufCluster.cluster_id,
step=1,
min_value=1,
max_value=10,
fallback_name="Sensitivity",
translation_key="sensitivity"
)
.number(
HumanPresenceSensorManufCluster.AttributeDefs.near_detection.name,
HumanPresenceSensorManufCluster.cluster_id,
step=1,
min_value=0,
max_value=1000,
fallback_name="Near Detection",
translation_key="near_detection"
)
.number(
HumanPresenceSensorManufCluster.AttributeDefs.far_detection.name,
HumanPresenceSensorManufCluster.cluster_id,
step=1,
min_value=0,
max_value=1000,
fallback_name="Far Detection",
translation_key="far_detection"
)
.enum(
HumanPresenceSensorManufCluster.AttributeDefs.human_motion_state.name,
HumanMotionState,
HumanPresenceSensorManufCluster.cluster_id,
entity_platform=EntityPlatform.SENSOR,
entity_type=EntityType.STANDARD,
fallback_name="Human Motion State",
translation_key="human_motion_state"
)
.number(
HumanPresenceSensorManufCluster.AttributeDefs.presence_time.name,
HumanPresenceSensorManufCluster.cluster_id,
step=1,
min_value=10,
max_value=28800,
fallback_name="Presence Time",
translation_key="presence_time"
)
.switch(
HumanPresenceSensorManufCluster.AttributeDefs.indicator.name,
HumanPresenceSensorManufCluster.cluster_id,
fallback_name="Indicator",
translation_key="indicator"
)
# .binary_sensor(
# HumanPresenceSensorManufCluster.AttributeDefs.reset_setting.name,
# HumanPresenceSensorManufCluster.cluster_id
# )
.enum(
HumanPresenceSensorManufCluster.AttributeDefs.motion_detection_mode.name,
MotionDetectionMode,
HumanPresenceSensorManufCluster.cluster_id,
fallback_name="Motion Detection Mode",
translation_key="motion_detection_mode"
)
.number(
HumanPresenceSensorManufCluster.AttributeDefs.motion_detection_sen.name,
HumanPresenceSensorManufCluster.cluster_id,
step=1,
min_value=0,
max_value=10,
fallback_name="Motion Detection Sensitivity",
translation_key="motion_detection_sen"
)
# .number(
# HumanPresenceSensorManufCluster.AttributeDefs.ver.name,
# HumanPresenceSensorManufCluster.cluster_id,
# step=1,
# min_value=0,
# max_value=10
# )
.add_to_registry()
)
@txip Thank you so much, did the update over the weekend then noticed it all stopped and your fix has given me occupancy back :-) Would seem that in the upgrades the old code returned a NONE instead of a number which caused the quirk not to load.
Yours seems to be much cleaner implentation / modern version .
Thanks again!
Same here. Your updated code fixed it for me too. Many thanks, @txip!
seems there are more changes to come with qurikbuilder and tuya: zigpy/zha-device-handlers#3417
I've updated the quirk a bit more here
I exposed some more settings and indicators so now the following settings|features are available:
- Near Detection
- Sensitivity
- Presence Time
- Far Detection
- Motion Detection Sensitivity
- Motion Detection Mode (you can switch between PIR only, PIR+radar and Radar only modes). Honestly I'm not sure that Radar only mode even works on this device.
- Indicator switch (you can turn on|off red light that flashes when detects any movement)
Vinzent did a great job, I've made just minor changes to the quirk tbf so all thankyous go to him. ;-)
Nice! Can you guys tell me what these settings controls?
Near Detection v Far Detection
Sensitivity v Motion Detection Sensitivity
Presence Time
You can get some understanding from the User Manual here
Thx @txip!
"""
- TS0601 ZG-204ZM
- _TZE200_kb5noeto
- Works with HA 2024.11
- https://de.aliexpress.com/item/1005006174074799.html ("Color": Mmwave PIR)
- https://github.com/13717033460/zigbee-herdsman-converters/blob/6c9cf1b0de836ec2172d569568d3c7fe75268958/src/devices/tuya.ts#L5730-L5762
- https://www.zigbee2mqtt.io/devices/ZG-204ZM.html
- https://smarthomescene.com/reviews/zigbee-battery-powered-presence-sensor-zg-204zm-review/
- https://doc.szalarm.com/zg-205ZL/cntop_zigbee_sensor.js
- Koenkk/zigbee2mqtt#21919
"""import logging
from typing import Finalfrom zigpy.quirks.v2 import QuirkBuilder
import zigpy.types as t
from zigpy.zcl.foundation import ZCLAttributeDef
from zigpy.zcl.clusters.measurement import (
IlluminanceMeasurement,
OccupancySensing,
)
from zigpy.zcl.clusters.security import IasZone
from zigpy.quirks.v2.homeassistant import EntityPlatform, EntityTypefrom zhaquirks.tuya import (
TuyaLocalCluster,
TuyaPowerConfigurationCluster2AAA,
)
from zhaquirks.tuya.mcu import TuyaMCUCluster, DPToAttributeMappingclass HumanMotionState(t.enum8):
"""Human Motion State values"""
none = 0x00
large_move = 0x01
small_move = 0x02
breathe = 0x03class MotionDetectionMode(t.enum8):
"""Motion detection mode values"""
Only_PIR = 0x00
PIR_radar = 0x01
Only_radar = 0x02@staticmethod def converter(value): """" If value is None, Only_PIR should be returned """ if value is None: return MotionDetectionMode.Only_PIR return value
class TuyaOccupancySensing(OccupancySensing, TuyaLocalCluster):
"""Tuya local OccupancySensing cluster."""class TuyaIlluminanceMeasurement(IlluminanceMeasurement, TuyaLocalCluster):
"""Tuya local IlluminanceMeasurement cluster."""class HumanPresenceSensorManufCluster(TuyaMCUCluster):
"""Human Presence Sensor ZG-204ZM (PIR+mmWave, battery)"""# Tuya Data points # "1":"Human Presence State", (presence_state, Enum, none|presence) # "2":"Stationary detection sensitivity", (sensitivity, Integer, 0-10, unit=x, step=1) # "3":"Minimum detection distance", (near_detection, Integer, 0-1000, unit=cm, step=1) (NOT AVAILABLE IN TUYA SMART LIFE APP) # "4":"Stationary detection distance", (far_detection, Integer, 0-1000, unit=cm, step=1) # "101":"Human Motion State", (human_motion_state, Enum, none|large_move|small_move|breathe) # "102":"Presence Keep Time", (presence_time, 10-28800, unit=s, step=1) # "106":"Illuminance Value", (illuminance_value, Integer, 0-6000, unit=lux ) # "107":"Indicator", (indicator, Boolean) # "112":"Reset setting", (reset_setting, Boolean) # "121":"Battery", (battery, Integer, -1-100, step=1, unit=%) # "122":"Motion detection ", (motion_detection_mode, Enum, Only_PIR|PIR_radar|Only_radar) (NOT AVAILABLE IN TUYA SMART LIFE APP) # "123":"Motion detection sensitivity", (motion_detection_sen, Integer, 0-10, step=1, unit=x) (NOT AVAILABLE IN TUYA SMART LIFE APP) # "124":"ver" (ver, Integer, 0-100, step=1) (NOT AVAILABLE IN TUYA SMART LIFE APP) class AttributeDefs(TuyaMCUCluster.AttributeDefs): """Tuya DataPoints attributes""" # Human presence state (mapped to the OccupancySensing cluster) #presence_state: Final = ZCLAttributeDef( # id=0xEF01, # DP 1 # type=Occupancy, # access="rp", # is_manufacturer_specific=True, #) # Stationary detection sensitivity sensitivity: Final = ZCLAttributeDef( id=0x0002, # DP 2 type=t.uint16_t, is_manufacturer_specific=True, ) # Minimum detection distance near_detection: Final = ZCLAttributeDef( id=0x0003, # DP 3 type=t.uint16_t, is_manufacturer_specific=True, ) # Stationary detection distance far_detection: Final = ZCLAttributeDef( id=0x0004, # DP 4 type=t.uint16_t, is_manufacturer_specific=True, ) # Human motion state human_motion_state: Final = ZCLAttributeDef( id=0x0101, # DP 101 type=HumanMotionState, access="rp", is_manufacturer_specific=True, ) # Presence keep time presence_time: Final = ZCLAttributeDef( id=0x0102, # DP 102 type=t.uint16_t, is_manufacturer_specific=True, ) # Illuminance value illuminance_value: Final = ZCLAttributeDef( id=0x0106, # DP 106 type=t.uint16_t, access="rp", is_manufacturer_specific=True, ) # Indicator indicator: Final = ZCLAttributeDef( id=0x0107, # DP 107 type=t.Bool, is_manufacturer_specific=True, ) # Reset setting reset_setting: Final = ZCLAttributeDef( id=0x0112, # DP 112 type=t.Bool, is_manufacturer_specific=True, ) # Battery (also provided by the TuyaPowerConfigurationCluster2AAA) battery: Final = ZCLAttributeDef( id=0x0121, # DP 121 type=t.int16s, is_manufacturer_specific=True, ) # Motion detection motion_detection_mode: Final = ZCLAttributeDef( id=0x0122, # DP 122 type=MotionDetectionMode, is_manufacturer_specific=True, ) # Motion detection sensitivity motion_detection_sen: Final = ZCLAttributeDef( id=0x0123, # DP 123 type=t.uint16_t, is_manufacturer_specific=True, ) # ver ver: Final = ZCLAttributeDef( id=0x0124, # DP 124 type=t.uint16_t, is_manufacturer_specific=True, ) dp_to_attribute: dict[int, DPToAttributeMapping] = { 1: DPToAttributeMapping( TuyaOccupancySensing.ep_attribute, "occupancy", ), 2: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "sensitivity", # Value in Tuya App after Factory reset is 6 converter=lambda x: x if x is not None else 6 ), 3: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "near_detection", # Guessing a default of 0 converter=lambda x: x if x is not None else 0 ), 4: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "far_detection", # Value in Tuya App after Factory reset is 600cm converter=lambda x: x if x is not None else 600 ), 101: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "human_motion_state", converter=HumanMotionState ), 102: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "presence_time", # Value in Tuya App is 30 after Factory reset converter=lambda x: x if x is not None else 30 ), 106: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "illuminance_value", ), 107: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "indicator", ), 112: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "reset_setting", ), 121: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "battery", ), 122: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "motion_detection_mode", converter=MotionDetectionMode, ), 123: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "motion_detection_sen", # Guessing a default of 10 converter=lambda x: x if x is not None else 10 ), 124: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "ver", ), } data_point_handlers = { 1: "_dp_2_attr_update", 2: "_dp_2_attr_update", 3: "_dp_2_attr_update", 4: "_dp_2_attr_update", 101: "_dp_2_attr_update", 102: "_dp_2_attr_update", 106: "_dp_2_attr_update", 107: "_dp_2_attr_update", 112: "_dp_2_attr_update", 121: "_dp_2_attr_update", 122: "_dp_2_attr_update", 123: "_dp_2_attr_update", 124: "_dp_2_attr_update", }
(
QuirkBuilder("_TZE200_kb5noeto", "TS0601")
.skip_configuration()
.removes(IasZone.cluster_id)
.adds(HumanPresenceSensorManufCluster)
.adds(TuyaOccupancySensing)
.replaces(TuyaPowerConfigurationCluster2AAA)
.replaces(TuyaIlluminanceMeasurement)
.number(
HumanPresenceSensorManufCluster.AttributeDefs.sensitivity.name,
HumanPresenceSensorManufCluster.cluster_id,
step=1,
min_value=1,
max_value=10,
fallback_name="Sensitivity",
translation_key="sensitivity"
)
.number(
HumanPresenceSensorManufCluster.AttributeDefs.near_detection.name,
HumanPresenceSensorManufCluster.cluster_id,
step=1,
min_value=0,
max_value=1000,
fallback_name="Near Detection",
translation_key="near_detection"
)
.number(
HumanPresenceSensorManufCluster.AttributeDefs.far_detection.name,
HumanPresenceSensorManufCluster.cluster_id,
step=1,
min_value=0,
max_value=1000,
fallback_name="Far Detection",
translation_key="far_detection"
)
.enum(
HumanPresenceSensorManufCluster.AttributeDefs.human_motion_state.name,
HumanMotionState,
HumanPresenceSensorManufCluster.cluster_id,
entity_platform=EntityPlatform.SENSOR,
entity_type=EntityType.STANDARD,
fallback_name="Human Motion State",
translation_key="human_motion_state"
)
.number(
HumanPresenceSensorManufCluster.AttributeDefs.presence_time.name,
HumanPresenceSensorManufCluster.cluster_id,
step=1,
min_value=10,
max_value=28800,
fallback_name="Presence Time",
translation_key="presence_time"
)
.switch(
HumanPresenceSensorManufCluster.AttributeDefs.indicator.name,
HumanPresenceSensorManufCluster.cluster_id,
fallback_name="Indicator",
translation_key="indicator"
).binary_sensor(
HumanPresenceSensorManufCluster.AttributeDefs.reset_setting.name,
HumanPresenceSensorManufCluster.cluster_id
)
.enum( HumanPresenceSensorManufCluster.AttributeDefs.motion_detection_mode.name, MotionDetectionMode, HumanPresenceSensorManufCluster.cluster_id, fallback_name="Motion Detection Mode", translation_key="motion_detection_mode" ) .number( HumanPresenceSensorManufCluster.AttributeDefs.motion_detection_sen.name, HumanPresenceSensorManufCluster.cluster_id, step=1, min_value=0, max_value=10, fallback_name="Motion Detection Sensitivity", translation_key="motion_detection_sen" )
.number(
HumanPresenceSensorManufCluster.AttributeDefs.ver.name,
HumanPresenceSensorManufCluster.cluster_id,
step=1,
min_value=0,
max_value=10
)
.add_to_registry()
)
Thanks for the good work.
After adding the quirk, new options appeared and everything seems to be ok, but the sensor, despite setting 10s presence, goes into idle mode after about 90 seconds. Can this be fixed?
it's not possible to go below 30s (but that worked for me). Finally, that pdf document from @txip gave me the inputs, which finally work:
Far Detection: 500
Mode: Only PIR
Motion Detection Sensitivity: 5
Presence Time: 30
Sensitivity: 6
@robert4y IMHO this is a "presence" sensor not a "motion" sensor. it will report "presence" or "no presence" not motion/no-motion. For me 30s is Ok for presence in my rooms.
does occupancy works on your side?
I have just tested this quirk and it 'works' reasonably. The parameters can be edited but for one of my sensors I have the impression the change is not applied to the device itself.
It adds features like human_motion_state
where I can see large_move
and small_move
. I have not seen breathe
. I put it under our television to see whether it would work correctly while watching a one hour show but it did change state to none
but this is more related to the hardware I think.
Any reason why no PR is created to add the Quirk to Zigpy? It would close issue zigpy/zha-device-handlers#3125.
I added the quirk above, but still no configuration available.
Edit: Works after another reboot just fine!
Still working on this. learning. :) there are multiple DPToAttributeMapping classes. one in tuya, one in tuya/mcu. the imported DPToAttributeMapping in rev 6 is probably wrong (why are there 2 of them?)