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] linptech Human Presence Sensor #2599

Open
seanhagen opened this issue Sep 20, 2023 · 26 comments
Open

[Device Support Request] linptech Human Presence Sensor #2599

seanhagen opened this issue Sep 20, 2023 · 26 comments
Labels
Tuya Request/PR regarding a Tuya device

Comments

@seanhagen
Copy link

Problem description

Request to add support for the linptech Human Presence Sensor ( aka Moes Human Presence Sensor -- might be a rebrand of the linptech )

It looks like folks in this thread are getting close to having it working in zigbee2mqtt.

Solution description

Integration into ZHA or zha_quirk to get the device working in HA.

Screenshots/Video

No response

Device signature

Device signature
{
  "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.FullFunctionDevice|MainsPowered|RxOnWhenIdle|AllocateAddress: 142>, manufacturer_code=4098, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)",
  "endpoints": {
    "1": {
      "profile_id": "0x0104",
      "device_type": "0x0402",
      "input_clusters": [
        "0x0000",
        "0x0003",
        "0x0004",
        "0x0005",
        "0x0500",
        "0x4000",
        "0xe002",
        "0xef00"
      ],
      "output_clusters": [
        "0x000a",
        "0x0019"
      ]
    }
  },
  "manufacturer": "_TZ3218_awarhusb",
  "model": "TS0225",
  "class": "zigpy.device.Device"
}

Diagnostic information

