Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """The OralB integration."""
2 
3 from __future__ import annotations
4 
5 import logging
6 
7 from oralb_ble import OralBBluetoothDeviceData, SensorUpdate
8 
10  BluetoothScanningMode,
11  BluetoothServiceInfoBleak,
12  async_ble_device_from_address,
13 )
15  ActiveBluetoothProcessorCoordinator,
16 )
17 from homeassistant.config_entries import ConfigEntry
18 from homeassistant.const import Platform
19 from homeassistant.core import CoreState, HomeAssistant
20 
21 PLATFORMS: list[Platform] = [Platform.SENSOR]
22 
23 _LOGGER = logging.getLogger(__name__)
24 
25 
26 type OralBConfigEntry = ConfigEntry[ActiveBluetoothProcessorCoordinator]
27 
28 
29 async def async_setup_entry(hass: HomeAssistant, entry: OralBConfigEntry) -> bool:
30  """Set up OralB BLE device from a config entry."""
31  address = entry.unique_id
32  assert address is not None
33  data = OralBBluetoothDeviceData()
34 
35  def _needs_poll(
36  service_info: BluetoothServiceInfoBleak, last_poll: float | None
37  ) -> bool:
38  # Only poll if hass is running, we need to poll,
39  # and we actually have a way to connect to the device
40  return (
41  hass.state is CoreState.running
42  and data.poll_needed(service_info, last_poll)
43  and bool(
45  hass, service_info.device.address, connectable=True
46  )
47  )
48  )
49 
50  async def _async_poll(service_info: BluetoothServiceInfoBleak) -> SensorUpdate:
51  # BluetoothServiceInfoBleak is defined in HA, otherwise would just pass it
52  # directly to the oralb code
53  # Make sure the device we have is one that we can connect with
54  # in case its coming from a passive scanner
55  if service_info.connectable:
56  connectable_device = service_info.device
57  elif device := async_ble_device_from_address(
58  hass, service_info.device.address, True
59  ):
60  connectable_device = device
61  else:
62  # We have no bluetooth controller that is in range of
63  # the device to poll it
64  raise RuntimeError(
65  f"No connectable device found for {service_info.device.address}"
66  )
67  return await data.async_poll(connectable_device)
68 
69  coordinator = entry.runtime_data = ActiveBluetoothProcessorCoordinator(
70  hass,
71  _LOGGER,
72  address=address,
73  mode=BluetoothScanningMode.PASSIVE,
74  update_method=data.update,
75  needs_poll_method=_needs_poll,
76  poll_method=_async_poll,
77  # We will take advertisements from non-connectable devices
78  # since we will trade the BLEDevice for a connectable one
79  # if we need to poll it
80  connectable=False,
81  )
82  await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
83  # only start after all platforms have had a chance to subscribe
84  entry.async_on_unload(coordinator.async_start())
85  return True
86 
87 
88 async def async_unload_entry(hass: HomeAssistant, entry: OralBConfigEntry) -> bool:
89  """Unload a config entry."""
90  return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
BLEDevice|None async_ble_device_from_address(HomeAssistant hass, str address, bool connectable=True)
Definition: api.py:88
bool async_unload_entry(HomeAssistant hass, OralBConfigEntry entry)
Definition: __init__.py:88
bool async_setup_entry(HomeAssistant hass, OralBConfigEntry entry)
Definition: __init__.py:29