Open sltvtr opened 5 months ago
One additional information - this device works without any issue by default under zigbee2mqtt, I've just checked it:
Hey There! I created a quirk for _TZE200_v9hkz2yn
version which supports 3 phase Voltage, Current and Power stats:
https://github.com/rrataj/zha-device-handlers/blob/0a6b19ab591378c53f6a8887e6c65b76ea31084b/zhaquirks/tuya/ts0601_din_power_3.py
Hope that helps someone :)
Hi! Thank You for the contribution, it looks really better now, and after some quick testing I can say it reports independent values from 3 phases. What bothers me - there are four measurments for power, current and voltage, and I think something is off. I think the first measurment of the same type should be sum (or maybe average for voltage), like: PowerABC PowerA PowerB PowerC but I see that always PowerABC = PowerA, the same for Current and Voltage:
Am I right?
Thanks again for Your work, it looks promising :-) Best regards.
Yes, you are right, there are 4 groups (ABC, A, B, C), where currently 1st group (ABC) is the same as 1st phase (A). Maybe I will find time and adapt it to show correct sum, but for now I do this directly in HA via simple sum:
{{ (states('sensor.miernik_energii_moc_2')|float(2) + states('sensor.miernik_energii_moc_3')|float(2) + states('sensor.miernik_energii_moc_4')|float(2) )| round(0) }}
Thanks, this is a very nice workaround and it works like a charm ;-) I can definitely live with that, until official resolution comes into place :)
It worked
Hi @rrataj have you solved the Power ABC issue? Thanks
Unfortunately not, Workaround works fine and I didn't have time to implement a proper solution.
I got some unknown values, can we somehow fix that?
Data can be accessed in zigbee2mqtt
Device signature
Diagnostic information
Problem description
Hi, I have device SPM02-D2TZ:
Device connects to zigbee network and shows up in HA, but by default it has no entities and no quirk assigned. After adding custom quirk ts0601_din_power.py (file pasted below) with forced model :
the quirk is assigned and some entities show but only for one phase - there should be 3 phases:
I'm using current version: Home Assistant Core 2024.5.5 Interfejs użytkownika 20240501.1
Any help/ideas will be appreciated :) Best regards, Janusz
Solution description
The device should be recognized by ZHA without custom quirks and should present data from all 3 phases (not just 1, like now).
Screenshots/Video
Screenshots/Video
[Paste/upload your media here]Device signature
Device signature
```json { "node_descriptor": "NodeDescriptor(logical_type=Diagnostic information
Diagnostic information
```json { "home_assistant": { "installation_type": "Home Assistant Container", "version": "2024.5.5", "dev": false, "hassio": false, "virtualenv": false, "python_version": "3.12.2", "docker": true, "arch": "x86_64", "timezone": "Europe/Warsaw", "os_name": "Linux", "os_version": "5.15.0-92-generic", "run_as_root": true }, "custom_components": { "hacs": { "documentation": "https://hacs.xyz/docs/configuration/start", "version": "1.34.0", "requirements": [ "aiogithubapi>=22.10.1" ] }, "zha_toolkit": { "documentation": "https://github.com/mdeweerd/zha-toolkit", "version": "v1.1.10", "requirements": [ "pytz" ] }, "smartthinq_sensors": { "documentation": "https://github.com/ollo69/ha-smartthinq-sensors", "version": "0.39.1", "requirements": [ "pycountry>=23.12.11", "xmltodict>=0.13.0", "charset_normalizer>=3.2.0" ] } }, "integration_manifest": { "domain": "zha", "name": "Zigbee Home Automation", "after_dependencies": [ "onboarding", "usb" ], "codeowners": [ "@dmulcahey", "@adminiuga", "@puddly", "@TheJulianJES" ], "config_flow": true, "dependencies": [ "file_upload" ], "documentation": "https://www.home-assistant.io/integrations/zha", "iot_class": "local_polling", "loggers": [ "aiosqlite", "bellows", "crccheck", "pure_pcapy3", "zhaquirks", "zigpy", "zigpy_deconz", "zigpy_xbee", "zigpy_zigate", "zigpy_znp", "universal_silabs_flasher" ], "requirements": [ "bellows==0.38.4", "pyserial==3.5", "pyserial-asyncio==0.6", "zha-quirks==0.0.115", "zigpy-deconz==0.23.1", "zigpy==0.64.0", "zigpy-xbee==0.20.1", "zigpy-zigate==0.12.0", "zigpy-znp==0.12.1", "universal-silabs-flasher==0.0.18", "pyserial-asyncio-fast==0.11" ], "usb": [ { "vid": "10C4", "pid": "EA60", "description": "*2652*", "known_devices": [ "slae.sh cc2652rb stick" ] }, { "vid": "10C4", "pid": "EA60", "description": "*slzb-07*", "known_devices": [ "smlight slzb-07" ] }, { "vid": "1A86", "pid": "55D4", "description": "*sonoff*plus*", "known_devices": [ "sonoff zigbee dongle plus v2" ] }, { "vid": "10C4", "pid": "EA60", "description": "*sonoff*plus*", "known_devices": [ "sonoff zigbee dongle plus" ] }, { "vid": "10C4", "pid": "EA60", "description": "*tubeszb*", "known_devices": [ "TubesZB Coordinator" ] }, { "vid": "1A86", "pid": "7523", "description": "*tubeszb*", "known_devices": [ "TubesZB Coordinator" ] }, { "vid": "1A86", "pid": "7523", "description": "*zigstar*", "known_devices": [ "ZigStar Coordinators" ] }, { "vid": "1CF1", "pid": "0030", "description": "*conbee*", "known_devices": [ "Conbee II" ] }, { "vid": "0403", "pid": "6015", "description": "*conbee*", "known_devices": [ "Conbee III" ] }, { "vid": "10C4", "pid": "8A2A", "description": "*zigbee*", "known_devices": [ "Nortek HUSBZB-1" ] }, { "vid": "0403", "pid": "6015", "description": "*zigate*", "known_devices": [ "ZiGate+" ] }, { "vid": "10C4", "pid": "EA60", "description": "*zigate*", "known_devices": [ "ZiGate" ] }, { "vid": "10C4", "pid": "8B34", "description": "*bv 2010/10*", "known_devices": [ "Bitron Video AV2010/10" ] } ], "zeroconf": [ { "type": "_esphomelib._tcp.local.", "name": "tube*" }, { "type": "_zigate-zigbee-gateway._tcp.local.", "name": "*zigate*" }, { "type": "_zigstar_gw._tcp.local.", "name": "*zigstar*" }, { "type": "_uzg-01._tcp.local.", "name": "uzg-01*" }, { "type": "_slzb-06._tcp.local.", "name": "slzb-06*" } ], "is_built_in": true }, "data": { "ieee": "**REDACTED**", "nwk": 4546, "manufacturer": "_TZE200_v9hkz2yn", "model": "TS0601", "name": "_TZE200_v9hkz2yn TS0601", "quirk_applied": true, "quirk_class": "ts0601_zemismart_power_meter.TuyaZemismartPowerMeter", "quirk_id": null, "manufacturer_code": 4098, "power_source": "Mains", "lqi": 184, "rssi": -54, "last_seen": "2024-06-03T09:29:22", "available": true, "device_type": "Router", "signature": { "node_descriptor": "NodeDescriptor(logical_type=Logs
Logs
```python [Paste the logs here] ```Custom quirk
Custom quirk
```python """Tuya Din Power Meter.""" from zigpy.profiles import zha from zigpy.quirks import CustomDevice import zigpy.types as t from zigpy.zcl.clusters.general import Basic, Groups, Ota, Scenes, Time from zigpy.zcl.clusters.homeautomation import ElectricalMeasurement from zigpy.zcl.clusters.smartenergy import Metering from zhaquirks import Bus, LocalDataCluster from zhaquirks.const import ( DEVICE_TYPE, ENDPOINTS, INPUT_CLUSTERS, MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, ) from zhaquirks.tuya import TuyaManufClusterAttributes, TuyaOnOff, TuyaSwitch TUYA_TOTAL_ENERGY_ATTR = 0x0211 TUYA_CURRENT_ATTR = 0x0212 TUYA_POWER_ATTR = 0x0213 TUYA_VOLTAGE_ATTR = 0x0214 TUYA_DIN_SWITCH_ATTR = 0x0101 SWITCH_EVENT = "switch_event" """Hiking Power Meter Attributes""" HIKING_DIN_SWITCH_ATTR = 0x0110 HIKING_TOTAL_ENERGY_DELIVERED_ATTR = 0x0201 HIKING_TOTAL_ENERGY_RECEIVED_ATTR = 0x0266 HIKING_VOLTAGE_CURRENT_ATTR = 0x0006 HIKING_POWER_ATTR = 0x0267 HIKING_FREQUENCY_ATTR = 0x0269 HIKING_POWER_FACTOR_ATTR = 0x026F HIKING_TOTAL_REACTIVE_ATTR = 0x026D HIKING_REACTIVE_POWER_ATTR = 0x026E """Zemismart Power Meter Attributes""" ZEMISMART_TOTAL_ENERGY_ATTR = 0x0201 ZEMISMART_TOTAL_REVERSE_ENERGY_ATTR = 0x0202 ZEMISMART_VCP_ATTR = 0x0006 ZEMISMART_VCP_P2_ATTR = ZEMISMART_VCP_ATTR + 1 ZEMISMART_VCP_P3_ATTR = ZEMISMART_VCP_ATTR + 2 class TuyaManufClusterDinPower(TuyaManufClusterAttributes): """Manufacturer Specific Cluster of the Tuya Power Meter device.""" attributes = { TUYA_TOTAL_ENERGY_ATTR: ("energy", t.uint32_t, True), TUYA_CURRENT_ATTR: ("current", t.int16s, True), TUYA_POWER_ATTR: ("power", t.uint16_t, True), TUYA_VOLTAGE_ATTR: ("voltage", t.uint16_t, True), TUYA_DIN_SWITCH_ATTR: ("switch", t.uint8_t, True), } def _update_attribute(self, attrid, value): super()._update_attribute(attrid, value) if attrid == TUYA_TOTAL_ENERGY_ATTR: self.endpoint.smartenergy_metering.energy_deliver_reported(value / 100) elif attrid == TUYA_CURRENT_ATTR: self.endpoint.electrical_measurement.current_reported(value) elif attrid == TUYA_POWER_ATTR: self.endpoint.electrical_measurement.power_reported(value / 10) elif attrid == TUYA_VOLTAGE_ATTR: self.endpoint.electrical_measurement.voltage_reported(value / 10) elif attrid == TUYA_DIN_SWITCH_ATTR: self.endpoint.device.switch_bus.listener_event( SWITCH_EVENT, self.endpoint.endpoint_id, value ) class TuyaPowerMeasurement(LocalDataCluster, ElectricalMeasurement): """Custom class for power, voltage and current measurement.""" cluster_id = ElectricalMeasurement.cluster_id POWER_ID = 0x050B VOLTAGE_ID = 0x0505 CURRENT_ID = 0x0508 REACTIVE_POWER_ID = 0x050E AC_FREQUENCY_ID = 0x0300 TOTAL_REACTIVE_POWER_ID = 0x0305 POWER_FACTOR_ID = 0x0510 AC_CURRENT_MULTIPLIER = 0x0602 AC_CURRENT_DIVISOR = 0x0603 AC_FREQUENCY_MULTIPLIER = 0x0400 AC_FREQUENCY_DIVISOR = 0x0401 _CONSTANT_ATTRIBUTES = { AC_CURRENT_MULTIPLIER: 1, AC_CURRENT_DIVISOR: 1000, AC_FREQUENCY_MULTIPLIER: 1, AC_FREQUENCY_DIVISOR: 100, } def voltage_reported(self, value): """Voltage reported.""" self._update_attribute(self.VOLTAGE_ID, value) def power_reported(self, value): """Power reported.""" self._update_attribute(self.POWER_ID, value) def power_factor_reported(self, value): """Power Factor reported.""" self._update_attribute(self.POWER_FACTOR_ID, value) def reactive_power_reported(self, value): """Reactive Power reported.""" self._update_attribute(self.REACTIVE_POWER_ID, value) def current_reported(self, value): """Ampers reported.""" self._update_attribute(self.CURRENT_ID, value) def frequency_reported(self, value): """AC Frequency reported.""" self._update_attribute(self.AC_FREQUENCY_ID, value) def reactive_energy_reported(self, value): """Summation Reactive Energy reported.""" self._update_attribute(self.TOTAL_REACTIVE_POWER_ID, value) class TuyaElectricalMeasurement(LocalDataCluster, Metering): """Custom class for total energy measurement.""" cluster_id = Metering.cluster_id CURRENT_DELIVERED_ID = 0x0000 CURRENT_RECEIVED_ID = 0x0001 POWER_WATT = 0x0000 """Setting unit of measurement.""" _CONSTANT_ATTRIBUTES = {0x0300: POWER_WATT} def energy_deliver_reported(self, value): """Summation Energy Deliver reported.""" self._update_attribute(self.CURRENT_DELIVERED_ID, value) def energy_receive_reported(self, value): """Summation Energy Receive reported.""" self._update_attribute(self.CURRENT_RECEIVED_ID, value) class HikingManufClusterDinPower(TuyaManufClusterAttributes): """Manufacturer Specific Cluster of the Hiking Power Meter device.""" attributes = { HIKING_DIN_SWITCH_ATTR: ("switch", t.uint8_t, True), HIKING_TOTAL_ENERGY_DELIVERED_ATTR: ("energy_delivered", t.uint32_t, True), HIKING_TOTAL_ENERGY_RECEIVED_ATTR: ("energy_received", t.uint16_t, True), HIKING_VOLTAGE_CURRENT_ATTR: ("voltage_current", t.uint32_t, True), HIKING_POWER_ATTR: ("power", t.uint16_t, True), HIKING_FREQUENCY_ATTR: ("frequency", t.uint16_t, True), HIKING_TOTAL_REACTIVE_ATTR: ("total_reactive_energy", t.int32s, True), HIKING_REACTIVE_POWER_ATTR: ("reactive_power", t.int16s, True), HIKING_POWER_FACTOR_ATTR: ("power_factor", t.uint16_t, True), } def _update_attribute(self, attrid, value): super()._update_attribute(attrid, value) if attrid == HIKING_DIN_SWITCH_ATTR: self.endpoint.device.switch_bus.listener_event(SWITCH_EVENT, 16, value) elif attrid == HIKING_TOTAL_ENERGY_DELIVERED_ATTR: self.endpoint.smartenergy_metering.energy_deliver_reported(value / 100) elif attrid == HIKING_TOTAL_ENERGY_RECEIVED_ATTR: self.endpoint.smartenergy_metering.energy_receive_reported(value / 100) elif attrid == HIKING_VOLTAGE_CURRENT_ATTR: self.endpoint.electrical_measurement.current_reported(value >> 16) self.endpoint.electrical_measurement.voltage_reported( (value & 0x0000FFFF) / 10 ) elif attrid == HIKING_POWER_ATTR: self.endpoint.electrical_measurement.power_reported(value) elif attrid == HIKING_FREQUENCY_ATTR: self.endpoint.electrical_measurement.frequency_reported(value) elif attrid == HIKING_TOTAL_REACTIVE_ATTR: self.endpoint.electrical_measurement.reactive_energy_reported(value) elif attrid == HIKING_REACTIVE_POWER_ATTR: self.endpoint.electrical_measurement.reactive_power_reported(value) elif attrid == HIKING_POWER_FACTOR_ATTR: self.endpoint.electrical_measurement.power_factor_reported(value / 10) class ZemismartManufCluster(TuyaManufClusterAttributes): """Manufacturer Specific Cluster of the Zemismart SPM series Power Meter devices.""" attributes = { ZEMISMART_TOTAL_ENERGY_ATTR: ("energy", t.uint32_t, True), ZEMISMART_TOTAL_REVERSE_ENERGY_ATTR: ("reverse_energy", t.uint32_t, True), ZEMISMART_VCP_ATTR: ("vcp_raw", t.data64, True), ZEMISMART_VCP_P2_ATTR: ("vcp_p2_raw", t.data64, True), ZEMISMART_VCP_P3_ATTR: ("vcp_p3_raw", t.data64, True), } def _update_attribute(self, attrid, value): super()._update_attribute(attrid, value) if attrid == ZEMISMART_TOTAL_ENERGY_ATTR: self.endpoint.smartenergy_metering.energy_deliver_reported(value) elif attrid == ZEMISMART_TOTAL_REVERSE_ENERGY_ATTR: self.endpoint.smartenergy_metering.energy_receive_reported(value) elif attrid == ZEMISMART_VCP_ATTR: self.endpoint.electrical_measurement.vcp_reported(value, 0) elif attrid == ZEMISMART_VCP_P2_ATTR: self.endpoint.electrical_measurement.vcp_reported(value, 1) elif attrid == ZEMISMART_VCP_P3_ATTR: self.endpoint.electrical_measurement.vcp_reported(value, 2) class ZemismartPowerMeasurement(LocalDataCluster, ElectricalMeasurement): """Custom class for power, voltage and current measurement.""" """Setting unit of measurement.""" _CONSTANT_ATTRIBUTES = { ElectricalMeasurement.AttributeDefs.ac_voltage_multiplier.id: 1, ElectricalMeasurement.AttributeDefs.ac_voltage_divisor.id: 10, ElectricalMeasurement.AttributeDefs.ac_current_multiplier.id: 1, ElectricalMeasurement.AttributeDefs.ac_current_divisor.id: 1000, } phase_attributes = [ { # Phase 1 (X) "voltage": ElectricalMeasurement.AttributeDefs.rms_voltage.id, "current": ElectricalMeasurement.AttributeDefs.rms_current.id, "power": ElectricalMeasurement.AttributeDefs.active_power.id, }, { # Phase 2 (Y) "voltage": ElectricalMeasurement.AttributeDefs.rms_voltage_ph_b.id, "current": ElectricalMeasurement.AttributeDefs.rms_current_ph_b.id, "power": ElectricalMeasurement.AttributeDefs.active_power_ph_b.id, }, { # Phase 3 (Z) "voltage": ElectricalMeasurement.AttributeDefs.rms_voltage_ph_c.id, "current": ElectricalMeasurement.AttributeDefs.rms_current_ph_c.id, "power": ElectricalMeasurement.AttributeDefs.active_power_ph_c.id, }, ] # Voltage, current, power is delivered in one value def vcp_reported(self, value, phase=0): """Voltage, current, power reported.""" if phase < 0 or phase > 2: phase = 0 voltage = int.from_bytes(value[6:8], byteorder="little") current = int.from_bytes(value[3:6], byteorder="little") power = int.from_bytes(value[0:3], byteorder="little") self._update_attribute(self.phase_attributes[phase]["voltage"], voltage) self._update_attribute(self.phase_attributes[phase]["current"], current) self._update_attribute(self.phase_attributes[phase]["power"], power) class ZemismartElectricalMeasurement(TuyaElectricalMeasurement): """Custom class for total energy measurement.""" """Setting unit of measurement.""" _CONSTANT_ATTRIBUTES = { Metering.AttributeDefs.unit_of_measure.id: 0, # kWh Metering.AttributeDefs.divisor.id: 100, } class TuyaPowerMeter(TuyaSwitch): """Tuya power meter device.""" def __init__(self, *args, **kwargs): """Init device.""" self.switch_bus = Bus() super().__init__(*args, **kwargs) signature = { # "node_descriptor": "Additional information
No response