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] _TZE204_dtzziy1e TS0601 24GHz Millimeter Wave Tuya Zigbee Human Presence Sensor with switch (relay) #2457

Open
Nelevit opened this issue Jul 4, 2023 · 36 comments
Labels
custom quirk available A custom quirk is available to solve the issue, but it's not merged in the repo yet Tuya Request/PR regarding a Tuya device

Comments

@Nelevit
Copy link

Nelevit commented Jul 4, 2023

Problem description

When adding to ZHA only device exists, no entities.

Solution description

Device is added with all related entities (sensor, switch). If possible add sensitivity controls.

Screenshots/Video

Screenshots/Video

image
PXL_20230704_132845009 – копія
PXL_20230704_132751715 – копія
PXL_20230704_132816177 – копія
PXL_20230704_132827544 – копія
PXL_20230704_132838648 – копія

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": "0x0051",
      "input_clusters": [
        "0x0000",
        "0x0004",
        "0x0005",
        "0xef00"
      ],
      "output_clusters": [
        "0x000a",
        "0x0019"
      ]
    }
  },
  "manufacturer": "_TZE204_dtzziy1e",
  "model": "TS0601",
  "class": "zigpy.device.Device"
}

Diagnostic information

Diagnostic information
{
  "home_assistant": {
    "installation_type": "Home Assistant OS",
    "version": "2023.6.3",
    "dev": false,
    "hassio": true,
    "virtualenv": false,
    "python_version": "3.11.4",
    "docker": true,
    "arch": "x86_64",
    "timezone": "Europe/Kiev",
    "os_name": "Linux",
    "os_version": "6.1.34",
    "supervisor": "2023.06.4",
    "host_os": "Home Assistant OS 10.3",
    "docker_version": "23.0.6",
    "chassis": "vm",
    "run_as_root": true
  },
  "custom_components": {
    "scheduler": {
      "version": "v0.0.0",
      "requirements": []
    },
    "hacs": {
      "version": "1.32.1",
      "requirements": [
        "aiogithubapi>=22.10.1"
      ]
    }
  },
  "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"
    ],
    "requirements": [
      "bellows==0.35.5",
      "pyserial==3.5",
      "pyserial-asyncio==0.6",
      "zha-quirks==0.0.100",
      "zigpy-deconz==0.21.0",
      "zigpy==0.55.0",
      "zigpy-xbee==0.18.0",
      "zigpy-zigate==0.11.0",
      "zigpy-znp==0.11.1"
    ],
    "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": "_slzb-06._tcp.local.",
        "name": "slzb-06*"
      }
    ],
    "is_built_in": true
  },
  "data": {
    "ieee": "**REDACTED**",
    "nwk": 20130,
    "manufacturer": "_TZE204_dtzziy1e",
    "model": "TS0601",
    "name": "_TZE204_dtzziy1e TS0601",
    "quirk_applied": false,
    "quirk_class": "zigpy.device.Device",
    "manufacturer_code": 4098,
    "power_source": "Mains",
    "lqi": 120,
    "rssi": -70,
    "last_seen": "2023-07-04T17:06:49",
    "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": "0x0051",
          "input_clusters": [
            "0x0000",
            "0x0004",
            "0x0005",
            "0xef00"
          ],
          "output_clusters": [
            "0x000a",
            "0x0019"
          ]
        }
      },
      "manufacturer": "_TZE204_dtzziy1e",
      "model": "TS0601"
    },
    "active_coordinator": false,
    "entities": [],
    "neighbors": [],
    "routes": [],
    "endpoint_names": [
      {
        "name": "SMART_PLUG"
      }
    ],
    "user_given_name": null,
    "device_reg_id": "7eaa8369d968bad6058dfa13271833d1",
    "area_id": null,
    "cluster_details": {
      "1": {
        "device_type": {
          "name": "SMART_PLUG",
          "id": 81
        },
        "profile_id": 260,
        "in_clusters": {
          "0x0000": {
            "endpoint_attribute": "basic",
            "attributes": {
              "0x0001": {
                "attribute_name": "app_version",
                "value": 70
              },
              "0x0004": {
                "attribute_name": "manufacturer",
                "value": "_TZE204_dtzziy1e"
              },
              "0x0005": {
                "attribute_name": "model",
                "value": "TS0601"
              }
            },
            "unsupported_attributes": {}
          },
          "0x0004": {
            "endpoint_attribute": "groups",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0005": {
            "endpoint_attribute": "scenes",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0xef00": {
            "endpoint_attribute": null,
            "attributes": {},
            "unsupported_attributes": {}
          }
        },
        "out_clusters": {
          "0x0019": {
            "endpoint_attribute": "ota",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x000a": {
            "endpoint_attribute": "time",
            "attributes": {},
            "unsupported_attributes": {}
          }
        }
      }
    }
  }
}

Logs

Logs
Logger: zigpy.zcl
Source: runner.py:179
First occurred: 4:33:38 PM (126 occurrences)
Last logged: 4:54:38 PM

[0x4EA2:1:0xef00] Unknown cluster command 2 b'\x00G\t\x02\x00\x04\x00\x00\x00\x00'
[0x4EA2:1:0xef00] Unknown cluster command 2 b'\x00H\x01\x04\x00\x01\x01'
[0x4EA2:1:0xef00] Unknown cluster command 2 b'\x00I\t\x02\x00\x04\x00\x00\x01o'
[0x4EA2:1:0xef00] Unknown cluster command 2 b'\x00J\t\x02\x00\x04\x00\x00\x00\x00'
[0x4EA2:1:0xef00] Unknown cluster command 2 b'\x00K\x01\x04\x00\x01\x00'

Additional information

Successfully loaded a custom ts0601_motion.py quirk (with additional MODELS INFO in MmwRadarMotion(CustomDevice) class) but it exposes only one binary sensor and relay isn't clicking when detected/clear.

Also as you can see on the board photo it has a IR led. Why is it there? Would it be possible to use it?

@javicalle
Copy link
Collaborator

Can you attach the logs with the quirk applied? Logs from quirk would be more descriptive.
Also, with the quirk applied, catch the logs from the device powerup (when wires are connected). Tuya devices usually reports its status and give to us some DPs information.
Any link to vendor site or device capabilities?

@Nelevit
Copy link
Author

Nelevit commented Jul 5, 2023

@javicalle Thanks a lot for your reply!

Sorry it takes me so long to post those logs. I can't reproduce loading the quirk now :/

Zigpy Logs
Logger: zhaquirks
Source: custom_zha_quirks/ts0601_motion.py:6
First occurred: 3:06:31 PM (1 occurrences)
Last logged: 3:06:31 PM

Unexpected exception importing custom quirk 'ts0601_motion'
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/zhaquirks/__init__.py", line 454, in setup
    importer.find_module(modname).load_module(modname)
  File "<frozen importlib._bootstrap_external>", line 605, in _check_name_wrapper
  File "<frozen importlib._bootstrap_external>", line 1120, in load_module
  File "<frozen importlib._bootstrap_external>", line 945, in load_module
  File "<frozen importlib._bootstrap>", line 290, in _load_module_shim
  File "<frozen importlib._bootstrap>", line 721, in _load
  File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 940, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/config/custom_zha_quirks/ts0601_motion.py", line 6, in <module>
    from zigpy.profiles import zgp, zha