Diagnostic information
{
  "home_assistant": {
    "installation_type": "Home Assistant OS",
    "version": "2023.9.2",
    "dev": false,
    "hassio": true,
    "virtualenv": false,
    "python_version": "3.11.5",
    "docker": true,
    "arch": "aarch64",
    "timezone": "America/Vancouver",
    "os_name": "Linux",
    "os_version": "6.1.21-v8",
    "supervisor": "2023.09.2",
    "host_os": "Home Assistant OS 10.5",
    "docker_version": "23.0.6",
    "chassis": "embedded",
    "run_as_root": true
  },
  "custom_components": {
    "plex_recently_added": {
      "version": "0.3.8",
      "requirements": []
    },
    "browser_mod": {
      "version": "2.3.0",
      "requirements": []
    },
    "radarr_upcoming_media": {
      "version": "0.3.6",
      "requirements": []
    },
    "holidays": {
      "version": "1.9.6",
      "requirements": [
        "python-dateutil>=2.8.2",
        "holidays>=0.14.2"
      ]
    },
    "truenas": {
      "version": "0.0.0",
      "requirements": []
    },
    "ble_monitor": {
      "version": "12.4.0",
      "requirements": [
        "pycryptodomex>=3.14.1",
        "janus>=1.0.0",
        "aioblescan>=0.2.14",
        "btsocket>=0.2.0",
        "pyric>=0.1.6.3"
      ]
    },
    "waste_collection_schedule": {
      "version": "1.42.0",
      "requirements": [
        "icalendar",
        "recurring_ical_events",
        "icalevents",
        "bs4"
      ]
    },
    "mail_and_packages": {
      "version": "0.3.18",
      "requirements": [
        "beautifulsoup4",
        "Pillow>=9.0"
      ]
    },
    "pfsense": {
      "version": "0.1.0",
      "requirements": [
        "mac-vendor-lookup>=0.1.11"
      ]
    },
    "adaptive_lighting": {
      "version": "1.19.0",
      "requirements": [
        "ulid-transform"
      ]
    },
    "schedule_state": {
      "version": "0.18.1",
      "requirements": [
        "portion==2.3.0"
      ]
    },
    "sonarr_upcoming_media": {
      "version": "0.2.7",
      "requirements": []
    },
    "alarmo": {
      "version": "v1.9.10",
      "requirements": []
    },
    "babybuddy": {
      "version": "v0.0.0",
      "requirements": []
    },
    "hacs": {
      "version": "1.32.1",
      "requirements": [
        "aiogithubapi>=22.10.1"
      ]
    },
    "grocy": {
      "version": "v4.11.1",
      "requirements": [
        "pygrocy==2.0.0"
      ]
    },
    "multiscrape": {
      "version": "6.5.0",
      "requirements": [
        "lxml==4.9.1",
        "beautifulsoup4==4.11.1"
      ]
    },
    "scheduler": {
      "version": "v0.0.0",
      "requirements": []
    },
    "garbage_collection": {
      "version": "3.21",
      "requirements": [
        "python-dateutil>=2.8.2"
      ]
    },
    "ics_calendar": {
      "version": "3.1.8",
      "requirements": [
        "ics>=0.7.2",
        "recurring_ical_events>=2.0.2",
        "icalendar>=5.0.4"
      ]
    },
    "keymaster": {
      "version": "v0.0.85",
      "requirements": []
    }
  },
  "integration_manifest": {
    "domain": "zha",
    "name": "Zigbee Home Automation",
    "after_dependencies": [
      "onboarding",
      "usb"
    ],
    "codeowners": [
      "@dmulcahey",
      "@adminiuga",
      "@puddly"
    ],
    "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.36.3",
      "pyserial==3.5",
      "pyserial-asyncio==0.6",
      "zha-quirks==0.0.103",
      "zigpy-deconz==0.21.1",
      "zigpy==0.57.1",
      "zigpy-xbee==0.18.2",
      "zigpy-zigate==0.11.0",
      "zigpy-znp==0.11.4",
      "universal-silabs-flasher==0.0.13"
    ],
    "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"
        ]
      }
    ],
    "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": 48475,
    "manufacturer": "_TZ3218_awarhusb",
    "model": "TS0225",
    "name": "_TZ3218_awarhusb TS0225",
    "quirk_applied": false,
    "quirk_class": "zigpy.device.Device",
    "manufacturer_code": 4098,
    "power_source": "Mains",
    "lqi": 116,
    "rssi": -71,
    "last_seen": "2023-09-20T15:30:32",
    "available": true,
    "device_type": "Router",
    "signature": {
      "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.FullFunctionDevice|MainsPowered|RxOnWhenIdle|AllocateAddress: 142>, manufacturer_code=4098, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)",
      "endpoints": {
        "1": {
          "profile_id": "0x0104",
          "device_type": "0x0402",
          "input_clusters": [
            "0x0000",
            "0x0003",
            "0x0004",
            "0x0005",
            "0x0500",
            "0x4000",
            "0xe002",
            "0xef00"
          ],
          "output_clusters": [
            "0x000a",
            "0x0019"
          ]
        }
      },
      "manufacturer": "_TZ3218_awarhusb",
      "model": "TS0225"
    },
    "active_coordinator": false,
    "entities": [
      {
        "entity_id": "binary_sensor.linptech_presence_sensor_iaszone",
        "name": "_TZ3218_awarhusb TS0225"
      },
      {
        "entity_id": "button.linptech_presence_sensor_identify",
        "name": "_TZ3218_awarhusb TS0225"
      }
    ],
    "neighbors": [],
    "routes": [],
    "endpoint_names": [
      {
        "name": "IAS_ZONE"
      }
    ],
    "user_given_name": "linptech Presence Sensor",
    "device_reg_id": "c6d51d3b072fca36eaef7e77eeb12ded",
    "area_id": null,
    "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": "_TZ3218_awarhusb"
              },
              "0x0005": {
                "attribute_name": "model",
                "value": "TS0225"
              }
            },
            "unsupported_attributes": {}
          },
          "0x0003": {
            "endpoint_attribute": "identify",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0004": {
            "endpoint_attribute": "groups",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0005": {
            "endpoint_attribute": "scenes",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0xe002": {
            "endpoint_attribute": null,
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x4000": {
            "endpoint_attribute": null,
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0xef00": {
            "endpoint_attribute": null,
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0500": {
            "endpoint_attribute": "ias_zone",
            "attributes": {
              "0x0010": {
                "attribute_name": "cie_addr",
                "value": [
                  52,
                  66,
                  7,
                  255,
                  255,
                  46,
                  33,
                  0
                ]
              },
              "0x0000": {
                "attribute_name": "zone_state",
                "value": 0
              },
              "0x0002": {
                "attribute_name": "zone_status",
                "value": 1
              },
              "0x0001": {
                "attribute_name": "zone_type",
                "value": 32771
              }
            },
            "unsupported_attributes": {}
          }
        },
        "out_clusters": {
          "0x000a": {
            "endpoint_attribute": "time",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0019": {
            "endpoint_attribute": "ota",
            "attributes": {},
            "unsupported_attributes": {}
          }
        }
      }
    }
  }
}

