Refactor Bluetooth scanners to avoid the need to pass a callback (#105607)

This commit is contained in:
J. Nick Koston 2023-12-12 22:17:48 -10:00 committed by GitHub
parent aaccf19013
commit 5dbd0dede1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 30 additions and 68 deletions

View file

@ -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:

View file

@ -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"
]
}

View file

@ -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

View file

@ -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 = [

View file

@ -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(),

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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(

View file

@ -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)

View file

@ -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)

View file

@ -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,
)

View file

@ -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,
)

View file

@ -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)

View file

@ -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),
)