zigpy / zha-device-handlers

ZHA device handlers bridge the functionality gap created when manufacturers deviate from the ZCL specification, handling deviations and exceptions by parsing custom messages to and from Zigbee devices.
Apache License 2.0
683 stars 634 forks source link

[Device Support Request] TS0601 by _TZE204_rhblgy0z DIN Power #2553

Open lesissou opened 10 months ago

lesissou commented 10 months ago

Problem description

Is it possible to add this tuya device to ZHA devices : https://www.amazon.fr/dp/B0C7C71DRS?psc=1&ref=ppx_yo2ov_dt_b_product_details

It is a DIN power. It seems similar to the tuya din_power quirk

Solution description

I would love if someone could add this device to the official quirk

Screenshots/Video

Screenshots/Video [Paste/upload your media here]

Device signature

Device signature ```json [Paste the device signature here] { "node_descriptor": "NodeDescriptor(logical_type=, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=, mac_capability_flags=, manufacturer_code=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, descriptor_capability_field=, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)", "endpoints": { "1": { "profile_id": "0x0104", "device_type": "0x0051", "input_clusters": [ "0x0000", "0x0004", "0x0005", "0xef00" ], "output_clusters": [ "0x000a", "0x0019" ] }, "242": { "profile_id": "0xa1e0", "device_type": "0x0061", "input_clusters": [], "output_clusters": [ "0x0021" ] } }, "manufacturer": "_TZE204_rhblgy0z", "model": "TS0601", "class": "zigpy.device.Device" }

Diagnostic information

Diagnostic information ```json [Paste the diagnostic information here] { "home_assistant": { "installation_type": "Home Assistant OS", "version": "2023.8.4", "dev": false, "hassio": true, "virtualenv": false, "python_version": "3.11.4", "docker": true, "arch": "aarch64", "timezone": "Europe/Paris", "os_name": "Linux", "os_version": "6.1.45", "supervisor": "2023.08.1", "host_os": "Home Assistant OS 10.5", "docker_version": "23.0.6", "chassis": "embedded", "run_as_root": true }, "integration_manifest": { "domain": "zha", "name": "Zigbee Home Automation", "after_dependencies": [ "onboarding", "usb" ], "codeowners": [ "@dmulcahey", "@adminiuga", "@puddly" ], "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" ], "requirements": [ "bellows==0.35.9", "pyserial==3.5", "pyserial-asyncio==0.6", "zha-quirks==0.0.102", "zigpy-deconz==0.21.0", "zigpy==0.56.4", "zigpy-xbee==0.18.1", "zigpy-zigate==0.11.0", "zigpy-znp==0.11.4" ], "usb": [ { "vid": "10C4", "pid": "EA60", "description": "*2652*", "known_devices": [ "slae.sh cc2652rb stick" ] }, { "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": "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": "_slzb-06._tcp.local.", "name": "slzb-06*" } ], "is_built_in": true }, "data": { "ieee": "**REDACTED**", "nwk": 57728, "manufacturer": "_TZE204_rhblgy0z", "model": "TS0601", "name": "_TZE204_rhblgy0z TS0601", "quirk_applied": false, "quirk_class": "zigpy.device.Device", "manufacturer_code": 4417, "power_source": "Mains", "lqi": 51, "rssi": null, "last_seen": "2023-08-29T20:17:08", "available": true, "device_type": "Router", "signature": { "node_descriptor": "NodeDescriptor(logical_type=, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=, mac_capability_flags=, manufacturer_code=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, descriptor_capability_field=, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)", "endpoints": { "1": { "profile_id": "0x0104", "device_type": "0x0051", "input_clusters": [ "0x0000", "0x0004", "0x0005", "0xef00" ], "output_clusters": [ "0x000a", "0x0019" ] }, "242": { "profile_id": "0xa1e0", "device_type": "0x0061", "input_clusters": [], "output_clusters": [ "0x0021" ] } }, "manufacturer": "_TZE204_rhblgy0z", "model": "TS0601" }, "active_coordinator": false, "entities": [], "neighbors": [], "routes": [], "endpoint_names": [ { "name": "SMART_PLUG" }, { "name": "PROXY_BASIC" } ], "user_given_name": "Din Power", "device_reg_id": "8d4578924d05eb4101814fe206990248", "area_id": "chalet", "cluster_details": { "1": { "device_type": { "name": "SMART_PLUG", "id": 81 }, "profile_id": 260, "in_clusters": { "0x0004": { "endpoint_attribute": "groups", "attributes": {}, "unsupported_attributes": {} }, "0x0005": { "endpoint_attribute": "scenes", "attributes": {}, "unsupported_attributes": {} }, "0xef00": { "endpoint_attribute": null, "attributes": {}, "unsupported_attributes": {} }, "0x0000": { "endpoint_attribute": "basic", "attributes": { "0x0001": { "attribute_name": "app_version", "value": 74 }, "0x0004": { "attribute_name": "manufacturer", "value": "_TZE204_rhblgy0z" }, "0x0005": { "attribute_name": "model", "value": "TS0601" } }, "unsupported_attributes": {} } }, "out_clusters": { "0x0019": { "endpoint_attribute": "ota", "attributes": {}, "unsupported_attributes": {} }, "0x000a": { "endpoint_attribute": "time", "attributes": {}, "unsupported_attributes": {} } } }, "242": { "device_type": { "name": "PROXY_BASIC", "id": 97 }, "profile_id": 41440, "in_clusters": {}, "out_clusters": { "0x0021": { "endpoint_attribute": "green_power", "attributes": {}, "unsupported_attributes": {} } } } } } }