Logs

No response

Custom quirk

No response

Additional information

No response

@betimmm
Copy link

betimmm commented Sep 28, 2023

Same need here, can anyone help?

@judahrand
Copy link

This seems to be working in z2mqtt, I believe. I've had a play with trying to write a custom quirk but I'm not really sure what I'm doing! If anyone is willing/able to help I'd appreciate it!

@felafel
Copy link

felafel commented Nov 4, 2023

This seems to be working in z2mqtt, I believe. I've had a play with trying to write a custom quirk but I'm not really sure what I'm doing! If anyone is willing/able to help I'd appreciate it!

I have only today learned about ZHA quirks. If you would like someone to test it let me know. Thanks

@maelremrem
Copy link

Got mine today, and I only have the occupancy working. Can someone help me to write an ZHA quirk ?

@felafel
Copy link

felafel commented Nov 7, 2023

I tried to use a different quirk that is similar and change it to accept this model. That did not work for me. I am going to look into Zigbee2MQTT but not sure if it works with SkyConnect.

@cbarth3
Copy link

cbarth3 commented Nov 14, 2023

Picked one of these up. If I can help in some way to get it working with zha let me know

@felafel
Copy link

felafel commented Nov 14, 2023

Picked one of these up. If I can help in some way to get it working with zha let me know

I would say that writing a quirk for it would be great.

@danielgomezrico
Copy link
Contributor

@felafel can you open a PR with that code? Opening that may show what code did you add to get some advice

@felafel
Copy link

felafel commented Nov 16, 2023

I am not sure if this is helpful but here is what I have. I do not know why it is not being picked up and I have not found a way to see if the quirk is being attempted. I set up the settings I have seen in the YAML file but whether it is being used is a mystery. It would be helpful if ZHA could confirm that it is looking for quirks in my folder, and also, whether it cannot use files that are there for whatever reason. If there is a file there then ZHA should assume I want to use it, I think.

