Skip to content

Instantly share code, notes, and snippets.

@manyos-robert
Created January 15, 2024 13:10
Show Gist options
  • Save manyos-robert/bbfb76d9b1735416376a5900d76987a9 to your computer and use it in GitHub Desktop.
Save manyos-robert/bbfb76d9b1735416376a5900d76987a9 to your computer and use it in GitHub Desktop.
"""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.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: [
("_TZE204_lsanae15", "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],
},
}
}
@AlexKorsakov
Copy link

Thank you, man!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment