Repository: zigpy/zha-device-handlers
Pull request #3163 (2024-05-22 07:28:00)

Add Aqara E1 motion sensor support
## Proposed change
<!--
  Explain your proposed change below.
-->

lumi.motion.acn001
Aqara E1 motion sensor RTCGQ15LM
https://home.miot-spec.com/s/lumi-acn001

I just borrow it from [motion_agl02](https://github.com/zigpy/zha-device-handlers/blob/dev/zhaquirks/xiaomi/aqara/motion_agl02.py).
I am not expert in zigbee or zha coding, so there maybe the need for code quality improvements. 
But it works in my test for motion, illuminance and battery.


## Additional information
<!--
  Please include any additional information that is important to this PR.
  For example, if this PR is a potentially breaking change, mention that here.
  If this PR requires other PRs to be merged in HA Core or other projects, mention that.
  Lastly, if this PR fixes a specific issue, please include "Fixes #xxxx".
-->
Fixes https://github.com/zigpy/zha-device-handlers/issues/2189


## Checklist
<!--
  Put an 'x' in all boxes that apply.
  Note: You do not need to tick all boxes before creating a PR.
-->

- [x] The changes are tested and work correctly
- [ ] `pre-commit` checks pass / the code has been formatted using Black
- [ ] Tests have been added to verify that the new code works


manymuch: Tested with home assistant core 2024.5.4.
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/zigpy/zha-device-handlers/pull/3163?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=zigpy) Report
Attention: Patch coverage is `59.09091%` with `9 lines` in your changes are missing coverage. Please review.
> Project coverage is 88.07%. Comparing base [(`bfbfb48`)](https://app.codecov.io/gh/zigpy/zha-device-handlers/commit/bfbfb4876d1811440b4a05cac9e3b83311d194a8?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=zigpy) to head [(`9cdab83`)](https://app.codecov.io/gh/zigpy/zha-device-handlers/pull/3163?dropdown=coverage&src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=zigpy).

| [Files](https://app.codecov.io/gh/zigpy/zha-device-handlers/pull/3163?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=zigpy) | Patch % | Lines |
|---|---|---|
| [zhaquirks/xiaomi/aqara/motion\_acn001.py](https://app.codecov.io/gh/zigpy/zha-device-handlers/pull/3163?src=pr&el=tree&filepath=zhaquirks%2Fxiaomi%2Faqara%2Fmotion_acn001.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=zigpy#diff-emhhcXVpcmtzL3hpYW9taS9hcWFyYS9tb3Rpb25fYWNuMDAxLnB5) | 59.09% | [9 Missing :warning: ](https://app.codecov.io/gh/zigpy/zha-device-handlers/pull/3163?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=zigpy) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##              dev    #3163      +/-   ##
==========================================
- Coverage   88.14%   88.07%   -0.07%     
==========================================
  Files         299      300       +1     
  Lines        9389     9411      +22     
==========================================
+ Hits         8276     8289      +13     
- Misses       1113     1122       +9     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/zigpy/zha-device-handlers/pull/3163?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=zigpy).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=zigpy).

manymuch: @TheJulianJES Please check the new commit

Patch:
diff --git a/zhaquirks/ikea/starkvind.py b/zhaquirks/ikea/starkvind.py
index 95b228d..11a1d1f 100644
--- a/zhaquirks/ikea/starkvind.py
+++ b/zhaquirks/ikea/starkvind.py
@@ -68,9 +68,9 @@ class IkeaAirpurifier(CustomCluster):
                 value is not None and value < 5500
             ):  # > 5500 = out of scale; if value is 65535 (0xFFFF), device is off
                 self.endpoint.device.pm25_bus.listener_event("update_state", value)
-        elif attrid == 0x0006:
-            if value > 9 and value < 51:
-                value = value / 5
+        elif attrid in (0x0006, 0x0007):
+            if value >= 10 and value <= 50:
+                value = value // 5
         super()._update_attribute(attrid, value)
 
     async def write_attributes(
diff --git a/zhaquirks/tuya/ts004f.py b/zhaquirks/tuya/ts004f.py
index c19892e..2eb5cf1 100644
--- a/zhaquirks/tuya/ts004f.py
+++ b/zhaquirks/tuya/ts004f.py
@@ -401,6 +401,40 @@ class TuyaSmartRemote004FSK(EnchantedDevice):
         (DOUBLE_PRESS, BUTTON_1): {ENDPOINT_ID: 1, COMMAND: DOUBLE_PRESS},
     }
 
