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
This commit is contained in:
Samantha 2020-09-29 20:25:05 +01:00 committed by GitHub
parent a2d2b7842d
commit a8b68dc4f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 97 additions and 24 deletions

View file

@ -35,6 +35,7 @@ ATTR_COMMAND_TYPE = "command_type"
ATTR_DEVICE_IEEE = "device_ieee" ATTR_DEVICE_IEEE = "device_ieee"
ATTR_DEVICE_TYPE = "device_type" ATTR_DEVICE_TYPE = "device_type"
ATTR_ENDPOINTS = "endpoints" ATTR_ENDPOINTS = "endpoints"
ATTR_ENDPOINT_NAMES = "endpoint_names"
ATTR_ENDPOINT_ID = "endpoint_id" ATTR_ENDPOINT_ID = "endpoint_id"
ATTR_IEEE = "ieee" ATTR_IEEE = "ieee"
ATTR_IN_CLUSTERS = "in_clusters" ATTR_IN_CLUSTERS = "in_clusters"
@ -46,6 +47,7 @@ ATTR_MANUFACTURER_CODE = "manufacturer_code"
ATTR_MEMBERS = "members" ATTR_MEMBERS = "members"
ATTR_MODEL = "model" ATTR_MODEL = "model"
ATTR_NAME = "name" ATTR_NAME = "name"
ATTR_NEIGHBORS = "neighbors"
ATTR_NODE_DESCRIPTOR = "node_descriptor" ATTR_NODE_DESCRIPTOR = "node_descriptor"
ATTR_NWK = "nwk" ATTR_NWK = "nwk"
ATTR_OUT_CLUSTERS = "out_clusters" ATTR_OUT_CLUSTERS = "out_clusters"

View file

@ -33,6 +33,7 @@ from .const import (
ATTR_DEVICE_IEEE, ATTR_DEVICE_IEEE,
ATTR_DEVICE_TYPE, ATTR_DEVICE_TYPE,
ATTR_ENDPOINT_ID, ATTR_ENDPOINT_ID,
ATTR_ENDPOINT_NAMES,
ATTR_ENDPOINTS, ATTR_ENDPOINTS,
ATTR_IEEE, ATTR_IEEE,
ATTR_LAST_SEEN, ATTR_LAST_SEEN,
@ -41,6 +42,7 @@ from .const import (
ATTR_MANUFACTURER_CODE, ATTR_MANUFACTURER_CODE,
ATTR_MODEL, ATTR_MODEL,
ATTR_NAME, ATTR_NAME,
ATTR_NEIGHBORS,
ATTR_NODE_DESCRIPTOR, ATTR_NODE_DESCRIPTOR,
ATTR_NWK, ATTR_NWK,
ATTR_POWER_SOURCE, ATTR_POWER_SOURCE,
@ -436,6 +438,46 @@ class ZHADevice(LogMixin):
} }
for entity_ref in self.gateway.device_registry[self.ieee] 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) reg_device = self.gateway.ha_device_registry.async_get(self.device_id)
if reg_device is not None: if reg_device is not None:
device_info["user_given_name"] = reg_device.name_by_user device_info["user_given_name"] = reg_device.name_by_user

View file

@ -108,6 +108,7 @@ class FakeDevice:
if node_desc is None: if node_desc is None:
node_desc = b"\x02@\x807\x10\x7fd\x00\x00*d\x00\x00" node_desc = b"\x02@\x807\x10\x7fd\x00\x00*d\x00\x00"
self.node_desc = zigpy.zdo.types.NodeDescriptor.deserialize(node_desc)[0] self.node_desc = zigpy.zdo.types.NodeDescriptor.deserialize(node_desc)[0]
self.neighbors = []
FakeDevice.add_to_group = zigpy_dev.add_to_group FakeDevice.add_to_group = zigpy_dev.add_to_group

View file

