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

[Device Support Request] vendor: 'TuYa' modelID: 'TS0601', manufacturerName: '_TZE200_whkgqxse' model: 'JM-TRH-ZGB-V1'

Open abstiger opened this issue 3 years ago • 17 comments

Is your feature request related to a problem? Please describe.

I was able to connect it to the HA zigbee, but neither of the sensors are working in HA.

Device Info: https://www.aliexpress.com/item/3256803794332794.html

Describe the solution you'd like

can support this device with ZHA

Device signature
Paste the device signature here.
Don't remove the extra line breaks outside the ``` marks.
Diagnostic information
{
  "home_assistant": {
    "installation_type": "Home Assistant Container",
    "version": "2022.9.2",
    "dev": false,
    "hassio": false,
    "virtualenv": false,
    "python_version": "3.10.5",
    "docker": true,
    "arch": "x86_64",
    "timezone": "Asia/Shanghai",
    "os_name": "Linux",
    "os_version": "5.4.0-125-generic",
    "run_as_root": true
  },
  "custom_components": {},
  "integration_manifest": {
    "domain": "zha",
    "name": "Zigbee Home Automation",
    "config_flow": true,
    "documentation": "https://www.home-assistant.io/integrations/zha",
    "requirements": [
      "bellows==0.33.1",
      "pyserial==3.5",
      "pyserial-asyncio==0.6",
      "zha-quirks==0.0.79",
      "zigpy-deconz==0.18.1",
      "zigpy==0.50.3",
      "zigpy-xbee==0.15.0",
      "zigpy-zigate==0.9.2",
      "zigpy-znp==0.8.2"
    ],
    "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"
        ]
      }
    ],
    "codeowners": [
      "@dmulcahey",
      "@adminiuga",
      "@puddly"
    ],
    "zeroconf": [
      {
        "type": "_esphomelib._tcp.local.",
        "name": "tube*"
      },
      {
        "type": "_zigate-zigbee-gateway._tcp.local.",
        "name": "*zigate*"
      }
    ],
    "dependencies": [
      "file_upload"
    ],
    "after_dependencies": [
      "onboarding",
      "usb",
      "zeroconf"
    ],
    "iot_class": "local_polling",
    "loggers": [
      "aiosqlite",
      "bellows",
      "crccheck",
      "pure_pcapy3",
      "zhaquirks",
      "zigpy",
      "zigpy_deconz",
      "zigpy_xbee",
      "zigpy_zigate",
      "zigpy_znp"
    ],
    "is_built_in": true
  },
  "data": {
    "ieee": "**REDACTED**",
    "nwk": 41779,
    "manufacturer": "_TZE200_whkgqxse",
    "model": "TS0601",
    "name": "_TZE200_whkgqxse TS0601",
    "quirk_applied": true,
    "quirk_class": "tuya.TuyaTempHumiditySensor",
    "manufacturer_code": 4417,
    "power_source": "Battery or Unknown",
    "lqi": null,
    "rssi": null,
    "last_seen": "2022-09-20T10:58:33",
    "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": 260,
          "device_type": "0x0302",
          "in_clusters": [
            "0x0001",
            "0x0402",
            "0x0405",
            "0xef00"
          ],
          "out_clusters": [
            "0x000a",
            "0x0019"
          ]
        }
      }
    },
    "active_coordinator": false,
    "entities": [
      {
        "entity_id": "sensor.tze200_whkgqxse_ts0601_battery",
        "name": "_TZE200_whkgqxse TS0601"
      },
      {
        "entity_id": "sensor.tze200_whkgqxse_ts0601_temperature",
        "name": "_TZE200_whkgqxse TS0601"
      },
      {
        "entity_id": "sensor.tze200_whkgqxse_ts0601_humidity",
        "name": "_TZE200_whkgqxse TS0601"
      }
    ],
    "neighbors": [],
    "endpoint_names": [
      {
        "name": "TEMPERATURE_SENSOR"
      }
    ],
    "user_given_name": null,
    "device_reg_id": "4c675c047ff7ec11fd3038c2cb14a6cb",
    "area_id": "er_tong_fang",
    "cluster_details": {
      "1": {
        "device_type": {
          "name": "TEMPERATURE_SENSOR",
          "id": 770
        },
        "profile_id": 260,
        "in_clusters": {
          "0xef00": {
            "endpoint_attribute": "tuya_manufacturer",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0402": {
            "endpoint_attribute": "temperature",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0405": {
            "endpoint_attribute": "humidity",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0001": {
            "endpoint_attribute": "power",
            "attributes": {},
            "unsupported_attributes": {}
          }
        },
        "out_clusters": {
          "0x0019": {
            "endpoint_attribute": "ota",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x000a": {
            "endpoint_attribute": "time",
            "attributes": {},
            "unsupported_attributes": {}
          }
        }
      }
    }
  }
}
Additional logs
Paste any additional debug logs here.
Don't remove the extra line breaks outside the ``` marks.

Additional context

Zigbee2MQTT has already supported, see this commit: https://github.com/Koenkk/zigbee-herdsman-converters/commit/8b5b6d50bb436c3664c87b12a44c8075dbfb7586

abstiger avatar Sep 20 '22 01:09 abstiger

the diagnostic information shows that this device signature is same with current tuya model("_TZE200_bjawzodf", "TS0601") which supported by quirk file: ts0601_sensor.py

so i just added the new model to the MODELS_INFO array.

i've tested that with

docker container ls 
docker -exec -it af578040bdff /bin/bash
vi /usr/local/lib/python3.10/site-packages/zhaquirks/tuya/ts0601_sensor.py

then restart home-assistant , currently the device can be recognized with quirk: tuya_ts0601_sensor.TuyaTempHumiditySensor

and the Temperature shows correctly, but the Humidiy and Battery keep Unknown.