ImportError: cannot import name 'zgp' from 'zigpy.profiles' (/usr/local/lib/python3.11/site-packages/zigpy/profiles/__init__.py)

Would you please help to figure it out?

Here is a link to device page on AliExpress

Thanks in advance!
Nestor

@javicalle
Copy link
Collaborator

Take the ts0601_motion.py version from here:
https://github.com/zigpy/zha-device-handlers/raw/release/0.0.74/zhaquirks/tuya/ts0601_motion.py

Add your model, save changes and restart HA.

Check here to enable the debug logs:

@Nelevit
Copy link
Author

Nelevit commented Jul 5, 2023

@javicalle Thanks for your help :)

Its alive! :D

I've experimented with it and 2 classes were able to load:

  • MmwRadarMotion

Single entity - human presence sensor which works ok

MmwRadarMotion_NAS-PD07 Diagnostics
{
  "home_assistant": {
    "installation_type": "Home Assistant OS",
    "version": "2023.7.0",
    "dev": false,
    "hassio": true,
    "virtualenv": false,
    "python_version": "3.11.4",
    "docker": true,
    "arch": "x86_64",
    "timezone": "Europe/Kiev",
    "os_name": "Linux",
    "os_version": "6.1.34",
    "supervisor": "2023.07.1",
    "host_os": "Home Assistant OS 10.3",
    "docker_version": "23.0.6",
    "chassis": "vm",
    "run_as_root": true
  },
  "custom_components": {
    "scheduler": {
      "version": "v0.0.0",
      "requirements": []
    },
    "hacs": {
      "version": "1.32.1",
      "requirements": [
        "aiogithubapi>=22.10.1"
      ]
    }
  },
  "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"
    ],
    "requirements": [
      "bellows==0.35.8",
      "pyserial==3.5",
      "pyserial-asyncio==0.6",
      "zha-quirks==0.0.101",
      "zigpy-deconz==0.21.0",
      "zigpy==0.56.1",
      "zigpy-xbee==0.18.1",
      "zigpy-zigate==0.11.0",
      "zigpy-znp==0.11.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"
        ]
      }
    ],
    "zeroconf": [
      {
        "type": "_esphomelib._tcp.local.",
        "name": "tube*"
      },
      {
        "type": "_zigate-zigbee-gateway._tcp.local.",
        "name": "*zigate*"
      },
      {
        "type": "_zigstar_gw._tcp.local.",
        "name": "*zigstar*"
      },
      {
        "type": "_slzb-06._tcp.local.",
        "name": "slzb-06*"
      }
    ],
    "is_built_in": true
  },
  "data": {
    "ieee": "**REDACTED**",
    "nwk": 7788,
    "manufacturer": "_TZE204_dtzziy1e",
    "model": "TS0601",
    "name": "_TZE204_dtzziy1e TS0601",
    "quirk_applied": true,
    "quirk_class": "ts0601_customMotion.MmwRadarMotion",
    "manufacturer_code": 4098,
    "power_source": "Mains",
    "lqi": 192,
    "rssi": -52,
    "last_seen": "2023-07-05T23:14:19",
    "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": "0x0107",
          "input_clusters": [
            "0x0000",
            "0x0004",
            "0x0005",
            "0x000c",
            "0x0400",
            "0x0406",
            "0xef00"
          ],
          "output_clusters": [
            "0x000a",
            "0x0019"
          ]
        }
      },
      "manufacturer": "_TZE204_dtzziy1e",
      "model": "TS0601"
    },
    "active_coordinator": false,
    "entities": [
      {
        "entity_id": "binary_sensor.tze204_dtzziy1e_ts0601_occupancy",
        "name": "_TZE204_dtzziy1e TS0601"
      }
    ],
    "neighbors": [],
    "routes": [],
    "endpoint_names": [
      {
        "name": "OCCUPANCY_SENSOR"
      }
    ],
    "user_given_name": null,
    "device_reg_id": "7eaa8369d968bad6058dfa13271833d1",
    "area_id": null,
    "cluster_details": {
      "1": {
        "device_type": {
          "name": "OCCUPANCY_SENSOR",
          "id": 263
        },
        "profile_id": 260,
        "in_clusters": {
          "0x0000": {
            "endpoint_attribute": "basic",
            "attributes": {
              "0x0001": {
                "attribute_name": "app_version",
                "value": 70
              }
            },
            "unsupported_attributes": {}
          },
          "0x0004": {
            "endpoint_attribute": "groups",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0005": {
            "endpoint_attribute": "scenes",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0xef00": {
            "endpoint_attribute": "tuya_manufacturer",
            "attributes": {
              "0xef65": {
                "attribute_name": "dp_101",
                "value": 10
              },
              "0xef66": {
                "attribute_name": "dp_102",
                "value": 30
              },
              "0xef67": {
                "attribute_name": "dp_103",
                "value": ""
              },
              "0xef69": {
                "attribute_name": "dp_105",
                "value": 5
              },
              "0xef6a": {
                "attribute_name": "dp_106",
                "value": 60
              },
              "0xef6b": {
                "attribute_name": "dp_107",
                "value": 0
              },
              "0xef6c": {
                "attribute_name": "dp_108",
                "value": 0
              },
              "0xef02": {
                "attribute_name": "dp_2",
                "value": 7
              },
              "0xef03": {
                "attribute_name": "dp_3",
                "value": 60
              },
              "0xef04": {
                "attribute_name": "dp_4",
                "value": 600
              },
              "0xef06": {
                "attribute_name": "dp_6",
                "value": 1
              },
              "0xef00": {
                "attribute_name": "mcu_version",
                "value": "1.0.0"
              }
            },
            "unsupported_attributes": {}
          },
          "0x0406": {
            "endpoint_attribute": "occupancy",
            "attributes": {
              "0x0000": {
                "attribute_name": "occupancy",
                "value": 0
              }
            },
            "unsupported_attributes": {
              "0x0000": {
                "attribute_name": "occupancy"
              }
            }
          },
          "0x000c": {
            "endpoint_attribute": "analog_input",
            "attributes": {
              "0x0055": {
                "attribute_name": "present_value",
                "value": 0.0
              }
            },
            "unsupported_attributes": {}
          },
          "0x0400": {
            "endpoint_attribute": "illuminance",
            "attributes": {
              "0x0000": {
                "attribute_name": "measured_value",
                "value": 36429.600525844915
              }
            },
            "unsupported_attributes": {
              "0x0000": {
                "attribute_name": "measured_value"
              }
            }
          }
        },
        "out_clusters": {
          "0x000a": {
            "endpoint_attribute": "time",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0019": {
            "endpoint_attribute": "ota",
            "attributes": {},
            "unsupported_attributes": {}
          }
        }
      }
    }
  }
}

MmwRadarMotion_NAS-PD07.txt

  • NeoMotion

image

