zigpy / zha-device-handlers

ZHA device handlers bridge the functionality gap created when manufacturers deviate from the ZCL specification, handling deviations and exceptions by parsing custom messages to and from Zigbee devices.
Apache License 2.0
751 stars 688 forks source link

[Device Support Request] _TZE200_v6ossqfy mmwave sensor #2059

Closed jimmyeao closed 1 year ago

jimmyeao commented 1 year ago

Is your feature request related to a problem? Please describe. A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like A clear and concise description of what you want to happen. _TZE200_v6ossqfy mmwave sensor is detected as a plug this is a MMwave sensor https://zigbee.blakadder.com/Tuya_PS-HPS.html

Device signature ```{ "node_descriptor": "NodeDescriptor(logical_type=, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=, mac_capability_flags=, manufacturer_code=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, descriptor_capability_field=, *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": 260, "device_type": "0x0051", "in_clusters": [ "0x0000", "0x0004", "0x0005", "0xef00" ], "out_clusters": [ "0x000a", "0x0019" ] }, "242": { "profile_id": 41440, "device_type": "0x0061", "in_clusters": [], "out_clusters": [ "0x0021" ] } }, "manufacturer": "_TZE200_v6ossqfy", "model": "TS0601", "class": "zigpy.device.Device" } ```
Diagnostic information ```yaml { "home_assistant": { "installation_type": "Home Assistant OS", "version": "2022.12.9", "dev": false, "hassio": true, "virtualenv": false, "python_version": "3.10.7", "docker": true, "arch": "x86_64", "timezone": "Europe/London", "os_name": "Linux", "os_version": "5.15.80", "supervisor": "2022.12.1", "host_os": "Home Assistant OS 9.4", "docker_version": "20.10.19", "chassis": "vm", "run_as_root": true }, "custom_components": { "matter_experimental": { "version": "0.3.0", "requirements": [ "python-matter-server==0.3.0" ] }, "alexa_media": { "version": "4.4.0", "requirements": [ "alexapy==1.26.4", "packaging>=20.3", "wrapt>=1.12.1" ] }, "philips_ambilight_hue": { "version": "1.0.1", "requirements": [ "ha-philipsjs==2.7.6" ] }, "philips_ambilight+hue": { "version": "0.0.4", "requirements": [] }, "entities_calendar": { "version": "0.0.9", "requirements": [] }, "dualmode_generic": { "version": "0.2", "requirements": [] }, "auto_backup": { "version": "1.3.0", "requirements": [] }, "govee": { "version": "1.1.2", "requirements": [ "govee-api-laggat==0.1.23", "dacite==1.5.1" ] }, "watchman": { "version": "0.5.1", "requirements": [ "prettytable==3.0.0" ] }, "garbage_collection": { "version": "4.10.2", "requirements": [ "python-dateutil>=2.8.2" ] }, "deebot": { "version": "1.5.0", "requirements": [ "deebot-client==1.6.0", "numpy>=1.21.2" ] }, "scheduler": { "version": "v0.0.0", "requirements": [] }, "mbapi2020": { "version": "0.7.4", "requirements": [ "protobuf>=3.19.1,<4" ] }, "variable": { "version": "1.0.0.0", "requirements": [] }, "skyq": { "version": "v2.10.8", "requirements": [ "pyskyqremote==0.3.23" ] }, "hacs": { "version": "1.29.0", "requirements": [ "aiogithubapi>=22.10.1" ] }, "circadian_lighting": { "version": "2.1.3", "requirements": [] }, "fullykiosk": { "version": "1.1.0", "requirements": [ "python-fullykiosk==0.0.11" ] }, "alarmo": { "version": "v1.9.7", "requirements": [] }, "pod_point": { "version": "0.4.1", "requirements": [ "podpointclient==1.0.0", "StrEnum>=0.4,<0.5" ] } }, "integration_manifest": { "domain": "zha", "name": "Zigbee Home Automation", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/zha", "requirements": [ "bellows==0.34.5", "pyserial==3.5", "pyserial-asyncio==0.6", "zha-quirks==0.0.89", "zigpy-deconz==0.19.2", "zigpy==0.52.3", "zigpy-xbee==0.16.2", "zigpy-zigate==0.10.3", "zigpy-znp==0.9.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*" }, { "type": "_zigstar_gw._tcp.local.", "name": "*zigstar*" } ], "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": 16235, "manufacturer": "_TZE200_v6ossqfy", "model": "TS0601", "name": "_TZE200_v6ossqfy TS0601", "quirk_applied": false, "quirk_class": "zigpy.device.Device", "manufacturer_code": 4417, "power_source": "Mains", "lqi": 147, "rssi": null, "last_seen": "2023-01-03T10:28:32", "available": true, "device_type": "Router", "signature": { "node_descriptor": "NodeDescriptor(logical_type=, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=, mac_capability_flags=, manufacturer_code=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, descriptor_capability_field=, *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": 260, "device_type": "0x0051", "in_clusters": [ "0x0000", "0x0004", "0x0005", "0xef00" ], "out_clusters": [ "0x000a", "0x0019" ] }, "242": { "profile_id": 41440, "device_type": "0x0061", "in_clusters": [], "out_clusters": [ "0x0021" ] } } }, "active_coordinator": false, "entities": [], "neighbors": [], "routes": [], "endpoint_names": [ { "name": "SMART_PLUG" }, { "name": "unknown 97 device_type of 0xa1e0 profile id" } ], "user_given_name": "officemmwave", "device_reg_id": "b1fca55bccea9f0446cd0171e2962922", "area_id": "72b6c263acdf4c31b94534ef5e09646d", "cluster_details": { "1": { "device_type": { "name": "SMART_PLUG", "id": 81 }, "profile_id": 260, "in_clusters": { "0x0004": { "endpoint_attribute": "groups", "attributes": {}, "unsupported_attributes": {} }, "0x0005": { "endpoint_attribute": "scenes", "attributes": {}, "unsupported_attributes": {} }, "0xef00": { "endpoint_attribute": null, "attributes": {}, "unsupported_attributes": {} }, "0x0000": { "endpoint_attribute": "basic", "attributes": { "0x0001": { "attribute_name": "app_version", "value": 70 }, "0x0004": { "attribute_name": "manufacturer", "value": "_TZE200_v6ossqfy" }, "0x0005": { "attribute_name": "model", "value": "TS0601" } }, "unsupported_attributes": {} } }, "out_clusters": { "0x0019": { "endpoint_attribute": "ota", "attributes": {}, "unsupported_attributes": {} }, "0x000a": { "endpoint_attribute": "time", "attributes": {}, "unsupported_attributes": {} } } }, "242": { "device_type": { "name": "unknown", "id": 97 }, "profile_id": 41440, "in_clusters": {}, "out_clusters": { "0x0021": { "endpoint_attribute": "green_power", "attributes": {}, "unsupported_attributes": {} } } } } } } ```
Additional logs ``` Paste any additional debug logs here. Don't remove the extra line breaks outside the ``` marks. ```

Additional context Add any other context or screenshots about the feature request here.

alexvaltchev commented 1 year ago

The USA Wall mounted one (square) or the ceiling version (round)?

jimmyeao commented 1 year ago

I got the wall mounted one, 5v

Sent from Outlook for iOShttps://aka.ms/o0ukef


From: Alex Valtchev @.> Sent: Monday, January 23, 2023 7:16:08 PM To: zigpy/zha-device-handlers @.> Cc: Jimmy White @.>; Author @.> Subject: Re: [zigpy/zha-device-handlers] [Device Support Request] _TZE200_v6ossqfy mmwave sensor (Issue #2059)

The USA Wall mounted one (square) or the ceiling version (round)?

— Reply to this email directly, view it on GitHubhttps://github.com/zigpy/zha-device-handlers/issues/2059#issuecomment-1400850146, or unsubscribehttps://github.com/notifications/unsubscribe-auth/ABHVAB6N2XCZWJKUO3W7JSTWT3KHRANCNFSM6AAAAAATPRIM6Y. You are receiving this because you authored the thread.Message ID: @.***>

alexvaltchev commented 1 year ago

Thanks. Does it work out of the box with ZHA? No need for additional quirks and device handles are extra steps?

javicalle commented 1 year ago

The attributes can be 'exposed' in HA creating a new ZHA sensor like this:

@MULTI_MATCH(
    channel_names="tuya_manufacturer",
    manufacturers={
        "_TZE200_0u3bj3rc",
        "_TZE200_mx6u6l4y",
        "_TZE200_v6ossqfy",
    },
)
class AttendanceTime(Sensor, id_suffix="duration_of_attendance"):
    """Sensor that displays the attendance time."""

    SENSOR_ATTR = "duration_of_attendance"
    _attr_device_class: SensorDeviceClass = SensorDeviceClass.DURATION
    _attr_icon = "mdi:timer"
    _attr_name: str = "Attendance time"
    _attr_native_unit_of_measurement = UnitOfTime.MINUTES

It's just the same approach that is already implemented here: https://github.com/home-assistant/core/blob/7d1dec8d315702020c5bb23bf0505bac7d584257/homeassistant/components/zha/sensor.py#L878-L891

Edit to add the code in the zha/sensor.py file or configure as a custom_component in HA. The duration_of_absence can be done the same way.

PS: probably sensor names can get proper names.

alexvaltchev commented 1 year ago

@javicalle this what is this new code above? Should I replace those lines in my original ts0601_sensor_custom.py ? I am getting confused. Can you please explain in simple English what does this do, and how to implement it. I do not see ZHA directory with a sensor.py file. Sorry for being lame, I am just very new and need step by step guide. Thank you.

javicalle commented 1 year ago

what is this new code above?

Jimmy was asking me how to expose the cluster attributes in HA, and that code shows how can be done.

Should I replace those lines in my original ts0601_sensor_custom.py ?

No, that code is for update the ZHA integration.

Can you please explain in simple English what does this do, and how to implement it. I do not see ZHA directory with a sensor.py file. Sorry for being lame, I am just very new and need step by step guide.

Most of the code is untested and prone to bugs, so it needs to be tested by someone who knows what they're doing so we can focus on the code. If you're not familiar with HA terminology and code, I think it's best to wait for the final version to be available on HA.

alexvaltchev commented 1 year ago

Yes, I have very basic knowledge, and agree would be better to wait until is implemented into HA. How long does it take for something like that to get official support, as I see you guys have been working already for a while. Thank you.

alexvaltchev commented 1 year ago

Guys I got a problem. The sensor was working it was taking about 1-2 second to change from "clear" to "detected" and about 65 seconds to from "detected" to "clear" and in Home Assistant. I then paired it with Smart Home app to check how is there and to see the other options available, and it got stuck on "detected" and now it never changes" I removed it from Smart Life and re-added, but does not work. I removed it and added into Home Assistant and still does not work. All it shoes is "detected" and even after 1 hour in the closet alone, still shows that. I tried to press fast the reset button 10 times, or to keep it on for 10s or other methods and nothing helps. How can I reboot the sensor to start working again ? Please help

javicalle commented 1 year ago

Sorry for the late response. Could you attach the diagnosis info from the device?

skycryer commented 1 year ago

Does that still work for you with zha in Home Assistant 2023.3.0? Seems to have a problem with the TuyaDPType stuff what I read in a different post.

besiktas97 commented 1 year ago

Does that still work for you with zha in Home Assistant 2023.3.0? Seems to have a problem with the TuyaDPType stuff what I read in a different post.

I've got the same thing and isnt working for me. Even after I have deleted the lines for it.

javicalle commented 1 year ago

Check this: https://github.com/zigpy/zha-device-handlers/issues/2250#issuecomment-1453978417

besiktas97 commented 1 year ago

Check this:

https://github.com/zigpy/zha-device-handlers/issues/2250#issuecomment-1453978417

I did exactly the same like you are commenting, but didnt work. I will try this again and let you know. Thanks.

skycryer commented 1 year ago

I updated the file like this and it works again. I have my Sensor back working and aha still works like expected. ts0601_sensor_custom.txt

besiktas97 commented 1 year ago

I updated the file like this and it works again. I have my Sensor back working and aha still works like expected.

ts0601_sensor_custom.txt

Thanks Sky. Can you repost it in plain text, so I can copy it easily? Will gonna try it tonight. I appreciate it.

skycryer commented 1 year ago
"""Human Presence Sensor 24GHz."""

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, GreenPowerProxy, Groups, Ota, Scenes, Time
from zigpy.zcl.clusters.measurement import OccupancySensing

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

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

class MmwRadarManufCluster(TuyaMCUCluster):
    """Human Presence Sensor 24GHz."""

    attributes = TuyaMCUCluster.attributes.copy()
    attributes.update(
        {
            # ramdom attribute IDs
            0xEF65: ("duration_of_attendance", t.uint32_t, True),
            0xEF66: ("duration_of_absence", t.uint32_t, True),
        }
    )

    dp_to_attribute: Dict[int, DPToAttributeMapping] = {
        1: DPToAttributeMapping(
            TuyaOccupancySensing.ep_attribute,
            "occupancy"
        ),
        101: DPToAttributeMapping(
            TuyaMCUCluster.ep_attribute,
            "duration_of_attendance"
        ),
        102: DPToAttributeMapping(
            TuyaMCUCluster.ep_attribute,
            "duration_of_absence"
        ),
        103: DPToAttributeMapping(
            TuyaOnOffNM.ep_attribute,
            "on_off"
        ),
    }

    data_point_handlers = {
        1: "_dp_2_attr_update",
        101: "_dp_2_attr_update",
        102: "_dp_2_attr_update",
        103: "_dp_2_attr_update",
    }

class MmwRadarMotion_var03(CustomDevice):
    """Millimeter wave occupancy sensor."""

    signature = {
        #  endpoint=1, profile=260, device_type=81, device_version=1,
        #  input_clusters=[4, 5, 61184, 0], output_clusters=[25, 10])
        MODELS_INFO: [
            ("_TZE200_0u3bj3rc", "TS0601"),
            ("_TZE200_mx6u6l4y", "TS0601"),
            ("_TZE200_v6ossqfy", "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,
                    TuyaMCUCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            242: {
                # <SimpleDescriptor endpoint=242 profile=41440 device_type=97
                # input_clusters=[]
                # output_clusters=[33]
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.OCCUPANCY_SENSOR,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    MmwRadarManufCluster,
                    TuyaOccupancySensing,
                    TuyaOnOffNM,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        }
    }
besiktas97 commented 1 year ago

"""Human Presence Sensor 24GHz."""

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, GreenPowerProxy, Groups, Ota, Scenes, Time

from zigpy.zcl.clusters.measurement import OccupancySensing

from zhaquirks.const import (

    DEVICE_TYPE,

    ENDPOINTS,

    INPUT_CLUSTERS,

    MODELS_INFO,

    OUTPUT_CLUSTERS,

    PROFILE_ID,

)

from zhaquirks.tuya import TuyaLocalCluster

from zhaquirks.tuya.mcu import (

    DPToAttributeMapping,

    TuyaMCUCluster,

    TuyaOnOffNM,

)

class TuyaOccupancySensing(OccupancySensing, TuyaLocalCluster):

    """Tuya local OccupancySensing cluster."""

class MmwRadarManufCluster(TuyaMCUCluster):

    """Human Presence Sensor 24GHz."""

    attributes = TuyaMCUCluster.attributes.copy()

    attributes.update(

        {

            # ramdom attribute IDs

            0xEF65: ("duration_of_attendance", t.uint32_t, True),

            0xEF66: ("duration_of_absence", t.uint32_t, True),

        }

    )

    dp_to_attribute: Dict[int, DPToAttributeMapping] = {

        1: DPToAttributeMapping(

            TuyaOccupancySensing.ep_attribute,

            "occupancy"

        ),

        101: DPToAttributeMapping(

            TuyaMCUCluster.ep_attribute,

            "duration_of_attendance"

        ),

        102: DPToAttributeMapping(

            TuyaMCUCluster.ep_attribute,

            "duration_of_absence"

        ),

        103: DPToAttributeMapping(

            TuyaOnOffNM.ep_attribute,

            "on_off"

        ),

    }

    data_point_handlers = {

        1: "_dp_2_attr_update",

        101: "_dp_2_attr_update",

        102: "_dp_2_attr_update",

        103: "_dp_2_attr_update",

    }

class MmwRadarMotion_var03(CustomDevice):

    """Millimeter wave occupancy sensor."""

    signature = {

        #  endpoint=1, profile=260, device_type=81, device_version=1,

        #  input_clusters=[4, 5, 61184, 0], output_clusters=[25, 10])

        MODELS_INFO: [

            ("_TZE200_0u3bj3rc", "TS0601"),

            ("_TZE200_mx6u6l4y", "TS0601"),

            ("_TZE200_v6ossqfy", "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,

                    TuyaMCUCluster.cluster_id,

                ],

                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],

            },

            242: {

                # <SimpleDescriptor endpoint=242 profile=41440 device_type=97

                # input_clusters=[]

                # output_clusters=[33]

                PROFILE_ID: 41440,

                DEVICE_TYPE: 97,

                INPUT_CLUSTERS: [],

                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],

            },

        },

    }

    replacement = {

        ENDPOINTS: {

            1: {

                PROFILE_ID: zha.PROFILE_ID,

                DEVICE_TYPE: zha.DeviceType.OCCUPANCY_SENSOR,

                INPUT_CLUSTERS: [

                    Basic.cluster_id,

                    Groups.cluster_id,

                    Scenes.cluster_id,

                    MmwRadarManufCluster,

                    TuyaOccupancySensing,

                    TuyaOnOffNM,

                ],

                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],

            },

            242: {

                PROFILE_ID: 41440,

                DEVICE_TYPE: 97,

                INPUT_CLUSTERS: [],

                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],

            },

        }

    }

Thanks!

Chreece commented 1 year ago

Thank you guys! Just got mine and added it with the custom quirk. The Led fortunatelly goes off with the switch and the occupancy sensor seems to work. Is there anything I can do to minimum the delay from on to off? It stays on some time with no occupancy

javicalle commented 1 year ago

You need to update the cluster attribute duration_of_absence (or duration_of_attendance) from the device cluster management.

Chreece commented 1 year ago

I have already done that, both are 0 but aren't the values populated from the sensor (how many minutes did detect presence...)?

javicalle commented 1 year ago

I have already done that, both are 0 but aren't the values populated from the sensor (how many minutes did detect presence...)?

Yes that's true 😓

Then there is no configuration for that property.

alexvaltchev commented 1 year ago

"""Human Presence Sensor 24GHz."""

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, GreenPowerProxy, Groups, Ota, Scenes, Time

from zigpy.zcl.clusters.measurement import OccupancySensing

from zhaquirks.const import (

    DEVICE_TYPE,

    ENDPOINTS,

    INPUT_CLUSTERS,

    MODELS_INFO,

    OUTPUT_CLUSTERS,

    PROFILE_ID,

)

from zhaquirks.tuya import TuyaLocalCluster

from zhaquirks.tuya.mcu import (

    DPToAttributeMapping,

    TuyaMCUCluster,

    TuyaOnOffNM,

)

class TuyaOccupancySensing(OccupancySensing, TuyaLocalCluster):

    """Tuya local OccupancySensing cluster."""

class MmwRadarManufCluster(TuyaMCUCluster):

    """Human Presence Sensor 24GHz."""

    attributes = TuyaMCUCluster.attributes.copy()

    attributes.update(

        {

            # ramdom attribute IDs

            0xEF65: ("duration_of_attendance", t.uint32_t, True),

            0xEF66: ("duration_of_absence", t.uint32_t, True),

        }

    )

    dp_to_attribute: Dict[int, DPToAttributeMapping] = {

        1: DPToAttributeMapping(

            TuyaOccupancySensing.ep_attribute,

            "occupancy"

        ),

        101: DPToAttributeMapping(

            TuyaMCUCluster.ep_attribute,

            "duration_of_attendance"

        ),

        102: DPToAttributeMapping(

            TuyaMCUCluster.ep_attribute,

            "duration_of_absence"

        ),

        103: DPToAttributeMapping(

            TuyaOnOffNM.ep_attribute,

            "on_off"

        ),

    }

    data_point_handlers = {

        1: "_dp_2_attr_update",

        101: "_dp_2_attr_update",

        102: "_dp_2_attr_update",

        103: "_dp_2_attr_update",

    }

class MmwRadarMotion_var03(CustomDevice):

    """Millimeter wave occupancy sensor."""

    signature = {

        #  endpoint=1, profile=260, device_type=81, device_version=1,

        #  input_clusters=[4, 5, 61184, 0], output_clusters=[25, 10])

        MODELS_INFO: [

            ("_TZE200_0u3bj3rc", "TS0601"),

            ("_TZE200_mx6u6l4y", "TS0601"),

            ("_TZE200_v6ossqfy", "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,

                    TuyaMCUCluster.cluster_id,

                ],

                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],

            },

            242: {

                # <SimpleDescriptor endpoint=242 profile=41440 device_type=97

                # input_clusters=[]

                # output_clusters=[33]

                PROFILE_ID: 41440,

                DEVICE_TYPE: 97,

                INPUT_CLUSTERS: [],

                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],

            },

        },

    }

    replacement = {

        ENDPOINTS: {

            1: {

                PROFILE_ID: zha.PROFILE_ID,

                DEVICE_TYPE: zha.DeviceType.OCCUPANCY_SENSOR,

                INPUT_CLUSTERS: [

                    Basic.cluster_id,

                    Groups.cluster_id,

                    Scenes.cluster_id,

                    MmwRadarManufCluster,

                    TuyaOccupancySensing,

                    TuyaOnOffNM,

                ],

                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],

            },

            242: {

                PROFILE_ID: 41440,

                DEVICE_TYPE: 97,

                INPUT_CLUSTERS: [],

                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],

            },

        }

    }

Thanks!

I put this into my my configuration.yaml file

zha: enable_quirks: true custom_quirks_path: /config/custom_zha_quirks/

Then inside I made file "ts0601_sensor_custom.py" and I put the code above from besiktas97

I can toggle the light ON and OFF but the status ALWAYS stays at "DETECTED". Why? I tried to remove the sensor from HA and added back again and restarted, nothing helps. It is always "detected" no matter what. Please help, why is it stuck like that? Thanks

Here is the diagnostic. zha-1be608adfd5dabaaecaf06df5a0aa201-_TZE200_v6ossqfy TS0601-790f4895d61d2335b9e2a7b1783801ec.json.txt

monstergubl commented 1 year ago

so my model is the TZE204_qasjif9e does this work ?

Wemmy0 commented 1 year ago

Looks like this has been updated to the TZE204_qasjif9e I've tried adding to to MODELS_INFO:

MODELS_INFO: [
            ("_TZE200_0u3bj3rc", "TS0601"),
            ("_TZE200_mx6u6l4y", "TS0601"),
            ("_TZE200_v6ossqfy", "TS0601"),
            ("_TZE204_qasjif9e", "TS0601"),
        ],

But I couldn't get it showing up correctly. I bought it from https://www.aliexpress.com/item/1005005709438307.html image

Wemmy0 commented 1 year ago

My bad, I got it working for _TZE204_qasjif9e:

"""Human Presence Sensor 24GHz."""

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, GreenPowerProxy, Groups, Ota, Scenes, Time
from zigpy.zcl.clusters.measurement import OccupancySensing

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

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

class MmwRadarManufCluster(TuyaMCUCluster):
    """Human Presence Sensor 24GHz."""

    attributes = TuyaMCUCluster.attributes.copy()
    attributes.update(
        {
            # ramdom attribute IDs
            0xEF65: ("duration_of_attendance", t.uint32_t, True),
            0xEF66: ("duration_of_absence", t.uint32_t, True),
        }
    )

    dp_to_attribute: Dict[int, DPToAttributeMapping] = {
        1: DPToAttributeMapping(
            TuyaOccupancySensing.ep_attribute,
            "occupancy"
        ),
        101: DPToAttributeMapping(
            TuyaMCUCluster.ep_attribute,
            "duration_of_attendance"
        ),
        102: DPToAttributeMapping(
            TuyaMCUCluster.ep_attribute,
            "duration_of_absence"
        ),
        103: DPToAttributeMapping(
            TuyaOnOffNM.ep_attribute,
            "on_off"
        ),
    }

    data_point_handlers = {
        1: "_dp_2_attr_update",
        101: "_dp_2_attr_update",
        102: "_dp_2_attr_update",
        103: "_dp_2_attr_update",
    }

class MmwRadarMotion_var03(CustomDevice):
    """Millimeter wave occupancy sensor."""

    signature = {
        #  endpoint=1, profile=260, device_type=81, device_version=1,
        #  input_clusters=[4, 5, 61184, 0], output_clusters=[25, 10])
        MODELS_INFO: [
            ("_TZE200_0u3bj3rc", "TS0601"),
            ("_TZE200_mx6u6l4y", "TS0601"),
            ("_TZE200_v6ossqfy", "TS0601"),
            ("_TZE204_qasjif9e", "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,
                    TuyaMCUCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            242: {
                # <SimpleDescriptor endpoint=242 profile=41440 device_type=97
                # input_clusters=[]
                # output_clusters=[33]
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.OCCUPANCY_SENSOR,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    MmwRadarManufCluster,
                    TuyaOccupancySensing,
                    TuyaOnOffNM,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        }
    }
jimmyeao commented 1 year ago

im going to close this off, as I've since abandoned ZHA in favour of Zigbee2mqtt