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] Tuya _TZE200_cirvgep4 #3041

Closed
dekar91 opened this issue Mar 15, 2024 · 5 comments
Closed

[Device Support Request] Tuya _TZE200_cirvgep4 #3041

dekar91 opened this issue Mar 15, 2024 · 5 comments
Labels
stale Issue is inactivate and might get closed soon Tuya Request/PR regarding a Tuya device

Comments

@dekar91
Copy link

dekar91 commented Mar 15, 2024

Problem description

The Quirk from #1944 works partually for me, apart from the battery and firmware fields. I would like to have it fixed.

Solution description

Battery level should be displayed.
Zigbee firmware should also be exposed, if possible.

Screenshots/Video

Screenshots/Video

image

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": "0x0302",
      "input_clusters": [
        "0x0000",
        "0x0001",
        "0x0402",
        "0x0405",
        "0xef00"
      ],
      "output_clusters": [
        "0x000a",
        "0x0019"
      ]
    }
  },
  "manufacturer": "_TZE200_cirvgep4",
  "model": "TS0601",
  "class": "ts0601_temperature.TuyaNousE6TempHumiditySensor"
}

Diagnostic information

Diagnostic information
{
  "home_assistant": {
    "installation_type": "Home Assistant OS",
    "version": "2024.3.1",
    "dev": false,
    "hassio": true,
    "virtualenv": false,
    "python_version": "3.12.2",
    "docker": true,
    "arch": "aarch64",
    "timezone": "Europe/Berlin",
    "os_name": "Linux",
    "os_version": "6.1.73-haos-raspi",
    "supervisor": "2024.03.0",
    "host_os": "Home Assistant OS 12.1",
    "docker_version": "24.0.7",
    "chassis": "embedded",
    "run_as_root": true
  },
  "custom_components": {
    "hacs": {
      "version": "1.34.0",
      "requirements": [
        "aiogithubapi>=22.10.1"
      ]
    },
    "watchman": {
      "version": "0.5.1",
      "requirements": [
        "prettytable==3.0.0"
      ]
    },
    "dwains_dashboard": {
      "version": "3.6.0",
      "requirements": []
    },
    "localtuya": {
      "version": "5.2.1",
      "requirements": []
    },
    "o365": {
      "version": "v4.7.0",
      "requirements": [
        "O365==2.0.34",
        "BeautifulSoup4>=4.10.0"
      ]
    },
    "sonoff": {
      "version": "3.6.0",
      "requirements": [
        "pycryptodome>=3.6.6"
      ]
    },
    "tuya_ble": {
      "version": "0.1.8",
      "requirements": [
        "tuya-iot-py-sdk==0.6.6",
        "pycountry==22.3.5"
      ]
    }
  },
  "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",
    "import_executor": true,
    "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.38.1",
      "pyserial==3.5",
      "pyserial-asyncio==0.6",
      "zha-quirks==0.0.112",
      "zigpy-deconz==0.23.1",
      "zigpy==0.63.4",
      "zigpy-xbee==0.20.1",
      "zigpy-zigate==0.12.0",
      "zigpy-znp==0.12.1",
      "universal-silabs-flasher==0.0.18",
      "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
  },
  "data": {
    "ieee": "**REDACTED**",
    "nwk": 50604,
    "manufacturer": "_TZE200_cirvgep4",
    "model": "TS0601",
    "name": "_TZE200_cirvgep4 TS0601",
    "quirk_applied": true,
    "quirk_class": "ts0601_temperature.TuyaNousE6TempHumiditySensor",
    "quirk_id": null,
    "manufacturer_code": 4417,
    "power_source": "Battery or Unknown",
    "lqi": 248,
    "rssi": -38,
    "last_seen": "2024-03-15T11:03:04",
    "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": "0x0302",
          "input_clusters": [
            "0x0000",
            "0x0001",
            "0x0402",
            "0x0405",
            "0xef00"
          ],
          "output_clusters": [
            "0x000a",
            "0x0019"
          ]
        }
      },
      "manufacturer": "_TZE200_cirvgep4",
      "model": "TS0601"
    },
    "active_coordinator": false,
    "entities": [
      {
        "entity_id": "sensor.bath_clock_battery",
        "name": "_TZE200_cirvgep4 TS0601"
      },
      {
        "entity_id": "sensor.bath_clock_temperature",
        "name": "_TZE200_cirvgep4 TS0601"
      },
      {
        "entity_id": "sensor.bath_clock_humidity",
        "name": "_TZE200_cirvgep4 TS0601"
      },
      {
        "entity_id": "update.bath_clock_firmware",
        "name": "_TZE200_cirvgep4 TS0601"
      }
    ],
    "neighbors": [],
    "routes": [],
    "endpoint_names": [
      {
        "name": "TEMPERATURE_SENSOR"
      }
    ],
    "user_given_name": "Bath clock",
    "device_reg_id": "029f5a4334aab87d89896e17580e9b7d",
    "area_id": "kitchen",
    "cluster_details": {
      "1": {
        "device_type": {
          "name": "TEMPERATURE_SENSOR",
          "id": 770
        },
        "profile_id": 260,
        "in_clusters": {
          "0x0000": {
            "endpoint_attribute": "basic",
            "attributes": {
              "0x0001": {
                "attribute_name": "app_version",
                "value": 72
              },
              "0x0004": {
                "attribute_name": "manufacturer",
                "value": "_TZE200_cirvgep4"
              },
              "0x0005": {
                "attribute_name": "model",
                "value": "TS0601"
              }
            },
            "unsupported_attributes": {}
          },
          "0xef00": {
            "endpoint_attribute": "tuya_manufacturer",
            "attributes": {
              "0xef00": {
                "attribute_name": "mcu_version",
                "value": "1.0.0"
              }
            },
            "unsupported_attributes": {}
          },
          "0x0402": {
            "endpoint_attribute": "temperature",
            "attributes": {
              "0x0000": {
                "attribute_name": "measured_value",
                "value": 2580
              }
            },
            "unsupported_attributes": {}
          },
          "0x0405": {
            "endpoint_attribute": "humidity",
            "attributes": {
              "0x0000": {
                "attribute_name": "measured_value",
                "value": 3400
              }
            },
            "unsupported_attributes": {}
          },
          "0x0001": {
            "endpoint_attribute": "power",
            "attributes": {
              "0x0033": {
                "attribute_name": "battery_quantity",
                "value": 2
              },
              "0x0034": {
                "attribute_name": "battery_rated_voltage",
                "value": 15
              },
              "0x0031": {
                "attribute_name": "battery_size",
                "value": 4
              }
            },
            "unsupported_attributes": {}
          }
        },
        "out_clusters": {
          "0x0019": {
            "endpoint_attribute": "ota",
            "attributes": {
              "0x0002": {
                "attribute_name": "current_file_version",
                "value": 72
              }
            },
            "unsupported_attributes": {}
          },
          "0x000a": {
            "endpoint_attribute": "time",
            "attributes": {},
            "unsupported_attributes": {}
          }
        }
      }
    }
  }
}