Logs

Logs ```python [Paste the logs here] ```

Custom quirk

Custom quirk ```python """Tuya Din Power Meter.""" from zigpy.profiles import zha, zgp import zigpy.types as t from zigpy.zcl.clusters.general import Basic, Groups, Ota, Scenes, Time, GreenPowerProxy 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 ( NoManufacturerCluster, TuyaManufClusterAttributes, TuyaSwitch, ) import logging _LOGGER = logging.getLogger(__name__) TUYA_TOTAL_ENERGY_ATTR = 0x0201 #total energy /100 0x0211 TUYA_CURRENT_ATTR = 0x0011 #0x0212 TUYA_POWER_ATTR = 0x0006 #0x0213 TUYA_VOLTAGE_ATTR = 0x0004 #0x0214 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), #t.int16s TUYA_POWER_ATTR: ("power", t.uint64_t, True), #t.uint16_t TUYA_VOLTAGE_ATTR: ("voltage", t.uint16_t, True), } def _update_attribute(self, attrid, value): #super()._update_attribute(attrid, value) if attrid == TUYA_TOTAL_ENERGY_ATTR: self.endpoint.smartenergy_metering.energy_reported(value) super()._update_attribute(attrid, value) elif attrid == TUYA_CURRENT_ATTR: _LOGGER.warning("TUYA_CURRENT_ATTR (0x%04x) value: %d (0x%x)" % (attrid, value, value)) elif attrid == TUYA_POWER_ATTR: self.endpoint.electrical_measurement.voltage_reported((value >> 48) & 0xffff) self.endpoint.electrical_measurement.current_reported((value >> 24) & 0xffffff) self.endpoint.electrical_measurement.power_reported(value & 0xffffff) super()._update_attribute(TUYA_VOLTAGE_ATTR, (value >> 48) & 0xffff) super()._update_attribute(TUYA_CURRENT_ATTR, (value >> 24) & 0xffffff) super()._update_attribute(TUYA_POWER_ATTR, value & 0xffffff) elif attrid == TUYA_VOLTAGE_ATTR: _LOGGER.warning("TUYA_VOLTAGE_ATTR (0x%04x) value: %d (0x%x)" % (attrid, value, value)) else: super()._update_attribute(attrid, value) _LOGGER.warning("attrid: 0x%04x value: %d (0x%x)" % (attrid, value, value)) class TuyaPowerMeasurement(LocalDataCluster, ElectricalMeasurement): """Custom class for power, voltage and current measurement.""" cluster_id = ElectricalMeasurement.cluster_id POWER_ID = 0x050b #0x050B VOLTAGE_ID = 0x0505 CURRENT_ID = 0x0508 AC_VOLTAGE_MULTIPLIER = 0x0600 AC_VOLTAGE_DIVISOR = 0x0601 AC_CURRENT_MULTIPLIER = 0x0602 AC_CURRENT_DIVISOR = 0x0603 _CONSTANT_ATTRIBUTES = {AC_CURRENT_MULTIPLIER: 1, AC_CURRENT_DIVISOR: 1000, AC_VOLTAGE_MULTIPLIER: 1, AC_VOLTAGE_DIVISOR: 10} 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 current_reported(self, value): """Ampers reported.""" self._update_attribute(self.CURRENT_ID, value) class TuyaElectricalMeasurement(LocalDataCluster, Metering): """Custom class for total energy measurement.""" cluster_id = Metering.cluster_id CURRENT_SUMM_DELIVERED_ID = 0x0000 UNIT_OF_MEASURE_ID = 0x0300 MULTIPLIER_ID = 0x0301 DIVISOR_ID = 0x0302 POWER_WATT_ENUM = 0x0000 """Setting unit of measurement.""" _CONSTANT_ATTRIBUTES = {UNIT_OF_MEASURE_ID: POWER_WATT_ENUM, DIVISOR_ID: 100} def energy_reported(self, value): """Summation Energy reported.""" self._update_attribute(self.CURRENT_SUMM_DELIVERED_ID, value) class TuyaPowerMeter(TuyaSwitch): """Tuya power meter device.""" signature = { # "node_descriptor": "", # device_version=1 # input_clusters=[0x0000, 0x0004, 0x0005, 0xef00] # output_clusters=[0x000a, 0x0019] MODELS_INFO: [ ("_TZE200_byzdayie", "TS0601"), ("_TZE200_ewxhg6o9", "TS0601"), ], ENDPOINTS: { # 1: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.SMART_PLUG, INPUT_CLUSTERS: [ Basic.cluster_id, Groups.cluster_id, Scenes.cluster_id, TuyaManufClusterAttributes.cluster_id, ], OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id], } }, } replacement = { ENDPOINTS: { 1: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.SMART_PLUG, INPUT_CLUSTERS: [ Basic.cluster_id, Groups.cluster_id, Scenes.cluster_id, TuyaManufClusterDinPower, TuyaPowerMeasurement, TuyaElectricalMeasurement, ], OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id], } } } class TuyaPowerMeter_GPP(TuyaSwitch): """Tuya power meter device.""" signature = { # "node_descriptor": "", # device_version=1 # input_clusters=[0x0000, 0x0004, 0x0005, 0xef00] # output_clusters=[0x000a, 0x0019] MODELS_INFO: [ ("_TZE200_lsanae15", "TS0601"), ("_TZE204_lsanae15", "TS0601"), ("_TZE204_rhblgy0z", "TS0601"), ], ENDPOINTS: { # 1: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.SMART_PLUG, INPUT_CLUSTERS: [ Basic.cluster_id, Groups.cluster_id, Scenes.cluster_id, TuyaManufClusterAttributes.cluster_id, ], OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id], }, 242: { #

Additional information

No response

lesissou commented 10 months ago

it seems the same device (same signature but different manufacturer) of issue #2549)

Srjosep commented 10 months ago

Not sure... It looks different : https://es.aliexpress.com/item/1005005532695534.html?spm=a2g0o.productlist.main.49.568ee273qwdnTa&algo_pvid=d6e726be-c5c3-46e7-8279-a7e4c937d75d&aem_p4p_detail=202308291327443504007627780000003633801&algo_exp_id=d6e726be-c5c3-46e7-8279-a7e4c937d75d-24&pdp_npi=4%40dis%21EUR%2144.25%2126.99%21%21%2146.84%21%21%40211b88ee16933408647204439e0490%2112000033950236714%21sea%21ES%21103947274%21&curPageLogUid=DaJplzWqaphj&search_p4p_id=202308291327443504007627780000003633801_25

lesissou commented 10 months ago

@Srjosep Yes sure, but the signature is the same. I would like to create (try) the quirk but I don't know how can i find the replacement code. Is there a guide to do that ?

Srjosep commented 10 months ago

@Srjosep Yes sure, but the signature is the same. I would like to create (try) the quirk but I don't know how can i find the replacement code. Is there a guide to do that ?

I have no idea... searching for the same. I found some code for z2m, and the manufacturer data to make it work. But not sure where to start learning to create the quirk. https://github.com/Koenkk/zigbee2mqtt/issues/18419#issuecomment-1657066719

lesissou commented 10 months ago

Hi, I have created a quirk (copy of another similar quirk) but no entities found. The quirck is well use (I can see it in the info device) but no entities and no command the switch See below the quirk code :

"""Tuya Din Power Meter.""" from zigpy.profiles import zha, zgp import zigpy.types as t from zigpy.zcl.clusters.general import Basic, Groups, Ota, Scenes, Time, GreenPowerProxy 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

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 HikingPowerMeter(TuyaSwitch): """Tuya power meter device."""

def __init__(self, *args, **kwargs):
    """Init device."""
    self.switch_bus = Bus()
    super().__init__(*args, **kwargs)

signature = {
    # "node_descriptor": "<NodeDescriptor byte1=1 byte2=64 mac_capability_flags=142 manufacturer_code=4417
    #                       maximum_buffer_size=66 maximum_incoming_transfer_size=66 server_mask=10752
    #                       maximum_outgoing_transfer_size=66 descriptor_capability_field=0>",
    # device_version=1
    # input_clusters=[0x0000, 0x0004, 0x0005, 0xef00]
    # output_clusters=[0x000a, 0x0019]
    MODELS_INFO: [
        ("_TZE204_rhblgy0z", "TS0601"),
    ],
    ENDPOINTS: {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=51
        # device_version=1
        # input_clusters=[0, 4, 5, 61184]
        # output_clusters=[10, 25]>
        1: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
            INPUT_CLUSTERS: [
                Basic.cluster_id,
                Groups.cluster_id,
                Scenes.cluster_id,
                TuyaManufClusterAttributes.cluster_id,
            ],
            OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
        },
        242: {
            PROFILE_ID: zgp.PROFILE_ID,
            DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
            INPUT_CLUSTERS: [],
            OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
        },
    },
}

replacement = {
    ENDPOINTS: {
        1: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
            INPUT_CLUSTERS: [
                Basic.cluster_id,
                Groups.cluster_id,
                Scenes.cluster_id,
                HikingManufClusterDinPower,
                TuyaElectricalMeasurement,
                TuyaPowerMeasurement,
            ],
            OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
        },
        16: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
            INPUT_CLUSTERS: [
                TuyaOnOff,
            ],
            OUTPUT_CLUSTERS: [],
        },
    }
}
Srjosep commented 10 months ago

In the link I posted, they wrote a converter for z2m , and they posted the Dpid data, etc. I am still searching for any manual or tutorial to understand how quirks must be created,named and used... there is not much info out there....meanwhile I think I will change to z2m to test if the device works locally or not. I can send it back to the seller yet , so I must be sure it does before the return period ends....

lesissou commented 10 months ago

It seems compatible with z2m : https://zigbee.blakadder.com/DAC2161C.html (the picture is the same) But the zigbee id (TZE204_rhblgy0z) is not referenced : Zigbee ID: TS0601 | _TZE200_eaac7dkw | _TZE200_lsanae15

The Tuya reference is XOCA-DAC2161C BI (device name on IoT Tuya project)

Srjosep commented 10 months ago

Yes sorry... I mean Tuya TS0601 TZE204_81yrt3lo, my device. It seems finally they are different. You can try asking the manufacturer...Did you find any manual or tutorial about quirk creation?

lesissou commented 10 months ago

I find this issue, I will try this quirk : https://github.com/zigpy/zha-device-handlers/issues/1768

lesissou commented 10 months ago

It works with this quirk I have add the quirk into this issue. @TheJulianJES is it possible to add this quirk to the main build ?

Srjosep commented 10 months ago

Sill not working for me... no sensors and quirk isn't applied... I am missing something about how to add quirks

lesissou commented 10 months ago

Hello @Srjosep You need to create the config/zha_quirks et copy your quirk into The quirky signature must be exactly the same with the original signature of your device To see if the quirky is applied you can have a look in the details info of your device when is added with ZHA Hope that help you

Srjosep commented 10 months ago

Hello @Srjosep You need to create the config/zha_quirks et copy your quirk into The quirky signature must exactly the same with the original signature of your device To sse if the quirky is applied you can see it in the details info of your device when is added with ZHA Hope that help you

That's what I did... But in the details info I can read quirk isn't applied. I must have any problem with the signature, but I can't find it...

lesissou commented 10 months ago

Could you post your device signature ?

Srjosep commented 10 months ago

Sure, this is what I get on log:

"manufacturer": "_TZE204_81yrt3lo", "model": "TS0601", "name": "_TZE204_81yrt3lo TS0601", "quirk_applied": false,
"quirk_class": "zigpy.device.Device", "manufacturer_code": 4417, "power_source": "Mains", "lqi": 108, "rssi": -73, "last_seen": "2023-09-02T18:04:45", "available": true, "device_type": "Router", "signature": { "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.FullFunctionDevice|MainsPowered|RxOnWhenIdle|AllocateAddress: 142>, manufacturer_code=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, descriptor_capability_field=<DescriptorCapability.NONE: 0>, allocate_address=True, is_alternate_pan_coordinator=False, is_coordinator=False, is_end_device=False, is_full_function_device=True, is_mains_powered=True, is_receiver_on_when_idle=True, is_router=True, *is_security_capable=False)", "endpoints": {

lesissou commented 10 months ago

And the endpoint ?

Srjosep commented 10 months ago

This...

"endpoints": { "1": { "profile_id": "0x0104", "device_type": "0x0051", "input_clusters": [ "0x0000", "0x0004", "0x0005", "0xef00" ], "output_clusters": [ "0x000a", "0x0019" ] }, "242": { "profile_id": "0xa1e0", "device_type": "0x0061", "input_clusters": [], "output_clusters": [ "0x0021" ] } }, "manufacturer": "_TZE204_81yrt3lo", "model": "TS0601" }, "active_coordinator": false, "entities": [], "neighbors": [], "routes": [], "endpoint_names": [ { "name": "SMART_PLUG" }, { "name": "PROXY_BASIC" } ], "user_given_name": null, "device_reg_id": "c7f139fc3dc0c3829df8cef20d87199b", "area_id": null, "cluster_details": { "1": { "device_type": { "name": "SMART_PLUG", "id": 81 }, "profile_id": 260, "in_clusters": { "0x0004": { "endpoint_attribute": "groups", "attributes": {}, "unsupported_attributes": {} }, "0x0005": { "endpoint_attribute": "scenes", "attributes": {}, "unsupported_attributes": {} }, "0xef00": { "endpoint_attribute": null, "attributes": {}, "unsupported_attributes": {} }, "0x0000": { "endpoint_attribute": "basic", "attributes": { "0x0001": { "attribute_name": "app_version", "value": 74 }, "0x0004": { "attribute_name": "manufacturer", "value": "_TZE204_81yrt3lo" }, "0x0005": { "attribute_name": "model", "value": "TS0601" } }, "unsupported_attributes": {} } }, "out_clusters": { "0x0019": { "endpoint_attribute": "ota", "attributes": {}, "unsupported_attributes": {} }, "0x000a": { "endpoint_attribute": "time", "attributes": {}, "unsupported_attributes": {} } } }, "242": { "device_type": { "name": "PROXY_BASIC", "id": 97 }, "profile_id": 41440, "in_clusters": {}, "out_clusters": { "0x0021": { "endpoint_attribute": "green_power", "attributes": {}, "unsupported_attributes": {} } } } } } }

lesissou commented 10 months ago

OK I think you can used my quirck because the list of data are different (see https://github.com/Koenkk/zigbee2mqtt/issues/18419) Do you add _TZE204_81yrt3lo TS0601 in your quirk ? See below MODELS_INFO: [ ("_TZE200_lsanae15", "TS0601"), ("_TZE204_lsanae15", "TS0601"), ("_TZE204_rhblgy0z", "TS0601"), ("_TZE204_81yrt3lo ", "TS0601"),

Srjosep commented 10 months ago

Is ts0601_din_power.py ? Mine looks like:

MODELS_INFO: [ ("_TZE200_byzdayie", "TS0601"), ("_TZE200_ewxhg6o9", "TS0601"), ("_TZE204_81yrt3lo ", "TS0601"),

Maybe I've got the wrong file

lesissou commented 10 months ago

this file is used by ZHA so you cannot used it into the custom quirk You need to rename this file (as you want), modify and copy it into custom quirk directory You need to modify the "HikingPowerMeter" class not the other (TuyaPowerMeter) add this in the signature

    MODELS_INFO: [
          ("_TZE200_bkkmqmyo", "TS0601"),
          ("_TZE204_81yrt3lo ", "TS0601"),
    ],

and

        242: {
            # <SimpleDescriptor endpoint=242 profile=41440 device_type=61
            # input_clusters=[]
            # output_clusters=[21]
            PROFILE_ID: zgp.PROFILE_ID,
            DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
            INPUT_CLUSTERS: [],
            OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
        },

replace the first 5 lines by

from zigpy.profiles import zha, zgp import zigpy.types as t from zigpy.zcl.clusters.general import Basic, Groups, Ota, Scenes, Time, GreenPowerProxy from zigpy.zcl.clusters.homeautomation import ElectricalMeasurement from zigpy.zcl.clusters.smartenergy import Metering

Srjosep commented 10 months ago

Working now, but only summation delivered. This is the quirk that is loaded fine `"""Tuya Din Power Meter.""" from zigpy.profiles import zha import zigpy.types as t from zigpy.zcl.clusters.general import Basic, Groups, Ota, Scenes, Time, GreenPowerProxy 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 ( NoManufacturerCluster, TuyaManufClusterAttributes, TuyaSwitch, )

import logging _LOGGER = logging.getLogger(name)

TUYA_TOTAL_ENERGY_ATTR = 0x0201 #total energy /100 0x0211 TUYA_CURRENT_ATTR = 0x0011 #0x0212 TUYA_POWER_ATTR = 0x0006 #0x0213 TUYA_VOLTAGE_ATTR = 0x0004 #0x0214

class TuyaManufClusterDinPower(TuyaManufClusterAttributes): """Manufacturer Specific Cluster of the Tuya Power Meter device."""

attributes = {
    TUYA_TOTAL_ENERGY_ATTR: ("energy", t.uint16_t, True),
    TUYA_CURRENT_ATTR: ("current", t.int16s, True),      #t.int16s
    TUYA_POWER_ATTR: ("power", t.uint64_t, True),         #t.uint16_t
    TUYA_VOLTAGE_ATTR: ("voltage", t.uint16_t, True),
}

def _update_attribute(self, attrid, value):
    #super()._update_attribute(attrid, value)
    if attrid == TUYA_TOTAL_ENERGY_ATTR:
        self.endpoint.smartenergy_metering.energy_reported(value)
        super()._update_attribute(attrid, value)
    elif attrid == TUYA_CURRENT_ATTR:
        _LOGGER.warning("TUYA_CURRENT_ATTR (0x%04x) value: %d (0x%x)" % (attrid, value, value))
    elif attrid == TUYA_POWER_ATTR:
        self.endpoint.electrical_measurement.voltage_reported((value >> 48) & 0xffff)
        self.endpoint.electrical_measurement.current_reported((value >> 24) & 0xffffff)
        self.endpoint.electrical_measurement.power_reported(value & 0xffffff)
        super()._update_attribute(TUYA_VOLTAGE_ATTR, (value >> 48) & 0xffff)
        super()._update_attribute(TUYA_CURRENT_ATTR, (value >> 24) & 0xffffff)
        super()._update_attribute(TUYA_POWER_ATTR, value & 0xffffff)
    elif attrid == TUYA_VOLTAGE_ATTR:
        _LOGGER.warning("TUYA_VOLTAGE_ATTR (0x%04x) value: %d (0x%x)" % (attrid, value, value))
    else:
        super()._update_attribute(attrid, value)
        _LOGGER.warning("attrid: 0x%04x value: %d (0x%x)" % (attrid, value, value))

