|
1 | 1 | """Tests for Develco/Frient.""" |
2 | 2 |
|
| 3 | +import itertools |
3 | 4 | from unittest import mock |
4 | 5 |
|
| 6 | +import zigpy.quirks |
5 | 7 | import zigpy.types as t |
6 | 8 | from zigpy.zcl import ClusterType, foundation |
7 | 9 | from zigpy.zcl.clusters.smartenergy import Metering |
|
12 | 14 | zhaquirks.setup() |
13 | 15 |
|
14 | 16 |
|
| 17 | +def _get_emi_led_quirk_entry(): |
| 18 | + """Return the registered EMIZB-141 quirk entry.""" |
| 19 | + for quirk in itertools.chain.from_iterable( |
| 20 | + zigpy.quirks.DEVICE_REGISTRY.registry_v2.values() |
| 21 | + ): |
| 22 | + if ("frient A/S", "EMIZB-141") in { |
| 23 | + (metadata.manufacturer, metadata.model) |
| 24 | + for metadata in quirk.manufacturer_model_metadata |
| 25 | + }: |
| 26 | + return quirk |
| 27 | + |
| 28 | + raise AssertionError("EMIZB-141 quirk not registered") |
| 29 | + |
| 30 | + |
| 31 | +def test_frient_emi_v2_metadata_current_summation(): |
| 32 | + """Test EMIZB-141 exposes current summation and reset button metadata.""" |
| 33 | + quirk = _get_emi_led_quirk_entry() |
| 34 | + |
| 35 | + entity_map = { |
| 36 | + entity_metadata.translation_key: entity_metadata |
| 37 | + for entity_metadata in quirk.entity_metadata |
| 38 | + if entity_metadata.translation_key is not None |
| 39 | + } |
| 40 | + |
| 41 | + assert ( |
| 42 | + entity_map["current_summation"].fallback_name == "Current summation delivered" |
| 43 | + ) |
| 44 | + assert ( |
| 45 | + entity_map["reset_summation_delivered"].fallback_name |
| 46 | + == "Reset summation delivered" |
| 47 | + ) |
| 48 | + |
| 49 | + |
15 | 50 | async def test_frient_emi(zigpy_device_from_v2_quirk): |
16 | 51 | """Test that the EMI correctly forwards custom attributes.""" |
17 | 52 | device = zigpy_device_from_v2_quirk( |
@@ -129,6 +164,43 @@ async def test_frient_emi(zigpy_device_from_v2_quirk): |
129 | 164 | assert attr_data == b"\x00\x00%d\x00\x00\x00\x00\x00" |
130 | 165 |
|
131 | 166 |
|
| 167 | +async def test_frient_emi_current_summation_write_request(zigpy_device_from_v2_quirk): |
| 168 | + """Test EMIZB-141 forwards current summation write as a mfg-specific write.""" |
| 169 | + device = zigpy_device_from_v2_quirk( |
| 170 | + "frient A/S", |
| 171 | + "EMIZB-141", |
| 172 | + cluster_ids={2: {Metering.cluster_id: ClusterType.Server}}, |
| 173 | + ) |
| 174 | + |
| 175 | + manufacturer_cluster = device.endpoints[2].in_clusters[0xFD10] |
| 176 | + current_summation_attr_id = manufacturer_cluster.AttributeDefs.current_summation.id |
| 177 | + |
| 178 | + request_patch = mock.patch("zigpy.device.Device.request", mock.AsyncMock()) |
| 179 | + with request_patch as request_mock: |
| 180 | + request_mock.return_value = (foundation.Status.SUCCESS, "done") |
| 181 | + |
| 182 | + await manufacturer_cluster.write_attributes({current_summation_attr_id: 1234}) |
| 183 | + |
| 184 | + assert request_mock.call_count == 1 |
| 185 | + assert request_mock.call_args[0] == () |
| 186 | + assert request_mock.call_args[1]["cluster"] == Metering.cluster_id |
| 187 | + assert ( |
| 188 | + request_mock.call_args[1]["data"] |
| 189 | + == b"\x04\xd2\x04\x01\x02\x01\x03%\xd2\x04\x00\x00\x00\x00" |
| 190 | + ) |
| 191 | + |
| 192 | + zcl_header, attr_data = foundation.ZCLHeader.deserialize( |
| 193 | + request_mock.call_args[1]["data"] |
| 194 | + ) |
| 195 | + assert ( |
| 196 | + zcl_header.frame_control.frame_type == foundation.FrameType.GLOBAL_COMMAND |
| 197 | + ) |
| 198 | + assert zcl_header.frame_control.is_manufacturer_specific == 1 |
| 199 | + assert zcl_header.manufacturer == 1234 |
| 200 | + assert zcl_header.command_id == foundation.GeneralCommand.Write_Attributes |
| 201 | + assert attr_data == b"\x01\x03%\xd2\x04\x00\x00\x00\x00" |
| 202 | + |
| 203 | + |
132 | 204 | async def test_mfg_cluster_events(zigpy_device_from_v2_quirk): |
133 | 205 | """Test Frient EMI Norwegian HAN ignoring incorrect divisor attribute reports.""" |
134 | 206 | device = zigpy_device_from_v2_quirk("frient A/S", "EMIZB-132", endpoint_ids=[1, 2]) |
|
0 commit comments