`"""Device handler for Tuya ZG-205Z-A Mini 24Ghz human presence sensor."""

import math
from typing import Dict, Optional, Tuple, Union
from zigpy.profiles import zgp, zha
from zigpy.profiles.zha import DeviceType
from zigpy.quirks import CustomCluster, CustomDevice
import zigpy.types as t
from zigpy.zcl import foundation

from zigpy.zcl.clusters.general import Basic, Identify, Ota, GreenPowerProxy, AnalogOutput
from zigpy.zcl.clusters.security import IasZone
from zigpy.zcl.clusters.measurement import (
IlluminanceMeasurement,
OccupancySensing,
)

from zhaquirks import MotionWithReset
from zhaquirks.const import (
DEVICE_TYPE,
ENDPOINTS,
INPUT_CLUSTERS,
MODELS_INFO,
OUTPUT_CLUSTERS,
PROFILE_ID,
)
from zhaquirks.tuya import TuyaLocalCluster, TuyaManufCluster, TuyaNewManufCluster, TuyaZBE000Cluster
from zhaquirks.tuya.mcu import (
DPToAttributeMapping,
TuyaAttributesCluster,
TuyaMCUCluster,
)

class MotionCluster(MotionWithReset):
"""Motion cluster."""

reset_s: int = 60

class TuyaOccupancySensing(OccupancySensing, TuyaLocalCluster):
"""Tuya local OccupancySensing cluster."""

class TuyaMmwRadarFadingTime(TuyaAttributesCluster, AnalogOutput):
"""AnalogOutput cluster for fading time."""

def __init__(self, *args, **kwargs):
    """Init."""
    super().__init__(*args, **kwargs)
    self._update_attribute(self.attributes_by_name["description"].id, "Fading time")
    self._update_attribute(self.attributes_by_name["min_present_value"].id, 0)
    self._update_attribute(self.attributes_by_name["max_present_value"].id, 600)
    self._update_attribute(self.attributes_by_name["resolution"].id, 1)
    self._update_attribute(
        self.attributes_by_name["engineering_units"].id, 73
    )

class TuyaMmwRadarLargeMotionDetectionSensitivity(TuyaAttributesCluster, AnalogOutput):
"""AnalogOutput cluster for Large motion detection sensitivity."""

def __init__(self, *args, **kwargs):
    """Init."""
    super().__init__(*args, **kwargs)
    self._update_attribute(self.attributes_by_name["description"].id, "Large motion sensitivity")
    self._update_attribute(self.attributes_by_name["min_present_value"].id, 0)
    self._update_attribute(self.attributes_by_name["max_present_value"].id, 10)
    self._update_attribute(self.attributes_by_name["resolution"].id, 1)

class TuyaMmwRadarLargeMotionDetectionDistance(TuyaAttributesCluster, AnalogOutput):
"""AnalogOutput cluster for Large motion detection distance."""

def __init__(self, *args, **kwargs):
    """Init."""
    super().__init__(*args, **kwargs)
    self._update_attribute(self.attributes_by_name["description"].id, "Large motion detection distance")
    self._update_attribute(self.attributes_by_name["min_present_value"].id, 0)
    self._update_attribute(self.attributes_by_name["max_present_value"].id, 1000)
    self._update_attribute(self.attributes_by_name["resolution"].id, 10)
    self._update_attribute(
        self.attributes_by_name["engineering_units"].id, 118
    )

class TuyaMmwRadarSmallMotionDetectionSensitivity(TuyaAttributesCluster, AnalogOutput):
"""AnalogOutput cluster for Small motion detection sensitivity."""

def __init__(self, *args, **kwargs):
    """Init."""
    super().__init__(*args, **kwargs)
    self._update_attribute(self.attributes_by_name["description"].id, "Small motion sensitivity")
    self._update_attribute(self.attributes_by_name["min_present_value"].id, 0)
    self._update_attribute(self.attributes_by_name["max_present_value"].id, 10)
    self._update_attribute(self.attributes_by_name["resolution"].id, 1)

class TuyaMmwRadarSmallMotionDetectionDistance(TuyaAttributesCluster, AnalogOutput):
"""AnalogOutput cluster for Small motion detection distance."""

def __init__(self, *args, **kwargs):
    """Init."""
    super().__init__(*args, **kwargs)
    self._update_attribute(self.attributes_by_name["description"].id, "Small motion detection distance")
    self._update_attribute(self.attributes_by_name["min_present_value"].id, 0)
    self._update_attribute(self.attributes_by_name["max_present_value"].id, 600)
    self._update_attribute(self.attributes_by_name["resolution"].id, 10)
    self._update_attribute(
        self.attributes_by_name["engineering_units"].id, 118
    )

class TuyaMmwRadarStaticMotionDetectionSensitivity(TuyaAttributesCluster, AnalogOutput):
"""AnalogOutput cluster for Static motion detection sensitivity."""

def __init__(self, *args, **kwargs):
    """Init."""
    super().__init__(*args, **kwargs)
    self._update_attribute(self.attributes_by_name["description"].id, "Static motion sensitivity")
    self._update_attribute(self.attributes_by_name["min_present_value"].id, 0)
    self._update_attribute(self.attributes_by_name["max_present_value"].id, 10)
    self._update_attribute(self.attributes_by_name["resolution"].id, 1)

class TuyaMmwRadarStaticMotionDetectionDistance(TuyaAttributesCluster, AnalogOutput):
"""AnalogOutput cluster for Static motion detection distance."""

def __init__(self, *args, **kwargs):
    """Init."""
    super().__init__(*args, **kwargs)
    self._update_attribute(self.attributes_by_name["description"].id, "Static motion detection distance")
    self._update_attribute(self.attributes_by_name["min_present_value"].id, 0)
    self._update_attribute(self.attributes_by_name["max_present_value"].id, 600)
    self._update_attribute(self.attributes_by_name["resolution"].id, 10)
    self._update_attribute(self.attributes_by_name["engineering_units"].id, 118)

class MmwRadarManufCluster(TuyaMCUCluster):
"""Tuya ZG-205Z-A Mini 24Ghz human presence sensor cluster."""

attributes = TuyaMCUCluster.attributes.copy()
attributes.update(
    {
        # ramdom attribute IDs
        #0xEF02: ("motion_detection_sensitivity", t.uint32_t, True),
        0xEF03: ("mov_minimum_distance", t.uint32_t, True),
        #0xEF04: ("motion_detection_distance", t.uint32_t, True),
        0xEF05: ("human_motion_state", t.enum8, True),
        #0xEF65: ("fading_time", t.uint32_t, True),
        0xEF66: ("motion_false_detection", t.uint32_t, True),
        #0xEF67: ("small_motion_detection_distance", t.uint32_t, True),
        #0xEF69: ("small_motion_detection_sensitivity", t.uint32_t, True),
        0xEF6A: ("illuminance_value", t.uint32_t, True),
        0xEF6B: ("indicator", t.enum8, True),
        #0xEF6C: ("static_detection_distance", t.uint32_t, True),
        #0xEF06: ("static_detection_sensitivity", t.uint32_t, True),
        0xEF07: ("micro_minimum_distance", t.uint32_t, True),
        0xEF08: ("motionless_minimum_distance", t.uint32_t, True),
        0xEF09: ("reset_setting", t.uint32_t, True),
        0xEF0A: ("breathe_false_detection", t.uint32_t, True),
        0xEF0B: ("time", t.uint32_t, True),
        0xEF0C: ("alarm_time", t.uint32_t, True),
        0xEF0D: ("alarm_volume", t.enum8, True),
        0xEF0E: ("working_mode", t.enum8, True),
        0xEF0F: ("auto1", t.uint32_t, True),
        0xEF10: ("auto2", t.uint32_t, True),
        0xEF11: ("auto3", t.uint32_t, True),
    }
)

dp_to_attribute: Dict[int, DPToAttributeMapping] = {
    1: DPToAttributeMapping(
        TuyaOccupancySensing.ep_attribute,
        "occupancy",
    ),
    2: DPToAttributeMapping(
        TuyaMmwRadarLargeMotionDetectionSensitivity.ep_attribute,
        "present_value",
    ),
    3: DPToAttributeMapping(
        TuyaMCUCluster.ep_attribute,
        "mov_minimum_distance",
    ),
    4: DPToAttributeMapping(
        TuyaMmwRadarLargeMotionDetectionDistance.ep_attribute,
        "present_value",
    ),
    101: DPToAttributeMapping(
        TuyaMCUCluster.ep_attribute,
        "human_motion_state",
    ),
    102: DPToAttributeMapping(
        TuyaMmwRadarFadingTime.ep_attribute,
        "present_value",
    ),
    103: DPToAttributeMapping(
        TuyaMCUCluster.ep_attribute,
        "motion_false_detection",
    ),
    104: DPToAttributeMapping(
        TuyaMmwRadarSmallMotionDetectionDistance.ep_attribute,
        "present_value",
    ),
    105: DPToAttributeMapping(
        TuyaMmwRadarSmallMotionDetectionSensitivity.ep_attribute,
        "present_value",
    ),
    106: DPToAttributeMapping(
        TuyaMCUCluster.ep_attribute,
        "illuminance_value",
    ),
    107: DPToAttributeMapping(
        TuyaMCUCluster.ep_attribute,
        "indicator",
    ),
    108: DPToAttributeMapping(
        TuyaMmwRadarStaticMotionDetectionDistance.ep_attribute,
        "present_value",
    ),
    109: DPToAttributeMapping(
        TuyaMmwRadarStaticMotionDetectionSensitivity.ep_attribute,
        "present_value",
    ),
    110: DPToAttributeMapping(
        TuyaMCUCluster.ep_attribute,
        "micro_minimum_distance",
    ),
    111: DPToAttributeMapping(
        TuyaMCUCluster.ep_attribute,
        "motionless_minimum_distance",
    ),
    112: DPToAttributeMapping(
        TuyaMCUCluster.ep_attribute,
        "reset_setting",
    ),
    113: DPToAttributeMapping(
        TuyaMCUCluster.ep_attribute,
        "breathe_false_detection",
    ),
    114: DPToAttributeMapping(
        TuyaMCUCluster.ep_attribute,
        "time",
    ),
    115: DPToAttributeMapping(
        TuyaMCUCluster.ep_attribute,
        "alarm_time",
    ),
    116: DPToAttributeMapping(
        TuyaMCUCluster.ep_attribute,
        "alarm_volume",
    ),
    117: DPToAttributeMapping(
        TuyaMCUCluster.ep_attribute,
        "working_mode",
    ),
    118: DPToAttributeMapping(
        TuyaMCUCluster.ep_attribute,
        "auto1",
    ),
    119: DPToAttributeMapping(
        TuyaMCUCluster.ep_attribute,
        "auto2",
    ),
    120: DPToAttributeMapping(
        TuyaMCUCluster.ep_attribute,
        "auto3",
    ),
}

data_point_handlers = {
    1: "_dp_2_attr_update",
    2: "_dp_2_attr_update",
    3: "_dp_2_attr_update",
    4: "_dp_2_attr_update",
    101: "_dp_2_attr_update",
    102: "_dp_2_attr_update",
    103: "_dp_2_attr_update",
    104: "_dp_2_attr_update",
    105: "_dp_2_attr_update",
    106: "_dp_2_attr_update",
    107: "_dp_2_attr_update",
    108: "_dp_2_attr_update",
    109: "_dp_2_attr_update",
    110: "_dp_2_attr_update",
    111: "_dp_2_attr_update",
    112: "_dp_2_attr_update",
    113: "_dp_2_attr_update",
    114: "_dp_2_attr_update",
    115: "_dp_2_attr_update",
    116: "_dp_2_attr_update",
    117: "_dp_2_attr_update",
    118: "_dp_2_attr_update",
    119: "_dp_2_attr_update",
    120: "_dp_2_attr_update",
}

class TS0225Radar(CustomDevice):
"""Quirk for Tuya ZG-205Z-A Mini 24Ghz human presence sensor."""

#note: Changed _TZE200_2aaelwxk to _TZ3218_awarhusb. Both appear to be model TS0225

signature = {
    #  endpoint=1, profile=260, device_type=1026, device_version=1,
    #  input_clusters=["0x0000", "0x0003", "0x0400", "0x0500","0xe000","0xe002", "0xee00", "0xef00"], output_clusters=[])
    MODELS_INFO: [("_TZ3218_awarhusb", "TS0225")],
    ENDPOINTS: {
        1: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.IAS_ZONE,
            INPUT_CLUSTERS: [
                Basic.cluster_id,
                Identify.cluster_id,
                IlluminanceMeasurement.cluster_id,
                IasZone.cluster_id,
                TuyaZBE000Cluster.cluster_id,
                0xE002, # Unknown
                0xEE00, # Unknown
                TuyaNewManufCluster.cluster_id,
            ],
            OUTPUT_CLUSTERS: [],
        },
        242: {
            # "profile_id": "0xA1E0", "device_type": "0x0061",
            # "in_clusters": [], "out_clusters": ["0x0021"]
            PROFILE_ID: zgp.PROFILE_ID,
            DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
            INPUT_CLUSTERS: [],
            OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
        },
    },
}
replacement = {
    ENDPOINTS: {
        1: {
            INPUT_CLUSTERS: [
                Basic.cluster_id,
                Identify.cluster_id,
                IlluminanceMeasurement.cluster_id,
                MotionCluster,
                TuyaZBE000Cluster,
                MmwRadarManufCluster,
                TuyaOccupancySensing,

            ],
            OUTPUT_CLUSTERS: [],
        },
        2: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarFadingTime,
            ],
            OUTPUT_CLUSTERS: [],
        },
        3: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarLargeMotionDetectionSensitivity,
            ],
            OUTPUT_CLUSTERS: [],
        },
        4: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarLargeMotionDetectionDistance,
            ],
            OUTPUT_CLUSTERS: [],
        },
        5: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarSmallMotionDetectionSensitivity,
            ],
            OUTPUT_CLUSTERS: [],
        },
        6: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarSmallMotionDetectionDistance,
            ],
            OUTPUT_CLUSTERS: [],
        },
        7: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarStaticMotionDetectionSensitivity,
            ],
            OUTPUT_CLUSTERS: [],
        },
        8: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarStaticMotionDetectionDistance,
            ],
            OUTPUT_CLUSTERS: [],
        },
        242: {
            PROFILE_ID: zgp.PROFILE_ID,
            DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
            INPUT_CLUSTERS: [],
            OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
        },
    },
}`

