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 _TZE284_81yrt3lo Tuya Smart Life Dual channel energy meter #3658

Open
Ralim opened this issue Dec 31, 2024 · 10 comments

Comments

@Ralim
Copy link

Ralim commented Dec 31, 2024

Problem description

Would like help in adding support for this small 2 channel AC power meter.
Purchased from Aliexpress.

Solution description

Able to see the power readings for the two channels

Screenshots/Video

Screenshots/Video

[Paste/upload your media here]

Device signature

Device signature
{
  "node_descriptor": {
    "logical_type": 1,
    "complex_descriptor_available": 0,
    "user_descriptor_available": 0,
    "reserved": 0,
    "aps_flags": 0,
    "frequency_band": 8,
    "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
  },
  "endpoints": {
    "1": {
      "profile_id": "0x0104",
      "device_type": "0x0051",
      "input_clusters": [
        "0x0000",
        "0x0004",
        "0x0005",
        "0xed00",
        "0xef00"
      ],
      "output_clusters": [
        "0x000a",
        "0x0019"
      ]
    },
    "242": {
      "profile_id": "0xa1e0",
      "device_type": "0x0061",
      "input_clusters": [],
      "output_clusters": [
        "0x0021"
      ]
    }
  },
  "manufacturer": "_TZE284_81yrt3lo",
  "model": "TS0601",
  "class": "zigpy.device.Device"
}

Diagnostic information