class TuyaPowerMeasurement(LocalDataCluster, ElectricalMeasurement): """Custom class for power, voltage and current measurement."""

cluster_id = ElectricalMeasurement.cluster_id

POWER_ID = 0x050b             #0x050B
VOLTAGE_ID = 0x0505
CURRENT_ID = 0x0508

AC_VOLTAGE_MULTIPLIER = 0x0600
AC_VOLTAGE_DIVISOR = 0x0601
AC_CURRENT_MULTIPLIER = 0x0602
AC_CURRENT_DIVISOR = 0x0603

_CONSTANT_ATTRIBUTES = {AC_CURRENT_MULTIPLIER: 1, AC_CURRENT_DIVISOR: 1000, AC_VOLTAGE_MULTIPLIER: 1, AC_VOLTAGE_DIVISOR: 10}

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 current_reported(self, value):
    """Ampers reported."""
    self._update_attribute(self.CURRENT_ID, value)

class TuyaElectricalMeasurement(LocalDataCluster, Metering): """Custom class for total energy measurement."""

cluster_id = Metering.cluster_id
CURRENT_SUMM_DELIVERED_ID = 0x0000
UNIT_OF_MEASURE_ID = 0x0300
MULTIPLIER_ID = 0x0301
DIVISOR_ID = 0x0302
POWER_WATT_ENUM = 0x0000

