From 5eaeb20bb3fdeb341d279cf2113ce29af38a32e8 Mon Sep 17 00:00:00 2001 From: "Keran :)" Date: Sat, 5 Sep 2026 02:18:28 +0930 Subject: [PATCH] Add Tuya two-channel energy meter sensors and numbers (#178415) --- homeassistant/components/tuya/const.py | 15 +++ homeassistant/components/tuya/number.py | 17 ++++ homeassistant/components/tuya/sensor.py | 107 ++++++++++++++++++++- homeassistant/components/tuya/strings.json | 28 ++++++ 4 files changed, 165 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/tuya/const.py b/homeassistant/components/tuya/const.py index 1b2793c02420..49a34db9064e 100644 --- a/homeassistant/components/tuya/const.py +++ b/homeassistant/components/tuya/const.py @@ -598,6 +598,7 @@ class DPCode(StrEnum): ALARM_SWITCH = "alarm_switch" # Alarm switch ALARM_TIME = "alarm_time" # Alarm time ALARM_VOLUME = "alarm_volume" # Alarm volume + ALL_ENERGY = "all_energy" # Combined energy of all channels ANGLE_HORIZONTAL = "angle_horizontal" ANGLE_VERTICAL = "angle_vertical" ANION = "anion" # Ionizer unit @@ -685,9 +686,15 @@ class DPCode(StrEnum): CUMULATIVE_ENERGY_OUTPUT_INV = "cumulative_energy_output_inv" CUP_NUMBER = "cup_number" # NUmber of cups CUR_CURRENT = "cur_current" # Actual current + CUR_CURRENT1 = "cur_current1" # Actual current, channel 1 + CUR_CURRENT2 = "cur_current2" # Actual current, channel 2 CUR_NEUTRAL = "cur_neutral" # Total reverse energy CUR_POWER = "cur_power" # Actual power + CUR_POWER1 = "cur_power1" # Actual power, channel 1 + CUR_POWER2 = "cur_power2" # Actual power, channel 2 CUR_VOLTAGE = "cur_voltage" # Actual voltage + CUR_VOLTAGE1 = "cur_voltage1" # Actual voltage, channel 1 + CUR_VOLTAGE2 = "cur_voltage2" # Actual voltage, channel 2 CURRENT_SOC = "current_soc" DECIBEL_SENSITIVITY = "decibel_sensitivity" DECIBEL_SWITCH = "decibel_switch" @@ -696,6 +703,8 @@ class DPCode(StrEnum): DELAY_CLEAN_TIME = "delay_clean_time" DELAY_SET = "delay_set" DEVICE_RESTART = "device_restart" + DEVICE_STATE1 = "device_state1" # Channel 1 monitoring state + DEVICE_STATE2 = "device_state2" # Channel 2 monitoring state DEW_POINT_TEMP = "dew_point_temp" DISINFECTION = "disinfection" DO_NOT_DISTURB = "do_not_disturb" @@ -947,9 +956,13 @@ class DPCode(StrEnum): TEMPER_ALARM = "temper_alarm" # Tamper alarm TIME_TOTAL = "time_total" TIME_USE = "time_use" # Total seconds of irrigation + TODAY_ACC_ENERGY1 = "today_acc_energy1" # Energy today, channel 1 + TODAY_ACC_ENERGY2 = "today_acc_energy2" # Energy today, channel 2 TOTAL_CLEAN_AREA = "total_clean_area" TOTAL_CLEAN_COUNT = "total_clean_count" TOTAL_CLEAN_TIME = "total_clean_time" + TOTAL_ENERGY1 = "total_energy1" # Total energy, channel 1 + TOTAL_ENERGY2 = "total_energy2" # Total energy, channel 2 TOTAL_FORWARD_ENERGY = "total_forward_energy" TOTAL_PM = "total_pm" TOTAL_POWER = "total_power" @@ -973,6 +986,8 @@ class DPCode(StrEnum): VOLUME_SET = "volume_set" WARM = "warm" # Heat preservation WARM_TIME = "warm_time" # Heat preservation time + WARN_POWER1 = "warn_power1" # Power warning threshold, channel 1 + WARN_POWER2 = "warn_power2" # Power warning threshold, channel 2 WATER = "water" WATER_LEVEL = "water_level" WATER_RESET = "water_reset" # Resetting of water usage days diff --git a/homeassistant/components/tuya/number.py b/homeassistant/components/tuya/number.py index 3c36599b93ec..150c0138f0d1 100644 --- a/homeassistant/components/tuya/number.py +++ b/homeassistant/components/tuya/number.py @@ -88,6 +88,23 @@ NUMBERS: dict[DeviceCategory, tuple[NumberEntityDescription, ...]] = { translation_key="voice_times", ), ), + DeviceCategory.CZ: ( + # Two-channel current transformer meters warn above these thresholds + NumberEntityDescription( + key=DPCode.WARN_POWER1, + translation_key="indexed_power_warning_threshold", + translation_placeholders={"index": "1"}, + device_class=NumberDeviceClass.POWER, + entity_category=EntityCategory.CONFIG, + ), + NumberEntityDescription( + key=DPCode.WARN_POWER2, + translation_key="indexed_power_warning_threshold", + translation_placeholders={"index": "2"}, + device_class=NumberDeviceClass.POWER, + entity_category=EntityCategory.CONFIG, + ), + ), DeviceCategory.DGNBJ: ( NumberEntityDescription( key=DPCode.ALARM_TIME, diff --git a/homeassistant/components/tuya/sensor.py b/homeassistant/components/tuya/sensor.py index f92a05731f8b..b0638c10428c 100644 --- a/homeassistant/components/tuya/sensor.py +++ b/homeassistant/components/tuya/sensor.py @@ -1673,8 +1673,111 @@ SENSORS: dict[DeviceCategory, tuple[TuyaSensorEntityDescription, ...]] = { ), } -# Socket (duplicate of `kg`) -SENSORS[DeviceCategory.CZ] = SENSORS[DeviceCategory.KG] +# Two-channel current transformer meters report a full set of electricity DPs +# per channel, plus a combined energy total for both channels. +DUAL_CHANNEL_METER_SENSORS: tuple[TuyaSensorEntityDescription, ...] = ( + TuyaSensorEntityDescription( + key=DPCode.DEVICE_STATE1, + translation_key="indexed_meter_status", + translation_placeholders={"index": "1"}, + ), + TuyaSensorEntityDescription( + key=DPCode.DEVICE_STATE2, + translation_key="indexed_meter_status", + translation_placeholders={"index": "2"}, + ), + TuyaSensorEntityDescription( + key=DPCode.CUR_CURRENT1, + translation_key="indexed_current", + translation_placeholders={"index": "1"}, + device_class=SensorDeviceClass.CURRENT, + state_class=SensorStateClass.MEASUREMENT, + suggested_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + ), + TuyaSensorEntityDescription( + key=DPCode.CUR_CURRENT2, + translation_key="indexed_current", + translation_placeholders={"index": "2"}, + device_class=SensorDeviceClass.CURRENT, + state_class=SensorStateClass.MEASUREMENT, + suggested_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + ), + TuyaSensorEntityDescription( + key=DPCode.CUR_POWER1, + translation_key="indexed_power", + translation_placeholders={"index": "1"}, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + ), + TuyaSensorEntityDescription( + key=DPCode.CUR_POWER2, + translation_key="indexed_power", + translation_placeholders={"index": "2"}, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + ), + TuyaSensorEntityDescription( + key=DPCode.CUR_VOLTAGE1, + translation_key="indexed_voltage", + translation_placeholders={"index": "1"}, + device_class=SensorDeviceClass.VOLTAGE, + state_class=SensorStateClass.MEASUREMENT, + suggested_unit_of_measurement=UnitOfElectricPotential.VOLT, + ), + TuyaSensorEntityDescription( + key=DPCode.CUR_VOLTAGE2, + translation_key="indexed_voltage", + translation_placeholders={"index": "2"}, + device_class=SensorDeviceClass.VOLTAGE, + state_class=SensorStateClass.MEASUREMENT, + suggested_unit_of_measurement=UnitOfElectricPotential.VOLT, + ), + TuyaSensorEntityDescription( + key=DPCode.TOTAL_ENERGY1, + translation_key="indexed_total_energy", + translation_placeholders={"index": "1"}, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + suggested_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + ), + TuyaSensorEntityDescription( + key=DPCode.TOTAL_ENERGY2, + translation_key="indexed_total_energy", + translation_placeholders={"index": "2"}, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + suggested_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + ), + TuyaSensorEntityDescription( + key=DPCode.TODAY_ACC_ENERGY1, + translation_key="indexed_energy_today", + translation_placeholders={"index": "1"}, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + suggested_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + ), + TuyaSensorEntityDescription( + key=DPCode.TODAY_ACC_ENERGY2, + translation_key="indexed_energy_today", + translation_placeholders={"index": "2"}, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + suggested_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + ), + TuyaSensorEntityDescription( + key=DPCode.ALL_ENERGY, + translation_key="total_energy", + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + suggested_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + ), +) + +# Socket (duplicate of `kg`, plus the two-channel meter DPs) +SENSORS[DeviceCategory.CZ] = ( + *SENSORS[DeviceCategory.KG], + *DUAL_CHANNEL_METER_SENSORS, +) # Smart Camera - Low power consumption camera (duplicate of `sp`) SENSORS[DeviceCategory.DGHSXJ] = SENSORS[DeviceCategory.SP] diff --git a/homeassistant/components/tuya/strings.json b/homeassistant/components/tuya/strings.json index 71e756e57f4c..8676c8dc8b24 100644 --- a/homeassistant/components/tuya/strings.json +++ b/homeassistant/components/tuya/strings.json @@ -229,6 +229,9 @@ "indexed_minimum_brightness": { "name": "Minimum brightness {index}" }, + "indexed_power_warning_threshold": { + "name": "Power warning threshold {index}" + }, "indexed_temperature": { "name": "Temperature {index}" }, @@ -765,12 +768,37 @@ "illuminance": { "name": "[%key:component::sensor::entity_component::illuminance::name%]" }, + "indexed_current": { + "name": "Current channel {index}" + }, + "indexed_energy_today": { + "name": "Energy today channel {index}" + }, "indexed_humidity_outdoor": { "name": "Outdoor humidity channel {index}" }, + "indexed_meter_status": { + "name": "Status channel {index}", + "state": { + "close": "[%key:common::state::closed%]", + "idle": "[%key:common::state::idle%]", + "monitor": "Monitoring", + "warning": "Warning", + "working": "Working" + } + }, + "indexed_power": { + "name": "Power channel {index}" + }, "indexed_temperature_external": { "name": "Probe temperature channel {index}" }, + "indexed_total_energy": { + "name": "Total energy channel {index}" + }, + "indexed_voltage": { + "name": "Voltage channel {index}" + }, "inverter_output_power": { "name": "Inverter output power" },