Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
lesissou opened this issue Aug 29, 2023 · 31 comments
Open

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

lesissou opened this issue Aug 29, 2023 · 31 comments
Labels
Tuya Request/PR regarding a Tuya device

Comments

@lesissou
Copy link

lesissou commented Aug 29, 2023

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
[Paste the device signature here]
{
  "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": {
    "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"
}

</details>


### Diagnostic information

<details><summary>Diagnostic information</summary>

```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=<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": {
        "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": {}
          }
        }
      }
    }
  }
}
</details>


### Logs

<details><summary>Logs</summary>

```python
[Paste the logs here]

Custom quirk

Custom quirk
"""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": "<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,
                ],
                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_lsanae15", "TS0601"),
            ("_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: {
                # <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,
                    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: zgp.PROFILE_ID,
                DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        }
    }

</details>


### Additional information

_No response_
@lesissou lesissou changed the title [Device Support Request] TS0601 by _TZE204_rhblgy0z [Device Support Request] TS0601 by _TZE204_rhblgy0z DIN Power Aug 29, 2023
@lesissou
Copy link
Author

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

@TheJulianJES TheJulianJES added the Tuya Request/PR regarding a Tuya device label Aug 29, 2023
@lesissou
Copy link
Author

lesissou commented Aug 30, 2023

@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
Copy link

Srjosep commented Aug 30, 2023

@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. Koenkk/zigbee2mqtt#18419 (comment)

@lesissou
Copy link
Author

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
Copy link

Srjosep commented Aug 31, 2023

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
Copy link
Author

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
Copy link

Srjosep commented Aug 31, 2023

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
Copy link
Author

I find this issue, I will try this quirk : #1768

@lesissou
Copy link
Author

lesissou commented Aug 31, 2023

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
Copy link

Srjosep commented Sep 2, 2023

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

@lesissou
Copy link
Author

lesissou commented Sep 2, 2023

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
Copy link

Srjosep commented Sep 2, 2023

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
Copy link
Author

lesissou commented Sep 2, 2023

Could you post your device signature ?

@Srjosep
Copy link

Srjosep commented Sep 2, 2023

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
Copy link
Author

lesissou commented Sep 2, 2023

And the endpoint ?

@Srjosep
Copy link

Srjosep commented Sep 2, 2023

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
Copy link
Author

lesissou commented Sep 2, 2023

OK
I think you can used my quirck because the list of data are different (see Koenkk/zigbee2mqtt#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
Copy link

Srjosep commented Sep 2, 2023

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
Copy link
Author

lesissou commented Sep 2, 2023

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
Copy link

Srjosep commented Sep 3, 2023

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
Copy link
Author

lesissou commented Sep 3, 2023

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
Copy link

Srjosep commented Sep 3, 2023

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

@TheJulianJES
Copy link
Collaborator

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

@lesissou
Copy link
Author

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

@lesissou lesissou reopened this Sep 17, 2023
@Roos-AID
Copy link

Roos-AID commented Jan 5, 2024

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
Copy link

Roos-AID commented Jan 16, 2024

I found a partial solution, I have now implemeted the version #2553 (comment) 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
Copy link

BluePenguin0 commented Feb 7, 2024

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

@lesissou
Copy link
Author

lesissou commented Feb 8, 2024

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/<quirks_directory>

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
Copy link

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
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Tuya Request/PR regarding a Tuya device
Projects
None yet
Development

No branches or pull requests

6 participants