abstiger avatar Sep 20 '22 07:09 abstiger

Maybe you can try with the EnchantedDevice class:

  1. Import the class
from zhaquirks.tuya.mcu import EnchantedDevice
  1. Add it in the class definition:
class TuyaTempHumiditySensor(EnchantedDevice, CustomDevice):
    """Custom device representing tuya temp and humidity sensor with e-ink screen."""

    .../...

Not the final implementation, just to check if it works.

If not working, the debug logs from the device will give us some info about what can be happening here.

javicalle avatar Sep 20 '22 17:09 javicalle

Thanks, here are some steps i did:

  1. restore the ts0601_sensor.py file in container pip packages
  2. copy the ts0601_sensor.py to custom_zha_quirks path https://github.com/zigpy/zha-device-handlers/discussions/693#discussioncomment-857274
  3. did some modification as you suggested, here is my custom quirk:
"""Tuya temp and humidity sensor with e-ink screen."""

from typing import Dict

from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
from zigpy.zcl.clusters.general import Basic, Groups, Ota, Scenes, Time
from zigpy.zcl.clusters.measurement import RelativeHumidity, TemperatureMeasurement

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

# NOTES:
# The data comes in as a string on cluster, if there is nothing set up you may see these lines in the logs:
# Unknown message (b'19830100a40102000400000118') on cluster 61184: unknown endpoint or cluster id: 'No cluster ID 0xef00 on (a4:c1:38:d0:18:8b:64:aa, 1)'
#                                          28.0 degrees
# Unknown message (b'19840100a5020200040000022c') on cluster 61184: unknown endpoint or cluster id: 'No cluster ID 0xef00 on (a4:c1:38:d0:18:8b:64:aa, 1)'
#                                          55.6% humid
# Unknown message (b'19850100a60402000400000064') on cluster 61184: unknown endpoint or cluster id: 'No cluster ID 0xef00 on (a4:c1:38:d0:18:8b:64:aa, 1)'
#                                          100% battery


class TuyaTemperatureMeasurement(TemperatureMeasurement, TuyaLocalCluster):
    """Tuya local TemperatureMeasurement cluster."""


class TuyaRelativeHumidity(RelativeHumidity, TuyaLocalCluster):
    """Tuya local RelativeHumidity cluster."""


class TemperatureHumidityManufCluster(TuyaMCUCluster):
    """Tuya Manufacturer Cluster with Temperature and Humidity data points."""

    dp_to_attribute: Dict[int, DPToAttributeMapping] = {
        1: DPToAttributeMapping(
            TuyaTemperatureMeasurement.ep_attribute,
            "measured_value",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 10,  # decidegree to centidegree
        ),
        2: DPToAttributeMapping(
            TuyaRelativeHumidity.ep_attribute,
            "measured_value",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 10,  # decipercent to centipercent
        ),
        4: DPToAttributeMapping(
            TuyaPowerConfigurationCluster2AAA.ep_attribute,
            "battery_percentage_remaining",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 2,  # double reported percentage
        ),
    }

    data_point_handlers = {
        1: "_dp_2_attr_update",
        2: "_dp_2_attr_update",
        4: "_dp_2_attr_update",
    }


class TuyaTempHumiditySensor(EnchantedDevice, CustomDevice):
    """Custom device representing tuya temp and humidity sensor with e-ink screen."""

    signature = {
        # <SimpleDescriptor endpoint=1, profile=260, device_type=81
        # device_version=1
        # input_clusters=[4, 5, 61184, 0]
        # output_clusters=[25, 10]>
        MODELS_INFO: [("_TZE200_whkgqxse", "TS0601")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TemperatureHumidityManufCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Ota.cluster_id, Time.cluster_id],
            }
        },
    }

    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.TEMPERATURE_SENSOR,
                INPUT_CLUSTERS: [
                    TemperatureHumidityManufCluster,  # Single bus for temp, humidity, and battery
                    TuyaTemperatureMeasurement,
                    TuyaRelativeHumidity,
                    TuyaPowerConfigurationCluster2AAA,
                ],
                OUTPUT_CLUSTERS: [Ota.cluster_id, Time.cluster_id],
            }
        },
    }
  1. enabled zha debug logs https://www.home-assistant.io/integrations/zha/#debug-logging
    then grep _TZE200_whkgqxse home-assistant.log got below:
2022-09-21 08:18:11.190 DEBUG (MainThread) [homeassistant.core] Bus:Handling <Event state_changed[L]: entity_id=sensor.tze200_whkgqxse_ts0601_battery, old_state=None, new_state=<state sensor.tze200_whkgqxse_ts0601_battery=unknown; state_class=measurement, unit_of_measurement=%, device_class=battery, friendly_name=_TZE200_whkgqxse TS0601 Battery @ 2022-09-21T08:18:11.190003+08:00>>
2022-09-21 08:18:11.190 DEBUG (MainThread) [homeassistant.core] Bus:Handling <Event state_changed[L]: entity_id=sensor.tze200_whkgqxse_ts0601_temperature, old_state=None, new_state=<state sensor.tze200_whkgqxse_ts0601_temperature=23.4; state_class=measurement, unit_of_measurement=°C, device_class=temperature, friendly_name=_TZE200_whkgqxse TS0601 Temperature @ 2022-09-21T08:18:11.190610+08:00>>
2022-09-21 08:18:11.191 DEBUG (MainThread) [homeassistant.core] Bus:Handling <Event state_changed[L]: entity_id=sensor.tze200_whkgqxse_ts0601_humidity, old_state=None, new_state=<state sensor.tze200_whkgqxse_ts0601_humidity=unknown; state_class=measurement, unit_of_measurement=%, device_class=humidity, friendly_name=_TZE200_whkgqxse TS0601 Humidity @ 2022-09-21T08:18:11.191385+08:00>>

abstiger avatar Sep 21 '22 00:09 abstiger