@felafel
Copy link

felafel commented Nov 21, 2023

Does @danielgomezrico or anyone else have constructive help with the code above?

@danielgomezrico
Copy link
Contributor

I was a bit out of clues about how to build this one, but I want to try

@kaiserkiwi
Copy link

Bought some of these because they were recommended. Sadly the person that recommended it didn't know about ZHA support (he said it works out of the box, but he meant Z2MQTT.

Any news on this?

@mroony
Copy link

mroony commented Dec 6, 2023

I did the same and too have no clue on how to make it better.

@TheJulianJES TheJulianJES added the Tuya Request/PR regarding a Tuya device label Dec 24, 2023
@kaiserkiwi
Copy link

According to blakkadder the device seems to work already. I don't have the opportunity to test it right now, so any updates on this?

See https://zigbee.blakadder.com/Linptech_ES1.html

@felafel
Copy link

felafel commented Dec 26, 2023

According to blakkadder the device seems to work already. I don't have the opportunity to test it right now, so any updates on this?

See https://zigbee.blakadder.com/Linptech_ES1.html

There is an attempted ZHA Quirk above to get the other features to work. Presence itself appears to be in ZHA but the other features do not. Do you have any suggestions on getting the quirk to work?

@kaiserkiwi
Copy link

I sadly have no experience in Python or ZHA quirks. So I'm just here to ask. 😅

