From a8b68dc4f94e32036211ff69cd5c6ab21279af35 Mon Sep 17 00:00:00 2001 From: Samantha Date: Tue, 29 Sep 2020 20:25:05 +0100 Subject: [PATCH] Add Neighbors & Endpoint Names to zha/devices reply (#40748) * Add Neighbors & Endpoint Names to zha/devices reply. * Remove unused const * Add tests & correct const name. * Change tests to use corresponding enum device_type --- homeassistant/components/zha/core/const.py | 2 + homeassistant/components/zha/core/device.py | 42 +++++++++++++++++++++ tests/components/zha/common.py | 1 + tests/components/zha/test_api.py | 4 ++ tests/components/zha/test_binary_sensor.py | 5 ++- tests/components/zha/test_channels.py | 7 +++- tests/components/zha/test_cover.py | 9 +++-- tests/components/zha/test_device.py | 13 ++++++- tests/components/zha/test_device_action.py | 3 +- tests/components/zha/test_device_trigger.py | 3 +- tests/components/zha/test_discover.py | 9 +++-- tests/components/zha/test_fan.py | 6 ++- tests/components/zha/test_gateway.py | 2 +- tests/components/zha/test_light.py | 6 +-- tests/components/zha/test_sensor.py | 7 ++-- tests/components/zha/test_switch.py | 2 +- 16 files changed, 97 insertions(+), 24 deletions(-) diff --git a/homeassistant/components/zha/core/const.py b/homeassistant/components/zha/core/const.py index 402c1505415..22f8f0f261d 100644 --- a/homeassistant/components/zha/core/const.py +++ b/homeassistant/components/zha/core/const.py @@ -35,6 +35,7 @@ ATTR_COMMAND_TYPE = "command_type" ATTR_DEVICE_IEEE = "device_ieee" ATTR_DEVICE_TYPE = "device_type" ATTR_ENDPOINTS = "endpoints" +ATTR_ENDPOINT_NAMES = "endpoint_names" ATTR_ENDPOINT_ID = "endpoint_id" ATTR_IEEE = "ieee" ATTR_IN_CLUSTERS = "in_clusters" @@ -46,6 +47,7 @@ ATTR_MANUFACTURER_CODE = "manufacturer_code" ATTR_MEMBERS = "members" ATTR_MODEL = "model" ATTR_NAME = "name" +ATTR_NEIGHBORS = "neighbors" ATTR_NODE_DESCRIPTOR = "node_descriptor" ATTR_NWK = "nwk" ATTR_OUT_CLUSTERS = "out_clusters" diff --git a/homeassistant/components/zha/core/device.py b/homeassistant/components/zha/core/device.py index b8229793a48..04054ebdd05 100644 --- a/homeassistant/components/zha/core/device.py +++ b/homeassistant/components/zha/core/device.py @@ -33,6 +33,7 @@ from .const import ( ATTR_DEVICE_IEEE, ATTR_DEVICE_TYPE, ATTR_ENDPOINT_ID, + ATTR_ENDPOINT_NAMES, ATTR_ENDPOINTS, ATTR_IEEE, ATTR_LAST_SEEN, @@ -41,6 +42,7 @@ from .const import ( ATTR_MANUFACTURER_CODE, ATTR_MODEL, ATTR_NAME, + ATTR_NEIGHBORS, ATTR_NODE_DESCRIPTOR, ATTR_NWK, ATTR_POWER_SOURCE, @@ -436,6 +438,46 @@ class ZHADevice(LogMixin): } for entity_ref in self.gateway.device_registry[self.ieee] ] + + # Return the neighbor information + device_info[ATTR_NEIGHBORS] = [ + { + "device_type": neighbor.neighbor.device_type.name, + "rx_on_when_idle": neighbor.neighbor.rx_on_when_idle.name, + "relationship": neighbor.neighbor.relationship.name, + "extended_pan_id": str(neighbor.neighbor.extended_pan_id), + "ieee": str(neighbor.neighbor.ieee), + "nwk": str(neighbor.neighbor.nwk), + "permit_joining": neighbor.neighbor.permit_joining.name, + "depth": str(neighbor.neighbor.depth), + "lqi": str(neighbor.neighbor.lqi), + } + for neighbor in self._zigpy_device.neighbors + ] + + # Return endpoint device type Names + try: + device_info[ATTR_ENDPOINT_NAMES] = [ + { + "name": endpoint.device_type.name, + } + for (ep_id, endpoint) in self._zigpy_device.endpoints.items() + if ep_id != 0 + and endpoint.profile_id in (zha.PROFILE_ID, zll.PROFILE_ID) + ] + except AttributeError as ex: + # Some device types are not using an enumeration + self.warning( + "Failed to identify endpoint name in '%s' with exception '%s'", + self._zigpy_device.endpoints.items(), + ex, + ) + device_info[ATTR_ENDPOINT_NAMES] = [ + { + "name": "unknown", + } + ] + reg_device = self.gateway.ha_device_registry.async_get(self.device_id) if reg_device is not None: device_info["user_given_name"] = reg_device.name_by_user diff --git a/tests/components/zha/common.py b/tests/components/zha/common.py index 82799e8dd9d..11f390b202e 100644 --- a/tests/components/zha/common.py +++ b/tests/components/zha/common.py @@ -108,6 +108,7 @@ class FakeDevice: if node_desc is None: node_desc = b"\x02@\x807\x10\x7fd\x00\x00*d\x00\x00" self.node_desc = zigpy.zdo.types.NodeDescriptor.deserialize(node_desc)[0] + self.neighbors = [] FakeDevice.add_to_group = zigpy_dev.add_to_group diff --git a/tests/components/zha/test_api.py b/tests/components/zha/test_api.py index b67891d7cbb..53861bc0d9a 100644 --- a/tests/components/zha/test_api.py +++ b/tests/components/zha/test_api.py @@ -23,10 +23,12 @@ from homeassistant.components.zha.core.const import ( ATTR_CLUSTER_ID, ATTR_CLUSTER_TYPE, ATTR_ENDPOINT_ID, + ATTR_ENDPOINT_NAMES, ATTR_IEEE, ATTR_MANUFACTURER, ATTR_MODEL, ATTR_NAME, + ATTR_NEIGHBORS, ATTR_QUIRK_APPLIED, CLUSTER_TYPE_IN, DATA_ZHA, @@ -184,6 +186,8 @@ async def test_list_devices(zha_client): assert device[ATTR_NAME] is not None assert device[ATTR_QUIRK_APPLIED] is not None assert device["entities"] is not None + assert device[ATTR_NEIGHBORS] is not None + assert device[ATTR_ENDPOINT_NAMES] is not None for entity_reference in device["entities"]: assert entity_reference[ATTR_NAME] is not None diff --git a/tests/components/zha/test_binary_sensor.py b/tests/components/zha/test_binary_sensor.py index afa86e90f2c..7a2217521ad 100644 --- a/tests/components/zha/test_binary_sensor.py +++ b/tests/components/zha/test_binary_sensor.py @@ -1,5 +1,6 @@ """Test zha binary sensor.""" import pytest +import zigpy.profiles.zha import zigpy.zcl.clusters.measurement as measurement import zigpy.zcl.clusters.security as security @@ -15,7 +16,7 @@ from .common import ( DEVICE_IAS = { 1: { - "device_type": 1026, + "device_type": zigpy.profiles.zha.DeviceType.IAS_ZONE, "in_clusters": [security.IasZone.cluster_id], "out_clusters": [], } @@ -24,7 +25,7 @@ DEVICE_IAS = { DEVICE_OCCUPANCY = { 1: { - "device_type": 263, + "device_type": zigpy.profiles.zha.DeviceType.OCCUPANCY_SENSOR, "in_clusters": [measurement.OccupancySensing.cluster_id], "out_clusters": [], } diff --git a/tests/components/zha/test_channels.py b/tests/components/zha/test_channels.py index 471e44f8409..8a6d934d373 100644 --- a/tests/components/zha/test_channels.py +++ b/tests/components/zha/test_channels.py @@ -3,6 +3,7 @@ import asyncio from unittest import mock import pytest +import zigpy.profiles.zha import zigpy.types as t import zigpy.zcl.clusters @@ -286,7 +287,11 @@ def test_ep_channels_all_channels(m1, zha_device_mock): """Test EndpointChannels adding all channels.""" zha_device = zha_device_mock( { - 1: {"in_clusters": [0, 1, 6, 8], "out_clusters": [], "device_type": 0x0000}, + 1: { + "in_clusters": [0, 1, 6, 8], + "out_clusters": [], + "device_type": zigpy.profiles.zha.DeviceType.ON_OFF_SWITCH, + }, 2: { "in_clusters": [0, 1, 6, 8, 768], "out_clusters": [], diff --git a/tests/components/zha/test_cover.py b/tests/components/zha/test_cover.py index c6c0e74050d..b295543b3e8 100644 --- a/tests/components/zha/test_cover.py +++ b/tests/components/zha/test_cover.py @@ -2,6 +2,7 @@ import asyncio import pytest +import zigpy.profiles.zha import zigpy.types import zigpy.zcl.clusters.closures as closures import zigpy.zcl.clusters.general as general @@ -41,7 +42,7 @@ def zigpy_cover_device(zigpy_device_mock): endpoints = { 1: { - "device_type": 1026, + "device_type": zigpy.profiles.zha.DeviceType.IAS_ZONE, "in_clusters": [closures.WindowCovering.cluster_id], "out_clusters": [], } @@ -55,7 +56,7 @@ def zigpy_cover_remote(zigpy_device_mock): endpoints = { 1: { - "device_type": 0x0203, + "device_type": zigpy.profiles.zha.DeviceType.WINDOW_COVERING_CONTROLLER, "in_clusters": [], "out_clusters": [closures.WindowCovering.cluster_id], } @@ -69,7 +70,7 @@ def zigpy_shade_device(zigpy_device_mock): endpoints = { 1: { - "device_type": 512, + "device_type": zigpy.profiles.zha.DeviceType.SHADE, "in_clusters": [ closures.Shade.cluster_id, general.LevelControl.cluster_id, @@ -87,7 +88,7 @@ def zigpy_keen_vent(zigpy_device_mock): endpoints = { 1: { - "device_type": 3, + "device_type": zigpy.profiles.zha.DeviceType.LEVEL_CONTROLLABLE_OUTPUT, "in_clusters": [general.LevelControl.cluster_id, general.OnOff.cluster_id], "out_clusters": [], } diff --git a/tests/components/zha/test_device.py b/tests/components/zha/test_device.py index 83a57f1fabf..1cc9fb27d89 100644 --- a/tests/components/zha/test_device.py +++ b/tests/components/zha/test_device.py @@ -4,6 +4,7 @@ import time from unittest import mock import pytest +import zigpy.profiles.zha import zigpy.zcl.clusters.general as general import homeassistant.components.zha.core.device as zha_core_device @@ -27,7 +28,11 @@ def zigpy_device(zigpy_device_mock): in_clusters.append(general.Basic.cluster_id) endpoints = { - 3: {"in_clusters": in_clusters, "out_clusters": [], "device_type": 0} + 3: { + "in_clusters": in_clusters, + "out_clusters": [], + "device_type": zigpy.profiles.zha.DeviceType.ON_OFF_SWITCH, + } } return zigpy_device_mock(endpoints) @@ -44,7 +49,11 @@ def zigpy_device_mains(zigpy_device_mock): in_clusters.append(general.Basic.cluster_id) endpoints = { - 3: {"in_clusters": in_clusters, "out_clusters": [], "device_type": 0} + 3: { + "in_clusters": in_clusters, + "out_clusters": [], + "device_type": zigpy.profiles.zha.DeviceType.ON_OFF_SWITCH, + } } return zigpy_device_mock( endpoints, node_descriptor=b"\x02@\x84_\x11\x7fd\x00\x00,d\x00\x00" diff --git a/tests/components/zha/test_device_action.py b/tests/components/zha/test_device_action.py index 40e64934f89..de3a4eb1296 100644 --- a/tests/components/zha/test_device_action.py +++ b/tests/components/zha/test_device_action.py @@ -2,6 +2,7 @@ from unittest.mock import patch import pytest +import zigpy.profiles.zha import zigpy.zcl.clusters.general as general import zigpy.zcl.clusters.security as security import zigpy.zcl.foundation as zcl_f @@ -31,7 +32,7 @@ async def device_ias(hass, zigpy_device_mock, zha_device_joined_restored): 1: { "in_clusters": [c.cluster_id for c in clusters], "out_clusters": [general.OnOff.cluster_id], - "device_type": 0, + "device_type": zigpy.profiles.zha.DeviceType.ON_OFF_SWITCH, } }, ) diff --git a/tests/components/zha/test_device_trigger.py b/tests/components/zha/test_device_trigger.py index e0a73903e0d..801b6831379 100644 --- a/tests/components/zha/test_device_trigger.py +++ b/tests/components/zha/test_device_trigger.py @@ -3,6 +3,7 @@ from datetime import timedelta import time import pytest +import zigpy.profiles.zha import zigpy.zcl.clusters.general as general import homeassistant.components.automation as automation @@ -58,7 +59,7 @@ async def mock_devices(hass, zigpy_device_mock, zha_device_joined_restored): 1: { "in_clusters": [general.Basic.cluster_id], "out_clusters": [general.OnOff.cluster_id], - "device_type": 0, + "device_type": zigpy.profiles.zha.DeviceType.ON_OFF_SWITCH, } } ) diff --git a/tests/components/zha/test_discover.py b/tests/components/zha/test_discover.py index 0cd8c58e49f..5589a7d94ac 100644 --- a/tests/components/zha/test_discover.py +++ b/tests/components/zha/test_discover.py @@ -4,6 +4,7 @@ import re from unittest import mock import pytest +import zigpy.profiles.zha import zigpy.quirks import zigpy.types import zigpy.zcl.clusters.closures @@ -163,9 +164,9 @@ def test_discover_entities(m1, m2): @pytest.mark.parametrize( "device_type, component, hit", [ - (0x0100, zha_const.LIGHT, True), - (0x0108, zha_const.SWITCH, True), - (0x0051, zha_const.SWITCH, True), + (zigpy.profiles.zha.DeviceType.ON_OFF_LIGHT, zha_const.LIGHT, True), + (zigpy.profiles.zha.DeviceType.ON_OFF_BALLAST, zha_const.SWITCH, True), + (zigpy.profiles.zha.DeviceType.SMART_PLUG, zha_const.SWITCH, True), (0xFFFF, None, False), ], ) @@ -379,7 +380,7 @@ async def test_device_override( zigpy_device = zigpy_device_mock( { 1: { - "device_type": 258, + "device_type": zigpy.profiles.zha.DeviceType.COLOR_DIMMABLE_LIGHT, "endpoint_id": 1, "in_clusters": [0, 3, 4, 5, 6, 8, 768, 2821, 64513], "out_clusters": [25], diff --git a/tests/components/zha/test_fan.py b/tests/components/zha/test_fan.py index b163edbd49a..b12b9249373 100644 --- a/tests/components/zha/test_fan.py +++ b/tests/components/zha/test_fan.py @@ -43,7 +43,11 @@ IEEE_GROUPABLE_DEVICE2 = "02:2d:6f:00:0a:90:69:e8" def zigpy_device(zigpy_device_mock): """Device tracker zigpy device.""" endpoints = { - 1: {"in_clusters": [hvac.Fan.cluster_id], "out_clusters": [], "device_type": 0} + 1: { + "in_clusters": [hvac.Fan.cluster_id], + "out_clusters": [], + "device_type": zha.DeviceType.ON_OFF_SWITCH, + } } return zigpy_device_mock(endpoints) diff --git a/tests/components/zha/test_gateway.py b/tests/components/zha/test_gateway.py index cc9e811cb49..718c7cdba19 100644 --- a/tests/components/zha/test_gateway.py +++ b/tests/components/zha/test_gateway.py @@ -28,7 +28,7 @@ def zigpy_dev_basic(zigpy_device_mock): 1: { "in_clusters": [general.Basic.cluster_id], "out_clusters": [], - "device_type": 0, + "device_type": zha.DeviceType.ON_OFF_SWITCH, } } ) diff --git a/tests/components/zha/test_light.py b/tests/components/zha/test_light.py index bd340445527..642504384cc 100644 --- a/tests/components/zha/test_light.py +++ b/tests/components/zha/test_light.py @@ -34,7 +34,7 @@ IEEE_GROUPABLE_DEVICE3 = "03:2d:6f:00:0a:90:69:e7" LIGHT_ON_OFF = { 1: { - "device_type": zigpy.profiles.zha.DeviceType.ON_OFF_LIGHT, + "device_type": zha.DeviceType.ON_OFF_LIGHT, "in_clusters": [ general.Basic.cluster_id, general.Identify.cluster_id, @@ -46,7 +46,7 @@ LIGHT_ON_OFF = { LIGHT_LEVEL = { 1: { - "device_type": zigpy.profiles.zha.DeviceType.DIMMABLE_LIGHT, + "device_type": zha.DeviceType.DIMMABLE_LIGHT, "in_clusters": [ general.Basic.cluster_id, general.LevelControl.cluster_id, @@ -58,7 +58,7 @@ LIGHT_LEVEL = { LIGHT_COLOR = { 1: { - "device_type": zigpy.profiles.zha.DeviceType.COLOR_DIMMABLE_LIGHT, + "device_type": zha.DeviceType.COLOR_DIMMABLE_LIGHT, "in_clusters": [ general.Basic.cluster_id, general.Identify.cluster_id, diff --git a/tests/components/zha/test_sensor.py b/tests/components/zha/test_sensor.py index 50ea430d1cc..8d854894ba0 100644 --- a/tests/components/zha/test_sensor.py +++ b/tests/components/zha/test_sensor.py @@ -2,6 +2,7 @@ from unittest import mock import pytest +import zigpy.profiles.zha import zigpy.zcl.clusters.general as general import zigpy.zcl.clusters.homeautomation as homeautomation import zigpy.zcl.clusters.measurement as measurement @@ -122,7 +123,7 @@ async def test_sensor( 1: { "in_clusters": [cluster_id, general.Basic.cluster_id], "out_cluster": [], - "device_type": 0x0000, + "device_type": zigpy.profiles.zha.DeviceType.ON_OFF_SWITCH, } } ) @@ -242,7 +243,7 @@ async def test_temp_uom( general.Basic.cluster_id, ], "out_cluster": [], - "device_type": 0x0000, + "device_type": zigpy.profiles.zha.DeviceType.ON_OFF_SWITCH, } } ) @@ -282,7 +283,7 @@ async def test_electrical_measurement_init( 1: { "in_clusters": [cluster_id, general.Basic.cluster_id], "out_cluster": [], - "device_type": 0x0000, + "device_type": zigpy.profiles.zha.DeviceType.ON_OFF_SWITCH, } } ) diff --git a/tests/components/zha/test_switch.py b/tests/components/zha/test_switch.py index b1c0c643bbc..aab8dafef4f 100644 --- a/tests/components/zha/test_switch.py +++ b/tests/components/zha/test_switch.py @@ -33,7 +33,7 @@ def zigpy_device(zigpy_device_mock): 1: { "in_clusters": [general.Basic.cluster_id, general.OnOff.cluster_id], "out_clusters": [], - "device_type": 0, + "device_type": zha.DeviceType.ON_OFF_SWITCH, } } return zigpy_device_mock(endpoints)