From a99f27e1316e41fbed5967ec65f4da53d6c4d6bb Mon Sep 17 00:00:00 2001 From: abmantis Date: Mon, 2 Dec 2024 01:46:12 +0000 Subject: [PATCH 1/4] Add TS0601 3 phase meter --- zhaquirks/tuya/__init__.py | 9 ++ zhaquirks/tuya/ts0601_din_power.py | 202 ++++++++++++++++++++++++++++- 2 files changed, 210 insertions(+), 1 deletion(-) diff --git a/zhaquirks/tuya/__init__.py b/zhaquirks/tuya/__init__.py index ac4554faac..152a93accf 100644 --- a/zhaquirks/tuya/__init__.py +++ b/zhaquirks/tuya/__init__.py @@ -1594,6 +1594,15 @@ def handle_get_data(self, command: TuyaCommand) -> foundation.Status: dp_error = True # return foundation.Status.UNSUPPORTED_ATTRIBUTE + _LOGGER.debug( + "[0x%04x:%s:0x%04x] Received value %s " "for attribute 0x%04x", + self.endpoint.device.nwk, + self.endpoint.endpoint_id, + self.cluster_id, + record.data.payload, + record.dp, + ) + return ( foundation.Status.SUCCESS if not dp_error diff --git a/zhaquirks/tuya/ts0601_din_power.py b/zhaquirks/tuya/ts0601_din_power.py index d9c1b76a25..02fcb30b55 100644 --- a/zhaquirks/tuya/ts0601_din_power.py +++ b/zhaquirks/tuya/ts0601_din_power.py @@ -1,6 +1,8 @@ """Tuya Din Power Meter.""" from zigpy.profiles import zha +from zigpy.quirks.v2 import SensorDeviceClass, SensorStateClass +from zigpy.quirks.v2.homeassistant import UnitOfEnergy import zigpy.types as t from zigpy.zcl.clusters.general import Basic, Groups, Ota, Scenes, Time from zigpy.zcl.clusters.homeautomation import ElectricalMeasurement @@ -15,7 +17,13 @@ OUTPUT_CLUSTERS, PROFILE_ID, ) -from zhaquirks.tuya import TuyaManufClusterAttributes, TuyaOnOff, TuyaSwitch +from zhaquirks.tuya import ( + TuyaLocalCluster, + TuyaManufClusterAttributes, + TuyaOnOff, + TuyaSwitch, +) +from zhaquirks.tuya.builder import TuyaQuirkBuilder TUYA_TOTAL_ENERGY_ATTR = 0x0211 TUYA_CURRENT_ATTR = 0x0212 @@ -233,6 +241,198 @@ def __init__(self, *args, **kwargs): } +class Tuya3PhaseElectricalMeasurement(ElectricalMeasurement, TuyaLocalCluster): + """Tuya Electrical Measurement cluster.""" + + _CONSTANT_ATTRIBUTES = { + ElectricalMeasurement.AttributeDefs.ac_current_divisor.id: 1000, + ElectricalMeasurement.AttributeDefs.ac_voltage_divisor.id: 10, + ElectricalMeasurement.AttributeDefs.ac_frequency_divisor.id: 100, + } + + +( + TuyaQuirkBuilder("_TZE204_ugekduaj", "TS0601") + .tuya_dp( + dp_id=0x65, + ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, + attribute_name="ac_frequency", + ) + # Energy consumed + .tuya_sensor( + dp_id=0x01, + attribute_name="energy_consumed", + type=t.uint32_t, + divisor=100, + state_class=SensorStateClass.TOTAL_INCREASING, + device_class=SensorDeviceClass.ENERGY, + unit=UnitOfEnergy.KILO_WATT_HOUR, + translation_key="total_energy", + fallback_name="Total energy", + ) + .tuya_sensor( + dp_id=0x70, + attribute_name="energy_consumed_ph_a", + type=t.uint32_t, + divisor=100, + state_class=SensorStateClass.TOTAL_INCREASING, + device_class=SensorDeviceClass.ENERGY, + unit=UnitOfEnergy.KILO_WATT_HOUR, + translation_key="energy", + fallback_name="Energy", + ) + .tuya_sensor( + dp_id=0x72, + attribute_name="energy_consumed_ph_b", + type=t.uint32_t, + divisor=100, + state_class=SensorStateClass.TOTAL_INCREASING, + device_class=SensorDeviceClass.ENERGY, + unit=UnitOfEnergy.KILO_WATT_HOUR, + translation_key="energy_2", + fallback_name="Energy 2", + ) + .tuya_sensor( + dp_id=0x74, + attribute_name="energy_consumed_ph_c", + divisor=100, + type=t.uint32_t, + state_class=SensorStateClass.TOTAL_INCREASING, + device_class=SensorDeviceClass.ENERGY, + unit=UnitOfEnergy.KILO_WATT_HOUR, + translation_key="energy_3", + fallback_name="Energy 3", + ) + # Energy produced + .tuya_sensor( + dp_id=0x02, + attribute_name="energy_produced", + type=t.uint32_t, + divisor=100, + state_class=SensorStateClass.TOTAL_INCREASING, + device_class=SensorDeviceClass.ENERGY, + unit=UnitOfEnergy.KILO_WATT_HOUR, + translation_key="total_energy_produced", + fallback_name="Total energy produced", + ) + .tuya_sensor( + dp_id=0x71, + attribute_name="energy_produced_ph_a", + type=t.uint32_t, + converter=lambda x: x / 100, + state_class=SensorStateClass.TOTAL_INCREASING, + device_class=SensorDeviceClass.ENERGY, + unit=UnitOfEnergy.KILO_WATT_HOUR, + translation_key="energy_produced", + fallback_name="Energy produced", + ) + .tuya_sensor( + dp_id=0x73, + attribute_name="energy_produced_ph_b", + type=t.uint32_t, + divisor=100, + state_class=SensorStateClass.TOTAL_INCREASING, + device_class=SensorDeviceClass.ENERGY, + unit=UnitOfEnergy.KILO_WATT_HOUR, + translation_key="energy_produced_2", + fallback_name="Energy produced 2", + ) + .tuya_sensor( + dp_id=0x75, + attribute_name="energy_produced_ph_c", + type=t.uint32_t, + divisor=100, + state_class=SensorStateClass.TOTAL_INCREASING, + device_class=SensorDeviceClass.ENERGY, + unit=UnitOfEnergy.KILO_WATT_HOUR, + translation_key="energy_produced_3", + fallback_name="Energy produced 3", + ) + # Power + .tuya_dp( + dp_id=0x6F, + ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, + attribute_name="total_active_power", + ) + .tuya_dp( + dp_id=0x68, + ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, + attribute_name="active_power", + ) + .tuya_dp( + dp_id=0x6B, + ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, + attribute_name="active_power_ph_b", + ) + .tuya_dp( + dp_id=0x6E, + ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, + attribute_name="active_power_ph_c", + ) + # Voltage + .tuya_dp( + dp_id=0x66, + ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, + attribute_name="rms_voltage", + ) + .tuya_dp( + dp_id=0x69, + ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, + attribute_name="rms_voltage_ph_b", + ) + .tuya_dp( + dp_id=0x6C, + ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, + attribute_name="rms_voltage_ph_c", + ) + # Current + .tuya_dp( + dp_id=0x67, + ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, + attribute_name="rms_current", + ) + .tuya_dp( + dp_id=0x6A, + ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, + attribute_name="rms_current_ph_b", + ) + .tuya_dp( + dp_id=0x6D, + ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, + attribute_name="rms_current_ph_c", + ) + # Power factor + .tuya_sensor( + dp_id=0x0F, + attribute_name="power_factor", + type=t.uint8_t, + state_class=SensorStateClass.MEASUREMENT, + device_class=SensorDeviceClass.POWER_FACTOR, + # unit=PERCENTAGE, # ZHA fails to validate this one + translation_key="total_power_factor", + fallback_name="Total power factor", + ) + .tuya_dp( + dp_id=0x76, + ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, + attribute_name="power_factor", + ) + .tuya_dp( + dp_id=0x77, + ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, + attribute_name="power_factor_ph_b", + ) + .tuya_dp( + dp_id=0x78, + ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, + attribute_name="power_factor_ph_c", + ) + .adds(Tuya3PhaseElectricalMeasurement) + .skip_configuration() + .add_to_registry() +) + + class HikingPowerMeter(TuyaSwitch): """Hiking Power Meter Device - DDS238-2.""" From 1df10e5bb574475b4eed77a3f94db68c7deb9011 Mon Sep 17 00:00:00 2001 From: abmantis Date: Tue, 24 Dec 2024 18:07:34 +0000 Subject: [PATCH 2/4] Improve energy entity names --- zhaquirks/tuya/ts0601_din_power.py | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/zhaquirks/tuya/ts0601_din_power.py b/zhaquirks/tuya/ts0601_din_power.py index 02fcb30b55..22f80eaa49 100644 --- a/zhaquirks/tuya/ts0601_din_power.py +++ b/zhaquirks/tuya/ts0601_din_power.py @@ -267,7 +267,6 @@ class Tuya3PhaseElectricalMeasurement(ElectricalMeasurement, TuyaLocalCluster): state_class=SensorStateClass.TOTAL_INCREASING, device_class=SensorDeviceClass.ENERGY, unit=UnitOfEnergy.KILO_WATT_HOUR, - translation_key="total_energy", fallback_name="Total energy", ) .tuya_sensor( @@ -278,8 +277,8 @@ class Tuya3PhaseElectricalMeasurement(ElectricalMeasurement, TuyaLocalCluster): state_class=SensorStateClass.TOTAL_INCREASING, device_class=SensorDeviceClass.ENERGY, unit=UnitOfEnergy.KILO_WATT_HOUR, - translation_key="energy", - fallback_name="Energy", + translation_key="energy_ph_a", + fallback_name="Energy phase A", ) .tuya_sensor( dp_id=0x72, @@ -289,8 +288,8 @@ class Tuya3PhaseElectricalMeasurement(ElectricalMeasurement, TuyaLocalCluster): state_class=SensorStateClass.TOTAL_INCREASING, device_class=SensorDeviceClass.ENERGY, unit=UnitOfEnergy.KILO_WATT_HOUR, - translation_key="energy_2", - fallback_name="Energy 2", + translation_key="energy_ph_b", + fallback_name="Energy phase B", ) .tuya_sensor( dp_id=0x74, @@ -300,8 +299,8 @@ class Tuya3PhaseElectricalMeasurement(ElectricalMeasurement, TuyaLocalCluster): state_class=SensorStateClass.TOTAL_INCREASING, device_class=SensorDeviceClass.ENERGY, unit=UnitOfEnergy.KILO_WATT_HOUR, - translation_key="energy_3", - fallback_name="Energy 3", + translation_key="energy_ph_c", + fallback_name="Energy phase C", ) # Energy produced .tuya_sensor( @@ -312,8 +311,8 @@ class Tuya3PhaseElectricalMeasurement(ElectricalMeasurement, TuyaLocalCluster): state_class=SensorStateClass.TOTAL_INCREASING, device_class=SensorDeviceClass.ENERGY, unit=UnitOfEnergy.KILO_WATT_HOUR, - translation_key="total_energy_produced", - fallback_name="Total energy produced", + translation_key="energy_produced", + fallback_name="Energy produced", ) .tuya_sensor( dp_id=0x71, @@ -323,8 +322,8 @@ class Tuya3PhaseElectricalMeasurement(ElectricalMeasurement, TuyaLocalCluster): state_class=SensorStateClass.TOTAL_INCREASING, device_class=SensorDeviceClass.ENERGY, unit=UnitOfEnergy.KILO_WATT_HOUR, - translation_key="energy_produced", - fallback_name="Energy produced", + translation_key="energy_produced_ph_a", + fallback_name="Energy produced phase A", ) .tuya_sensor( dp_id=0x73, @@ -334,8 +333,8 @@ class Tuya3PhaseElectricalMeasurement(ElectricalMeasurement, TuyaLocalCluster): state_class=SensorStateClass.TOTAL_INCREASING, device_class=SensorDeviceClass.ENERGY, unit=UnitOfEnergy.KILO_WATT_HOUR, - translation_key="energy_produced_2", - fallback_name="Energy produced 2", + translation_key="energy_produced_ph_b", + fallback_name="Energy produced phase B", ) .tuya_sensor( dp_id=0x75, @@ -345,8 +344,8 @@ class Tuya3PhaseElectricalMeasurement(ElectricalMeasurement, TuyaLocalCluster): state_class=SensorStateClass.TOTAL_INCREASING, device_class=SensorDeviceClass.ENERGY, unit=UnitOfEnergy.KILO_WATT_HOUR, - translation_key="energy_produced_3", - fallback_name="Energy produced 3", + translation_key="energy_produced_ph_c", + fallback_name="Energy produced phase C", ) # Power .tuya_dp( From 45af14d358fe8532f837ac572cd7d303010757b5 Mon Sep 17 00:00:00 2001 From: abmantis Date: Sun, 26 Jan 2025 15:12:06 +0000 Subject: [PATCH 3/4] Use proper unit for total power factor --- zhaquirks/tuya/ts0601_din_power.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zhaquirks/tuya/ts0601_din_power.py b/zhaquirks/tuya/ts0601_din_power.py index 22f80eaa49..a15e5d75aa 100644 --- a/zhaquirks/tuya/ts0601_din_power.py +++ b/zhaquirks/tuya/ts0601_din_power.py @@ -2,7 +2,7 @@ from zigpy.profiles import zha from zigpy.quirks.v2 import SensorDeviceClass, SensorStateClass -from zigpy.quirks.v2.homeassistant import UnitOfEnergy +from zigpy.quirks.v2.homeassistant import PERCENTAGE, UnitOfEnergy import zigpy.types as t from zigpy.zcl.clusters.general import Basic, Groups, Ota, Scenes, Time from zigpy.zcl.clusters.homeautomation import ElectricalMeasurement @@ -407,7 +407,7 @@ class Tuya3PhaseElectricalMeasurement(ElectricalMeasurement, TuyaLocalCluster): type=t.uint8_t, state_class=SensorStateClass.MEASUREMENT, device_class=SensorDeviceClass.POWER_FACTOR, - # unit=PERCENTAGE, # ZHA fails to validate this one + unit=PERCENTAGE, translation_key="total_power_factor", fallback_name="Total power factor", ) From bf1b6b64bf7bb10654f4e37b70f56db0729ca14a Mon Sep 17 00:00:00 2001 From: abmantis Date: Sun, 26 Jan 2025 23:36:37 +0000 Subject: [PATCH 4/4] Replace hex with dec --- zhaquirks/tuya/ts0601_din_power.py | 46 +++++++++++++++--------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/zhaquirks/tuya/ts0601_din_power.py b/zhaquirks/tuya/ts0601_din_power.py index a15e5d75aa..b4787940d6 100644 --- a/zhaquirks/tuya/ts0601_din_power.py +++ b/zhaquirks/tuya/ts0601_din_power.py @@ -254,13 +254,13 @@ class Tuya3PhaseElectricalMeasurement(ElectricalMeasurement, TuyaLocalCluster): ( TuyaQuirkBuilder("_TZE204_ugekduaj", "TS0601") .tuya_dp( - dp_id=0x65, + dp_id=101, ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, attribute_name="ac_frequency", ) # Energy consumed .tuya_sensor( - dp_id=0x01, + dp_id=1, attribute_name="energy_consumed", type=t.uint32_t, divisor=100, @@ -270,7 +270,7 @@ class Tuya3PhaseElectricalMeasurement(ElectricalMeasurement, TuyaLocalCluster): fallback_name="Total energy", ) .tuya_sensor( - dp_id=0x70, + dp_id=112, attribute_name="energy_consumed_ph_a", type=t.uint32_t, divisor=100, @@ -281,7 +281,7 @@ class Tuya3PhaseElectricalMeasurement(ElectricalMeasurement, TuyaLocalCluster): fallback_name="Energy phase A", ) .tuya_sensor( - dp_id=0x72, + dp_id=114, attribute_name="energy_consumed_ph_b", type=t.uint32_t, divisor=100, @@ -292,7 +292,7 @@ class Tuya3PhaseElectricalMeasurement(ElectricalMeasurement, TuyaLocalCluster): fallback_name="Energy phase B", ) .tuya_sensor( - dp_id=0x74, + dp_id=116, attribute_name="energy_consumed_ph_c", divisor=100, type=t.uint32_t, @@ -304,7 +304,7 @@ class Tuya3PhaseElectricalMeasurement(ElectricalMeasurement, TuyaLocalCluster): ) # Energy produced .tuya_sensor( - dp_id=0x02, + dp_id=2, attribute_name="energy_produced", type=t.uint32_t, divisor=100, @@ -315,7 +315,7 @@ class Tuya3PhaseElectricalMeasurement(ElectricalMeasurement, TuyaLocalCluster): fallback_name="Energy produced", ) .tuya_sensor( - dp_id=0x71, + dp_id=113, attribute_name="energy_produced_ph_a", type=t.uint32_t, converter=lambda x: x / 100, @@ -326,7 +326,7 @@ class Tuya3PhaseElectricalMeasurement(ElectricalMeasurement, TuyaLocalCluster): fallback_name="Energy produced phase A", ) .tuya_sensor( - dp_id=0x73, + dp_id=115, attribute_name="energy_produced_ph_b", type=t.uint32_t, divisor=100, @@ -337,7 +337,7 @@ class Tuya3PhaseElectricalMeasurement(ElectricalMeasurement, TuyaLocalCluster): fallback_name="Energy produced phase B", ) .tuya_sensor( - dp_id=0x75, + dp_id=117, attribute_name="energy_produced_ph_c", type=t.uint32_t, divisor=100, @@ -349,60 +349,60 @@ class Tuya3PhaseElectricalMeasurement(ElectricalMeasurement, TuyaLocalCluster): ) # Power .tuya_dp( - dp_id=0x6F, + dp_id=111, ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, attribute_name="total_active_power", ) .tuya_dp( - dp_id=0x68, + dp_id=104, ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, attribute_name="active_power", ) .tuya_dp( - dp_id=0x6B, + dp_id=107, ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, attribute_name="active_power_ph_b", ) .tuya_dp( - dp_id=0x6E, + dp_id=110, ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, attribute_name="active_power_ph_c", ) # Voltage .tuya_dp( - dp_id=0x66, + dp_id=102, ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, attribute_name="rms_voltage", ) .tuya_dp( - dp_id=0x69, + dp_id=105, ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, attribute_name="rms_voltage_ph_b", ) .tuya_dp( - dp_id=0x6C, + dp_id=108, ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, attribute_name="rms_voltage_ph_c", ) # Current .tuya_dp( - dp_id=0x67, + dp_id=103, ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, attribute_name="rms_current", ) .tuya_dp( - dp_id=0x6A, + dp_id=106, ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, attribute_name="rms_current_ph_b", ) .tuya_dp( - dp_id=0x6D, + dp_id=109, ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, attribute_name="rms_current_ph_c", ) # Power factor .tuya_sensor( - dp_id=0x0F, + dp_id=15, attribute_name="power_factor", type=t.uint8_t, state_class=SensorStateClass.MEASUREMENT, @@ -412,17 +412,17 @@ class Tuya3PhaseElectricalMeasurement(ElectricalMeasurement, TuyaLocalCluster): fallback_name="Total power factor", ) .tuya_dp( - dp_id=0x76, + dp_id=118, ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, attribute_name="power_factor", ) .tuya_dp( - dp_id=0x77, + dp_id=119, ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, attribute_name="power_factor_ph_b", ) .tuya_dp( - dp_id=0x78, + dp_id=120, ep_attribute=Tuya3PhaseElectricalMeasurement.ep_attribute, attribute_name="power_factor_ph_c", )