When I use it the way it works now and someone writes a quirk does it automatically work or do I have to re-pair it?

@felafel

This comment was marked as off-topic.

@dmulcahey
Copy link
Collaborator

@felafel i understand you may be frustrated but everyone working on these things are volunteers. This isn’t the appropriate place to vent.

@kaiserkiwi
Copy link

I think it's fair to point out that the official implementation is much worse in many points than a community alternative. The wrong place to vent? Definitely. But he is right in my opinion.

I'm really frustrated too. Tried to switch ti Zigbee2MQTT, failed and now are trapped in this.

I really wish that ZHA would get much more attention. Not only for Device support.

@dmulcahey
Copy link
Collaborator

I think it's fair to point out that the official implementation is much worse in many points than a community alternative. The wrong place to vent? Definitely. But he is right in my opinion.

I'm really frustrated too. Tried to switch ti Zigbee2MQTT, failed and now are trapped in this.

I really wish that ZHA would get much more attention. Not only for Device support.

What am I missing? All of this is FREE and done by folks in their spare time… ZHA came from the community and is largely maintained by community members… no one forces anyone to use it. everything here in this repo is from the community. The problem is with device manufacturers… they basically do what they want.

Tbh, being frustrated is perfectly normal and acceptable but dumping it on folks who put a lot of effort into this in their free time is just not right. Try to look at the situation from the opposite perspective and imagine how you would feel.

