Home Assistant Unofficial Reference 2024.12.1
silabs_multiprotocol.py
Go to the documentation of this file.
1 """Silicon Labs Multiprotocol support."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable, Coroutine
6 from functools import wraps
7 import logging
8 from typing import TYPE_CHECKING, Any, Concatenate
9 
10 import aiohttp
11 from python_otbr_api import tlv_parser
12 from python_otbr_api.tlv_parser import MeshcopTLVType
13 
15  is_multiprotocol_url,
16 )
17 from homeassistant.components.thread import async_add_dataset
18 from homeassistant.core import HomeAssistant
19 from homeassistant.exceptions import HomeAssistantError
20 
21 from .const import DOMAIN
22 from .util import OTBRData
23 
24 if TYPE_CHECKING:
25  from . import OTBRConfigEntry
26 
27 _LOGGER = logging.getLogger(__name__)
28 
29 
30 def async_get_otbr_data[**_P, _R, _R_Def](
31  retval: _R_Def,
32 ) -> Callable[
33  [Callable[Concatenate[HomeAssistant, OTBRData, _P], Coroutine[Any, Any, _R]]],
34  Callable[Concatenate[HomeAssistant, _P], Coroutine[Any, Any, _R | _R_Def]],
35 ]:
36  """Decorate function to get OTBR data."""
37 
38  def _async_get_otbr_data(
39  orig_func: Callable[
40  Concatenate[HomeAssistant, OTBRData, _P],
41  Coroutine[Any, Any, _R],
42  ],
43  ) -> Callable[Concatenate[HomeAssistant, _P], Coroutine[Any, Any, _R | _R_Def]]:
44  """Decorate function to get OTBR data."""
45 
46  @wraps(orig_func)
47  async def async_get_otbr_data_wrapper(
48  hass: HomeAssistant, *args: _P.args, **kwargs: _P.kwargs
49  ) -> _R | _R_Def:
50  """Fetch OTBR data and pass to orig_func."""
51  config_entry: OTBRConfigEntry
52  for config_entry in hass.config_entries.async_loaded_entries(DOMAIN):
53  data = config_entry.runtime_data
54  if is_multiprotocol_url(data.url):
55  return await orig_func(hass, data, *args, **kwargs)
56 
57  return retval
58 
59  return async_get_otbr_data_wrapper
60 
61  return _async_get_otbr_data
62 
63 
64 @async_get_otbr_data(None)
66  hass: HomeAssistant,
67  data: OTBRData,
68  channel: int,
69  delay: float,
70 ) -> None:
71  """Set the channel to be used.
72 
73  Does nothing if not configured.
74  """
75  await data.set_channel(channel, delay)
76 
77  # Import the new dataset
78  dataset_tlvs = await data.get_pending_dataset_tlvs()
79  if dataset_tlvs is None:
80  # The activation timer may have expired already
81  dataset_tlvs = await data.get_active_dataset_tlvs()
82  if dataset_tlvs is None:
83  # Don't try to import a None dataset
84  return
85 
86  dataset = tlv_parser.parse_tlv(dataset_tlvs.hex())
87  dataset.pop(MeshcopTLVType.DELAYTIMER, None)
88  dataset.pop(MeshcopTLVType.PENDINGTIMESTAMP, None)
89  dataset_tlvs_str = tlv_parser.encode_tlv(dataset)
90  await async_add_dataset(hass, DOMAIN, dataset_tlvs_str)
91 
92 
93 @async_get_otbr_data(None)
94 async def async_get_channel(hass: HomeAssistant, data: OTBRData) -> int | None:
95  """Return the channel.
96 
97  Returns None if not configured.
98  """
99  try:
100  dataset = await data.get_active_dataset()
101  except (
102  HomeAssistantError,
103  aiohttp.ClientError,
104  TimeoutError,
105  ) as err:
106  _LOGGER.warning("Failed to communicate with OTBR %s", err)
107  return None
108 
109  if dataset is None:
110  return None
111 
112  return dataset.channel
113 
114 
115 @async_get_otbr_data(False)
116 async def async_using_multipan(hass: HomeAssistant, data: OTBRData) -> bool:
117  """Return if the multiprotocol device is used.
118 
119  Returns False if not configured.
120  """
121  return True
int|None async_get_channel(HomeAssistant hass, OTBRData data)
None async_change_channel(HomeAssistant hass, OTBRData data, int channel, float delay)
bool async_using_multipan(HomeAssistant hass, OTBRData data)
Callable[[HomeAssistant, websocket_api.ActiveConnection, dict], Coroutine[Any, Any, None]] async_get_otbr_data(Callable[[HomeAssistant, websocket_api.ActiveConnection, dict, OTBRData], Coroutine[Any, Any, None],] orig_func)
None async_add_dataset(HomeAssistant hass, str source, str tlv, *str|None preferred_border_agent_id=None, str|None preferred_extended_address=None)