diff --git a/homeassistant/components/bluetooth/__init__.py b/homeassistant/components/bluetooth/__init__.py index c59249e8bd5..5948d4d1358 100644 --- a/homeassistant/components/bluetooth/__init__.py +++ b/homeassistant/components/bluetooth/__init__.py @@ -59,7 +59,11 @@ from .api import ( async_set_fallback_availability_interval, async_track_unavailable, ) -from .base_scanner import BaseHaRemoteScanner, BaseHaScanner, BluetoothScannerDevice +from .base_scanner import ( + BaseHaScanner, + BluetoothScannerDevice, + HomeAssistantRemoteScanner, +) from .const import ( BLUETOOTH_DISCOVERY_COOLDOWN_SECONDS, CONF_ADAPTER, @@ -103,7 +107,7 @@ __all__ = [ "async_scanner_count", "async_scanner_devices_by_address", "BaseHaScanner", - "BaseHaRemoteScanner", + "HomeAssistantRemoteScanner", "BluetoothCallbackMatcher", "BluetoothChange", "BluetoothServiceInfo", diff --git a/homeassistant/components/bluetooth/base_scanner.py b/homeassistant/components/bluetooth/base_scanner.py index 21935dab6ef..f7696c2e90b 100644 --- a/homeassistant/components/bluetooth/base_scanner.py +++ b/homeassistant/components/bluetooth/base_scanner.py @@ -1,14 +1,13 @@ """Base classes for HA Bluetooth scanners for bluetooth.""" from __future__ import annotations -from abc import ABC, abstractmethod +from abc import abstractmethod +import asyncio from collections.abc import Callable, Generator from contextlib import contextmanager from dataclasses import dataclass -import datetime -from datetime import timedelta import logging -from typing import Any, Final +from typing import Any, Final, final from bleak.backends.device import BLEDevice from bleak.backends.scanner import AdvertisementData @@ -24,8 +23,6 @@ from homeassistant.core import ( HomeAssistant, callback as hass_callback, ) -from homeassistant.helpers.event import async_track_time_interval -import homeassistant.util.dt as dt_util from . import models from .const import ( @@ -35,6 +32,7 @@ from .const import ( ) from .models import HaBluetoothConnector +SCANNER_WATCHDOG_INTERVAL_SECONDS: Final = SCANNER_WATCHDOG_INTERVAL.total_seconds() MONOTONIC_TIME: Final = monotonic_time_coarse _LOGGER = logging.getLogger(__name__) @@ -48,11 +46,10 @@ class BluetoothScannerDevice: advertisement: AdvertisementData -class BaseHaScanner(ABC): - """Base class for Ha Scanners.""" +class BaseHaScanner: + """Base class for high availability BLE scanners.""" __slots__ = ( - "hass", "adapter", "connectable", "source", @@ -63,17 +60,16 @@ class BaseHaScanner(ABC): "_last_detection", "_start_time", "_cancel_watchdog", + "_loop", ) def __init__( self, - hass: HomeAssistant, source: str, adapter: str, connector: HaBluetoothConnector | None = None, ) -> None: """Initialize the scanner.""" - self.hass = hass self.connectable = False self.source = source self.connector = connector @@ -83,13 +79,20 @@ class BaseHaScanner(ABC): self.scanning = True self._last_detection = 0.0 self._start_time = 0.0 - self._cancel_watchdog: CALLBACK_TYPE | None = None + self._cancel_watchdog: asyncio.TimerHandle | None = None + self._loop: asyncio.AbstractEventLoop | None = None + + @hass_callback + def async_setup(self) -> CALLBACK_TYPE: + """Set up the scanner.""" + self._loop = asyncio.get_running_loop() + return self._unsetup @hass_callback def _async_stop_scanner_watchdog(self) -> None: """Stop the scanner watchdog.""" if self._cancel_watchdog: - self._cancel_watchdog() + self._cancel_watchdog.cancel() self._cancel_watchdog = None @hass_callback @@ -97,12 +100,22 @@ class BaseHaScanner(ABC): """If something has restarted or updated, we need to restart the scanner.""" self._start_time = self._last_detection = MONOTONIC_TIME() if not self._cancel_watchdog: - self._cancel_watchdog = async_track_time_interval( - self.hass, - self._async_scanner_watchdog, - SCANNER_WATCHDOG_INTERVAL, - name=f"{self.name} Bluetooth scanner watchdog", - ) + self._schedule_watchdog() + + def _schedule_watchdog(self) -> None: + """Schedule the watchdog.""" + loop = self._loop + assert loop is not None + self._cancel_watchdog = loop.call_at( + loop.time() + SCANNER_WATCHDOG_INTERVAL_SECONDS, + self._async_call_scanner_watchdog, + ) + + @final + def _async_call_scanner_watchdog(self) -> None: + """Call the scanner watchdog and schedule the next one.""" + self._async_scanner_watchdog() + self._schedule_watchdog() @hass_callback def _async_watchdog_triggered(self) -> bool: @@ -116,7 +129,7 @@ class BaseHaScanner(ABC): return time_since_last_detection > SCANNER_WATCHDOG_TIMEOUT @hass_callback - def _async_scanner_watchdog(self, now: datetime.datetime) -> None: + def _async_scanner_watchdog(self) -> None: """Check if the scanner is running. Override this method if you need to do something else when the watchdog @@ -135,6 +148,10 @@ class BaseHaScanner(ABC): return self.scanning = not self._connecting + @hass_callback + def _unsetup(self) -> None: + """Unset up the scanner.""" + @contextmanager def connecting(self) -> Generator[None, None, None]: """Context manager to track connecting state.""" @@ -183,7 +200,7 @@ class BaseHaScanner(ABC): class BaseHaRemoteScanner(BaseHaScanner): - """Base class for a Home Assistant remote BLE scanner.""" + """Base class for a high availability remote BLE scanner.""" __slots__ = ( "_new_info_callback", @@ -191,12 +208,11 @@ class BaseHaRemoteScanner(BaseHaScanner): "_discovered_device_timestamps", "_details", "_expire_seconds", - "_storage", + "_cancel_track", ) def __init__( self, - hass: HomeAssistant, scanner_id: str, name: str, new_info_callback: Callable[[BluetoothServiceInfoBleak], None], @@ -204,7 +220,7 @@ class BaseHaRemoteScanner(BaseHaScanner): connectable: bool, ) -> None: """Initialize the scanner.""" - super().__init__(hass, scanner_id, name, connector) + super().__init__(scanner_id, name, connector) self._new_info_callback = new_info_callback self._discovered_device_advertisement_datas: dict[ str, tuple[BLEDevice, AdvertisementData] @@ -215,55 +231,37 @@ class BaseHaRemoteScanner(BaseHaScanner): # Scanners only care about connectable devices. The manager # will handle taking care of availability for non-connectable devices self._expire_seconds = CONNECTABLE_FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS - assert models.MANAGER is not None - self._storage = models.MANAGER.storage + self._cancel_track: asyncio.TimerHandle | None = None + + def _cancel_expire_devices(self) -> None: + """Cancel the expiration of old devices.""" + if self._cancel_track: + self._cancel_track.cancel() + self._cancel_track = None + + @hass_callback + def _unsetup(self) -> None: + """Unset up the scanner.""" + self._async_stop_scanner_watchdog() + self._cancel_expire_devices() @hass_callback def async_setup(self) -> CALLBACK_TYPE: """Set up the scanner.""" - if history := self._storage.async_get_advertisement_history(self.source): - self._discovered_device_advertisement_datas = ( - history.discovered_device_advertisement_datas - ) - self._discovered_device_timestamps = history.discovered_device_timestamps - # Expire anything that is too old - self._async_expire_devices(dt_util.utcnow()) - - cancel_track = async_track_time_interval( - self.hass, - self._async_expire_devices, - timedelta(seconds=30), - name=f"{self.name} Bluetooth scanner device expire", - ) - cancel_stop = self.hass.bus.async_listen( - EVENT_HOMEASSISTANT_STOP, self._async_save_history - ) + super().async_setup() + self._schedule_expire_devices() self._async_setup_scanner_watchdog() + return self._unsetup - @hass_callback - def _cancel() -> None: - self._async_save_history() - self._async_stop_scanner_watchdog() - cancel_track() - cancel_stop() - - return _cancel + def _schedule_expire_devices(self) -> None: + """Schedule the expiration of old devices.""" + loop = self._loop + assert loop is not None + self._cancel_expire_devices() + self._cancel_track = loop.call_at(loop.time() + 30, self._async_expire_devices) @hass_callback - def _async_save_history(self, event: Event | None = None) -> None: - """Save the history.""" - self._storage.async_set_advertisement_history( - self.source, - DiscoveredDeviceAdvertisementData( - self.connectable, - self._expire_seconds, - self._discovered_device_advertisement_datas, - self._discovered_device_timestamps, - ), - ) - - @hass_callback - def _async_expire_devices(self, _datetime: datetime.datetime) -> None: + def _async_expire_devices(self) -> None: """Expire old devices.""" now = MONOTONIC_TIME() expired = [ @@ -274,6 +272,7 @@ class BaseHaRemoteScanner(BaseHaScanner): for address in expired: del self._discovered_device_advertisement_datas[address] del self._discovered_device_timestamps[address] + self._schedule_expire_devices() @property def discovered_devices(self) -> list[BLEDevice]: @@ -395,9 +394,6 @@ class BaseHaRemoteScanner(BaseHaScanner): """Return diagnostic information about the scanner.""" now = MONOTONIC_TIME() return await super().async_diagnostics() | { - "storage": self._storage.async_get_advertisement_history_as_dict( - self.source - ), "connectable": self.connectable, "discovered_device_timestamps": self._discovered_device_timestamps, "time_since_last_device_detection": { @@ -405,3 +401,79 @@ class BaseHaRemoteScanner(BaseHaScanner): for address, timestamp in self._discovered_device_timestamps.items() }, } + + +class HomeAssistantRemoteScanner(BaseHaRemoteScanner): + """Home Assistant remote BLE scanner. + + This is the only object that should know about + the hass object. + """ + + __slots__ = ( + "hass", + "_storage", + "_cancel_stop", + ) + + def __init__( + self, + hass: HomeAssistant, + scanner_id: str, + name: str, + new_info_callback: Callable[[BluetoothServiceInfoBleak], None], + connector: HaBluetoothConnector | None, + connectable: bool, + ) -> None: + """Initialize the scanner.""" + self.hass = hass + assert models.MANAGER is not None + self._storage = models.MANAGER.storage + self._cancel_stop: CALLBACK_TYPE | None = None + super().__init__(scanner_id, name, new_info_callback, connector, connectable) + + @hass_callback + def async_setup(self) -> CALLBACK_TYPE: + """Set up the scanner.""" + super().async_setup() + if history := self._storage.async_get_advertisement_history(self.source): + self._discovered_device_advertisement_datas = ( + history.discovered_device_advertisement_datas + ) + self._discovered_device_timestamps = history.discovered_device_timestamps + # Expire anything that is too old + self._async_expire_devices() + + self._cancel_stop = self.hass.bus.async_listen( + EVENT_HOMEASSISTANT_STOP, self._async_save_history + ) + return self._unsetup + + @hass_callback + def _unsetup(self) -> None: + super()._unsetup() + self._async_save_history() + if self._cancel_stop: + self._cancel_stop() + self._cancel_stop = None + + @hass_callback + def _async_save_history(self, event: Event | None = None) -> None: + """Save the history.""" + self._storage.async_set_advertisement_history( + self.source, + DiscoveredDeviceAdvertisementData( + self.connectable, + self._expire_seconds, + self._discovered_device_advertisement_datas, + self._discovered_device_timestamps, + ), + ) + + async def async_diagnostics(self) -> dict[str, Any]: + """Return diagnostic information about the scanner.""" + diag = await super().async_diagnostics() + diag["storage"] = self._storage.async_get_advertisement_history_as_dict( + self.source + ) + return diag diff --git a/homeassistant/components/bluetooth/scanner.py b/homeassistant/components/bluetooth/scanner.py index 896d9dc7958..712fe1c0d9a 100644 --- a/homeassistant/components/bluetooth/scanner.py +++ b/homeassistant/components/bluetooth/scanner.py @@ -3,7 +3,6 @@ from __future__ import annotations import asyncio from collections.abc import Callable -from datetime import datetime import logging import platform from typing import Any @@ -19,7 +18,7 @@ from bleak_retry_connector import restore_discoveries from bluetooth_adapters import DEFAULT_ADDRESS from dbus_fast import InvalidMessageError -from homeassistant.core import HomeAssistant, callback as hass_callback +from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback as hass_callback from homeassistant.exceptions import HomeAssistantError from homeassistant.util.package import is_docker_env @@ -133,12 +132,13 @@ class HaScanner(BaseHaScanner): """Init bluetooth discovery.""" self.mac_address = address source = address if address != DEFAULT_ADDRESS else adapter or SOURCE_LOCAL - super().__init__(hass, source, adapter) + super().__init__(source, adapter) self.connectable = True self.mode = mode self._start_stop_lock = asyncio.Lock() self._new_info_callback = new_info_callback self.scanning = False + self.hass = hass @property def discovered_devices(self) -> list[BLEDevice]: @@ -153,11 +153,13 @@ class HaScanner(BaseHaScanner): return self.scanner.discovered_devices_and_advertisement_data @hass_callback - def async_setup(self) -> None: + def async_setup(self) -> CALLBACK_TYPE: """Set up the scanner.""" + super().async_setup() self.scanner = create_bleak_scanner( self._async_detection_callback, self.mode, self.adapter ) + return self._unsetup async def async_diagnostics(self) -> dict[str, Any]: """Return diagnostic information about the scanner.""" @@ -314,7 +316,7 @@ class HaScanner(BaseHaScanner): await restore_discoveries(self.scanner, self.adapter) @hass_callback - def _async_scanner_watchdog(self, now: datetime) -> None: + def _async_scanner_watchdog(self) -> None: """Check if the scanner is running.""" if not self._async_watchdog_triggered(): return diff --git a/homeassistant/components/esphome/bluetooth/scanner.py b/homeassistant/components/esphome/bluetooth/scanner.py index a54e7af59a6..b4fb12210d3 100644 --- a/homeassistant/components/esphome/bluetooth/scanner.py +++ b/homeassistant/components/esphome/bluetooth/scanner.py @@ -7,11 +7,14 @@ from bluetooth_data_tools import ( parse_advertisement_data_tuple, ) -from homeassistant.components.bluetooth import MONOTONIC_TIME, BaseHaRemoteScanner +from homeassistant.components.bluetooth import ( + MONOTONIC_TIME, + HomeAssistantRemoteScanner, +) from homeassistant.core import callback -class ESPHomeScanner(BaseHaRemoteScanner): +class ESPHomeScanner(HomeAssistantRemoteScanner): """Scanner for esphome.""" __slots__ = () diff --git a/homeassistant/components/ruuvi_gateway/bluetooth.py b/homeassistant/components/ruuvi_gateway/bluetooth.py index 47a9bbfdde0..8a154bca019 100644 --- a/homeassistant/components/ruuvi_gateway/bluetooth.py +++ b/homeassistant/components/ruuvi_gateway/bluetooth.py @@ -10,7 +10,7 @@ from home_assistant_bluetooth import BluetoothServiceInfoBleak from homeassistant.components.bluetooth import ( FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS, MONOTONIC_TIME, - BaseHaRemoteScanner, + HomeAssistantRemoteScanner, async_get_advertisement_callback, async_register_scanner, ) @@ -22,7 +22,7 @@ from .coordinator import RuuviGatewayUpdateCoordinator _LOGGER = logging.getLogger(__name__) -class RuuviGatewayScanner(BaseHaRemoteScanner): +class RuuviGatewayScanner(HomeAssistantRemoteScanner): """Scanner for Ruuvi Gateway.""" def __init__( diff --git a/homeassistant/components/shelly/bluetooth/scanner.py b/homeassistant/components/shelly/bluetooth/scanner.py index 7c0dc3c792a..3ada1ce55f5 100644 --- a/homeassistant/components/shelly/bluetooth/scanner.py +++ b/homeassistant/components/shelly/bluetooth/scanner.py @@ -6,13 +6,16 @@ from typing import Any from aioshelly.ble import parse_ble_scan_result_event from aioshelly.ble.const import BLE_SCAN_RESULT_EVENT, BLE_SCAN_RESULT_VERSION -from homeassistant.components.bluetooth import MONOTONIC_TIME, BaseHaRemoteScanner +from homeassistant.components.bluetooth import ( + MONOTONIC_TIME, + HomeAssistantRemoteScanner, +) from homeassistant.core import callback from ..const import LOGGER -class ShellyBLEScanner(BaseHaRemoteScanner): +class ShellyBLEScanner(HomeAssistantRemoteScanner): """Scanner for shelly.""" @callback diff --git a/tests/components/bluetooth/test_api.py b/tests/components/bluetooth/test_api.py index 63b60c8f487..30e9554f2af 100644 --- a/tests/components/bluetooth/test_api.py +++ b/tests/components/bluetooth/test_api.py @@ -7,9 +7,9 @@ import pytest from homeassistant.components import bluetooth from homeassistant.components.bluetooth import ( MONOTONIC_TIME, - BaseHaRemoteScanner, BaseHaScanner, HaBluetoothConnector, + HomeAssistantRemoteScanner, async_scanner_by_source, async_scanner_devices_by_address, ) @@ -27,7 +27,7 @@ from . import ( async def test_scanner_by_source(hass: HomeAssistant, enable_bluetooth: None) -> None: """Test we can get a scanner by source.""" - hci2_scanner = FakeScanner(hass, "hci2", "hci2") + hci2_scanner = FakeScanner("hci2", "hci2") cancel_hci2 = bluetooth.async_register_scanner(hass, hci2_scanner, True) assert async_scanner_by_source(hass, "hci2") is hci2_scanner @@ -46,7 +46,7 @@ async def test_async_scanner_devices_by_address_connectable( """Test getting scanner devices by address with connectable devices.""" manager = _get_manager() - class FakeInjectableScanner(BaseHaRemoteScanner): + class FakeInjectableScanner(HomeAssistantRemoteScanner): def inject_advertisement( self, device: BLEDevice, advertisement_data: AdvertisementData ) -> None: @@ -135,7 +135,7 @@ async def test_async_scanner_devices_by_address_non_connectable( connector = ( HaBluetoothConnector(MockBleakClient, "mock_bleak_client", lambda: False), ) - scanner = FakeStaticScanner(hass, "esp32", "esp32", connector) + scanner = FakeStaticScanner("esp32", "esp32", connector) cancel = manager.async_register_scanner(scanner, False) assert scanner.discovered_devices_and_advertisement_data == { diff --git a/tests/components/bluetooth/test_base_scanner.py b/tests/components/bluetooth/test_base_scanner.py index 31d90a6e93d..a39f18e037e 100644 --- a/tests/components/bluetooth/test_base_scanner.py +++ b/tests/components/bluetooth/test_base_scanner.py @@ -13,8 +13,8 @@ import pytest from homeassistant.components import bluetooth from homeassistant.components.bluetooth import ( MONOTONIC_TIME, - BaseHaRemoteScanner, HaBluetoothConnector, + HomeAssistantRemoteScanner, storage, ) from homeassistant.components.bluetooth.advertisement_tracker import ( @@ -89,7 +89,7 @@ async def test_remote_scanner( rssi=-100, ) - class FakeScanner(BaseHaRemoteScanner): + class FakeScanner(HomeAssistantRemoteScanner): def inject_advertisement( self, device: BLEDevice, advertisement_data: AdvertisementData ) -> None: @@ -173,7 +173,7 @@ async def test_remote_scanner_expires_connectable( rssi=-100, ) - class FakeScanner(BaseHaRemoteScanner): + class FakeScanner(HomeAssistantRemoteScanner): def inject_advertisement( self, device: BLEDevice, advertisement_data: AdvertisementData ) -> None: @@ -248,7 +248,7 @@ async def test_remote_scanner_expires_non_connectable( rssi=-100, ) - class FakeScanner(BaseHaRemoteScanner): + class FakeScanner(HomeAssistantRemoteScanner): def inject_advertisement( self, device: BLEDevice, advertisement_data: AdvertisementData ) -> None: @@ -346,7 +346,7 @@ async def test_base_scanner_connecting_behavior( rssi=-100, ) - class FakeScanner(BaseHaRemoteScanner): + class FakeScanner(HomeAssistantRemoteScanner): def inject_advertisement( self, device: BLEDevice, advertisement_data: AdvertisementData ) -> None: @@ -418,7 +418,7 @@ async def test_restore_history_remote_adapter( connector = ( HaBluetoothConnector(MockBleakClient, "mock_bleak_client", lambda: False), ) - scanner = BaseHaRemoteScanner( + scanner = HomeAssistantRemoteScanner( hass, "atom-bluetooth-proxy-ceaac4", "atom-bluetooth-proxy-ceaac4", @@ -434,7 +434,7 @@ async def test_restore_history_remote_adapter( cancel() unsetup() - scanner = BaseHaRemoteScanner( + scanner = HomeAssistantRemoteScanner( hass, "atom-bluetooth-proxy-ceaac4", "atom-bluetooth-proxy-ceaac4", @@ -470,7 +470,7 @@ async def test_device_with_ten_minute_advertising_interval( rssi=-100, ) - class FakeScanner(BaseHaRemoteScanner): + class FakeScanner(HomeAssistantRemoteScanner): def inject_advertisement( self, device: BLEDevice, advertisement_data: AdvertisementData ) -> None: @@ -592,7 +592,7 @@ async def test_scanner_stops_responding( """Test we mark a scanner are not scanning when it stops responding.""" manager = _get_manager() - class FakeScanner(BaseHaRemoteScanner): + class FakeScanner(HomeAssistantRemoteScanner): """A fake remote scanner.""" def inject_advertisement( diff --git a/tests/components/bluetooth/test_diagnostics.py b/tests/components/bluetooth/test_diagnostics.py index 0e8b2b54f06..8625283266e 100644 --- a/tests/components/bluetooth/test_diagnostics.py +++ b/tests/components/bluetooth/test_diagnostics.py @@ -7,8 +7,8 @@ from bluetooth_adapters import DEFAULT_ADDRESS from homeassistant.components import bluetooth from homeassistant.components.bluetooth import ( MONOTONIC_TIME, - BaseHaRemoteScanner, HaBluetoothConnector, + HomeAssistantRemoteScanner, ) from homeassistant.core import HomeAssistant @@ -442,7 +442,7 @@ async def test_diagnostics_remote_adapter( local_name="wohand", service_uuids=[], manufacturer_data={1: b"\x01"} ) - class FakeScanner(BaseHaRemoteScanner): + class FakeScanner(HomeAssistantRemoteScanner): def inject_advertisement( self, device: BLEDevice, advertisement_data: AdvertisementData ) -> None: diff --git a/tests/components/bluetooth/test_manager.py b/tests/components/bluetooth/test_manager.py index 6c89074e471..361f0cd008f 100644 --- a/tests/components/bluetooth/test_manager.py +++ b/tests/components/bluetooth/test_manager.py @@ -12,12 +12,12 @@ import pytest from homeassistant.components import bluetooth from homeassistant.components.bluetooth import ( MONOTONIC_TIME, - BaseHaRemoteScanner, BluetoothChange, BluetoothScanningMode, BluetoothServiceInfo, BluetoothServiceInfoBleak, HaBluetoothConnector, + HomeAssistantRemoteScanner, async_ble_device_from_address, async_get_advertisement_callback, async_get_fallback_availability_interval, @@ -56,7 +56,7 @@ from tests.common import async_fire_time_changed, load_fixture @pytest.fixture def register_hci0_scanner(hass: HomeAssistant) -> Generator[None, None, None]: """Register an hci0 scanner.""" - hci0_scanner = FakeScanner(hass, "hci0", "hci0") + hci0_scanner = FakeScanner("hci0", "hci0") cancel = bluetooth.async_register_scanner(hass, hci0_scanner, True) yield cancel() @@ -65,7 +65,7 @@ def register_hci0_scanner(hass: HomeAssistant) -> Generator[None, None, None]: @pytest.fixture def register_hci1_scanner(hass: HomeAssistant) -> Generator[None, None, None]: """Register an hci1 scanner.""" - hci1_scanner = FakeScanner(hass, "hci1", "hci1") + hci1_scanner = FakeScanner("hci1", "hci1") cancel = bluetooth.async_register_scanner(hass, hci1_scanner, True) yield cancel() @@ -562,7 +562,7 @@ async def test_switching_adapters_when_one_goes_away( ) -> None: """Test switching adapters when one goes away.""" cancel_hci2 = bluetooth.async_register_scanner( - hass, FakeScanner(hass, "hci2", "hci2"), True + hass, FakeScanner("hci2", "hci2"), True ) address = "44:44:33:11:23:45" @@ -612,7 +612,7 @@ async def test_switching_adapters_when_one_stop_scanning( hass: HomeAssistant, enable_bluetooth: None, register_hci0_scanner: None ) -> None: """Test switching adapters when stops scanning.""" - hci2_scanner = FakeScanner(hass, "hci2", "hci2") + hci2_scanner = FakeScanner("hci2", "hci2") cancel_hci2 = bluetooth.async_register_scanner(hass, hci2_scanner, True) address = "44:44:33:11:23:45" @@ -704,7 +704,7 @@ async def test_goes_unavailable_connectable_only_and_recovers( BluetoothScanningMode.ACTIVE, ) - class FakeScanner(BaseHaRemoteScanner): + class FakeScanner(HomeAssistantRemoteScanner): def inject_advertisement( self, device: BLEDevice, advertisement_data: AdvertisementData ) -> None: @@ -877,7 +877,7 @@ async def test_goes_unavailable_dismisses_discovery_and_makes_discoverable( BluetoothScanningMode.ACTIVE, ) - class FakeScanner(BaseHaRemoteScanner): + class FakeScanner(HomeAssistantRemoteScanner): def inject_advertisement( self, device: BLEDevice, advertisement_data: AdvertisementData ) -> None: diff --git a/tests/components/bluetooth/test_models.py b/tests/components/bluetooth/test_models.py index 746f52537cb..1d07ab75a48 100644 --- a/tests/components/bluetooth/test_models.py +++ b/tests/components/bluetooth/test_models.py @@ -10,9 +10,9 @@ from bleak.backends.scanner import AdvertisementData import pytest from homeassistant.components.bluetooth import ( - BaseHaRemoteScanner, BaseHaScanner, HaBluetoothConnector, + HomeAssistantRemoteScanner, ) from homeassistant.components.bluetooth.wrappers import ( HaBleakClientWrapper, @@ -158,7 +158,7 @@ async def test_wrapped_bleak_client_set_disconnected_callback_after_connected( local_name="wohand", service_uuids=[], manufacturer_data={1: b"\x01"}, rssi=-100 ) - class FakeScanner(BaseHaRemoteScanner): + class FakeScanner(HomeAssistantRemoteScanner): @property def discovered_devices(self) -> list[BLEDevice]: """Return a list of discovered devices.""" @@ -271,7 +271,7 @@ async def test_ble_device_with_proxy_client_out_of_connections( local_name="wohand", service_uuids=[], manufacturer_data={1: b"\x01"} ) - class FakeScanner(BaseHaRemoteScanner): + class FakeScanner(HomeAssistantRemoteScanner): @property def discovered_devices(self) -> list[BLEDevice]: """Return a list of discovered devices.""" @@ -336,7 +336,7 @@ async def test_ble_device_with_proxy_clear_cache( local_name="wohand", service_uuids=[], manufacturer_data={1: b"\x01"} ) - class FakeScanner(BaseHaRemoteScanner): + class FakeScanner(HomeAssistantRemoteScanner): @property def discovered_devices(self) -> list[BLEDevice]: """Return a list of discovered devices.""" @@ -439,7 +439,7 @@ async def test_ble_device_with_proxy_client_out_of_connections_uses_best_availab "esp32_no_connection_slot", ) - class FakeScanner(BaseHaRemoteScanner): + class FakeScanner(HomeAssistantRemoteScanner): @property def discovered_devices(self) -> list[BLEDevice]: """Return a list of discovered devices.""" @@ -553,7 +553,7 @@ async def test_ble_device_with_proxy_client_out_of_connections_uses_best_availab "esp32_no_connection_slot", ) - class FakeScanner(BaseHaRemoteScanner): + class FakeScanner(HomeAssistantRemoteScanner): @property def discovered_devices(self) -> list[BLEDevice]: """Return a list of discovered devices.""" diff --git a/tests/components/bluetooth/test_wrappers.py b/tests/components/bluetooth/test_wrappers.py index f69f8971479..d3c2e1b54db 100644 --- a/tests/components/bluetooth/test_wrappers.py +++ b/tests/components/bluetooth/test_wrappers.py @@ -12,9 +12,9 @@ import pytest from homeassistant.components.bluetooth import ( MONOTONIC_TIME, - BaseHaRemoteScanner, BluetoothServiceInfoBleak, HaBluetoothConnector, + HomeAssistantRemoteScanner, async_get_advertisement_callback, ) from homeassistant.components.bluetooth.usage import ( @@ -26,7 +26,7 @@ from homeassistant.core import HomeAssistant from . import _get_manager, generate_advertisement_data, generate_ble_device -class FakeScanner(BaseHaRemoteScanner): +class FakeScanner(HomeAssistantRemoteScanner): """Fake scanner.""" def __init__(