zha-device-handlers icon indicating copy to clipboard operation
zha-device-handlers copied to clipboard

[Device Support Request] Tuya Thermometer TS0201 different manufacturer (round with display)

Open bleistift2 opened this issue 2 months ago • 0 comments

Problem description

Hi,

I purchased a round Tuya Zigbee thermometer with display. https://de.aliexpress.com/item/1005005872944768.html I use a Skyconnect with ZHA, the thermometer connects without problems and reports the initial temperature and air pressure. Unfortunately it never updates those values and after a few hours only reports 0 degrees and air pressure. I noticed that there exists a quirk for the TS0201, unfortunately not for my specific model. In the quirk I found the class class MoesTemperatureHumidtySensorWithScreen(CustomDevice): """Moes temperature and humidity sensor with screen."" and figured that that might best fit my device.

I tried editing the quirk with my zigbee signature, but the quirk won't be applied, no matter how often I re-pair or restart.

Solution description

Could somebody please adjust the quirk to my model?

Screenshots/Video

Screenshots/Video

[Paste/upload your media here]

Device signature

Device signature
{
  "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.EndDevice: 2>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress: 128>, 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=True, *is_full_function_device=False, *is_mains_powered=False, *is_receiver_on_when_idle=False, *is_router=False, *is_security_capable=False)",
  "endpoints": {
    "1": {
      "profile_id": "0x0104",
      "device_type": "0x0402",
      "input_clusters": [
        "0x0000",
        "0x0001",
        "0x0004",
        "0x0402",
        "0x0405",
        "0xe002"
      ],
      "output_clusters": [
        "0x0004",
        "0x000a",
        "0x0019"
      ]
    }
  },
  "manufacturer": "_TZ3210_qkj7rujp",
  "model": "TS0201",
  "class": "zigpy.device.Device"
}

Diagnostic information

