Home Assistant Unofficial Reference 2024.12.1
helpers.py
Go to the documentation of this file.
1 """Provide integration helpers that are aware of the matter integration."""
2 
3 from __future__ import annotations
4 
5 import asyncio
6 from dataclasses import dataclass
7 from typing import TYPE_CHECKING
8 
9 from homeassistant.core import HomeAssistant, callback
10 from homeassistant.exceptions import HomeAssistantError
11 from homeassistant.helpers import device_registry as dr
12 
13 from .const import DOMAIN, ID_TYPE_DEVICE_ID
14 
15 if TYPE_CHECKING:
16  from matter_server.client.models.node import MatterEndpoint, MatterNode
17  from matter_server.common.models import ServerInfoMessage
18 
19  from .adapter import MatterAdapter
20 
21 
23  """Exception raised when we can't find a node."""
24 
25 
26 @dataclass
28  """Hold Matter data for the config entry."""
29 
30  adapter: MatterAdapter
31  listen_task: asyncio.Task
32 
33 
34 @callback
35 def get_matter(hass: HomeAssistant) -> MatterAdapter:
36  """Return MatterAdapter instance."""
37  # NOTE: This assumes only one Matter connection/fabric can exist.
38  # Shall we support connecting to multiple servers in the client or by
39  # config entries? In case of the config entry we need to fix this.
40  matter_entry_data: MatterEntryData = next(iter(hass.data[DOMAIN].values()))
41  return matter_entry_data.adapter
42 
43 
45  server_info: ServerInfoMessage,
46  node: MatterNode,
47 ) -> str:
48  """Return `Operational Instance Name` for given MatterNode."""
49  fabric_id_hex = f"{server_info.compressed_fabric_id:016X}"
50  node_id_hex = f"{node.node_id:016X}"
51  # Operational instance id matches the mDNS advertisement for the node
52  # this is the recommended ID to recognize a unique matter node (within a fabric).
53  return f"{fabric_id_hex}-{node_id_hex}"
54 
55 
57  server_info: ServerInfoMessage,
58  endpoint: MatterEndpoint,
59 ) -> str:
60  """Return HA device_id for the given MatterEndpoint."""
61  operational_instance_id = get_operational_instance_id(server_info, endpoint.node)
62  # if this is a composed device we need to get the compose parent
63  # example: Philips Hue motion sensor on Hue Hub (bridged to Matter)
64  if compose_parent := endpoint.node.get_compose_parent(endpoint.endpoint_id):
65  endpoint = compose_parent
66  if endpoint.is_bridged_device:
67  # Append endpoint ID if this endpoint is a bridged device
68  postfix = str(endpoint.endpoint_id)
69  else:
70  # this should be compatible with previous versions
71  postfix = "MatterNodeDevice"
72  return f"{operational_instance_id}-{postfix}"
73 
74 
75 @callback
76 def node_from_ha_device_id(hass: HomeAssistant, ha_device_id: str) -> MatterNode | None:
77  """Get node id from ha device id."""
78  dev_reg = dr.async_get(hass)
79  device = dev_reg.async_get(ha_device_id)
80  if device is None:
81  raise MissingNode(f"Invalid device ID: {ha_device_id}")
82  return get_node_from_device_entry(hass, device)
83 
84 
85 @callback
87  hass: HomeAssistant, device: dr.DeviceEntry
88 ) -> MatterNode | None:
89  """Return MatterNode from device entry."""
90  matter = get_matter(hass)
91  device_id_type_prefix = f"{ID_TYPE_DEVICE_ID}_"
92  device_id_full = next(
93  (
94  identifier[1]
95  for identifier in device.identifiers
96  if identifier[0] == DOMAIN
97  and identifier[1].startswith(device_id_type_prefix)
98  ),
99  None,
100  )
101 
102  if device_id_full is None:
103  return None
104 
105  device_id = device_id_full.lstrip(device_id_type_prefix)
106  matter_client = matter.matter_client
107  server_info = matter_client.server_info
108 
109  if server_info is None:
110  raise RuntimeError("Matter server information is not available")
111 
112  return next(
113  (
114  node
115  for node in matter_client.get_nodes()
116  for endpoint in node.endpoints.values()
117  if get_device_id(server_info, endpoint) == device_id
118  ),
119  None,
120  )
MatterAdapter get_matter(HomeAssistant hass)
Definition: helpers.py:35
str get_operational_instance_id(ServerInfoMessage server_info, MatterNode node)
Definition: helpers.py:47
MatterNode|None node_from_ha_device_id(HomeAssistant hass, str ha_device_id)
Definition: helpers.py:76
str get_device_id(ServerInfoMessage server_info, MatterEndpoint endpoint)
Definition: helpers.py:59
MatterNode|None get_node_from_device_entry(HomeAssistant hass, dr.DeviceEntry device)
Definition: helpers.py:88