NeoMotion_NAS-PD07 Diagnostics
{
  "home_assistant": {
    "installation_type": "Home Assistant OS",
    "version": "2023.7.0",
    "dev": false,
    "hassio": true,
    "virtualenv": false,
    "python_version": "3.11.4",
    "docker": true,
    "arch": "x86_64",
    "timezone": "Europe/Kiev",
    "os_name": "Linux",
    "os_version": "6.1.34",
    "supervisor": "2023.07.1",
    "host_os": "Home Assistant OS 10.3",
    "docker_version": "23.0.6",
    "chassis": "vm",
    "run_as_root": true
  },
  "custom_components": {
    "scheduler": {
      "version": "v0.0.0",
      "requirements": []
    },
    "hacs": {
      "version": "1.32.1",
      "requirements": [
        "aiogithubapi>=22.10.1"
      ]
    }
  },
  "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"
    ],
    "requirements": [
      "bellows==0.35.8",
      "pyserial==3.5",
      "pyserial-asyncio==0.6",
      "zha-quirks==0.0.101",
      "zigpy-deconz==0.21.0",
      "zigpy==0.56.1",
      "zigpy-xbee==0.18.1",
      "zigpy-zigate==0.11.0",
      "zigpy-znp==0.11.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"
        ]
      }
    ],
    "zeroconf": [
      {
        "type": "_esphomelib._tcp.local.",
        "name": "tube*"
      },
      {
        "type": "_zigate-zigbee-gateway._tcp.local.",
        "name": "*zigate*"
      },
      {
        "type": "_zigstar_gw._tcp.local.",
        "name": "*zigstar*"
      },
      {
        "type": "_slzb-06._tcp.local.",
        "name": "slzb-06*"
      }
    ],
    "is_built_in": true
  },
  "data": {
    "ieee": "**REDACTED**",
    "nwk": 2112,
    "manufacturer": "_TZE204_dtzziy1e",
    "model": "TS0601",
    "name": "_TZE204_dtzziy1e TS0601",
    "quirk_applied": true,
    "quirk_class": "ts0601_customMotion.NeoMotion",
    "manufacturer_code": 4098,
    "power_source": "Mains",
    "lqi": 192,
    "rssi": -52,
    "last_seen": "2023-07-05T23:38:30",
    "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": "0x0107",
          "input_clusters": [
            "0x0000",
            "0x0004",
            "0x0005",
            "0x0402",
            "0x0405",
            "0x0406",
            "0xef00"
          ],
          "output_clusters": [
            "0x000a",
            "0x0019"
          ]
        }
      },
      "manufacturer": "_TZE204_dtzziy1e",
      "model": "TS0601"
    },
    "active_coordinator": false,
    "entities": [
      {
        "entity_id": "binary_sensor.tze204_dtzziy1e_ts0601_occupancy",
        "name": "_TZE204_dtzziy1e TS0601"
      },
      {
        "entity_id": "sensor.tze204_dtzziy1e_ts0601_temperature",
        "name": "_TZE204_dtzziy1e TS0601"
      },
      {
        "entity_id": "sensor.tze204_dtzziy1e_ts0601_humidity",
        "name": "_TZE204_dtzziy1e TS0601"
      }
    ],
    "neighbors": [],
    "routes": [],
    "endpoint_names": [
      {
        "name": "OCCUPANCY_SENSOR"
      }
    ],
    "user_given_name": null,
    "device_reg_id": "7eaa8369d968bad6058dfa13271833d1",
    "area_id": null,
    "cluster_details": {
      "1": {
        "device_type": {
          "name": "OCCUPANCY_SENSOR",
          "id": 263
        },
        "profile_id": 260,
        "in_clusters": {
          "0x0000": {
            "endpoint_attribute": "basic",
            "attributes": {
              "0x0001": {
                "attribute_name": "app_version",
                "value": 70
              },
              "0x0004": {
                "attribute_name": "manufacturer",
                "value": "_TZE204_dtzziy1e"
              },
              "0x0005": {
                "attribute_name": "model",
                "value": "TS0601"
              }
            },
            "unsupported_attributes": {}
          },
          "0x0004": {
            "endpoint_attribute": "groups",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0005": {
            "endpoint_attribute": "scenes",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0xef00": {
            "endpoint_attribute": "tuya_manufacturer",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0406": {
            "endpoint_attribute": "occupancy",
            "attributes": {
              "0x0000": {
                "attribute_name": "occupancy",
                "value": 10
              }
            },
            "unsupported_attributes": {}
          },
          "0x0402": {
            "endpoint_attribute": "temperature",
            "attributes": {
              "0x0000": {
                "attribute_name": "measured_value",
                "value": 43940
              }
            },
            "unsupported_attributes": {}
          },
          "0x0405": {
            "endpoint_attribute": "humidity",
            "attributes": {
              "0x0000": {
                "attribute_name": "measured_value",
                "value": 500
              }
            },
            "unsupported_attributes": {}
          }
        },
        "out_clusters": {
          "0x000a": {
            "endpoint_attribute": "time",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0019": {
            "endpoint_attribute": "ota",
            "attributes": {},
            "unsupported_attributes": {}
          }
        }
      }
    }
  }
}

NeoMotion_NAS-PD07.txt

txt files files contain logs while resetting.

Hope it helps,
Nestor

@TheJulianJES TheJulianJES added Tuya Request/PR regarding a Tuya device custom quirk available A custom quirk is available to solve the issue, but it's not merged in the repo yet labels Jul 30, 2023
@Nelevit
Copy link
Author

Nelevit commented Aug 2, 2023

Hi, @TheJulianJES
I've noticed you tagged a custom quirk but can't find it 😕
Could you please help? Would be happy to test it out and report back.
Thanks in advance,
Nestor

@JeroenVanOort
Copy link
Contributor

I think the label just concerns adding _TZE204_dtzziy1e to the existing MmwRadarMotion cluster. That's what I did and it does work for the basic function of detecting occupancy and illuminance, but I can't control the relay or the parameters that should make the relay switch.

Does anybody know where to get started on this? There is some information available from another project: Koenkk/zigbee-herdsman-converters#5930

@evgenln
Copy link
Contributor

evgenln commented Sep 13, 2023

@JeroenVanOort I did quirk for it's brother _TZE204_clrdrnya, it's same options device. But it probably will not really usable for you as I running zha as component and exposed all options/target distance sensor in it's bundles. Anyway it contains all datapoints so at least you will be able to change values of options via Mange ZigBee device.

@evgenln
Copy link
Contributor

evgenln commented Sep 13, 2023

ts0601_presence.zip

But add your signature 1st

@JeroenVanOort
Copy link
Contributor

Thank you very much!

Have you been able to get the relay working? For me, the relay never switches, neither automatic nor manual. Maybe my unit is just broken, but I don't know.

@evgenln
Copy link
Contributor

evgenln commented Sep 15, 2023

Yes @JeroenVanOort , it is working.

I have the full UI due to custom changes I did in ZHA, with default ZHA you will not see controls
but you can try to do it manually from the device page via the Manage Zigbee device.

Open Manage Zigbee device and select MmwRadarV3ManufCluster
Select breaker_mode attribute and write 0 to it (it will set the device to Standart mode with the ability to manipulate relay)
then select the breaker_status attribute and write 0 to set it off or 1 to set it on (polarity depends on one more attribute breaker_polarity but I am not sure if it is implemented in your device)

@RiRomain
Copy link

RiRomain commented Jan 2, 2024

I tried with the attached zip file by replacing the device info, but I only have occupancy showed, does someone know how to correct it and have the .py file that fit the _TZE204_dtzziy1e ?

