weather station esphome and others
This commit is contained in:
BIN
custom_zha_quirks/__pycache__/ts0601_smoke.cpython-312.pyc
Normal file
BIN
custom_zha_quirks/__pycache__/ts0601_smoke.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
174
custom_zha_quirks/ts0601_smoke.py
Normal file
174
custom_zha_quirks/ts0601_smoke.py
Normal file
@@ -0,0 +1,174 @@
|
||||
"""
|
||||
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,
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
149
custom_zha_quirks/ts0601_valve_garden.py
Normal file
149
custom_zha_quirks/ts0601_valve_garden.py
Normal file
@@ -0,0 +1,149 @@
|
||||
"""Tuya valve devices."""
|
||||
|
||||
import logging
|
||||
from typing import Dict
|
||||
|
||||
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 (
|
||||
Basic,
|
||||
Groups,
|
||||
Ota,
|
||||
PowerConfiguration,
|
||||
Scenes,
|
||||
Time,
|
||||
)
|
||||
|
||||
from zhaquirks.const import (
|
||||
DEVICE_TYPE,
|
||||
ENDPOINTS,
|
||||
INPUT_CLUSTERS,
|
||||
MODELS_INFO,
|
||||
OUTPUT_CLUSTERS,
|
||||
PROFILE_ID,
|
||||
)
|
||||
from zhaquirks.tuya import NoManufacturerCluster
|
||||
from zhaquirks.tuya.mcu import (
|
||||
DPToAttributeMapping,
|
||||
TuyaAttributesCluster,
|
||||
TuyaDPType,
|
||||
TuyaLevelControl,
|
||||
TuyaMCUCluster,
|
||||
TuyaOnOff,
|
||||
TuyaOnOffNM,
|
||||
TuyaPowerConfigurationCluster,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TuyaLevelControlNM(NoManufacturerCluster, TuyaLevelControl):
|
||||
"""Tuya LevelControl cluster with NoManufacturerID."""
|
||||
|
||||
|
||||
class TuyaValveManufCluster(TuyaMCUCluster):
|
||||
"""Tuya valve manufacturer cluster."""
|
||||
|
||||
attributes = TuyaMCUCluster.attributes.copy()
|
||||
attributes.update(
|
||||
{
|
||||
0xEF03: ("dp_3", t.uint32_t, True),
|
||||
0xEF65: ("dp_101", t.uint32_t, True),
|
||||
0xEF66: ("dp_102", t.uint32_t, True), # <-- new cluster attribute with fake IDs (102=0x66).Format= ID: ("name", type, True)
|
||||
}
|
||||
)
|
||||
|
||||
dp_to_attribute: Dict[int, DPToAttributeMapping] = {
|
||||
2: DPToAttributeMapping(
|
||||
TuyaOnOffNM.ep_attribute,
|
||||
"on_off",
|
||||
dp_type=TuyaDPType.BOOL,
|
||||
),
|
||||
1: DPToAttributeMapping(
|
||||
TuyaLevelControlNM.ep_attribute,
|
||||
"current_level",
|
||||
dp_type=TuyaDPType.VALUE,
|
||||
converter=lambda x: (x * 255) // 100,
|
||||
dp_converter=lambda x: (x * 100) // 255,
|
||||
),
|
||||
3: DPToAttributeMapping(
|
||||
TuyaMCUCluster.ep_attribute,
|
||||
"dp_3",
|
||||
dp_type=TuyaDPType.VALUE,
|
||||
),
|
||||
101: DPToAttributeMapping(
|
||||
TuyaMCUCluster.ep_attribute,
|
||||
"dp_101",
|
||||
dp_type=TuyaDPType.VALUE,
|
||||
),
|
||||
102: DPToAttributeMapping( # <-- device DP102
|
||||
TuyaMCUCluster.ep_attribute, # <-- reference to the cluster which has the attribute
|
||||
"dp_102", # <-- attribute "name"
|
||||
dp_type=TuyaDPType.VALUE, # <-- DP Type it is related to the attribute type
|
||||
),
|
||||
108: DPToAttributeMapping(
|
||||
TuyaPowerConfigurationCluster.ep_attribute,
|
||||
"battery_percentage_remaining",
|
||||
dp_type=TuyaDPType.VALUE,
|
||||
),
|
||||
}
|
||||
|
||||
data_point_handlers = {
|
||||
2: "_dp_2_attr_update",
|
||||
1: "_dp_2_attr_update",
|
||||
3: "_dp_2_attr_update",
|
||||
101: "_dp_2_attr_update",
|
||||
102: "_dp_2_attr_update",
|
||||
108: "_dp_2_attr_update",
|
||||
}
|
||||
|
||||
async def write_attributes(self, attributes, manufacturer=None):
|
||||
"""Overwrite to force manufacturer code."""
|
||||
|
||||
return await super().write_attributes(
|
||||
attributes, manufacturer=foundation.ZCLHeader.NO_MANUFACTURER_ID
|
||||
)
|
||||
|
||||
|
||||
class TuyaValve(CustomDevice):
|
||||
"""Tuya valve device."""
|
||||
|
||||
signature = {
|
||||
MODELS_INFO: [("_TZE200_sh1btabb", "TS0601")],
|
||||
ENDPOINTS: {
|
||||
# <SimpleDescriptor endpoint=1 profile=260 device_type=0x0051
|
||||
# input_clusters=[0x0000, 0x0004, 0x0005, 0xef00]
|
||||
# output_clusters=[0x000a, 0x0019]>
|
||||
1: {
|
||||
PROFILE_ID: zha.PROFILE_ID,
|
||||
DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
|
||||
INPUT_CLUSTERS: [
|
||||
Basic.cluster_id,
|
||||
Groups.cluster_id,
|
||||
Scenes.cluster_id,
|
||||
TuyaValveManufCluster.cluster_id,
|
||||
],
|
||||
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
replacement = {
|
||||
ENDPOINTS: {
|
||||
1: {
|
||||
DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
|
||||
INPUT_CLUSTERS: [
|
||||
Basic.cluster_id,
|
||||
Groups.cluster_id,
|
||||
Scenes.cluster_id,
|
||||
TuyaValveManufCluster,
|
||||
TuyaOnOffNM,
|
||||
TuyaLevelControlNM,
|
||||
TuyaPowerConfigurationCluster,
|
||||
],
|
||||
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user