Mark Bluetooth scanner as not scanning when watchdog timeout is reached (#100738)
parent
f837e6722c
commit
667f4b1ca8
homeassistant/components/bluetooth
tests/components/bluetooth
|
@ -131,6 +131,9 @@ class BaseHaScanner(ABC):
|
||||||
self.name,
|
self.name,
|
||||||
SCANNER_WATCHDOG_TIMEOUT,
|
SCANNER_WATCHDOG_TIMEOUT,
|
||||||
)
|
)
|
||||||
|
self.scanning = False
|
||||||
|
return
|
||||||
|
self.scanning = not self._connecting
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def connecting(self) -> Generator[None, None, None]:
|
def connecting(self) -> Generator[None, None, None]:
|
||||||
|
@ -302,6 +305,7 @@ class BaseHaRemoteScanner(BaseHaScanner):
|
||||||
advertisement_monotonic_time: float,
|
advertisement_monotonic_time: float,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Call the registered callback."""
|
"""Call the registered callback."""
|
||||||
|
self.scanning = not self._connecting
|
||||||
self._last_detection = advertisement_monotonic_time
|
self._last_detection = advertisement_monotonic_time
|
||||||
try:
|
try:
|
||||||
prev_discovery = self._discovered_device_advertisement_datas[address]
|
prev_discovery = self._discovered_device_advertisement_datas[address]
|
||||||
|
|
|
@ -329,6 +329,9 @@ class HaScanner(BaseHaScanner):
|
||||||
self.name,
|
self.name,
|
||||||
SCANNER_WATCHDOG_TIMEOUT,
|
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())
|
self.hass.async_create_task(self._async_restart_scanner())
|
||||||
|
|
||||||
async def _async_restart_scanner(self) -> None:
|
async def _async_restart_scanner(self) -> None:
|
||||||
|
|
|
@ -23,6 +23,8 @@ from homeassistant.components.bluetooth.advertisement_tracker import (
|
||||||
from homeassistant.components.bluetooth.const import (
|
from homeassistant.components.bluetooth.const import (
|
||||||
CONNECTABLE_FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS,
|
CONNECTABLE_FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS,
|
||||||
FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS,
|
FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS,
|
||||||
|
SCANNER_WATCHDOG_INTERVAL,
|
||||||
|
SCANNER_WATCHDOG_TIMEOUT,
|
||||||
UNAVAILABLE_TRACK_SECONDS,
|
UNAVAILABLE_TRACK_SECONDS,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
|
@ -557,3 +559,82 @@ async def test_device_with_ten_minute_advertising_interval(
|
||||||
|
|
||||||
cancel()
|
cancel()
|
||||||
unsetup()
|
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