ts0601_presence.py.txt

@RiRomain
Copy link

RiRomain commented Jan 4, 2024

Working fine with the following:

import math
from typing import Dict

from zigpy.profiles import zgp, zha
from zigpy.quirks import CustomDevice
import zigpy.types as t
from zigpy.zcl.clusters.general import (
    AnalogInput,
    AnalogOutput,
    Basic,
    GreenPowerProxy,
    Groups,
    Ota,
    Scenes,
    Time,
)
from zigpy.zcl.clusters.measurement import IlluminanceMeasurement, OccupancySensing

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

ZONE_TYPE = 0x0001


class TuyaMmwRadarSelfTest(t.enum8):
    """Mmw radar self test values."""

    TESTING = 0
    TEST_SUCCESS = 1
    TEST_FAILURE = 2
    OTHER = 3
    COMM_FAULT = 4
    RADAR_FAULT = 5


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


class TuyaAnalogInput(AnalogInput, TuyaLocalCluster):
    """Tuya local AnalogInput cluster."""


class TuyaIlluminanceMeasurement(IlluminanceMeasurement, TuyaLocalCluster):
    """Tuya local IlluminanceMeasurement cluster."""


class TuyaMmwRadarSensitivity(TuyaAttributesCluster, AnalogOutput):
    """AnalogOutput cluster for sensitivity."""

    def __init__(self, *args, **kwargs):
        """Init."""
        super().__init__(*args, **kwargs)
        self._update_attribute(self.attributes_by_name["description"].id, "Sensitivity")
        self._update_attribute(self.attributes_by_name["min_present_value"].id, 1)
        self._update_attribute(self.attributes_by_name["max_present_value"].id, 9)
        self._update_attribute(self.attributes_by_name["resolution"].id, 1)


class TuyaMmwRadarMinRange(TuyaAttributesCluster, AnalogOutput):
    """AnalogOutput cluster for min range."""

    def __init__(self, *args, **kwargs):
        """Init."""
        super().__init__(*args, **kwargs)
        self._update_attribute(self.attributes_by_name["description"].id, "Min range")
        self._update_attribute(self.attributes_by_name["min_present_value"].id, 0)
        self._update_attribute(self.attributes_by_name["max_present_value"].id, 950)
        self._update_attribute(self.attributes_by_name["resolution"].id, 10)
        self._update_attribute(
            self.attributes_by_name["engineering_units"].id, 118
        ) # 31: meters


class TuyaMmwRadarMaxRange(TuyaAttributesCluster, AnalogOutput):
    """AnalogOutput cluster for max range."""

    def __init__(self, *args, **kwargs):
        """Init."""
        super().__init__(*args, **kwargs)
        self._update_attribute(self.attributes_by_name["description"].id, "Max range")
        self._update_attribute(self.attributes_by_name["min_present_value"].id, 10)
        self._update_attribute(self.attributes_by_name["max_present_value"].id, 950)
        self._update_attribute(self.attributes_by_name["resolution"].id, 10)
        self._update_attribute(
            self.attributes_by_name["engineering_units"].id, 118
        ) # 31: meters


class TuyaMmwRadarDetectionDelay(TuyaAttributesCluster, AnalogOutput):
    """AnalogOutput cluster for detection delay."""

    def __init__(self, *args, **kwargs):
        """Init."""
        super().__init__(*args, **kwargs)
        self._update_attribute(
            self.attributes_by_name["description"].id, "Detection delay"
        )
        self._update_attribute(self.attributes_by_name["min_present_value"].id, 000)
        self._update_attribute(self.attributes_by_name["max_present_value"].id, 20000)
        self._update_attribute(self.attributes_by_name["resolution"].id, 100)
        self._update_attribute(
            self.attributes_by_name["engineering_units"].id, 159
        ) # 73: seconds


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, 2000)
        self._update_attribute(self.attributes_by_name["max_present_value"].id, 200000)
        self._update_attribute(self.attributes_by_name["resolution"].id, 1000)
        self._update_attribute(
            self.attributes_by_name["engineering_units"].id, 159
        ) # 73: seconds


class TuyaMmwRadarTargetDistance(TuyaAttributesCluster, AnalogInput):
    """AnalogInput cluster for target distance."""

    def __init__(self, *args, **kwargs):
        """Init."""
        super().__init__(*args, **kwargs)
        self._update_attribute(
            self.attributes_by_name["description"].id, "Target distance"
        )
        self._update_attribute(
            self.attributes_by_name["engineering_units"].id, 31
        ) # 31: meters


class TuyaMmwRadarClusterBase(NoManufacturerCluster, TuyaMCUCluster):
    """Mmw radar cluster, base class."""

    attributes = TuyaMCUCluster.attributes.copy()
    attributes.update(
        {
            # ramdom attribute IDs
            0xEF01: ("occupancy", t.uint32_t, True),
            0xEF02: ("sensitivity", t.uint32_t, True),
            0xEF03: ("min_range", t.uint32_t, True),
            0xEF04: ("max_range", t.uint32_t, True),
            0xEF06: ("self_test", TuyaMmwRadarSelfTest, True),
            0xEF09: ("target_distance", t.uint32_t, True),
            0xEF65: ("detection_delay", t.uint32_t, True),
            0xEF66: ("fading_time", t.uint32_t, True),
            0xEF67: ("cli", t.CharacterString, True),
            0xEF68: ("illuminance", t.uint32_t, True),
        }
    )


class TuyaMmwRadarClusterVariant1(TuyaMmwRadarClusterBase):
    """Mmw radar cluster, variant 1."""

    dp_to_attribute: Dict[int, DPToAttributeMapping] = {
        1: DPToAttributeMapping(
            TuyaOccupancySensing.ep_attribute,
            "occupancy",
        ),
        2: DPToAttributeMapping(
            TuyaMmwRadarSensitivity.ep_attribute,
            "present_value",
        ),
        3: DPToAttributeMapping(
            TuyaMmwRadarMinRange.ep_attribute,
            "present_value",
            endpoint_id=2,
        ),
        4: DPToAttributeMapping(
            TuyaMmwRadarMaxRange.ep_attribute,
            "present_value",
            endpoint_id=3,
        ),
        6: DPToAttributeMapping(
            TuyaMCUCluster.ep_attribute,
            "self_test",
        ),
        9: DPToAttributeMapping(
            TuyaMmwRadarTargetDistance.ep_attribute,
            "present_value",
            lambda x: x / 100,
        ),
        101: DPToAttributeMapping(
            TuyaMmwRadarDetectionDelay.ep_attribute,
            "present_value",
            converter=lambda x: x * 100,
            dp_converter=lambda x: x // 100,
            endpoint_id=4,
        ),
        102: DPToAttributeMapping(
            TuyaMmwRadarFadingTime.ep_attribute,
            "present_value",
            converter=lambda x: x * 100,
            dp_converter=lambda x: x // 100,
            endpoint_id=5,
        ),
        103: DPToAttributeMapping(
            TuyaMCUCluster.ep_attribute,
            "cli",
        ),
        104: DPToAttributeMapping(
            TuyaIlluminanceMeasurement.ep_attribute,
            "measured_value",
            converter=lambda x: int(math.log10(x) * 10000 + 1) if x > 0 else int(0),
        ),
    }

    data_point_handlers = {
        1: "_dp_2_attr_update",
        2: "_dp_2_attr_update",
        3: "_dp_2_attr_update",
        4: "_dp_2_attr_update",
        6: "_dp_2_attr_update",
        9: "_dp_2_attr_update",
        101: "_dp_2_attr_update",
        102: "_dp_2_attr_update",
        103: "_dp_2_attr_update",
        104: "_dp_2_attr_update",
    }


