Reduce overhead to update passive bluetooth devices (#78545)
This commit is contained in:
parent
b093c2840b
commit
085abc74ee
25 changed files with 364 additions and 709 deletions
|
@ -103,6 +103,16 @@ def async_discovered_service_info(
|
|||
return _get_manager(hass).async_discovered_service_info(connectable)
|
||||
|
||||
|
||||
@hass_callback
|
||||
def async_last_service_info(
|
||||
hass: HomeAssistant, address: str, connectable: bool = True
|
||||
) -> BluetoothServiceInfoBleak | None:
|
||||
"""Return the last service info for an address."""
|
||||
if DATA_MANAGER not in hass.data:
|
||||
return None
|
||||
return _get_manager(hass).async_last_service_info(address, connectable)
|
||||
|
||||
|
||||
@hass_callback
|
||||
def async_ble_device_from_address(
|
||||
hass: HomeAssistant, address: str, connectable: bool = True
|
||||
|
@ -173,7 +183,7 @@ async def async_process_advertisements(
|
|||
@hass_callback
|
||||
def async_track_unavailable(
|
||||
hass: HomeAssistant,
|
||||
callback: Callable[[str], None],
|
||||
callback: Callable[[BluetoothServiceInfoBleak], None],
|
||||
address: str,
|
||||
connectable: bool = True,
|
||||
) -> Callable[[], None]:
|
||||
|
|
|
@ -143,9 +143,11 @@ class BluetoothManager:
|
|||
self.hass = hass
|
||||
self._integration_matcher = integration_matcher
|
||||
self._cancel_unavailable_tracking: list[CALLBACK_TYPE] = []
|
||||
self._unavailable_callbacks: dict[str, list[Callable[[str], None]]] = {}
|
||||
self._unavailable_callbacks: dict[
|
||||
str, list[Callable[[BluetoothServiceInfoBleak], None]]
|
||||
] = {}
|
||||
self._connectable_unavailable_callbacks: dict[
|
||||
str, list[Callable[[str], None]]
|
||||
str, list[Callable[[BluetoothServiceInfoBleak], None]]
|
||||
] = {}
|
||||
self._callback_index = BluetoothCallbackMatcherIndex()
|
||||
self._bleak_callbacks: list[
|
||||
|
@ -269,12 +271,12 @@ class BluetoothManager:
|
|||
}
|
||||
disappeared = history_set.difference(active_addresses)
|
||||
for address in disappeared:
|
||||
del history[address]
|
||||
service_info = history.pop(address)
|
||||
if not (callbacks := unavailable_callbacks.get(address)):
|
||||
continue
|
||||
for callback in callbacks:
|
||||
try:
|
||||
callback(address)
|
||||
callback(service_info)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
_LOGGER.exception("Error in unavailable callback")
|
||||
|
||||
|
@ -358,7 +360,10 @@ class BluetoothManager:
|
|||
|
||||
@hass_callback
|
||||
def async_track_unavailable(
|
||||
self, callback: Callable[[str], None], address: str, connectable: bool
|
||||
self,
|
||||
callback: Callable[[BluetoothServiceInfoBleak], None],
|
||||
address: str,
|
||||
connectable: bool,
|
||||
) -> Callable[[], None]:
|
||||
"""Register a callback."""
|
||||
unavailable_callbacks = self._get_unavailable_callbacks_by_type(connectable)
|
||||
|
@ -430,9 +435,16 @@ class BluetoothManager:
|
|||
def async_discovered_service_info(
|
||||
self, connectable: bool
|
||||
) -> Iterable[BluetoothServiceInfoBleak]:
|
||||
"""Return if the address is present."""
|
||||
"""Return all the discovered services info."""
|
||||
return self._get_history_by_type(connectable).values()
|
||||
|
||||
@hass_callback
|
||||
def async_last_service_info(
|
||||
self, address: str, connectable: bool
|
||||
) -> BluetoothServiceInfoBleak | None:
|
||||
"""Return the last service info for an address."""
|
||||
return self._get_history_by_type(connectable).get(address)
|
||||
|
||||
@hass_callback
|
||||
def async_rediscover_address(self, address: str) -> None:
|
||||
"""Trigger discovery of devices which have already been seen."""
|
||||
|
@ -448,7 +460,7 @@ class BluetoothManager:
|
|||
|
||||
def _get_unavailable_callbacks_by_type(
|
||||
self, connectable: bool
|
||||
) -> dict[str, list[Callable[[str], None]]]:
|
||||
) -> dict[str, list[Callable[[BluetoothServiceInfoBleak], None]]]:
|
||||
"""Return the unavailable callbacks by type."""
|
||||
return (
|
||||
self._connectable_unavailable_callbacks
|
||||
|
|
|
@ -41,9 +41,11 @@ class PassiveBluetoothDataUpdateCoordinator(BasePassiveBluetoothCoordinator):
|
|||
update_callback()
|
||||
|
||||
@callback
|
||||
def _async_handle_unavailable(self, address: str) -> None:
|
||||
def _async_handle_unavailable(
|
||||
self, service_info: BluetoothServiceInfoBleak
|
||||
) -> None:
|
||||
"""Handle the device going unavailable."""
|
||||
super()._async_handle_unavailable(address)
|
||||
super()._async_handle_unavailable(service_info)
|
||||
self.async_update_listeners()
|
||||
|
||||
@callback
|
||||
|
@ -73,7 +75,6 @@ class PassiveBluetoothDataUpdateCoordinator(BasePassiveBluetoothCoordinator):
|
|||
change: BluetoothChange,
|
||||
) -> None:
|
||||
"""Handle a Bluetooth event."""
|
||||
super()._async_handle_bluetooth_event(service_info, change)
|
||||
self.async_update_listeners()
|
||||
|
||||
|
||||
|
|
|
@ -101,9 +101,11 @@ class PassiveBluetoothProcessorCoordinator(
|
|||
return remove_processor
|
||||
|
||||
@callback
|
||||
def _async_handle_unavailable(self, address: str) -> None:
|
||||
def _async_handle_unavailable(
|
||||
self, service_info: BluetoothServiceInfoBleak
|
||||
) -> None:
|
||||
"""Handle the device going unavailable."""
|
||||
super()._async_handle_unavailable(address)
|
||||
super()._async_handle_unavailable(service_info)
|
||||
for processor in self._processors:
|
||||
processor.async_handle_unavailable()
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
"""Update coordinator for the Bluetooth integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import abstractmethod
|
||||
import logging
|
||||
import time
|
||||
|
||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
|
||||
|
||||
|
@ -11,6 +11,8 @@ from . import (
|
|||
BluetoothChange,
|
||||
BluetoothScanningMode,
|
||||
BluetoothServiceInfoBleak,
|
||||
async_address_present,
|
||||
async_last_service_info,
|
||||
async_register_callback,
|
||||
async_track_unavailable,
|
||||
)
|
||||
|
@ -33,14 +35,13 @@ class BasePassiveBluetoothCoordinator:
|
|||
"""Initialize the coordinator."""
|
||||
self.hass = hass
|
||||
self.logger = logger
|
||||
self.name: str | None = None
|
||||
self.address = address
|
||||
self.connectable = connectable
|
||||
self._cancel_track_unavailable: CALLBACK_TYPE | None = None
|
||||
self._cancel_bluetooth_advertisements: CALLBACK_TYPE | None = None
|
||||
self._present = False
|
||||
self.mode = mode
|
||||
self.last_seen = 0.0
|
||||
self._last_unavailable_time = 0.0
|
||||
self._last_name = address
|
||||
|
||||
@callback
|
||||
def async_start(self) -> CALLBACK_TYPE:
|
||||
|
@ -53,10 +54,41 @@ class BasePassiveBluetoothCoordinator:
|
|||
|
||||
return _async_cancel
|
||||
|
||||
@callback
|
||||
@abstractmethod
|
||||
def _async_handle_bluetooth_event(
|
||||
self,
|
||||
service_info: BluetoothServiceInfoBleak,
|
||||
change: BluetoothChange,
|
||||
) -> None:
|
||||
"""Handle a bluetooth event."""
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return last known name of the device."""
|
||||
if service_info := async_last_service_info(
|
||||
self.hass, self.address, self.connectable
|
||||
):
|
||||
return service_info.name
|
||||
return self._last_name
|
||||
|
||||
@property
|
||||
def last_seen(self) -> float:
|
||||
"""Return the last time the device was seen."""
|
||||
# If the device is unavailable it will not have a service
|
||||
# info and fall through below.
|
||||
if service_info := async_last_service_info(
|
||||
self.hass, self.address, self.connectable
|
||||
):
|
||||
return service_info.time
|
||||
# This is the time from the last advertisement that
|
||||
# was set when the unavailable callback was called.
|
||||
return self._last_unavailable_time
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
"""Return if the device is available."""
|
||||
return self._present
|
||||
return async_address_present(self.hass, self.address, self.connectable)
|
||||
|
||||
@callback
|
||||
def _async_start(self) -> None:
|
||||
|
@ -84,17 +116,9 @@ class BasePassiveBluetoothCoordinator:
|
|||
self._cancel_track_unavailable = None
|
||||
|
||||
@callback
|
||||
def _async_handle_unavailable(self, address: str) -> None:
|
||||
"""Handle the device going unavailable."""
|
||||
self._present = False
|
||||
|
||||
@callback
|
||||
def _async_handle_bluetooth_event(
|
||||
self,
|
||||
service_info: BluetoothServiceInfoBleak,
|
||||
change: BluetoothChange,
|
||||
def _async_handle_unavailable(
|
||||
self, service_info: BluetoothServiceInfoBleak
|
||||
) -> None:
|
||||
"""Handle a Bluetooth event."""
|
||||
self.last_seen = time.monotonic()
|
||||
self.name = service_info.name
|
||||
self._present = True
|
||||
"""Handle the device going unavailable."""
|
||||
self._last_unavailable_time = service_info.time
|
||||
self._last_name = service_info.name
|
||||
|
|
|
@ -56,7 +56,9 @@ class YALEXSBLEEntity(Entity):
|
|||
self.async_write_ha_state()
|
||||
|
||||
@callback
|
||||
def _async_device_unavailable(self, _address: str) -> None:
|
||||
def _async_device_unavailable(
|
||||
self, _service_info: bluetooth.BluetoothServiceInfoBleak
|
||||
) -> None:
|
||||
"""Handle device not longer being seen by the bluetooth stack."""
|
||||
self._attr_available = False
|
||||
self.async_write_ha_state()
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
"""Test the BlueMaestro sensors."""
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.components.bluemaestro.const import DOMAIN
|
||||
from homeassistant.components.bluetooth import BluetoothChange
|
||||
from homeassistant.components.sensor import ATTR_STATE_CLASS
|
||||
from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
|
||||
|
||||
from . import BLUEMAESTRO_SERVICE_INFO
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.bluetooth import inject_bluetooth_service_info
|
||||
|
||||
|
||||
async def test_sensors(hass):
|
||||
|
@ -20,22 +19,11 @@ async def test_sensors(hass):
|
|||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all("sensor")) == 0
|
||||
saved_callback(BLUEMAESTRO_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, BLUEMAESTRO_SERVICE_INFO)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_all("sensor")) == 4
|
||||
|
||||
|
|
|
@ -19,6 +19,16 @@ from homeassistant.setup import async_setup_component
|
|||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
__all__ = (
|
||||
"inject_advertisement",
|
||||
"inject_advertisement_with_source",
|
||||
"inject_advertisement_with_time_and_source",
|
||||
"inject_advertisement_with_time_and_source_connectable",
|
||||
"inject_bluetooth_service_info",
|
||||
"patch_all_discovered_devices",
|
||||
"patch_discovered_devices",
|
||||
)
|
||||
|
||||
|
||||
def _get_manager() -> BluetoothManager:
|
||||
"""Return the bluetooth manager."""
|
||||
|
@ -80,6 +90,51 @@ def inject_advertisement_with_time_and_source_connectable(
|
|||
)
|
||||
|
||||
|
||||
def inject_bluetooth_service_info_bleak(
|
||||
hass: HomeAssistant, info: models.BluetoothServiceInfoBleak
|
||||
) -> None:
|
||||
"""Inject an advertisement into the manager with connectable status."""
|
||||
advertisement_data = AdvertisementData( # type: ignore[no-untyped-call]
|
||||
local_name=None if info.name == "" else info.name,
|
||||
manufacturer_data=info.manufacturer_data,
|
||||
service_data=info.service_data,
|
||||
service_uuids=info.service_uuids,
|
||||
)
|
||||
device = BLEDevice( # type: ignore[no-untyped-call]
|
||||
address=info.address,
|
||||
name=info.name,
|
||||
details={},
|
||||
rssi=info.rssi,
|
||||
)
|
||||
inject_advertisement_with_time_and_source_connectable(
|
||||
hass,
|
||||
device,
|
||||
advertisement_data,
|
||||
info.time,
|
||||
SOURCE_LOCAL,
|
||||
connectable=info.connectable,
|
||||
)
|
||||
|
||||
|
||||
def inject_bluetooth_service_info(
|
||||
hass: HomeAssistant, info: models.BluetoothServiceInfo
|
||||
) -> None:
|
||||
"""Inject a BluetoothServiceInfo into the manager."""
|
||||
advertisement_data = AdvertisementData( # type: ignore[no-untyped-call]
|
||||
local_name=None if info.name == "" else info.name,
|
||||
manufacturer_data=info.manufacturer_data,
|
||||
service_data=info.service_data,
|
||||
service_uuids=info.service_uuids,
|
||||
)
|
||||
device = BLEDevice( # type: ignore[no-untyped-call]
|
||||
address=info.address,
|
||||
name=info.name,
|
||||
details={},
|
||||
rssi=info.rssi,
|
||||
)
|
||||
inject_advertisement(hass, device, advertisement_data)
|
||||
|
||||
|
||||
def patch_all_discovered_devices(mock_discovered: list[BLEDevice]) -> None:
|
||||
"""Mock all the discovered devices from all the scanners."""
|
||||
return patch.object(
|
||||
|
@ -87,18 +142,6 @@ def patch_all_discovered_devices(mock_discovered: list[BLEDevice]) -> None:
|
|||
)
|
||||
|
||||
|
||||
def patch_history(mock_history: dict[str, models.BluetoothServiceInfoBleak]) -> None:
|
||||
"""Patch the history."""
|
||||
return patch.dict(_get_manager()._history, mock_history)
|
||||
|
||||
|
||||
def patch_connectable_history(
|
||||
mock_history: dict[str, models.BluetoothServiceInfoBleak]
|
||||
) -> None:
|
||||
"""Patch the connectable history."""
|
||||
return patch.dict(_get_manager()._connectable_history, mock_history)
|
||||
|
||||
|
||||
def patch_discovered_devices(mock_discovered: list[BLEDevice]) -> None:
|
||||
"""Mock the combined best path to discovered devices from all the scanners."""
|
||||
return patch.object(
|
||||
|
|
|
@ -3,13 +3,12 @@ from __future__ import annotations
|
|||
|
||||
import asyncio
|
||||
import logging
|
||||
from unittest.mock import MagicMock, call, patch
|
||||
from unittest.mock import MagicMock, call
|
||||
|
||||
from bleak import BleakError
|
||||
|
||||
from homeassistant.components.bluetooth import (
|
||||
DOMAIN,
|
||||
BluetoothChange,
|
||||
BluetoothScanningMode,
|
||||
BluetoothServiceInfoBleak,
|
||||
)
|
||||
|
@ -21,6 +20,8 @@ from homeassistant.helpers.debounce import Debouncer
|
|||
from homeassistant.helpers.service_info.bluetooth import BluetoothServiceInfo
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from tests.components.bluetooth import inject_bluetooth_service_info
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
@ -60,26 +61,14 @@ async def test_basic_usage(hass: HomeAssistant, mock_bleak_scanner_start):
|
|||
poll_method=_poll,
|
||||
)
|
||||
assert coordinator.available is False # no data yet
|
||||
saved_callback = None
|
||||
|
||||
processor = MagicMock()
|
||||
coordinator.async_register_processor(processor)
|
||||
async_handle_update = processor.async_handle_update
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
cancel = coordinator.async_start()
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
cancel = coordinator.async_start()
|
||||
|
||||
assert saved_callback is not None
|
||||
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert coordinator.available is True
|
||||
|
@ -126,38 +115,26 @@ async def test_poll_can_be_skipped(hass: HomeAssistant, mock_bleak_scanner_start
|
|||
),
|
||||
)
|
||||
assert coordinator.available is False # no data yet
|
||||
saved_callback = None
|
||||
|
||||
processor = MagicMock()
|
||||
coordinator.async_register_processor(processor)
|
||||
async_handle_update = processor.async_handle_update
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
cancel = coordinator.async_start()
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
cancel = coordinator.async_start()
|
||||
|
||||
assert saved_callback is not None
|
||||
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
await hass.async_block_till_done()
|
||||
assert async_handle_update.mock_calls[-1] == call({"testdata": True})
|
||||
|
||||
flag = False
|
||||
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
await hass.async_block_till_done()
|
||||
assert async_handle_update.mock_calls[-1] == call({"testdata": None})
|
||||
|
||||
flag = True
|
||||
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
await hass.async_block_till_done()
|
||||
assert async_handle_update.mock_calls[-1] == call({"testdata": True})
|
||||
|
||||
|
@ -200,27 +177,15 @@ async def test_bleak_error_and_recover(
|
|||
),
|
||||
)
|
||||
assert coordinator.available is False # no data yet
|
||||
saved_callback = None
|
||||
|
||||
processor = MagicMock()
|
||||
coordinator.async_register_processor(processor)
|
||||
async_handle_update = processor.async_handle_update
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
cancel = coordinator.async_start()
|
||||
|
||||
assert saved_callback is not None
|
||||
cancel = coordinator.async_start()
|
||||
|
||||
# First poll fails
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
await hass.async_block_till_done()
|
||||
assert async_handle_update.mock_calls[-1] == call({"testdata": None})
|
||||
|
||||
|
@ -231,7 +196,7 @@ async def test_bleak_error_and_recover(
|
|||
|
||||
# Second poll works
|
||||
flag = False
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
await hass.async_block_till_done()
|
||||
assert async_handle_update.mock_calls[-1] == call({"testdata": False})
|
||||
|
||||
|
@ -272,33 +237,21 @@ async def test_poll_failure_and_recover(hass: HomeAssistant, mock_bleak_scanner_
|
|||
),
|
||||
)
|
||||
assert coordinator.available is False # no data yet
|
||||
saved_callback = None
|
||||
|
||||
processor = MagicMock()
|
||||
coordinator.async_register_processor(processor)
|
||||
async_handle_update = processor.async_handle_update
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
cancel = coordinator.async_start()
|
||||
|
||||
assert saved_callback is not None
|
||||
cancel = coordinator.async_start()
|
||||
|
||||
# First poll fails
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
await hass.async_block_till_done()
|
||||
assert async_handle_update.mock_calls[-1] == call({"testdata": None})
|
||||
|
||||
# Second poll works
|
||||
flag = False
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
await hass.async_block_till_done()
|
||||
assert async_handle_update.mock_calls[-1] == call({"testdata": False})
|
||||
|
||||
|
@ -334,29 +287,17 @@ async def test_second_poll_needed(hass: HomeAssistant, mock_bleak_scanner_start)
|
|||
poll_method=_poll,
|
||||
)
|
||||
assert coordinator.available is False # no data yet
|
||||
saved_callback = None
|
||||
|
||||
processor = MagicMock()
|
||||
coordinator.async_register_processor(processor)
|
||||
async_handle_update = processor.async_handle_update
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
cancel = coordinator.async_start()
|
||||
|
||||
assert saved_callback is not None
|
||||
cancel = coordinator.async_start()
|
||||
|
||||
# First poll gets queued
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
# Second poll gets stuck behind first poll
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
assert async_handle_update.mock_calls[-1] == call({"testdata": 1})
|
||||
|
@ -392,31 +333,19 @@ async def test_rate_limit(hass: HomeAssistant, mock_bleak_scanner_start):
|
|||
poll_method=_poll,
|
||||
)
|
||||
assert coordinator.available is False # no data yet
|
||||
saved_callback = None
|
||||
|
||||
processor = MagicMock()
|
||||
coordinator.async_register_processor(processor)
|
||||
async_handle_update = processor.async_handle_update
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
cancel = coordinator.async_start()
|
||||
|
||||
assert saved_callback is not None
|
||||
cancel = coordinator.async_start()
|
||||
|
||||
# First poll gets queued
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
# Second poll gets stuck behind first poll
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
# Third poll gets stuck behind first poll doesn't get queued
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
assert async_handle_update.mock_calls[-1] == call({"testdata": 1})
|
||||
|
|
|
@ -20,9 +20,10 @@ from homeassistant.helpers.service_info.bluetooth import BluetoothServiceInfo
|
|||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from . import patch_all_discovered_devices, patch_history
|
||||
from . import patch_all_discovered_devices
|
||||
|
||||
from tests.common import async_fire_time_changed
|
||||
from tests.components.bluetooth import inject_bluetooth_service_info
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -65,32 +66,20 @@ async def test_basic_usage(hass, mock_bleak_scanner_start):
|
|||
hass, _LOGGER, "aa:bb:cc:dd:ee:ff", BluetoothScanningMode.ACTIVE
|
||||
)
|
||||
assert coordinator.available is False # no data yet
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
mock_listener = MagicMock()
|
||||
unregister_listener = coordinator.async_add_listener(mock_listener)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
cancel = coordinator.async_start()
|
||||
cancel = coordinator.async_start()
|
||||
|
||||
assert saved_callback is not None
|
||||
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
|
||||
assert len(mock_listener.mock_calls) == 1
|
||||
assert coordinator.data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
|
||||
assert coordinator.available is True
|
||||
|
||||
unregister_listener()
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
|
||||
assert len(mock_listener.mock_calls) == 1
|
||||
assert coordinator.data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
|
||||
|
@ -107,21 +96,11 @@ async def test_context_compatiblity_with_data_update_coordinator(
|
|||
hass, _LOGGER, "aa:bb:cc:dd:ee:ff", BluetoothScanningMode.ACTIVE
|
||||
)
|
||||
assert coordinator.available is False # no data yet
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
mock_listener = MagicMock()
|
||||
coordinator.async_add_listener(mock_listener)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
coordinator.async_start()
|
||||
coordinator.async_start()
|
||||
|
||||
assert not set(coordinator.async_contexts())
|
||||
|
||||
|
@ -158,41 +137,27 @@ async def test_unavailable_callbacks_mark_the_coordinator_unavailable(
|
|||
hass, _LOGGER, "aa:bb:cc:dd:ee:ff", BluetoothScanningMode.PASSIVE
|
||||
)
|
||||
assert coordinator.available is False # no data yet
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
mock_listener = MagicMock()
|
||||
coordinator.async_add_listener(mock_listener)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
coordinator.async_start()
|
||||
coordinator.async_start()
|
||||
|
||||
assert coordinator.available is False
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
assert coordinator.available is True
|
||||
|
||||
with patch_all_discovered_devices(
|
||||
[MagicMock(address="44:44:33:11:23:45")]
|
||||
), patch_history({"aa:bb:cc:dd:ee:ff": MagicMock()}):
|
||||
with patch_all_discovered_devices([MagicMock(address="44:44:33:11:23:45")]):
|
||||
async_fire_time_changed(
|
||||
hass, dt_util.utcnow() + timedelta(seconds=UNAVAILABLE_TRACK_SECONDS)
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert coordinator.available is False
|
||||
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
assert coordinator.available is True
|
||||
|
||||
with patch_all_discovered_devices(
|
||||
[MagicMock(address="44:44:33:11:23:45")]
|
||||
), patch_history({"aa:bb:cc:dd:ee:ff": MagicMock()}):
|
||||
with patch_all_discovered_devices([MagicMock(address="44:44:33:11:23:45")]):
|
||||
async_fire_time_changed(
|
||||
hass, dt_util.utcnow() + timedelta(seconds=UNAVAILABLE_TRACK_SECONDS)
|
||||
)
|
||||
|
@ -209,21 +174,10 @@ async def test_passive_bluetooth_coordinator_entity(hass, mock_bleak_scanner_sta
|
|||
entity = PassiveBluetoothCoordinatorEntity(coordinator)
|
||||
assert entity.available is False
|
||||
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
coordinator.async_start()
|
||||
coordinator.async_start()
|
||||
|
||||
assert coordinator.available is False
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
assert coordinator.available is True
|
||||
entity.hass = hass
|
||||
await entity.async_update()
|
||||
|
|
|
@ -3,6 +3,7 @@ from __future__ import annotations
|
|||
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
import time
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from home_assistant_bluetooth import BluetoothServiceInfo
|
||||
|
@ -16,6 +17,7 @@ from homeassistant.components.bluetooth import (
|
|||
DOMAIN,
|
||||
BluetoothChange,
|
||||
BluetoothScanningMode,
|
||||
BluetoothServiceInfoBleak,
|
||||
)
|
||||
from homeassistant.components.bluetooth.const import UNAVAILABLE_TRACK_SECONDS
|
||||
from homeassistant.components.bluetooth.passive_update_processor import (
|
||||
|
@ -32,9 +34,13 @@ from homeassistant.helpers.entity import DeviceInfo
|
|||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from . import patch_all_discovered_devices, patch_connectable_history, patch_history
|
||||
from . import patch_all_discovered_devices
|
||||
|
||||
from tests.common import MockEntityPlatform, async_fire_time_changed
|
||||
from tests.components.bluetooth import (
|
||||
inject_bluetooth_service_info,
|
||||
inject_bluetooth_service_info_bleak,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -50,6 +56,7 @@ GENERIC_BLUETOOTH_SERVICE_INFO = BluetoothServiceInfo(
|
|||
service_uuids=[],
|
||||
source="local",
|
||||
)
|
||||
|
||||
GENERIC_PASSIVE_BLUETOOTH_DATA_UPDATE = PassiveBluetoothDataUpdate(
|
||||
devices={
|
||||
None: DeviceInfo(
|
||||
|
@ -105,21 +112,11 @@ async def test_basic_usage(hass, mock_bleak_scanner_start):
|
|||
_mock_update_method,
|
||||
)
|
||||
assert coordinator.available is False # no data yet
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
processor = PassiveBluetoothDataProcessor(_async_generate_mock_data)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
unregister_processor = coordinator.async_register_processor(processor)
|
||||
cancel_coordinator = coordinator.async_start()
|
||||
unregister_processor = coordinator.async_register_processor(processor)
|
||||
cancel_coordinator = coordinator.async_start()
|
||||
|
||||
entity_key = PassiveBluetoothEntityKey("temperature", None)
|
||||
entity_key_events = []
|
||||
|
@ -149,7 +146,7 @@ async def test_basic_usage(hass, mock_bleak_scanner_start):
|
|||
mock_add_entities,
|
||||
)
|
||||
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
|
||||
# Each listener should receive the same data
|
||||
# since both match
|
||||
|
@ -159,7 +156,7 @@ async def test_basic_usage(hass, mock_bleak_scanner_start):
|
|||
# There should be 4 calls to create entities
|
||||
assert len(mock_entity.mock_calls) == 2
|
||||
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
|
||||
# Each listener should receive the same data
|
||||
# since both match
|
||||
|
@ -174,7 +171,7 @@ async def test_basic_usage(hass, mock_bleak_scanner_start):
|
|||
cancel_listener()
|
||||
cancel_async_add_entities_listener()
|
||||
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
|
||||
# Each listener should not trigger any more now
|
||||
# that they were cancelled
|
||||
|
@ -217,20 +214,11 @@ async def test_unavailable_after_no_data(hass, mock_bleak_scanner_start):
|
|||
_mock_update_method,
|
||||
)
|
||||
assert coordinator.available is False # no data yet
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
processor = PassiveBluetoothDataProcessor(_async_generate_mock_data)
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
unregister_processor = coordinator.async_register_processor(processor)
|
||||
cancel_coordinator = coordinator.async_start()
|
||||
|
||||
unregister_processor = coordinator.async_register_processor(processor)
|
||||
cancel_coordinator = coordinator.async_start()
|
||||
|
||||
mock_entity = MagicMock()
|
||||
mock_add_entities = MagicMock()
|
||||
|
@ -242,38 +230,49 @@ async def test_unavailable_after_no_data(hass, mock_bleak_scanner_start):
|
|||
assert coordinator.available is False
|
||||
assert processor.available is False
|
||||
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
now = time.monotonic()
|
||||
service_info_at_time = BluetoothServiceInfoBleak(
|
||||
name="Generic",
|
||||
address="aa:bb:cc:dd:ee:ff",
|
||||
rssi=-95,
|
||||
manufacturer_data={
|
||||
1: b"\x01\x01\x01\x01\x01\x01\x01\x01",
|
||||
},
|
||||
service_data={},
|
||||
service_uuids=[],
|
||||
source="local",
|
||||
time=now,
|
||||
device=MagicMock(),
|
||||
advertisement=MagicMock(),
|
||||
connectable=True,
|
||||
)
|
||||
|
||||
inject_bluetooth_service_info_bleak(hass, service_info_at_time)
|
||||
assert len(mock_add_entities.mock_calls) == 1
|
||||
assert coordinator.available is True
|
||||
assert processor.available is True
|
||||
with patch_all_discovered_devices(
|
||||
[MagicMock(address="44:44:33:11:23:45")]
|
||||
), patch_history({"aa:bb:cc:dd:ee:ff": MagicMock()}), patch_connectable_history(
|
||||
{"aa:bb:cc:dd:ee:ff": MagicMock()},
|
||||
):
|
||||
with patch_all_discovered_devices([MagicMock(address="44:44:33:11:23:45")]):
|
||||
async_fire_time_changed(
|
||||
hass, dt_util.utcnow() + timedelta(seconds=UNAVAILABLE_TRACK_SECONDS)
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert coordinator.available is False
|
||||
assert processor.available is False
|
||||
assert coordinator.last_seen == service_info_at_time.time
|
||||
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info_bleak(hass, service_info_at_time)
|
||||
assert len(mock_add_entities.mock_calls) == 1
|
||||
assert coordinator.available is True
|
||||
assert processor.available is True
|
||||
|
||||
with patch_all_discovered_devices(
|
||||
[MagicMock(address="44:44:33:11:23:45")]
|
||||
), patch_history({"aa:bb:cc:dd:ee:ff": MagicMock()}), patch_connectable_history(
|
||||
{"aa:bb:cc:dd:ee:ff": MagicMock()},
|
||||
):
|
||||
with patch_all_discovered_devices([MagicMock(address="44:44:33:11:23:45")]):
|
||||
async_fire_time_changed(
|
||||
hass, dt_util.utcnow() + timedelta(seconds=UNAVAILABLE_TRACK_SECONDS)
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert coordinator.available is False
|
||||
assert processor.available is False
|
||||
assert coordinator.last_seen == service_info_at_time.time
|
||||
|
||||
unregister_processor()
|
||||
cancel_coordinator()
|
||||
|
@ -304,21 +303,11 @@ async def test_no_updates_once_stopping(hass, mock_bleak_scanner_start):
|
|||
_mock_update_method,
|
||||
)
|
||||
assert coordinator.available is False # no data yet
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
processor = PassiveBluetoothDataProcessor(_async_generate_mock_data)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
unregister_processor = coordinator.async_register_processor(processor)
|
||||
cancel_coordinator = coordinator.async_start()
|
||||
unregister_processor = coordinator.async_register_processor(processor)
|
||||
cancel_coordinator = coordinator.async_start()
|
||||
|
||||
all_events = []
|
||||
|
||||
|
@ -330,13 +319,13 @@ async def test_no_updates_once_stopping(hass, mock_bleak_scanner_start):
|
|||
_all_listener,
|
||||
)
|
||||
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
assert len(all_events) == 1
|
||||
|
||||
hass.state = CoreState.stopping
|
||||
|
||||
# We should stop processing events once hass is stopping
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
assert len(all_events) == 1
|
||||
unregister_processor()
|
||||
cancel_coordinator()
|
||||
|
@ -361,7 +350,7 @@ async def test_exception_from_update_method(hass, caplog, mock_bleak_scanner_sta
|
|||
"""Generate mock data."""
|
||||
nonlocal run_count
|
||||
run_count += 1
|
||||
if run_count == 2:
|
||||
if run_count == 1:
|
||||
raise Exception("Test exception")
|
||||
return GENERIC_PASSIVE_BLUETOOTH_DATA_UPDATE
|
||||
|
||||
|
@ -390,7 +379,7 @@ async def test_exception_from_update_method(hass, caplog, mock_bleak_scanner_sta
|
|||
|
||||
processor.async_add_listener(MagicMock())
|
||||
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
assert processor.available is True
|
||||
|
||||
# We should go unavailable once we get an exception
|
||||
|
@ -424,7 +413,7 @@ async def test_bad_data_from_update_method(hass, mock_bleak_scanner_start):
|
|||
"""Generate mock data."""
|
||||
nonlocal run_count
|
||||
run_count += 1
|
||||
if run_count == 2:
|
||||
if run_count == 1:
|
||||
return "bad_data"
|
||||
return GENERIC_PASSIVE_BLUETOOTH_DATA_UPDATE
|
||||
|
||||
|
@ -453,7 +442,7 @@ async def test_bad_data_from_update_method(hass, mock_bleak_scanner_start):
|
|||
|
||||
processor.async_add_listener(MagicMock())
|
||||
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
assert processor.available is True
|
||||
|
||||
# We should go unavailable once we get bad data
|
||||
|
@ -788,20 +777,11 @@ async def test_integration_with_entity(hass, mock_bleak_scanner_start):
|
|||
_mock_update_method,
|
||||
)
|
||||
assert coordinator.available is False # no data yet
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
processor = PassiveBluetoothDataProcessor(_async_generate_mock_data)
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
coordinator.async_register_processor(processor)
|
||||
cancel_coordinator = coordinator.async_start()
|
||||
|
||||
coordinator.async_register_processor(processor)
|
||||
cancel_coordinator = coordinator.async_start()
|
||||
|
||||
processor.async_add_listener(MagicMock())
|
||||
|
||||
|
@ -812,19 +792,19 @@ async def test_integration_with_entity(hass, mock_bleak_scanner_start):
|
|||
mock_add_entities,
|
||||
)
|
||||
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
# First call with just the remote sensor entities results in them being added
|
||||
assert len(mock_add_entities.mock_calls) == 1
|
||||
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
# Second call with just the remote sensor entities does not add them again
|
||||
assert len(mock_add_entities.mock_calls) == 1
|
||||
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
# Third call with primary and remote sensor entities adds the primary sensor entities
|
||||
assert len(mock_add_entities.mock_calls) == 2
|
||||
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
# Forth call with both primary and remote sensor entities does not add them again
|
||||
assert len(mock_add_entities.mock_calls) == 2
|
||||
|
||||
|
@ -908,20 +888,11 @@ async def test_integration_with_entity_without_a_device(hass, mock_bleak_scanner
|
|||
_mock_update_method,
|
||||
)
|
||||
assert coordinator.available is False # no data yet
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
processor = PassiveBluetoothDataProcessor(_async_generate_mock_data)
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
coordinator.async_register_processor(processor)
|
||||
cancel_coordinator = coordinator.async_start()
|
||||
|
||||
coordinator.async_register_processor(processor)
|
||||
cancel_coordinator = coordinator.async_start()
|
||||
|
||||
mock_add_entities = MagicMock()
|
||||
|
||||
|
@ -930,11 +901,11 @@ async def test_integration_with_entity_without_a_device(hass, mock_bleak_scanner
|
|||
mock_add_entities,
|
||||
)
|
||||
|
||||
saved_callback(NO_DEVICES_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, NO_DEVICES_BLUETOOTH_SERVICE_INFO)
|
||||
# First call with just the remote sensor entities results in them being added
|
||||
assert len(mock_add_entities.mock_calls) == 1
|
||||
|
||||
saved_callback(NO_DEVICES_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, NO_DEVICES_BLUETOOTH_SERVICE_INFO)
|
||||
# Second call with just the remote sensor entities does not add them again
|
||||
assert len(mock_add_entities.mock_calls) == 1
|
||||
|
||||
|
@ -982,20 +953,11 @@ async def test_passive_bluetooth_entity_with_entity_platform(
|
|||
_mock_update_method,
|
||||
)
|
||||
assert coordinator.available is False # no data yet
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
processor = PassiveBluetoothDataProcessor(_async_generate_mock_data)
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
coordinator.async_register_processor(processor)
|
||||
cancel_coordinator = coordinator.async_start()
|
||||
|
||||
coordinator.async_register_processor(processor)
|
||||
cancel_coordinator = coordinator.async_start()
|
||||
|
||||
processor.async_add_entities_listener(
|
||||
PassiveBluetoothProcessorEntity,
|
||||
|
@ -1003,9 +965,9 @@ async def test_passive_bluetooth_entity_with_entity_platform(
|
|||
entity_platform.async_add_entities(entities)
|
||||
),
|
||||
)
|
||||
saved_callback(NO_DEVICES_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, NO_DEVICES_BLUETOOTH_SERVICE_INFO)
|
||||
await hass.async_block_till_done()
|
||||
saved_callback(NO_DEVICES_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, NO_DEVICES_BLUETOOTH_SERVICE_INFO)
|
||||
await hass.async_block_till_done()
|
||||
assert (
|
||||
hass.states.get("test_domain.test_platform_aa_bb_cc_dd_ee_ff_temperature")
|
||||
|
@ -1079,12 +1041,6 @@ async def test_integration_multiple_entity_platforms(hass, mock_bleak_scanner_st
|
|||
_mock_update_method,
|
||||
)
|
||||
assert coordinator.available is False # no data yet
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
binary_sensor_processor = PassiveBluetoothDataProcessor(
|
||||
lambda service_info: BINARY_SENSOR_PASSIVE_BLUETOOTH_DATA_UPDATE
|
||||
|
@ -1093,13 +1049,9 @@ async def test_integration_multiple_entity_platforms(hass, mock_bleak_scanner_st
|
|||
lambda service_info: SENSOR_PASSIVE_BLUETOOTH_DATA_UPDATE
|
||||
)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
coordinator.async_register_processor(binary_sensor_processor)
|
||||
coordinator.async_register_processor(sesnor_processor)
|
||||
cancel_coordinator = coordinator.async_start()
|
||||
coordinator.async_register_processor(binary_sensor_processor)
|
||||
coordinator.async_register_processor(sesnor_processor)
|
||||
cancel_coordinator = coordinator.async_start()
|
||||
|
||||
binary_sensor_processor.async_add_listener(MagicMock())
|
||||
sesnor_processor.async_add_listener(MagicMock())
|
||||
|
@ -1116,7 +1068,7 @@ async def test_integration_multiple_entity_platforms(hass, mock_bleak_scanner_st
|
|||
mock_add_binary_sensor_entities,
|
||||
)
|
||||
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
# First call with just the remote sensor entities results in them being added
|
||||
assert len(mock_add_binary_sensor_entities.mock_calls) == 1
|
||||
assert len(mock_add_sensor_entities.mock_calls) == 1
|
||||
|
@ -1193,33 +1145,24 @@ async def test_exception_from_coordinator_update_method(
|
|||
_mock_update_method,
|
||||
)
|
||||
assert coordinator.available is False # no data yet
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
processor = PassiveBluetoothDataProcessor(_async_generate_mock_data)
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
unregister_processor = coordinator.async_register_processor(processor)
|
||||
cancel_coordinator = coordinator.async_start()
|
||||
|
||||
unregister_processor = coordinator.async_register_processor(processor)
|
||||
cancel_coordinator = coordinator.async_start()
|
||||
|
||||
processor.async_add_listener(MagicMock())
|
||||
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
assert processor.available is True
|
||||
|
||||
# We should go unavailable once we get an exception
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
assert "Test exception" in caplog.text
|
||||
assert processor.available is False
|
||||
|
||||
# We should go available again once we get data again
|
||||
saved_callback(GENERIC_BLUETOOTH_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
assert processor.available is True
|
||||
unregister_processor()
|
||||
cancel_coordinator()
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
"""Test BTHome binary sensors."""
|
||||
|
||||
import logging
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.bluetooth import BluetoothChange
|
||||
from homeassistant.components.bthome.const import DOMAIN
|
||||
from homeassistant.const import ATTR_FRIENDLY_NAME, STATE_OFF, STATE_ON
|
||||
|
||||
from . import make_advertisement
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.bluetooth import inject_bluetooth_service_info
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -81,25 +80,14 @@ async def test_binary_sensors(
|
|||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all()) == 0
|
||||
|
||||
saved_callback(
|
||||
inject_bluetooth_service_info(
|
||||
hass,
|
||||
advertisement,
|
||||
BluetoothChange.ADVERTISEMENT,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
"""Test the BTHome sensors."""
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.bluetooth import BluetoothChange
|
||||
from homeassistant.components.bthome.const import DOMAIN
|
||||
from homeassistant.components.sensor import ATTR_STATE_CLASS
|
||||
from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
|
||||
|
@ -12,6 +10,7 @@ from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
|
|||
from . import make_advertisement, make_encrypted_advertisement
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.bluetooth import inject_bluetooth_service_info
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
@ -340,25 +339,14 @@ async def test_sensors(
|
|||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all()) == 0
|
||||
|
||||
saved_callback(
|
||||
inject_bluetooth_service_info(
|
||||
hass,
|
||||
advertisement,
|
||||
BluetoothChange.ADVERTISEMENT,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_all()) == len(result)
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
"""Test the Govee BLE sensors."""
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.components.bluetooth import BluetoothChange
|
||||
from homeassistant.components.govee_ble.const import DOMAIN
|
||||
from homeassistant.components.sensor import ATTR_STATE_CLASS
|
||||
from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
|
||||
|
@ -10,6 +8,7 @@ from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
|
|||
from . import GVH5075_SERVICE_INFO
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.bluetooth import inject_bluetooth_service_info
|
||||
|
||||
|
||||
async def test_sensors(hass):
|
||||
|
@ -20,22 +19,11 @@ async def test_sensors(hass):
|
|||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all()) == 0
|
||||
saved_callback(GVH5075_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, GVH5075_SERVICE_INFO)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_all()) == 3
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
"""Test the INKBIRD config flow."""
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.components.bluetooth import BluetoothChange
|
||||
from homeassistant.components.inkbird.const import DOMAIN
|
||||
from homeassistant.components.sensor import ATTR_STATE_CLASS
|
||||
from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
|
||||
|
@ -10,6 +8,7 @@ from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
|
|||
from . import SPS_SERVICE_INFO
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.bluetooth import inject_bluetooth_service_info
|
||||
|
||||
|
||||
async def test_sensors(hass):
|
||||
|
@ -20,22 +19,11 @@ async def test_sensors(hass):
|
|||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all()) == 0
|
||||
saved_callback(SPS_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, SPS_SERVICE_INFO)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_all()) == 3
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
"""Test the Moat sensors."""
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.components.bluetooth import BluetoothChange
|
||||
from homeassistant.components.moat.const import DOMAIN
|
||||
from homeassistant.components.sensor import ATTR_STATE_CLASS
|
||||
from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
|
||||
|
@ -10,32 +8,22 @@ from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
|
|||
from . import MOAT_S2_SERVICE_INFO
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.bluetooth import inject_bluetooth_service_info
|
||||
|
||||
|
||||
async def test_sensors(hass):
|
||||
"""Test setting up creates the sensors."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id="61DE521B-F0BF-9F44-64D4-75BBE1738105",
|
||||
unique_id="aa:bb:cc:dd:ee:ff",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all()) == 0
|
||||
saved_callback(MOAT_S2_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, MOAT_S2_SERVICE_INFO)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_all()) == 4
|
||||
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
"""Test the Qingping binary sensors."""
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.components.bluetooth import BluetoothChange
|
||||
from homeassistant.components.qingping.const import DOMAIN
|
||||
from homeassistant.const import ATTR_FRIENDLY_NAME
|
||||
|
||||
from . import LIGHT_AND_SIGNAL_SERVICE_INFO
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.bluetooth import inject_bluetooth_service_info
|
||||
|
||||
|
||||
async def test_binary_sensors(hass):
|
||||
|
@ -19,22 +18,11 @@ async def test_binary_sensors(hass):
|
|||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all("binary_sensor")) == 0
|
||||
saved_callback(LIGHT_AND_SIGNAL_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, LIGHT_AND_SIGNAL_SERVICE_INFO)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_all("binary_sensor")) == 1
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
"""Test the Qingping sensors."""
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.components.bluetooth import BluetoothChange
|
||||
from homeassistant.components.qingping.const import DOMAIN
|
||||
from homeassistant.components.sensor import ATTR_STATE_CLASS
|
||||
from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
|
||||
|
@ -10,6 +8,7 @@ from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
|
|||
from . import LIGHT_AND_SIGNAL_SERVICE_INFO
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.bluetooth import inject_bluetooth_service_info
|
||||
|
||||
|
||||
async def test_sensors(hass):
|
||||
|
@ -20,22 +19,11 @@ async def test_sensors(hass):
|
|||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all("sensor")) == 0
|
||||
saved_callback(LIGHT_AND_SIGNAL_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, LIGHT_AND_SIGNAL_SERVICE_INFO)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_all("sensor")) == 1
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
"""Test the SensorPro sensors."""
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.components.bluetooth import BluetoothChange
|
||||
from homeassistant.components.sensor import ATTR_STATE_CLASS
|
||||
from homeassistant.components.sensorpro.const import DOMAIN
|
||||
from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
|
||||
|
@ -10,6 +8,7 @@ from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
|
|||
from . import SENSORPRO_SERVICE_INFO
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.bluetooth import inject_bluetooth_service_info
|
||||
|
||||
|
||||
async def test_sensors(hass):
|
||||
|
@ -20,22 +19,11 @@ async def test_sensors(hass):
|
|||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all("sensor")) == 0
|
||||
saved_callback(SENSORPRO_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, SENSORPRO_SERVICE_INFO)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_all("sensor")) == 4
|
||||
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
"""Test the SensorPush config flow."""
|
||||
"""Test the SensorPush sensors."""
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.components.bluetooth import BluetoothChange
|
||||
from homeassistant.components.sensor import ATTR_STATE_CLASS
|
||||
from homeassistant.components.sensorpush.const import DOMAIN
|
||||
from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
|
||||
|
@ -10,32 +7,22 @@ from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
|
|||
from . import HTPWX_SERVICE_INFO
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.bluetooth import inject_bluetooth_service_info
|
||||
|
||||
|
||||
async def test_sensors(hass):
|
||||
"""Test setting up creates the sensors."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id="61DE521B-F0BF-9F44-64D4-75BBE1738105",
|
||||
unique_id="4125DDBA-2774-4851-9889-6AADDD4CAC3D",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all()) == 0
|
||||
saved_callback(HTPWX_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, HTPWX_SERVICE_INFO)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_all()) == 3
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
"""Test the ThermoBeacon sensors."""
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.components.bluetooth import BluetoothChange
|
||||
from homeassistant.components.sensor import ATTR_STATE_CLASS
|
||||
from homeassistant.components.thermobeacon.const import DOMAIN
|
||||
from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
|
||||
|
@ -10,6 +8,7 @@ from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
|
|||
from . import THERMOBEACON_SERVICE_INFO
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.bluetooth import inject_bluetooth_service_info
|
||||
|
||||
|
||||
async def test_sensors(hass):
|
||||
|
@ -20,22 +19,11 @@ async def test_sensors(hass):
|
|||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all("sensor")) == 0
|
||||
saved_callback(THERMOBEACON_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, THERMOBEACON_SERVICE_INFO)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_all("sensor")) == 4
|
||||
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
"""Test the ThermoPro config flow."""
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.components.bluetooth import BluetoothChange
|
||||
from homeassistant.components.sensor import ATTR_STATE_CLASS
|
||||
from homeassistant.components.thermopro.const import DOMAIN
|
||||
from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
|
||||
|
@ -10,32 +7,22 @@ from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
|
|||
from . import TP357_SERVICE_INFO
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.bluetooth import inject_bluetooth_service_info
|
||||
|
||||
|
||||
async def test_sensors(hass):
|
||||
"""Test setting up creates the sensors."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id="61DE521B-F0BF-9F44-64D4-75BBE1738105",
|
||||
unique_id="4125DDBA-2774-4851-9889-6AADDD4CAC3D",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all()) == 0
|
||||
saved_callback(TP357_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, TP357_SERVICE_INFO)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_all()) == 2
|
||||
|
||||
|
|
|
@ -2,9 +2,6 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.components.bluetooth import BluetoothCallback, BluetoothChange
|
||||
from homeassistant.components.sensor import ATTR_STATE_CLASS
|
||||
from homeassistant.components.tilt_ble.const import DOMAIN
|
||||
from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
|
||||
|
@ -13,33 +10,22 @@ from homeassistant.core import HomeAssistant
|
|||
from . import TILT_GREEN_SERVICE_INFO
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.bluetooth import inject_bluetooth_service_info
|
||||
|
||||
|
||||
async def test_sensors(hass: HomeAssistant):
|
||||
"""Test setting up creates the sensors."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id="61DE521B-F0BF-9F44-64D4-75BBE1738105",
|
||||
unique_id="F6:0F:28:F2:1F:CB",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
saved_callback: BluetoothCallback | None = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all()) == 0
|
||||
assert saved_callback is not None
|
||||
saved_callback(TILT_GREEN_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info(hass, TILT_GREEN_SERVICE_INFO)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_all()) == 2
|
||||
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
"""Test Xiaomi binary sensors."""
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.components.bluetooth import BluetoothChange
|
||||
from homeassistant.components.xiaomi_ble.const import DOMAIN
|
||||
from homeassistant.const import ATTR_FRIENDLY_NAME
|
||||
|
||||
from . import make_advertisement
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.bluetooth import inject_bluetooth_service_info_bleak
|
||||
|
||||
|
||||
async def test_smoke_sensor(hass):
|
||||
|
@ -20,27 +18,16 @@ async def test_smoke_sensor(hass):
|
|||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all()) == 0
|
||||
saved_callback(
|
||||
inject_bluetooth_service_info_bleak(
|
||||
hass,
|
||||
make_advertisement(
|
||||
"54:EF:44:E3:9C:BC",
|
||||
b"XY\x97\tf\xbc\x9c\xe3D\xefT\x01" b"\x08\x12\x05\x00\x00\x00q^\xbe\x90",
|
||||
),
|
||||
BluetoothChange.ADVERTISEMENT,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_all()) == 1
|
||||
|
@ -62,29 +49,18 @@ async def test_moisture(hass):
|
|||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all()) == 0
|
||||
|
||||
# WARNING: This test data is synthetic, rather than captured from a real device
|
||||
# obj type is 0x1014, payload len is 0x2 and payload is 0xf400
|
||||
saved_callback(
|
||||
inject_bluetooth_service_info_bleak(
|
||||
hass,
|
||||
make_advertisement(
|
||||
"C4:7C:8D:6A:3E:7A", b"q \x5d\x01iz>j\x8d|\xc4\r\x14\x10\x02\xf4\x00"
|
||||
),
|
||||
BluetoothChange.ADVERTISEMENT,
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
"""Test the Xiaomi config flow."""
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.components.bluetooth import (
|
||||
BluetoothChange,
|
||||
async_get_advertisement_callback,
|
||||
)
|
||||
from homeassistant.components.sensor import ATTR_STATE_CLASS
|
||||
from homeassistant.components.xiaomi_ble.const import DOMAIN
|
||||
from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
|
||||
|
@ -13,6 +8,7 @@ from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
|
|||
from . import MMC_T201_1_SERVICE_INFO, make_advertisement
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.bluetooth import inject_bluetooth_service_info_bleak
|
||||
|
||||
|
||||
async def test_sensors(hass):
|
||||
|
@ -23,22 +19,11 @@ async def test_sensors(hass):
|
|||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all()) == 0
|
||||
saved_callback(MMC_T201_1_SERVICE_INFO, BluetoothChange.ADVERTISEMENT)
|
||||
inject_bluetooth_service_info_bleak(hass, MMC_T201_1_SERVICE_INFO)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_all()) == 2
|
||||
|
||||
|
@ -63,29 +48,18 @@ async def test_xiaomi_formaldeyhde(hass):
|
|||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all()) == 0
|
||||
|
||||
# WARNING: This test data is synthetic, rather than captured from a real device
|
||||
# obj type is 0x1010, payload len is 0x2 and payload is 0xf400
|
||||
saved_callback(
|
||||
inject_bluetooth_service_info_bleak(
|
||||
hass,
|
||||
make_advertisement(
|
||||
"C4:7C:8D:6A:3E:7A", b"q \x5d\x01iz>j\x8d|\xc4\r\x10\x10\x02\xf4\x00"
|
||||
),
|
||||
BluetoothChange.ADVERTISEMENT,
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
@ -110,29 +84,18 @@ async def test_xiaomi_consumable(hass):
|
|||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all()) == 0
|
||||
|
||||
# WARNING: This test data is synthetic, rather than captured from a real device
|
||||
# obj type is 0x1310, payload len is 0x2 and payload is 0x6000
|
||||
saved_callback(
|
||||
inject_bluetooth_service_info_bleak(
|
||||
hass,
|
||||
make_advertisement(
|
||||
"C4:7C:8D:6A:3E:7A", b"q \x5d\x01iz>j\x8d|\xc4\r\x13\x10\x02\x60\x00"
|
||||
),
|
||||
BluetoothChange.ADVERTISEMENT,
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
@ -157,29 +120,16 @@ async def test_xiaomi_battery_voltage(hass):
|
|||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all()) == 0
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# WARNING: This test data is synthetic, rather than captured from a real device
|
||||
# obj type is 0x0a10, payload len is 0x2 and payload is 0x6400
|
||||
saved_callback(
|
||||
inject_bluetooth_service_info_bleak(
|
||||
hass,
|
||||
make_advertisement(
|
||||
"C4:7C:8D:6A:3E:7A", b"q \x5d\x01iz>j\x8d|\xc4\r\x0a\x10\x02\x64\x00"
|
||||
),
|
||||
BluetoothChange.ADVERTISEMENT,
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
@ -211,44 +161,33 @@ async def test_xiaomi_HHCCJCY01(hass):
|
|||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all()) == 0
|
||||
saved_callback(
|
||||
inject_bluetooth_service_info_bleak(
|
||||
hass,
|
||||
make_advertisement(
|
||||
"C4:7C:8D:6A:3E:7A", b"q \x98\x00fz>j\x8d|\xc4\r\x07\x10\x03\x00\x00\x00"
|
||||
),
|
||||
BluetoothChange.ADVERTISEMENT,
|
||||
)
|
||||
saved_callback(
|
||||
inject_bluetooth_service_info_bleak(
|
||||
hass,
|
||||
make_advertisement(
|
||||
"C4:7C:8D:6A:3E:7A", b"q \x98\x00hz>j\x8d|\xc4\r\t\x10\x02W\x02"
|
||||
),
|
||||
BluetoothChange.ADVERTISEMENT,
|
||||
)
|
||||
saved_callback(
|
||||
inject_bluetooth_service_info_bleak(
|
||||
hass,
|
||||
make_advertisement(
|
||||
"C4:7C:8D:6A:3E:7A", b"q \x98\x00Gz>j\x8d|\xc4\r\x08\x10\x01@"
|
||||
),
|
||||
BluetoothChange.ADVERTISEMENT,
|
||||
)
|
||||
saved_callback(
|
||||
inject_bluetooth_service_info_bleak(
|
||||
hass,
|
||||
make_advertisement(
|
||||
"C4:7C:8D:6A:3E:7A", b"q \x98\x00iz>j\x8d|\xc4\r\x04\x10\x02\xf4\x00"
|
||||
),
|
||||
BluetoothChange.ADVERTISEMENT,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_all()) == 5
|
||||
|
@ -296,56 +235,45 @@ async def test_xiaomi_HHCCJCY01_not_connectable(hass):
|
|||
"""This device has multiple advertisements before all sensors are visible but not connectable."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id="C4:7C:8D:6A:3E:7B",
|
||||
unique_id="C4:7C:8D:6A:3E:7A",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all()) == 0
|
||||
saved_callback(
|
||||
inject_bluetooth_service_info_bleak(
|
||||
hass,
|
||||
make_advertisement(
|
||||
"C4:7C:8D:6A:3E:7A",
|
||||
b"q \x98\x00fz>j\x8d|\xc4\r\x07\x10\x03\x00\x00\x00",
|
||||
connectable=False,
|
||||
),
|
||||
BluetoothChange.ADVERTISEMENT,
|
||||
)
|
||||
saved_callback(
|
||||
inject_bluetooth_service_info_bleak(
|
||||
hass,
|
||||
make_advertisement(
|
||||
"C4:7C:8D:6A:3E:7A",
|
||||
b"q \x98\x00hz>j\x8d|\xc4\r\t\x10\x02W\x02",
|
||||
connectable=False,
|
||||
),
|
||||
BluetoothChange.ADVERTISEMENT,
|
||||
)
|
||||
saved_callback(
|
||||
inject_bluetooth_service_info_bleak(
|
||||
hass,
|
||||
make_advertisement(
|
||||
"C4:7C:8D:6A:3E:7A",
|
||||
b"q \x98\x00Gz>j\x8d|\xc4\r\x08\x10\x01@",
|
||||
connectable=False,
|
||||
),
|
||||
BluetoothChange.ADVERTISEMENT,
|
||||
)
|
||||
saved_callback(
|
||||
inject_bluetooth_service_info_bleak(
|
||||
hass,
|
||||
make_advertisement(
|
||||
"C4:7C:8D:6A:3E:7A",
|
||||
b"q \x98\x00iz>j\x8d|\xc4\r\x04\x10\x02\xf4\x00",
|
||||
connectable=False,
|
||||
),
|
||||
BluetoothChange.ADVERTISEMENT,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_all()) == 4
|
||||
|
@ -392,34 +320,36 @@ async def test_xiaomi_HHCCJCY01_only_some_sources_connectable(hass):
|
|||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
saved_callback = async_get_advertisement_callback(hass)
|
||||
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all()) == 0
|
||||
saved_callback(
|
||||
inject_bluetooth_service_info_bleak(
|
||||
hass,
|
||||
make_advertisement(
|
||||
"C4:7C:8D:6A:3E:7A",
|
||||
b"q \x98\x00fz>j\x8d|\xc4\r\x07\x10\x03\x00\x00\x00",
|
||||
connectable=True,
|
||||
),
|
||||
)
|
||||
saved_callback(
|
||||
inject_bluetooth_service_info_bleak(
|
||||
hass,
|
||||
make_advertisement(
|
||||
"C4:7C:8D:6A:3E:7A",
|
||||
b"q \x98\x00hz>j\x8d|\xc4\r\t\x10\x02W\x02",
|
||||
connectable=False,
|
||||
),
|
||||
)
|
||||
saved_callback(
|
||||
inject_bluetooth_service_info_bleak(
|
||||
hass,
|
||||
make_advertisement(
|
||||
"C4:7C:8D:6A:3E:7A",
|
||||
b"q \x98\x00Gz>j\x8d|\xc4\r\x08\x10\x01@",
|
||||
connectable=False,
|
||||
),
|
||||
)
|
||||
saved_callback(
|
||||
inject_bluetooth_service_info_bleak(
|
||||
hass,
|
||||
make_advertisement(
|
||||
"C4:7C:8D:6A:3E:7A",
|
||||
b"q \x98\x00iz>j\x8d|\xc4\r\x04\x10\x02\xf4\x00",
|
||||
|
@ -477,27 +407,16 @@ async def test_xiaomi_CGDK2(hass):
|
|||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
saved_callback = None
|
||||
|
||||
def _async_register_callback(_hass, _callback, _matcher, _mode):
|
||||
nonlocal saved_callback
|
||||
saved_callback = _callback
|
||||
return lambda: None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.update_coordinator.async_register_callback",
|
||||
_async_register_callback,
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all()) == 0
|
||||
saved_callback(
|
||||
inject_bluetooth_service_info_bleak(
|
||||
hass,
|
||||
make_advertisement(
|
||||
"58:2D:34:12:20:89",
|
||||
b"XXo\x06\x07\x89 \x124-X_\x17m\xd5O\x02\x00\x00/\xa4S\xfa",
|
||||
),
|
||||
BluetoothChange.ADVERTISEMENT,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_all()) == 1
|
||||
|
|
Loading…
Add table
Reference in a new issue