Closed wryandginger closed 1 year ago
Hi, any link to the manufacturer/vendor site? This can give us some clues about the device capabilities.
Enable debug logs and attach the device relevant info of the device, identifying the events (movement, etc) with logs. We need to match the device reported info with the device capabilities.
Here is info about enable debug logs:
I think it's made by Aubess, but there's no branding or company listed on the box or in the manual other than Tuya. AliExpress listings say it is a PIR sensor, but this is clearly mmWave (see my images, above)
Here are the AliExpress listings that are selling the device:
Based on my tinkering so far, it looks like the occupancy is happening on dp_119 or dp_141, which aren't being assigned in the current ts0601_motion.py. When I tried to add them in a custom quirk (under "class MmwRadarMotionGPP(CustomDevice)") it seemed to show presence activity, but then gets stuck on "presence detected."
I enabled logs and I'll re-pair them and report back later.
Okay, I enabled logs, but I'm not sure if this is what you need. There's a lot of crap in my logs to sort through.
This logs are dificult to me to analyze, so if you don't matter, we can come back to the quirk and work from it. The logs from the quirk will give to us more information (or in the format usefull to us).
My proposal quirk is this:
There's a lot of crap in my logs to sort through.
Yes, it is very verbose. But if you can get the logs from the same events, it will give us the DPs and values that device is using. Then we can try to map DPs to functionallity.
Thanks for your help, @javicalle. I created a TuyaMMWSensor.py file using your proposed quirk and put it in /config/custom_zha_quirks and rebooted.
[0x19E7:1:0xef00] No 'handle_set_data_response' tuya handler found for set_data_response(data=TuyaCommand(status=0, tsn=164, dp=141, data=TuyaData(dp_type=<TuyaDPType.ENUM: 4>, function=0, raw=b'\x02', *payload=<enum8.undefined_0x02: 2>)))
[0x19E7:1:0xef00] No 'handle_set_data_response' tuya handler found for set_data_response(data=TuyaCommand(status=0, tsn=165, dp=119, data=TuyaData(dp_type=<TuyaDPType.ENUM: 4>, function=0, raw=b'\x01', *payload=<enum8.undefined_0x01: 1>)))
[0x19E7:1:0xef00] No 'handle_set_data_response' tuya handler found for set_data_response(data=TuyaCommand(status=0, tsn=166, dp=141, data=TuyaData(dp_type=<TuyaDPType.ENUM: 4>, function=0, raw=b'\x02', *payload=<enum8.undefined_0x02: 2>)))
[0x19E7:1:0xef00] No 'handle_set_data_response' tuya handler found for set_data_response(data=TuyaCommand(status=0, tsn=167, dp=119, data=TuyaData(dp_type=<TuyaDPType.ENUM: 4>, function=0, raw=b'\x01', *payload=<enum8.undefined_0x01: 1>)))
[0x19E7:1:0xef00] No 'handle_set_data_response' tuya handler found for set_data_response(data=TuyaCommand(status=0, tsn=168, dp=141, data=TuyaData(dp_type=<TuyaDPType.ENUM: 4>, function=0, raw=b'\x02', *payload=<enum8.undefined_0x02: 2>)))
And if I look at the home-assistant.log:
2022-06-15 13:25:30 DEBUG (MainThread) [zigpy_deconz.api] Command Command.aps_data_indication (1, 1)
2022-06-15 13:25:30 DEBUG (MainThread) [zigpy_deconz.api] APS data indication response: [33, <DeviceState.APSDE_DATA_REQUEST_SLOTS_AVAILABLE|2: 34>, <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x0000>, 1, <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x19e7>, 1, 260, 61184, b'\tF\x02\x00%w\x04\x00\x01\x00', 0, 175, 255, 22, 149, 18, 8, -40]
2022-06-15 13:25:30 DEBUG (MainThread) [zigpy.zcl] [0x19E7:1:0xef00] Received ZCL frame: b'\tF\x02\x00%w\x04\x00\x01\x00'
2022-06-15 13:25:30 DEBUG (MainThread) [zigpy.zcl] [0x19E7:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=0, is_reply=1, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False), tsn=70, command_id=2, *is_reply=True)
2022-06-15 13:25:30 DEBUG (MainThread) [zigpy.zcl] [0x19E7:1:0xef00] Decoded ZCL frame: MmwRadarManufCluster:set_data_response(data=TuyaCommand(status=0, tsn=37, dp=119, data=TuyaData(dp_type=<TuyaDPType.ENUM: 4>, function=0, raw=b'\x00', *payload=<enum8.undefined_0x00: 0>)))
2022-06-15 13:25:30 DEBUG (MainThread) [zigpy.zcl] [0x19E7:1:0xef00] Received command 0x02 (TSN 70): set_data_response(data=TuyaCommand(status=0, tsn=37, dp=119, data=TuyaData(dp_type=<TuyaDPType.ENUM: 4>, function=0, raw=b'\x00', *payload=<enum8.undefined_0x00: 0>)))
2022-06-15 13:25:30 DEBUG (MainThread) [zigpy.zcl] [0x19E7:1:0xef00] No datapoint handler for TuyaCommand(status=0, tsn=37, dp=119, data=TuyaData(dp_type=<TuyaDPType.ENUM: 4>, function=0, raw=b'\x00', *payload=<enum8.undefined_0x00: 0>))
2022-06-15 13:25:30 WARNING (MainThread) [zigpy.zcl] [0x19E7:1:0xef00] No 'handle_set_data_response' tuya handler found for set_data_response(data=TuyaCommand(status=0, tsn=37, dp=119, data=TuyaData(dp_type=<TuyaDPType.ENUM: 4>, function=0, raw=b'\x00', *payload=<enum8.undefined_0x00: 0>)))
2022-06-15 13:25:30 DEBUG (MainThread) [zigpy.zcl] [0x19E7:1:0xef00] Sending reply header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=False, is_reply=1, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True), tsn=70, command_id=<GeneralCommand.Default_Response: 11>, *is_reply=True)
2022-06-15 13:25:30 DEBUG (MainThread) [zigpy.zcl] [0x19E7:1:0xef00] Sending reply: Default_Response(command_id=2, status=<Status.UNSUP_CLUSTER_COMMAND: 129>)
2022-06-15 13:25:30 DEBUG (MainThread) [zigpy_deconz.zigbee.application] Sending Zigbee request with tsn 70 under 96 request id, data: b'18460b0281'
2022-06-15 13:25:30 DEBUG (MainThread) [zigpy_deconz.zigbee.application] Max concurrency (8) reached, delaying requests (158 enqueued)
2022-06-15 13:25:30 DEBUG (MainThread) [zigpy_deconz.api] 'aps_data_indication' response from <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x19e7>, ep: 1, profile: 0x0104, cluster_id: 0xef00, data: b'09460200257704000100'
2022-06-15 13:25:30 DEBUG (MainThread) [zigpy_deconz.api] Device state changed response: [<DeviceState.128|APSDE_DATA_REQUEST_SLOTS_AVAILABLE|APSDE_DATA_INDICATION|APSDE_DATA_CONFIRM|2: 174>, 0]
2022-06-15 13:25:30 DEBUG (MainThread) [zigpy_deconz.api] Command Command.aps_data_indication (1, 1)
I would say that DP_119 can be occupancy or movement (whatever device report).
I have updated the quirk in my previous comment. DP_119 is mapped to TuyaOccupancySensing and DP_141 as a MmwRadarManufCluster
attribute.
Your updated quirk crashed ZHA for me.
Logger: homeassistant.config_entries
Source: custom_zha_quirks/TuyaMMWSensor.py:81
First occurred: 3:13:12 PM (1 occurrences)
Last logged: 3:13:12 PM
Error setting up entry ConBee II, s/n: - dresden elektronik ingenieurtechnik GmbH for zha
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/config_entries.py", line 339, in async_setup
result = await component.async_setup_entry(hass, self)
File "/usr/src/homeassistant/homeassistant/components/zha/__init__.py", line 99, in async_setup_entry
setup_quirks(config)
File "/usr/local/lib/python3.9/site-packages/zhaquirks/__init__.py", line 409, in setup
importer.find_module(modname).load_module(modname)
File "<frozen importlib._bootstrap_external>", line 529, in _check_name_wrapper
File "<frozen importlib._bootstrap_external>", line 1029, in load_module
File "<frozen importlib._bootstrap_external>", line 854, in load_module
File "<frozen importlib._bootstrap>", line 274, in _load_module_shim
File "<frozen importlib._bootstrap>", line 711, in _load
File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 850, in exec_module
File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
File "/config/custom_zha_quirks/TuyaMMWSensor.py", line 57, in <module>
class MmwRadarManufCluster(TuyaMCUCluster):
File "/config/custom_zha_quirks/TuyaMMWSensor.py", line 81, in MmwRadarManufCluster
1: DPToAttributeMapping(
TypeError: __init__() missing 1 required positional argument: 'dp_type'
Ouuuuch... fixed.
Hurrah! It appears to work! Thank you so much @javicalle!!
It will be great if you can get the list of the used DPs. It could be that DP_141 can be "sensing range" with values from 0-2 or maybe more.
Device is identified as 'mains powered', but if it have a battery maybe there is also a DP for battery reporting.
Is there a specific way you'd like me to do that?
Poking around the MmWRadarManufCluster Attributes, here's what I found: DP_102 = 48 DP_105 = enum8.undefined_0x05 DP_141 = enum8.undefined_0x02
All other DPs are None. The sensor is only microUSB powered but it does act as a router
So I got out a Tuya zigbee hub and I decided to do some more digging:
If you press "device lookup" the lights flash red and blue. It's kinda cool. I really wish I could turn them off completely.
DP 102 for sure is "induction time" which I'm pretty sure is just the cooldown for the motion sensor. It can be any number between 24 seconds and 300 seconds.
So if DP 119 is occupancy, I would guess 105 is maybe distance sensitivity, and 141 is movement/stillness? From what I can tell 102, 105, 119, and 141 are the only DPs being used.
Pretty good findings!
I agree that DP_102 would be that 'induction time", and the units could be seconds. Device reports for DP_105 and DP_141 are enumerations. Can you get the list of possibles values? They are needed to map between values (0-N) and significance (0.5m, 1m, 3m, ...)
During the weekend I will try to propose a cleaner quirk.
Pretty good findings!
I agree that DP_102 would be that 'induction time", and the units could be seconds. Device reports for DP_105 and DP_141 are enumerations. Can you get the list of possibles values? They are needed to map between values (0-N) and significance (0.5m, 1m, 3m, ...)
During the weekend I will try to propose a cleaner quirk.
DP_102 is seconds and can be any value from 24 to 300. DP_105 might be target distance. Target distance for the device is 0.5 - 5 meters in 0.5 meter (0.5, 1, 1.5, 2, 2.5.....5) increments.
If DP_141 is the motion data, it might be something like this (see Tuya Solution Center doc for a similar device) :
Induction stateRequired | presence_state | Report Only | Enum | Enum Value: none, presence, peaceful, small_move, large_move -- | -- | -- | -- | --with 0 = none, 1 = presence, 2= peaceful, 3 = small, 4 = large?
Though I wonder if this motion data is on DP_119? Because if DP_119 is also ENUM then it could have a value higher than 1, right?
That is the new quirk version:
Some of the changes:
You should be able to modify the sensor sensitivity and cooldown value from the device view, "admin clusters" option, target_distance
and induction_delay
attributes
You should also be able to query the type of motion from the motion_type
attribute. Some changes have been made in HA to be able to show these values as entities, but I don't know how to do it.
hmm. It didn't like that.
2022-06-19 13:50:02 DEBUG (MainThread) [zhaquirks] Loading custom quirks module MMWTest
2022-06-19 13:50:02 ERROR (MainThread) [homeassistant.config_entries] Error setting up entry ConBee II, s/n: - dresden elektronik ingenieurtechnik GmbH for zha
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/config_entries.py", line 339, in async_setup
result = await component.async_setup_entry(hass, self)
File "/usr/src/homeassistant/homeassistant/components/zha/__init__.py", line 99, in async_setup_entry
setup_quirks(config)
File "/usr/local/lib/python3.9/site-packages/zhaquirks/__init__.py", line 409, in setup
importer.find_module(modname).load_module(modname)
File "<frozen importlib._bootstrap_external>", line 529, in _check_name_wrapper
File "<frozen importlib._bootstrap_external>", line 1029, in load_module
File "<frozen importlib._bootstrap_external>", line 854, in load_module
File "<frozen importlib._bootstrap>", line 274, in _load_module_shim
File "<frozen importlib._bootstrap>", line 711, in _load
File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 846, in exec_module
File "<frozen importlib._bootstrap_external>", line 983, in get_code
File "<frozen importlib._bootstrap_external>", line 913, in source_to_code
File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
File "/config/custom_zha_quirks/MMWTest.py", line 26
_0.5_M = 0x00
^
SyntaxError: invalid decimal literal
I replaced the range sensing with this and was able to get ZHA to start up.
CEILING_R0_5M = 0x00
CEILING_R1_0M = 0x01
CEILING_R1_5M = 0x02
CEILING_R2_0M = 0x03
CEILING_R2_5M = 0x04
CEILING_R3_0M = 0x05
CEILING_R3_5M = 0x06
CEILING_R4_0M = 0x07
CEILING_R4_5M = 0x08
CEILING_R5_0M = 0x09
I can get induction_time to read 48, but I can't write a new value. target_distance is still reporting 5 (which is the same as _3.0_M, default) and I can't write a new value. motion_type is coming back as: enum8.undefined_0x03 when there's little movement, enum8.undefined_0x02 when there's activity (which seems backwards), and 1 when there's no motion for certain.
hmm. It didn't like that.
Ouuuuch, sorry for that. My local tests didn't catch these errors.
I can get induction_time to read 48, but I can't write a new value. target_distance is still reporting 5 (which is the same as _3.0_M, default) and I can't write a new value.
I would try with the NoManufacturerCluster
implementation.
motion_type is coming back as: enum8.undefined_0x03 when there's little movement, enum8.undefined_0x02
These values are not the expected ones. I would expect something like RangeSensing.CEILING_R3_0M
and MotionType.PEACEFULL
, but not enum8.undefined_0x03
...
I have added converters for these DPs:
105: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"target_distance",
dp_type=TuyaDPType.ENUM,
converter=lambda x: RangeSensing(x),
),
.../...
141: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"motion_type",
dp_type=TuyaDPType.ENUM,
converter=lambda x: MotionType(x),
),
The new version would be:
I have been looking at the AnalogOutput
cluster and I think that can be usefull here.
Would you try with this other version:
"""Tuya mmWave sensor quirk."""
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 (
AnalogOutput,
Basic,
GreenPowerProxy,
Groups,
Ota,
Scenes,
Time,
)
from zigpy.zcl.clusters.measurement import OccupancySensing
from zhaquirks.const import (
DEVICE_TYPE,
ENDPOINTS,
INPUT_CLUSTERS,
MODELS_INFO,
OUTPUT_CLUSTERS,
PROFILE_ID,
)
from zhaquirks.tuya import NoManufacturerCluster, TuyaLocalCluster, TuyaNewManufCluster
from zhaquirks.tuya.mcu import (
DPToAttributeMapping,
TuyaAttributesCluster,
TuyaDPType,
TuyaMCUCluster,
)
class RangeSensing(t.enum8):
"""Radar range sensing enum."""
METERS_0_5 = 0x00
METERS_1_0 = 0x01
METERS_1_5 = 0x02
METERS_2_0 = 0x03
METERS_2_5 = 0x04
METERS_3_0 = 0x05
METERS_3_5 = 0x06
METERS_4_0 = 0x07
METERS_4_5 = 0x08
METERS_5_0 = 0x09
class MotionType(t.enum8):
"""Type of motion detected enum."""
NONE = 0x00
PRESENCE = 0x01
PEACEFULL = 0x02
SMALL_MOVE = 0x03
LARGE_MOVE = 0x04
class TuyaOccupancySensing(OccupancySensing, TuyaLocalCluster):
"""Tuya local OccupancySensing cluster."""
class CooldownTime(TuyaAttributesCluster, AnalogOutput):
"""AnalogOutput cluster for cooldown time."""
def __init__(self, *args, **kwargs):
"""Init."""
super().__init__(*args, **kwargs)
self._update_attribute(
self.attributes_by_name["description"].id, "Cooldown time"
)
self._update_attribute(
self.attributes_by_name["max_present_value"].id,
300,
)
self._update_attribute(
self.attributes_by_name["min_present_value"].id,
24,
)
self._update_attribute(self.attributes_by_name["resolution"].id, 1)
# self._update_attribute(self.attributes_by_name["application_type"].id, 0 << 16)
self._update_attribute(
self.attributes_by_name["engineering_units"].id, 73
) # 73: seconds
class MmwRadarManufCluster(NoManufacturerCluster, TuyaMCUCluster):
"""Neo manufacturer cluster."""
attributes = TuyaMCUCluster.attributes.copy()
attributes.update(
{
# ramdom attribute IDs
# 0xEF66: ("induction_delay", t.uint32_t, True),
0xEF69: ("target_distance", RangeSensing, True),
0xEF8D: ("motion_type", MotionType, True),
}
)
dp_to_attribute: Dict[int, DPToAttributeMapping] = {
102: DPToAttributeMapping(
CooldownTime.ep_attribute,
"present_value",
dp_type=TuyaDPType.VALUE,
),
105: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"target_distance",
dp_type=TuyaDPType.ENUM,
converter=lambda x: RangeSensing(x),
),
119: DPToAttributeMapping(
TuyaOccupancySensing.ep_attribute,
"occupancy",
dp_type=TuyaDPType.ENUM,
),
141: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"motion_type",
dp_type=TuyaDPType.ENUM,
converter=lambda x: MotionType(x),
),
}
data_point_handlers = {
102: "_dp_2_attr_update",
105: "_dp_2_attr_update",
119: "_dp_2_attr_update",
141: "_dp_2_attr_update",
}
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_9qayzqa8", "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,
CooldownTime,
],
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
},
242: {
PROFILE_ID: 41440,
DEVICE_TYPE: 97,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
},
}
}
It is expected to generate a new number entity where you can set the cooldown_time
(induction relay or whatever it is called) attribute.
Thanks in advanced.
hmm. It didn't like that.
Ouuuuch, sorry for that. My local tests didn't catch these errors.
I can get induction_time to read 48, but I can't write a new value. target_distance is still reporting 5 (which is the same as _3.0_M, default) and I can't write a new value.
I would try with the
NoManufacturerCluster
implementation.motion_type is coming back as: enum8.undefined_0x03 when there's little movement, enum8.undefined_0x02
These values are not the expected ones. I would expect something like
RangeSensing.CEILING_R3_0M
andMotionType.PEACEFULL
, but notenum8.undefined_0x03
... I have added converters for these DPs:The new version would be:
ts0601_radar.py
This version seems to be working the best! I have induction_time, motion_type, and target_distance.
The induction_time and target_distance are all accepting values. Though, with target_distance you have to send 1 to the cluster to get RangeSensing.METERS_1_0 as a reply.
The motion_type is a little wonky -- the names are changing, but they appear to be off slightly:
MotionType.PRESENCE shows when there's nobody in the room. MotionType.PEACEFULL happens on entry/activity MotionType.SMALL_MOVE happens when I'm sitting.
I would assume just changing the text in the quirk to None, Active, Presence or something would probably fix that:
class MotionType(t.enum8):
"""Type of motion detected enum."""
EMPTY = 0x00
NONE = 0x01
ACTIVE = 0x02
PRESENCE = 0x03
UNKNOWN = 0x04
Thank you for all of your help on this @javicalle! This is really helping me learn and understand ZHA quirks more, so I greatly appreciate your hard work and help on this.
I have been looking at the
AnalogOutput
cluster and I think that can be usefull here. Would you try with this other version:It is expected to generate a new number entity where you can set the
cooldown_time
(induction relay or whatever it is called) attribute.Thanks in advanced.
This didn't seem to work. I got errors with DP 102:
Logger: zigpy.zcl
Source: /usr/local/lib/python3.9/site-packages/zhaquirks/tuya/__init__.py:1411
First occurred: 9:46:44 AM (1 occurrences)
Last logged: 9:46:44 AM
[0xD4F3:1:0xef00] No 'handle_set_data_response' tuya handler found for set_data_response(data=TuyaCommand(status=0, tsn=210, dp=102, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x18\x00\x00\x00', *payload=24)))
I'll go back to the previous version
The induction_time and target_distance are all accepting values. Though, with target_distance you have to send 1 to the cluster to get RangeSensing.METERS_1_0 as a reply.
Yes, you need to set the value number (0-9 or 0x00-0x09). And when you get the value, you will also get the 'label' wich would give to user some clue about the value meaning. (At least this is the intention).
I would assume just changing the text in the quirk to None, Active, Presence or something would probably fix that
If not documented, setting 'labels' to values usually is a trial and error process. Only someone testing the device can get the meanings to values. You can also implement the quirk without an enumeration, but then users will have to 'guess' the meaning of each value.
This didn't seem to work. I got errors with DP 102:
Ouuuch^2
I have fixed the code. Just added the CooldownTime
cluster in the replacement
part:
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,
CooldownTime,
],
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
},
242: {
PROFILE_ID: 41440,
DEVICE_TYPE: 97,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
},
}
}
Would you be so kind as to try the fixed version?
Thanks in advanced.
WOW!!
That seems to work really well. The device instantly responds to changing the cooldown time.
Thanks for trying it out. I apreciate it.
So far this updated quirk you wrote is working great and it's doing more than I could have hoped, thank you again!
I was reading through this and was wondering if it would be possible to use the IAS_Zone cluster to have the target_distance show up under controls?
For example, can we put the target distance to CurrentZoneSensitivityLevel and NumberOfZoneSensitivityLevels to 10? (see page 460)
ZoneType / E_CLD_IASZONE_TYPE_MOTION_SENSOR (see page 458) looks like the motion alarms (intrusion/presence) might work for the motion type too, maybe?
if it would be possible to use the IAS_Zone cluster
Yes, it should be possible. Same way that we have implemented the quirk with a OccupancySensing
, probably we can use a IasZone
cluster. It's just a matter of finding the cluster that best fits the functionality of the device
to have the target_distance show up under controls
Meeeeeh, probably not or not in the way you'd like.
can we put the target distance to CurrentZoneSensitivityLevel and NumberOfZoneSensitivityLevels to 10?
Yes for sure:
But this would not be show in HA as control entities it will be just an attributes of cluster.
The ZHA integration is very limited yet. It's growing big and fast, but some less common use cases are harder to find implemented. This would be one of this cases. Anyone can implement it, but it not my area and I can't give support in the HA implementation part.
More references:
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.
Here's an updated quirk for this. I literally have no clue how to put this as a PR, could someone do that (or tell me what to do?)
"""Tuya mmWave sensor quirk."""
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 (
AnalogOutput,
Basic,
GreenPowerProxy,
Groups,
Ota,
Scenes,
Time,
)
from zigpy.zcl.clusters.measurement import OccupancySensing
from zhaquirks.const import (
DEVICE_TYPE,
ENDPOINTS,
INPUT_CLUSTERS,
MODELS_INFO,
OUTPUT_CLUSTERS,
PROFILE_ID,
)
from zhaquirks.tuya import NoManufacturerCluster, TuyaLocalCluster, TuyaNewManufCluster
from zhaquirks.tuya.mcu import (
DPToAttributeMapping,
TuyaAttributesCluster,
TuyaMCUCluster,
)
class RangeSensing(t.enum8):
"""Radar range sensing enum."""
METERS_0_5 = 0x00
METERS_1_0 = 0x01
METERS_1_5 = 0x02
METERS_2_0 = 0x03
METERS_2_5 = 0x04
METERS_3_0 = 0x05
METERS_3_5 = 0x06
METERS_4_0 = 0x07
METERS_4_5 = 0x08
METERS_5_0 = 0x09
class MotionType(t.enum8):
"""Type of motion detected enum."""
ERROR_LOW = 0x00
CLEAR = 0x01
ACTIVE = 0x02
PRESENCE = 0x03
ERROR_HIGH = 0x04
class TuyaOccupancySensing(OccupancySensing, TuyaLocalCluster):
"""Tuya local OccupancySensing cluster."""
class CooldownTime(TuyaAttributesCluster, AnalogOutput):
"""AnalogOutput cluster for cooldown time."""
def __init__(self, *args, **kwargs):
"""Init."""
super().__init__(*args, **kwargs)
self._update_attribute(
self.attributes_by_name["description"].id, "Cooldown time"
)
self._update_attribute(
self.attributes_by_name["max_present_value"].id,
300,
)
self._update_attribute(
self.attributes_by_name["min_present_value"].id,
24,
)
self._update_attribute(self.attributes_by_name["resolution"].id, 1)
# self._update_attribute(self.attributes_by_name["application_type"].id, 0 << 16)
self._update_attribute(
self.attributes_by_name["engineering_units"].id, 73
) # 73: seconds
class MmwRadarManufCluster(NoManufacturerCluster, TuyaMCUCluster):
"""Neo manufacturer cluster."""
attributes = TuyaMCUCluster.attributes.copy()
attributes.update(
{
# ramdom attribute IDs
# 0xEF66: ("induction_delay", t.uint32_t, True),
0xEF69: ("target_distance", RangeSensing, True),
0xEF8D: ("motion_type", MotionType, True),
}
)
dp_to_attribute: Dict[int, DPToAttributeMapping] = {
102: DPToAttributeMapping(
CooldownTime.ep_attribute,
"present_value",
),
105: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"target_distance",
converter=lambda x: RangeSensing(x),
),
119: DPToAttributeMapping(
TuyaOccupancySensing.ep_attribute,
"occupancy",
),
141: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"motion_type",
converter=lambda x: MotionType(x),
),
}
data_point_handlers = {
102: "_dp_2_attr_update",
105: "_dp_2_attr_update",
119: "_dp_2_attr_update",
141: "_dp_2_attr_update",
}
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_9qayzqa8", "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,
CooldownTime,
],
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
},
242: {
PROFILE_ID: 41440,
DEVICE_TYPE: 97,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
},
}
}
Is your feature request related to a problem? Please describe.
I just bought a Tuya Zigbee Human Presence Sensor (Model is listed as LQ-CG01-RDR in the manual) It pairs, but shows no entities
Describe the solution you'd like I'd like to see a presence entity
Device signature
```yaml { "node_descriptor": "NodeDescriptor(logical_type=Diagnostic information
```yaml { "home_assistant": { "installation_type": "Home Assistant OS", "version": "2022.6.5", "dev": false, "hassio": true, "virtualenv": false, "python_version": "3.9.12", "docker": true, "arch": "x86_64", "timezone": "America/Los_Angeles", "os_name": "Linux", "os_version": "5.15.41", "supervisor": "2022.05.3", "host_os": "Home Assistant OS 8.1", "docker_version": "20.10.14", "chassis": "embedded", "run_as_root": true }, "custom_components": { "watchman": { "version": "0.5.1", "requirements": [ "prettytable==3.0.0" ] }, "smartthinq_sensors": { "version": "0.23.0", "requirements": [ "pycountry>=20.7.3", "xmltodict>=0.12.0", "chardet>=4.0.0" ] }, "dyson_local": { "version": "0.16.4-4", "requirements": [ "libdyson==0.8.11" ] }, "frigate": { "version": "2.3", "requirements": [] }, "zha_toolkit": { "version": "v0.8.11", "requirements": [] }, "dyson_cloud": { "version": "0.15.0", "requirements": [ "libdyson==0.8.7" ] }, "alexa_media": { "version": "4.0.2", "requirements": [ "alexapy==1.26.0", "packaging>=20.3", "wrapt>=1.12.1" ] }, "hacs": { "version": "1.25.5", "requirements": [ "aiogithubapi>=22.2.4" ] }, "govee": { "version": "0.2.2", "requirements": [ "govee-api-laggat==0.2.2", "dacite==1.6.0" ] } }, "integration_manifest": { "domain": "zha", "name": "Zigbee Home Automation", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/zha", "requirements": [ "bellows==0.30.0", "pyserial==3.5", "pyserial-asyncio==0.6", "zha-quirks==0.0.75", "zigpy-deconz==0.16.0", "zigpy==0.45.1", "zigpy-xbee==0.14.0", "zigpy-zigate==0.7.4", "zigpy-znp==0.7.0" ], "usb": [ { "vid": "10C4", "pid": "EA60", "description": "*2652*", "known_devices": [ "slae.sh cc2652rb stick" ] }, { "vid": "10C4", "pid": "EA60", "description": "*sonoff*plus*", "known_devices": [ "sonoff zigbee dongle plus" ] }, { "vid": "10C4", "pid": "EA60", "description": "*tubeszb*", "known_devices": [ "TubesZB Coordinator" ] }, { "vid": "1A86", "pid": "7523", "description": "*tubeszb*", "known_devices": [ "TubesZB Coordinator" ] }, { "vid": "1A86", "pid": "7523", "description": "*zigstar*", "known_devices": [ "ZigStar Coordinators" ] }, { "vid": "1CF1", "pid": "0030", "description": "*conbee*", "known_devices": [ "Conbee II" ] }, { "vid": "10C4", "pid": "8A2A", "description": "*zigbee*", "known_devices": [ "Nortek HUSBZB-1" ] }, { "vid": "0403", "pid": "6015", "description": "*zigate*", "known_devices": [ "ZiGate+" ] }, { "vid": "10C4", "pid": "EA60", "description": "*zigate*", "known_devices": [ "ZiGate" ] }, { "vid": "10C4", "pid": "8B34", "description": "*bv 2010/10*", "known_devices": [ "Bitron Video AV2010/10" ] } ], "codeowners": [ "@dmulcahey", "@adminiuga" ], "zeroconf": [ { "type": "_esphomelib._tcp.local.", "name": "tube*" }, { "type": "_zigate-zigbee-gateway._tcp.local.", "name": "*zigate*" } ], "after_dependencies": [ "usb", "zeroconf" ], "iot_class": "local_polling", "loggers": [ "aiosqlite", "bellows", "crccheck", "pure_pcapy3", "zhaquirks", "zigpy", "zigpy_deconz", "zigpy_xbee", "zigpy_zigate", "zigpy_znp" ], "is_built_in": true }, "data": { "ieee": "**REDACTED**", "nwk": 53347, "manufacturer": "_TZE200_9qayzqa8", "model": "TS0601", "name": "_TZE200_9qayzqa8 TS0601", "quirk_applied": false, "quirk_class": "zigpy.device.Device", "manufacturer_code": 4417, "power_source": "Mains", "lqi": 255, "rssi": -67, "last_seen": "2022-06-11T16:27:24", "available": true, "device_type": "Router", "signature": { "node_descriptor": "NodeDescriptor(logical_type=Additional logs
``` ```Additional context https://snipboard.io/OnSaFh.jpg https://snipboard.io/40lnZe.jpg https://snipboard.io/zocPLk.jpg
Update: I tried to roll my own quirk using the info here: https://github.com/zigpy/zha-device-handlers/issues/1590 I appended the manufacturer info (_TZE200_9qayzqa8 TS0601) to the TS0601_motion.py file and put it in as a custom quirk. It does expose the occupancy entity, but never shows motion.