Open jdm09 opened 6 months ago
@jdm09 I've managed to get this working using the below quirk. I get illuminance and motion. I don't know if I should get ocupancy sensor or settings for the sensitivity. For that I can't help but would be verry interested if someone could help with this. Please note that I'm not a coder and I just did some research and added the model to this quirk.
"""ZY-M100 Human Presence Sensor"""
import math
from typing import Dict, Optional, Tuple, Union
from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
import zigpy.types as t
from zigpy.zcl import foundation
from zigpy.zcl.clusters.general import (
AnalogInput,
AnalogOutput,
Basic,
GreenPowerProxy,
Groups,
Identify,
Ota,
Scenes,
Time,
)
from zigpy.zcl.clusters.measurement import (
IlluminanceMeasurement,
OccupancySensing,
RelativeHumidity,
TemperatureMeasurement,
)
from zigpy.zcl.clusters.security import IasZone
from zhaquirks import Bus, LocalDataCluster, MotionOnEvent
from zhaquirks.const import (
DEVICE_TYPE,
ENDPOINTS,
INPUT_CLUSTERS,
MODELS_INFO,
MOTION_EVENT,
OUTPUT_CLUSTERS,
PROFILE_ID,
)
from zhaquirks.tuya import (
#DPToAttributeMapping,
TuyaLocalCluster,
TuyaManufCluster,
TuyaNewManufCluster,
TuyaDPType,
)
from zhaquirks.tuya.mcu import (
TuyaAttributesCluster,
DPToAttributeMapping,
TuyaMCUCluster,
)
ZONE_TYPE = 0x0001
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 TuyaTemperatureMeasurement(TemperatureMeasurement, TuyaLocalCluster):
"""Tuya local TemperatureMeasurement cluster."""
class TuyaRelativeHumidity(RelativeHumidity, TuyaLocalCluster):
"""Tuya local RelativeHumidity cluster."""
class MmwRadarManufCluster(TuyaMCUCluster):
"""ZY-M100 manufacturer cluster."""
attributes = TuyaMCUCluster.attributes.copy()
attributes.update(
{
0xEF00: ("dp_0", t.CharacterString, True),
0xEF68: ("dp_104", t.enum8, True),
0xEF69: ("dp_105", t.enum8, True),
0xEF6A: ("dp_106", t.enum8, True),
0xEF6B: ("dp_107", t.uint16_t, True),
0xEF6C: ("dp_108", t.uint16_t, True),
0xEF6D: ("dp_109", t.uint16_t, True),
0xEF6E: ("dp_110", t.uint8_t, True),
0xEF6F: ("dp_111", t.uint8_t, True),
}
)
dp_to_attribute: Dict[int, DPToAttributeMapping] = {
104: DPToAttributeMapping(
TuyaIlluminanceMeasurement.ep_attribute,
"measured_value",
lambda x: 10000 * math.log10(x) + 1 if x != 0 else 0,
),
1: DPToAttributeMapping(
TuyaOccupancySensing.ep_attribute,
"occupancy",
),
2: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"present_value",
endpoint_id=6,
),
4: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"present_value",
endpoint_id=3,
),
3: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"present_value",
endpoint_id=2,
),
109: DPToAttributeMapping(
TuyaAnalogInput.ep_attribute,
"Tpresent_value",
lambda x: x / 100,
),
101: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"present_value",
endpoint_id=4,
),
102: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"present_value",
endpoint_id=5,
),
}
data_point_handlers = {
1: "_dp_2_attr_update",
2: "_dp_2_attr_update",
3: "_dp_2_attr_update",
4: "_dp_2_attr_update",
9: "_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 MotionCluster(LocalDataCluster, MotionOnEvent):
"""Tuya Motion Sensor."""
_CONSTANT_ATTRIBUTES = {ZONE_TYPE: IasZone.ZoneType.Motion_Sensor}
reset_s = 15
class TuyaManufacturerClusterMotion(TuyaManufCluster):
"""Manufacturer Specific Cluster of the Motion device."""
def handle_cluster_request(
self,
hdr: foundation.ZCLHeader,
args: Tuple[TuyaManufCluster.Command],
*,
dst_addressing: Optional[
Union[t.Addressing.Group, t.Addressing.IEEE, t.Addressing.NWK]
] = None,
) -> None:
"""Handle cluster request."""
tuya_cmd = args[0]
self.debug("handle_cluster_request--> hdr: %s, args: %s", hdr, args)
if hdr.command_id == 0x0001 and tuya_cmd.command_id == 1027:
self.endpoint.device.motion_bus.listener_event(MOTION_EVENT)
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, 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, 0000)
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 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 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 MmwRadarMotionZYM100(CustomDevice):
"""Millimeter wave occupancy sensor."""
signature = {
MODELS_INFO: [
("_TZE200_kb5noeto", "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: 41440,
DEVICE_TYPE: 97,
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,
MmwRadarManufCluster,
TuyaOccupancySensing,
TuyaAnalogInput,
TuyaIlluminanceMeasurement,
],
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
},
#start of new replacements
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,
],
},
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: [],
},
6: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
INPUT_CLUSTERS: [
TuyaMmwRadarSensitivity,
],
OUTPUT_CLUSTERS: [],
},
#### end of new replacements.
242: {
PROFILE_ID: 41440,
DEVICE_TYPE: 97,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
},
}
}
@cobirnm how does your _TZE200_kb5noeto
device look like? Is it a battery powered device? your definition shows much more functionality than the zigbee2mqtt defines: https://github.com/13717033460/zigbee-herdsman-converters/blob/6c9cf1b0de836ec2172d569568d3c7fe75268958/src/devices/tuya.ts#L5730-L5762
also the ZY-M100 in the name look more like: https://smarthomescene.com/reviews/tuya-zigbee-human-presence-sensor-zy-m100-review/ instead of https://de.aliexpress.com/item/1005006190626320.html .
oes your
_TZE200_kb5noeto
device look like? Is it a battery powered devic
Hello,
this is my device https://www.aliexpress.com/item/1005006851082995.html
Regarding functionality I'm still testing but something strange is happening. Without the above quirk I can't add the device. If I add the quirk the device gets added but when I look at HA the quirk is not being used. Never the less it is working and I can't explain it.
TS0601 by _TZE200_kb5noeto Also known as Tuya ZG-204ZM. (PIR+radar 24Ghz) https://smarthomescene.com/blog/best-and-worst-presence-sensors-for-home-assistant/#best-battery-presence-sensor Please look into zha drivers. Zigbee2mqtt is no option. Parameters can not be addjusted. Others say device is constantly sending out its state to the coordinator
my first try to add a quirk for this ZG-204ZM.
Copied into gist: https://gist.github.com/vinzent/2cd645b848fd3b6a0c3e5762956ec89f#file-zg-204zm-py
my first try to add a quirk for this ZG-204ZM.
Copied into gist: https://gist.github.com/vinzent/2cd645b848fd3b6a0c3e5762956ec89f#file-zg-204zm-py
I used your quirk and it seems better. only the setting parameters are missing.
In this review: https://smarthomescene.com/reviews/zigbee-battery-powered-presence-sensor-zg-204zm-review/ it says that Z2M has settings. It would be great to have it! Never the less this looks quite good!
@cobirnm the attributes arent shown "nicely". You should be able to read/write the attributes by visiting the "Manage Zigbee-Device" link in the 3-dots menu:
then:
Honestly I really don't know if everything is working fine. The first time I read the attributes, it reported "None". then i wrote some value. Afterwards if I read it will show the value i've saved. But I don't know if it has any effect on the device.
Something doesnt seem to be quite right:
2024-05-17 16:08:13.116 DEBUG (MainThread) [homeassistant.components.zha.core.cluster_handlers] [0xE4BF:1:0x0400]: cluster_handler[illuminance] attribute_updated - cluster[Illuminance Measurement] attr[measured_value] value[2570]
2024-05-17 16:08:13.444 DEBUG (MainThread) [homeassistant.components.zha.core.cluster_handlers] [0xE4BF:1:0x0400]: cluster_handler[illuminance] attribute_updated - cluster[Illuminance Measurement] attr[measured_value] value[34099]
2024-05-17 16:12:13.169 DEBUG (MainThread) [homeassistant.components.zha.core.cluster_handlers] [0xE4BF:1:0x0400]: cluster_handler[illuminance] attribute_updated - cluster[Illuminance Measurement] attr[measured_value] value[2560]
2024-05-17 16:12:13.647 DEBUG (MainThread) [homeassistant.components.zha.core.cluster_handlers] [0xE4BF:1:0x0400]: cluster_handler[illuminance] attribute_updated - cluster[Illuminance Measurement] attr[measured_value] value[34082]
2024-05-17 16:16:13.219 DEBUG (MainThread) [homeassistant.components.zha.core.cluster_handlers] [0xE4BF:1:0x0400]: cluster_handler[illuminance] attribute_updated - cluster[Illuminance Measurement] attr[measured_value] value[2532]
2024-05-17 16:16:13.778 DEBUG (MainThread) [homeassistant.components.zha.core.cluster_handlers] [0xE4BF:1:0x0400]: cluster_handler[illuminance] attribute_updated - cluster[Illuminance Measurement] attr[measured_value] value[34035]
The illuminance seems to be reported 2x each time.
I've updated https://gist.github.com/vinzent/2cd645b848fd3b6a0c3e5762956ec89f
seems the IlluminanceMeasurement is binding to the 0x0000 measured_value too and does some calculations. whereas the tuya datapoint would deliver the already calculated value. Don't have enough insights to understand whats going on here. disabling the illuminance measured_value datapoind did fix this issue.
Loaded the quirk which changed it from motion to presence however, it goes to presence detected and does not change at all.
I have removed it and readded it as a new name but that did not change anything.
@BambamNZ it sometimes takes 20-30 minutes to change to unoccupied/no-motion. with or without the quirk. with the quirk enabled, did you try to change some of the settings (distance, detection sensitivity)?
No matter which setting you tweak it detects presence after you install the batteries and no amount of tweaking of settings get it to clear the presence. I put it in a drawer for 4 hours and still shows presence detected.
Motion_State changes between "Large" & "Static" but never goes to "None" which is suspect is why occupancy value remains "1" and not changes to "0". Force occupancy to "0" which clears it in HA, but it never fires again until you remove the batteries and the cycle starts all over with it stuck with presence detected.
That is strange. Mine has been verry stable and reliable. Right now it's not at it's final location but rather in a test position and it detects presence with a verry arcuate degree:
These are the settings that I have:
Based off your shared config @cobirnm - Thank you. I've been able to make some progress, been able to get it clear presence automatically, but the time it takes to clear is still strange. It takes between 5 and 15 minutes to clear from when I leave the room, it works just not very predictably right now.
I have the same issue as above. The occupancy state (not motion) is being cleared and detected but the clearing time takes a long time. The time to clear seems to be unrelated to the fading time.
Attributes can be written but seem to have no effect. After removing the battery to reboot the device the attributes return to the default state.
My device reports itself as _TZE200_kb5noeto
i've ordered a tuya zigbee gateway to test the device with the tuya app and see if it works there as expected.
large rewrite. i've got the tuya zigbee gatewaay and i was able to access the IOT Dev thing (iot.tuya.com) to discover the datapoints:
https://gist.github.com/vinzent/2cd645b848fd3b6a0c3e5762956ec89f
still need to figure out how to implement it as a quirk v2 with exposed config entries. (https://github.com/zigpy/zha-device-handlers/pull/3019)
Thanks a lot for working on this vinzent. Is there any use for the "HumanPresenceSensorManufCluster" on 0xef00? It has loads of settings but I haven't seen it mentioned, but it only appears for me after installing your quirk.
I run zigbee2mqtt on the side for testing and compatibility and haven't been able to get this device working in ZHA as reliably as MQTT sadly. Did you have any plans to continue with your quirk or do you have it working perfectly? Would love to know what settings you have after your V7 as some of the names changed I think as you introduced new settings? Cheers!
I can't seem to get the quirk to work.
I've deleted and re-added the device several times and tried reconfiguring several times. HA logs report that quirks are loaded. Anything I can try?
So did anyone get this device working correctly? the quirk at the top that was posted doesn't seem to be picked up by zha for the device (have restarted HA and re-added the device).
trying the other script on the gist gives me a little more but all of the "config" aspects don't have names and are blank, I tried to change one to a value and it bizarrely killed my ZHA (had to remove the quirk and reboot before it would successfully initialize again.
oh and checking the state of the entity with the quirk not enabled, it doesn't seem to ever clear the motion. my entity history only shows "motion" or unavailable (during the troubleshooting times) but never clear
I've updated https://gist.github.com/vinzent/2cd645b848fd3b6a0c3e5762956ec89f
seems the IlluminanceMeasurement is binding to the 0x0000 measured_value too and does some calculations. whereas the tuya datapoint would deliver the already calculated value. Don't have enough insights to understand whats going on here. disabling the illuminance measured_value datapoind did fix this issue.
not sure if you've tested your latest one, but my ZHA just doesn't start if i have it in my quirks folder at all.
not sure if you've tested your latest one, but my ZHA just doesn't start if i have it in my quirks folder at all.
latest does just work with >= HA 2024.08 due to api changes.
if you have that, you might provide error messages.
not sure if you've tested your latest one, but my ZHA just doesn't start if i have it in my quirks folder at all.
latest does just work with >= HA 2024.08 due to api changes.
if you have that, you might provide error messages.
yes i'm on the latest HA. I've managed to get it working now (as in that it is not rebooting the zha constantly), but its not actually working correctly. I've re-paired the sensor, it doesn't imply its unavailable, but the lux value and occupancy never change
not sure if you've tested your latest one, but my ZHA just doesn't start if i have it in my quirks folder at all.
latest does just work with >= HA 2024.08 due to api changes. if you have that, you might provide error messages.
yes i'm on the latest HA. I've managed to get it working now (as in that it is not rebooting the zha constantly), but its not actually working correctly. I've re-paired the sensor, it doesn't imply its unavailable, but the lux value and occupancy never change
Must admit, I gave up after weeks of trying and struggling, the quirk really helped to get things going, however the sensor was just not reliable. Mine would get stuck on "Occupancy Detected" with no state changes for hours and even days. Had to power cycle (remove batteries) every couple of days.
Found this Zigbee motion Sensor that is doing just fine for the application I was intending to use this one.
not sure if you've tested your latest one, but my ZHA just doesn't start if i have it in my quirks folder at all.
latest does just work with >= HA 2024.08 due to api changes. if you have that, you might provide error messages.
yes i'm on the latest HA. I've managed to get it working now (as in that it is not rebooting the zha constantly), but its not actually working correctly. I've re-paired the sensor, it doesn't imply its unavailable, but the lux value and occupancy never change
Must admit, I gave up after weeks of trying and struggling, the quirk really helped to get things going, however the sensor was just not reliable. Mine would get stuck on "Occupancy Detected" with no state changes for hours and even days. Had to power cycle (remove batteries) every couple of days.
Found this Zigbee motion Sensor that is doing just fine for the application I was intending to use this one.
ah, yeah thats just PIR, the whole point in using this one was it was Radar with PIR as an "assist" to help it with battery life.
tbh i've had nothing but problems with any radar based (bloody tuya) devices , so far this is the 3rd type i've tried. and yet all 3 seem to apparently work great in z2m. i really am in two minds whether to just bite the bullet and move everything over to z2m, despite it being a gigantuan task.
Just wanted to inject a bit of hope here with this sensor! It took me weeks of trying different configurations of detection distance, detection sensitivity, and motion detection sensitivity, but I finally got this working perfectly - no false positives, always on when I'm in the room no matter how still I am, etc. It was just about fiddling with those 3 numbers. Mine are 3, 8, and 5 respectively for a small 2 meter by 2 meters ish bathroom.
One thing I did resort to was cleaning and lightly re-soldering the connections for the PIR and RADAR modules after seeing this mentioned elsewhere. Not sure that helped though as I still had issues until I stumbled upon the right combination of settings. Before I got it right my wife described it as "the bathroom is having disco time" with it going on and off! Battery life has also been amazing which is worth noting considering it's a more complex device than a simple PIR.
Finally, one thing I'd recommend is setting the fading time as low as possible (10 seconds) and then just do your fading time manually via the off automation you create, ie: IF: Presence sensor is none FOR 30 seconds THEN turn of lights. Somehow that fading time was always wrong no matter what you set it to. So I decided to take that out of the equation as far as possible.
It's certainly not the best product experience I've had but it's very satisfying once it works. Keep slogging!
ps: thanks a lot to @vinzent for your hard work on the quirk !
Just wanted to inject a bit of hope here with this sensor! It took me weeks of trying different configurations of detection distance, detection sensitivity, and motion detection sensitivity, but I finally got this working perfectly - no false positives, always on when I'm in the room no matter how still I am, etc. It was just about fiddling with those 3 numbers. Mine are 3, 8, and 5 respectively for a small 2 meter by 2 meters ish bathroom.
One thing I did resort to was cleaning and lightly re-soldering the connections for the PIR and RADAR modules after seeing this mentioned elsewhere. Not sure that helped though as I still had issues until I stumbled upon the right combination of settings. Before I got it right my wife described it as "the bathroom is having disco time" with it going on and off! Battery life has also been amazing which is worth noting considering it's a more complex device than a simple PIR.
Finally, one thing I'd recommend is setting the fading time as low as possible (10 seconds) and then just do your fading time manually via the off automation you create, ie: IF: Presence sensor is none FOR 30 seconds THEN turn of lights. Somehow that fading time was always wrong no matter what you set it to. So I decided to take that out of the equation as far as possible.
It's certainly not the best product experience I've had but it's very satisfying once it works. Keep slogging!
is this on ZHA ? Or MQTT?
I would assume zha given the GitHub page we are in. would be nice if he shared his working quirk though.
@lukasdchass congrats on your success. You mentioned your magic three numbers: 3,8 and 5.
Do you mean:
What values are you using?
I would assume zha given the GitHub page we are in. would be nice if he shared his working quirk though.
I'd hope so, but I just can't see how what he is saying would work with ZHA atm - unless he has a separate quirk as you say.
Hello, has anyone managed to create a quirk that can be used to set the devices? I've tried a few of the ones listed here, but they all don't seem to work. For example, I don't have an entry with “TuyaOccupancySencing”
Problem description
Hi, this is another Zigbee Device which is recognized as a default motion sensor in ZHA, but without any possibilities for configurations such as distance zone config, sensitivity config etc. The Device is a battery powered presence and motion detector including illuminance sensor.
I bought this from here: https://de.aliexpress.com/item/1005006190626320.html
Thought, it should be near by this device custom quirk: https://github.com/zigpy/zha-device-handlers/blob/bfbfb4876d1811440b4a05cac9e3b83311d194a8/zhaquirks/tuya/ts0601_motion.py#L353
but its not working.
Signature of this device: { "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.EndDevice: 2>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress: 128>, manufacturer_code=4742, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, descriptor_capability_field=<DescriptorCapability.NONE: 0>, allocate_address=True, is_alternate_pan_coordinator=False, is_coordinator=False, is_end_device=True, is_full_function_device=False, is_mains_powered=False, is_receiver_on_when_idle=False, is_router=False, *is_security_capable=False)", "endpoints": { "1": { "profile_id": "0x0104", "device_type": "0x0402", "input_clusters": [ "0x0000", "0x0001", "0x0003", "0x0400", "0x0500" ], "output_clusters": [] } }, "manufacturer": "_TZE200_kb5noeto", "model": "TS0601", "class": "zigpy.device.Device" }
Solution description
I tried to put the device model and manufacturer to the quirk above.
Would be glad, if someone could help with the quirk for this device. Thanks.
Screenshots/Video
Screenshots/Video
[Paste/upload your media here]Device signature
Device signature
``` { "node_descriptor": "NodeDescriptor(logical_type=Diagnostic information
Diagnostic information
```json [Paste the diagnostic information here] ```Logs
Logs
```python [Paste the logs here] ```Custom quirk
Custom quirk
``` """BlitzWolf IS-3/Tuya motion rechargeable occupancy sensor.""" import math from typing import Optional, Union from zigpy.profiles import zgp, zha from zigpy.quirks import CustomDevice import zigpy.types as t from zigpy.zcl import foundation from zigpy.zcl.clusters.general import ( AnalogInput, Basic, GreenPowerProxy, Groups, Identify, Ota, Scenes, Time, ) from zigpy.zcl.clusters.measurement import ( IlluminanceMeasurement, OccupancySensing, RelativeHumidity, TemperatureMeasurement, ) from zigpy.zcl.clusters.security import IasZone from zhaquirks import Bus, LocalDataCluster, MotionOnEvent from zhaquirks.const import ( DEVICE_TYPE, ENDPOINTS, INPUT_CLUSTERS, MODELS_INFO, MOTION_EVENT, OUTPUT_CLUSTERS, PROFILE_ID, ) from zhaquirks.tuya import ( DPToAttributeMapping, TuyaLocalCluster, TuyaManufCluster, TuyaNewManufCluster, ) from zhaquirks.tuya.mcu import TuyaMCUCluster ZONE_TYPE = 0x0001 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 TuyaTemperatureMeasurement(TemperatureMeasurement, TuyaLocalCluster): """Tuya local TemperatureMeasurement cluster.""" class TuyaRelativeHumidity(RelativeHumidity, TuyaLocalCluster): """Tuya local RelativeHumidity cluster.""" class NeoBatteryLevel(t.enum8): """NEO battery level enum.""" BATTERY_FULL = 0x00 BATTERY_HIGH = 0x01 BATTERY_MEDIUM = 0x02 BATTERY_LOW = 0x03 USB_POWER = 0x04 class NeoMotionManufCluster(TuyaNewManufCluster): """Neo manufacturer cluster.""" attributes = TuyaNewManufCluster.attributes.copy() attributes.update( { 0xEF0D: ("dp_113", t.enum8, True), # ramdom attribute ID } ) dp_to_attribute: dict[int, DPToAttributeMapping] = { 101: DPToAttributeMapping( TuyaOccupancySensing.ep_attribute, "occupancy", ), 104: DPToAttributeMapping( TuyaTemperatureMeasurement.ep_attribute, "measured_value", lambda x: x * 10, ), 105: DPToAttributeMapping( TuyaRelativeHumidity.ep_attribute, "measured_value", lambda x: x * 100, ), 113: DPToAttributeMapping( TuyaNewManufCluster.ep_attribute, "dp_113", ), } data_point_handlers = { 101: "_dp_2_attr_update", 104: "_dp_2_attr_update", 105: "_dp_2_attr_update", 113: "_dp_2_attr_update", } class MmwRadarManufCluster(TuyaMCUCluster): """Neo manufacturer cluster.""" # # Possible DPs and values # presence_state: presence # target distance: 1.61m # illuminance: 250lux # sensitivity: 9 # minimum_detection_distance: 0.00m # maximum_detection_distance: 4.05m # dp_detection_delay: 0.1 # dp_fading_time: 5.0 # ¿illuminance?: 255lux # presence_brightness: no control # no_one_brightness: no control # current_brightness: off attributes = TuyaMCUCluster.attributes.copy() attributes.update( { # ramdom attribute IDs 0xEF02: ("dp_2", t.uint32_t, True), 0xEF03: ("dp_3", t.uint32_t, True), 0xEF04: ("dp_4", t.uint32_t, True), 0xEF06: ("dp_6", t.enum8, True), 0xEF65: ("dp_101", t.uint32_t, True), 0xEF66: ("dp_102", t.uint32_t, True), 0xEF67: ("dp_103", t.CharacterString, True), 0xEF69: ("dp_105", t.enum8, True), 0xEF6A: ("dp_106", t.enum8, True), 0xEF6B: ("dp_107", t.enum8, True), 0xEF6C: ("dp_108", t.uint32_t, True), } ) dp_to_attribute: dict[int, DPToAttributeMapping] = { 1: DPToAttributeMapping( TuyaOccupancySensing.ep_attribute, "occupancy", ), 2: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "dp_2", ), 3: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "dp_3", ), 4: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "dp_4", ), 6: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "dp_6", ), 9: DPToAttributeMapping( TuyaAnalogInput.ep_attribute, "present_value", lambda x: x / 100, ), 101: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "dp_101", ), 102: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "dp_102", ), 103: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "dp_103", ), 104: DPToAttributeMapping( TuyaIlluminanceMeasurement.ep_attribute, "measured_value", lambda x: 10000 * math.log10(x) + 1 if x != 0 else 0, ), 105: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "dp_105", ), 106: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "dp_106", ), 107: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "dp_107", ), 108: DPToAttributeMapping( TuyaMCUCluster.ep_attribute, "dp_108", ), } 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", 105: "_dp_2_attr_update", 106: "_dp_2_attr_update", 107: "_dp_2_attr_update", 108: "_dp_2_attr_update", } class MotionCluster(LocalDataCluster, MotionOnEvent): """Tuya Motion Sensor.""" _CONSTANT_ATTRIBUTES = {ZONE_TYPE: IasZone.ZoneType.Motion_Sensor} reset_s = 15 class TuyaManufacturerClusterMotion(TuyaManufCluster): """Manufacturer Specific Cluster of the Motion device.""" def handle_cluster_request( self, hdr: foundation.ZCLHeader, args: tuple[TuyaManufCluster.Command], *, dst_addressing: Optional[ Union[t.Addressing.Group, t.Addressing.IEEE, t.Addressing.NWK] ] = None, ) -> None: """Handle cluster request.""" tuya_cmd = args[0] self.debug("handle_cluster_request--> hdr: %s, args: %s", hdr, args) if hdr.command_id == 0x0001 and tuya_cmd.command_id == 1027: self.endpoint.device.motion_bus.listener_event(MOTION_EVENT) class TuyaMotion(CustomDevice): """BW-IS3 occupancy sensor.""" def __init__(self, *args, **kwargs): """Init device.""" self.motion_bus = Bus() super().__init__(*args, **kwargs) signature = { # endpoint=1 profile=260 device_type=0 device_version=0 input_clusters=[0, 3] # output_clusters=[3, 25]> MODELS_INFO: [("_TYST11_i5j6ifxj", "5j6ifxj"), ("_TYST11_7hfcudw5", "hfcudw5")], ENDPOINTS: { 1: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH, INPUT_CLUSTERS: [Basic.cluster_id, Identify.cluster_id], OUTPUT_CLUSTERS: [Identify.cluster_id, Ota.cluster_id], } }, } replacement = { ENDPOINTS: { 1: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.OCCUPANCY_SENSOR, INPUT_CLUSTERS: [ Basic.cluster_id, Identify.cluster_id, MotionCluster, TuyaManufacturerClusterMotion, ], OUTPUT_CLUSTERS: [Identify.cluster_id, Ota.cluster_id], } } } class NeoMotion(CustomDevice): """NAS-PD07 occupancy sensor.""" signature = { # endpoint=1 profile=260 device_type=81 device_version=0 input_clusters=[0, 4, 5, 61184] # output_clusters=[10, 25]> MODELS_INFO: [ ("_TZE200_7hfcudw5", "TS0601"), ("_TZE200_ppuj1vem", "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, NeoMotionManufCluster.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, NeoMotionManufCluster, TuyaOccupancySensing, TuyaTemperatureMeasurement, TuyaRelativeHumidity, ], OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id], } } } class MmwRadarMotion(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_wukb7rhc", "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, MmwRadarManufCluster, TuyaOccupancySensing, TuyaAnalogInput, TuyaIlluminanceMeasurement, ], OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id], }, } } 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_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: { #Additional information
No response