@kineticscreen
Copy link

I think my frustration is certainly less about the work of the volunteers, which as you say is entirely supported by the community, and more that I listened to Home Assistant when they announced ZHA as the native support for Zigbee. I was at the time on Zigbee2MQTT and changed over thinking that I was moving to the more stable / supported platform. Since then it's consistently lagged in features and support. For example, at the time I already had OTA updates presented nicely in the UI for Z2M, years late ZHA still handles OTA update incredibly unintuitively. I kept expecting that such basic things were only around the corner, but like the experience of this presence sensor, there's no predictable outcome for ZHA based on what Z2M is managing to do.

Expressing frustration at the countless hours spent by volunteers on ZHA is definitely missing the point, and they don't owe anyone anything, but to someone starting a Home Assistant build afresh, they're still encouraged that ZHA is best option for them to set up their Zigbee network, and I just don't think that's proven to be accurate.

@kaiserkiwi
Copy link

To come back to the initial topic: Has someone already implemented a custom quirk that we could test to get this running?

I really would like to use the luminance sensor in this thing instead of trying to guess the current light based on time and weather. 😅

@milobt
Copy link

milobt commented Jan 25, 2024

I have 5 of these and they work pretty well, however, there is a lag from some of them some time, not sure if this is because of some interference or due to the sensors flooding the zigbee log.

