637 lines
21 KiB
Python
637 lines
21 KiB
Python
"""Tests for the Bluetooth integration scanners."""
|
|
import asyncio
|
|
from datetime import timedelta
|
|
import time
|
|
from unittest.mock import ANY, MagicMock, patch
|
|
|
|
from bleak import BleakError
|
|
from bleak.backends.scanner import AdvertisementDataCallback
|
|
from dbus_fast import InvalidMessageError
|
|
import pytest
|
|
|
|
from homeassistant.components import bluetooth
|
|
from homeassistant.components.bluetooth.const import (
|
|
SCANNER_WATCHDOG_INTERVAL,
|
|
SCANNER_WATCHDOG_TIMEOUT,
|
|
)
|
|
from homeassistant.components.bluetooth.scanner import NEED_RESET_ERRORS
|
|
from homeassistant.config_entries import ConfigEntryState
|
|
from homeassistant.const import EVENT_HOMEASSISTANT_STARTED, EVENT_HOMEASSISTANT_STOP
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.setup import async_setup_component
|
|
from homeassistant.util import dt as dt_util
|
|
|
|
from . import (
|
|
_get_manager,
|
|
async_setup_with_one_adapter,
|
|
generate_advertisement_data,
|
|
generate_ble_device,
|
|
)
|
|
|
|
from tests.common import MockConfigEntry, async_fire_time_changed
|
|
|
|
|
|
async def test_config_entry_can_be_reloaded_when_stop_raises(
|
|
hass: HomeAssistant,
|
|
caplog: pytest.LogCaptureFixture,
|
|
enable_bluetooth: None,
|
|
macos_adapter: None,
|
|
) -> None:
|
|
"""Test we can reload if stopping the scanner raises."""
|
|
entry = hass.config_entries.async_entries(bluetooth.DOMAIN)[0]
|
|
assert entry.state == ConfigEntryState.LOADED
|
|
|
|
with patch(
|
|
"homeassistant.components.bluetooth.scanner.OriginalBleakScanner.stop",
|
|
side_effect=BleakError,
|
|
):
|
|
await hass.config_entries.async_reload(entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
assert entry.state == ConfigEntryState.LOADED
|
|
assert "Error stopping scanner" in caplog.text
|
|
|
|
|
|
async def test_dbus_socket_missing_in_container(
|
|
hass: HomeAssistant, caplog: pytest.LogCaptureFixture, one_adapter: None
|
|
) -> None:
|
|
"""Test we handle dbus being missing in the container."""
|
|
|
|
with patch(
|
|
"homeassistant.components.bluetooth.scanner.is_docker_env", return_value=True
|
|
), patch(
|
|
"homeassistant.components.bluetooth.scanner.OriginalBleakScanner.start",
|
|
side_effect=FileNotFoundError,
|
|
):
|
|
await async_setup_with_one_adapter(hass)
|
|
|
|
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
|
await hass.async_block_till_done()
|
|
|
|
hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP)
|
|
await hass.async_block_till_done()
|
|
assert "/run/dbus" in caplog.text
|
|
assert "docker" in caplog.text
|
|
|
|
|
|
async def test_dbus_socket_missing(
|
|
hass: HomeAssistant, caplog: pytest.LogCaptureFixture, one_adapter: None
|
|
) -> None:
|
|
"""Test we handle dbus being missing."""
|
|
|
|
with patch(
|
|
"homeassistant.components.bluetooth.scanner.is_docker_env", return_value=False
|
|
), patch(
|
|
"homeassistant.components.bluetooth.scanner.OriginalBleakScanner.start",
|
|
side_effect=FileNotFoundError,
|
|
):
|
|
await async_setup_with_one_adapter(hass)
|
|
|
|
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
|
await hass.async_block_till_done()
|
|
|
|
hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP)
|
|
await hass.async_block_till_done()
|
|
assert "DBus" in caplog.text
|
|
assert "docker" not in caplog.text
|
|
|
|
|
|
async def test_dbus_broken_pipe_in_container(
|
|
hass: HomeAssistant, caplog: pytest.LogCaptureFixture, one_adapter: None
|
|
) -> None:
|
|
"""Test we handle dbus broken pipe in the container."""
|
|
|
|
with patch(
|
|
"homeassistant.components.bluetooth.scanner.is_docker_env", return_value=True
|
|
), patch(
|
|
"homeassistant.components.bluetooth.scanner.OriginalBleakScanner.start",
|
|
side_effect=BrokenPipeError,
|
|
):
|
|
await async_setup_with_one_adapter(hass)
|
|
|
|
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
|
await hass.async_block_till_done()
|
|
|
|
hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP)
|
|
await hass.async_block_till_done()
|
|
assert "dbus" in caplog.text
|
|
assert "restarting" in caplog.text
|
|
assert "container" in caplog.text
|
|
|
|
|
|
async def test_dbus_broken_pipe(
|
|
hass: HomeAssistant, caplog: pytest.LogCaptureFixture, one_adapter: None
|
|
) -> None:
|
|
"""Test we handle dbus broken pipe."""
|
|
|
|
with patch(
|
|
"homeassistant.components.bluetooth.scanner.is_docker_env", return_value=False
|
|
), patch(
|
|
"homeassistant.components.bluetooth.scanner.OriginalBleakScanner.start",
|
|
side_effect=BrokenPipeError,
|
|
):
|
|
await async_setup_with_one_adapter(hass)
|
|
|
|
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
|
await hass.async_block_till_done()
|
|
|
|
hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP)
|
|
await hass.async_block_till_done()
|
|
assert "DBus" in caplog.text
|
|
assert "restarting" in caplog.text
|
|
assert "container" not in caplog.text
|
|
|
|
|
|
async def test_invalid_dbus_message(
|
|
hass: HomeAssistant, caplog: pytest.LogCaptureFixture, one_adapter: None
|
|
) -> None:
|
|
"""Test we handle invalid dbus message."""
|
|
|
|
with patch(
|
|
"homeassistant.components.bluetooth.scanner.OriginalBleakScanner.start",
|
|
side_effect=InvalidMessageError,
|
|
):
|
|
await async_setup_with_one_adapter(hass)
|
|
|
|
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
|
await hass.async_block_till_done()
|
|
|
|
hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP)
|
|
await hass.async_block_till_done()
|
|
assert "dbus" in caplog.text
|
|
|
|
|
|
@pytest.mark.parametrize("error", NEED_RESET_ERRORS)
|
|
async def test_adapter_needs_reset_at_start(
|
|
hass: HomeAssistant, caplog: pytest.LogCaptureFixture, one_adapter: None, error: str
|
|
) -> None:
|
|
"""Test we cycle the adapter when it needs a restart."""
|
|
|
|
with patch(
|
|
"homeassistant.components.bluetooth.scanner.OriginalBleakScanner.start",
|
|
side_effect=[BleakError(error), None],
|
|
), patch(
|
|
"homeassistant.components.bluetooth.util.recover_adapter", return_value=True
|
|
) as mock_recover_adapter:
|
|
await async_setup_with_one_adapter(hass)
|
|
|
|
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
|
await hass.async_block_till_done()
|
|
|
|
assert len(mock_recover_adapter.mock_calls) == 1
|
|
|
|
hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP)
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
async def test_recovery_from_dbus_restart(
|
|
hass: HomeAssistant, one_adapter: None
|
|
) -> None:
|
|
"""Test we can recover when DBus gets restarted out from under us."""
|
|
|
|
called_start = 0
|
|
called_stop = 0
|
|
_callback = None
|
|
mock_discovered = []
|
|
|
|
class MockBleakScanner:
|
|
def __init__(self, detection_callback, *args, **kwargs):
|
|
nonlocal _callback
|
|
_callback = detection_callback
|
|
|
|
async def start(self, *args, **kwargs):
|
|
"""Mock Start."""
|
|
nonlocal called_start
|
|
called_start += 1
|
|
|
|
async def stop(self, *args, **kwargs):
|
|
"""Mock Start."""
|
|
nonlocal called_stop
|
|
called_stop += 1
|
|
|
|
@property
|
|
def discovered_devices(self):
|
|
"""Mock discovered_devices."""
|
|
nonlocal mock_discovered
|
|
return mock_discovered
|
|
|
|
with patch(
|
|
"homeassistant.components.bluetooth.scanner.OriginalBleakScanner",
|
|
MockBleakScanner,
|
|
):
|
|
await async_setup_with_one_adapter(hass)
|
|
|
|
assert called_start == 1
|
|
|
|
start_time_monotonic = time.monotonic()
|
|
mock_discovered = [MagicMock()]
|
|
|
|
# Ensure we don't restart the scanner if we don't need to
|
|
with patch(
|
|
"homeassistant.components.bluetooth.base_scanner.MONOTONIC_TIME",
|
|
return_value=start_time_monotonic + 10,
|
|
):
|
|
async_fire_time_changed(hass, dt_util.utcnow() + SCANNER_WATCHDOG_INTERVAL)
|
|
await hass.async_block_till_done()
|
|
|
|
assert called_start == 1
|
|
|
|
# Fire a callback to reset the timer
|
|
with patch(
|
|
"homeassistant.components.bluetooth.base_scanner.MONOTONIC_TIME",
|
|
return_value=start_time_monotonic,
|
|
):
|
|
_callback(
|
|
generate_ble_device("44:44:33:11:23:42", "any_name"),
|
|
generate_advertisement_data(local_name="any_name"),
|
|
)
|
|
|
|
# Ensure we don't restart the scanner if we don't need to
|
|
with patch(
|
|
"homeassistant.components.bluetooth.base_scanner.MONOTONIC_TIME",
|
|
return_value=start_time_monotonic + 20,
|
|
):
|
|
async_fire_time_changed(hass, dt_util.utcnow() + SCANNER_WATCHDOG_INTERVAL)
|
|
await hass.async_block_till_done()
|
|
|
|
assert called_start == 1
|
|
|
|
# We hit the timer, so we restart the scanner
|
|
with patch(
|
|
"homeassistant.components.bluetooth.base_scanner.MONOTONIC_TIME",
|
|
return_value=start_time_monotonic + SCANNER_WATCHDOG_TIMEOUT + 20,
|
|
):
|
|
async_fire_time_changed(
|
|
hass, dt_util.utcnow() + SCANNER_WATCHDOG_INTERVAL + timedelta(seconds=20)
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert called_start == 2
|
|
|
|
|
|
async def test_adapter_recovery(hass: HomeAssistant, one_adapter: None) -> None:
|
|
"""Test we can recover when the adapter stops responding."""
|
|
|
|
called_start = 0
|
|
called_stop = 0
|
|
_callback = None
|
|
mock_discovered = []
|
|
|
|
class MockBleakScanner:
|
|
async def start(self, *args, **kwargs):
|
|
"""Mock Start."""
|
|
nonlocal called_start
|
|
called_start += 1
|
|
|
|
async def stop(self, *args, **kwargs):
|
|
"""Mock Start."""
|
|
nonlocal called_stop
|
|
called_stop += 1
|
|
|
|
@property
|
|
def discovered_devices(self):
|
|
"""Mock discovered_devices."""
|
|
nonlocal mock_discovered
|
|
return mock_discovered
|
|
|
|
def register_detection_callback(self, callback: AdvertisementDataCallback):
|
|
"""Mock Register Detection Callback."""
|
|
nonlocal _callback
|
|
_callback = callback
|
|
|
|
scanner = MockBleakScanner()
|
|
start_time_monotonic = time.monotonic()
|
|
|
|
with patch(
|
|
"homeassistant.components.bluetooth.base_scanner.MONOTONIC_TIME",
|
|
return_value=start_time_monotonic,
|
|
), patch(
|
|
"homeassistant.components.bluetooth.scanner.OriginalBleakScanner",
|
|
return_value=scanner,
|
|
):
|
|
await async_setup_with_one_adapter(hass)
|
|
|
|
assert called_start == 1
|
|
|
|
scanner = _get_manager()
|
|
mock_discovered = [MagicMock()]
|
|
|
|
# Ensure we don't restart the scanner if we don't need to
|
|
with patch(
|
|
"homeassistant.components.bluetooth.base_scanner.MONOTONIC_TIME",
|
|
return_value=start_time_monotonic + 10,
|
|
):
|
|
async_fire_time_changed(hass, dt_util.utcnow() + SCANNER_WATCHDOG_INTERVAL)
|
|
await hass.async_block_till_done()
|
|
|
|
assert called_start == 1
|
|
|
|
# Ensure we don't restart the scanner if we don't need to
|
|
with patch(
|
|
"homeassistant.components.bluetooth.base_scanner.MONOTONIC_TIME",
|
|
return_value=start_time_monotonic + 20,
|
|
):
|
|
async_fire_time_changed(hass, dt_util.utcnow() + SCANNER_WATCHDOG_INTERVAL)
|
|
await hass.async_block_till_done()
|
|
|
|
assert called_start == 1
|
|
|
|
# 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=start_time_monotonic
|
|
+ SCANNER_WATCHDOG_TIMEOUT
|
|
+ SCANNER_WATCHDOG_INTERVAL.total_seconds(),
|
|
), patch(
|
|
"homeassistant.components.bluetooth.util.recover_adapter", return_value=True
|
|
) as mock_recover_adapter:
|
|
async_fire_time_changed(hass, dt_util.utcnow() + SCANNER_WATCHDOG_INTERVAL)
|
|
await hass.async_block_till_done()
|
|
|
|
assert len(mock_recover_adapter.mock_calls) == 1
|
|
assert called_start == 2
|
|
|
|
|
|
async def test_adapter_scanner_fails_to_start_first_time(
|
|
hass: HomeAssistant, one_adapter: None
|
|
) -> None:
|
|
"""Test we can recover when the adapter stops responding and the first recovery fails."""
|
|
|
|
called_start = 0
|
|
called_stop = 0
|
|
_callback = None
|
|
mock_discovered = []
|
|
|
|
class MockBleakScanner:
|
|
async def start(self, *args, **kwargs):
|
|
"""Mock Start."""
|
|
nonlocal called_start
|
|
called_start += 1
|
|
if called_start == 1:
|
|
return # Start ok the first time
|
|
if called_start < 4:
|
|
raise BleakError("Failed to start")
|
|
|
|
async def stop(self, *args, **kwargs):
|
|
"""Mock Start."""
|
|
nonlocal called_stop
|
|
called_stop += 1
|
|
|
|
@property
|
|
def discovered_devices(self):
|
|
"""Mock discovered_devices."""
|
|
nonlocal mock_discovered
|
|
return mock_discovered
|
|
|
|
def register_detection_callback(self, callback: AdvertisementDataCallback):
|
|
"""Mock Register Detection Callback."""
|
|
nonlocal _callback
|
|
_callback = callback
|
|
|
|
scanner = MockBleakScanner()
|
|
start_time_monotonic = time.monotonic()
|
|
|
|
with patch(
|
|
"homeassistant.components.bluetooth.base_scanner.MONOTONIC_TIME",
|
|
return_value=start_time_monotonic,
|
|
), patch(
|
|
"homeassistant.components.bluetooth.scanner.OriginalBleakScanner",
|
|
return_value=scanner,
|
|
):
|
|
await async_setup_with_one_adapter(hass)
|
|
|
|
assert called_start == 1
|
|
|
|
scanner = _get_manager()
|
|
mock_discovered = [MagicMock()]
|
|
|
|
# Ensure we don't restart the scanner if we don't need to
|
|
with patch(
|
|
"homeassistant.components.bluetooth.base_scanner.MONOTONIC_TIME",
|
|
return_value=start_time_monotonic + 10,
|
|
):
|
|
async_fire_time_changed(hass, dt_util.utcnow() + SCANNER_WATCHDOG_INTERVAL)
|
|
await hass.async_block_till_done()
|
|
|
|
assert called_start == 1
|
|
|
|
# Ensure we don't restart the scanner if we don't need to
|
|
with patch(
|
|
"homeassistant.components.bluetooth.base_scanner.MONOTONIC_TIME",
|
|
return_value=start_time_monotonic + 20,
|
|
):
|
|
async_fire_time_changed(hass, dt_util.utcnow() + SCANNER_WATCHDOG_INTERVAL)
|
|
await hass.async_block_till_done()
|
|
|
|
assert called_start == 1
|
|
|
|
# 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=start_time_monotonic
|
|
+ SCANNER_WATCHDOG_TIMEOUT
|
|
+ SCANNER_WATCHDOG_INTERVAL.total_seconds(),
|
|
), patch(
|
|
"homeassistant.components.bluetooth.util.recover_adapter", return_value=True
|
|
) as mock_recover_adapter:
|
|
async_fire_time_changed(hass, dt_util.utcnow() + SCANNER_WATCHDOG_INTERVAL)
|
|
await hass.async_block_till_done()
|
|
|
|
assert len(mock_recover_adapter.mock_calls) == 1
|
|
assert called_start == 3
|
|
|
|
# We hit the timer again the previous start call failed, make sure
|
|
# we try again
|
|
with patch(
|
|
"homeassistant.components.bluetooth.base_scanner.MONOTONIC_TIME",
|
|
return_value=start_time_monotonic
|
|
+ SCANNER_WATCHDOG_TIMEOUT
|
|
+ SCANNER_WATCHDOG_INTERVAL.total_seconds(),
|
|
), patch(
|
|
"homeassistant.components.bluetooth.util.recover_adapter", return_value=True
|
|
) as mock_recover_adapter:
|
|
async_fire_time_changed(hass, dt_util.utcnow() + SCANNER_WATCHDOG_INTERVAL)
|
|
await hass.async_block_till_done()
|
|
|
|
assert len(mock_recover_adapter.mock_calls) == 1
|
|
assert called_start == 4
|
|
|
|
|
|
async def test_adapter_fails_to_start_and_takes_a_bit_to_init(
|
|
hass: HomeAssistant, one_adapter: None, caplog: pytest.LogCaptureFixture
|
|
) -> None:
|
|
"""Test we can recover the adapter at startup and we wait for Dbus to init."""
|
|
assert await async_setup_component(hass, "logger", {})
|
|
await hass.services.async_call(
|
|
"logger",
|
|
"set_level",
|
|
{"homeassistant.components.bluetooth": "DEBUG"},
|
|
blocking=True,
|
|
)
|
|
called_start = 0
|
|
called_stop = 0
|
|
_callback = None
|
|
mock_discovered = []
|
|
|
|
class MockBleakScanner:
|
|
async def start(self, *args, **kwargs):
|
|
"""Mock Start."""
|
|
nonlocal called_start
|
|
called_start += 1
|
|
if called_start == 1:
|
|
raise BleakError("org.bluez.Error.InProgress")
|
|
if called_start == 2:
|
|
raise BleakError("org.freedesktop.DBus.Error.UnknownObject")
|
|
|
|
async def stop(self, *args, **kwargs):
|
|
"""Mock Start."""
|
|
nonlocal called_stop
|
|
called_stop += 1
|
|
|
|
@property
|
|
def discovered_devices(self):
|
|
"""Mock discovered_devices."""
|
|
nonlocal mock_discovered
|
|
return mock_discovered
|
|
|
|
def register_detection_callback(self, callback: AdvertisementDataCallback):
|
|
"""Mock Register Detection Callback."""
|
|
nonlocal _callback
|
|
_callback = callback
|
|
|
|
scanner = MockBleakScanner()
|
|
start_time_monotonic = time.monotonic()
|
|
|
|
with patch(
|
|
"homeassistant.components.bluetooth.scanner.ADAPTER_INIT_TIME",
|
|
0,
|
|
), patch(
|
|
"homeassistant.components.bluetooth.base_scanner.MONOTONIC_TIME",
|
|
return_value=start_time_monotonic,
|
|
), patch(
|
|
"homeassistant.components.bluetooth.scanner.OriginalBleakScanner",
|
|
return_value=scanner,
|
|
), patch(
|
|
"homeassistant.components.bluetooth.util.recover_adapter", return_value=True
|
|
) as mock_recover_adapter:
|
|
await async_setup_with_one_adapter(hass)
|
|
|
|
assert called_start == 3
|
|
|
|
assert len(mock_recover_adapter.mock_calls) == 1
|
|
assert "Waiting for adapter to initialize" in caplog.text
|
|
|
|
|
|
async def test_restart_takes_longer_than_watchdog_time(
|
|
hass: HomeAssistant, one_adapter: None, caplog: pytest.LogCaptureFixture
|
|
) -> None:
|
|
"""Test we do not try to recover the adapter again if the restart is still in progress."""
|
|
|
|
release_start_event = asyncio.Event()
|
|
called_start = 0
|
|
|
|
class MockBleakScanner:
|
|
async def start(self, *args, **kwargs):
|
|
"""Mock Start."""
|
|
nonlocal called_start
|
|
called_start += 1
|
|
if called_start == 1:
|
|
return
|
|
await release_start_event.wait()
|
|
|
|
async def stop(self, *args, **kwargs):
|
|
"""Mock Start."""
|
|
|
|
@property
|
|
def discovered_devices(self):
|
|
"""Mock discovered_devices."""
|
|
return []
|
|
|
|
def register_detection_callback(self, callback: AdvertisementDataCallback):
|
|
"""Mock Register Detection Callback."""
|
|
|
|
scanner = MockBleakScanner()
|
|
start_time_monotonic = time.monotonic()
|
|
|
|
with patch(
|
|
"homeassistant.components.bluetooth.scanner.ADAPTER_INIT_TIME",
|
|
0,
|
|
), patch(
|
|
"homeassistant.components.bluetooth.base_scanner.MONOTONIC_TIME",
|
|
return_value=start_time_monotonic,
|
|
), patch(
|
|
"homeassistant.components.bluetooth.scanner.OriginalBleakScanner",
|
|
return_value=scanner,
|
|
), patch(
|
|
"homeassistant.components.bluetooth.util.recover_adapter", return_value=True
|
|
):
|
|
await async_setup_with_one_adapter(hass)
|
|
|
|
assert called_start == 1
|
|
|
|
# Now force a recover adapter 2x
|
|
for _ in range(2):
|
|
with patch(
|
|
"homeassistant.components.bluetooth.base_scanner.MONOTONIC_TIME",
|
|
return_value=start_time_monotonic
|
|
+ SCANNER_WATCHDOG_TIMEOUT
|
|
+ SCANNER_WATCHDOG_INTERVAL.total_seconds(),
|
|
):
|
|
async_fire_time_changed(
|
|
hass, dt_util.utcnow() + SCANNER_WATCHDOG_INTERVAL
|
|
)
|
|
await asyncio.sleep(0)
|
|
|
|
# Now release the start event
|
|
release_start_event.set()
|
|
await hass.async_block_till_done()
|
|
|
|
assert "already restarting" in caplog.text
|
|
|
|
|
|
async def test_setup_and_stop_macos(
|
|
hass: HomeAssistant, mock_bleak_scanner_start: MagicMock, macos_adapter: None
|
|
) -> None:
|
|
"""Test we enable use_bdaddr on MacOS."""
|
|
entry = MockConfigEntry(
|
|
domain=bluetooth.DOMAIN,
|
|
data={},
|
|
unique_id="00:00:00:00:00:00",
|
|
)
|
|
entry.add_to_hass(hass)
|
|
init_kwargs = None
|
|
|
|
class MockBleakScanner:
|
|
def __init__(self, *args, **kwargs):
|
|
"""Init the scanner."""
|
|
nonlocal init_kwargs
|
|
init_kwargs = kwargs
|
|
|
|
async def start(self, *args, **kwargs):
|
|
"""Start the scanner."""
|
|
|
|
async def stop(self, *args, **kwargs):
|
|
"""Stop the scanner."""
|
|
|
|
def register_detection_callback(self, *args, **kwargs):
|
|
"""Register a callback."""
|
|
|
|
with patch(
|
|
"homeassistant.components.bluetooth.scanner.OriginalBleakScanner",
|
|
MockBleakScanner,
|
|
):
|
|
assert await async_setup_component(
|
|
hass, bluetooth.DOMAIN, {bluetooth.DOMAIN: {}}
|
|
)
|
|
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
|
await hass.async_block_till_done()
|
|
|
|
hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP)
|
|
await hass.async_block_till_done()
|
|
|
|
assert init_kwargs == {
|
|
"detection_callback": ANY,
|
|
"scanning_mode": "active",
|
|
"cb": {"use_bdaddr": True},
|
|
}
|