From 5dbd0dede1556be103e0588ddafa27c7829500d5 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 12 Dec 2023 22:17:48 -1000 Subject: [PATCH] Refactor Bluetooth scanners to avoid the need to pass a callback (#105607) --- .../components/bluetooth/__init__.py | 4 ++-- .../components/bluetooth/manifest.json | 2 +- .../components/esphome/bluetooth/__init__.py | 6 +----- .../components/ruuvi_gateway/bluetooth.py | 7 ------- .../components/shelly/bluetooth/__init__.py | 4 +--- homeassistant/package_constraints.txt | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/bluetooth/test_api.py | 13 ++++++++---- .../components/bluetooth/test_base_scanner.py | 20 ++++++------------- .../components/bluetooth/test_diagnostics.py | 3 +-- tests/components/bluetooth/test_manager.py | 7 ------- tests/components/bluetooth/test_models.py | 7 ++----- tests/components/bluetooth/test_wrappers.py | 15 +++----------- .../esphome/bluetooth/test_client.py | 4 +--- 15 files changed, 30 insertions(+), 68 deletions(-) diff --git a/homeassistant/components/bluetooth/__init__.py b/homeassistant/components/bluetooth/__init__.py index c4434f8695f..234712bddaf 100644 --- a/homeassistant/components/bluetooth/__init__.py +++ b/homeassistant/components/bluetooth/__init__.py @@ -106,6 +106,7 @@ __all__ = [ "async_scanner_by_source", "async_scanner_count", "async_scanner_devices_by_address", + "async_get_advertisement_callback", "BaseHaScanner", "HomeAssistantRemoteScanner", "BluetoothCallbackMatcher", @@ -287,9 +288,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: passive = entry.options.get(CONF_PASSIVE) mode = BluetoothScanningMode.PASSIVE if passive else BluetoothScanningMode.ACTIVE - new_info_callback = async_get_advertisement_callback(hass) manager: HomeAssistantBluetoothManager = hass.data[DATA_MANAGER] - scanner = HaScanner(mode, adapter, address, new_info_callback) + scanner = HaScanner(mode, adapter, address) try: scanner.async_setup() except RuntimeError as err: diff --git a/homeassistant/components/bluetooth/manifest.json b/homeassistant/components/bluetooth/manifest.json index 5abec24b6d1..a4c96c91727 100644 --- a/homeassistant/components/bluetooth/manifest.json +++ b/homeassistant/components/bluetooth/manifest.json @@ -20,6 +20,6 @@ "bluetooth-auto-recovery==1.2.3", "bluetooth-data-tools==1.17.0", "dbus-fast==2.21.0", - "habluetooth==0.11.1" + "habluetooth==1.0.0" ] } diff --git a/homeassistant/components/esphome/bluetooth/__init__.py b/homeassistant/components/esphome/bluetooth/__init__.py index 0fe28730fce..e7dd0697987 100644 --- a/homeassistant/components/esphome/bluetooth/__init__.py +++ b/homeassistant/components/esphome/bluetooth/__init__.py @@ -11,7 +11,6 @@ from aioesphomeapi import APIClient, BluetoothProxyFeature from homeassistant.components.bluetooth import ( HaBluetoothConnector, - async_get_advertisement_callback, async_register_scanner, ) from homeassistant.config_entries import ConfigEntry @@ -63,7 +62,6 @@ async def async_connect_scanner( """Connect scanner.""" assert entry.unique_id is not None source = str(entry.unique_id) - new_info_callback = async_get_advertisement_callback(hass) device_info = entry_data.device_info assert device_info is not None feature_flags = device_info.bluetooth_proxy_feature_flags_compat( @@ -98,9 +96,7 @@ async def async_connect_scanner( partial(_async_can_connect, entry_data, bluetooth_device, source) ), ) - scanner = ESPHomeScanner( - source, entry.title, new_info_callback, connector, connectable - ) + scanner = ESPHomeScanner(source, entry.title, connector, connectable) client_data.scanner = scanner coros: list[Coroutine[Any, Any, CALLBACK_TYPE]] = [] # These calls all return a callback that can be used to unsubscribe diff --git a/homeassistant/components/ruuvi_gateway/bluetooth.py b/homeassistant/components/ruuvi_gateway/bluetooth.py index 2d9bf8c6644..d3cf1e81379 100644 --- a/homeassistant/components/ruuvi_gateway/bluetooth.py +++ b/homeassistant/components/ruuvi_gateway/bluetooth.py @@ -1,17 +1,13 @@ """Bluetooth support for Ruuvi Gateway.""" from __future__ import annotations -from collections.abc import Callable import logging import time -from home_assistant_bluetooth import BluetoothServiceInfoBleak - from homeassistant.components.bluetooth import ( FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS, MONOTONIC_TIME, BaseHaRemoteScanner, - async_get_advertisement_callback, async_register_scanner, ) from homeassistant.config_entries import ConfigEntry @@ -29,7 +25,6 @@ class RuuviGatewayScanner(BaseHaRemoteScanner): self, scanner_id: str, name: str, - new_info_callback: Callable[[BluetoothServiceInfoBleak], None], *, coordinator: RuuviGatewayUpdateCoordinator, ) -> None: @@ -37,7 +32,6 @@ class RuuviGatewayScanner(BaseHaRemoteScanner): super().__init__( scanner_id, name, - new_info_callback, connector=None, connectable=False, ) @@ -87,7 +81,6 @@ def async_connect_scanner( scanner = RuuviGatewayScanner( scanner_id=source, name=entry.title, - new_info_callback=async_get_advertisement_callback(hass), coordinator=coordinator, ) unload_callbacks = [ diff --git a/homeassistant/components/shelly/bluetooth/__init__.py b/homeassistant/components/shelly/bluetooth/__init__.py index 007900a5cdc..92c630323ba 100644 --- a/homeassistant/components/shelly/bluetooth/__init__.py +++ b/homeassistant/components/shelly/bluetooth/__init__.py @@ -14,7 +14,6 @@ from aioshelly.ble.const import ( from homeassistant.components.bluetooth import ( HaBluetoothConnector, - async_get_advertisement_callback, async_register_scanner, ) from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback as hass_callback @@ -36,14 +35,13 @@ async def async_connect_scanner( device = coordinator.device entry = coordinator.entry source = format_mac(coordinator.mac).upper() - new_info_callback = async_get_advertisement_callback(hass) connector = HaBluetoothConnector( # no active connections to shelly yet client=None, # type: ignore[arg-type] source=source, can_connect=lambda: False, ) - scanner = ShellyBLEScanner(source, entry.title, new_info_callback, connector, False) + scanner = ShellyBLEScanner(source, entry.title, connector, False) unload_callbacks = [ async_register_scanner(hass, scanner, False), scanner.async_setup(), diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 53ed955f791..1832c61712e 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -23,7 +23,7 @@ dbus-fast==2.21.0 fnv-hash-fast==0.5.0 ha-av==10.1.1 ha-ffmpeg==3.1.0 -habluetooth==0.11.1 +habluetooth==1.0.0 hass-nabucasa==0.74.0 hassil==1.5.1 home-assistant-bluetooth==1.11.0 diff --git a/requirements_all.txt b/requirements_all.txt index ff852542d0d..2fdbe18fa27 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -984,7 +984,7 @@ ha-philipsjs==3.1.1 habitipy==0.2.0 # homeassistant.components.bluetooth -habluetooth==0.11.1 +habluetooth==1.0.0 # homeassistant.components.cloud hass-nabucasa==0.74.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index bb14d282a21..148d0597d8a 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -783,7 +783,7 @@ ha-philipsjs==3.1.1 habitipy==0.2.0 # homeassistant.components.bluetooth -habluetooth==0.11.1 +habluetooth==1.0.0 # homeassistant.components.cloud hass-nabucasa==0.74.0 diff --git a/tests/components/bluetooth/test_api.py b/tests/components/bluetooth/test_api.py index aee15f7874e..732fce4c8e2 100644 --- a/tests/components/bluetooth/test_api.py +++ b/tests/components/bluetooth/test_api.py @@ -40,6 +40,14 @@ async def test_monotonic_time() -> None: assert MONOTONIC_TIME() == pytest.approx(time.monotonic(), abs=0.1) +async def test_async_get_advertisement_callback( + hass: HomeAssistant, enable_bluetooth: None +) -> None: + """Test getting advertisement callback.""" + callback = bluetooth.async_get_advertisement_callback(hass) + assert callback is not None + + async def test_async_scanner_devices_by_address_connectable( hass: HomeAssistant, enable_bluetooth: None ) -> None: @@ -63,13 +71,10 @@ async def test_async_scanner_devices_by_address_connectable( MONOTONIC_TIME(), ) - new_info_callback = manager.scanner_adv_received connector = ( HaBluetoothConnector(MockBleakClient, "mock_bleak_client", lambda: False), ) - scanner = FakeInjectableScanner( - "esp32", "esp32", new_info_callback, connector, False - ) + scanner = FakeInjectableScanner("esp32", "esp32", connector, False) unsetup = scanner.async_setup() cancel = manager.async_register_scanner(scanner, True) switchbot_device = generate_ble_device( diff --git a/tests/components/bluetooth/test_base_scanner.py b/tests/components/bluetooth/test_base_scanner.py index c94e3c874e0..4f60fc9ef9b 100644 --- a/tests/components/bluetooth/test_base_scanner.py +++ b/tests/components/bluetooth/test_base_scanner.py @@ -111,11 +111,10 @@ async def test_remote_scanner( rssi=-100, ) - new_info_callback = manager.scanner_adv_received connector = ( HaBluetoothConnector(MockBleakClient, "mock_bleak_client", lambda: False), ) - scanner = FakeScanner("esp32", "esp32", new_info_callback, connector, True) + scanner = FakeScanner("esp32", "esp32", connector, True) unsetup = scanner.async_setup() cancel = manager.async_register_scanner(scanner, True) @@ -178,11 +177,10 @@ async def test_remote_scanner_expires_connectable( rssi=-100, ) - new_info_callback = manager.scanner_adv_received connector = ( HaBluetoothConnector(MockBleakClient, "mock_bleak_client", lambda: False), ) - scanner = FakeScanner("esp32", "esp32", new_info_callback, connector, True) + scanner = FakeScanner("esp32", "esp32", connector, True) unsetup = scanner.async_setup() cancel = manager.async_register_scanner(scanner, True) @@ -233,11 +231,10 @@ async def test_remote_scanner_expires_non_connectable( rssi=-100, ) - new_info_callback = manager.scanner_adv_received connector = ( HaBluetoothConnector(MockBleakClient, "mock_bleak_client", lambda: False), ) - scanner = FakeScanner("esp32", "esp32", new_info_callback, connector, False) + scanner = FakeScanner("esp32", "esp32", connector, False) unsetup = scanner.async_setup() cancel = manager.async_register_scanner(scanner, True) @@ -308,11 +305,10 @@ async def test_base_scanner_connecting_behavior( rssi=-100, ) - new_info_callback = manager.scanner_adv_received connector = ( HaBluetoothConnector(MockBleakClient, "mock_bleak_client", lambda: False), ) - scanner = FakeScanner("esp32", "esp32", new_info_callback, connector, False) + scanner = FakeScanner("esp32", "esp32", connector, False) unsetup = scanner.async_setup() cancel = manager.async_register_scanner(scanner, True) @@ -366,7 +362,6 @@ async def test_restore_history_remote_adapter( scanner = BaseHaRemoteScanner( "atom-bluetooth-proxy-ceaac4", "atom-bluetooth-proxy-ceaac4", - lambda adv: None, connector, True, ) @@ -381,7 +376,6 @@ async def test_restore_history_remote_adapter( scanner = BaseHaRemoteScanner( "atom-bluetooth-proxy-ceaac4", "atom-bluetooth-proxy-ceaac4", - lambda adv: None, connector, True, ) @@ -413,11 +407,10 @@ async def test_device_with_ten_minute_advertising_interval( rssi=-100, ) - new_info_callback = manager.scanner_adv_received connector = ( HaBluetoothConnector(MockBleakClient, "mock_bleak_client", lambda: False), ) - scanner = FakeScanner("esp32", "esp32", new_info_callback, connector, False) + scanner = FakeScanner("esp32", "esp32", connector, False) unsetup = scanner.async_setup() cancel = manager.async_register_scanner(scanner, True) @@ -505,11 +498,10 @@ async def test_scanner_stops_responding( """Test we mark a scanner are not scanning when it stops responding.""" manager = _get_manager() - new_info_callback = manager.scanner_adv_received connector = ( HaBluetoothConnector(MockBleakClient, "mock_bleak_client", lambda: False), ) - scanner = FakeScanner("esp32", "esp32", new_info_callback, connector, False) + scanner = FakeScanner("esp32", "esp32", connector, False) unsetup = scanner.async_setup() cancel = manager.async_register_scanner(scanner, True) diff --git a/tests/components/bluetooth/test_diagnostics.py b/tests/components/bluetooth/test_diagnostics.py index 8d87d5ef396..f70c301dcfe 100644 --- a/tests/components/bluetooth/test_diagnostics.py +++ b/tests/components/bluetooth/test_diagnostics.py @@ -454,11 +454,10 @@ async def test_diagnostics_remote_adapter( assert await hass.config_entries.async_setup(entry1.entry_id) await hass.async_block_till_done() - new_info_callback = manager.scanner_adv_received connector = ( HaBluetoothConnector(MockBleakClient, "mock_bleak_client", lambda: False), ) - scanner = FakeScanner("esp32", "esp32", new_info_callback, connector, False) + scanner = FakeScanner("esp32", "esp32", connector, False) unsetup = scanner.async_setup() cancel = manager.async_register_scanner(scanner, True) diff --git a/tests/components/bluetooth/test_manager.py b/tests/components/bluetooth/test_manager.py index 63201f790fe..2a470feacfa 100644 --- a/tests/components/bluetooth/test_manager.py +++ b/tests/components/bluetooth/test_manager.py @@ -20,7 +20,6 @@ from homeassistant.components.bluetooth import ( BluetoothServiceInfoBleak, HaBluetoothConnector, async_ble_device_from_address, - async_get_advertisement_callback, async_get_fallback_availability_interval, async_get_learned_advertising_interval, async_scanner_count, @@ -720,14 +719,12 @@ async def test_goes_unavailable_connectable_only_and_recovers( MONOTONIC_TIME(), ) - new_info_callback = async_get_advertisement_callback(hass) connector = ( HaBluetoothConnector(MockBleakClient, "mock_bleak_client", lambda: False), ) connectable_scanner = FakeScanner( "connectable", "connectable", - new_info_callback, connector, True, ) @@ -750,7 +747,6 @@ async def test_goes_unavailable_connectable_only_and_recovers( not_connectable_scanner = FakeScanner( "not_connectable", "not_connectable", - new_info_callback, connector, False, ) @@ -800,7 +796,6 @@ async def test_goes_unavailable_connectable_only_and_recovers( connectable_scanner_2 = FakeScanner( "connectable", "connectable", - new_info_callback, connector, True, ) @@ -896,14 +891,12 @@ async def test_goes_unavailable_dismisses_discovery_and_makes_discoverable( self._discovered_device_timestamps.clear() self._previous_service_info.clear() - new_info_callback = async_get_advertisement_callback(hass) connector = ( HaBluetoothConnector(MockBleakClient, "mock_bleak_client", lambda: False), ) non_connectable_scanner = FakeScanner( "connectable", "connectable", - new_info_callback, connector, False, ) diff --git a/tests/components/bluetooth/test_models.py b/tests/components/bluetooth/test_models.py index c0423aca357..6e8181b5a22 100644 --- a/tests/components/bluetooth/test_models.py +++ b/tests/components/bluetooth/test_models.py @@ -184,7 +184,6 @@ async def test_wrapped_bleak_client_set_disconnected_callback_after_connected( scanner = FakeScanner( "esp32_has_connection_slot", "esp32_has_connection_slot", - lambda info: None, connector, True, ) @@ -291,7 +290,7 @@ async def test_ble_device_with_proxy_client_out_of_connections( return None connector = HaBluetoothConnector(MockBleakClient, "esp32", lambda: False) - scanner = FakeScanner("esp32", "esp32", lambda info: None, connector, True) + scanner = FakeScanner("esp32", "esp32", connector, True) cancel = manager.async_register_scanner(scanner, True) inject_advertisement_with_source( hass, switchbot_proxy_device_no_connection_slot, switchbot_adv, "esp32" @@ -356,7 +355,7 @@ async def test_ble_device_with_proxy_clear_cache( return None connector = HaBluetoothConnector(MockBleakClient, "esp32", lambda: True) - scanner = FakeScanner("esp32", "esp32", lambda info: None, connector, True) + scanner = FakeScanner("esp32", "esp32", connector, True) cancel = manager.async_register_scanner(scanner, True) inject_advertisement_with_source( hass, switchbot_proxy_device_with_connection_slot, switchbot_adv, "esp32" @@ -464,7 +463,6 @@ async def test_ble_device_with_proxy_client_out_of_connections_uses_best_availab scanner = FakeScanner( "esp32_has_connection_slot", "esp32_has_connection_slot", - lambda info: None, connector, True, ) @@ -577,7 +575,6 @@ async def test_ble_device_with_proxy_client_out_of_connections_uses_best_availab scanner = FakeScanner( "esp32_has_connection_slot", "esp32_has_connection_slot", - lambda info: None, connector, True, ) diff --git a/tests/components/bluetooth/test_wrappers.py b/tests/components/bluetooth/test_wrappers.py index 6ebba080f6a..78ec5bd16ac 100644 --- a/tests/components/bluetooth/test_wrappers.py +++ b/tests/components/bluetooth/test_wrappers.py @@ -1,7 +1,6 @@ """Tests for the Bluetooth integration.""" from __future__ import annotations -from collections.abc import Callable from contextlib import contextmanager from unittest.mock import patch @@ -18,10 +17,8 @@ import pytest from homeassistant.components.bluetooth import ( MONOTONIC_TIME, BaseHaRemoteScanner, - BluetoothServiceInfoBleak, HaBluetoothConnector, HomeAssistantBluetoothManager, - async_get_advertisement_callback, ) from homeassistant.core import HomeAssistant @@ -43,12 +40,11 @@ class FakeScanner(BaseHaRemoteScanner): self, scanner_id: str, name: str, - new_info_callback: Callable[[BluetoothServiceInfoBleak], None], connector: None, connectable: bool, ) -> None: """Initialize the scanner.""" - super().__init__(scanner_id, name, new_info_callback, connector, connectable) + super().__init__(scanner_id, name, connector, connectable) self._details: dict[str, str | HaBluetoothConnector] = {} def __repr__(self) -> str: @@ -182,13 +178,8 @@ def _generate_scanners_with_fake_devices(hass): ) hci1_device_advs[device.address] = (device, adv_data) - new_info_callback = async_get_advertisement_callback(hass) - scanner_hci0 = FakeScanner( - "00:00:00:00:00:01", "hci0", new_info_callback, None, True - ) - scanner_hci1 = FakeScanner( - "00:00:00:00:00:02", "hci1", new_info_callback, None, True - ) + scanner_hci0 = FakeScanner("00:00:00:00:00:01", "hci0", None, True) + scanner_hci1 = FakeScanner("00:00:00:00:00:02", "hci1", None, True) for device, adv_data in hci0_device_advs.values(): scanner_hci0.inject_advertisement(device, adv_data) diff --git a/tests/components/esphome/bluetooth/test_client.py b/tests/components/esphome/bluetooth/test_client.py index d74766023d7..e770c75cf03 100644 --- a/tests/components/esphome/bluetooth/test_client.py +++ b/tests/components/esphome/bluetooth/test_client.py @@ -43,9 +43,7 @@ async def client_data_fixture( ), api_version=APIVersion(1, 9), title=ESP_NAME, - scanner=ESPHomeScanner( - ESP_MAC_ADDRESS, ESP_NAME, lambda info: None, connector, True - ), + scanner=ESPHomeScanner(ESP_MAC_ADDRESS, ESP_NAME, connector, True), )