### Problem description
I've just bought a couple of these from Aliexpress (htt…ps://www.aliexpress.com/item/1005007335302133.html) and have been playing around to see if they work in HA / ZHA. I copied a quirks file I found on the HA forum and added the model references in.
I can now see controls for detection delay; fading time; max / min range; sensitivity and can see sensors for illuminance (shows unknown), occupancy (shows clear) and firmware (shows up to date)
### Solution description
Correctly operating illuminance and occupancy sensors
### Screenshots/Video
<details><summary>Screenshots/Video</summary>
[Paste/upload your media here]
</details>
### Device signature
<details><summary>Device signature</summary>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
{
"node_descriptor": {
"logical_type": 1,
"complex_descriptor_available": 0,
"user_descriptor_available": 0,
"reserved": 0,
"aps_flags": 0,
"frequency_band": 8,
"mac_capability_flags": 142,
"manufacturer_code": 4417,
"maximum_buffer_size": 66,
"maximum_incoming_transfer_size": 66,
"server_mask": 10752,
"maximum_outgoing_transfer_size": 66,
"descriptor_capability_field": 0
},
"endpoints": {
"1": {
"profile_id": "0x0104",
"device_type": "0x0107",
"input_clusters": [
"0x0000",
"0x0004",
"0x0005",
"0x000c",
"0x000d",
"0x0400",
"0x0406",
"0xef00"
],
"output_clusters": [
"0x000a",
"0x0019"
]
},
"2": {
"profile_id": "0x0104",
"device_type": "0x0007",
"input_clusters": [
"0x000d"
],
"output_clusters": []
},
"3": {
"profile_id": "0x0104",
"device_type": "0x0007",
"input_clusters": [
"0x000d"
],
"output_clusters": []
},
"4": {
"profile_id": "0x0104",
"device_type": "0x0007",
"input_clusters": [
"0x000d"
],
"output_clusters": []
},
"5": {
"profile_id": "0x0104",
"device_type": "0x0007",
"input_clusters": [
"0x000d"
],
"output_clusters": []
},
"242": {
"profile_id": "0xa1e0",
"device_type": "0x0061",
"input_clusters": [],
"output_clusters": [
"0x0021"
]
}
},
"manufacturer": "_TZE204_ex3rcdha",
"model": "TS0601",
"class": "ts0601_radar.TuyaMmwRadarOccupancyVariant1GPP"
}
</details>
### Diagnostic information
<details><summary>Diagnostic information</summary>
{
"home_assistant": {
"installation_type": "Home Assistant OS",
"version": "2024.8.2",
"dev": false,
"hassio": true,
"virtualenv": false,
"python_version": "3.12.4",
"docker": true,
"arch": "x86_64",
"timezone": "Europe/London",
"os_name": "Linux",
"os_version": "6.6.46-haos",
"supervisor": "2024.08.0",
"host_os": "Home Assistant OS 13.1",
"docker_version": "26.1.4",
"chassis": "vm",
"run_as_root": true
},
"custom_components": {
"truenas": {
"documentation": "https://github.com/tomaae/homeassistant-truenas",
"version": "0.0.0",
"requirements": []
},
"spook_inverse": {
"documentation": "https://spook.boo",
"version": "3.1.0",
"requirements": []
},
"frigate": {
"documentation": "https://github.com/blakeblackshear/frigate",
"version": "5.3.0",
"requirements": [
"pytz"
]
},
"hypervolt_charger": {
"documentation": "https://github.com/gndean/home-assistant-hypervolt-charger",
"version": "2.3.2",
"requirements": [
"websockets==11.0.3",
"aiofiles==24.1.0"
]
},
"octopus_energy": {
"documentation": "https://bottlecapdave.github.io/HomeAssistant-OctopusEnergy",
"version": "12.2.0",
"requirements": []
},
"spook": {
"documentation": "https://spook.boo",
"version": "3.1.0",
"requirements": []
},
"mass": {
"documentation": "https://music-assistant.io",
"version": "2024.8.0",
"requirements": [
"music-assistant==2.1.3"
]
},
"scrypted": {
"documentation": "https://www.home-assistant.io/integrations/scrypted",
"version": "0.0.9",
"requirements": []
},
"foxess": {
"documentation": "https://github.com/macxq/foxess-ha",
"version": "v0.4",
"requirements": [
"random_user_agent"
]
},
"uptime_kuma": {
"documentation": "https://github.com/meichthys/uptime_kuma/blob/main/README.md",
"version": "2.1.0",
"requirements": [
"pyuptimekuma-hass"
]
},
"powercalc": {
"documentation": "https://docs.powercalc.nl",
"version": "v1.14.2",
"requirements": [
"numpy>=1.21.1"
]
},
"flightradar24": {
"documentation": "https://github.com/AlexandrErohin/home-assistant-flightradar24",
"version": "1.15.0",
"requirements": [
"FlightRadarAPI==1.3.25",
"pycountry==23.12.11"
]
},
"hacs": {
"documentation": "https://hacs.xyz/docs/configuration/start",
"version": "2.0.0",
"requirements": [
"aiogithubapi>=22.10.1"
]
}
},
"integration_manifest": {
"domain": "zha",
"name": "Zigbee Home Automation",
"after_dependencies": [
"onboarding",
"usb"
],
"codeowners": [
"dmulcahey",
"adminiuga",
"puddly",
"TheJulianJES"
],
"config_flow": true,
"dependencies": [
"file_upload"
],
"documentation": "https://www.home-assistant.io/integrations/zha",
"iot_class": "local_polling",
"loggers": [
"aiosqlite",
"bellows",
"crccheck",
"pure_pcapy3",
"zhaquirks",
"zigpy",
"zigpy_deconz",
"zigpy_xbee",
"zigpy_zigate",
"zigpy_znp",
"zha",
"universal_silabs_flasher"
],
"requirements": [
"universal-silabs-flasher==0.0.22",
"zha==0.0.31"
],
"usb": [
{
"vid": "10C4",
"pid": "EA60",
"description": "*2652*",
"known_devices": [
"slae.sh cc2652rb stick"
]
},
{
"vid": "10C4",
"pid": "EA60",
"description": "*slzb-07*",
"known_devices": [
"smlight slzb-07"
]
},
{
"vid": "1A86",
"pid": "55D4",
"description": "*sonoff*plus*",
"known_devices": [
"sonoff zigbee dongle plus v2"
]
},
{
"vid": "10C4",
"pid": "EA60",
"description": "*sonoff*plus*",
"known_devices": [
"sonoff zigbee dongle plus"
]
},
{
"vid": "10C4",
"pid": "EA60",
"description": "*tubeszb*",
"known_devices": [
"TubesZB Coordinator"
]
},
{
"vid": "1A86",
"pid": "7523",
"description": "*tubeszb*",
"known_devices": [
"TubesZB Coordinator"
]
},
{
"vid": "1A86",
"pid": "7523",
"description": "*zigstar*",
"known_devices": [
"ZigStar Coordinators"
]
},
{
"vid": "1CF1",
"pid": "0030",
"description": "*conbee*",
"known_devices": [
"Conbee II"
]
},
{
"vid": "0403",
"pid": "6015",
"description": "*conbee*",
"known_devices": [
"Conbee III"
]
},
{
"vid": "10C4",
"pid": "8A2A",
"description": "*zigbee*",
"known_devices": [
"Nortek HUSBZB-1"
]
},
{
"vid": "0403",
"pid": "6015",
"description": "*zigate*",
"known_devices": [
"ZiGate+"
]
},
{
"vid": "10C4",
"pid": "EA60",
"description": "*zigate*",
"known_devices": [
"ZiGate"
]
},
{
"vid": "10C4",
"pid": "8B34",
"description": "*bv 2010/10*",
"known_devices": [
"Bitron Video AV2010/10"
]
}
],
"zeroconf": [
{
"type": "_esphomelib._tcp.local.",
"name": "tube*"
},
{
"type": "_zigate-zigbee-gateway._tcp.local.",
"name": "*zigate*"
},
{
"type": "_zigstar_gw._tcp.local.",
"name": "*zigstar*"
},
{
"type": "_uzg-01._tcp.local.",
"name": "uzg-01*"
},
{
"type": "_slzb-06._tcp.local.",
"name": "slzb-06*"
},
{
"type": "_xzg._tcp.local.",
"name": "xzg*"
},
{
"type": "_czc._tcp.local.",
"name": "czc*"
}
],
"is_built_in": true
},
"setup_times": {
"null": {
"setup": 0.00018496799999923041
},
"1939130f5ea2867d4ad08cc2b59a92ce": {
"wait_import_platforms": -0.07864109599999836,
"config_entry_setup": 20.42540425099999
}
},
"data": {
"ieee": "**REDACTED**",
"nwk": 9290,
"manufacturer": "_TZE204_ex3rcdha",
"model": "TS0601",
"name": "_TZE204_ex3rcdha TS0601",
"quirk_applied": true,
"quirk_class": "ts0601_radar.TuyaMmwRadarOccupancyVariant1GPP",
"quirk_id": null,
"manufacturer_code": 4417,
"power_source": "Mains",
"lqi": 36,
"rssi": null,
"last_seen": "2024-08-22T10:21:22",
"available": true,
"device_type": "Router",
"signature": {
"node_descriptor": {
"logical_type": 1,
"complex_descriptor_available": 0,
"user_descriptor_available": 0,
"reserved": 0,
"aps_flags": 0,
"frequency_band": 8,
"mac_capability_flags": 142,
"manufacturer_code": 4417,
"maximum_buffer_size": 66,
"maximum_incoming_transfer_size": 66,
"server_mask": 10752,
"maximum_outgoing_transfer_size": 66,
"descriptor_capability_field": 0
},
"endpoints": {
"1": {
"profile_id": "0x0104",
"device_type": "0x0107",
"input_clusters": [
"0x0000",
"0x0004",
"0x0005",
"0x000c",
"0x000d",
"0x0400",
"0x0406",
"0xef00"
],
"output_clusters": [
"0x000a",
"0x0019"
]
},
"2": {
"profile_id": "0x0104",
"device_type": "0x0007",
"input_clusters": [
"0x000d"
],
"output_clusters": []
},
"3": {
"profile_id": "0x0104",
"device_type": "0x0007",
"input_clusters": [
"0x000d"
],
"output_clusters": []
},
"4": {
"profile_id": "0x0104",
"device_type": "0x0007",
"input_clusters": [
"0x000d"
],
"output_clusters": []
},
"5": {
"profile_id": "0x0104",
"device_type": "0x0007",
"input_clusters": [
"0x000d"
],
"output_clusters": []
},
"242": {
"profile_id": "0xa1e0",
"device_type": "0x0061",
"input_clusters": [],
"output_clusters": [
"0x0021"
]
}
},
"manufacturer": "_TZE204_ex3rcdha",
"model": "TS0601"
},
"active_coordinator": false,
"entities": [
{
"entity_id": "binary_sensor.zigbee_presence_2_small_occupancy",
"name": "_TZE204_ex3rcdha TS0601"
},
{
"entity_id": "number.zigbee_presence_2_small_number_sensitivity",
"name": "_TZE204_ex3rcdha TS0601"
},
{
"entity_id": "number.zigbee_presence_2_small_number_min_range",
"name": "_TZE204_ex3rcdha TS0601"
},
{
"entity_id": "number.zigbee_presence_2_small_number_max_range",
"name": "_TZE204_ex3rcdha TS0601"
},
{
"entity_id": "number.zigbee_presence_2_small_number_detection_delay",
"name": "_TZE204_ex3rcdha TS0601"
},
{
"entity_id": "number.zigbee_presence_2_small_number_fading_time",
"name": "_TZE204_ex3rcdha TS0601"
},
{
"entity_id": "sensor.zigbee_presence_2_small_illuminance",
"name": "_TZE204_ex3rcdha TS0601"
},
{
"entity_id": "update.zigbee_presence_2_small_firmware",
"name": "_TZE204_ex3rcdha TS0601"
}
],
"neighbors": [
{
"device_type": "Router",
"rx_on_when_idle": "On",
"relationship": "Parent",
"extended_pan_id": "**REDACTED**",
"ieee": "**REDACTED**",
"nwk": "0x1B1F",
"permit_joining": "Unknown",
"depth": "2",
"lqi": "151"
},
{
"device_type": "Router",
"rx_on_when_idle": "On",
"relationship": "Sibling",
"extended_pan_id": "**REDACTED**",
"ieee": "**REDACTED**",
"nwk": "0x771B",
"permit_joining": "Unknown",
"depth": "0",
"lqi": "15"
},
{
"device_type": "Router",
"rx_on_when_idle": "On",
"relationship": "Sibling",
"extended_pan_id": "**REDACTED**",
"ieee": "**REDACTED**",
"nwk": "0x7A23",
"permit_joining": "Unknown",
"depth": "0",
"lqi": "51"
},
{
"device_type": "Router",
"rx_on_when_idle": "On",
"relationship": "Sibling",
"extended_pan_id": "**REDACTED**",
"ieee": "**REDACTED**",
"nwk": "0x4D60",
"permit_joining": "Unknown",
"depth": "0",
"lqi": "69"
},
{
"device_type": "Router",
"rx_on_when_idle": "On",
"relationship": "Sibling",
"extended_pan_id": "**REDACTED**",
"ieee": "**REDACTED**",
"nwk": "0x1EE3",
"permit_joining": "Unknown",
"depth": "0",
"lqi": "15"
},
{
"device_type": "Coordinator",
"rx_on_when_idle": "On",
"relationship": "Sibling",
"extended_pan_id": "**REDACTED**",
"ieee": "**REDACTED**",
"nwk": "0x0000",
"permit_joining": "Unknown",
"depth": "0",
"lqi": "36"
},
{
"device_type": "Router",
"rx_on_when_idle": "On",
"relationship": "Sibling",
"extended_pan_id": "**REDACTED**",
"ieee": "**REDACTED**",
"nwk": "0x242D",
"permit_joining": "Unknown",
"depth": "0",
"lqi": "30"
},
{
"device_type": "Router",
"rx_on_when_idle": "On",
"relationship": "Sibling",
"extended_pan_id": "**REDACTED**",
"ieee": "**REDACTED**",
"nwk": "0x46E5",
"permit_joining": "Unknown",
"depth": "0",
"lqi": "0"
}
],
"routes": [],
"endpoint_names": [
{
"name": "OCCUPANCY_SENSOR"
},
{
"name": "COMBINED_INTERFACE"
},
{
"name": "COMBINED_INTERFACE"
},
{
"name": "COMBINED_INTERFACE"
},
{
"name": "COMBINED_INTERFACE"
},
{
"name": "PROXY_BASIC"
}
],
"user_given_name": "ZigBee Presence 2 small",
"device_reg_id": "6a3b86ff04cd4ccc64ae5027c75088d6",
"area_id": null,
"cluster_details": {
"1": {
"device_type": {
"name": "OCCUPANCY_SENSOR",
"id": 263
},
"profile_id": 260,
"in_clusters": {
"0x0000": {
"endpoint_attribute": "basic",
"attributes": {
"0x0001": {
"attribute_name": "app_version",
"value": 74
},
"0x0004": {
"attribute_name": "manufacturer",
"value": "_TZE204_ex3rcdha"
},
"0x0005": {
"attribute_name": "model",
"value": "TS0601"
}
},
"unsupported_attributes": {}
},
"0x0004": {
"endpoint_attribute": "groups",
"attributes": {},
"unsupported_attributes": {}
},
"0x0005": {
"endpoint_attribute": "scenes",
"attributes": {},
"unsupported_attributes": {}
},
"0xef00": {
"endpoint_attribute": "tuya_manufacturer",
"attributes": {
"0xef00": {
"attribute_name": "mcu_version",
"value": "1.0.2"
}
},
"unsupported_attributes": {}
},
"0x0400": {
"endpoint_attribute": "illuminance",
"attributes": {},
"unsupported_attributes": {
"0x0000": {
"attribute_name": "measured_value"
}
}
},
"0x0406": {
"endpoint_attribute": "occupancy",
"attributes": {},
"unsupported_attributes": {
"0x0000": {
"attribute_name": "occupancy"
}
}
},
"0x000c": {
"endpoint_attribute": "analog_input",
"attributes": {
"0x001c": {
"attribute_name": "description",
"value": "Target distance"
},
"0x0075": {
"attribute_name": "engineering_units",
"value": 31
}
},
"unsupported_attributes": {}
},
"0x000d": {
"endpoint_attribute": "analog_output",
"attributes": {
"0x001c": {
"attribute_name": "description",
"value": "Sensitivity"
},
"0x0041": {
"attribute_name": "max_present_value",
"value": 9
},
"0x0045": {
"attribute_name": "min_present_value",
"value": 1
},
"0x006a": {
"attribute_name": "resolution",
"value": 1
}
},
"unsupported_attributes": {}
}
},
"out_clusters": {
"0x000a": {
"endpoint_attribute": "time",
"attributes": {},
"unsupported_attributes": {}
},
"0x0019": {
"endpoint_attribute": "ota",
"attributes": {
"0x0002": {
"attribute_name": "current_file_version",
"value": 74
}
},
"unsupported_attributes": {}
}
}
},
"2": {
"device_type": {
"name": "COMBINED_INTERFACE",
"id": 7
},
"profile_id": 260,
"in_clusters": {
"0x000d": {
"endpoint_attribute": "analog_output",
"attributes": {
"0x001c": {
"attribute_name": "description",
"value": "Min range"
},
"0x0075": {
"attribute_name": "engineering_units",
"value": 118
},
"0x0041": {
"attribute_name": "max_present_value",
"value": 950
},
"0x0045": {
"attribute_name": "min_present_value",
"value": 0
},
"0x006a": {
"attribute_name": "resolution",
"value": 10
}
},
"unsupported_attributes": {}
}
},
"out_clusters": {}
},
"3": {
"device_type": {
"name": "COMBINED_INTERFACE",
"id": 7
},
"profile_id": 260,
"in_clusters": {
"0x000d": {
"endpoint_attribute": "analog_output",
"attributes": {
"0x001c": {
"attribute_name": "description",
"value": "Max range"
},
"0x0075": {
"attribute_name": "engineering_units",
"value": 118
},
"0x0041": {
"attribute_name": "max_present_value",
"value": 950
},
"0x0045": {
"attribute_name": "min_present_value",
"value": 10
},
"0x006a": {
"attribute_name": "resolution",
"value": 10
}
},
"unsupported_attributes": {}
}
},
"out_clusters": {}
},
"4": {
"device_type": {
"name": "COMBINED_INTERFACE",
"id": 7
},
"profile_id": 260,
"in_clusters": {
"0x000d": {
"endpoint_attribute": "analog_output",
"attributes": {
"0x001c": {
"attribute_name": "description",
"value": "Detection delay"
},
"0x0075": {
"attribute_name": "engineering_units",
"value": 159
},
"0x0041": {
"attribute_name": "max_present_value",
"value": 20000
},
"0x0045": {
"attribute_name": "min_present_value",
"value": 0
},
"0x0055": {
"attribute_name": "present_value",
"value": 0
},
"0x006a": {
"attribute_name": "resolution",
"value": 100
}
},
"unsupported_attributes": {}
}
},
"out_clusters": {}
},
"5": {
"device_type": {
"name": "COMBINED_INTERFACE",
"id": 7
},
"profile_id": 260,
"in_clusters": {
"0x000d": {
"endpoint_attribute": "analog_output",
"attributes": {
"0x001c": {
"attribute_name": "description",
"value": "Fading time"
},
"0x0075": {
"attribute_name": "engineering_units",
"value": 159
},
"0x0041": {
"attribute_name": "max_present_value",
"value": 200000
},
"0x0045": {
"attribute_name": "min_present_value",
"value": 2000
},
"0x006a": {
"attribute_name": "resolution",
"value": 1000
}
},
"unsupported_attributes": {}
}
},
"out_clusters": {}
},
"242": {
"device_type": {
"name": "PROXY_BASIC",
"id": 97
},
"profile_id": 41440,
"in_clusters": {},
"out_clusters": {
"0x0021": {
"endpoint_attribute": "green_power",
"attributes": {},
"unsupported_attributes": {}
}
}
}
}
}
}
</details>
### Logs
<details><summary>Logs</summary>
```python
[Paste the logs here]
```
</details>
### Custom quirk
<details><summary>Custom quirk</summary>
"""Tuya mmw radar occupancy sensor."""
#https://github.com/zigpy/zha-device-handlers/issues/2457
import math
from typing import Dict
from zigpy.profiles import zgp, zha
from zigpy.quirks import CustomDevice
import zigpy.types as t
from zigpy.zcl.clusters.general import (
AnalogInput,
AnalogOutput,
Basic,
GreenPowerProxy,
Groups,
Ota,
Scenes,
Time,
)
from zigpy.zcl.clusters.measurement import IlluminanceMeasurement, OccupancySensing
from zhaquirks.const import (
DEVICE_TYPE,
ENDPOINTS,
INPUT_CLUSTERS,
MODELS_INFO,
OUTPUT_CLUSTERS,
PROFILE_ID,
)
from zhaquirks.tuya import NoManufacturerCluster, TuyaLocalCluster, TuyaNewManufCluster
from zhaquirks.tuya.mcu import (
DPToAttributeMapping,
TuyaAttributesCluster,
TuyaMCUCluster,
)
ZONE_TYPE = 0x0001
class TuyaMmwRadarSelfTest(t.enum8):
"""Mmw radar self test values."""
TESTING = 0
TEST_SUCCESS = 1
TEST_FAILURE = 2
OTHER = 3
COMM_FAULT = 4
RADAR_FAULT = 5
class TuyaOccupancySensing(OccupancySensing, TuyaLocalCluster):
"""Tuya local OccupancySensing cluster."""
class TuyaAnalogInput(AnalogInput, TuyaLocalCluster):
"""Tuya local AnalogInput cluster."""
class TuyaIlluminanceMeasurement(IlluminanceMeasurement, TuyaLocalCluster):
"""Tuya local IlluminanceMeasurement cluster."""
class TuyaMmwRadarSensitivity(TuyaAttributesCluster, AnalogOutput):
"""AnalogOutput cluster for sensitivity."""
def __init__(self, *args, **kwargs):
"""Init."""
super().__init__(*args, **kwargs)
self._update_attribute(self.attributes_by_name["description"].id, "Sensitivity")
self._update_attribute(self.attributes_by_name["min_present_value"].id, 1)
self._update_attribute(self.attributes_by_name["max_present_value"].id, 9)
self._update_attribute(self.attributes_by_name["resolution"].id, 1)
class TuyaMmwRadarMinRange(TuyaAttributesCluster, AnalogOutput):
"""AnalogOutput cluster for min range."""
def __init__(self, *args, **kwargs):
"""Init."""
super().__init__(*args, **kwargs)
self._update_attribute(self.attributes_by_name["description"].id, "Min range")
self._update_attribute(self.attributes_by_name["min_present_value"].id, 0)
self._update_attribute(self.attributes_by_name["max_present_value"].id, 950)
self._update_attribute(self.attributes_by_name["resolution"].id, 10)
self._update_attribute(
self.attributes_by_name["engineering_units"].id, 118
) # 31: meters
class TuyaMmwRadarMaxRange(TuyaAttributesCluster, AnalogOutput):
"""AnalogOutput cluster for max range."""
def __init__(self, *args, **kwargs):
"""Init."""
super().__init__(*args, **kwargs)
self._update_attribute(self.attributes_by_name["description"].id, "Max range")
self._update_attribute(self.attributes_by_name["min_present_value"].id, 10)
self._update_attribute(self.attributes_by_name["max_present_value"].id, 950)
self._update_attribute(self.attributes_by_name["resolution"].id, 10)
self._update_attribute(
self.attributes_by_name["engineering_units"].id, 118
) # 31: meters
class TuyaMmwRadarDetectionDelay(TuyaAttributesCluster, AnalogOutput):
"""AnalogOutput cluster for detection delay."""
def __init__(self, *args, **kwargs):
"""Init."""
super().__init__(*args, **kwargs)
self._update_attribute(
self.attributes_by_name["description"].id, "Detection delay"
)
self._update_attribute(self.attributes_by_name["min_present_value"].id, 000)
self._update_attribute(self.attributes_by_name["max_present_value"].id, 20000)
self._update_attribute(self.attributes_by_name["resolution"].id, 100)
self._update_attribute(
self.attributes_by_name["engineering_units"].id, 159
) # 73: seconds
class TuyaMmwRadarFadingTime(TuyaAttributesCluster, AnalogOutput):
"""AnalogOutput cluster for fading time."""
def __init__(self, *args, **kwargs):
"""Init."""
super().__init__(*args, **kwargs)
self._update_attribute(self.attributes_by_name["description"].id, "Fading time")
self._update_attribute(self.attributes_by_name["min_present_value"].id, 2000)
self._update_attribute(self.attributes_by_name["max_present_value"].id, 200000)
self._update_attribute(self.attributes_by_name["resolution"].id, 1000)
self._update_attribute(
self.attributes_by_name["engineering_units"].id, 159
) # 73: seconds
class TuyaMmwRadarTargetDistance(TuyaAttributesCluster, AnalogInput):
"""AnalogInput cluster for target distance."""
def __init__(self, *args, **kwargs):
"""Init."""
super().__init__(*args, **kwargs)
self._update_attribute(
self.attributes_by_name["description"].id, "Target distance"
)
self._update_attribute(
self.attributes_by_name["engineering_units"].id, 31
) # 31: meters
class TuyaMmwRadarClusterBase(NoManufacturerCluster, TuyaMCUCluster):
"""Mmw radar cluster, base class."""
attributes = TuyaMCUCluster.attributes.copy()
attributes.update(
{
# ramdom attribute IDs
0xEF01: ("occupancy", t.uint32_t, True),
0xEF02: ("sensitivity", t.uint32_t, True),
0xEF03: ("min_range", t.uint32_t, True),
0xEF04: ("max_range", t.uint32_t, True),
0xEF06: ("self_test", TuyaMmwRadarSelfTest, True),
0xEF09: ("target_distance", t.uint32_t, True),
0xEF65: ("detection_delay", t.uint32_t, True),
0xEF66: ("fading_time", t.uint32_t, True),
0xEF67: ("cli", t.CharacterString, True),
0xEF68: ("illuminance", t.uint32_t, True),
}
)
class TuyaMmwRadarClusterVariant1(TuyaMmwRadarClusterBase):
"""Mmw radar cluster, variant 1."""
dp_to_attribute: Dict[int, DPToAttributeMapping] = {
1: DPToAttributeMapping(
TuyaOccupancySensing.ep_attribute,
"occupancy",
),
2: DPToAttributeMapping(
TuyaMmwRadarSensitivity.ep_attribute,
"present_value",
),
3: DPToAttributeMapping(
TuyaMmwRadarMinRange.ep_attribute,
"present_value",
endpoint_id=2,
),
4: DPToAttributeMapping(
TuyaMmwRadarMaxRange.ep_attribute,
"present_value",
endpoint_id=3,
),
6: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"self_test",
),
9: DPToAttributeMapping(
TuyaMmwRadarTargetDistance.ep_attribute,
"present_value",
lambda x: x / 100,
),
101: DPToAttributeMapping(
TuyaMmwRadarDetectionDelay.ep_attribute,
"present_value",
converter=lambda x: x * 100,
dp_converter=lambda x: x // 100,
endpoint_id=4,
),
102: DPToAttributeMapping(
TuyaMmwRadarFadingTime.ep_attribute,
"present_value",
converter=lambda x: x * 100,
dp_converter=lambda x: x // 100,
endpoint_id=5,
),
103: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"cli",
),
104: DPToAttributeMapping(
TuyaIlluminanceMeasurement.ep_attribute,
"measured_value",
converter=lambda x: int(math.log10(x) * 10000 + 1) if x > 0 else int(0),
),
}
data_point_handlers = {
1: "_dp_2_attr_update",
2: "_dp_2_attr_update",
3: "_dp_2_attr_update",
4: "_dp_2_attr_update",
6: "_dp_2_attr_update",
9: "_dp_2_attr_update",
101: "_dp_2_attr_update",
102: "_dp_2_attr_update",
103: "_dp_2_attr_update",
104: "_dp_2_attr_update",
}
class TuyaMmwRadarOccupancyVariant1(CustomDevice):
"""Millimeter wave occupancy sensor, variant 1."""
signature = {
# endpoint=1, profile=260, device_type=81, device_version=1,
# input_clusters=[0, 4, 5, 61184], output_clusters=[25, 10]
MODELS_INFO: [
("_TZE200_ar0slwnd", "TS0601"),
("_TZE200_sfiy5tfs", "TS0601"),
("_TZE200_mrf6vtua", "TS0601"),
("_TZE200_ztc6ggyl", "TS0601"),
("_TZE204_ztc6ggyl", "TS0601"),
("_TZE200_wukb7rhc", "TS0601"),
("_TZE204_qasjif9e", "TS0601"),
("_TZE204_dtzziy1e", "TS0601"),
("_TZE204_sbyx0lm6", "TS0601"),
("_TZE204_ex3rcdha", "TS0601"),
],
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
INPUT_CLUSTERS: [
Basic.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
TuyaNewManufCluster.cluster_id,
],
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
},
},
}
replacement = {
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.OCCUPANCY_SENSOR,
INPUT_CLUSTERS: [
Basic.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
TuyaMmwRadarClusterVariant1,
TuyaIlluminanceMeasurement,
TuyaOccupancySensing,
TuyaMmwRadarTargetDistance,
TuyaMmwRadarSensitivity,
],
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
},
2: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
INPUT_CLUSTERS: [
TuyaMmwRadarMinRange,
],
OUTPUT_CLUSTERS: [],
},
3: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
INPUT_CLUSTERS: [
TuyaMmwRadarMaxRange,
],
OUTPUT_CLUSTERS: [],
},
4: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
INPUT_CLUSTERS: [
TuyaMmwRadarDetectionDelay,
],
OUTPUT_CLUSTERS: [],
},
5: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
INPUT_CLUSTERS: [
TuyaMmwRadarFadingTime,
],
OUTPUT_CLUSTERS: [],
},
}
}
class TuyaMmwRadarOccupancyVariant1GPP(CustomDevice):
"""Millimeter wave occupancy sensor, variant 1 with GPP."""
signature = {
# endpoint=1, profile=260, device_type=81, device_version=1,
# input_clusters=[0, 4, 5, 61184], output_clusters=[25, 10])
MODELS_INFO: [
("_TZE200_ar0slwnd", "TS0601"),
("_TZE200_sfiy5tfs", "TS0601"),
("_TZE200_mrf6vtua", "TS0601"),
("_TZE204_qasjif9e", "TS0601"),
("_TZE204_sbyx0lm6", "TS0601"),
("_TZE204_ex3rcdha", "TS0601"),
],
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
INPUT_CLUSTERS: [
Basic.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
TuyaNewManufCluster.cluster_id,
],
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
},
242: {
# <SimpleDescriptor endpoint=242 profile=41440 device_type=97
# input_clusters=[]
# output_clusters=[33]
PROFILE_ID: zgp.PROFILE_ID,
DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
},
},
}
replacement = {
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.OCCUPANCY_SENSOR,
INPUT_CLUSTERS: [
Basic.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
TuyaMmwRadarClusterVariant1,
TuyaIlluminanceMeasurement,
TuyaOccupancySensing,
TuyaMmwRadarTargetDistance,
TuyaMmwRadarSensitivity,
],
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
},
2: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
INPUT_CLUSTERS: [
TuyaMmwRadarMinRange,
],
OUTPUT_CLUSTERS: [],
},
3: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
INPUT_CLUSTERS: [
TuyaMmwRadarMaxRange,
],
OUTPUT_CLUSTERS: [],
},
4: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
INPUT_CLUSTERS: [
TuyaMmwRadarDetectionDelay,
],
OUTPUT_CLUSTERS: [],
},
5: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
INPUT_CLUSTERS: [
TuyaMmwRadarFadingTime,
],
OUTPUT_CLUSTERS: [],
},
242: {
PROFILE_ID: zgp.PROFILE_ID,
DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
},
}
}
class TuyaMmwRadarClusterVariant2(TuyaMmwRadarClusterBase):
"""Tuya MMW radar cluster, variant 2."""
dp_to_attribute: Dict[int, DPToAttributeMapping] = {
103: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"cli",
),
104: DPToAttributeMapping(
TuyaIlluminanceMeasurement.ep_attribute,
"measured_value",
converter=lambda x: int(math.log10(x) * 10000 + 1) if x > 0 else int(0),
),
105: DPToAttributeMapping(
TuyaOccupancySensing.ep_attribute,
"occupancy",
),
106: DPToAttributeMapping(
TuyaMmwRadarSensitivity.ep_attribute,
"present_value",
),
107: DPToAttributeMapping(
TuyaMmwRadarMaxRange.ep_attribute,
"present_value",
endpoint_id=3,
),
108: DPToAttributeMapping(
TuyaMmwRadarMinRange.ep_attribute,
"present_value",
endpoint_id=2,
),
109: DPToAttributeMapping(
TuyaMmwRadarTargetDistance.ep_attribute,
"present_value",
),
110: DPToAttributeMapping(
TuyaMmwRadarFadingTime.ep_attribute,
"present_value",
converter=lambda x: x * 100,
dp_converter=lambda x: x // 100,
endpoint_id=5,
),
111: DPToAttributeMapping(
TuyaMmwRadarDetectionDelay.ep_attribute,
"present_value",
converter=lambda x: x * 100,
dp_converter=lambda x: x // 100,
endpoint_id=4,
),
}
data_point_handlers = {
103: "_dp_2_attr_update",
104: "_dp_2_attr_update",
105: "_dp_2_attr_update",
106: "_dp_2_attr_update",
107: "_dp_2_attr_update",
108: "_dp_2_attr_update",
109: "_dp_2_attr_update",
110: "_dp_2_attr_update",
111: "_dp_2_attr_update",
}
class TuyaMmwRadarOccupancyVariant2(CustomDevice):
"""Millimeter wave occupancy sensor, variant 2."""
signature = {
# endpoint=1, profile=260, device_type=81, device_version=1,
# input_clusters=[0, 4, 5, 61184], output_clusters=[25, 10])
MODELS_INFO: [
("_TZE204_sxm7l9xa", "TS0601"),
("_TZE204_bmdsp6bs", "TS0601"),
],
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
INPUT_CLUSTERS: [
Basic.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
TuyaNewManufCluster.cluster_id,
],
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
},
242: {
# <SimpleDescriptor endpoint=242 profile=41440 device_type=97
# input_clusters=[]
# output_clusters=[33]
PROFILE_ID: zgp.PROFILE_ID,
DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
},
},
}
replacement = {
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.OCCUPANCY_SENSOR,
INPUT_CLUSTERS: [
Basic.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
TuyaMmwRadarClusterVariant2,
TuyaIlluminanceMeasurement,
TuyaOccupancySensing,
TuyaMmwRadarTargetDistance,
TuyaMmwRadarSensitivity,
],
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
},
2: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
INPUT_CLUSTERS: [
TuyaMmwRadarMinRange,
],
OUTPUT_CLUSTERS: [],
},
3: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
INPUT_CLUSTERS: [
TuyaMmwRadarMaxRange,
],
OUTPUT_CLUSTERS: [],
},
4: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
INPUT_CLUSTERS: [
TuyaMmwRadarDetectionDelay,
],
OUTPUT_CLUSTERS: [],
},
5: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
INPUT_CLUSTERS: [
TuyaMmwRadarFadingTime,
],
OUTPUT_CLUSTERS: [],
},
242: {
PROFILE_ID: zgp.PROFILE_ID,
DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
},
}
}
</details>
### Additional information
_No response_