Mark Bluetooth scanner as not scanning when watchdog timeout is reached (#100738)

pull/100918/head
J. Nick Koston 2023-09-26 05:29:46 -05:00 committed by GitHub
parent f837e6722c
commit 667f4b1ca8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 88 additions and 0 deletions

View File

@ -131,6 +131,9 @@ class BaseHaScanner(ABC):
self.name,
SCANNER_WATCHDOG_TIMEOUT,
)
self.scanning = False
return
self.scanning = not self._connecting
@contextmanager
def connecting(self) -> Generator[None, None, None]:
@ -302,6 +305,7 @@ class BaseHaRemoteScanner(BaseHaScanner):
advertisement_monotonic_time: float,
) -> None:
"""Call the registered callback."""
self.scanning = not self._connecting
self._last_detection = advertisement_monotonic_time
try:
prev_discovery = self._discovered_device_advertisement_datas[address]

View File

@ -329,6 +329,9 @@ class HaScanner(BaseHaScanner):
self.name,
SCANNER_WATCHDOG_TIMEOUT,
)
# Immediately mark the scanner as not scanning
# since the restart task will have to wait for the lock
self.scanning = False
self.hass.async_create_task(self._async_restart_scanner())
async def _async_restart_scanner(self) -> None:

View File

@ -23,6 +23,8 @@ from homeassistant.components.bluetooth.advertisement_tracker import (
from homeassistant.components.bluetooth.const import (
CONNECTABLE_FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS,
FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS,
SCANNER_WATCHDOG_INTERVAL,
SCANNER_WATCHDOG_TIMEOUT,
UNAVAILABLE_TRACK_SECONDS,
)
from homeassistant.core import HomeAssistant, callback
@ -557,3 +559,82 @@ async def test_device_with_ten_minute_advertising_interval(
cancel()
unsetup()
async def test_scanner_stops_responding(
hass: HomeAssistant, caplog: pytest.LogCaptureFixture, enable_bluetooth: None
) -> None:
"""Test we mark a scanner are not scanning when it stops responding."""
manager = _get_manager()
class FakeScanner(BaseHaRemoteScanner):
"""A fake remote scanner."""
def inject_advertisement(
self, device: BLEDevice, advertisement_data: AdvertisementData
) -> None:
"""Inject an advertisement."""
self._async_on_advertisement(
device.address,
advertisement_data.rssi,
device.name,
advertisement_data.service_uuids,
advertisement_data.service_data,
advertisement_data.manufacturer_data,
advertisement_data.tx_power,
{"scanner_specific_data": "test"},
MONOTONIC_TIME(),
)
new_info_callback = manager.scanner_adv_received
connector = (
HaBluetoothConnector(MockBleakClient, "mock_bleak_client", lambda: False),
)
scanner = FakeScanner(hass, "esp32", "esp32", new_info_callback, connector, False)
unsetup = scanner.async_setup()
cancel = manager.async_register_scanner(scanner, True)
start_time_monotonic = time.monotonic()
assert scanner.scanning is True
failure_reached_time = (
start_time_monotonic
+ SCANNER_WATCHDOG_TIMEOUT
+ SCANNER_WATCHDOG_INTERVAL.total_seconds()
)
# We hit the timer with no detections, so we reset the adapter and restart the scanner
with patch(
"homeassistant.components.bluetooth.base_scanner.MONOTONIC_TIME",
return_value=failure_reached_time,
):
async_fire_time_changed(hass, dt_util.utcnow() + SCANNER_WATCHDOG_INTERVAL)
await hass.async_block_till_done()
assert scanner.scanning is False
bparasite_device = generate_ble_device(
"44:44:33:11:23:45",
"bparasite",
{},
rssi=-100,
)
bparasite_device_adv = generate_advertisement_data(
local_name="bparasite",
service_uuids=[],
manufacturer_data={1: b"\x01"},
rssi=-100,
)
failure_reached_time += 1
with patch(
"homeassistant.components.bluetooth.base_scanner.MONOTONIC_TIME",
return_value=failure_reached_time,
):
scanner.inject_advertisement(bparasite_device, bparasite_device_adv)
# As soon as we get a detection, we know the scanner is working again
assert scanner.scanning is True
cancel()
unsetup()