i've found there are some warnings in the log:

grep WARNING home-assistant.log :

2022-09-21 08:56:41.528 WARNING (MainThread) [zigpy.zcl] [0xF537:1:0xef00] Data remains after deserializing ZCL frame: b'\x02\x02\x00\x04\x00\x00\x00?\x04\x02\x00\x04\x00\x00\x00d\n\x02\x00\x04\x00\x00\x01h\x0b\x02\x00\x04\x00\x00\x00\xc8'
2022-09-21 08:56:42.292 WARNING (MainThread) [zigpy.zcl] [0xF537:1:0xef00] Data remains after deserializing ZCL frame: b'\r\x02\x00\x04\x00\x00\x00\x14\x11\x02\x00\x04\x00\x00\x00\x1e\t\x04\x00\x01\x00'
2022-09-21 08:56:42.294 WARNING (MainThread) [zigpy.zcl] [0xF537:1:0xef00] No 'handle_set_data_response' tuya handler found for set_data_response(data=TuyaCommand(status=9, tsn=163, dp=12, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'F\x00\x00\x00', *payload=70)))

grep zigpy.zcl home-assistant.log :

2022-09-21 08:56:43.034 DEBUG (MainThread) [zigpy.zcl] [0xF537:1:0xef00] Received ZCL frame: b'\x09\x5E\x02\x09\xA7\x0C\x02\x00\x04\x00\x00\x00\x46\x0D\x02\x00\x04\x00\x00\x00\x14\x11\x02\x00\x04\x00\x00\x00\x1E\x09\x04\x00\x01\x00'
2022-09-21 08:56:43.034 DEBUG (MainThread) [zigpy.zcl] [0xF537:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 1>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False, *is_reply=True), tsn=94, command_id=2, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2022-09-21 08:56:43.035 DEBUG (MainThread) [zigpy.zcl] [0xF537:1:0xef00] Decoded ZCL frame: TemperatureHumidityManufCluster:set_data_response(data=TuyaCommand(status=9, tsn=167, dp=12, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'F\x00\x00\x00', *payload=70)))
2022-09-21 08:56:43.035 WARNING (MainThread) [zigpy.zcl] [0xF537:1:0xef00] Data remains after deserializing ZCL frame: b'\r\x02\x00\x04\x00\x00\x00\x14\x11\x02\x00\x04\x00\x00\x00\x1e\t\x04\x00\x01\x00'
2022-09-21 08:56:43.036 DEBUG (MainThread) [zigpy.zcl] [0xF537:1:0xef00] Received command 0x02 (TSN 94): set_data_response(data=TuyaCommand(status=9, tsn=167, dp=12, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'F\x00\x00\x00', *payload=70)))
2022-09-21 08:56:43.037 DEBUG (MainThread) [zigpy.zcl] [0xF537:1:0xef00] No datapoint handler for TuyaCommand(status=9, tsn=167, dp=12, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'F\x00\x00\x00', *payload=70))
2022-09-21 08:56:43.037 WARNING (MainThread) [zigpy.zcl] [0xF537:1:0xef00] No 'handle_set_data_response' tuya handler found for set_data_response(data=TuyaCommand(status=9, tsn=167, dp=12, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'F\x00\x00\x00', *payload=70)))
2022-09-21 08:56:43.038 DEBUG (MainThread) [zigpy.zcl] [0xF537:1:0xef00] Sending reply header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=False, direction=<Direction.Client_to_Server: 1>, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True, *is_reply=True), tsn=94, command_id=<GeneralCommand.Default_Response: 11>, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2022-09-21 08:56:43.039 DEBUG (MainThread) [zigpy.zcl] [0xF537:1:0xef00] Sending reply: Default_Response(command_id=2, status=<Status.UNSUP_CLUSTER_COMMAND: 129>)

abstiger avatar Sep 21 '22 01:09 abstiger

A few comments.

Have you tried to remove the device from HA and pires it again? We want to fire the bind process here.

According to Z2M dp=12 is the nousMaxHumi. We can address the issue later.

Maybe it will be the same result but try with grep 0xF537 home-assistant.log to get the device logs. Also attach the pairing process logs.

javicalle avatar Sep 21 '22 06:09 javicalle

removed and paired the device, Nothing has changed, the problem remains

here is pairing process logs from HA web Add Device then SHOW LOGS:

pairing.log

abstiger avatar Sep 21 '22 12:09 abstiger

Related to: #1566

That will need a major change in Tuya handler. I will try to check in the weekend

javicalle avatar Sep 21 '22 15:09 javicalle

A couple of PRs that can be helpfull here had been merged:

  • #1737
  • #1779

With the new HA version it is expected that:

  1. the device successfully sync date/time
  2. multi-attribute reports can be managed

In your logs DP12 and DP15 is already reported, with the next version it can be also this DPs:

    nousTemperature: 1,
    nousHumidity: 2,
    nousBattery: 4,
    nousTempUnitConvert: 9,
    nousMaxTemp: 10,
    nousMinTemp: 11,
    nousMaxHumi: 12,
    nousMinHumi: 13,
    nousTempAlarm: 14,
    nousHumiAlarm: 15,
    nousTempSensitivity: 19,
    nousReportInterval: 17,

Most of these DPs are already in the TuyaTemperatureHumidityAlarmCluster class:

  • https://github.com/zigpy/zha-device-handlers/blob/dev/zhaquirks/tuya/ts0201.py#L34-L51

My assumption is that the nousMaxXXX and nousMinXXX attributes define the limits of the alarm and the nousXXXAlarm attributes should be the Enum with the type of alarm:

  • https://github.com/zigpy/zha-device-handlers/blob/dev/zhaquirks/tuya/ts0201.py#L26-L31

