1 """A Bluetooth passive processor coordinator.
3 Collects 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_processor
import PassiveBluetoothProcessorCoordinator
21 POLL_DEFAULT_COOLDOWN = 10
22 POLL_DEFAULT_IMMEDIATE =
True
26 PassiveBluetoothProcessorCoordinator[_DataT]
28 """A processor coordinator that parses passive data.
30 Parses passive data from advertisements but can also poll.
32 Every time an advertisement is received, needs_poll_method is called to work
33 out if a poll is needed. This should return True if it is and False if it is
36 def needs_poll_method(
37 svc_info: BluetoothServiceInfoBleak,
38 last_poll: float | None
42 If there has been no poll since HA started, `last_poll` will be None.
43 Otherwise it is the number of seconds since one was last attempted.
45 If a poll is needed, the coordinator will call poll_method. This is a coroutine.
46 It should return the same type of data as your update_method. The expectation is
47 that data from advertisements and from polling are being parsed and fed into a
48 shared object that represents the current state of the device.
50 async def poll_method(svc_info: BluetoothServiceInfoBleak) -> YourDataType:
51 return YourDataType(....)
53 BluetoothServiceInfoBleak.device contains a BLEDevice. You should use this in
54 your poll function, as it is the most efficient way to get a BleakClient.
60 logger: logging.Logger,
63 mode: BluetoothScanningMode,
64 update_method: Callable[[BluetoothServiceInfoBleak], _DataT],
65 needs_poll_method: Callable[[BluetoothServiceInfoBleak, float |
None], bool],
66 poll_method: Callable[
67 [BluetoothServiceInfoBleak],
68 Coroutine[Any, Any, _DataT],
71 poll_debouncer: Debouncer[Coroutine[Any, Any,
None]] |
None =
None,
72 connectable: bool =
True,
74 """Initialize the processor."""
75 super().
__init__(hass, logger, address, mode, update_method, connectable)
86 if poll_debouncer
is None:
90 cooldown=POLL_DEFAULT_COOLDOWN,
91 immediate=POLL_DEFAULT_IMMEDIATE,
96 poll_debouncer.function = self.
_async_poll_async_poll
100 def needs_poll(self, service_info: BluetoothServiceInfoBleak) -> bool:
101 """Return true if time to try and poll."""
102 if self.
hasshass.is_stopping:
104 poll_age: float |
None =
None
106 poll_age = service_info.time - self.
_last_poll_last_poll
110 self, last_service_info: BluetoothServiceInfoBleak
112 """Fetch the latest data from the source."""
114 raise NotImplementedError(
"Poll method not implemented")
115 return await self.
_poll_method_poll_method(last_service_info)
118 """Poll the device to retrieve any extra data."""
123 except BleakError
as exc:
126 "%s: Bluetooth error whilst polling: %s", self.
addressaddress,
str(exc)
132 self.
loggerlogger.exception(
"%s: Failure while polling", self.
addressaddress)
139 self.
loggerlogger.debug(
"%s: Polling recovered", self.
addressaddress)
142 for processor
in self._processors:
143 processor.async_handle_update(update)
148 service_info: BluetoothServiceInfoBleak,
149 change: BluetoothChange,
151 """Handle a Bluetooth event."""
164 """Cancel debouncer and stop the callbacks."""
bool needs_poll(self, BluetoothServiceInfoBleak service_info)
None __init__(self, HomeAssistant hass, logging.Logger logger, *str address, BluetoothScanningMode mode, Callable[[BluetoothServiceInfoBleak], _DataT] update_method, Callable[[BluetoothServiceInfoBleak, float|None], bool] needs_poll_method, Callable[[BluetoothServiceInfoBleak], Coroutine[Any, Any, _DataT],]|None poll_method=None, Debouncer[Coroutine[Any, Any, None]]|None poll_debouncer=None, bool connectable=True)
None _async_handle_bluetooth_event(self, BluetoothServiceInfoBleak service_info, BluetoothChange change)
_DataT _async_poll_data(self, BluetoothServiceInfoBleak last_service_info)