"""Setting unit of measurement."""
_CONSTANT_ATTRIBUTES = {UNIT_OF_MEASURE_ID: POWER_WATT_ENUM, DIVISOR_ID: 100}

def energy_reported(self, value):
    """Summation Energy reported."""
    self._update_attribute(self.CURRENT_SUMM_DELIVERED_ID, value)

class TuyaPowerMeter(TuyaSwitch): """Tuya power meter device."""

signature = {
    # "node_descriptor": "<NodeDescriptor byte1=1 byte2=64 mac_capability_flags=142 manufacturer_code=4098
    #                       maximum_buffer_size=82 maximum_incoming_transfer_size=82 server_mask=11264
    #                       maximum_outgoing_transfer_size=82 descriptor_capability_field=0>",
    # device_version=1
    # input_clusters=[0x0000, 0x0004, 0x0005, 0xef00]
    # output_clusters=[0x000a, 0x0019]
    MODELS_INFO: [
        ("_TZE200_byzdayie", "TS0601"),
        ("_TZE200_ewxhg6o9", "TS0601"),
        ("_TZE204_81yrt3lo", "TS0601"),
    ],
    ENDPOINTS: {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=51
        # device_version=1
        # input_clusters=[0, 4, 5, 61184]
        # output_clusters=[10, 25]>
        1: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
            INPUT_CLUSTERS: [
                Basic.cluster_id,
                Groups.cluster_id,
                Scenes.cluster_id,
                TuyaManufClusterAttributes.cluster_id,
            ],
            OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
        }
    },
}