@ -23,10 +23,12 @@ from homeassistant.components.zha.core.const import (
ATTR_CLUSTER_ID, ATTR_CLUSTER_ID,
ATTR_CLUSTER_TYPE, ATTR_CLUSTER_TYPE,
ATTR_ENDPOINT_ID, ATTR_ENDPOINT_ID,
ATTR_ENDPOINT_NAMES,
ATTR_IEEE, ATTR_IEEE,
ATTR_MANUFACTURER, ATTR_MANUFACTURER,
ATTR_MODEL, ATTR_MODEL,
ATTR_NAME, ATTR_NAME,
ATTR_NEIGHBORS,
ATTR_QUIRK_APPLIED, ATTR_QUIRK_APPLIED,
CLUSTER_TYPE_IN, CLUSTER_TYPE_IN,
DATA_ZHA, DATA_ZHA,
@ -184,6 +186,8 @@ async def test_list_devices(zha_client):
assert device[ATTR_NAME] is not None assert device[ATTR_NAME] is not None
assert device[ATTR_QUIRK_APPLIED] is not None assert device[ATTR_QUIRK_APPLIED] is not None
assert device["entities"] 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"]: for entity_reference in device["entities"]:
assert entity_reference[ATTR_NAME] is not None assert entity_reference[ATTR_NAME] is not None

View file

@ -1,5 +1,6 @@
"""Test zha binary sensor.""" """Test zha binary sensor."""
import pytest import pytest
import zigpy.profiles.zha
import zigpy.zcl.clusters.measurement as measurement import zigpy.zcl.clusters.measurement as measurement
import zigpy.zcl.clusters.security as security import zigpy.zcl.clusters.security as security
@ -15,7 +16,7 @@ from .common import (
DEVICE_IAS = { DEVICE_IAS = {
1: { 1: {
"device_type": 1026, "device_type": zigpy.profiles.zha.DeviceType.IAS_ZONE,
"in_clusters": [security.IasZone.cluster_id], "in_clusters": [security.IasZone.cluster_id],
"out_clusters": [], "out_clusters": [],
} }
@ -24,7 +25,7 @@ DEVICE_IAS = {
DEVICE_OCCUPANCY = { DEVICE_OCCUPANCY = {
1: { 1: {
"device_type": 263, "device_type": zigpy.profiles.zha.DeviceType.OCCUPANCY_SENSOR,
"in_clusters": [measurement.OccupancySensing.cluster_id], "in_clusters": [measurement.OccupancySensing.cluster_id],
"out_clusters": [], "out_clusters": [],
} }

View file

@ -3,6 +3,7 @@ import asyncio
from unittest import mock from unittest import mock
import pytest import pytest
import zigpy.profiles.zha
import zigpy.types as t import zigpy.types as t
import zigpy.zcl.clusters import zigpy.zcl.clusters
@ -286,7 +287,11 @@ def test_ep_channels_all_channels(m1, zha_device_mock):
"""Test EndpointChannels adding all channels.""" """Test EndpointChannels adding all channels."""
zha_device = zha_device_mock( 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: { 2: {
"in_clusters": [0, 1, 6, 8, 768], "in_clusters": [0, 1, 6, 8, 768],
"out_clusters": [], "out_clusters": [],

View file

@ -2,6 +2,7 @@
import asyncio import asyncio
import pytest import pytest
import zigpy.profiles.zha
import zigpy.types import zigpy.types
import zigpy.zcl.clusters.closures as closures import zigpy.zcl.clusters.closures as closures
import zigpy.zcl.clusters.general as general import zigpy.zcl.clusters.general as general
@ -41,7 +42,7 @@ def zigpy_cover_device(zigpy_device_mock):
endpoints = { endpoints = {
1: { 1: {
"device_type": 1026, "device_type": zigpy.profiles.zha.DeviceType.IAS_ZONE,
"in_clusters": [closures.WindowCovering.cluster_id], "in_clusters": [closures.WindowCovering.cluster_id],
"out_clusters": [], "out_clusters": [],
} }
@ -55,7 +56,7 @@ def zigpy_cover_remote(zigpy_device_mock):
endpoints = { endpoints = {
1: { 1: {
"device_type": 0x0203, "device_type": zigpy.profiles.zha.DeviceType.WINDOW_COVERING_CONTROLLER,
"in_clusters": [], "in_clusters": [],
"out_clusters": [closures.WindowCovering.cluster_id], "out_clusters": [closures.WindowCovering.cluster_id],
} }
@ -69,7 +70,7 @@ def zigpy_shade_device(zigpy_device_mock):
endpoints = { endpoints = {
1: { 1: {
"device_type": 512, "device_type": zigpy.profiles.zha.DeviceType.SHADE,
"in_clusters": [ "in_clusters": [
closures.Shade.cluster_id, closures.Shade.cluster_id,
general.LevelControl.cluster_id, general.LevelControl.cluster_id,
@ -87,7 +88,7 @@ def zigpy_keen_vent(zigpy_device_mock):
endpoints = { endpoints = {
1: { 1: {
"device_type": 3, "device_type": zigpy.profiles.zha.DeviceType.LEVEL_CONTROLLABLE_OUTPUT,
"in_clusters": [general.LevelControl.cluster_id, general.OnOff.cluster_id], "in_clusters": [general.LevelControl.cluster_id, general.OnOff.cluster_id],
"out_clusters": [], "out_clusters": [],
} }

View file

@ -4,6 +4,7 @@ import time
from unittest import mock from unittest import mock
import pytest import pytest
import zigpy.profiles.zha
import zigpy.zcl.clusters.general as general import zigpy.zcl.clusters.general as general
import homeassistant.components.zha.core.device as zha_core_device 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) in_clusters.append(general.Basic.cluster_id)
endpoints = { 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) return zigpy_device_mock(endpoints)
@ -44,7 +49,11 @@ def zigpy_device_mains(zigpy_device_mock):
in_clusters.append(general.Basic.cluster_id) in_clusters.append(general.Basic.cluster_id)
endpoints = { 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( return zigpy_device_mock(
endpoints, node_descriptor=b"\x02@\x84_\x11\x7fd\x00\x00,d\x00\x00" endpoints, node_descriptor=b"\x02@\x84_\x11\x7fd\x00\x00,d\x00\x00"

View file

@ -2,6 +2,7 @@
from unittest.mock import patch from unittest.mock import patch
import pytest import pytest
import zigpy.profiles.zha
import zigpy.zcl.clusters.general as general import zigpy.zcl.clusters.general as general
import zigpy.zcl.clusters.security as security import zigpy.zcl.clusters.security as security
import zigpy.zcl.foundation as zcl_f import zigpy.zcl.foundation as zcl_f
@ -31,7 +32,7 @@ async def device_ias(hass, zigpy_device_mock, zha_device_joined_restored):
1: { 1: {
"in_clusters": [c.cluster_id for c in clusters], "in_clusters": [c.cluster_id for c in clusters],
"out_clusters": [general.OnOff.cluster_id], "out_clusters": [general.OnOff.cluster_id],
"device_type": 0, "device_type": zigpy.profiles.zha.DeviceType.ON_OFF_SWITCH,
} }
}, },
) )

View file

@ -3,6 +3,7 @@ from datetime import timedelta
import time import time
import pytest import pytest
import zigpy.profiles.zha
import zigpy.zcl.clusters.general as general import zigpy.zcl.clusters.general as general
import homeassistant.components.automation as automation import homeassistant.components.automation as automation
@ -58,7 +59,7 @@ async def mock_devices(hass, zigpy_device_mock, zha_device_joined_restored):
1: { 1: {
"in_clusters": [general.Basic.cluster_id], "in_clusters": [general.Basic.cluster_id],
"out_clusters": [general.OnOff.cluster_id], "out_clusters": [general.OnOff.cluster_id],
"device_type": 0, "device_type": zigpy.profiles.zha.DeviceType.ON_OFF_SWITCH,
} }
} }
) )

View file

@ -4,6 +4,7 @@ import re
from unittest import mock from unittest import mock
import pytest import pytest
import zigpy.profiles.zha
import zigpy.quirks import zigpy.quirks
import zigpy.types import zigpy.types
import zigpy.zcl.clusters.closures import zigpy.zcl.clusters.closures
@ -163,9 +164,9 @@ def test_discover_entities(m1, m2):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"device_type, component, hit", "device_type, component, hit",
[ [
(0x0100, zha_const.LIGHT, True), (zigpy.profiles.zha.DeviceType.ON_OFF_LIGHT, zha_const.LIGHT, True),
(0x0108, zha_const.SWITCH, True), (zigpy.profiles.zha.DeviceType.ON_OFF_BALLAST, zha_const.SWITCH, True),
(0x0051, zha_const.SWITCH, True), (zigpy.profiles.zha.DeviceType.SMART_PLUG, zha_const.SWITCH, True),
(0xFFFF, None, False), (0xFFFF, None, False),
], ],
) )
@ -379,7 +380,7 @@ async def test_device_override(
zigpy_device = zigpy_device_mock( zigpy_device = zigpy_device_mock(
{ {
1: { 1: {
"device_type": 258, "device_type": zigpy.profiles.zha.DeviceType.COLOR_DIMMABLE_LIGHT,
"endpoint_id": 1, "endpoint_id": 1,
"in_clusters": [0, 3, 4, 5, 6, 8, 768, 2821, 64513], "in_clusters": [0, 3, 4, 5, 6, 8, 768, 2821, 64513],
"out_clusters": [25], "out_clusters": [25],

View file

@ -43,7 +43,11 @@ IEEE_GROUPABLE_DEVICE2 = "02:2d:6f:00:0a:90:69:e8"
def zigpy_device(zigpy_device_mock): def zigpy_device(zigpy_device_mock):
"""Device tracker zigpy device.""" """Device tracker zigpy device."""
endpoints = { 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) return zigpy_device_mock(endpoints)

View file

@ -28,7 +28,7 @@ def zigpy_dev_basic(zigpy_device_mock):
1: { 1: {
"in_clusters": [general.Basic.cluster_id], "in_clusters": [general.Basic.cluster_id],
"out_clusters": [], "out_clusters": [],
"device_type": 0, "device_type": zha.DeviceType.ON_OFF_SWITCH,
} }
} }
) )

View file

@ -34,7 +34,7 @@ IEEE_GROUPABLE_DEVICE3 = "03:2d:6f:00:0a:90:69:e7"
LIGHT_ON_OFF = { LIGHT_ON_OFF = {
1: { 1: {
"device_type": zigpy.profiles.zha.DeviceType.ON_OFF_LIGHT, "device_type": zha.DeviceType.ON_OFF_LIGHT,
"in_clusters": [ "in_clusters": [
general.Basic.cluster_id, general.Basic.cluster_id,
general.Identify.cluster_id, general.Identify.cluster_id,
@ -46,7 +46,7 @@ LIGHT_ON_OFF = {
LIGHT_LEVEL = { LIGHT_LEVEL = {
1: { 1: {
"device_type": zigpy.profiles.zha.DeviceType.DIMMABLE_LIGHT, "device_type": zha.DeviceType.DIMMABLE_LIGHT,
"in_clusters": [ "in_clusters": [
general.Basic.cluster_id, general.Basic.cluster_id,
general.LevelControl.cluster_id, general.LevelControl.cluster_id,
@ -58,7 +58,7 @@ LIGHT_LEVEL = {
LIGHT_COLOR = { LIGHT_COLOR = {
1: { 1: {
"device_type": zigpy.profiles.zha.DeviceType.COLOR_DIMMABLE_LIGHT, "device_type": zha.DeviceType.COLOR_DIMMABLE_LIGHT,
"in_clusters": [ "in_clusters": [
general.Basic.cluster_id, general.Basic.cluster_id,
general.Identify.cluster_id, general.Identify.cluster_id,

View file

@ -2,6 +2,7 @@
from unittest import mock from unittest import mock
import pytest import pytest
import zigpy.profiles.zha
import zigpy.zcl.clusters.general as general import zigpy.zcl.clusters.general as general
import zigpy.zcl.clusters.homeautomation as homeautomation import zigpy.zcl.clusters.homeautomation as homeautomation
import zigpy.zcl.clusters.measurement as measurement import zigpy.zcl.clusters.measurement as measurement
@ -122,7 +123,7 @@ async def test_sensor(
1: { 1: {
"in_clusters": [cluster_id, general.Basic.cluster_id], "in_clusters": [cluster_id, general.Basic.cluster_id],
"out_cluster": [], "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, general.Basic.cluster_id,
], ],
"out_cluster": [], "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: { 1: {
"in_clusters": [cluster_id, general.Basic.cluster_id], "in_clusters": [cluster_id, general.Basic.cluster_id],
"out_cluster": [], "out_cluster": [],
"device_type": 0x0000, "device_type": zigpy.profiles.zha.DeviceType.ON_OFF_SWITCH,
} }
} }
) )

View file

@ -33,7 +33,7 @@ def zigpy_device(zigpy_device_mock):
1: { 1: {
"in_clusters": [general.Basic.cluster_id, general.OnOff.cluster_id], "in_clusters": [general.Basic.cluster_id, general.OnOff.cluster_id],
"out_clusters": [], "out_clusters": [],
"device_type": 0, "device_type": zha.DeviceType.ON_OFF_SWITCH,
} }
} }
return zigpy_device_mock(endpoints) return zigpy_device_mock(endpoints)