1 """A Bluetooth passive coordinator.
3 Receives data from advertisements but can also poll.
6 from __future__
import annotations
8 from collections.abc
import Callable, Coroutine
10 from typing
import Any
12 from bleak
import BleakError
13 from bluetooth_data_tools
import monotonic_time_coarse
18 from .
import BluetoothChange, BluetoothScanningMode, BluetoothServiceInfoBleak
19 from .passive_update_coordinator
import PassiveBluetoothDataUpdateCoordinator
21 POLL_DEFAULT_COOLDOWN = 10
22 POLL_DEFAULT_IMMEDIATE =
True
26 """A coordinator that receives passive data from advertisements but can also poll.
28 Unlike the passive processor coordinator, this coordinator does call a parser
29 method to parse the data from the advertisement.
31 Every time an advertisement is received, needs_poll_method is called to work
32 out if a poll is needed. This should return True if it is and False if it is
35 def needs_poll_method(
36 svc_info: BluetoothServiceInfoBleak,
37 last_poll: float | None
41 If there has been no poll since HA started, `last_poll` will be None.
42 Otherwise it is the number of seconds since one was last attempted.
44 If a poll is needed, the coordinator will call poll_method. This is a coroutine.
45 It should return the same type of data as your update_method. The expectation is
46 that data from advertisements and from polling are being parsed and fed into
47 a shared object that represents the current state of the device.
49 async def poll_method(svc_info: BluetoothServiceInfoBleak) -> YourDataType:
50 return YourDataType(....)
52 BluetoothServiceInfoBleak.device contains a BLEDevice. You should use this in
53 your poll function, as it is the most efficient way to get a BleakClient.
55 Once the poll is complete, the coordinator will call _async_handle_bluetooth_poll
56 which needs to be implemented in the subclass.
62 logger: logging.Logger,
65 mode: BluetoothScanningMode,
66 needs_poll_method: Callable[[BluetoothServiceInfoBleak, float |
None], bool],
67 poll_method: Callable[
68 [BluetoothServiceInfoBleak],
69 Coroutine[Any, Any, _T],
72 poll_debouncer: Debouncer[Coroutine[Any, Any,
None]] |
None =
None,
73 connectable: bool =
True,
75 """Initialize the coordinator."""
76 super().
__init__(hass, logger, address, mode, connectable)
80 self.
datadata: _T =
None
91 if poll_debouncer
is None:
95 cooldown=POLL_DEFAULT_COOLDOWN,
96 immediate=POLL_DEFAULT_IMMEDIATE,
101 poll_debouncer.function = self.
_async_poll_async_poll
105 def needs_poll(self, service_info: BluetoothServiceInfoBleak) -> bool:
106 """Return true if time to try and poll."""
107 if self.
hasshass.is_stopping:
109 poll_age: float |
None =
None
111 poll_age = service_info.time - self.
_last_poll_last_poll
115 self, last_service_info: BluetoothServiceInfoBleak
117 """Fetch the latest data from the source."""
119 raise NotImplementedError(
"Poll method not implemented")
120 return await self.
_poll_method_poll_method(last_service_info)
123 """Poll the device to retrieve any extra data."""
128 except BleakError
as exc:
131 "%s: Bluetooth error whilst polling: %s", self.
addressaddress,
str(exc)
137 self.
loggerlogger.exception(
"%s: Failure while polling", self.
addressaddress)
144 self.
loggerlogger.debug(
"%s: Polling recovered", self.
addressaddress)
151 """Handle a poll event."""
157 service_info: BluetoothServiceInfoBleak,
158 change: BluetoothChange,
160 """Handle a Bluetooth event."""
173 """Cancel debouncer and stop the callbacks."""
None _async_handle_bluetooth_event(self, BluetoothServiceInfoBleak service_info, BluetoothChange change)
bool needs_poll(self, BluetoothServiceInfoBleak service_info)
_T _async_poll_data(self, BluetoothServiceInfoBleak last_service_info)
None __init__(self, HomeAssistant hass, logging.Logger logger, *str address, BluetoothScanningMode mode, Callable[[BluetoothServiceInfoBleak, float|None], bool] needs_poll_method, Callable[[BluetoothServiceInfoBleak], Coroutine[Any, Any, _T],]|None poll_method=None, Debouncer[Coroutine[Any, Any, None]]|None poll_debouncer=None, bool connectable=True)
None _async_handle_bluetooth_poll(self)
None async_update_listeners(self)