class TuyaMmwRadarOccupancyVariant1(CustomDevice):
    """Millimeter wave occupancy sensor, variant 1."""

    signature = {
        # endpoint=1, profile=260, device_type=81, device_version=1,
        # input_clusters=[0, 4, 5, 61184], output_clusters=[25, 10]
        MODELS_INFO: [
     ("_TZE204_dtzziy1e", "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,
                    TuyaNewManufCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.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,
                    TuyaMmwRadarClusterVariant1,
                    TuyaIlluminanceMeasurement,
                    TuyaOccupancySensing,
                    TuyaMmwRadarTargetDistance,
                    TuyaMmwRadarSensitivity,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    TuyaMmwRadarMinRange,
                ],
                OUTPUT_CLUSTERS: [],
            },
            3: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    TuyaMmwRadarMaxRange,
                ],
                OUTPUT_CLUSTERS: [],
            },
            4: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    TuyaMmwRadarDetectionDelay,
                ],
                OUTPUT_CLUSTERS: [],
            },
            5: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    TuyaMmwRadarFadingTime,
                ],
                OUTPUT_CLUSTERS: [],
            },
        }
    }


class TuyaMmwRadarOccupancyVariant1GPP(CustomDevice):
    """Millimeter wave occupancy sensor, variant 1 with GPP."""

    signature = {
        # endpoint=1, profile=260, device_type=81, device_version=1,
        # input_clusters=[0, 4, 5, 61184], output_clusters=[25, 10])
        MODELS_INFO: [
     ("_TZE204_dtzziy1e", "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,
                    TuyaNewManufCluster.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: zgp.PROFILE_ID,
                DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
                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,
                    TuyaMmwRadarClusterVariant1,
                    TuyaIlluminanceMeasurement,
                    TuyaOccupancySensing,
                    TuyaMmwRadarTargetDistance,
                    TuyaMmwRadarSensitivity,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    TuyaMmwRadarMinRange,
                ],
                OUTPUT_CLUSTERS: [],
            },
            3: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    TuyaMmwRadarMaxRange,
                ],
                OUTPUT_CLUSTERS: [],
            },
            4: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    TuyaMmwRadarDetectionDelay,
                ],
                OUTPUT_CLUSTERS: [],
            },
            5: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    TuyaMmwRadarFadingTime,
                ],
                OUTPUT_CLUSTERS: [],
            },
            242: {
                PROFILE_ID: zgp.PROFILE_ID,
                DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        }
    }


class TuyaMmwRadarClusterVariant2(TuyaMmwRadarClusterBase):
    """Tuya MMW radar cluster, variant 2."""

    dp_to_attribute: Dict[int, DPToAttributeMapping] = {
        103: DPToAttributeMapping(
            TuyaMCUCluster.ep_attribute,
            "cli",
        ),
        104: DPToAttributeMapping(
            TuyaIlluminanceMeasurement.ep_attribute,
            "measured_value",
            converter=lambda x: int(math.log10(x) * 10000 + 1) if x > 0 else int(0),
        ),
        105: DPToAttributeMapping(
            TuyaOccupancySensing.ep_attribute,
            "occupancy",
        ),
        106: DPToAttributeMapping(
            TuyaMmwRadarSensitivity.ep_attribute,
            "present_value",
        ),
        107: DPToAttributeMapping(
            TuyaMmwRadarMaxRange.ep_attribute,
            "present_value",
            endpoint_id=3,
        ),
        108: DPToAttributeMapping(
            TuyaMmwRadarMinRange.ep_attribute,
            "present_value",
            endpoint_id=2,
        ),
        109: DPToAttributeMapping(
            TuyaMmwRadarTargetDistance.ep_attribute,
            "present_value",
        ),
        110: DPToAttributeMapping(
            TuyaMmwRadarFadingTime.ep_attribute,
            "present_value",
            converter=lambda x: x * 100,
            dp_converter=lambda x: x // 100,
            endpoint_id=5,
        ),
        111: DPToAttributeMapping(
            TuyaMmwRadarDetectionDelay.ep_attribute,
            "present_value",
            converter=lambda x: x * 100,
            dp_converter=lambda x: x // 100,
            endpoint_id=4,
        ),
    }

    data_point_handlers = {
        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",
    }