+class TuyaSmartRemote004FSK_v2(TuyaSmartRemote004FSK):
+    """Tuya Smart (Single) Knob device."""
+
+    signature = {
+        # "node_descriptor": "NodeDescriptor(byte1=2, byte2=64, mac_capability_flags=128, manufacturer_code=4098, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, descriptor_capability_field=0, *allocate_address=True, *complex_descriptor_available=False, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=True, *is_full_function_device=False, *is_mains_powered=False, *is_receiver_on_when_idle=False, *is_router=False, *is_security_capable=False, *is_valid=True, *logical_type=<LogicalType.EndDevice: 2>, *user_descriptor_available=False)",
+        # SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=260, device_version=1, input_clusters=[0, 1, 3, 4, 6, 4096, 57345], output_clusters=[25, 10, 3, 4, 6, 8, 4096])
+        MODELS_INFO: [
+            ("_TZ3000_ja5osu5g", "TS004F"),
+        ],
+        ENDPOINTS: {
+            1: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
+                INPUT_CLUSTERS: [
+                    Basic.cluster_id,
+                    PowerConfiguration.cluster_id,
+                    Identify.cluster_id,
+                    Groups.cluster_id,
+                    OnOff.cluster_id,
+                    LightLink.cluster_id,
+                    TuyaZBExternalSwitchTypeCluster.cluster_id,
+                ],
+                OUTPUT_CLUSTERS: [
+                    Ota.cluster_id,
+                    Time.cluster_id,
+                    Identify.cluster_id,
+                    Groups.cluster_id,
+                    OnOff.cluster_id,
+                    LevelControl.cluster_id,
+                    LightLink.cluster_id,
+                ],
+            },
+        },
+    }
 
 class TuyaSmartRemote004F(EnchantedDevice):
     """Tuya 4-button New version remote device."""
diff --git a/zhaquirks/tuya/ts0601_cover.py b/zhaquirks/tuya/ts0601_cover.py
index a95b490..57b981e 100644
--- a/zhaquirks/tuya/ts0601_cover.py
+++ b/zhaquirks/tuya/ts0601_cover.py
@@ -460,6 +460,61 @@ class TuyaMoesCover0601_alt_controls(TuyaWindowCover):
         }
     }
 
+class TuyaMoesCover0601_alt_controls2(TuyaWindowCover):
+    """Tuya blind controller device."""
+
+    tuya_cover_command = {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001}
+    tuya_cover_inverted_by_default = True
+
+    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": 260, "device_type": "0x0051", "in_clusters": [ "0x0000", "0x0004","0x0005","0x0102","0xef00"], "out_clusters": ["0x000a","0x0019"] }
+        # },
+        # "manufacturer": "_TZE200_2odrmqwq",
+        # "model": "TS0601",
+        # "class": "zigpy.device.Device"
+        # }
+        MODELS_INFO: [
+            ("_TZE200_2odrmqwq", "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,
+                    TuyaManufCluster.cluster_id,
+                ],
+                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
+            }
+        },
+    }
+
+    replacement = {
+        ENDPOINTS: {
+            1: {
+                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
+                INPUT_CLUSTERS: [
+                    Basic.cluster_id,
+                    Groups.cluster_id,
+                    Scenes.cluster_id,
+                    TuyaManufacturerWindowCover,
+                    TuyaWindowCoverControl,
+                ],
+                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
+            }
+        }
+    }
+
 
 class TuyaMoesCover0601_inv_position(TuyaWindowCover):
     """Tuya blind controller device."""
diff --git a/zhaquirks/tuya/ts0601_sensor.py b/zhaquirks/tuya/ts0601_sensor.py
index f76648a..4cc711d 100644
--- a/zhaquirks/tuya/ts0601_sensor.py
+++ b/zhaquirks/tuya/ts0601_sensor.py
@@ -372,6 +372,7 @@ class TuyaSoilSensor(CustomDevice):
             ("_TZE200_myd45weu", "TS0601"),
             ("_TZE200_ga1maeof", "TS0601"),
             ("_TZE200_9cqcpkgb", "TS0601"),
