Open gbarrena opened 5 months ago
can anybody help me?
I'm interested as well! I tried modifying an existing profile but ran into some trouble(it's my first time making one).
Some other info I found is that people over from Hubitat suggested using the profile from Tuya human presence mmWave Radar ZY-M100 which seems to be the same.
I'm looking forward to support for this device.
This code works for me, but i cant regulate the sensibility
`"""BlitzWolf IS-3/Tuya motion rechargeable occupancy sensor."""
import math from typing import Optional, Union
from zigpy.profiles import zgp, zha from zigpy.quirks import CustomDevice import zigpy.types as t from zigpy.zcl import foundation from zigpy.zcl.clusters.general import ( AnalogInput, Basic, GreenPowerProxy, Groups, Identify, Ota, Scenes, Time, ) from zigpy.zcl.clusters.measurement import ( IlluminanceMeasurement, OccupancySensing, RelativeHumidity, TemperatureMeasurement, ) from zigpy.zcl.clusters.security import IasZone
from zhaquirks import Bus, LocalDataCluster, MotionOnEvent from zhaquirks.const import ( DEVICE_TYPE, ENDPOINTS, INPUT_CLUSTERS, MODELS_INFO, MOTION_EVENT, OUTPUT_CLUSTERS, PROFILE_ID, ) from zhaquirks.tuya import ( DPToAttributeMapping, TuyaLocalCluster, TuyaManufCluster, TuyaNewManufCluster, ) from zhaquirks.tuya.mcu import TuyaMCUCluster
ZONE_TYPE = 0x0001
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 TuyaTemperatureMeasurement(TemperatureMeasurement, TuyaLocalCluster): """Tuya local TemperatureMeasurement cluster."""
class TuyaRelativeHumidity(RelativeHumidity, TuyaLocalCluster): """Tuya local RelativeHumidity cluster."""
class NeoBatteryLevel(t.enum8): """NEO battery level enum."""
BATTERY_FULL = 0x00
BATTERY_HIGH = 0x01
BATTERY_MEDIUM = 0x02
BATTERY_LOW = 0x03
USB_POWER = 0x04
class NeoMotionManufCluster(TuyaNewManufCluster): """Neo manufacturer cluster."""
attributes = TuyaNewManufCluster.attributes.copy()
attributes.update(
{
0xEF0D: ("dp_113", t.enum8, True), # ramdom attribute ID
}
)
dp_to_attribute: dict[int, DPToAttributeMapping] = {
101: DPToAttributeMapping(
TuyaOccupancySensing.ep_attribute,
"occupancy",
),
104: DPToAttributeMapping(
TuyaTemperatureMeasurement.ep_attribute,
"measured_value",
lambda x: x * 10,
),
105: DPToAttributeMapping(
TuyaRelativeHumidity.ep_attribute,
"measured_value",
lambda x: x * 100,
),
113: DPToAttributeMapping(
TuyaNewManufCluster.ep_attribute,
"dp_113",
),
}
data_point_handlers = {
101: "_dp_2_attr_update",
104: "_dp_2_attr_update",
105: "_dp_2_attr_update",
113: "_dp_2_attr_update",
}
class MmwRadarManufCluster(TuyaMCUCluster): """Neo manufacturer cluster."""
# # Possible DPs and values
# presence_state: presence
# target distance: 1.61m
# illuminance: 250lux
# sensitivity: 9
# minimum_detection_distance: 0.00m
# maximum_detection_distance: 4.05m
# dp_detection_delay: 0.1
# dp_fading_time: 5.0
# ¿illuminance?: 255lux
# presence_brightness: no control
# no_one_brightness: no control
# current_brightness: off
attributes = TuyaMCUCluster.attributes.copy()
attributes.update(
{
# ramdom attribute IDs
0xEF02: ("dp_2", t.uint32_t, True),
0xEF03: ("dp_3", t.uint32_t, True),
0xEF04: ("dp_4", t.uint32_t, True),
0xEF06: ("dp_6", t.enum8, True),
0xEF65: ("dp_101", t.uint32_t, True),
0xEF66: ("dp_102", t.uint32_t, True),
0xEF67: ("dp_103", t.CharacterString, True),
0xEF69: ("dp_105", t.enum8, True),
0xEF6A: ("dp_106", t.enum8, True),
0xEF6B: ("dp_107", t.enum8, True),
0xEF6C: ("dp_108", t.uint32_t, True),
}
)
dp_to_attribute: dict[int, DPToAttributeMapping] = {
1: DPToAttributeMapping(
TuyaOccupancySensing.ep_attribute,
"occupancy",
),
2: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"dp_2",
),
3: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"dp_3",
),
4: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"dp_4",
),
6: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"dp_6",
),
9: DPToAttributeMapping(
TuyaAnalogInput.ep_attribute,
"present_value",
lambda x: x / 100,
),
101: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"dp_101",
),
102: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"dp_102",
),
103: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"dp_103",
),
104: DPToAttributeMapping(
TuyaIlluminanceMeasurement.ep_attribute,
"measured_value",
lambda x: 10000 * math.log10(x) + 1 if x != 0 else 0,
),
105: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"dp_105",
),
106: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"dp_106",
),
107: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"dp_107",
),
108: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"dp_108",
),
}
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",
105: "_dp_2_attr_update",
106: "_dp_2_attr_update",
107: "_dp_2_attr_update",
108: "_dp_2_attr_update",
}
class MotionCluster(LocalDataCluster, MotionOnEvent): """Tuya Motion Sensor."""
_CONSTANT_ATTRIBUTES = {ZONE_TYPE: IasZone.ZoneType.Motion_Sensor}
reset_s = 15
class TuyaManufacturerClusterMotion(TuyaManufCluster): """Manufacturer Specific Cluster of the Motion device."""
def handle_cluster_request(
self,
hdr: foundation.ZCLHeader,
args: tuple[TuyaManufCluster.Command],
*,
dst_addressing: Optional[
Union[t.Addressing.Group, t.Addressing.IEEE, t.Addressing.NWK]
] = None,
) -> None:
"""Handle cluster request."""
tuya_cmd = args[0]
self.debug("handle_cluster_request--> hdr: %s, args: %s", hdr, args)
if hdr.command_id == 0x0001 and tuya_cmd.command_id == 1027:
self.endpoint.device.motion_bus.listener_event(MOTION_EVENT)
class TuyaMotion(CustomDevice): """BW-IS3 occupancy sensor."""
def __init__(self, *args, **kwargs):
"""Init device."""
self.motion_bus = Bus()
super().__init__(*args, **kwargs)
signature = {
# endpoint=1 profile=260 device_type=0 device_version=0 input_clusters=[0, 3]
# output_clusters=[3, 25]>
MODELS_INFO: [("_TYST11_i5j6ifxj", "5j6ifxj"), ("_TYST11_7hfcudw5", "hfcudw5")],
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
INPUT_CLUSTERS: [Basic.cluster_id, Identify.cluster_id],
OUTPUT_CLUSTERS: [Identify.cluster_id, Ota.cluster_id],
}
},
}
replacement = {
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.OCCUPANCY_SENSOR,
INPUT_CLUSTERS: [
Basic.cluster_id,
Identify.cluster_id,
MotionCluster,
TuyaManufacturerClusterMotion,
],
OUTPUT_CLUSTERS: [Identify.cluster_id, Ota.cluster_id],
}
}
}
class NeoMotion(CustomDevice): """NAS-PD07 occupancy sensor."""
signature = {
# endpoint=1 profile=260 device_type=81 device_version=0 input_clusters=[0, 4, 5, 61184]
# output_clusters=[10, 25]>
MODELS_INFO: [
("_TZE200_7hfcudw5", "TS0601"),
("_TZE200_ppuj1vem", "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,
NeoMotionManufCluster.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,
NeoMotionManufCluster,
TuyaOccupancySensing,
TuyaTemperatureMeasurement,
TuyaRelativeHumidity,
],
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
}
}
}
class MmwRadarMotion(CustomDevice): """Millimeter wave occupancy sensor."""
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"),
],
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,
MmwRadarManufCluster,
TuyaOccupancySensing,
TuyaAnalogInput,
TuyaIlluminanceMeasurement,
],
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
},
}
}
class MmwRadarMotionGPP(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_ar0slwnd", "TS0601"),
("_TZE200_sfiy5tfs", "TS0601"),
("_TZE200_mrf6vtua", "TS0601"),
("_TZE204_qasjif9e", "TS0601"),
#mio
("_TZE204_fwondbzy", "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,
MmwRadarManufCluster,
TuyaOccupancySensing,
TuyaAnalogInput,
TuyaIlluminanceMeasurement,
],
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
},
242: {
PROFILE_ID: zgp.PROFILE_ID,
DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
},
}
}`
any chances to have it running with Zigbee2MQTT?
i only try hza
I think I have enough info to build or modify a quirk but a lack of time is keeping me from creating/finishing it. I will give it a try this weekend.
Thanks!
El mar, 9 jul 2024, 19:28, Nubbit @.***> escribió:
I think I have enough info to build or modify a quirk but a lack of time is keeping me from creating/finishing it. I will give it a try this weekend.
— Reply to this email directly, view it on GitHub https://github.com/zigpy/zha-device-handlers/issues/3216#issuecomment-2218283769, or unsubscribe https://github.com/notifications/unsubscribe-auth/AYY5SLSG7WHKZWBHPBP4J6TZLQMU7AVCNFSM6AAAAABJQXFWQ2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEMJYGI4DGNZWHE . You are receiving this because you authored the thread.Message ID: @.***>
Problem description
You cannot regulate intensity or any other control.
{ "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=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, descriptor_capability_field=<DescriptorCapability.NONE: 0>, allocate_address=True, is_alternate_pan_coordinator=False, is_coordinator=False, is_end_device=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" ] }, "242": { "profile_id": "0xa1e0", "device_type": "0x0061", "input_clusters": [], "output_clusters": [ "0x0021" ] } }, "manufacturer": "_TZE204_fwondbzy", "model": "TS0601", "class": "ts0601_motion.MmwRadarMotionGPP"
Solution description
Help
Screenshots/Video
Screenshots/Video
[Paste/upload your media here]Device signature
Device signature
```json [Paste the device signature here] ```Diagnostic information
Diagnostic information
```json [Paste the diagnostic information here] ```Logs
Logs
```python [Paste the logs here] ```Custom quirk
Custom quirk
```python [Paste your custom quirk here] ```Additional information
No response