The nousTempUnitConvert should be an Enum to change the display (and measures?) units (ºC/ºF). The nousReportInterval should be a value between 1min to 120min. Not sure about the nousTempSensitivity.

Sooooo, what I would do is:

  • to add the TuyaTemperatureHumidityAlarmCluster to the INPUT_CLUSTERS in the replacement part
  • add the mappings between the DPs and the new cluster attributes (dp_to_attribute and data_point_handlers )
  • I believe that the missing attributes can be added to the TuyaTemperatureHumidityAlarmCluster. For testing purposes, you can add it to the TemperatureHumidityManufCluster

javicalle avatar Sep 26 '22 17:09 javicalle

thanks, i'll give it a try after new HA version released.

abstiger avatar Sep 27 '22 00:09 abstiger

@javicalle after upgraded to the Home Assistant 2022.10.1 Version. the Humidity and Battery can be shown, except that Humidity is shown like 7% but actually it's 70%

i tried to modify my custom quark file tuya_ts0601_tze200_whkgqxse.py as you suggested. but i'm not sure about if that is correct and how to add the missing attributes(nousTempUnitConvert: 9, nousTempSensitivity: 19, nousReportInterval: 17,) could you please help checking the quark file?

then i restart HA without re-pairing, i'll re-pairing it when i get home.

"""Tuya temp and humidity sensor with e-ink screen."""

from typing import Dict

from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
import zigpy.types as t
from zigpy.zcl.clusters.general import Basic, Groups, Ota, Scenes, Time
from zigpy.zcl.clusters.measurement import RelativeHumidity, TemperatureMeasurement

from zhaquirks.const import (
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
    SKIP_CONFIGURATION,
)
from zhaquirks.tuya import TuyaLocalCluster, TuyaPowerConfigurationCluster2AAA
from zhaquirks.tuya.ts0201 import TuyaTemperatureHumidityAlarmCluster
from zhaquirks.tuya.mcu import DPToAttributeMapping, EnchantedDevice, TuyaDPType, TuyaMCUCluster

# NOTES:
# The data comes in as a string on cluster, if there is nothing set up you may see these lines in the logs:
# Unknown message (b'19830100a40102000400000118') on cluster 61184: unknown endpoint or cluster id: 'No cluster ID 0xef00 on (a4:c1:38:d0:18:8b:64:aa, 1)'
#                                          28.0 degrees
# Unknown message (b'19840100a5020200040000022c') on cluster 61184: unknown endpoint or cluster id: 'No cluster ID 0xef00 on (a4:c1:38:d0:18:8b:64:aa, 1)'
#                                          55.6% humid
# Unknown message (b'19850100a60402000400000064') on cluster 61184: unknown endpoint or cluster id: 'No cluster ID 0xef00 on (a4:c1:38:d0:18:8b:64:aa, 1)'
#                                          100% battery


class TuyaTemperatureMeasurement(TemperatureMeasurement, TuyaLocalCluster):
    """Tuya local TemperatureMeasurement cluster."""


class TuyaRelativeHumidity(RelativeHumidity, TuyaLocalCluster):
    """Tuya local RelativeHumidity cluster."""


class TemperatureHumidityManufCluster(TuyaMCUCluster):
    """Tuya Manufacturer Cluster with Temperature and Humidity data points."""

    attributes = {
        0xD009: ("temperature_unit_converter", t.CharacterString, True),
        # Alarm information
        0xD013: ("temperature_sensitivity", t.CharacterString, True),
        0xD011: ("report_interval", t.uint16_t, True),
        # Unknown
        0xD010: ("unknown", t.uint8_t, True),
    }

    dp_to_attribute: Dict[int, DPToAttributeMapping] = {
        1: DPToAttributeMapping(
            TuyaTemperatureMeasurement.ep_attribute,
            "measured_value",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 10,  # decidegree to centidegree
        ),
        2: DPToAttributeMapping(
            TuyaRelativeHumidity.ep_attribute,
            "measured_value",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 100,  
        ),
        4: DPToAttributeMapping(
            TuyaPowerConfigurationCluster2AAA.ep_attribute,
            "battery_percentage_remaining",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 2,  # double reported percentage
        ),
        10: DPToAttributeMapping(
            TuyaTemperatureHumidityAlarmCluster.ep_attribute,
            "alarm_temperature_max",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 10,  # decipercent to centipercent
        ),
        11: DPToAttributeMapping(
            TuyaTemperatureHumidityAlarmCluster.ep_attribute,
            "alarm_temperature_min",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 10,  # decipercent to centipercent
        ),
        12: DPToAttributeMapping(
            TuyaTemperatureHumidityAlarmCluster.ep_attribute,
            "alarm_humidity_max",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 10,  # decipercent to centipercent
        ),
        13: DPToAttributeMapping(
            TuyaTemperatureHumidityAlarmCluster.ep_attribute,
            "alarm_humidity_min",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 10,  # decipercent to centipercent
        ),
        14: DPToAttributeMapping(
            TuyaTemperatureHumidityAlarmCluster.ep_attribute,
            "alarm_temperature",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x,
        ),
        15: DPToAttributeMapping(
            TuyaTemperatureHumidityAlarmCluster.ep_attribute,
            "alarm_humidity",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x,
        ),
    }

    data_point_handlers = {
        1: "_dp_2_attr_update",
        2: "_dp_2_attr_update",
        4: "_dp_2_attr_update",
        10: "_dp_2_attr_update",
        11: "_dp_2_attr_update",
        12: "_dp_2_attr_update",
        13: "_dp_2_attr_update",
        14: "_dp_2_attr_update",
        15: "_dp_2_attr_update",
    }