class TuyaMmwRadarOccupancyVariant2(CustomDevice):
    """Millimeter wave occupancy sensor, variant 2."""

    signature = {
        # endpoint=1, profile=260, device_type=81, device_version=1,
        # input_clusters=[0, 4, 5, 61184], output_clusters=[25, 10])
        MODELS_INFO: [
                 ("_TZE204_dtzziy1e", "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,
                    TuyaNewManufCluster.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: zgp.PROFILE_ID,
                DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
                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,
                    TuyaMmwRadarClusterVariant2,
                    TuyaIlluminanceMeasurement,
                    TuyaOccupancySensing,
                    TuyaMmwRadarTargetDistance,
                    TuyaMmwRadarSensitivity,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    TuyaMmwRadarMinRange,
                ],
                OUTPUT_CLUSTERS: [],
            },
            3: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    TuyaMmwRadarMaxRange,
                ],
                OUTPUT_CLUSTERS: [],
            },
            4: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    TuyaMmwRadarDetectionDelay,
                ],
                OUTPUT_CLUSTERS: [],
            },
            5: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    TuyaMmwRadarFadingTime,
                ],
                OUTPUT_CLUSTERS: [],
            },
            242: {
                PROFILE_ID: zgp.PROFILE_ID,
                DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        }
    }
    ```

@bouboun59
Copy link

bouboun59 commented Jan 9, 2024

Thanks a lot, it's work fine with my TS060 _TZE204_clrdrnya, but I don't understand why i don't see the radar target distance in my sensors
image
so i see in the advanced parameters
image

could you explain why ? And you, you can see the radar target distance

@tommetje
Copy link

I tried with the attached zip file by replacing the device info, but I only have occupancy showed, does someone know how to correct it and have the .py file that fit the _TZE204_dtzziy1e ?

ts0601_presence.py.txt

@RiRomain Do you see more than Illuminance and Occupancy in ZHA?

@RiRomain
Copy link

RiRomain commented Jan 16, 2024

I only see illuminance and occupancy, but didn't think that the sensor can handle anything more (appart from the settings).
And I didn't use the zip, but the code in the comment.
Screenshot_20240116_220607_Home Assistant

@tommetje
Copy link

Wow nice, GUI controls woohoo! :)
I tried it and it works!

My detectors are picking up movements of neighbors so for me the entry controls are essential. Currently, Entry Sensitivity and Entry Distance Indentation are sadly missing in the quirk update.
I currently have no time nor knowledge (yet :) ) to adjust your quirk, so I will revert back and keep an eye out for possible updates in this thread.

Thanks for sharing your quirk @RiRomain !

@mariovw
Copy link

mariovw commented Feb 21, 2024

Hi @evgenln ,

I have _TZE204_clrdrnya. I load the quirk ts0601_presence.py.txt
but I only get the presence and iluminance but not the Controls to adjust the parametres.

Do you know what could be the issue?

Many thanks!

image

@tommetje
Copy link

Sometimes it helps to reload the ZHA integration, just in case you have not tried this.
You can also try to remove the devices and add them again. I had the same problem and this fixed things for me.
image

@mariovw
Copy link

mariovw commented Feb 21, 2024

thanks @tommetje for your quick answer.

Unfortunally I followed your instructions several times with no results. Any other idea?

Many thanks!

PD: just to say I have the last firmware version

@tommetje
Copy link

thanks @tommetje for your quick answer.

Unfortunally I followed your instructions several times with no results. Any other idea?

Many thanks!

I updated the existing quirk, after this I did not see the changes.

From what I remember, I also tried removing removing the affected devices + removing the quirk folder + HA restart + ZHA reload. After this I added the folder of the updated quirk and gave it a different name, again HA restart + adding devices again + ZHA reload (if needed) .

Not sure if all the steps are needed but this is what I tried. Eventually I got the updated quirk working.

@mariovw
Copy link

mariovw commented Feb 22, 2024

thks @tommetje,

I'll try to play more the weekend!

Best,

@matsjrosenberg
Copy link

Hello, I have a _TZE204_sbyx0lm6 (the 5.8G version as opposed to the 2.4G) and have tried all quirks above, changing the device specs in the code, and only randomly gotten only the illuminance and presence to work. I am not a coder so can't unfortunately contribute to this, but would really appreciate if somebody could continue developing this quirk further. Many thanks!

@frawau
Copy link

frawau commented Mar 16, 2024

I have a _TZE204_clrdrnya device and with @RiRomain python script, I get the occupancy to work fine ... Yeah! Thank you.

But

Luminance is not working, and neither Ota nor Time are working. Then there is the the question of the relay.

According to @LuisAlbertoFB in this thead it is possible to get it all working. I tried a few things, but so far no luck... Anyone has a clue on how to port this?

@OakfieldDrive
Copy link

Hi all,
I got it to work on _TZE204_clrdrnya using the quirk shared in the zip file above. however, the illuminance figures are not within the expected range. e.g, I am currently in a room, in a cloudy day; would expect to have something between 15 to 30 lx but instead, it shows 1,522lx. Anyone else has the same problem?

@macf0x
Copy link

macf0x commented May 5, 2024

Was there any luck getting the relay to work?

@cHeeSaW
Copy link

cHeeSaW commented May 21, 2024

I got it working for _TZE204_dtzziy1e with the code from @RiRomain's comment. The illuminance value does not show up at first, i have to restart HA every time i add a new device of this type, then it shows up.
Anyone working on the missing values and relay?

@macf0x
Copy link

macf0x commented Jun 30, 2024

Same. I get following controls and Occupancy Sensor. No lux.

Detection Delay
Fading Time
Max Range
Min Range
Sensitivity

Firmware Update is also visible

Relay isn't exposed and doesn't align to Occupancy. That all I really need.

@nnae06
Copy link

nnae06 commented Aug 13, 2024

I got everything working except the relay. In my case, I don't use the relay function.

Can this be added to ZHA. This ZHA quirks prevent me from updating to 2024.08 ->. Many of my automations at home use these devices to function.

"""Tuya mmw radar occupancy sensor."""

import math
from typing import Dict

from zigpy.profiles import zgp, zha
from zigpy.quirks import CustomDevice
import zigpy.types as t
from zigpy.zcl.clusters.general import (
AnalogInput,
AnalogOutput,
Basic,
GreenPowerProxy,
Groups,
Ota,
Scenes,
Time,
)
from zigpy.zcl.clusters.measurement import IlluminanceMeasurement, OccupancySensing

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

ZONE_TYPE = 0x0001

class TuyaMmwRadarSelfTest(t.enum8):
"""Mmw radar self test values."""

TESTING = 0
TEST_SUCCESS = 1
TEST_FAILURE = 2
OTHER = 3
COMM_FAULT = 4
RADAR_FAULT = 5

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

class TuyaAnalogInput(AnalogInput, TuyaLocalCluster):
"""Tuya local AnalogInput cluster."""

class TuyaIlluminanceMeasurement(IlluminanceMeasurement, TuyaLocalCluster):
"""Tuya local IlluminanceMeasurement cluster."""

class TuyaMmwRadarSensitivity(TuyaAttributesCluster, AnalogOutput):
"""AnalogOutput cluster for sensitivity."""

def __init__(self, *args, **kwargs):
    """Init."""
    super().__init__(*args, **kwargs)
    self._update_attribute(self.attributes_by_name["description"].id, "Sensitivity")
    self._update_attribute(self.attributes_by_name["min_present_value"].id, 1)
    self._update_attribute(self.attributes_by_name["max_present_value"].id, 9)
    self._update_attribute(self.attributes_by_name["resolution"].id, 1)

class TuyaMmwRadarMinRange(TuyaAttributesCluster, AnalogOutput):
"""AnalogOutput cluster for min range."""

def __init__(self, *args, **kwargs):
    """Init."""
    super().__init__(*args, **kwargs)
    self._update_attribute(self.attributes_by_name["description"].id, "Min range")
    self._update_attribute(self.attributes_by_name["min_present_value"].id, 0)
    self._update_attribute(self.attributes_by_name["max_present_value"].id, 950)
    self._update_attribute(self.attributes_by_name["resolution"].id, 10)
    self._update_attribute(
        self.attributes_by_name["engineering_units"].id, 118
    )  # 31: meters

class TuyaMmwRadarMaxRange(TuyaAttributesCluster, AnalogOutput):
"""AnalogOutput cluster for max range."""

def __init__(self, *args, **kwargs):
    """Init."""
    super().__init__(*args, **kwargs)
    self._update_attribute(self.attributes_by_name["description"].id, "Max range")
    self._update_attribute(self.attributes_by_name["min_present_value"].id, 10)
    self._update_attribute(self.attributes_by_name["max_present_value"].id, 950)
    self._update_attribute(self.attributes_by_name["resolution"].id, 10)
    self._update_attribute(
        self.attributes_by_name["engineering_units"].id, 118
    )  # 31: meters

class TuyaMmwRadarDetectionDelay(TuyaAttributesCluster, AnalogOutput):
"""AnalogOutput cluster for detection delay."""

def __init__(self, *args, **kwargs):
    """Init."""
    super().__init__(*args, **kwargs)
    self._update_attribute(
        self.attributes_by_name["description"].id, "Detection delay"
    )
    self._update_attribute(self.attributes_by_name["min_present_value"].id, 000)
    self._update_attribute(self.attributes_by_name["max_present_value"].id, 20000)
    self._update_attribute(self.attributes_by_name["resolution"].id, 100)
    self._update_attribute(
        self.attributes_by_name["engineering_units"].id, 159
    )  # 73: seconds

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, 2000)
    self._update_attribute(self.attributes_by_name["max_present_value"].id, 200000)
    self._update_attribute(self.attributes_by_name["resolution"].id, 1000)
    self._update_attribute(
        self.attributes_by_name["engineering_units"].id, 159
    )  # 73: seconds

class TuyaMmwRadarTargetDistance(TuyaAttributesCluster, AnalogInput):
"""AnalogInput cluster for target distance."""

def __init__(self, *args, **kwargs):
    """Init."""
    super().__init__(*args, **kwargs)
    self._update_attribute(
        self.attributes_by_name["description"].id, "Target distance"
    )
    self._update_attribute(
        self.attributes_by_name["engineering_units"].id, 31
    )  # 31: meters

class TuyaMmwRadarClusterBase(NoManufacturerCluster, TuyaMCUCluster):
"""Mmw radar cluster, base class."""

attributes = TuyaMCUCluster.attributes.copy()
attributes.update(
    {
        # ramdom attribute IDs
        0xEF01: ("occupancy", t.uint32_t, True),
        0xEF02: ("sensitivity", t.uint32_t, True),
        0xEF03: ("min_range", t.uint32_t, True),
        0xEF04: ("max_range", t.uint32_t, True),
        0xEF06: ("self_test", TuyaMmwRadarSelfTest, True),
        0xEF09: ("target_distance", t.uint32_t, True),
        0xEF65: ("detection_delay", t.uint32_t, True),
        0xEF66: ("fading_time", t.uint32_t, True),
        0xEF67: ("cli", t.CharacterString, True),
        0xEF68: ("illuminance", t.uint32_t, True),
    }
)

class TuyaMmwRadarClusterVariant1(TuyaMmwRadarClusterBase):
"""Mmw radar cluster, variant 1."""

dp_to_attribute: Dict[int, DPToAttributeMapping] = {
    1: DPToAttributeMapping(
        TuyaOccupancySensing.ep_attribute,
        "occupancy",
    ),
    2: DPToAttributeMapping(
        TuyaMmwRadarSensitivity.ep_attribute,
        "present_value",
    ),
    3: DPToAttributeMapping(
        TuyaMmwRadarMinRange.ep_attribute,
        "present_value",
        endpoint_id=2,
    ),
    4: DPToAttributeMapping(
        TuyaMmwRadarMaxRange.ep_attribute,
        "present_value",
        endpoint_id=3,
    ),
    6: DPToAttributeMapping(
        TuyaMCUCluster.ep_attribute,
        "self_test",
    ),
    9: DPToAttributeMapping(
        TuyaMmwRadarTargetDistance.ep_attribute,
        "present_value",
        lambda x: x / 100,
    ),
    101: DPToAttributeMapping(
        TuyaMmwRadarDetectionDelay.ep_attribute,
        "present_value",
        converter=lambda x: x * 100,
        dp_converter=lambda x: x // 100,
        endpoint_id=4,
    ),
    102: DPToAttributeMapping(
        TuyaMmwRadarFadingTime.ep_attribute,
        "present_value",
        converter=lambda x: x * 100,
        dp_converter=lambda x: x // 100,
        endpoint_id=5,
    ),
    103: DPToAttributeMapping(
        TuyaMCUCluster.ep_attribute,
        "cli",
    ),
    104: DPToAttributeMapping(
        TuyaIlluminanceMeasurement.ep_attribute,
        "measured_value",
        converter=lambda x: int(math.log10(x) * 10000 + 1) if x > 0 else int(0),
    ),
}

data_point_handlers = {
    1: "_dp_2_attr_update",
    2: "_dp_2_attr_update",
    3: "_dp_2_attr_update",
    4: "_dp_2_attr_update",
    6: "_dp_2_attr_update",
    9: "_dp_2_attr_update",
    101: "_dp_2_attr_update",
    102: "_dp_2_attr_update",
    103: "_dp_2_attr_update",
    104: "_dp_2_attr_update",
}

class TuyaMmwRadarOccupancyVariant1(CustomDevice):
"""Millimeter wave occupancy sensor, variant 1."""

signature = {
    #  endpoint=1, profile=260, device_type=81, device_version=1,
    #  input_clusters=[0, 4, 5, 61184], output_clusters=[25, 10]
    MODELS_INFO: [
        ("_TZE200_ar0slwnd", "TS0601"),
        ("_TZE200_sfiy5tfs", "TS0601"),
        ("_TZE200_mrf6vtua", "TS0601"),
        ("_TZE200_ztc6ggyl", "TS0601"),
        ("_TZE204_ztc6ggyl", "TS0601"),
        ("_TZE200_wukb7rhc", "TS0601"),
        ("_TZE204_qasjif9e", "TS0601"),
        ("_TZE204_dtzziy1e", "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,
                TuyaNewManufCluster.cluster_id,
            ],
            OUTPUT_CLUSTERS: [Time.cluster_id, Ota.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,
                TuyaMmwRadarClusterVariant1,
                TuyaIlluminanceMeasurement,
                TuyaOccupancySensing,
                TuyaMmwRadarTargetDistance,
                TuyaMmwRadarSensitivity,
            ],
            OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
        },
        2: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarMinRange,
            ],
            OUTPUT_CLUSTERS: [],
        },
        3: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarMaxRange,
            ],
            OUTPUT_CLUSTERS: [],
        },
        4: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarDetectionDelay,
            ],
            OUTPUT_CLUSTERS: [],
        },
        5: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarFadingTime,
            ],
            OUTPUT_CLUSTERS: [],
        },
    }
}

class TuyaMmwRadarOccupancyVariant1GPP(CustomDevice):
"""Millimeter wave occupancy sensor, variant 1 with GPP."""

signature = {
    #  endpoint=1, profile=260, device_type=81, device_version=1,
    #  input_clusters=[0, 4, 5, 61184], output_clusters=[25, 10])
    MODELS_INFO: [
        ("_TZE200_ar0slwnd", "TS0601"),
        ("_TZE200_sfiy5tfs", "TS0601"),
        ("_TZE200_mrf6vtua", "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,
                TuyaNewManufCluster.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: zgp.PROFILE_ID,
            DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
            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,
                TuyaMmwRadarClusterVariant1,
                TuyaIlluminanceMeasurement,
                TuyaOccupancySensing,
                TuyaMmwRadarTargetDistance,
                TuyaMmwRadarSensitivity,
            ],
            OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
        },
        2: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarMinRange,
            ],
            OUTPUT_CLUSTERS: [],
        },
        3: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarMaxRange,
            ],
            OUTPUT_CLUSTERS: [],
        },
        4: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarDetectionDelay,
            ],
            OUTPUT_CLUSTERS: [],
        },
        5: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarFadingTime,
            ],
            OUTPUT_CLUSTERS: [],
        },
        242: {
            PROFILE_ID: zgp.PROFILE_ID,
            DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
            INPUT_CLUSTERS: [],
            OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
        },
    }
}

class TuyaMmwRadarClusterVariant2(TuyaMmwRadarClusterBase):
"""Tuya MMW radar cluster, variant 2."""

dp_to_attribute: Dict[int, DPToAttributeMapping] = {
    103: DPToAttributeMapping(
        TuyaMCUCluster.ep_attribute,
        "cli",
    ),
    104: DPToAttributeMapping(
        TuyaIlluminanceMeasurement.ep_attribute,
        "measured_value",
        converter=lambda x: int(math.log10(x) * 10000 + 1) if x > 0 else int(0),
    ),
    105: DPToAttributeMapping(
        TuyaOccupancySensing.ep_attribute,
        "occupancy",
    ),
    106: DPToAttributeMapping(
        TuyaMmwRadarSensitivity.ep_attribute,
        "present_value",
    ),
    107: DPToAttributeMapping(
        TuyaMmwRadarMaxRange.ep_attribute,
        "present_value",
        endpoint_id=3,
    ),
    108: DPToAttributeMapping(
        TuyaMmwRadarMinRange.ep_attribute,
        "present_value",
        endpoint_id=2,
    ),
    109: DPToAttributeMapping(
        TuyaMmwRadarTargetDistance.ep_attribute,
        "present_value",
    ),
    110: DPToAttributeMapping(
        TuyaMmwRadarFadingTime.ep_attribute,
        "present_value",
        converter=lambda x: x * 100,
        dp_converter=lambda x: x // 100,
        endpoint_id=5,
    ),
    111: DPToAttributeMapping(
        TuyaMmwRadarDetectionDelay.ep_attribute,
        "present_value",
        converter=lambda x: x * 100,
        dp_converter=lambda x: x // 100,
        endpoint_id=4,
    ),
}

data_point_handlers = {
    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",
}

class TuyaMmwRadarOccupancyVariant2(CustomDevice):
"""Millimeter wave occupancy sensor, variant 2."""

signature = {
    #  endpoint=1, profile=260, device_type=81, device_version=1,
    #  input_clusters=[0, 4, 5, 61184], output_clusters=[25, 10])
    MODELS_INFO: [
        ("_TZE204_sxm7l9xa", "TS0601"),
        ("_TZE204_bmdsp6bs", "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,
                TuyaNewManufCluster.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: zgp.PROFILE_ID,
            DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
            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,
                TuyaMmwRadarClusterVariant2,
                TuyaIlluminanceMeasurement,
                TuyaOccupancySensing,
                TuyaMmwRadarTargetDistance,
                TuyaMmwRadarSensitivity,
            ],
            OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
        },
        2: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarMinRange,
            ],
            OUTPUT_CLUSTERS: [],
        },
        3: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarMaxRange,
            ],
            OUTPUT_CLUSTERS: [],
        },
        4: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarDetectionDelay,
            ],
            OUTPUT_CLUSTERS: [],
        },
        5: {
            PROFILE_ID: zha.PROFILE_ID,
            DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
            INPUT_CLUSTERS: [
                TuyaMmwRadarFadingTime,
            ],
            OUTPUT_CLUSTERS: [],
        },
        242: {
            PROFILE_ID: zgp.PROFILE_ID,
            DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
            INPUT_CLUSTERS: [],
            OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
        },
    }
}

@nnae06
Copy link

nnae06 commented Aug 13, 2024

Skärmbild från 2024-08-13 20-04-38

@matsjrosenberg
Copy link

Thank you for this @nnae06 . Tried to copy paste this into a new customised quirk, and then reinstalled the device. It still insists on picking up the original zhaquirks.tuya.ts0601_motion.MmwRadarMotionGPP instead of the customised one. Can anybody help explaining how I make the custom quirk override the default one? Any specific file naming convention to be followed? The hardware specs correspond to what is in the customised quirk so this should not be the issue. And all my other customised device quirks work well.

@nnae06
Copy link

nnae06 commented Aug 14, 2024

I will post a finished file later in the day. Maybe can help.

@nnae06
Copy link

nnae06 commented Aug 14, 2024

ts0601_radar.py.zip

@matsjrosenberg
Copy link

ts0601_radar.zip
Added support for TS0601 by _TZE204_sbyx0lm6. Occupancy and Lux but no relay.

@macf0x
Copy link

macf0x commented Sep 26, 2024

Attempted to update latest quirk with the full DP's from zigbee2mqtt herdsmen (link)

More experimenting is required as I don't fully understand quirks, but posting this as it might help someone else.

 tuyaDatapoints: [
                [1, 'presence', tuya.valueConverter.trueFalse1],
                [2, 'radar_sensitivity', tuya.valueConverter.raw],
                [3, 'shield_range', tuya.valueConverter.divideBy100],
                [4, 'detection_range', tuya.valueConverter.divideBy100],
                [6, 'equipment_status', tuya.valueConverter.raw],
                [9, 'target_distance', tuya.valueConverter.divideBy100],
                [101, 'entry_filter_time', tuya.valueConverter.divideBy10],
                [102, 'departure_delay', tuya.valueConverter.raw],
                [103, 'cline', tuya.valueConverter.raw],
                [104, 'illuminance_lux', tuya.valueConverter.divideBy10],
                [105, 'entry_sensitivity', tuya.valueConverter.raw],
                [106, 'entry_distance_indentation', tuya.valueConverter.divideBy100],
                [107, 'breaker_mode', tuya.valueConverterBasic.lookup({'standard': tuya.enum(0), 'local': tuya.enum(1)})],
                [108, 'breaker_status', tuya.valueConverterBasic.lookup({'OFF': tuya.enum(0), 'ON': tuya.enum(1)})],
                [109, 'status_indication', tuya.valueConverterBasic.lookup({'OFF': tuya.enum(0), 'ON': tuya.enum(1)})],
                [110, 'illuminance_threshold', tuya.valueConverter.divideBy10],
                [111, 'breaker_polarity', tuya.valueConverterBasic.lookup({'NC': tuya.enum(0), 'NO': tuya.enum(1)})],
                [112, 'block_time', tuya.valueConverter.divideBy10],
                [113, 'parameter_setting_result', tuya.valueConverter.raw],
                [114, 'factory_parameters', tuya.valueConverter.raw],
                [115, 'sensor', tuya.valueConverterBasic.lookup({
                    'on': tuya.enum(0), 'off': tuya.enum(1), 'occupied': tuya.enum(2), 'unoccupied': tuya.enum(3)})],
                [116, 'distance_report', tuya.valueConverterBasic.lookup({
                    'off': tuya.enum(0), 
                    'on': tuya.enum(1)

ts0601_radar_new.py.txt

@dala318
Copy link

dala318 commented Oct 1, 2024

ts0601_radar_new.py.txt

Thanks a lot! Could you please add a TS0601 "_TZE204_iaeejhvf" to TuyaMmwRadarOccupancyVariant1GPP. I have added it locally and it show up as I would think it is supposed to by the quirk.
image

Looking forward to see if the breaker part of device can get solved as well.
zha-10bd056a4de4cbece683ed97f85638a7-_TZE204_iaeejhvf TS0601-dac28b9c161b2bebc10f7ebf01608fb2.json

@dala318
Copy link

dala318 commented Oct 1, 2024

One more improvement suggestion (I would love to contribute more actively but have yet not passed the threshold of understanding the quirks and how to debug/try/error/improve).

Currently the number-sliders for the device settings show up as "Controls" in the device in Home Assistant, I think they would be better placed under "Configuration". The small benefit that I see of that is that they would then not show up in the default dashboard in Home Assistant. (You likely don't want to change those on a daily basis).

Yes, I can make them hidden to achieve the same so no major issue, but just a proposal :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
custom quirk available A custom quirk is available to solve the issue, but it's not merged in the repo yet Tuya Request/PR regarding a Tuya device
Projects
None yet
Development

No branches or pull requests