From 94d168e20e3bf1b18b6d163a3b2df953c4c95a55 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 5 Dec 2023 08:53:29 -1000 Subject: [PATCH] Move Bluetooth advertisement tracker to habluetooth library (#105083) --- .../bluetooth/advertisement_tracker.py | 82 ------------------- homeassistant/components/bluetooth/manager.py | 5 +- .../bluetooth/test_advertisement_tracker.py | 4 +- .../components/bluetooth/test_base_scanner.py | 4 +- .../private_ble_device/test_device_tracker.py | 5 +- .../private_ble_device/test_sensor.py | 5 +- 6 files changed, 7 insertions(+), 98 deletions(-) delete mode 100644 homeassistant/components/bluetooth/advertisement_tracker.py diff --git a/homeassistant/components/bluetooth/advertisement_tracker.py b/homeassistant/components/bluetooth/advertisement_tracker.py deleted file mode 100644 index f17bcf938f5..00000000000 --- a/homeassistant/components/bluetooth/advertisement_tracker.py +++ /dev/null @@ -1,82 +0,0 @@ -"""The bluetooth integration advertisement tracker.""" -from __future__ import annotations - -from typing import Any - -from homeassistant.core import callback - -from .models import BluetoothServiceInfoBleak - -ADVERTISING_TIMES_NEEDED = 16 - -# Each scanner may buffer incoming packets so -# we need to give a bit of leeway before we -# mark a device unavailable -TRACKER_BUFFERING_WOBBLE_SECONDS = 5 - - -class AdvertisementTracker: - """Tracker to determine the interval that a device is advertising.""" - - __slots__ = ("intervals", "fallback_intervals", "sources", "_timings") - - def __init__(self) -> None: - """Initialize the tracker.""" - self.intervals: dict[str, float] = {} - self.fallback_intervals: dict[str, float] = {} - self.sources: dict[str, str] = {} - self._timings: dict[str, list[float]] = {} - - @callback - def async_diagnostics(self) -> dict[str, dict[str, Any]]: - """Return diagnostics.""" - return { - "intervals": self.intervals, - "fallback_intervals": self.fallback_intervals, - "sources": self.sources, - "timings": self._timings, - } - - @callback - def async_collect(self, service_info: BluetoothServiceInfoBleak) -> None: - """Collect timings for the tracker. - - For performance reasons, it is the responsibility of the - caller to check if the device already has an interval set or - the source has changed before calling this function. - """ - address = service_info.address - self.sources[address] = service_info.source - timings = self._timings.setdefault(address, []) - timings.append(service_info.time) - if len(timings) != ADVERTISING_TIMES_NEEDED: - return - - max_time_between_advertisements = timings[1] - timings[0] - for i in range(2, len(timings)): - time_between_advertisements = timings[i] - timings[i - 1] - if time_between_advertisements > max_time_between_advertisements: - max_time_between_advertisements = time_between_advertisements - - # We now know the maximum time between advertisements - self.intervals[address] = max_time_between_advertisements - del self._timings[address] - - @callback - def async_remove_address(self, address: str) -> None: - """Remove the tracker.""" - self.intervals.pop(address, None) - self.sources.pop(address, None) - self._timings.pop(address, None) - - @callback - def async_remove_fallback_interval(self, address: str) -> None: - """Remove fallback interval.""" - self.fallback_intervals.pop(address, None) - - @callback - def async_remove_source(self, source: str) -> None: - """Remove the tracker.""" - for address, tracked_source in list(self.sources.items()): - if tracked_source == source: - self.async_remove_address(address) diff --git a/homeassistant/components/bluetooth/manager.py b/homeassistant/components/bluetooth/manager.py index e9f490285c9..9c3517982af 100644 --- a/homeassistant/components/bluetooth/manager.py +++ b/homeassistant/components/bluetooth/manager.py @@ -17,6 +17,7 @@ from bluetooth_adapters import ( BluetoothAdapters, ) from bluetooth_data_tools import monotonic_time_coarse +from habluetooth import TRACKER_BUFFERING_WOBBLE_SECONDS, AdvertisementTracker from homeassistant import config_entries from homeassistant.const import EVENT_LOGGING_CHANGED @@ -29,10 +30,6 @@ from homeassistant.core import ( from homeassistant.helpers import discovery_flow from homeassistant.helpers.event import async_track_time_interval -from .advertisement_tracker import ( - TRACKER_BUFFERING_WOBBLE_SECONDS, - AdvertisementTracker, -) from .base_scanner import BaseHaScanner, BluetoothScannerDevice from .const import ( FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS, diff --git a/tests/components/bluetooth/test_advertisement_tracker.py b/tests/components/bluetooth/test_advertisement_tracker.py index 6ae847ba84a..8681287baa2 100644 --- a/tests/components/bluetooth/test_advertisement_tracker.py +++ b/tests/components/bluetooth/test_advertisement_tracker.py @@ -3,6 +3,7 @@ from datetime import timedelta import time from unittest.mock import patch +from habluetooth.advertisement_tracker import ADVERTISING_TIMES_NEEDED import pytest from homeassistant.components.bluetooth import ( @@ -10,9 +11,6 @@ from homeassistant.components.bluetooth import ( async_register_scanner, async_track_unavailable, ) -from homeassistant.components.bluetooth.advertisement_tracker import ( - ADVERTISING_TIMES_NEEDED, -) from homeassistant.components.bluetooth.const import ( FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS, SOURCE_LOCAL, diff --git a/tests/components/bluetooth/test_base_scanner.py b/tests/components/bluetooth/test_base_scanner.py index 5886cc10aac..1228a4efc5b 100644 --- a/tests/components/bluetooth/test_base_scanner.py +++ b/tests/components/bluetooth/test_base_scanner.py @@ -8,6 +8,7 @@ from unittest.mock import patch from bleak.backends.device import BLEDevice from bleak.backends.scanner import AdvertisementData +from habluetooth.advertisement_tracker import TRACKER_BUFFERING_WOBBLE_SECONDS import pytest from homeassistant.components import bluetooth @@ -17,9 +18,6 @@ from homeassistant.components.bluetooth import ( HomeAssistantRemoteScanner, storage, ) -from homeassistant.components.bluetooth.advertisement_tracker import ( - TRACKER_BUFFERING_WOBBLE_SECONDS, -) from homeassistant.components.bluetooth.const import ( CONNECTABLE_FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS, FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS, diff --git a/tests/components/private_ble_device/test_device_tracker.py b/tests/components/private_ble_device/test_device_tracker.py index d8b30738865..3834254ac7f 100644 --- a/tests/components/private_ble_device/test_device_tracker.py +++ b/tests/components/private_ble_device/test_device_tracker.py @@ -3,9 +3,8 @@ import time -from homeassistant.components.bluetooth.advertisement_tracker import ( - ADVERTISING_TIMES_NEEDED, -) +from habluetooth.advertisement_tracker import ADVERTISING_TIMES_NEEDED + from homeassistant.components.bluetooth.api import ( async_get_fallback_availability_interval, ) diff --git a/tests/components/private_ble_device/test_sensor.py b/tests/components/private_ble_device/test_sensor.py index 65f08d5653d..e35643d7626 100644 --- a/tests/components/private_ble_device/test_sensor.py +++ b/tests/components/private_ble_device/test_sensor.py @@ -1,10 +1,9 @@ """Tests for sensors.""" +from habluetooth.advertisement_tracker import ADVERTISING_TIMES_NEEDED + from homeassistant.components.bluetooth import async_set_fallback_availability_interval -from homeassistant.components.bluetooth.advertisement_tracker import ( - ADVERTISING_TIMES_NEEDED, -) from homeassistant.core import HomeAssistant from . import (