class TuyaTempHumiditySensor(EnchantedDevice, CustomDevice):
    """Custom device representing tuya temp and humidity sensor with e-ink screen."""

    signature = {
        # <SimpleDescriptor endpoint=1, profile=260, device_type=81
        # device_version=1
        # input_clusters=[4, 5, 61184, 0]
        # output_clusters=[25, 10]>
        MODELS_INFO: [("_TZE200_whkgqxse", "TS0601")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TemperatureHumidityManufCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Ota.cluster_id, Time.cluster_id],
            }
        },
    }

    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.TEMPERATURE_SENSOR,
                INPUT_CLUSTERS: [
                    TemperatureHumidityManufCluster,  # Single bus for temp, humidity, and battery
                    TuyaTemperatureHumidityAlarmCluster,
                    TuyaTemperatureMeasurement,
                    TuyaRelativeHumidity,
                    TuyaPowerConfigurationCluster2AAA,
                ],
                OUTPUT_CLUSTERS: [Ota.cluster_id, Time.cluster_id],
            }
        },
    }

here are some log info:

2022-10-09 09:59:08.197 DEBUG (MainThread) [homeassistant.components.zha.core.device] [0x35D9](TS0601): Device seen - marking the device available and resetting counter
2022-10-09 09:59:08.197 DEBUG (MainThread) [homeassistant.components.zha.core.device] [0x35D9](TS0601): Update device availability -  device available: True - new availability: True - changed: False
2022-10-09 09:59:09.213 DEBUG (MainThread) [zigpy_znp.api] Received command: AF.IncomingMsg.Callback(GroupId=0x0000, ClusterId=61184, SrcAddr=0x35D9, SrcEndpoint=1, DstEndpoint=1, WasBroadcast=<Bool.false: 0>, LQI=51, SecurityUse=<Bool.false: 0>, TimeStamp=14090783, TSN=0, Data=b'\x09\x5B\x02\x36\xA3\x01\x02\x00\x04\x00\x00\x00\xBE\x02\x02\x00\x04\x00\x00\x00\x44\x04\x02\x00\x04\x00\x00\x00\x64\x0A\x02\x00\x04\x00\x00\x01\x68\x0B\x02\x00\x04\x00\x00\x00\xC8', MacSrcAddr=0x35D9, MsgResultRadius=29)
2022-10-09 09:59:09.214 DEBUG (MainThread) [zigpy.application] Received a packet: ZigbeePacket(src=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x35D9), src_ep=1, dst=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x0000), dst_ep=1, source_route=None, extended_timeout=False, tsn=0, profile_id=260, cluster_id=61184, data=Serialized[b'\t[\x026\xa3\x01\x02\x00\x04\x00\x00\x00\xbe\x02\x02\x00\x04\x00\x00\x00D\x04\x02\x00\x04\x00\x00\x00d\n\x02\x00\x04\x00\x00\x01h\x0b\x02\x00\x04\x00\x00\x00\xc8'], tx_options=<TransmitOptions.NONE: 0>, radius=29, non_member_radius=0, lqi=51, rssi=None)
2022-10-09 09:59:09.214 DEBUG (MainThread) [zigpy.zcl] [0x35D9:1:0xef00] Received ZCL frame: b'\t[\x026\xa3\x01\x02\x00\x04\x00\x00\x00\xbe\x02\x02\x00\x04\x00\x00\x00D\x04\x02\x00\x04\x00\x00\x00d\n\x02\x00\x04\x00\x00\x01h\x0b\x02\x00\x04\x00\x00\x00\xc8'
2022-10-09 09:59:09.214 DEBUG (MainThread) [zigpy.zcl] [0x35D9:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 1>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False, *is_reply=True), tsn=91, command_id=2, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2022-10-09 09:59:09.215 DEBUG (MainThread) [zigpy.zcl] [0x35D9:1:0xef00] Decoded ZCL frame: TemperatureHumidityManufCluster:set_data_response(data=TuyaCommand(status=54, tsn=163, datapoints=[TuyaDatapointData(dp=1, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\xbe\x00\x00\x00', *payload=190)), TuyaDatapointData(dp=2, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'D\x00\x00\x00', *payload=68)), TuyaDatapointData(dp=4, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'd\x00\x00\x00', *payload=100)), TuyaDatapointData(dp=10, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'h\x01\x00\x00', *payload=360)), TuyaDatapointData(dp=11, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\xc8\x00\x00\x00', *payload=200))]))
2022-10-09 09:59:09.216 DEBUG (MainThread) [zigpy.zcl] [0x35D9:1:0xef00] Received command 0x02 (TSN 91): set_data_response(data=TuyaCommand(status=54, tsn=163, datapoints=[TuyaDatapointData(dp=1, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\xbe\x00\x00\x00', *payload=190)), TuyaDatapointData(dp=2, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'D\x00\x00\x00', *payload=68)), TuyaDatapointData(dp=4, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'd\x00\x00\x00', *payload=100)), TuyaDatapointData(dp=10, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'h\x01\x00\x00', *payload=360)), TuyaDatapointData(dp=11, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\xc8\x00\x00\x00', *payload=200))]))

abstiger avatar Oct 09 '22 02:10 abstiger

here is my pairing log pairing.log

abstiger avatar Oct 09 '22 11:10 abstiger

except that Humidity is shown like 7% but actually it's 70%

That can be fixed here:

        2: DPToAttributeMapping(
            TuyaRelativeHumidity.ep_attribute,
            "measured_value",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 1000,  
        ),

Probably would be the same in DP 12 and 13.

From the log I can see a couple of things:

  1. that #1779 handle all the attributes report from this device 🎉
  2. the device is reporting that values (and its current assignation)
DP value (raw) value (converted) attribute
1 190 19 (ºC?) temperature
2 68 68 (%) humidity
4 100 100 (%) battery percentage
10 360 36 (ºC?) alarm_temperature_max
11 200 20 (ºC?) alarm_temperature_min

Can you check if the alarm values are fine to you? Is possible to read these values from device to verify if they are the same?

javicalle avatar Oct 09 '22 17:10 javicalle

