diff --git a/homeassistant/components/matter/adapter.py b/homeassistant/components/matter/adapter.py index a3536435ded..d7a9f398c9f 100644 --- a/homeassistant/components/matter/adapter.py +++ b/homeassistant/components/matter/adapter.py @@ -4,7 +4,9 @@ from __future__ import annotations from typing import TYPE_CHECKING, cast +from chip.clusters.Objects import GeneralDiagnostics from matter_server.client.models.device_types import BridgedDevice +from matter_server.common.helpers.util import convert_mac_address from matter_server.common.models import EventType, ServerInfoMessage from homeassistant.config_entries import ConfigEntry @@ -22,6 +24,30 @@ if TYPE_CHECKING: from matter_server.client.models.node import MatterEndpoint, MatterNode +def get_connections_for_endpoint(endpoint: MatterEndpoint) -> set[tuple[str, str]]: + """Return a set of connections for a MatterEndpoint.""" + network_interfaces: list[GeneralDiagnostics.Structs.NetworkInterface] = ( + endpoint.get_attribute_value( + None, GeneralDiagnostics.Attributes.NetworkInterfaces + ) + or [] + ) + + hardware_addresses: set[str] = { + convert_mac_address(network_interface.hardwareAddress) + for network_interface in network_interfaces + if network_interface.hardwareAddress + } + + return { + (dr.CONNECTION_NETWORK_MAC, address) + if len(address) == 17 + else (dr.CONNECTION_ZIGBEE, address) + for address in hardware_addresses + if len(address) in (17, 23) # EUI-48 -> 17, EUI-64 -> 23 + } + + def get_clean_name(name: str | None) -> str | None: """Strip spaces and null char from the name.""" if name is None: @@ -185,6 +211,9 @@ class MatterAdapter: endpoint, ) identifiers = {(DOMAIN, f"{ID_TYPE_DEVICE_ID}_{node_device_id}")} + + connections = get_connections_for_endpoint(endpoint) + serial_number: str | None = None # if available, we also add the serialnumber as identifier if ( @@ -203,6 +232,7 @@ class MatterAdapter: name=name, config_entry_id=self.config_entry.entry_id, identifiers=identifiers, + connections=connections, hw_version=basic_info.hardwareVersionString, sw_version=basic_info.softwareVersionString, manufacturer=basic_info.vendorName or endpoint.node.device_info.vendorName, diff --git a/tests/components/matter/test_adapter.py b/tests/components/matter/test_adapter.py index da2ef179c44..dfe23f0ad70 100644 --- a/tests/components/matter/test_adapter.py +++ b/tests/components/matter/test_adapter.py @@ -187,6 +187,60 @@ async def test_device_registry_single_node_composed_device( assert len(dev_reg.devices) == 1 +async def test_device_registry_single_node_with_connection( + hass: HomeAssistant, + device_registry: dr.DeviceRegistry, + matter_client: MagicMock, +) -> None: + """Test that a device with mac address adds a connection to the HA device entry.""" + await setup_integration_with_node_fixture( + hass, + "thermostat", + matter_client, + ) + + assert device_registry.async_get_device(connections={("mac", "DC:54:75:5F:BA:AC")}) + + +async def test_device_registry_single_node_without_mac_address_has_no_mac_connection( + hass: HomeAssistant, + device_registry: dr.DeviceRegistry, + matter_client: MagicMock, +) -> None: + """Test that a device without mac address doesn't have a `mac` connection in the HA device entry.""" + await setup_integration_with_node_fixture( + hass, + "temperature-sensor", + matter_client, + ) + + entry = device_registry.async_get_device( + identifiers={ + (DOMAIN, "deviceid_00000000000004D2-0000000000000001-MatterNodeDevice") + } + ) + + for connection_type, _ in entry.connections: + assert connection_type != dr.CONNECTION_NETWORK_MAC + + +async def test_device_registry_node_with_EUI64_address( + hass: HomeAssistant, + device_registry: dr.DeviceRegistry, + matter_client: MagicMock, +) -> None: + """Test that a device with a mac address has a `zigbee` connection in the HA device entry.""" + await setup_integration_with_node_fixture( + hass, + "eve-energy-plug", + matter_client, + ) + + assert device_registry.async_get_device( + connections={("zigbee", "ca:6b:4a:23:f6:f8:bb:ee")} + ) + + async def test_multi_endpoint_name( hass: HomeAssistant, matter_client: MagicMock,