Logs

Logs
[Paste the logs here]

Custom quirk

Custom quirk
"""Tuya temp and humidity sensor with screen."""

from typing import Dict

################## clean this up
import zigpy.types as t
from zigpy.zcl import foundation
from zhaquirks.tuya import TuyaTimePayload, TuyaCommand
import datetime
from typing import Tuple, Optional, Union
##################

from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
from zigpy.zcl.clusters.general import Basic, Groups, Ota, Scenes, Time, AnalogOutput
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
# old from zhaquirks.tuya.mcu import DPToAttributeMapping, TuyaDPType, TuyaMCUCluster
from zhaquirks.tuya.mcu import DPToAttributeMapping, TuyaMCUCluster

TUYA_SET_TIME = 0x24

# 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 TemperatureUnitConvert(t.enum8):
    """Tuya Temp unit convert enum."""

    Celsius = 0x00
    Fahrenheit = 0x01


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

    attributes = TemperatureMeasurement.attributes.copy()
    attributes.update(
        {
            0x8001: ("temp_unit_convert", t.enum8),
            0x8002: ("alarm_max_temperature", t.Single),
            0x8003: ("alarm_min_temperature", t.Single),
            0x8004: ("temperature_sensitivity", t.Single),
        }
    )


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 * 100,  # 0.01 to 1.0
        ),
        4: DPToAttributeMapping(
            TuyaPowerConfigurationCluster2AAA.ep_attribute,
            "battery_percentage_remaining",
#           dp_type=TuyaDPType.VALUE,
            converter=lambda x: x * 2,  # reported percentage is doubled
        ),
        9: DPToAttributeMapping(
            TuyaTemperatureMeasurement.ep_attribute,
            "temp_unit_convert",
#            dp_type=TuyaDPType.ENUM,
            converter=lambda x: TemperatureUnitConvert(x)
        ),
        10: DPToAttributeMapping(
            TuyaTemperatureMeasurement.ep_attribute,
            "alarm_max_temperature",
#            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x / 10
        ),
        11: DPToAttributeMapping(
            TuyaTemperatureMeasurement.ep_attribute,
            "alarm_min_temperature",
#            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x / 10
        ),
        19: DPToAttributeMapping(
            TuyaTemperatureMeasurement.ep_attribute,
            "temperature_sensitivity",
#            dp_type=TuyaDPType.VALUE,
            converter=lambda x: x / 10
        )
    }
    
    set_time_offset = 1970
    set_time_local_offset = 1970

    data_point_handlers = {
        1: "_dp_2_attr_update",
        2: "_dp_2_attr_update",
        4: "_dp_2_attr_update",
        9: "_dp_2_attr_update",
        10: "_dp_2_attr_update",
        11: "_dp_2_attr_update",
        19: "_dp_2_attr_update",
    }

    def handle_set_time_request(self, sequence_number: t.uint16_t) -> foundation.Status:
        payload = TuyaTimePayload()

        utc_now = datetime.datetime.utcnow()
        now = datetime.datetime.now()

        offset_time = datetime.datetime(self.set_time_offset, 1, 1)
        offset_time_local = datetime.datetime(self.set_time_local_offset, 1, 1)
        
        utc_timestamp = int((utc_now - offset_time).total_seconds())
        local_timestamp = int((now - offset_time).total_seconds())
        
        payload.extend(utc_timestamp.to_bytes(4, "big", signed=False))
        payload.extend(local_timestamp.to_bytes(4, "big", signed=False))

        self.create_catching_task(
            self.command(TUYA_SET_TIME, payload, manufacturer=foundation.ZCLHeader.NO_MANUFACTURER_ID, expect_reply=False)
        )

        return foundation.Status.SUCCESS