how to add the missing attributes(nousTempUnitConvert: 9, nousTempSensitivity: 19, nousReportInterval: 17,)

I'll give one to you, but the rest would be the same.

Let's take nousTempUnitConvert as example. The attribute is already defined as:

    attributes = {
        0xD009: ("temperature_unit_converter", t.CharacterString, True),
        # Alarm information
        0xD013: ("temperature_sensitivity", t.CharacterString, True),
        0xD011: ("report_interval", t.uint16_t, True),
        # Unknown
        0xD010: ("unknown", t.uint8_t, True),
    }

The next step is to map the attribute and the DP. That is done in the dp_to_attribute and data_point_handlers. Just add the definition as:

        9: DPToAttributeMapping( # <-- the new DP
            TemperatureHumidityManufCluster.ep_attribute, # <-- the class that have the attribute
            "temperature_unit_converter", # <-- the attribute name
            dp_type=TuyaDPType.ENUM, # <-- the DP type 
        ),

.../...

    data_point_handlers = {
        1: "_dp_2_attr_update",
        2: "_dp_2_attr_update",
        4: "_dp_2_attr_update",
        9: "_dp_2_attr_update",  # <-- the new DP
        10: "_dp_2_attr_update",
        11: "_dp_2_attr_update",
        12: "_dp_2_attr_update",
        13: "_dp_2_attr_update",
        14: "_dp_2_attr_update",
        15: "_dp_2_attr_update",
    }

Once modified, deleted the cache and restarted HA, you can try to write the attribute value from the device vies, 'manage clusters', selecting the TemperatureHumidityManufCluster and setting the value. I'll recommend to ou, first read the value and then try to set the new one.

javicalle avatar Oct 09 '22 17:10 javicalle

Now I have a few requests:

  • Can you check if the device syncs date/time correctly?
  • Can you check if the TemperatureHumidityManufCluster has mcu_version attribute? If not, there is any attribute with ID 0xEF00?

Thanks in advanced.

javicalle avatar Oct 09 '22 17:10 javicalle

That can be fixed here:

    2: DPToAttributeMapping(
        TuyaRelativeHumidity.ep_attribute,
        "measured_value",
        dp_type=TuyaDPType.VALUE,
        converter=lambda x: x * 1000,  
    ),

Probably would be the same in DP 12 and 13.

yes, i've already changed the converter from converter=lambda x: x * 10, to converter=lambda x: x * 100, then it shows correctly.

abstiger avatar Oct 10 '22 00:10 abstiger

Can you check if the device syncs date/time correctly?

how can i check? i tried to change the device date manually to 2021/1/1, waited for some minutes, it doesn't change.

Can you check if the TemperatureHumidityManufCluster has mcu_version attribute? If not, there is any attribute with ID 0xEF00?

if i defined attributes in TemperatureHumidityManufCluster, there are no mcu_version, just some attributes i defined. 2

if i remove those attributes, i got mcu_version, but Read Attribute gets None: 3

and the other attributes you mentioned above get None also. 1

i just can get DP 1,2,4 4

abstiger avatar Oct 10 '22 01:10 abstiger

how can i check? i tried to change the device date manually to 2021/1/1, waited for some minutes, it doesn't change.

I would try removing the battery and putting it on again. I hope that the device will trigger the time sync, but the logs will tell to us.

if i defined attributes in TemperatureHumidityManufCluster, there are no mcu_version, just some attributes i defined. if i remove those attributes, i got mcu_version

I see the bug:



class TemperatureHumidityManufCluster(TuyaMCUCluster):
    """Tuya Manufacturer Cluster with Temperature and Humidity data points."""

    attributes = TuyaMCUCluster.attributes.copy()
    attributes.append({
        0xD009: ("temperature_unit_converter", t.CharacterString, True),
        .../...

javicalle avatar Oct 10 '22 23:10 javicalle

I see the bug:

class TemperatureHumidityManufCluster(TuyaMCUCluster):
    """Tuya Manufacturer Cluster with Temperature and Humidity data points."""

    attributes = TuyaMCUCluster.attributes.copy()
    attributes.append({
        0xD009: ("temperature_unit_converter", t.CharacterString, True),
        .../...

I got exception here File "/config/quirks/tuya_ts0601_tze200_whkgqxse.py", line 46, in TemperatureHumidityManufCluster attributes.append({ AttributeError: 'dict' object has no attribute 'append'

blomnik avatar Oct 28 '22 00:10 blomnik

Upsssss, try with:

class TemperatureHumidityManufCluster(TuyaMCUCluster):
    """Tuya Manufacturer Cluster with Temperature and Humidity data points."""

    attributes = TuyaMCUCluster.attributes.copy()
    attributes.update({
        0xD009: ("temperature_unit_converter", t.CharacterString, True),
        .../...
    })

javicalle avatar Oct 28 '22 08:10 javicalle

Now I have a few requests:

  • Can you check if the device syncs date/time correctly?
  • Can you check if the TemperatureHumidityManufCluster has mcu_version attribute? If not, there is any attribute with ID 0xEF00?

Thanks in advanced.

I got correct values of temp, hum and battery at first time after pairing (again). But this values does not updates. How can I set update interval. Requesting value from 'report_interval (id 0xd011)' returns None. I'm stuck (

blomnik avatar Oct 28 '22 18:10 blomnik

That can be a pairing issue. Battery powered devices must keep 'awake' during all the pairing process. For that, short press the pairing button every second or so while device pairing last.

javicalle avatar Oct 28 '22 19:10 javicalle

That can be a pairing issue. Battery powered devices must keep 'awake' during all the pairing process. For that, short press the pairing button every second or so while device pairing last.

Unfortunately, this did not help. :( Same issue: got valid values first time after re-pair and no updates later. And now I see 'not available' in UI.

But, if I hold "+" and "-" buttons for a several seconds, values are become 'available', but still not updated. I guess due to 'time request' from device.

blomnik avatar Oct 29 '22 18:10 blomnik

The 'time requests part would be already fixed. Please attach the logs from your device. Any logs from command 0x0024, 0x24, 40 are wellcomed.

javicalle avatar Nov 02 '22 00:11 javicalle

The 'time requests part would be already fixed. Please attach the logs from your device. Any logs from command 0x0024, 0x24, 40 are wellcomed.

Sorry for long response. Here is my logs right after "+" and "-" pressed. By the way, Temp and Humidity began updates after last core upgrade. Time sync still does not work. May be I made something wrong?

zha.log

blomnik avatar Nov 08 '22 22:11 blomnik

Hi Arthur, from your logs it seems that there is something wrong in the quirk but not sure if related. Can you post here your quirk version? Put the code between ``` marks to format the code:

```
All your quirk here
```

javicalle avatar Nov 13 '22 21:11 javicalle

@javicalle , thank you for reply. I guess, I coded something wrong, but can't find where I failed :). Here is my quirk

"""Tuya temp and humidity sensor"""

from typing import Dict

from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
import zigpy.types as t
from zigpy.zcl.clusters.general import Basic, Groups, Ota, Scenes, Time
from zigpy.zcl.clusters.measurement import RelativeHumidity, TemperatureMeasurement

from zhaquirks.const import (
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
    SKIP_CONFIGURATION,
)
from zhaquirks.tuya import TuyaLocalCluster, TuyaPowerConfigurationCluster2AAA
from zhaquirks.tuya.ts0201 import TuyaTemperatureHumidityAlarmCluster
from zhaquirks.tuya.mcu import DPToAttributeMapping, EnchantedDevice, TuyaDPType, TuyaMCUCluster

class TuyaTemperatureMeasurement(TemperatureMeasurement, TuyaLocalCluster):
    """Tuya local TemperatureMeasurement cluster."""


class TuyaRelativeHumidity(RelativeHumidity, TuyaLocalCluster):
    """Tuya local RelativeHumidity cluster."""


class TemperatureHumidityManufCluster(TuyaMCUCluster):
    """Tuya Manufacturer Cluster with Temperature and Humidity data points."""

    attributes = TuyaMCUCluster.attributes.copy()
    attributes.update({
        0xD009: ("temperature_unit_converter", t.CharacterString, True),
        # Alarm information
        0xD013: ("temperature_sensitivity", t.CharacterString, True),
        0xD011: ("report_interval", t.uint16_t, True),
        # Unknown
        0xD010: ("unknown", t.uint8_t, True),
    })

    dp_to_attribute: Dict[int, DPToAttributeMapping] = {
        1: DPToAttributeMapping(
            TuyaTemperatureMeasurement.ep_attribute,
            "measured_value",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 10,  # decidegree to centidegree
        ),
        2: DPToAttributeMapping(
            TuyaRelativeHumidity.ep_attribute,
            "measured_value",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 100,  
        ),
        4: DPToAttributeMapping(
            TuyaPowerConfigurationCluster2AAA.ep_attribute,
            "battery_percentage_remaining",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 2,  # double reported percentage
        ),
        10: DPToAttributeMapping(
            TuyaTemperatureHumidityAlarmCluster.ep_attribute,
            "alarm_temperature_max",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 10,  # decipercent to centipercent
        ),
        11: DPToAttributeMapping(
            TuyaTemperatureHumidityAlarmCluster.ep_attribute,
            "alarm_temperature_min",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 10,  # decipercent to centipercent
        ),
        12: DPToAttributeMapping(
            TuyaTemperatureHumidityAlarmCluster.ep_attribute,
            "alarm_humidity_max",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 10,  # decipercent to centipercent
        ),
        13: DPToAttributeMapping(
            TuyaTemperatureHumidityAlarmCluster.ep_attribute,
            "alarm_humidity_min",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 10,  # decipercent to centipercent
        ),
        14: DPToAttributeMapping(
            TuyaTemperatureHumidityAlarmCluster.ep_attribute,
            "alarm_temperature",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x,
        ),
        15: DPToAttributeMapping(
            TuyaTemperatureHumidityAlarmCluster.ep_attribute,
            "alarm_humidity",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x,
        ),
    }

    data_point_handlers = {
        1: "_dp_2_attr_update",
        2: "_dp_2_attr_update",
        4: "_dp_2_attr_update",
        10: "_dp_2_attr_update",
        11: "_dp_2_attr_update",
        12: "_dp_2_attr_update",
        13: "_dp_2_attr_update",
        14: "_dp_2_attr_update",
        15: "_dp_2_attr_update",
    }


class TuyaTempHumiditySensor(EnchantedDevice, CustomDevice):
    """Custom device representing tuya temp and humidity sensor with e-ink screen."""

    signature = {
        # <SimpleDescriptor endpoint=1, profile=260, device_type=81
        # device_version=1
        # input_clusters=[4, 5, 61184, 0]
        # output_clusters=[25, 10]>
        MODELS_INFO: [("_TZE200_whkgqxse", "TS0601")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TemperatureHumidityManufCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Ota.cluster_id, Time.cluster_id],
            }
        },
    }

    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.TEMPERATURE_SENSOR,
                INPUT_CLUSTERS: [
                    TemperatureHumidityManufCluster,  # Single bus for temp, humidity, and battery
                    TuyaTemperatureHumidityAlarmCluster,
                    TuyaTemperatureMeasurement,
                    TuyaRelativeHumidity,
                    TuyaPowerConfigurationCluster2AAA,
                ],
                OUTPUT_CLUSTERS: [Ota.cluster_id, Time.cluster_id],
            }
        },
    }

blomnik avatar Nov 14 '22 19:11 blomnik

Sorry for the late response. The issue went to the backlog and I lost the track of it.

I have reviewed the issue and I believe that I have found the issue. That's the new proposed quirk:

ts0601_sensor2.py
"""Tuya temp and humidity sensor"""

from typing import Dict

from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
import zigpy.types as t
from zigpy.zcl.clusters.general import Basic, Groups, Ota, Scenes, Time
from zigpy.zcl.clusters.measurement import RelativeHumidity, TemperatureMeasurement

from zhaquirks.const import (
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
    SKIP_CONFIGURATION,
)
from zhaquirks.tuya import TuyaLocalCluster, TuyaPowerConfigurationCluster2AAA
from zhaquirks.tuya.ts0201 import TuyaTemperatureHumidityAlarmCluster
from zhaquirks.tuya.mcu import (
    DPToAttributeMapping,
    EnchantedDevice,
    TuyaDPType,
    TuyaMCUCluster,
)


class TuyaTemperatureMeasurement(TemperatureMeasurement, TuyaLocalCluster):
    """Tuya local TemperatureMeasurement cluster."""


class TuyaRelativeHumidity(RelativeHumidity, TuyaLocalCluster):
    """Tuya local RelativeHumidity cluster."""


class TuyaTHAC(TuyaTemperatureHumidityAlarmCluster):
    """Tuya cluster."""

    ep_attribute = "tuya_temp_hum_alarm_cluster"


class TemperatureHumidityManufCluster(TuyaMCUCluster):
    """Tuya Manufacturer Cluster with Temperature and Humidity data points."""

    attributes = TuyaMCUCluster.attributes.copy()
    attributes.update(
        {
            0xD009: ("temperature_unit_converter", t.CharacterString, True),
            # Alarm information
            0xD013: ("temperature_sensitivity", t.CharacterString, True),
            0xD011: ("report_interval", t.uint16_t, True),
            # Unknown
            0xD010: ("unknown", t.uint8_t, True),
        }
    )

    dp_to_attribute: Dict[int, DPToAttributeMapping] = {
        1: DPToAttributeMapping(
            TuyaTemperatureMeasurement.ep_attribute,
            "measured_value",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 10,  # decidegree to centidegree
        ),
        2: DPToAttributeMapping(
            TuyaRelativeHumidity.ep_attribute,
            "measured_value",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 100,
        ),
        4: DPToAttributeMapping(
            TuyaPowerConfigurationCluster2AAA.ep_attribute,
            "battery_percentage_remaining",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 2,  # double reported percentage
        ),
        10: DPToAttributeMapping(
            TuyaTHAC.ep_attribute,
            "alarm_temperature_max",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 10,  # decipercent to centipercent
        ),
        11: DPToAttributeMapping(
            TuyaTHAC.ep_attribute,
            "alarm_temperature_min",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 10,  # decipercent to centipercent
        ),
        12: DPToAttributeMapping(
            TuyaTHAC.ep_attribute,
            "alarm_humidity_max",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 10,  # decipercent to centipercent
        ),
        13: DPToAttributeMapping(
            TuyaTHAC.ep_attribute,
            "alarm_humidity_min",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 10,  # decipercent to centipercent
        ),
        14: DPToAttributeMapping(
            TuyaTHAC.ep_attribute,
            "temperature_humidity",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x,
        ),
        15: DPToAttributeMapping(
            TuyaTHAC.ep_attribute,
            "alarm_humidity",
            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x,
        ),
    }

    data_point_handlers = {
        1: "_dp_2_attr_update",
        2: "_dp_2_attr_update",
        4: "_dp_2_attr_update",
        10: "_dp_2_attr_update",
        11: "_dp_2_attr_update",
        12: "_dp_2_attr_update",
        13: "_dp_2_attr_update",
        14: "_dp_2_attr_update",
        15: "_dp_2_attr_update",
    }


class TuyaTempHumiditySensor(EnchantedDevice, CustomDevice):
    """Custom device representing tuya temp and humidity sensor with e-ink screen."""

    signature = {
        # <SimpleDescriptor endpoint=1, profile=260, device_type=81
        # device_version=1
        # input_clusters=[4, 5, 61184, 0]
        # output_clusters=[25, 10]>
        MODELS_INFO: [("_TZE200_whkgqxse", "TS0601")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TemperatureHumidityManufCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Ota.cluster_id, Time.cluster_id],
            }
        },
    }

    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.TEMPERATURE_SENSOR,
                INPUT_CLUSTERS: [
                    TemperatureHumidityManufCluster,  # Single bus for temp, humidity, and battery
                    TuyaTHAC,
                    TuyaTemperatureMeasurement,
                    TuyaRelativeHumidity,
                    TuyaPowerConfigurationCluster2AAA,
                ],
                OUTPUT_CLUSTERS: [Ota.cluster_id, Time.cluster_id],
            }
        },
    }

javicalle avatar Nov 30 '22 08:11 javicalle

I have the same sensor.

With the deCONZ REST API, the device worked perfectly.

Now I have switched from deCONZ to ZHA (still using the Conbee), and the device no longer provides any data.

The last quirk from the end of November does ensure that the temperature and humidity sensor is now displayed, but without data.

I have removed and added the device several times, but the result is still the same: The device is added when pairing with both sensors, but after that there is no more communication.

The time is also no longer synchronised.


pairing logs will be added later

b2un0 avatar Jan 30 '23 14:01 b2un0

Logs from the device reporting are also welcomed. Enable the debug logs and look for your NWK device in the logs.

javicalle avatar Jan 30 '23 18:01 javicalle

OK, strange behaviour.

after pairing again, the sensor data is now displayed with your quirk.

Log attached, is that enough? is something missing?

0x308f.log

image

clock sync still not work, but i think this is still related to #1737

Device: https://www.aliexpress.com/item/1005005012094422.html

b2un0 avatar Jan 30 '23 20:01 b2un0