Some good news of the LED indicator front, I found to that when pairing these sensors with a TUYA hub, instead of my Z2M network, it pops up saying there’s an update, specifically to allow you to turn off the indicator LED.
So, if you update the device and then set the LED to off in the TUYA app, remove the device from the TUYA hub and repair with you Z2M network, it keeps the off setting and so stays off when motion is detected - GREAT!

This does posisble mean that there is now a cluster exposed to be able to configure the LED state over zigbee so anyone that can, please look into whether the LED cluster is exposed and add it to the device configuration.

@comperta
Copy link

comperta commented Apr 15, 2024

Hello everyone,

The _TZ3218_awarhusb module uses different clusters than those used by _TZE200_2aaelwxk so we cannot simply add the device, despite the fact that they are both TS0225 models.

I tried to implement a quirk that takes into account the signature of the _TZ3218_awarhusb module, without success so far.
I simply managed to recover the "Fading Time" and only in the device management.

I'll give you the code I use, if someone has better knowledge than me (first time I'm getting into this), I'm interested :-)

I am blocked in particular on two points:

  • For the luminance the cluster is 0x4000 instead of 0x0400 and I cannot read it.

  • For the "custom" cluster 0xE002 I tried to implement it but my knowledge is limited.

source from which I took inspiration: https://raw.githubusercontent.com/kkossev/Hubitat/development/Drivers/Tuya%20Multi%20Sensor%204%20In%201/Tuya%20Multi%20Sensor%204%20In%201.groovy

search TS0225_LINPTECH_RADAR inside the file.

"// LINPTECH / MOES are using a custom cluster 0xE002 for the settings (except for the fadingTime), ZCL cluster 0x0400 for illuminance (malformed reports!) and the IAS cluster 0x0500 for motion detection"

and of course zigbee2mqtt: Koenkk/zigbee2mqtt#18637
there are screenshots and valuable information on the data to read :-)

I Hope someone could help with this start :
ts0225_presence.zip

@rafmet
Copy link

rafmet commented Apr 23, 2024

Hi,

I don't have any experience writing zigpy quirks and at the beginning it seemed to be way above my head but as a complete beginner I was able to write a partially working quirk for TZ3218/TS0225.
First I tried to write V1 quirk but it was very difficult to expose sensor values as entities in Home Assistant. Then I tried V2 and they look a little simpler but documentation is poor and there are almost no examples since V2 quirks are quite a new idea.
The Zigbee2mqtt converter was helpful as a source of device details.

What is working:

  • target_distance
  • setting motion_detection_sensitivity, static_detection_sensitivity and motion_detection_distance (with problems)

What is not working:

  • luminance
  • setting sensitivity or detection distance returns error to home assistant but ... it works
  • initial sensor names in home assistant are trashy

When setting sensitivity or detection distance I get UNSUPPORTED_ATTRIBUTE

tz3218_ts0225.zip

I would be grateful for any help/feedback

@mool
Copy link

mool commented Apr 23, 2024

Hi, I'm also totally new with quirks but yesterday I was able to get this kind of working.... at least I was able to set the motion_detection_distance to reduce the distance where the sensor was detecting presence.

https://gist.github.com/mool/d4fb96eaed3d04b9bdbf1d7c1517141c

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Tuya Request/PR regarding a Tuya device
Projects
None yet
Development

No branches or pull requests