Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """The LED BLE integration."""
2 
3 from __future__ import annotations
4 
5 import asyncio
6 from datetime import timedelta
7 import logging
8 
9 from led_ble import BLEAK_EXCEPTIONS, LEDBLE
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 CONF_ADDRESS, EVENT_HOMEASSISTANT_STOP, Platform
15 from homeassistant.core import Event, HomeAssistant, callback
16 from homeassistant.exceptions import ConfigEntryNotReady
17 from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
18 
19 from .const import DEVICE_TIMEOUT, DOMAIN, UPDATE_SECONDS
20 from .models import LEDBLEData
21 
22 PLATFORMS: list[Platform] = [Platform.LIGHT]
23 
24 _LOGGER = logging.getLogger(__name__)
25 
26 
27 async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
28  """Set up LED BLE from a config entry."""
29  address: str = entry.data[CONF_ADDRESS]
30  ble_device = bluetooth.async_ble_device_from_address(hass, address.upper(), True)
31  if not ble_device:
32  raise ConfigEntryNotReady(
33  f"Could not find LED BLE device with address {address}"
34  )
35 
36  led_ble = LEDBLE(ble_device)
37 
38  @callback
39  def _async_update_ble(
40  service_info: bluetooth.BluetoothServiceInfoBleak,
41  change: bluetooth.BluetoothChange,
42  ) -> None:
43  """Update from a ble callback."""
44  led_ble.set_ble_device_and_advertisement_data(
45  service_info.device, service_info.advertisement
46  )
47 
48  entry.async_on_unload(
49  bluetooth.async_register_callback(
50  hass,
51  _async_update_ble,
52  BluetoothCallbackMatcher({ADDRESS: address}),
53  bluetooth.BluetoothScanningMode.PASSIVE,
54  )
55  )
56 
57  async def _async_update() -> None:
58  """Update the device state."""
59  try:
60  await led_ble.update()
61  except BLEAK_EXCEPTIONS as ex:
62  raise UpdateFailed(str(ex)) from ex
63 
64  startup_event = asyncio.Event()
65  cancel_first_update = led_ble.register_callback(lambda *_: startup_event.set())
66  coordinator = DataUpdateCoordinator(
67  hass,
68  _LOGGER,
69  config_entry=entry,
70  name=led_ble.name,
71  update_method=_async_update,
72  update_interval=timedelta(seconds=UPDATE_SECONDS),
73  )
74 
75  try:
76  await coordinator.async_config_entry_first_refresh()
77  except ConfigEntryNotReady:
78  cancel_first_update()
79  raise
80 
81  try:
82  async with asyncio.timeout(DEVICE_TIMEOUT):
83  await startup_event.wait()
84  except TimeoutError as ex:
85  raise ConfigEntryNotReady(
86  "Unable to communicate with the device; "
87  f"Try moving the Bluetooth adapter closer to {led_ble.name}"
88  ) from ex
89  finally:
90  cancel_first_update()
91 
92  hass.data.setdefault(DOMAIN, {})[entry.entry_id] = LEDBLEData(
93  entry.title, led_ble, coordinator
94  )
95 
96  await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
97  entry.async_on_unload(entry.add_update_listener(_async_update_listener))
98 
99  async def _async_stop(event: Event) -> None:
100  """Close the connection."""
101  await led_ble.stop()
102 
103  entry.async_on_unload(
104  hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _async_stop)
105  )
106  return True
107 
108 
109 async def _async_update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
110  """Handle options update."""
111  data: LEDBLEData = hass.data[DOMAIN][entry.entry_id]
112  if entry.title != data.title:
113  await hass.config_entries.async_reload(entry.entry_id)
114 
115 
116 async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
117  """Unload a config entry."""
118  if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
119  data: LEDBLEData = hass.data[DOMAIN].pop(entry.entry_id)
120  await data.device.stop()
121 
122  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:109
bool async_unload_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:116
bool async_setup_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:27