Mark Bluetooth scanner as not scanning when watchdog timeout is reached (#100738)
parent
f837e6722c
commit
667f4b1ca8
|
@ -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]
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue