Files
zorruno-homeassistant/custom_zha_quirks/ts0601_motion.py
2024-12-13 14:33:44 +13:00

361 lines
12 KiB
Python

import logging
from typing import Final
from zigpy.quirks.v2 import QuirkBuilder, BinarySensorDeviceClass
import zigpy.types as t
from zigpy.zcl.foundation import ZCLAttributeDef
from zigpy.zcl.clusters.measurement import (
IlluminanceMeasurement,
OccupancySensing,
)
from zigpy.zcl.clusters.security import IasZone
from zigpy.quirks.v2.homeassistant import EntityPlatform, EntityType
from zhaquirks.tuya import (
TuyaLocalCluster,
TuyaPowerConfigurationCluster2AAA,
)
from zhaquirks.tuya.mcu import TuyaMCUCluster, DPToAttributeMapping
class PresenceState(t.enum8):
"""Presence State values"""
none = 0x00
presence = 0x01
peaceful = 0x02
small_movement = 0x03
large_movement = 0x04
class TuyaOccupancySensing(OccupancySensing, TuyaLocalCluster):
"""Tuya local OccupancySensing cluster."""
class TuyaIlluminanceMeasurement(IlluminanceMeasurement, TuyaLocalCluster):
"""Tuya local IlluminanceMeasurement cluster."""
class HumanPresenceSensorManufCluster(TuyaMCUCluster):
"""Human Presence Sensor ZG-205Z (5.8GHz)"""
class AttributeDefs(TuyaMCUCluster.AttributeDefs):
"""Tuya DataPoints attributes"""
# Presence state
presence_state: Final = ZCLAttributeDef(
id=0x0001, # DP 1
type=t.uint16_t,
access="rp",
is_manufacturer_specific=True,
)
# Target distance
target_distance: Final = ZCLAttributeDef(
id=0x0101, # DP 101
type=t.uint16_t,
access="rp",
is_manufacturer_specific=True,
)
# Illuminance value
illuminance_lux: Final = ZCLAttributeDef(
id=0x0102, # DP 102
type=t.uint16_t,
access="rp",
is_manufacturer_specific=True,
)
# None delay time (presence keep time)
none_delay_time: Final = ZCLAttributeDef(
id=0x0103, # DP 103
type=t.uint16_t,
is_manufacturer_specific=True,
)
# Indicator
indicator: Final = ZCLAttributeDef(
id=0x0104, # DP 104
type=t.Bool,
is_manufacturer_specific=True,
)
# Move detection max distance
move_detection_max: Final = ZCLAttributeDef(
id=0x0107, # DP 107
type=t.uint16_t,
is_manufacturer_specific=True,
)
# Move detection min distance
move_detection_min: Final = ZCLAttributeDef(
id=0x0108, # DP 108
type=t.uint16_t,
is_manufacturer_specific=True,
)
# Breath detection max distance
breath_detection_max: Final = ZCLAttributeDef(
id=0x0109, # DP 109
type=t.uint16_t,
is_manufacturer_specific=True,
)
# Breath detection min distance
breath_detection_min: Final = ZCLAttributeDef(
id=0x0110, # DP 110
type=t.uint16_t,
is_manufacturer_specific=True,
)
# Small move detection max distance
small_move_detection_max: Final = ZCLAttributeDef(
id=0x0114, # DP 114
type=t.uint16_t,
is_manufacturer_specific=True,
)
# Small move detection min distance
small_move_detection_min: Final = ZCLAttributeDef(
id=0x0115, # DP 115
type=t.uint16_t,
is_manufacturer_specific=True,
)
# Move sensitivity (1 is higher, 9 is lower)
move_sensitivity: Final = ZCLAttributeDef(
id=0x0116, # DP 116
type=t.uint8_t,
is_manufacturer_specific=True,
)
# Small move sensitivity
small_move_sensitivity: Final = ZCLAttributeDef(
id=0x0117, # DP 117
type=t.uint8_t,
is_manufacturer_specific=True,
)
# Breath sensitivity
breath_sensitivity: Final = ZCLAttributeDef(
id=0x0118, # DP 118
type=t.uint8_t,
is_manufacturer_specific=True,
)
dp_to_attribute: dict[int, DPToAttributeMapping] = {
1: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"presence_state",
converter=PresenceState
),
101: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"target_distance",
converter=lambda x: x / 100 if x is not None else 0
),
102: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"illuminance_lux",
),
103: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"none_delay_time",
# Value in Tuya App is 30 after Factory reset
#converter=lambda x: x if x is not None else 30
),
104: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"indicator",
),
107: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"move_detection_max",
converter=lambda x: x / 100 if x is not None else 10
),
108: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"move_detection_min",
converter=lambda x: x / 100 if x is not None else 0
),
109: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"breath_detection_max",
converter=lambda x: x / 100 if x is not None else 6
),
110: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"breath_detection_min",
converter=lambda x: x / 100 if x is not None else 0
),
114: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"small_move_detection_max",
converter=lambda x: x / 100 if x is not None else 6
),
115: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"small_move_detection_min",
converter=lambda x: x / 100 if x is not None else 0
),
116: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"move_sensitivity",
converter=lambda x: x if x is not None else 5
),
117: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"small_move_sensitivity",
converter=lambda x: x if x is not None else 5
),
118: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"breath_sensitivity",
converter=lambda x: x if x is not None else 5
),
}
data_point_handlers = {
1: "_dp_2_attr_update",
101: "_dp_2_attr_update",
102: "_dp_2_attr_update",
103: "_dp_2_attr_update",
104: "_dp_2_attr_update",
107: "_dp_2_attr_update",
108: "_dp_2_attr_update",
109: "_dp_2_attr_update",
110: "_dp_2_attr_update",
114: "_dp_2_attr_update",
115: "_dp_2_attr_update",
116: "_dp_2_attr_update",
117: "_dp_2_attr_update",
118: "_dp_2_attr_update",
}
(
QuirkBuilder("_TZE204_dapwryy7", "TS0601")
.skip_configuration()
.removes(IasZone.cluster_id)
.adds(HumanPresenceSensorManufCluster)
#.adds(TuyaOccupancySensing)
.replaces(TuyaPowerConfigurationCluster2AAA)
.replaces(TuyaIlluminanceMeasurement)
.binary_sensor(
"presence_state",
HumanPresenceSensorManufCluster.cluster_id,
endpoint_id=1,
#entity_type=EntityType.STANDARD, # very soon (zigpy channel #dev on github
device_class=BinarySensorDeviceClass.OCCUPANCY,
fallback_name="Presence"
)
.enum(
HumanPresenceSensorManufCluster.AttributeDefs.presence_state.name,
PresenceState,
HumanPresenceSensorManufCluster.cluster_id,
entity_platform=EntityPlatform.SENSOR,
entity_type=EntityType.STANDARD,
fallback_name="Presence State",
translation_key="presence_state"
)
.number(
HumanPresenceSensorManufCluster.AttributeDefs.illuminance_lux.name,
HumanPresenceSensorManufCluster.cluster_id,
step=1,
min_value=0,
max_value=2500,
fallback_name="Illuminance (lx)",
translation_key="illuminance_lux",
#entity_type=EntityType.STANDARD # not yet :/
)
.number(
HumanPresenceSensorManufCluster.AttributeDefs.target_distance.name,
HumanPresenceSensorManufCluster.cluster_id,
step=0.01,
min_value=0,
max_value=10,
fallback_name="Target Distance (m)",
translation_key="target_distance",
#entity_type=EntityType.STANDARD # not yet :/
)
.number(
HumanPresenceSensorManufCluster.AttributeDefs.none_delay_time.name,
HumanPresenceSensorManufCluster.cluster_id,
step=1,
min_value=0,
max_value=28800,
#unit="s",
fallback_name="Hold Delay Time",
translation_key="none_delay_time"
)
.switch(
HumanPresenceSensorManufCluster.AttributeDefs.indicator.name,
HumanPresenceSensorManufCluster.cluster_id,
fallback_name="LED Indicator",
translation_key="indicator"
)
.number(
HumanPresenceSensorManufCluster.AttributeDefs.move_detection_max.name,
HumanPresenceSensorManufCluster.cluster_id,
step=0.01,
min_value=0,
max_value=10,
fallback_name="Move Detection Max Distance (m)",
translation_key="move_detection_max"
)
.number(
HumanPresenceSensorManufCluster.AttributeDefs.move_detection_min.name,
HumanPresenceSensorManufCluster.cluster_id,
step=0.01,
min_value=0,
max_value=10,
fallback_name="Move Detection Min Distance (m)",
translation_key="move_detection_min"
)
.number(
HumanPresenceSensorManufCluster.AttributeDefs.small_move_detection_max.name,
HumanPresenceSensorManufCluster.cluster_id,
step=0.01,
min_value=0,
max_value=6,
fallback_name="Small Move Detection Max Distance (m)",
translation_key="small_move_detection_max"
)
.number(
HumanPresenceSensorManufCluster.AttributeDefs.small_move_detection_min.name,
HumanPresenceSensorManufCluster.cluster_id,
step=0.01,
min_value=0,
max_value=6,
fallback_name="Small Move Detection Min Distance (m)",
translation_key="small_move_detection_min"
)
.number(
HumanPresenceSensorManufCluster.AttributeDefs.breath_detection_max.name,
HumanPresenceSensorManufCluster.cluster_id,
step=0.01,
min_value=0,
max_value=6,
fallback_name="Breath Detection Max Distance (m)",
translation_key="breath_detection_max"
)
.number(
HumanPresenceSensorManufCluster.AttributeDefs.breath_detection_min.name,
HumanPresenceSensorManufCluster.cluster_id,
step=0.01,
min_value=0,
max_value=6,
fallback_name="Breath Detection Min Distance (m)",
translation_key="breath_detection_min"
)
.number(
HumanPresenceSensorManufCluster.AttributeDefs.move_sensitivity.name,
HumanPresenceSensorManufCluster.cluster_id,
step=1,
min_value=0,
max_value=10,
fallback_name="Move Sensitivity",
translation_key="move_sensitivity"
)
.number(
HumanPresenceSensorManufCluster.AttributeDefs.small_move_sensitivity.name,
HumanPresenceSensorManufCluster.cluster_id,
step=1,
min_value=0,
max_value=10,
fallback_name="Small Move Sensitivity",
translation_key="small_move_sensitivity"
)
.number(
HumanPresenceSensorManufCluster.AttributeDefs.breath_sensitivity.name,
HumanPresenceSensorManufCluster.cluster_id,
step=1,
min_value=0,
max_value=10,
fallback_name="Breath Sensitivity",
translation_key="breath_sensitivity"
)
.add_to_registry()
)