Diagnostic information
{
  "home_assistant": {
    "installation_type": "Home Assistant OS",
    "version": "2024.6.3",
    "dev": false,
    "hassio": true,
    "virtualenv": false,
    "python_version": "3.12.2",
    "docker": true,
    "arch": "aarch64",
    "timezone": "Europe/Berlin",
    "os_name": "Linux",
    "os_version": "6.6.29-haos",
    "supervisor": "2024.06.0",
    "host_os": "Home Assistant OS 12.3",
    "docker_version": "25.0.5",
    "chassis": "embedded",
    "run_as_root": true
  },
  "custom_components": {
    "homematicip_local": {
      "documentation": "https://github.com/danielperna84/custom_homematic",
      "version": "1.62.1",
      "requirements": [
        "hahomematic==2024.6.0"
      ]
    },
    "home_connect_alt": {
      "documentation": "https://github.com/ekutner/home-connect-hass",
      "version": "1.1.6",
      "requirements": [
        "home-connect-async==0.8.0"
      ]
    },
    "hacs": {
      "documentation": "https://hacs.xyz/docs/configuration/start",
      "version": "1.34.0",
      "requirements": [
        "aiogithubapi>=22.10.1"
      ]
    },
    "dwd": {
      "documentation": "https://github.com/hg1337/homeassistant-dwd#readme",
      "version": "2024.4.0",
      "requirements": [
        "defusedxml==0.7.1"
      ]
    },
    "zeo_one": {
      "documentation": "https://github.com/yangqian/hass-zeo_one",
      "version": "1.1.0",
      "requirements": [
        "python-roborock"
      ]
    },
    "xiaomi_miot": {
      "documentation": "https://github.com/al-one/hass-xiaomi-miot",
      "version": "0.7.18",
      "requirements": [
        "construct>=2.10.68",
        "python-miio>=0.5.12",
        "micloud>=0.5"
      ]
    },
    "better_thermostat": {
      "documentation": "https://github.com/KartoffelToby/better_thermostat",
      "version": "1.5.1",
      "requirements": []
    }
  },
  "integration_manifest": {
    "domain": "zha",
    "name": "Zigbee Home Automation",
    "after_dependencies": [
      "onboarding",
      "usb"
    ],
    "codeowners": [
      "dmulcahey",
      "adminiuga",
      "puddly",
      "TheJulianJES"
    ],
    "config_flow": true,
    "dependencies": [
      "file_upload"
    ],
    "documentation": "https://www.home-assistant.io/integrations/zha",
    "iot_class": "local_polling",
    "loggers": [
      "aiosqlite",
      "bellows",
      "crccheck",
      "pure_pcapy3",
      "zhaquirks",
      "zigpy",
      "zigpy_deconz",
      "zigpy_xbee",
      "zigpy_zigate",
      "zigpy_znp",
      "universal_silabs_flasher"
    ],
    "requirements": [
      "bellows==0.39.1",
      "pyserial==3.5",
      "zha-quirks==0.0.116",
      "zigpy-deconz==0.23.1",
      "zigpy==0.64.1",
      "zigpy-xbee==0.20.1",
      "zigpy-zigate==0.12.0",
      "zigpy-znp==0.12.1",
      "universal-silabs-flasher==0.0.20",
      "pyserial-asyncio-fast==0.11"
    ],
    "usb": [
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*2652*",
        "known_devices": [
          "slae.sh cc2652rb stick"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*slzb-07*",
        "known_devices": [
          "smlight slzb-07"
        ]
      },
      {
        "vid": "1A86",
        "pid": "55D4",
        "description": "*sonoff*plus*",
        "known_devices": [
          "sonoff zigbee dongle plus v2"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*sonoff*plus*",
        "known_devices": [
          "sonoff zigbee dongle plus"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*tubeszb*",
        "known_devices": [
          "TubesZB Coordinator"
        ]
      },
      {
        "vid": "1A86",
        "pid": "7523",
        "description": "*tubeszb*",
        "known_devices": [
          "TubesZB Coordinator"
        ]
      },
      {
        "vid": "1A86",
        "pid": "7523",
        "description": "*zigstar*",
        "known_devices": [
          "ZigStar Coordinators"
        ]
      },
      {
        "vid": "1CF1",
        "pid": "0030",
        "description": "*conbee*",
        "known_devices": [
          "Conbee II"
        ]
      },
      {
        "vid": "0403",
        "pid": "6015",
        "description": "*conbee*",
        "known_devices": [
          "Conbee III"
        ]
      },
      {
        "vid": "10C4",
        "pid": "8A2A",
        "description": "*zigbee*",
        "known_devices": [
          "Nortek HUSBZB-1"
        ]
      },
      {
        "vid": "0403",
        "pid": "6015",
        "description": "*zigate*",
        "known_devices": [
          "ZiGate+"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*zigate*",
        "known_devices": [
          "ZiGate"
        ]
      },
      {
        "vid": "10C4",
        "pid": "8B34",
        "description": "*bv 2010/10*",
        "known_devices": [
          "Bitron Video AV2010/10"
        ]
      }
    ],
    "zeroconf": [
      {
        "type": "_esphomelib._tcp.local.",
        "name": "tube*"
      },
      {
        "type": "_zigate-zigbee-gateway._tcp.local.",
        "name": "*zigate*"
      },
      {
        "type": "_zigstar_gw._tcp.local.",
        "name": "*zigstar*"
      },
      {
        "type": "_uzg-01._tcp.local.",
        "name": "uzg-01*"
      },
      {
        "type": "_slzb-06._tcp.local.",
        "name": "slzb-06*"
      }
    ],
    "is_built_in": true
  },
  "setup_times": {
    "null": {
      "setup": 0.0002770849969238043
    },
    "8e42468e822f68622f774ebecdf9ea1b": {
      "wait_import_platforms": -0.0009566720109432936,
      "config_entry_setup": 25.965530738933012
    }
  },
  "data": {
    "ieee": "**REDACTED**",
    "nwk": 14899,
    "manufacturer": "_TZ3210_qkj7rujp",
    "model": "TS0201",
    "name": "_TZ3210_qkj7rujp TS0201",
    "quirk_applied": false,
    "quirk_class": "zigpy.device.Device",
    "quirk_id": null,
    "manufacturer_code": 4417,
    "power_source": "Battery or Unknown",
    "lqi": 192,
    "rssi": -52,
    "last_seen": "2024-06-17T15:59:26",
    "available": true,
    "device_type": "EndDevice",
    "signature": {
      "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.EndDevice: 2>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress: 128>, 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=True, *is_full_function_device=False, *is_mains_powered=False, *is_receiver_on_when_idle=False, *is_router=False, *is_security_capable=False)",
      "endpoints": {
        "1": {
          "profile_id": "0x0104",
          "device_type": "0x0402",
          "input_clusters": [
            "0x0000",
            "0x0001",
            "0x0004",
            "0x0402",
            "0x0405",
            "0xe002"
          ],
          "output_clusters": [
            "0x0004",
            "0x000a",
            "0x0019"
          ]
        }
      },
      "manufacturer": "_TZ3210_qkj7rujp",
      "model": "TS0201"
    },
    "active_coordinator": false,
    "entities": [
      {
        "entity_id": "sensor.thermometer_pantry_batterie",
        "name": "_TZ3210_qkj7rujp TS0201"
      },
      {
        "entity_id": "sensor.thermometer_pantry_temperatur",
        "name": "_TZ3210_qkj7rujp TS0201"
      },
      {
        "entity_id": "sensor.thermometer_pantry_luftfeuchtigkeit",
        "name": "_TZ3210_qkj7rujp TS0201"
      },
      {
        "entity_id": "update.thermometer_pantry_firmware",
        "name": "_TZ3210_qkj7rujp TS0201"
      }
    ],
    "neighbors": [],
    "routes": [],
    "endpoint_names": [
      {
        "name": "IAS_ZONE"
      }
    ],
    "user_given_name": "Thermometer Pantry",
    "device_reg_id": "1d66d7db0c63e22b253aac6b48c5ade2",
    "area_id": "pantry",
    "cluster_details": {
      "1": {
        "device_type": {
          "name": "IAS_ZONE",
          "id": 1026
        },
        "profile_id": 260,
        "in_clusters": {
          "0x0000": {
            "endpoint_attribute": "basic",
            "attributes": {
              "0x0004": {
                "attribute_name": "manufacturer",
                "value": "_TZ3210_qkj7rujp"
              },
              "0x0005": {
                "attribute_name": "model",
                "value": "TS0201"
              }
            },
            "unsupported_attributes": {}
          },
          "0x0004": {
            "endpoint_attribute": "groups",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0001": {
            "endpoint_attribute": "power",
            "attributes": {
              "0x0021": {
                "attribute_name": "battery_percentage_remaining",
                "value": 200
              },
              "0x0020": {
                "attribute_name": "battery_voltage",
                "value": 0
              }
            },
            "unsupported_attributes": {
              "0x0031": {
                "attribute_name": "battery_size"
              },
              "0x0033": {
                "attribute_name": "battery_quantity"
              }
            }
          },
          "0x0402": {
            "endpoint_attribute": "temperature",
            "attributes": {
              "0x0000": {
                "attribute_name": "measured_value",
                "value": 0
              }
            },
            "unsupported_attributes": {}
          },
          "0x0405": {
            "endpoint_attribute": "humidity",
            "attributes": {
              "0x0000": {
                "attribute_name": "measured_value",
                "value": 0
              }
            },
            "unsupported_attributes": {}
          },
          "0xe002": {
            "endpoint_attribute": null,
            "attributes": {},
            "unsupported_attributes": {}
          }
        },
        "out_clusters": {
          "0x0004": {
            "endpoint_attribute": "groups",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x000a": {
            "endpoint_attribute": "time",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0019": {
            "endpoint_attribute": "ota",
            "attributes": {
              "0x0002": {
                "attribute_name": "current_file_version",
                "value": 67
              }
            },
            "unsupported_attributes": {}
          }
        }
      }
    }
  }
}

Logs

Logs
[Paste the logs here]

Custom quirk

Custom quirk
"""Tuya TS201 temperature, humidity and optional illumination sensors."""

from zigpy.profiles import zha
from zigpy.profiles.zha import DeviceType
from zigpy.quirks import CustomCluster, CustomDevice
import zigpy.types as t
from zigpy.zcl.clusters.general import Basic, Identify, Ota, PowerConfiguration, Time
from zigpy.zcl.clusters.measurement import (
    IlluminanceMeasurement,
    RelativeHumidity,
    TemperatureMeasurement,
)
from zigpy.zdo.types import NodeDescriptor

from zhaquirks.const import (
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    MODELS_INFO,
    NODE_DESCRIPTOR,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
)


class ValueAlarm(t.enum8):
    """Temperature and humidity alarm values."""

    ALARM_OFF = 0x02
    MAX_ALARM_ON = 0x01
    MIN_ALARM_ON = 0x00


class TuyaTemperatureHumidityAlarmCluster(CustomCluster):
    """Tuya temperature and humidity alarm cluster (0xE002)."""

    name = "Tuya Temperature and Humidity Alarm Cluster"
    cluster_id = 0xE002

    attributes = {
        # Alarm settings
        0xD00A: ("alarm_temperature_max", t.uint16_t, True),
        0xD00B: ("alarm_temperature_min", t.uint16_t, True),
        0xD00C: ("alarm_humidity_max", t.uint16_t, True),
        0xD00E: ("alarm_humidity_min", t.uint16_t, True),
        # Alarm information
        0xD00F: ("alarm_humidity", ValueAlarm, True),
        0xD006: ("temperature_humidity", ValueAlarm, True),
        # Unknown
        0xD010: ("unknown", t.uint8_t, True),
    }


class RelativeHumidityX10(CustomCluster, RelativeHumidity):
    """Handles invalid humidity values."""

    def _update_attribute(self, attrid, value):
        # x10 factor in measured_value`(attrid=0)
        if attrid == 0:
            value = value * 10
        super()._update_attribute(attrid, value)


class MoesTemperatureHumidtySensorWithScreen(CustomDevice):
    """Moes temperature and humidity sensor with screen."""

    signature = {
        #  <SimpleDescriptor endpoint=1, profile=260, device_type="0x0402"
        #  input_clusters=["0x0000", "0x0001", "0x0004", "0x0402", "0x0405", "0xe002"]
        #  output_clusters=["0x0004", "0x000a", "0x0019"]>
        MODELS_INFO: [("_TZ3210_qkj7rujp", "TS0201")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: DeviceType.TEMPERATURE_SENSOR,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    PowerConfiguration.cluster_id,
                    Identify.cluster_id,
                    TemperatureMeasurement.cluster_id,
                    RelativeHumidity.cluster_id,
                    TuyaTemperatureHumidityAlarmCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [
                    Identify.cluster_id,
                    Time.cluster_id,
                    Ota.cluster_id,
                ],
            },
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    PowerConfiguration.cluster_id,
                    Identify.cluster_id,
                    TemperatureMeasurement.cluster_id,
                    RelativeHumidityX10,
                    TuyaTemperatureHumidityAlarmCluster,
                ],
                OUTPUT_CLUSTERS: [
                    Identify.cluster_id,
                    Time.cluster_id,
                    Ota.cluster_id,
                ],
            },
        },
    }

Additional information

No response

bleistift2 avatar Jun 17 '24 14:06 bleistift2