class TuyaNousE6TempHumiditySensor(CustomDevice):
    """Custom device representing tuya temp and humidity sensor with a screen (NOUS E6)."""

    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_locansqn", "TS0601"), ("_TZE200_cirvgep4", "TS0601")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.SMART_PLUG, # this is how the device reports itself
                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: [
                    Basic.cluster_id,
                    TemperatureHumidityManufCluster,  # Single bus for temp, humidity, and battery
                    TuyaTemperatureMeasurement,
                    TuyaRelativeHumidity,
                    TuyaPowerConfigurationCluster2AAA,
                ],
                OUTPUT_CLUSTERS: [Ota.cluster_id, Time.cluster_id],
            }
        },
    }

Additional information

No response

@jacekk015
Copy link
Contributor

Your quirk already support battery state under DP4. Device just doesn't send it.
Take out battery, wait few seconds, put it inside. Then probably it will send it.
That's battery operated device and it sends as low data as it can.

@TheJulianJES TheJulianJES added the Tuya Request/PR regarding a Tuya device label Mar 18, 2024
@dekar91
Copy link
Author

dekar91 commented Mar 18, 2024

Thanks for the response @jacekk015!
This is weird, because when the device is connected to "Smart Life" it updates the battery status.
If your have some debugging guide or docs, so I could check, could you please share it with me?

@jacekk015
Copy link
Contributor

If your have some debugging guide or docs, so I could check, could you please share it with me?

You cant find in the logs data that haven't been sent.
If device sends something from DP4 you can be more than sure that quirk will forward this to HA.

SmartLife just caches last read. Same as HA do, it will just show you last read from the cache/database.
You could always try to hack SmartLife <-> Device communication, but I'm pretty sure it's not too wise to often ask battery device about battery status, because that drains battery even more.
All battery driven devices are known to be lazy Zigbee devices.

@nono031
Copy link

nono031 commented Mar 28, 2024

duplicated with #2304

Copy link

There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates. Please make sure to update to the latest version and check if that solves the issue. Let us know if that works for you by adding a comment 👍 This issue has now been marked as stale and will be closed if no further activity occurs. Thank you for your contributions.

@github-actions github-actions bot added the stale Issue is inactivate and might get closed soon label Sep 24, 2024
@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Oct 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stale Issue is inactivate and might get closed soon Tuya Request/PR regarding a Tuya device
Projects
None yet
Development

No branches or pull requests

4 participants