replacement = {
    ENDPOINTS: {
        1: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
            INPUT_CLUSTERS: [
                Basic.cluster_id,
                Groups.cluster_id,
                Scenes.cluster_id,
                TuyaManufClusterDinPower,
                TuyaPowerMeasurement,
                TuyaElectricalMeasurement,
            ],
            OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
        }
    }
}

class TuyaPowerMeter_GPP(TuyaSwitch): """Tuya power meter device."""

signature = {
    # "node_descriptor": "<NodeDescriptor byte1=1 byte2=64 mac_capability_flags=142 manufacturer_code=4417
    #                       maximum_buffer_size=66 maximum_incoming_transfer_size=66 server_mask=10752
    #                       maximum_outgoing_transfer_size=66 descriptor_capability_field=0>",
    # device_version=1
    # input_clusters=[0x0000, 0x0004, 0x0005, 0xef00]
    # output_clusters=[0x000a, 0x0019]
    MODELS_INFO: [
        ("_TZE200_lsanae15", "TS0601"),
        ("_TZE204_81yrt3lo", "TS0601"),
    ],
    ENDPOINTS: {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=51
        # device_version=1
        # input_clusters=[0, 4, 5, 61184]
        # output_clusters=[10, 25]>
        1: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
            INPUT_CLUSTERS: [
                Basic.cluster_id,
                Groups.cluster_id,
                Scenes.cluster_id,
                TuyaManufClusterAttributes.cluster_id,
            ],
            OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
        },
        242: {
            # <SimpleDescriptor endpoint=242 profile=41440 device_type=61
            # input_clusters=[]
            # output_clusters=[21]
            PROFILE_ID: 41440,
            DEVICE_TYPE: 97,
            INPUT_CLUSTERS: [],
            OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
        },
    },
}