Diagnostic information
{
  "home_assistant": {
    "installation_type": "Home Assistant OS",
    "version": "2024.12.5",
    "dev": false,
    "hassio": true,
    "virtualenv": false,
    "python_version": "3.13.0",
    "docker": true,
    "arch": "aarch64",
    "timezone": "Australia/Sydney",
    "os_name": "Linux",
    "os_version": "6.6.62-haos-raspi",
    "supervisor": "2024.12.0",
    "host_os": "Home Assistant OS 14.1",
    "docker_version": "27.2.0",
    "chassis": "embedded",
    "run_as_root": true
  },
  "custom_components": {
    "hacs": {
      "documentation": "https://hacs.xyz/docs/configuration/start",
      "version": "2.0.1",
      "requirements": [
        "aiogithubapi>=22.10.1"
      ]
    },
    "waste_collection_schedule": {
      "documentation": "https://github.com/mampfes/hacs_waste_collection_schedule#readme",
      "version": "2.5.0",
      "requirements": [
        "icalendar",
        "recurring_ical_events",
        "icalevents>=0.1.26,!=0.1.28",
        "beautifulsoup4",
        "lxml",
        "pycryptodome"
      ]
    }
  },
  "integration_manifest": {
    "domain": "zha",
    "name": "Zigbee Home Automation",
    "after_dependencies": [
      "hassio",
      "onboarding",
      "usb"
    ],
    "codeowners": [
      "dmulcahey",
      "adminiuga",
      "puddly",
      "TheJulianJES"
    ],
    "config_flow": true,
    "dependencies": [
      "file_upload"
    ],
    "documentation": "https://www.home-assistant.io/integrations/zha",
    "iot_class": "local_polling",
    "loggers": [
      "aiosqlite",
      "bellows",
      "crccheck",
      "pure_pcapy3",
      "zhaquirks",
      "zigpy",
      "zigpy_deconz",
      "zigpy_xbee",
      "zigpy_zigate",
      "zigpy_znp",
      "zha",
      "universal_silabs_flasher"
    ],
    "requirements": [
      "universal-silabs-flasher==0.0.25",
      "zha==0.0.42"
    ],
    "usb": [
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*2652*",
        "known_devices": [
          "slae.sh cc2652rb stick"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*slzb-07*",
        "known_devices": [
          "smlight slzb-07"
        ]
      },
      {
        "vid": "1A86",
        "pid": "55D4",
        "description": "*sonoff*plus*",
        "known_devices": [
          "sonoff zigbee dongle plus v2"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*sonoff*plus*",
        "known_devices": [
          "sonoff zigbee dongle plus"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*tubeszb*",
        "known_devices": [
          "TubesZB Coordinator"
        ]
      },
      {
        "vid": "1A86",
        "pid": "7523",
        "description": "*tubeszb*",
        "known_devices": [
          "TubesZB Coordinator"
        ]
      },
      {
        "vid": "1A86",
        "pid": "7523",
        "description": "*zigstar*",
        "known_devices": [
          "ZigStar Coordinators"
        ]
      },
      {
        "vid": "1CF1",
        "pid": "0030",
        "description": "*conbee*",
        "known_devices": [
          "Conbee II"
        ]
      },
      {
        "vid": "0403",
        "pid": "6015",
        "description": "*conbee*",
        "known_devices": [
          "Conbee III"
        ]
      },
      {
        "vid": "10C4",
        "pid": "8A2A",
        "description": "*zigbee*",
        "known_devices": [
          "Nortek HUSBZB-1"
        ]
      },
      {
        "vid": "0403",
        "pid": "6015",
        "description": "*zigate*",
        "known_devices": [
          "ZiGate+"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*zigate*",
        "known_devices": [
          "ZiGate"
        ]
      },
      {
        "vid": "10C4",
        "pid": "8B34",
        "description": "*bv 2010/10*",
        "known_devices": [
          "Bitron Video AV2010/10"
        ]
      }
    ],
    "zeroconf": [
      {
        "type": "_esphomelib._tcp.local.",
        "name": "tube*"
      },
      {
        "type": "_zigate-zigbee-gateway._tcp.local.",
        "name": "*zigate*"
      },
      {
        "type": "_zigstar_gw._tcp.local.",
        "name": "*zigstar*"
      },
      {
        "type": "_uzg-01._tcp.local.",
        "name": "uzg-01*"
      },
      {
        "type": "_slzb-06._tcp.local.",
        "name": "slzb-06*"
      },
      {
        "type": "_xzg._tcp.local.",
        "name": "xzg*"
      },
      {
        "type": "_czc._tcp.local.",
        "name": "czc*"
      },
      {
        "type": "_zigbee-coordinator._tcp.local.",
        "name": "*"
      }
    ],
    "is_built_in": true,
    "overwrites_built_in": false
  },
  "setup_times": {
    "null": {
      "setup": 0.0001411839621141553
    },
    "1e3e986c701bf2ab7361cb8960ad6f16": {
      "config_entry_setup": 23.60823148302734
    }
  },
  "data": {
    "ieee": "**REDACTED**",
    "nwk": 12546,
    "manufacturer": "_TZE284_81yrt3lo",
    "model": "TS0601",
    "name": "_TZE284_81yrt3lo TS0601",
    "quirk_applied": false,
    "quirk_class": "zigpy.device.Device",
    "quirk_id": null,
    "manufacturer_code": 4417,
    "power_source": "Mains",
    "lqi": 255,
    "rssi": -80,
    "last_seen": "2024-12-31T11:34:04",
    "available": true,
    "device_type": "Router",
    "signature": {
      "node_descriptor": {
        "logical_type": 1,
        "complex_descriptor_available": 0,
        "user_descriptor_available": 0,
        "reserved": 0,
        "aps_flags": 0,
        "frequency_band": 8,
        "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
      },
      "endpoints": {
        "1": {
          "profile_id": "0x0104",
          "device_type": "0x0051",
          "input_clusters": [
            "0x0000",
            "0x0004",
            "0x0005",
            "0xed00",
            "0xef00"
          ],
          "output_clusters": [
            "0x000a",
            "0x0019"
          ]
        },
        "242": {
          "profile_id": "0xa1e0",
          "device_type": "0x0061",
          "input_clusters": [],
          "output_clusters": [
            "0x0021"
          ]
        }
      },
      "manufacturer": "_TZE284_81yrt3lo",
      "model": "TS0601"
    },
    "active_coordinator": false,
    "entities": [
      {
        "entity_id": "update.back_ac_firmware",
        "name": "_TZE284_81yrt3lo TS0601"
      }
    ],
    "neighbors": [
      {
        "device_type": "Router",
        "rx_on_when_idle": "On",
        "relationship": "Parent",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0x399E",
        "permit_joining": "Unknown",
        "depth": "3",
        "lqi": "45"
      },
      {
        "device_type": "Router",
        "rx_on_when_idle": "On",
        "relationship": "Sibling",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0x8CF3",
        "permit_joining": "Unknown",
        "depth": "3",
        "lqi": "30"
      }
    ],
    "routes": [],
    "endpoint_names": [
      {
        "name": "SMART_PLUG"
      },
      {
        "name": "PROXY_BASIC"
      }
    ],
    "user_given_name": "Back AC",
    "device_reg_id": "7693de6f89a8265645ded656338c7ad0",
    "area_id": "energy_generation",
    "cluster_details": {
      "1": {
        "device_type": {
          "name": "SMART_PLUG",
          "id": 81
        },
        "profile_id": 260,
        "in_clusters": {
          "0x0004": {
            "endpoint_attribute": "groups",
            "attributes": {
              "0xfffd": {
                "attribute": "ZCLAttributeDef(id=0xFFFD, name='cluster_revision', type=<class 'zigpy.types.basic.uint16_t'>, zcl_type=<DataTypeId.uint16: 33>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0000": {
                "attribute": "ZCLAttributeDef(id=0x0000, name='name_support', type=<flag 'NameSupport'>, zcl_type=<DataTypeId.map8: 24>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0xfffe": {
                "attribute": "ZCLAttributeDef(id=0xFFFE, name='reporting_status', type=<enum 'AttributeReportingStatus'>, zcl_type=<DataTypeId.enum8: 48>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              }
            },
            "unsupported_attributes": []
          },
          "0x0005": {
            "endpoint_attribute": "scenes",
            "attributes": {
              "0xfffd": {
                "attribute": "ZCLAttributeDef(id=0xFFFD, name='cluster_revision', type=<class 'zigpy.types.basic.uint16_t'>, zcl_type=<DataTypeId.uint16: 33>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0000": {
                "attribute": "ZCLAttributeDef(id=0x0000, name='count', type=<class 'zigpy.types.basic.uint8_t'>, zcl_type=<DataTypeId.uint8: 32>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0002": {
                "attribute": "ZCLAttributeDef(id=0x0002, name='current_group', type=<class 'zigpy.types.basic.uint16_t'>, zcl_type=<DataTypeId.uint16: 33>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0001": {
                "attribute": "ZCLAttributeDef(id=0x0001, name='current_scene', type=<class 'zigpy.types.basic.uint8_t'>, zcl_type=<DataTypeId.uint8: 32>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0005": {
                "attribute": "ZCLAttributeDef(id=0x0005, name='last_configured_by', type=<class 'zigpy.types.named.EUI64'>, zcl_type=<DataTypeId.EUI64: 240>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0004": {
                "attribute": "ZCLAttributeDef(id=0x0004, name='name_support', type=<flag 'NameSupport'>, zcl_type=<DataTypeId.map8: 24>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0xfffe": {
                "attribute": "ZCLAttributeDef(id=0xFFFE, name='reporting_status', type=<enum 'AttributeReportingStatus'>, zcl_type=<DataTypeId.enum8: 48>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0003": {
                "attribute": "ZCLAttributeDef(id=0x0003, name='scene_valid', type=<enum 'Bool'>, zcl_type=<DataTypeId.bool_: 16>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              }
            },
            "unsupported_attributes": []
          },
          "0xef00": {
            "endpoint_attribute": null,
            "attributes": {},
            "unsupported_attributes": []
          },
          "0x0000": {
            "endpoint_attribute": "basic",
            "attributes": {
              "0x0013": {
                "attribute": "ZCLAttributeDef(id=0x0013, name='alarm_mask', type=<flag 'AlarmMask'>, zcl_type=<DataTypeId.map8: 24>, access=<ZCLAttributeAccess.Read|Write: 3>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0001": {
                "attribute": "ZCLAttributeDef(id=0x0001, name='app_version', type=<class 'zigpy.types.basic.uint8_t'>, zcl_type=<DataTypeId.uint8: 32>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": 78
              },
              "0xfffd": {
                "attribute": "ZCLAttributeDef(id=0xFFFD, name='cluster_revision', type=<class 'zigpy.types.basic.uint16_t'>, zcl_type=<DataTypeId.uint16: 33>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0006": {
                "attribute": "ZCLAttributeDef(id=0x0006, name='date_code', type=<class 'zigpy.types.basic.LimitedCharString.<locals>.LimitedCharString'>, zcl_type=<DataTypeId.string: 66>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0012": {
                "attribute": "ZCLAttributeDef(id=0x0012, name='device_enabled', type=<enum 'Bool'>, zcl_type=<DataTypeId.bool_: 16>, access=<ZCLAttributeAccess.Read|Write: 3>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0014": {
                "attribute": "ZCLAttributeDef(id=0x0014, name='disable_local_config', type=<flag 'DisableLocalConfig'>, zcl_type=<DataTypeId.map8: 24>, access=<ZCLAttributeAccess.Read|Write: 3>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0008": {
                "attribute": "ZCLAttributeDef(id=0x0008, name='generic_device_class', type=<enum 'GenericDeviceClass'>, zcl_type=<DataTypeId.enum8: 48>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0009": {
                "attribute": "ZCLAttributeDef(id=0x0009, name='generic_device_type', type=<enum 'GenericLightingDeviceType'>, zcl_type=<DataTypeId.enum8: 48>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0003": {
                "attribute": "ZCLAttributeDef(id=0x0003, name='hw_version', type=<class 'zigpy.types.basic.uint8_t'>, zcl_type=<DataTypeId.uint8: 32>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0010": {
                "attribute": "ZCLAttributeDef(id=0x0010, name='location_desc', type=<class 'zigpy.types.basic.LimitedCharString.<locals>.LimitedCharString'>, zcl_type=<DataTypeId.string: 66>, access=<ZCLAttributeAccess.Read|Write: 3>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0004": {
                "attribute": "ZCLAttributeDef(id=0x0004, name='manufacturer', type=<class 'zigpy.types.basic.LimitedCharString.<locals>.LimitedCharString'>, zcl_type=<DataTypeId.string: 66>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": "_TZE284_81yrt3lo"
              },
              "0x000c": {
                "attribute": "ZCLAttributeDef(id=0x000C, name='manufacturer_version_details', type=<class 'zigpy.types.basic.CharacterString'>, zcl_type=<DataTypeId.string: 66>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0005": {
                "attribute": "ZCLAttributeDef(id=0x0005, name='model', type=<class 'zigpy.types.basic.LimitedCharString.<locals>.LimitedCharString'>, zcl_type=<DataTypeId.string: 66>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": "TS0601"
              },
              "0x0011": {
                "attribute": "ZCLAttributeDef(id=0x0011, name='physical_env', type=<enum 'PhysicalEnvironment'>, zcl_type=<DataTypeId.enum8: 48>, access=<ZCLAttributeAccess.Read|Write: 3>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0007": {
                "attribute": "ZCLAttributeDef(id=0x0007, name='power_source', type=<enum 'PowerSource'>, zcl_type=<DataTypeId.enum8: 48>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x000a": {
                "attribute": "ZCLAttributeDef(id=0x000A, name='product_code', type=<class 'zigpy.types.basic.LVBytes'>, zcl_type=<DataTypeId.octstr: 65>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x000e": {
                "attribute": "ZCLAttributeDef(id=0x000E, name='product_label', type=<class 'zigpy.types.basic.CharacterString'>, zcl_type=<DataTypeId.string: 66>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x000b": {
                "attribute": "ZCLAttributeDef(id=0x000B, name='product_url', type=<class 'zigpy.types.basic.CharacterString'>, zcl_type=<DataTypeId.string: 66>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0xfffe": {
                "attribute": "ZCLAttributeDef(id=0xFFFE, name='reporting_status', type=<enum 'AttributeReportingStatus'>, zcl_type=<DataTypeId.enum8: 48>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x000d": {
                "attribute": "ZCLAttributeDef(id=0x000D, name='serial_number', type=<class 'zigpy.types.basic.CharacterString'>, zcl_type=<DataTypeId.string: 66>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0002": {
                "attribute": "ZCLAttributeDef(id=0x0002, name='stack_version', type=<class 'zigpy.types.basic.uint8_t'>, zcl_type=<DataTypeId.uint8: 32>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x4000": {
                "attribute": "ZCLAttributeDef(id=0x4000, name='sw_build_id', type=<class 'zigpy.types.basic.CharacterString'>, zcl_type=<DataTypeId.string: 66>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0000": {
                "attribute": "ZCLAttributeDef(id=0x0000, name='zcl_version', type=<class 'zigpy.types.basic.uint8_t'>, zcl_type=<DataTypeId.uint8: 32>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              }
            },
            "unsupported_attributes": []
          },
          "0xed00": {
            "endpoint_attribute": null,
            "attributes": {},
            "unsupported_attributes": []
          }
        },
        "out_clusters": {
          "0x0019": {
            "endpoint_attribute": "ota",
            "attributes": {
              "0xfffd": {
                "attribute": "ZCLAttributeDef(id=0xFFFD, name='cluster_revision', type=<class 'zigpy.types.basic.uint16_t'>, zcl_type=<DataTypeId.uint16: 33>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0002": {
                "attribute": "ZCLAttributeDef(id=0x0002, name='current_file_version', type=<class 'zigpy.types.basic.uint32_t'>, zcl_type=<DataTypeId.uint32: 35>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": 78
              },
              "0x0003": {
                "attribute": "ZCLAttributeDef(id=0x0003, name='current_zigbee_stack_version', type=<class 'zigpy.types.basic.uint16_t'>, zcl_type=<DataTypeId.uint16: 33>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0004": {
                "attribute": "ZCLAttributeDef(id=0x0004, name='downloaded_file_version', type=<class 'zigpy.types.basic.uint32_t'>, zcl_type=<DataTypeId.uint32: 35>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0005": {
                "attribute": "ZCLAttributeDef(id=0x0005, name='downloaded_zigbee_stack_version', type=<class 'zigpy.types.basic.uint16_t'>, zcl_type=<DataTypeId.uint16: 33>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0001": {
                "attribute": "ZCLAttributeDef(id=0x0001, name='file_offset', type=<class 'zigpy.types.basic.uint32_t'>, zcl_type=<DataTypeId.uint32: 35>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x000a": {
                "attribute": "ZCLAttributeDef(id=0x000A, name='image_stamp', type=<class 'zigpy.types.basic.uint32_t'>, zcl_type=<DataTypeId.uint32: 35>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0008": {
                "attribute": "ZCLAttributeDef(id=0x0008, name='image_type_id', type=<class 'zigpy.types.basic.uint16_t'>, zcl_type=<DataTypeId.uint16: 33>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0006": {
                "attribute": "ZCLAttributeDef(id=0x0006, name='image_upgrade_status', type=<enum 'ImageUpgradeStatus'>, zcl_type=<DataTypeId.enum8: 48>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0007": {
                "attribute": "ZCLAttributeDef(id=0x0007, name='manufacturer_id', type=<class 'zigpy.types.basic.uint16_t'>, zcl_type=<DataTypeId.uint16: 33>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0009": {
                "attribute": "ZCLAttributeDef(id=0x0009, name='minimum_block_req_delay', type=<class 'zigpy.types.basic.uint16_t'>, zcl_type=<DataTypeId.uint16: 33>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0xfffe": {
                "attribute": "ZCLAttributeDef(id=0xFFFE, name='reporting_status', type=<enum 'AttributeReportingStatus'>, zcl_type=<DataTypeId.enum8: 48>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x000b": {
                "attribute": "ZCLAttributeDef(id=0x000B, name='upgrade_activation_policy', type=<enum 'UpgradeActivationPolicy'>, zcl_type=<DataTypeId.enum8: 48>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0000": {
                "attribute": "ZCLAttributeDef(id=0x0000, name='upgrade_server_id', type=<class 'zigpy.types.named.EUI64'>, zcl_type=<DataTypeId.EUI64: 240>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x000c": {
                "attribute": "ZCLAttributeDef(id=0x000C, name='upgrade_timeout_policy', type=<enum 'UpgradeTimeoutPolicy'>, zcl_type=<DataTypeId.enum8: 48>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              }
            },
            "unsupported_attributes": []
          },
          "0x000a": {
            "endpoint_attribute": "time",
            "attributes": {
              "0xfffd": {
                "attribute": "ZCLAttributeDef(id=0xFFFD, name='cluster_revision', type=<class 'zigpy.types.basic.uint16_t'>, zcl_type=<DataTypeId.uint16: 33>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0004": {
                "attribute": "ZCLAttributeDef(id=0x0004, name='dst_end', type=<class 'zigpy.types.basic.uint32_t'>, zcl_type=<DataTypeId.uint32: 35>, access=<ZCLAttributeAccess.Read|Write: 3>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0005": {
                "attribute": "ZCLAttributeDef(id=0x0005, name='dst_shift', type=<class 'zigpy.types.basic.int32s'>, zcl_type=<DataTypeId.int32: 43>, access=<ZCLAttributeAccess.Read|Write: 3>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0003": {
                "attribute": "ZCLAttributeDef(id=0x0003, name='dst_start', type=<class 'zigpy.types.basic.uint32_t'>, zcl_type=<DataTypeId.uint32: 35>, access=<ZCLAttributeAccess.Read|Write: 3>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0008": {
                "attribute": "ZCLAttributeDef(id=0x0008, name='last_set_time', type=<class 'zigpy.types.named.UTCTime'>, zcl_type=<DataTypeId.UTC: 226>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0007": {
                "attribute": "ZCLAttributeDef(id=0x0007, name='local_time', type=<class 'zigpy.types.named.LocalTime'>, zcl_type=<DataTypeId.uint32: 35>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0xfffe": {
                "attribute": "ZCLAttributeDef(id=0xFFFE, name='reporting_status', type=<enum 'AttributeReportingStatus'>, zcl_type=<DataTypeId.enum8: 48>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0006": {
                "attribute": "ZCLAttributeDef(id=0x0006, name='standard_time', type=<class 'zigpy.types.named.StandardTime'>, zcl_type=<DataTypeId.uint32: 35>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0000": {
                "attribute": "ZCLAttributeDef(id=0x0000, name='time', type=<class 'zigpy.types.named.UTCTime'>, zcl_type=<DataTypeId.UTC: 226>, access=<ZCLAttributeAccess.Read|Write_Optional: 5>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0001": {
                "attribute": "ZCLAttributeDef(id=0x0001, name='time_status', type=<flag 'TimeStatus'>, zcl_type=<DataTypeId.map8: 24>, access=<ZCLAttributeAccess.Read|Write_Optional: 5>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0002": {
                "attribute": "ZCLAttributeDef(id=0x0002, name='time_zone', type=<class 'zigpy.types.basic.int32s'>, zcl_type=<DataTypeId.int32: 43>, access=<ZCLAttributeAccess.Read|Write: 3>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0009": {
                "attribute": "ZCLAttributeDef(id=0x0009, name='valid_until_time', type=<class 'zigpy.types.named.UTCTime'>, zcl_type=<DataTypeId.UTC: 226>, access=<ZCLAttributeAccess.Read|Write: 3>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              }
            },
            "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

Custom quirk

Custom quirk

Additional information

Happy to test quirks, help debug etc. New to custom quirks for Zigbee, but not new to python & programming. Can't find a good guide for this so filing the request while I look more.

@Ralim Ralim changed the title [Device Support Request] TS0601 _TZE284_81yrt3lo Dual energy meter [Device Support Request] TS0601 _TZE284_81yrt3lo Tuya Smart Life Dual channel energy meter Dec 31, 2024
@sasojerman
Copy link

Hello,
I’m experiencing the same issue with the recognition of this meter. I believe the problem lies with the incorrect identifier _TZE284_81yrt3lo. I have an identical meter recognized as _TZE204_81yrt3lo, and it is successfully integrated into Zigbee2MQTT, working without any issues. Could the solution be to adjust the external converter for the _TZE204_81yrt3lo meter to support this new identifier?

@mitxol
Copy link

mitxol commented Jan 13, 2025

Hi,
I have the same problem but it is when integrating into ZHA. ZHA discovers the device, configures it but it has no entities or sensors. It detects that it is _TZE284_81yrt3lo and does not apply the quirk. I have other devices with quirks applied but this one is not applied.
I have adapted a quirk for the _TZE204_81yrt3lo by changing the model to the _TZE284_81yrt3lo but it has not worked.
`"""Tuya Din Power Meter."""
from typing import Dict

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

from zhaquirks import LocalDataCluster
from zhaquirks.const import (
DEVICE_TYPE,
ENDPOINTS,
INPUT_CLUSTERS,
MODELS_INFO,
OUTPUT_CLUSTERS,
PROFILE_ID,
)
from zhaquirks.tuya import TuyaLocalCluster
from zhaquirks.tuya.mcu import (
DPToAttributeMapping,
EnchantedDevice,
TuyaMCUCluster,
TuyaOnOff,
)

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

AC_CURRENT_MULTIPLIER = 0x0602
AC_CURRENT_DIVISOR = 0x0603

_CONSTANT_ATTRIBUTES = {AC_CURRENT_MULTIPLIER: 1, AC_CURRENT_DIVISOR: 1000}

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

POWER_WATT = 0x0000

_CONSTANT_ATTRIBUTES = {
    0x0300: POWER_WATT,  # unit_of_measure
    0x0302: 1000,  # divisor
}

class DinPowerManufCluster(TuyaMCUCluster):
"""Tuya Manufacturer Cluster with din power datapoints."""

class TuyaConnectionStatus(t.Struct):
    """Tuya request data."""

    tsn: t.uint8_t
    status: t.LVBytes

client_commands = TuyaMCUCluster.client_commands.copy()
client_commands.update(
    {
        0x25: foundation.ZCLCommandDef(
            "mcu_connection_status",
            {"payload": TuyaConnectionStatus},
            True,
            is_manufacturer_specific=True,
        ),
    }
)

server_commands = TuyaMCUCluster.server_commands.copy()
server_commands.update(
    {
        0x25: foundation.ZCLCommandDef(
            "mcu_connection_status_rsp",
            {"payload": TuyaConnectionStatus},
            False,
            is_manufacturer_specific=True,
        ),
    }
)

def handle_mcu_connection_status(
    self, payload: TuyaConnectionStatus
) -> foundation.Status:
    """Handle gateway connection status requests (0x25)."""

    payload_rsp = DinPowerManufCluster.TuyaConnectionStatus()
    payload_rsp.tsn = payload.tsn
    payload_rsp.status = b"\x01"  # 0x00 not connected to internet | 0x01 connected to internet | 0x02 time out

    self.create_catching_task(
        super().command(0x25, payload_rsp, expect_reply=False)
    )

    return foundation.Status.SUCCESS

dp_to_attribute: Dict[int, DPToAttributeMapping] = {
    0x01: DPToAttributeMapping(
        TuyaElectricalMeasurement.ep_attribute,
        "current_summ_delivered",
    ),
    0x06: DPToAttributeMapping(
        TuyaPowerMeasurement.ep_attribute,
        ("rms_current", "rms_voltage"),
        converter=lambda x: (x >> 16, (x & 0x0000FFFF) / 10),
    ),
    0x10: DPToAttributeMapping(
        TuyaOnOff.ep_attribute,
        "on_off",
    ),
    0x66: DPToAttributeMapping(
        TuyaElectricalMeasurement.ep_attribute,
        "current_summ_received",
    ),
    0x67: DPToAttributeMapping(
        TuyaPowerMeasurement.ep_attribute,
        "active_power",
    ),
    0x69: DPToAttributeMapping(
        TuyaPowerMeasurement.ep_attribute,
        "ac_frequency",
    ),
    0x6D: DPToAttributeMapping(
        TuyaPowerMeasurement.ep_attribute,
        "total_reactive_power",
    ),
    0x6E: DPToAttributeMapping(
        TuyaPowerMeasurement.ep_attribute,
        "reactive_power",
    ),
    0x6F: DPToAttributeMapping(
        TuyaPowerMeasurement.ep_attribute,
        "power_factor",
    ),
}

data_point_handlers = {
    0x01: "_dp_2_attr_update",
    0x06: "_dp_2_attr_update",
    0x10: "_dp_2_attr_update",
    0x66: "_dp_2_attr_update",
    0x67: "_dp_2_attr_update",
    0x69: "_dp_2_attr_update",
    0x6D: "_dp_2_attr_update",
    0x6E: "_dp_2_attr_update",
    0x6F: "_dp_2_attr_update",
}

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

dp_to_attribute: Dict[int, DPToAttributeMapping] = {
    17: DPToAttributeMapping(
        TuyaElectricalMeasurement.ep_attribute,
        "current_summ_delivered",
    ),
    18: DPToAttributeMapping(
        TuyaPowerMeasurement.ep_attribute,
        "rms_current",
    ),
    19: DPToAttributeMapping(
        TuyaPowerMeasurement.ep_attribute,
        "active_power",
        converter=lambda x: x // 10,
    ),
    20: DPToAttributeMapping(
        TuyaPowerMeasurement.ep_attribute,
        "rms_voltage",
        converter=lambda x: x // 10,
    ),
}

data_point_handlers = {
    17: "_dp_2_attr_update",
    18: "_dp_2_attr_update",
    19: "_dp_2_attr_update",
    20: "_dp_2_attr_update",
}

class TuyaPowerMeter(EnchantedDevice):
"""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: [
        ("_TZE284_cjbofhxw", "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,
                TuyaManufClusterDinPower.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 HikingPowerMeter(CustomDevice):
"""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"),
        ("ffffffffffffffff", "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,
                DinPowerManufCluster.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,
                DinPowerManufCluster,
                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: [],
        },
    }
}`

@sasojerman
Copy link

Hi,
I switched from ZHA to Z2M some time ago. Somehow, I find it more user-friendly. Regarding the converter for this meter in Z2M, I managed to put something together, and it now recognizes the device, and the measurements seem correct. If there are any possible improvements, I’d greatly appreciate them. As for the quirk in ZHA, I’m not sure. This is external converter that works for me.

const exposes = require('zigbee-herdsman-converters/lib/exposes');
const tuya = require('zigbee-herdsman-converters/lib/tuya');
const e = exposes.presets;
const ea = exposes.access;

const definition = {
    fingerprint: [
        {modelID: 'TS0601', manufacturerName: '_TZE284_81yrt3lo'},
    ],
    model: 'TS0601_Energy_Meter',
    vendor: 'Tuya',
    description: 'Energy meter with 80A clamp',
    fromZigbee: [tuya.fz.datapoints],
    toZigbee: [],
    exposes: [ //only report data
        e.ac_frequency(), // Frequency in Hz
        exposes.numeric('total_power_A', ea.STATE).withUnit('W').withDescription('Total power A'),
        exposes.numeric('total_power_B', ea.STATE).withUnit('W').withDescription('Total power B'),
        exposes.numeric('total_power_AB', ea.STATE).withUnit('W').withDescription('Total power A'),
        exposes.numeric('voltage', ea.STATE).withUnit('V').withDescription('Voltage'),
        exposes.numeric('current_A', ea.STATE).withUnit('A').withDescription('Current A'),
        exposes.numeric('current_B', ea.STATE).withUnit('A').withDescription('Current B'),
        exposes.numeric('power_factor_A', ea.STATE).withUnit('%').withDescription('Instantaneous measured pow>
        exposes.numeric('power_factor_B', ea.STATE).withUnit('%').withDescription('Instantaneous measured pow>
        exposes.numeric('power_direction A', ea.STATE).withDescription('Power direction A 0/1 for forward/rev>
        exposes.numeric('power_direction B', ea.STATE).withDescription('Power direction B 0/1 for forward/rev>
        exposes.numeric('energy_forward_A', ea.STATE).withUnit('kWh').withDescription('Total energy A forward>
        exposes.numeric('energy_forward_B', ea.STATE).withUnit('kWh').withDescription('Total energy B forward>
        exposes.numeric('energy_reverse_A', ea.STATE).withUnit('kWh').withDescription('Total energy A reverse>
        exposes.numeric('energy_reverse_B', ea.STATE).withUnit('kWh').withDescription('Total energy B reverse>
        exposes.numeric('update_frequency', ea.STATE).withUnit('sec').withDescription('Update frequency'),
    ],
    meta: {
        tuyaDatapoints: [//only report data
            [111, 'ac_frequency', tuya.valueConverter.divideBy100],
            [101, 'total_power_A', tuya.valueConverter.divideBy10],
            [105, 'total_power_B', tuya.valueConverter.divideBy10],
            [115, 'total_power_AB', tuya.valueConverter.divideBy10],
            [112, 'voltage', tuya.valueConverter.divideBy10],
            [113, 'current_A', tuya.valueConverter.divideBy1000],
            [114, 'current_B', tuya.valueConverter.divideBy1000],
            [110, 'power_factor_A', tuya.valueConverter.divideBy100],
            [121, 'power_factor_B', tuya.valueConverter.divideBy100],
            [102, 'power_direction A', tuya.valueConverter.raw],
            [104, 'power_direction B', tuya.valueConverter.raw],
            [106, 'energy_forward_A', tuya.valueConverter.divideBy100],
            [108, 'energy_forward_B', tuya.valueConverter.divideBy100],
            [107, 'energy_reverse_A', tuya.valueConverter.divideBy100],
            [109, 'energy_reverse_B', tuya.valueConverter.divideBy100],
            [129, 'update_frequency' , tuya.valueConverter.raw],
        ],
    },
};

module.exports = definition;


@Eguar-rc
Copy link

Hi,
I have the same problem and I would like to try your converter but with the new version 2.0 I don't know where to put the js file.
I use the z2m addon from Home Assistant, can you help me?

Thanks

@sasojerman
Copy link

Hi,
I was also on version 2.0, but during one of my attempts, I reverted to version 1.42. Now, I’m not sure what will happen when I update.
I think there shouldn’t be any issues. Try this procedure:

  1. Create a Directory for External Converters
  • Access your terminal (via SSH) or use the File Editor in Home Assistant.
  • Create the directory if it doesn’t already exist:
mkdir -p /config/zigbee2mqtt/data/external_converters/

  1. Create a New External Converter File
  • In the /config/zigbee2mqtt/data/external_converters/ directory, create a new file:
nano /config/zigbee2mqtt/data/external_converters/Tuya_TZE284_81yrt3lo.js

  • Paste the code for your device.
const exposes = require('zigbee-herdsman-converters/lib/exposes');
const tuya = require('zigbee-herdsman-converters/lib/tuya');
const e = exposes.presets;
const ea = exposes.access;

const definition = {
   fingerprint: [
       {modelID: 'TS0601', manufacturerName: '_TZE284_81yrt3lo'},
   ],
   model: 'PJ-1203A',
   vendor: 'Tuya',
   description: 'Energy meter with 80A clamp',
   fromZigbee: [tuya.fz.datapoints],
   toZigbee: [tuya.tz.datapoints],
   onEvent: tuya.onEventSetTime,
   configure: tuya.configureMagicPacket,
   exposes: [ //only report data
       e.ac_frequency(), // Frequency in Hz
       exposes.numeric('total_power_A', ea.STATE).withUnit('W').withDescription('Total power A'),
       exposes.numeric('total_power_B', ea.STATE).withUnit('W').withDescription('Total power B'),
       exposes.numeric('total_power_AB', ea.STATE).withUnit('W').withDescription('Total power A'),
       exposes.numeric('voltage', ea.STATE).withUnit('V').withDescription('Voltage'),
       exposes.numeric('current_A', ea.STATE).withUnit('A').withDescription('Current A'),
       exposes.numeric('current_B', ea.STATE).withUnit('A').withDescription('Current B'),
       exposes.numeric('power_factor_A', ea.STATE).withUnit('%').withDescription('Instantaneous measured power factor A'),
       exposes.numeric('power_factor_B', ea.STATE).withUnit('%').withDescription('Instantaneous measured power factor B'),
       exposes.numeric('power_direction A', ea.STATE).withDescription('Power direction A 0/1 for forward/reverse'),
       exposes.numeric('power_direction B', ea.STATE).withDescription('Power direction B 0/1 for forward/reverse'),
       exposes.numeric('energy_forward_A', ea.STATE).withUnit('kWh').withDescription('Total energy A forward'),
       exposes.numeric('energy_forward_B', ea.STATE).withUnit('kWh').withDescription('Total energy B forward'),
       exposes.numeric('energy_reverse_A', ea.STATE).withUnit('kWh').withDescription('Total energy A reverse'),
       exposes.numeric('energy_reverse_B', ea.STATE).withUnit('kWh').withDescription('Total energy B reverse'),
       exposes.numeric('update_frequency', ea.STATE).withUnit('sec').withDescription('Update frequency'),
   ],
   meta: {
       tuyaDatapoints: [//only report data
           [111, 'ac_frequency', tuya.valueConverter.divideBy100],
           [101, 'total_power_A', tuya.valueConverter.divideBy10],
           [105, 'total_power_B', tuya.valueConverter.divideBy10],
           [115, 'total_power_AB', tuya.valueConverter.divideBy10],
           [112, 'voltage', tuya.valueConverter.divideBy10],
           [113, 'current_A', tuya.valueConverter.divideBy1000],
           [114, 'current_B', tuya.valueConverter.divideBy1000],
           [110, 'power_factor_A', tuya.valueConverter.divideBy100],
           [121, 'power_factor_B', tuya.valueConverter.divideBy100],
           [102, 'power_direction A', tuya.valueConverter.raw],
           [104, 'power_direction B', tuya.valueConverter.raw],
           [106, 'energy_forward_A', tuya.valueConverter.divideBy100],
           [108, 'energy_forward_B', tuya.valueConverter.divideBy100],
           [107, 'energy_reverse_A', tuya.valueConverter.divideBy100],
           [109, 'energy_reverse_B', tuya.valueConverter.divideBy100],
           [129, 'update_frequency' , tuya.valueConverter.raw],
       ],
   },
};

module.exports = definition;


  • Save the file: Press CTRL+O, confirm with Enter, then CTRL+X
  1. Add the Converter Path to configuration.yaml
  • Open the configuration.yaml file:
nano /config/zigbee2mqtt/configuration.yaml

  • Add or update the external_converters section to include your new file:
external_converters:
 - data/external_converters/Tuya_TZE284_81yrt3lo.js

  • Save the changes.
  1. Restart Zigbee2MQTT

@Eguar-rc
Copy link

It finally worked! Thank you very much.
In my case the directory is \config\zigbee2mqtt\external_converters, without \data.

@tuga89
Copy link

tuga89 commented Jan 14, 2025

Hello, I have also installed this module, but I am using ZHA. Could someone share the quirk to make it report correctly with the data? Thank you.

@Celsius456
Copy link

Hello, I just wanted to thank you. Also, I think in next Z2M version realeasing 1 feb, they gonna add official support

@simonedimarzio
Copy link

simonedimarzio commented Jan 16, 2025

Hello, do you have any suggestions for solving the issue with the device "_TZE284_81yrt3lo" using ZHA in Home Assistant?

Currently, it is not supported by the quirk available here: https://github.com/jeverley/zha-device-handlers/blob/ts0601_energy_meter_devices/zhaquirks/tuya/ts0601_energy_meter.py

If it helps, I have the device and am available to capture data and debug logs.

Thank you very much!

@Edsol
Copy link

Edsol commented Jan 18, 2025

Hi, I was also on version 2.0, but during one of my attempts, I reverted to version 1.42. Now, I’m not sure what will happen when I update. I think there shouldn’t be any issues. Try this procedure:

  1. Create a Directory for External Converters
  • Access your terminal (via SSH) or use the File Editor in Home Assistant.
  • Create the directory if it doesn’t already exist:
mkdir -p /config/zigbee2mqtt/data/external_converters/
  1. Create a New External Converter File
  • In the /config/zigbee2mqtt/data/external_converters/ directory, create a new file:
nano /config/zigbee2mqtt/data/external_converters/Tuya_TZE284_81yrt3lo.js
  • Paste the code for your device.
const exposes = require('zigbee-herdsman-converters/lib/exposes');
const tuya = require('zigbee-herdsman-converters/lib/tuya');
const e = exposes.presets;
const ea = exposes.access;

const definition = {
   fingerprint: [
       {modelID: 'TS0601', manufacturerName: '_TZE284_81yrt3lo'},
   ],
   model: 'PJ-1203A',
   vendor: 'Tuya',
   description: 'Energy meter with 80A clamp',
   fromZigbee: [tuya.fz.datapoints],
   toZigbee: [tuya.tz.datapoints],
   onEvent: tuya.onEventSetTime,
   configure: tuya.configureMagicPacket,
   exposes: [ //only report data
       e.ac_frequency(), // Frequency in Hz
       exposes.numeric('total_power_A', ea.STATE).withUnit('W').withDescription('Total power A'),
       exposes.numeric('total_power_B', ea.STATE).withUnit('W').withDescription('Total power B'),
       exposes.numeric('total_power_AB', ea.STATE).withUnit('W').withDescription('Total power A'),
       exposes.numeric('voltage', ea.STATE).withUnit('V').withDescription('Voltage'),
       exposes.numeric('current_A', ea.STATE).withUnit('A').withDescription('Current A'),
       exposes.numeric('current_B', ea.STATE).withUnit('A').withDescription('Current B'),
       exposes.numeric('power_factor_A', ea.STATE).withUnit('%').withDescription('Instantaneous measured power factor A'),
       exposes.numeric('power_factor_B', ea.STATE).withUnit('%').withDescription('Instantaneous measured power factor B'),
       exposes.numeric('power_direction A', ea.STATE).withDescription('Power direction A 0/1 for forward/reverse'),
       exposes.numeric('power_direction B', ea.STATE).withDescription('Power direction B 0/1 for forward/reverse'),
       exposes.numeric('energy_forward_A', ea.STATE).withUnit('kWh').withDescription('Total energy A forward'),
       exposes.numeric('energy_forward_B', ea.STATE).withUnit('kWh').withDescription('Total energy B forward'),
       exposes.numeric('energy_reverse_A', ea.STATE).withUnit('kWh').withDescription('Total energy A reverse'),
       exposes.numeric('energy_reverse_B', ea.STATE).withUnit('kWh').withDescription('Total energy B reverse'),
       exposes.numeric('update_frequency', ea.STATE).withUnit('sec').withDescription('Update frequency'),
   ],
   meta: {
       tuyaDatapoints: [//only report data
           [111, 'ac_frequency', tuya.valueConverter.divideBy100],
           [101, 'total_power_A', tuya.valueConverter.divideBy10],
           [105, 'total_power_B', tuya.valueConverter.divideBy10],
           [115, 'total_power_AB', tuya.valueConverter.divideBy10],
           [112, 'voltage', tuya.valueConverter.divideBy10],
           [113, 'current_A', tuya.valueConverter.divideBy1000],
           [114, 'current_B', tuya.valueConverter.divideBy1000],
           [110, 'power_factor_A', tuya.valueConverter.divideBy100],
           [121, 'power_factor_B', tuya.valueConverter.divideBy100],
           [102, 'power_direction A', tuya.valueConverter.raw],
           [104, 'power_direction B', tuya.valueConverter.raw],
           [106, 'energy_forward_A', tuya.valueConverter.divideBy100],
           [108, 'energy_forward_B', tuya.valueConverter.divideBy100],
           [107, 'energy_reverse_A', tuya.valueConverter.divideBy100],
           [109, 'energy_reverse_B', tuya.valueConverter.divideBy100],
           [129, 'update_frequency' , tuya.valueConverter.raw],
       ],
   },
};

module.exports = definition;
  • Save the file: Press CTRL+O, confirm with Enter, then CTRL+X
  1. Add the Converter Path to configuration.yaml
  • Open the configuration.yaml file:
nano /config/zigbee2mqtt/configuration.yaml
  • Add or update the external_converters section to include your new file:
external_converters:
 - data/external_converters/Tuya_TZE284_81yrt3lo.js
  • Save the changes.
  1. Restart Zigbee2MQTT

it works great! thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants