Home Assistant Unofficial Reference 2024.12.1
discovery.py
Go to the documentation of this file.
1 """The elkm1 integration discovery."""
2 
3 from __future__ import annotations
4 
5 import asyncio
6 from dataclasses import asdict
7 import logging
8 
9 from elkm1_lib.discovery import AIOELKDiscovery, ElkSystem
10 
11 from homeassistant import config_entries
12 from homeassistant.components import network
13 from homeassistant.core import HomeAssistant, callback
14 from homeassistant.helpers import device_registry as dr, discovery_flow
15 
16 from .const import DISCOVER_SCAN_TIMEOUT, DOMAIN
17 
18 _LOGGER = logging.getLogger(__name__)
19 
20 
21 def _short_mac(mac_address: str) -> str:
22  return mac_address.replace(":", "")[-6:]
23 
24 
25 @callback
27  hass: HomeAssistant,
29  device: ElkSystem,
30 ) -> bool:
31  """Update a config entry from a discovery."""
32  if not entry.unique_id or ":" not in entry.unique_id:
33  _LOGGER.debug("Adding unique id from discovery: %s", device)
34  return hass.config_entries.async_update_entry(
35  entry, unique_id=dr.format_mac(device.mac_address)
36  )
37  _LOGGER.debug("Unique id is already present from discovery: %s", device)
38  return False
39 
40 
42  hass: HomeAssistant, timeout: int, address: str | None = None
43 ) -> list[ElkSystem]:
44  """Discover elkm1 devices."""
45  if address:
46  targets = [address]
47  else:
48  targets = [
49  str(broadcast_address)
50  for broadcast_address in await network.async_get_ipv4_broadcast_addresses(
51  hass
52  )
53  ]
54 
55  scanner = AIOELKDiscovery()
56  combined_discoveries: dict[str, ElkSystem] = {}
57  for idx, discovered in enumerate(
58  await asyncio.gather(
59  *[
60  scanner.async_scan(timeout=timeout, address=target_address)
61  for target_address in targets
62  ],
63  return_exceptions=True,
64  )
65  ):
66  if isinstance(discovered, Exception):
67  _LOGGER.debug("Scanning %s failed with error: %s", targets[idx], discovered)
68  continue
69  if isinstance(discovered, BaseException):
70  raise discovered from None
71  for device in discovered:
72  assert isinstance(device, ElkSystem)
73  combined_discoveries[device.ip_address] = device
74 
75  return list(combined_discoveries.values())
76 
77 
78 async def async_discover_device(hass: HomeAssistant, host: str) -> ElkSystem | None:
79  """Direct discovery at a single ip instead of broadcast."""
80  # If we are missing the unique_id we should be able to fetch it
81  # from the device by doing a directed discovery at the host only
82  for device in await async_discover_devices(hass, DISCOVER_SCAN_TIMEOUT, host):
83  if device.ip_address == host:
84  return device
85  return None
86 
87 
88 @callback
90  hass: HomeAssistant,
91  discovered_devices: list[ElkSystem],
92 ) -> None:
93  """Trigger config flows for discovered devices."""
94  for device in discovered_devices:
95  discovery_flow.async_create_flow(
96  hass,
97  DOMAIN,
98  context={"source": config_entries.SOURCE_INTEGRATION_DISCOVERY},
99  data=asdict(device),
100  )
ElkSystem|None async_discover_device(HomeAssistant hass, str host)
Definition: discovery.py:78
None async_trigger_discovery(HomeAssistant hass, list[ElkSystem] discovered_devices)
Definition: discovery.py:92
list[ElkSystem] async_discover_devices(HomeAssistant hass, int timeout, str|None address=None)
Definition: discovery.py:43
bool async_update_entry_from_discovery(HomeAssistant hass, config_entries.ConfigEntry entry, ElkSystem device)
Definition: discovery.py:30