TLDR - I bought a sensor, realised it didn’t work and spent a small fraction of my life getting it to work. I publish a short ‘how-to’ to outline the steps to get the sensor to work. I ask for some further support to get the sensor ‘out of the box’ ready. The code is now more appropriate for the device and has more functionality.
Edit 1 - 27/08/2024 - Updated code block with fix for user input values resetting to default. Intended behaviour would be user input values remain until changed by user.
Edit 2 - 30/08/2024 - Updated code block to actually fix user input values resetting to default. Intended behaviour would be user input values remain until changed by user. Illuminance sensor now working.
After using a couple of the Sonoff SNZB-03’s for a short while I decided it was time for an upgrade to mmWave. I initially got the ZY-M100 wall mount version which integrated seamlessly into HA through ZHA - a great sensor.
Shortly after, I purchased the ceiling mount version (WZ-M100), punched a hole into the ceiling and wired it into the 230V mains. Only then did I decide to begin the setup process - this was quite the mistake!
The ceiling version, or at least the particular variant I had purchased, does not integrate as seamlessly as the wall mount version. In fact it does not function at all out of the box. I should note other people have had better luck using zigbee2mqtt and/or different variants of the same sensor.
After having a slight panic that I had punched a hole in the ceiling for a dud-sensor, I began trawling the forums looking for people in a similar situation - of which there are plenty. A couple hours later and I had managed to get the sensor working perfectly (minus the lux sensor which I am yet to bother with). The particular variant I had purchased isn’t as widespread as some others so I think it best to summarise my experience below. With the exception of the code, you may choose to follow the extremely helpful guide linked here.
The following guide is a collection of steps from various sources, I take no credit for any of this. This guide applies to the ZHA implementation of Zigbee and I use HA OS based on an SD card on a Raspberry Pi 4. I assume that you already have Studio Code Server (or equivalent) installed on your HA instance, and you can follow instructions (you do not need any python knowledge).
If I can do this, as a complete python novice, so can you!
Step 1: Attempt to setup the sensor BEFORE considering using a drill or any other hole making device. This is very important.
Step 2: Realise your device is not out of the box ready and have a panic proportional to the situation.
Step 3: Using Studio Code Server (or equivalent) create a folder within the config folder named ‘custom_zha_quirks’
Step 4: Within the newly created folder create a file named ‘ts0601_radar.py’. I do not know if the name of this file is particularly important, but I do know that the file extension is paramount.
Step 5: Copy the below code into the newly created file and save it. Ensure indentation is identical.
[Last Updated 30/08/2024]
import math
from typing import Dict, Optional, Tuple, Union
from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
import zigpy.types as t
from zigpy.zcl import foundation
from zigpy.zcl.clusters.general import (
AnalogInput,
AnalogOutput,
Basic,
GreenPowerProxy,
Groups,
Identify,
Ota,
Scenes,
Time,
)
from zigpy.zcl.clusters.measurement import (
IlluminanceMeasurement,
OccupancySensing
)
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 (
NoManufacturerCluster,
TuyaLocalCluster,
TuyaNewManufCluster,
)
from zhaquirks.tuya.mcu import (
# TuyaDPType,
DPToAttributeMapping,
TuyaAttributesCluster,
TuyaMCUCluster,
)
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 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, 75)
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, 75)
self._update_attribute(self.attributes_by_name["max_present_value"].id, 900)
self._update_attribute(self.attributes_by_name["resolution"].id, 75)
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, 1000)
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, 118
) # 31: meters
class TuyaMmwRadarCluster(NoManufacturerCluster, TuyaMCUCluster):
"""Mmw radar cluster."""
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),
}
)
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,
# converter=lambda x: x / 100,
# dp_converter=lambda x: x * 100,
),
4: DPToAttributeMapping(
TuyaMmwRadarMaxRange.ep_attribute,
"present_value",
endpoint_id=3,
# converter=lambda x: x / 100,
# dp_converter=lambda x: x * 100,
),
6: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"self_test",
),
9: DPToAttributeMapping(
TuyaMmwRadarTargetDistance.ep_attribute,
"present_value",
# converter=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,
),
103: DPToAttributeMapping(
TuyaIlluminanceMeasurement.ep_attribute,
"measured_value",
converter=lambda x: 10000 * math.log10(x) + 1 if x != 0 else 0,
),
#104: DPToAttributeMapping( Unknown what this attribute is at this time
#TuyaMCUCluster.ep_attribute,
#"cli",
#),
105: DPToAttributeMapping(
TuyaMmwRadarFadingTime.ep_attribute,
"present_value",
converter=lambda x: x * 100,
dp_converter=lambda x: x // 100,
endpoint_id=5,
),
}
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",
103: "_dp_2_attr_update",
# 104: "_dp_2_attr_update",
105: "_dp_2_attr_update",
}
class TuyaMmwRadarOccupancy(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: [
("_TZE204_7gclukjs", "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: 41440,
DEVICE_TYPE: 97,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
},
},
}
replacement = {
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.OCCUPANCY_SENSOR,
INPUT_CLUSTERS: [
Basic.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
TuyaMmwRadarCluster,
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: 41440,
DEVICE_TYPE: 97,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
},
}
}
Step 6: Add the following code to your configuration.yaml entry, again ensuring correct indentation.
zha:
custom_quirks_path: /config/custom_zha_quirks
Step 7: Restart Home Assistant.
Step 8: Sigh relief that the sensor now works!
Step 9: Realise you now need to actually install the sensor in a suitable location and do that. Exercise caution!
The resources I used to get the sensor working were;
Fixt’s guide on the ZY-M100 sensor. A big thank you to fixt!
Github resource 3112
Github resource 21738 (attribute mappings)
The code was published by KLM30330 over on Github.
It would be beneficial if this code (with some alterations) could be included with ZHA as standard so the ‘kjs’ variant works out of the box for future buyers. How can I go about doing this?
The lux sensor outputs either 0 or 1, therefore the sensor is not fully operational as someone might expect it to be - could someone with a smidge more python experience help me out with getting this to output something useful?
Original code for reference only (Pre-27/08/2024)
import math
from typing import Dict, Optional, Tuple, Union
from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
import zigpy.types as t
from zigpy.zcl import foundation
from zigpy.zcl.clusters.general import (
AnalogInput,
AnalogOutput,
Basic,
GreenPowerProxy,
Groups,
Identify,
Ota,
Scenes,
Time,
)
from zigpy.zcl.clusters.measurement import (
IlluminanceMeasurement,
OccupancySensing
)
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 (
NoManufacturerCluster,
TuyaLocalCluster,
TuyaNewManufCluster,
)
from zhaquirks.tuya.mcu import (
# TuyaDPType,
DPToAttributeMapping,
TuyaAttributesCluster,
TuyaMCUCluster,
)
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 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, 118
) # 31: meters
class TuyaMmwRadarCluster(NoManufacturerCluster, TuyaMCUCluster):
"""Mmw radar cluster."""
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),
0xEF09: ("target_distance", t.uint32_t, True),
0xEF65: ("detection_delay", t.uint32_t, True),
0xEF66: ("fading_time", t.uint32_t, True),
0xEF68: ("illuminance", t.uint32_t, True),
}
)
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,
),
9: DPToAttributeMapping(
TuyaMmwRadarTargetDistance.ep_attribute,
"present_value",
),
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,
),
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",
9: "_dp_2_attr_update",
101: "_dp_2_attr_update",
102: "_dp_2_attr_update",
104: "_dp_2_attr_update",
}
class TuyaMmwRadarOccupancy(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: [
("_TZE204_7gclukjs", "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: 41440,
DEVICE_TYPE: 97,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
},
},
}
replacement = {
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.OCCUPANCY_SENSOR,
INPUT_CLUSTERS: [
Basic.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
TuyaMmwRadarCluster,
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: 41440,
DEVICE_TYPE: 97,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
},
}
}