mirror of
https://github.com/home-assistant/core.git
synced 2026-08-24 10:13:52 -05:00
Allow bluetooth coordinators to request an active scan cadence (#172015)
This commit is contained in:
@@ -68,9 +68,20 @@ class ActiveBluetoothProcessorCoordinator[_DataT](
|
||||
| None = None,
|
||||
poll_debouncer: Debouncer[Coroutine[Any, Any, None]] | None = None,
|
||||
connectable: bool = True,
|
||||
scan_interval: float | None = None,
|
||||
scan_duration: float | None = None,
|
||||
) -> None:
|
||||
"""Initialize the processor."""
|
||||
super().__init__(hass, logger, address, mode, update_method, connectable)
|
||||
super().__init__(
|
||||
hass,
|
||||
logger,
|
||||
address,
|
||||
mode,
|
||||
update_method,
|
||||
connectable,
|
||||
scan_interval,
|
||||
scan_duration,
|
||||
)
|
||||
|
||||
self._needs_poll_method = needs_poll_method
|
||||
self._poll_method = poll_method
|
||||
|
||||
@@ -298,9 +298,13 @@ class PassiveBluetoothProcessorCoordinator[_DataT](BasePassiveBluetoothCoordinat
|
||||
mode: BluetoothScanningMode,
|
||||
update_method: Callable[[BluetoothServiceInfoBleak], _DataT],
|
||||
connectable: bool = False,
|
||||
scan_interval: float | None = None,
|
||||
scan_duration: float | None = None,
|
||||
) -> None:
|
||||
"""Initialize the coordinator."""
|
||||
super().__init__(hass, logger, address, mode, connectable)
|
||||
super().__init__(
|
||||
hass, logger, address, mode, connectable, scan_interval, scan_duration
|
||||
)
|
||||
self._processors: list[PassiveBluetoothDataProcessor[Any, _DataT]] = []
|
||||
self._update_method = update_method
|
||||
self.last_update_success = True
|
||||
|
||||
@@ -30,6 +30,8 @@ class BasePassiveBluetoothCoordinator(ABC):
|
||||
address: str,
|
||||
mode: BluetoothScanningMode,
|
||||
connectable: bool,
|
||||
scan_interval: float | None = None,
|
||||
scan_duration: float | None = None,
|
||||
) -> None:
|
||||
"""Initialize the coordinator."""
|
||||
self.hass = hass
|
||||
@@ -38,6 +40,8 @@ class BasePassiveBluetoothCoordinator(ABC):
|
||||
self.connectable = connectable
|
||||
self._on_stop: list[CALLBACK_TYPE] = []
|
||||
self.mode = mode
|
||||
self._scan_interval = scan_interval
|
||||
self._scan_duration = scan_duration
|
||||
self._last_unavailable_time = 0.0
|
||||
self._last_name = address
|
||||
# Subclasses are responsible for setting _available to True
|
||||
@@ -92,6 +96,8 @@ class BasePassiveBluetoothCoordinator(ABC):
|
||||
address=self.address, connectable=self.connectable
|
||||
),
|
||||
self.mode,
|
||||
scan_interval=self._scan_interval,
|
||||
scan_duration=self._scan_duration,
|
||||
)
|
||||
)
|
||||
self._on_stop.append(
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
from unittest.mock import MagicMock, call
|
||||
from unittest.mock import MagicMock, call, patch
|
||||
|
||||
from bleak import BleakError
|
||||
import pytest
|
||||
@@ -15,6 +15,7 @@ from homeassistant.components.bluetooth import (
|
||||
from homeassistant.components.bluetooth.active_update_processor import (
|
||||
ActiveBluetoothProcessorCoordinator,
|
||||
)
|
||||
from homeassistant.components.bluetooth.manager import HomeAssistantBluetoothManager
|
||||
from homeassistant.core import CoreState, HomeAssistant
|
||||
from homeassistant.helpers.debounce import Debouncer
|
||||
from homeassistant.helpers.service_info.bluetooth import BluetoothServiceInfo
|
||||
@@ -422,3 +423,44 @@ async def test_no_polling_after_stop_event(hass: HomeAssistant) -> None:
|
||||
assert needs_poll_calls == 1
|
||||
|
||||
cancel()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_bleak_scanner_start", "mock_bluetooth_adapters")
|
||||
async def test_scan_interval_and_duration_forwarded(hass: HomeAssistant) -> None:
|
||||
"""Test scan_interval and scan_duration reach the bluetooth manager."""
|
||||
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
|
||||
|
||||
def _update_method(service_info: BluetoothServiceInfoBleak):
|
||||
return {"testdata": 0}
|
||||
|
||||
def _poll_needed(*args, **kwargs):
|
||||
return False
|
||||
|
||||
async def _poll(*args, **kwargs):
|
||||
return {"testdata": 1}
|
||||
|
||||
coordinator = ActiveBluetoothProcessorCoordinator(
|
||||
hass,
|
||||
_LOGGER,
|
||||
address="aa:bb:cc:dd:ee:ff",
|
||||
mode=BluetoothScanningMode.ACTIVE,
|
||||
update_method=_update_method,
|
||||
needs_poll_method=_poll_needed,
|
||||
poll_method=_poll,
|
||||
scan_interval=165.0,
|
||||
scan_duration=10.0,
|
||||
)
|
||||
|
||||
cancel_scan = MagicMock()
|
||||
with patch.object(
|
||||
HomeAssistantBluetoothManager,
|
||||
"async_register_active_scan",
|
||||
return_value=cancel_scan,
|
||||
) as mock_register:
|
||||
cancel = coordinator.async_start()
|
||||
|
||||
mock_register.assert_called_once_with("aa:bb:cc:dd:ee:ff", 165.0, 10.0)
|
||||
cancel_scan.assert_not_called()
|
||||
|
||||
cancel()
|
||||
cancel_scan.assert_called_once()
|
||||
|
||||
@@ -703,7 +703,9 @@ async def test_exception_from_update_method(
|
||||
assert coordinator.available is False # no data yet
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
def _async_register_callback(
|
||||
_hass, _callback, _matcher, _mode, *, scan_interval=None, scan_duration=None
|
||||
):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
@@ -768,7 +770,9 @@ async def test_bad_data_from_update_method(hass: HomeAssistant) -> None:
|
||||
assert coordinator.available is False # no data yet
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
def _async_register_callback(
|
||||
_hass, _callback, _matcher, _mode, *, scan_interval=None, scan_duration=None
|
||||
):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
@@ -501,7 +501,9 @@ async def test_async_step_reauth(hass: HomeAssistant) -> None:
|
||||
entry.add_to_hass(hass)
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
def _async_register_callback(
|
||||
_hass, _callback, _matcher, _mode, *, scan_interval=None, scan_duration=None
|
||||
):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
@@ -541,7 +543,9 @@ async def test_async_step_reauth_wrong_key(hass: HomeAssistant) -> None:
|
||||
entry.add_to_hass(hass)
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
def _async_register_callback(
|
||||
_hass, _callback, _matcher, _mode, *, scan_interval=None, scan_duration=None
|
||||
):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
@@ -40,7 +40,9 @@ async def _setup_entry(
|
||||
|
||||
saved_callback: Callable[[object, BluetoothChange], None] | None = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
def _async_register_callback(
|
||||
_hass, _callback, _matcher, _mode, *, scan_interval=None, scan_duration=None
|
||||
):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
@@ -1162,7 +1162,9 @@ async def test_async_step_reauth_legacy(hass: HomeAssistant) -> None:
|
||||
entry.add_to_hass(hass)
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
def _async_register_callback(
|
||||
_hass, _callback, _matcher, _mode, *, scan_interval=None, scan_duration=None
|
||||
):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
@@ -1211,7 +1213,9 @@ async def test_async_step_reauth_legacy_wrong_key(hass: HomeAssistant) -> None:
|
||||
entry.add_to_hass(hass)
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
def _async_register_callback(
|
||||
_hass, _callback, _matcher, _mode, *, scan_interval=None, scan_duration=None
|
||||
):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
@@ -1268,7 +1272,9 @@ async def test_async_step_reauth_v4(hass: HomeAssistant) -> None:
|
||||
entry.add_to_hass(hass)
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
def _async_register_callback(
|
||||
_hass, _callback, _matcher, _mode, *, scan_interval=None, scan_duration=None
|
||||
):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
@@ -1322,7 +1328,9 @@ async def test_async_step_reauth_v4_wrong_key(hass: HomeAssistant) -> None:
|
||||
entry.add_to_hass(hass)
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
def _async_register_callback(
|
||||
_hass, _callback, _matcher, _mode, *, scan_interval=None, scan_duration=None
|
||||
):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
@@ -1384,7 +1392,9 @@ async def test_async_step_reauth_v4_from_cloud(hass: HomeAssistant) -> None:
|
||||
entry.add_to_hass(hass)
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
def _async_register_callback(
|
||||
_hass, _callback, _matcher, _mode, *, scan_interval=None, scan_duration=None
|
||||
):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
Reference in New Issue
Block a user