174 lines
5.4 KiB
Python
174 lines
5.4 KiB
Python
"""
|
|
DY-YG400A Smoke Sensor, TS0601 from _TZE204_ntcy3xu1
|
|
https://www.aliexpress.com/item/1005005863519099.html
|
|
https://www.aliexpress.com/item/1005005854203557.html
|
|
"""
|
|
|
|
import logging
|
|
|
|
import zigpy.profiles.zha
|
|
from zigpy.quirks import CustomDevice
|
|
import zigpy.types as t
|
|
from zigpy.zcl.clusters.general import (
|
|
Basic,
|
|
Groups,
|
|
Ota,
|
|
Scenes,
|
|
Time,
|
|
BinaryInput,
|
|
BatterySize,
|
|
)
|
|
from zigpy.zcl.clusters.security import IasZone
|
|
from zhaquirks import Bus
|
|
from zhaquirks.const import (
|
|
DEVICE_TYPE,
|
|
ENDPOINTS,
|
|
INPUT_CLUSTERS,
|
|
MODELS_INFO,
|
|
OUTPUT_CLUSTERS,
|
|
PROFILE_ID,
|
|
ZONE_TYPE,
|
|
)
|
|
from zhaquirks.tuya import (
|
|
TuyaLocalCluster,
|
|
TuyaManufCluster,
|
|
TuyaManufClusterAttributes,
|
|
TuyaPowerConfigurationCluster,
|
|
)
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
TUYA_SMOKE_DETECTED_ATTR = 0x0401 # [0]/[1] [Detected]/[Clear]!
|
|
TUYA_SMOKE_TAMPERED_ATTR = 0x0104 # [0]/[1] [Clear]/[Tampered]!
|
|
TUYA_SMOKE_BATTERY_ATTR = 0x040e # [0]/[1]/[2] [Low]/[Med]]/[Full]!
|
|
|
|
|
|
class TuyaSmokeDetectorCluster(TuyaManufClusterAttributes):
|
|
"""Manufacturer Specific Cluster of the TS0601 smoke detector."""
|
|
|
|
attributes = {
|
|
TUYA_SMOKE_DETECTED_ATTR: ("smoke_detected", t.uint8_t, True),
|
|
TUYA_SMOKE_TAMPERED_ATTR: ("tampered_device", t.uint8_t, True),
|
|
TUYA_SMOKE_BATTERY_ATTR: ("battery_status", t.uint8_t, True),
|
|
}
|
|
|
|
def _update_attribute(self, attrid, value):
|
|
super()._update_attribute(attrid, value)
|
|
if attrid == TUYA_SMOKE_DETECTED_ATTR:
|
|
status = IasZone.ZoneStatus.Alarm_1 if value == 0 else 0
|
|
self.endpoint.device.ias_bus.listener_event("update_attribute", "zone_status", status)
|
|
elif attrid == TUYA_SMOKE_TAMPERED_ATTR:
|
|
self.endpoint.device.tamper_detection_bus.listener_event(
|
|
"update_attribute", "present_value", bool(value)
|
|
)
|
|
elif attrid == TUYA_SMOKE_BATTERY_ATTR:
|
|
batt = 5 if value == 0 else 40 if value == 1 else 100
|
|
self.endpoint.device.battery_bus.listener_event("battery_change", batt)
|
|
else:
|
|
_LOGGER.warning(
|
|
"[0x%04x:%s:0x%04x] unhandled attribute: 0x%04x",
|
|
self.endpoint.device.nwk,
|
|
self.endpoint.endpoint_id,
|
|
self.cluster_id,
|
|
attrid,
|
|
)
|
|
|
|
|
|
class TuyaIasZone(TuyaLocalCluster, IasZone):
|
|
"""
|
|
IAS Zone: this generates the "Smoke" entity for HA.
|
|
Receives updates from TuyaSmokeDetectorCluster.
|
|
"""
|
|
|
|
_CONSTANT_ATTRIBUTES = {ZONE_TYPE: IasZone.ZoneType.Fire_Sensor}
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
"""Init."""
|
|
super().__init__(*args, **kwargs)
|
|
self.endpoint.device.ias_bus.add_listener(self)
|
|
|
|
|
|
class TuyaPowerConfigCluster(TuyaPowerConfigurationCluster):
|
|
"""
|
|
Power Config Cluster: this generates the "Battery" entity for HA.
|
|
Receives updates from TuyaSmokeDetectorCluster.
|
|
"""
|
|
|
|
_CONSTANT_ATTRIBUTES = {
|
|
TuyaPowerConfigurationCluster.attributes_by_name["battery_size"].id: BatterySize.AAA,
|
|
TuyaPowerConfigurationCluster.attributes_by_name["battery_quantity"].id: 2,
|
|
TuyaPowerConfigurationCluster.attributes_by_name["battery_rated_voltage"].id: 15,
|
|
}
|
|
|
|
|
|
class TuyaTamperDetection(TuyaLocalCluster, BinaryInput):
|
|
"""
|
|
Tamper Detection Cluster: this generates the "Binary input" entity for HA, which is updated
|
|
with the Tampered state. Receives updates from TuyaSmokeDetectorCluster.
|
|
"""
|
|
|
|
_CONSTANT_ATTRIBUTES = {
|
|
BinaryInput.attributes_by_name["description"].id: "Tamper Detected",
|
|
BinaryInput.attributes_by_name["active_text"].id: "Tampered",
|
|
BinaryInput.attributes_by_name["inactive_text"].id: "Clear",
|
|
}
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
"""Init."""
|
|
super().__init__(*args, **kwargs)
|
|
self.endpoint.device.tamper_detection_bus.add_listener(self)
|
|
|
|
|
|
class TuyaSmokeDetector0601(CustomDevice):
|
|
"""TS0601 Smoke detector quirk."""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
"""Init."""
|
|
self.ias_bus = Bus()
|
|
self.battery_bus = Bus()
|
|
self.tamper_detection_bus = Bus()
|
|
super().__init__(*args, **kwargs)
|
|
|
|
signature = {
|
|
MODELS_INFO: [
|
|
("_TZE200_uebojraa", "TS0601"),
|
|
],
|
|
ENDPOINTS: {
|
|
1: {
|
|
PROFILE_ID: zigpy.profiles.zha.PROFILE_ID,
|
|
DEVICE_TYPE: zigpy.profiles.zha.DeviceType.SMART_PLUG,
|
|
INPUT_CLUSTERS: [
|
|
Basic.cluster_id,
|
|
Groups.cluster_id,
|
|
Scenes.cluster_id,
|
|
TuyaManufCluster.cluster_id,
|
|
],
|
|
OUTPUT_CLUSTERS: [
|
|
Time.cluster_id,
|
|
Ota.cluster_id,
|
|
],
|
|
},
|
|
},
|
|
}
|
|
|
|
replacement = {
|
|
ENDPOINTS: {
|
|
1: {
|
|
PROFILE_ID: zigpy.profiles.zha.PROFILE_ID,
|
|
DEVICE_TYPE: zigpy.profiles.zha.DeviceType.IAS_ZONE,
|
|
INPUT_CLUSTERS: [
|
|
Basic.cluster_id,
|
|
Groups.cluster_id,
|
|
Scenes.cluster_id,
|
|
TuyaIasZone,
|
|
TuyaSmokeDetectorCluster,
|
|
TuyaPowerConfigCluster,
|
|
TuyaTamperDetection,
|
|
],
|
|
OUTPUT_CLUSTERS: [
|
|
Time.cluster_id,
|
|
Ota.cluster_id,
|
|
],
|
|
},
|
|
},
|
|
} |