Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """The IKEA Idasen Desk integration."""
2 
3 from __future__ import annotations
4 
5 import logging
6 
7 from attr import dataclass
8 from bleak.exc import BleakError
9 from idasen_ha.errors import AuthFailedError
10 
11 from homeassistant.components import bluetooth
12 from homeassistant.components.bluetooth.match import ADDRESS, BluetoothCallbackMatcher
13 from homeassistant.config_entries import ConfigEntry
14 from homeassistant.const import (
15  ATTR_NAME,
16  CONF_ADDRESS,
17  EVENT_HOMEASSISTANT_STOP,
18  Platform,
19 )
20 from homeassistant.core import Event, HomeAssistant, callback
21 from homeassistant.exceptions import ConfigEntryNotReady
22 from homeassistant.helpers import device_registry as dr
23 from homeassistant.helpers.device_registry import DeviceInfo
24 
25 from .const import DOMAIN
26 from .coordinator import IdasenDeskCoordinator
27 
28 PLATFORMS: list[Platform] = [Platform.BUTTON, Platform.COVER, Platform.SENSOR]
29 
30 _LOGGER = logging.getLogger(__name__)
31 
32 
33 @dataclass
34 class DeskData:
35  """Data for the Idasen Desk integration."""
36 
37  address: str
38  device_info: DeviceInfo
39  coordinator: IdasenDeskCoordinator
40 
41 
42 async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
43  """Set up IKEA Idasen from a config entry."""
44  address: str = entry.data[CONF_ADDRESS].upper()
45 
46  coordinator = IdasenDeskCoordinator(hass, _LOGGER, entry.title, address)
47  device_info = DeviceInfo(
48  name=entry.title,
49  connections={(dr.CONNECTION_BLUETOOTH, address)},
50  )
51  hass.data.setdefault(DOMAIN, {})[entry.entry_id] = DeskData(
52  address, device_info, coordinator
53  )
54 
55  try:
56  if not await coordinator.async_connect():
57  raise ConfigEntryNotReady(f"Unable to connect to desk {address}") # noqa: TRY301
58  except (AuthFailedError, TimeoutError, BleakError, Exception) as ex:
59  raise ConfigEntryNotReady(f"Unable to connect to desk {address}") from ex
60 
61  await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
62  entry.async_on_unload(entry.add_update_listener(_async_update_listener))
63 
64  @callback
65  def _async_bluetooth_callback(
66  service_info: bluetooth.BluetoothServiceInfoBleak,
67  change: bluetooth.BluetoothChange,
68  ) -> None:
69  """Update from a Bluetooth callback to ensure that a new BLEDevice is fetched."""
70  _LOGGER.debug("Bluetooth callback triggered")
71  hass.async_create_task(coordinator.async_connect_if_expected())
72 
73  entry.async_on_unload(
74  bluetooth.async_register_callback(
75  hass,
76  _async_bluetooth_callback,
77  BluetoothCallbackMatcher({ADDRESS: address}),
78  bluetooth.BluetoothScanningMode.ACTIVE,
79  )
80  )
81 
82  async def _async_stop(event: Event) -> None:
83  """Close the connection."""
84  await coordinator.async_disconnect()
85 
86  entry.async_on_unload(
87  hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _async_stop)
88  )
89  return True
90 
91 
92 async def _async_update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
93  """Handle options update."""
94  data: DeskData = hass.data[DOMAIN][entry.entry_id]
95  if entry.title != data.device_info[ATTR_NAME]:
96  await hass.config_entries.async_reload(entry.entry_id)
97 
98 
99 async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
100  """Unload a config entry."""
101  if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
102  data: DeskData = hass.data[DOMAIN].pop(entry.entry_id)
103  await data.coordinator.async_disconnect()
104  bluetooth.async_rediscover_address(hass, data.address)
105 
106  return unload_ok
None _async_stop(HomeAssistant hass, bool restart)
Definition: __init__.py:392
None _async_update_listener(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:92
bool async_unload_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:99
bool async_setup_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:42