replacement = {
    ENDPOINTS: {
        1: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
            INPUT_CLUSTERS: [
                Basic.cluster_id,
                Groups.cluster_id,
                Scenes.cluster_id,
                TuyaManufClusterDinPower,
                TuyaPowerMeasurement,
                TuyaElectricalMeasurement,
            ],
            OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
        },
        242: {
            # <SimpleDescriptor endpoint=242 profile=41440 device_type=61
            # input_clusters=[]
            # output_clusters=[21]
            PROFILE_ID: 41440,
            DEVICE_TYPE: 97,
            INPUT_CLUSTERS: [],
            OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
        },
    }
}`

And this is the result. image

lesissou commented 10 months ago

Don't use my quirk file because it isn't for your device.

Copy the code below into your file (replace the code) I hope this will work ....

"""Tuya Din Power Meter.""" from zigpy.profiles import zha, zgp import zigpy.types as t from zigpy.zcl.clusters.general import Basic, Groups, Ota, Scenes, Time, GreenPowerProxy 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

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 TuyaPowerMeter(TuyaSwitch): """Tuya power meter device."""

def __init__(self, *args, **kwargs):
    """Init device."""
    self.switch_bus = Bus()
    super().__init__(*args, **kwargs)

signature = {
    # "node_descriptor": "<NodeDescriptor byte1=1 byte2=64 mac_capability_flags=142 manufacturer_code=4098
    #                       maximum_buffer_size=82 maximum_incoming_transfer_size=82 server_mask=11264
    #                       maximum_outgoing_transfer_size=82 descriptor_capability_field=0>",
    # device_version=1
    # input_clusters=[0x0000, 0x0004, 0x0005, 0xef00]
    # output_clusters=[0x000a, 0x0019]
    MODELS_INFO: [
        ("_TZE200_byzdayie", "TS0601"),
        ("_TZE200_ewxhg6o9", "TS0601"),
    ],
    ENDPOINTS: {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=51
        # device_version=1
        # input_clusters=[0, 4, 5, 61184]
        # output_clusters=[10, 25]>
        1: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
            INPUT_CLUSTERS: [
                Basic.cluster_id,
                Groups.cluster_id,
                Scenes.cluster_id,
                TuyaManufClusterAttributes.cluster_id,
            ],
            OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
        }
    },
}

replacement = {
    ENDPOINTS: {
        1: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
            INPUT_CLUSTERS: [
                Basic.cluster_id,
                Groups.cluster_id,
                Scenes.cluster_id,
                TuyaManufClusterDinPower,
                TuyaPowerMeasurement,
                TuyaElectricalMeasurement,
                TuyaOnOff,
            ],
            OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
        }
    }
}

class HikingPowerMeter(TuyaSwitch): """Hiking Power Meter Device - DDS238-2."""

signature = {
    # "node_descriptor": "<NodeDescriptor byte1=1 byte2=64 mac_capability_flags=142 manufacturer_code=4098
    #                       maximum_buffer_size=82 maximum_incoming_transfer_size=82 server_mask=11264
    #                       maximum_outgoing_transfer_size=82 descriptor_capability_field=0>",
    # device_version=1
    # input_clusters=[0x0000, 0x0004, 0x0005, 0xef00]
    # output_clusters=[0x000a, 0x0019]
    MODELS_INFO: [
      ("_TZE200_bkkmqmyo", "TS0601"),
      ("_TZE204_81yrt3lo ", "TS0601"),
    ],      
    ENDPOINTS: {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=51
        # device_version=1
        # input_clusters=[0, 4, 5, 61184]
        # output_clusters=[10, 25]>
        1: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
            INPUT_CLUSTERS: [
                Basic.cluster_id,
                Groups.cluster_id,
                Scenes.cluster_id,
                TuyaManufClusterAttributes.cluster_id,
            ],
            OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
        }
        242: {
            # <SimpleDescriptor endpoint=242 profile=41440 device_type=61
            # input_clusters=[]
            # output_clusters=[21]
            PROFILE_ID: zgp.PROFILE_ID,
            DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
            INPUT_CLUSTERS: [],
            OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
        },
    },
}

replacement = {
    ENDPOINTS: {
        1: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
            INPUT_CLUSTERS: [
                Basic.cluster_id,
                Groups.cluster_id,
                Scenes.cluster_id,
                HikingManufClusterDinPower,
                TuyaElectricalMeasurement,
                TuyaPowerMeasurement,
            ],
            OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
        },
        16: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
            INPUT_CLUSTERS: [
                TuyaOnOff,
            ],
            OUTPUT_CLUSTERS: [],
        },
    }
}
Srjosep commented 10 months ago

Don't work... the quirk isn't applied.
image

TheJulianJES commented 9 months ago

Is this solved now? We should ideally keep issues open until the issue is fixed in zha-quirks/HA (without using custom quirks).

lesissou commented 9 months ago

No it isn't solve : I reopen this issue.

Roos-AID commented 6 months ago

Hi, I also acquired this device. Tried all above suggestions to modify existing TS0601 quirks but cannot get it to work. No values are shown with ZHA and switch cannot be used. The only values shown are RSSI and LQI (when enabled).

"manufacturer": "_TZE204_rhblgy0z", "name": "_TZE204_rhblgy0z TS0601",

So, I did setup Rpi with ZIgbee2MQTT and voila, it works there. Not the ideal long term solution. This is the Zigbee2MQTT page https://www.zigbee2mqtt.io/devices/TS0601_din_3.html that works with the device.

Will try to debug a little bit more.

I found a lot of errors when no Quirk is applied Logger: zigpy.zcl Source: runner.py:188 First occurred: 15:27:56 (2 occurrences) Last logged: 15:27:57

[0x130A:1:0xef00] Unknown cluster command 2 b'\x00\x08\x04\x00\x00\x08\x01\x05\x01\x05\x00\x00\x00\x00' [0x130A:1:0xef00] Unknown cluster command 2 b'\x00\x0b\x0b\x00\x00\x02\x01\x00'

Roos-AID commented 5 months ago

I found a partial solution, I have now implemeted the version https://github.com/zigpy/zha-device-handlers/issues/2553#issuecomment-1704138325 with modification in class TuyaPowerMeter_GPP(TuyaSwitch): added ("_TZE204_rhblgy0z", "TS0601").

However, although this seems to fix the errors, it show the returned total energy in stead off the consumed energy.

image

TUYA_TOTAL_ENERGY_ATTR = 0x0201 is pointing to returned energy.

I have tried all kind of values, but can't find the missing Energy Consumed or Energy Total.

BluePenguin0 commented 4 months ago

Does anyone have a working quirk file for 'TS0601 _TZE204_81yrt3lo' (for ZHA)?

lesissou commented 4 months ago

See beelow, I put a working quirk file for 'TS0601 _TZE204_81yrt3lo' (for ZHA). You need to put the file in the quircks directory and add the files into configuration.yaml : _zha: custom_quirks_path: /config/_

When you add your device, sometimes it isn't working for the first time. So you need to reboot HA and after is working well (normally).

I hope that's help you

BluePenguin0 commented 4 months ago

See beelow, I put a working quirk file for 'TS0601 _TZE204_81yrt3lo' (for ZHA). Hi, Sorry - I'm not being very bright today. There was no file attached? I have checked the 'code' section and cannot see a file either. The 'ts0601_din_power.py' - does not reference the device I have (_TZE204_81yrt3lo) which is a 2 channel CT clamp. I have tried adding my device to this file. Cleared cache, rebooted, reconfigured, removed and readded....still nothing. So sorry for my newbieness! (only had HA for about a month - sooo much to learn).

noseshimself commented 2 weeks ago

I don't want to complain but things were easier if people formatted their postings a bit better; this is python and damaging the indentation is making it quite useless.