+            ("_TZE204_myd45weu", "TS0601"),
         ],
         ENDPOINTS: {
             1: {
diff --git a/zhaquirks/xiaomi/__init__.py b/zhaquirks/xiaomi/__init__.py
index 91607cf..251d137 100644
--- a/zhaquirks/xiaomi/__init__.py
+++ b/zhaquirks/xiaomi/__init__.py
@@ -24,6 +24,7 @@ from zigpy.zcl.clusters.general import (
 from zigpy.zcl.clusters.homeautomation import ElectricalMeasurement
 from zigpy.zcl.clusters.measurement import (
     IlluminanceMeasurement,
+    OccupancySensing,
     PressureMeasurement,
     RelativeHumidity,
     TemperatureMeasurement,
@@ -389,7 +390,7 @@ class XiaomiCluster(CustomCluster):
             attribute_names.update({11: ILLUMINANCE_MEASUREMENT})
         elif self.endpoint.device.model == "lumi.curtain.acn002":
             attribute_names.update({101: BATTERY_PERCENTAGE_REMAINING_ATTRIBUTE})
-        elif self.endpoint.device.model in ["lumi.motion.agl02", "lumi.motion.ac02"]:
+        elif self.endpoint.device.model in ["lumi.motion.agl02", "lumi.motion.ac02", "lumi.motion.acn001"]:
             attribute_names.update({101: ILLUMINANCE_MEASUREMENT})
             if self.endpoint.device.model == "lumi.motion.ac02":
                 attribute_names.update({105: DETECTION_INTERVAL})
@@ -464,6 +465,22 @@ class XiaomiAqaraE1Cluster(XiaomiCluster):
     ep_attribute = "opple_cluster"
 
 
+class XiaomiMotionManufacturerCluster(XiaomiAqaraE1Cluster):
+    """Xiaomi manufacturer cluster to parse motion and illuminance reports."""
+
+    def _update_attribute(self, attrid, value):
+        super()._update_attribute(attrid, value)
+        if attrid == 274:
+            value = value - 65536
+            self.endpoint.illuminance.update_attribute(
+                IlluminanceMeasurement.AttributeDefs.measured_value.id, value
+            )
+            self.endpoint.occupancy.update_attribute(
+                OccupancySensing.AttributeDefs.occupancy.id,
+                OccupancySensing.Occupancy.Occupied,
+            )
+
+
 class BinaryOutputInterlock(CustomCluster, BinaryOutput):
     """Xiaomi binaryoutput cluster with added interlock attribute."""
 
diff --git a/zhaquirks/xiaomi/aqara/motion_ac02.py b/zhaquirks/xiaomi/aqara/motion_ac02.py
index efb5217..c372691 100644
--- a/zhaquirks/xiaomi/aqara/motion_ac02.py
+++ b/zhaquirks/xiaomi/aqara/motion_ac02.py
@@ -8,7 +8,6 @@ from zigpy import types
 from zigpy.profiles import zha
 from zigpy.quirks import CustomDevice
 from zigpy.zcl.clusters.general import Basic, Identify, Ota, PowerConfiguration
-from zigpy.zcl.clusters.measurement import IlluminanceMeasurement, OccupancySensing
 
 from zhaquirks import Bus, LocalDataCluster
 from zhaquirks.const import (
@@ -23,7 +22,7 @@ from zhaquirks.xiaomi import (
     LocalIlluminanceMeasurementCluster,
     MotionCluster,
     OccupancyCluster,
-    XiaomiAqaraE1Cluster,
+    XiaomiMotionManufacturerCluster,
     XiaomiPowerConfiguration,
 )
 
@@ -34,8 +33,12 @@ TRIGGER_INDICATOR = 0x0152
 _LOGGER = logging.getLogger(__name__)
 
 
-class OppleCluster(XiaomiAqaraE1Cluster):
-    """Opple cluster."""
+class OppleCluster(XiaomiMotionManufacturerCluster):
+    """Xiaomi manufacturer cluster.
+
+    This uses the shared XiaomiMotionManufacturerCluster implementation
+    which parses motion and illuminance reports from Xiaomi devices.
+    """
 
     attributes = {
         DETECTION_INTERVAL: ("detection_interval", types.uint8_t, True),
@@ -43,18 +46,6 @@ class OppleCluster(XiaomiAqaraE1Cluster):
         TRIGGER_INDICATOR: ("trigger_indicator", types.uint8_t, True),
     }
 
-    def _update_attribute(self, attrid: int, value: Any) -> None:
-        super()._update_attribute(attrid, value)
-        if attrid == MOTION_ATTRIBUTE:
-            value = value - 65536
-            self.endpoint.illuminance.update_attribute(
-                IlluminanceMeasurement.AttributeDefs.measured_value.id, value
-            )
-            self.endpoint.occupancy.update_attribute(
-                OccupancySensing.AttributeDefs.occupancy.id,
-                OccupancySensing.Occupancy.Occupied,
-            )
-
     async def write_attributes(
         self, attributes: dict[str | int, Any], manufacturer: int | None = None
     ) -> list:
diff --git a/zhaquirks/xiaomi/aqara/motion_acn001.py b/zhaquirks/xiaomi/aqara/motion_acn001.py
new file mode 100644
index 0000000..168372a
--- /dev/null
+++ b/zhaquirks/xiaomi/aqara/motion_acn001.py
@@ -0,0 +1,68 @@
+"""Xiaomi Aqara E1 motion sensor device."""
+from zigpy.profiles import zha
+from zigpy.zcl.clusters.general import Identify, Ota
+
+from zhaquirks import Bus
+from zhaquirks.const import (
+    DEVICE_TYPE,
+    ENDPOINTS,
+    INPUT_CLUSTERS,
+    MODELS_INFO,
+    OUTPUT_CLUSTERS,
+    PROFILE_ID,
+)
+from zhaquirks.xiaomi import (
+    LUMI,
+    BasicCluster,
+    IlluminanceMeasurementCluster,
+    LocalOccupancyCluster,
+    MotionCluster,
+    XiaomiAqaraE1Cluster,
+    XiaomiCustomDevice,
+    XiaomiMotionManufacturerCluster,
+    XiaomiPowerConfiguration,
+)
+
+
+class MotionE1(XiaomiCustomDevice):
+    """Xiaomi motion sensor device lumi.motion.acn001."""
+
+    def __init__(self, *args, **kwargs):
+        """Init."""
+        self.battery_size = 11
+        self.motion_bus = Bus()
+        super().__init__(*args, **kwargs)
+
+    signature = {
+        MODELS_INFO: [(LUMI, "lumi.motion.acn001")],
+        ENDPOINTS: {
+            1: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.IAS_ZONE,
+                INPUT_CLUSTERS: [
+                    BasicCluster.cluster_id,
+                    XiaomiPowerConfiguration.cluster_id,
+                    Identify.cluster_id,
+                    XiaomiAqaraE1Cluster.cluster_id,
+                ],
+                OUTPUT_CLUSTERS: [Identify.cluster_id, Ota.cluster_id],
+            }
+        },
+    }
+
+    replacement = {
+        ENDPOINTS: {
+            1: {
+                INPUT_CLUSTERS: [
+                    BasicCluster,
+                    XiaomiPowerConfiguration,
+                    Identify.cluster_id,
+                    LocalOccupancyCluster,
+                    MotionCluster,
+                    IlluminanceMeasurementCluster,
+                    XiaomiMotionManufacturerCluster,
+                ],
+                OUTPUT_CLUSTERS: [Identify.cluster_id, Ota.cluster_id],
+            }
+        },
+    }
diff --git a/zhaquirks/xiaomi/aqara/motion_agl02.py b/zhaquirks/xiaomi/aqara/motion_agl02.py
index e8c0fd1..3022332 100644
--- a/zhaquirks/xiaomi/aqara/motion_agl02.py
+++ b/zhaquirks/xiaomi/aqara/motion_agl02.py
@@ -3,7 +3,7 @@ from __future__ import annotations
 
 from zigpy.profiles import zha
 from zigpy.zcl.clusters.general import Identify, Ota
-from zigpy.zcl.clusters.measurement import IlluminanceMeasurement, OccupancySensing
+from zigpy.zcl.clusters.measurement import OccupancySensing
 
 from zhaquirks import Bus
 from zhaquirks.const import (
@@ -20,29 +20,11 @@ from zhaquirks.xiaomi import (
     IlluminanceMeasurementCluster,
     LocalOccupancyCluster,
     MotionCluster,
-    XiaomiAqaraE1Cluster,
     XiaomiCustomDevice,
+    XiaomiMotionManufacturerCluster,
     XiaomiPowerConfiguration,
 )
 
-XIAOMI_CLUSTER_ID = 0xFCC0
-
-
-class XiaomiManufacturerCluster(XiaomiAqaraE1Cluster):
-    """Xiaomi manufacturer cluster."""
-
-    def _update_attribute(self, attrid, value):
-        super()._update_attribute(attrid, value)
-        if attrid == 274:
-            value = value - 65536
-            self.endpoint.illuminance.update_attribute(
-                IlluminanceMeasurement.AttributeDefs.measured_value.id, value
-            )
-            self.endpoint.occupancy.update_attribute(
-                OccupancySensing.AttributeDefs.occupancy.id,
-                OccupancySensing.Occupancy.Occupied,
-            )
-
 
 class MotionT1(XiaomiCustomDevice):
     """Xiaomi motion sensor device."""
@@ -73,6 +55,7 @@ class MotionT1(XiaomiCustomDevice):
             }
         },
     }
+
     replacement = {
         ENDPOINTS: {
             1: {
@@ -83,7 +66,7 @@ class MotionT1(XiaomiCustomDevice):
                     LocalOccupancyCluster,
                     MotionCluster,
                     IlluminanceMeasurementCluster,
-                    XiaomiManufacturerCluster,
+                    XiaomiMotionManufacturerCluster,
                 ],
                 OUTPUT_CLUSTERS: [Identify.cluster_id, Ota.cluster_id],
             }


Test patch:
diff --git a/tests/test_ikea.py b/tests/test_ikea.py
index fa44700..6d57427 100644
--- a/tests/test_ikea.py
+++ b/tests/test_ikea.py
@@ -10,6 +10,7 @@ from zigpy.zcl.clusters.measurement import PM25
 from tests.common import ClusterListener
 import zhaquirks
 import zhaquirks.ikea.starkvind
+from zhaquirks.ikea.starkvind import IkeaAirpurifier
 
 zhaquirks.setup()
 
@@ -85,6 +86,33 @@ def test_ikea_starkvind_v2(assert_signature_matches_quirk):
     assert_signature_matches_quirk(zhaquirks.ikea.starkvind.IkeaSTARKVIND_v2, signature)
 
 
+@pytest.mark.parametrize("attribute", ["fan_speed", "fan_mode"])
+@pytest.mark.parametrize("value,expected", [
+        (0, 0),  # off
+        (1, 1),  # auto
+        (10, 2),
+        (20, 4),
+        (50, 10),
+    ]
+ )
+async def test_fan_speed_mode_update(zigpy_device_from_quirk, attribute, value, expected):
+    """Test reading the fan speed and mode."""
+
+    starkvind_device = zigpy_device_from_quirk(zhaquirks.ikea.starkvind.IkeaSTARKVIND)
+    assert starkvind_device.model == "STARKVIND Air purifier"
+
+    ikea_cluster = starkvind_device.endpoints[1].in_clusters[
+        zhaquirks.ikea.starkvind.IkeaAirpurifier.cluster_id
+    ]
+    ikea_listener = ClusterListener(ikea_cluster)
+
+    attr_id = getattr(IkeaAirpurifier.AttributeDefs, attribute).id
+
+    ikea_cluster.update_attribute(attr_id, value)
+    assert len(ikea_listener.attribute_updates) == 1
+    assert ikea_listener.attribute_updates[0] == (attr_id, expected)
+
+
 async def test_pm25_cluster_read(zigpy_device_from_quirk):
     """Test reading from PM25 cluster."""
 
diff --git a/tests/test_xiaomi.py b/tests/test_xiaomi.py
index 3836c79..f534e09 100644
--- a/tests/test_xiaomi.py
+++ b/tests/test_xiaomi.py
@@ -1135,12 +1135,13 @@ async def test_xiaomi_e1_thermostat_schedule_settings_deserialization(
     (
         (zhaquirks.xiaomi.aqara.motion_ac02.LumiMotionAC02, 0),
         (zhaquirks.xiaomi.aqara.motion_agl02.MotionT1, -1),
+        (zhaquirks.xiaomi.aqara.motion_acn001.MotionE1, -1),
     ),
 )
 async def test_xiaomi_p1_t1_motion_sensor(
     zigpy_device_from_quirk, quirk, invalid_iilluminance_report
 ):
-    """Test Aqara P1 and T1 motion sensors."""
+    """Test Aqara P1, T1, and E1 motion sensors."""
 
     device = zigpy_device_from_quirk(quirk)
 
@@ -1192,12 +1193,12 @@ async def test_xiaomi_p1_t1_motion_sensor(
     opple_cluster.update_attribute(274, 0xFFFF)
 
     # confirm invalid illuminance report is interpreted as 0 for P1 sensor,
-    # and -1 for the T1 sensor, as it doesn't seem like the T1 sensor sends invalid illuminance reports
+    # and -1 for the T1/E1 sensors, as they don't seem to send invalid illuminance reports
     assert len(illuminance_listener.attribute_updates) == 2
     assert illuminance_listener.attribute_updates[1][0] == zcl_iilluminance_id
     assert illuminance_listener.attribute_updates[1][1] == invalid_iilluminance_report
 
-    # send illuminance report only
+    # send illuminance report only, parsed via Xiaomi cluster implementation
     opple_cluster.update_attribute(
         XIAOMI_AQARA_ATTRIBUTE_E1, create_aqara_attr_report({101: 20})
     )