Update to bleak 0.15 (#75941)

This commit is contained in:
J. Nick Koston 2022-07-29 14:53:33 -10:00 committed by GitHub
parent c4ad6d46ae
commit 80a9659524
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 223 additions and 152 deletions

View file

@ -8,7 +8,7 @@ from dataclasses import dataclass
from datetime import datetime, timedelta
from enum import Enum
import logging
from typing import Final, Union
from typing import Final
import async_timeout
from bleak import BleakError
@ -96,12 +96,8 @@ SCANNING_MODE_TO_BLEAK = {
BluetoothChange = Enum("BluetoothChange", "ADVERTISEMENT")
BluetoothCallback = Callable[
[Union[BluetoothServiceInfoBleak, BluetoothServiceInfo], BluetoothChange], None
]
ProcessAdvertisementCallback = Callable[
[Union[BluetoothServiceInfoBleak, BluetoothServiceInfo]], bool
]
BluetoothCallback = Callable[[BluetoothServiceInfoBleak, BluetoothChange], None]
ProcessAdvertisementCallback = Callable[[BluetoothServiceInfoBleak], bool]
@hass_callback
@ -157,9 +153,15 @@ def async_register_callback(
hass: HomeAssistant,
callback: BluetoothCallback,
match_dict: BluetoothCallbackMatcher | None,
mode: BluetoothScanningMode,
) -> Callable[[], None]:
"""Register to receive a callback on bluetooth change.
mode is currently not used as we only support active scanning.
Passive scanning will be available in the future. The flag
is required to be present to avoid a future breaking change
when we support passive scanning.
Returns a callback that can be used to cancel the registration.
"""
manager: BluetoothManager = hass.data[DOMAIN]
@ -170,19 +172,20 @@ async def async_process_advertisements(
hass: HomeAssistant,
callback: ProcessAdvertisementCallback,
match_dict: BluetoothCallbackMatcher,
mode: BluetoothScanningMode,
timeout: int,
) -> BluetoothServiceInfo:
) -> BluetoothServiceInfoBleak:
"""Process advertisements until callback returns true or timeout expires."""
done: Future[BluetoothServiceInfo] = Future()
done: Future[BluetoothServiceInfoBleak] = Future()
@hass_callback
def _async_discovered_device(
service_info: BluetoothServiceInfo, change: BluetoothChange
service_info: BluetoothServiceInfoBleak, change: BluetoothChange
) -> None:
if callback(service_info):
done.set_result(service_info)
unload = async_register_callback(hass, _async_discovered_device, match_dict)
unload = async_register_callback(hass, _async_discovered_device, match_dict, mode)
try:
async with async_timeout.timeout(timeout):
@ -333,7 +336,7 @@ class BluetoothManager:
)
try:
async with async_timeout.timeout(START_TIMEOUT):
await self.scanner.start()
await self.scanner.start() # type: ignore[no-untyped-call]
except asyncio.TimeoutError as ex:
self._cancel_device_detected()
raise ConfigEntryNotReady(
@ -500,7 +503,7 @@ class BluetoothManager:
self._cancel_unavailable_tracking = None
if self.scanner:
try:
await self.scanner.stop()
await self.scanner.stop() # type: ignore[no-untyped-call]
except BleakError as ex:
# This is not fatal, and they may want to reload
# the config entry to restart the scanner if they

View file

@ -4,7 +4,7 @@
"documentation": "https://www.home-assistant.io/integrations/bluetooth",
"dependencies": ["websocket_api"],
"quality_scale": "internal",
"requirements": ["bleak==0.14.3", "bluetooth-adapters==0.1.2"],
"requirements": ["bleak==0.15.0", "bluetooth-adapters==0.1.2"],
"codeowners": ["@bdraco"],
"config_flow": true,
"iot_class": "local_push"

View file

@ -4,7 +4,7 @@ from __future__ import annotations
import asyncio
import contextlib
import logging
from typing import Any, Final, cast
from typing import Any, Final
from bleak import BleakScanner
from bleak.backends.device import BLEDevice
@ -32,7 +32,7 @@ def _dispatch_callback(
"""Dispatch the callback."""
if not callback:
# Callback destroyed right before being called, ignore
return
return # type: ignore[unreachable]
if (uuids := filters.get(FILTER_UUIDS)) and not uuids.intersection(
advertisement_data.service_uuids
@ -45,7 +45,7 @@ def _dispatch_callback(
_LOGGER.exception("Error in callback: %s", callback)
class HaBleakScanner(BleakScanner): # type: ignore[misc]
class HaBleakScanner(BleakScanner):
"""BleakScanner that cannot be stopped."""
def __init__( # pylint: disable=super-init-not-called
@ -106,16 +106,29 @@ class HaBleakScanner(BleakScanner): # type: ignore[misc]
_dispatch_callback(*callback_filters, device, advertisement_data)
class HaBleakScannerWrapper(BaseBleakScanner): # type: ignore[misc]
class HaBleakScannerWrapper(BaseBleakScanner):
"""A wrapper that uses the single instance."""
def __init__(self, *args: Any, **kwargs: Any) -> None:
def __init__(
self,
*args: Any,
detection_callback: AdvertisementDataCallback | None = None,
service_uuids: list[str] | None = None,
**kwargs: Any,
) -> None:
"""Initialize the BleakScanner."""
self._detection_cancel: CALLBACK_TYPE | None = None
self._mapped_filters: dict[str, set[str]] = {}
self._adv_data_callback: AdvertisementDataCallback | None = None
self._map_filters(*args, **kwargs)
super().__init__(*args, **kwargs)
remapped_kwargs = {
"detection_callback": detection_callback,
"service_uuids": service_uuids or [],
**kwargs,
}
self._map_filters(*args, **remapped_kwargs)
super().__init__(
detection_callback=detection_callback, service_uuids=service_uuids or []
)
async def stop(self, *args: Any, **kwargs: Any) -> None:
"""Stop scanning for devices."""
@ -153,9 +166,11 @@ class HaBleakScannerWrapper(BaseBleakScanner): # type: ignore[misc]
def discovered_devices(self) -> list[BLEDevice]:
"""Return a list of discovered devices."""
assert HA_BLEAK_SCANNER is not None
return cast(list[BLEDevice], HA_BLEAK_SCANNER.discovered_devices)
return HA_BLEAK_SCANNER.discovered_devices
def register_detection_callback(self, callback: AdvertisementDataCallback) -> None:
def register_detection_callback(
self, callback: AdvertisementDataCallback | None
) -> None:
"""Register a callback that is called when a device is discovered or has a property changed.
This method takes the callback and registers it with the long running
@ -171,6 +186,7 @@ class HaBleakScannerWrapper(BaseBleakScanner): # type: ignore[misc]
self._cancel_callback()
super().register_detection_callback(self._adv_data_callback)
assert HA_BLEAK_SCANNER is not None
assert self._callback is not None
self._detection_cancel = HA_BLEAK_SCANNER.async_register_callback(
self._callback, self._mapped_filters
)

View file

@ -6,10 +6,9 @@ import logging
from typing import Any
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
from homeassistant.helpers.service_info.bluetooth import BluetoothServiceInfo
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from . import BluetoothChange
from . import BluetoothChange, BluetoothScanningMode, BluetoothServiceInfoBleak
from .update_coordinator import BasePassiveBluetoothCoordinator
@ -25,9 +24,10 @@ class PassiveBluetoothDataUpdateCoordinator(BasePassiveBluetoothCoordinator):
hass: HomeAssistant,
logger: logging.Logger,
address: str,
mode: BluetoothScanningMode,
) -> None:
"""Initialize PassiveBluetoothDataUpdateCoordinator."""
super().__init__(hass, logger, address)
super().__init__(hass, logger, address, mode)
self._listeners: dict[CALLBACK_TYPE, tuple[CALLBACK_TYPE, object | None]] = {}
@callback
@ -65,7 +65,7 @@ class PassiveBluetoothDataUpdateCoordinator(BasePassiveBluetoothCoordinator):
@callback
def _async_handle_bluetooth_event(
self,
service_info: BluetoothServiceInfo,
service_info: BluetoothServiceInfoBleak,
change: BluetoothChange,
) -> None:
"""Handle a Bluetooth event."""

View file

@ -6,14 +6,12 @@ import dataclasses
import logging
from typing import Any, Generic, TypeVar
from home_assistant_bluetooth import BluetoothServiceInfo
from homeassistant.const import ATTR_IDENTIFIERS, ATTR_NAME
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity import DeviceInfo, Entity, EntityDescription
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import BluetoothChange
from . import BluetoothChange, BluetoothScanningMode, BluetoothServiceInfoBleak
from .const import DOMAIN
from .update_coordinator import BasePassiveBluetoothCoordinator
@ -62,9 +60,10 @@ class PassiveBluetoothProcessorCoordinator(BasePassiveBluetoothCoordinator):
hass: HomeAssistant,
logger: logging.Logger,
address: str,
mode: BluetoothScanningMode,
) -> None:
"""Initialize the coordinator."""
super().__init__(hass, logger, address)
super().__init__(hass, logger, address, mode)
self._processors: list[PassiveBluetoothDataProcessor] = []
@callback
@ -92,7 +91,7 @@ class PassiveBluetoothProcessorCoordinator(BasePassiveBluetoothCoordinator):
@callback
def _async_handle_bluetooth_event(
self,
service_info: BluetoothServiceInfo,
service_info: BluetoothServiceInfoBleak,
change: BluetoothChange,
) -> None:
"""Handle a Bluetooth event."""
@ -122,7 +121,7 @@ class PassiveBluetoothDataProcessor(Generic[_T]):
The processor will call the update_method every time the bluetooth device
receives a new advertisement data from the coordinator with the following signature:
update_method(service_info: BluetoothServiceInfo) -> PassiveBluetoothDataUpdate
update_method(service_info: BluetoothServiceInfoBleak) -> PassiveBluetoothDataUpdate
As the size of each advertisement is limited, the update_method should
return a PassiveBluetoothDataUpdate object that contains only data that
@ -135,7 +134,9 @@ class PassiveBluetoothDataProcessor(Generic[_T]):
def __init__(
self,
update_method: Callable[[BluetoothServiceInfo], PassiveBluetoothDataUpdate[_T]],
update_method: Callable[
[BluetoothServiceInfoBleak], PassiveBluetoothDataUpdate[_T]
],
) -> None:
"""Initialize the coordinator."""
self.coordinator: PassiveBluetoothProcessorCoordinator
@ -241,7 +242,7 @@ class PassiveBluetoothDataProcessor(Generic[_T]):
@callback
def async_handle_bluetooth_event(
self,
service_info: BluetoothServiceInfo,
service_info: BluetoothServiceInfoBleak,
change: BluetoothChange,
) -> None:
"""Handle a Bluetooth event."""

View file

@ -4,13 +4,13 @@ from __future__ import annotations
import logging
import time
from home_assistant_bluetooth import BluetoothServiceInfo
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
from . import (
BluetoothCallbackMatcher,
BluetoothChange,
BluetoothScanningMode,
BluetoothServiceInfoBleak,
async_register_callback,
async_track_unavailable,
)
@ -27,6 +27,7 @@ class BasePassiveBluetoothCoordinator:
hass: HomeAssistant,
logger: logging.Logger,
address: str,
mode: BluetoothScanningMode,
) -> None:
"""Initialize the coordinator."""
self.hass = hass
@ -36,6 +37,7 @@ class BasePassiveBluetoothCoordinator:
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
@callback
@ -61,6 +63,7 @@ class BasePassiveBluetoothCoordinator:
self.hass,
self._async_handle_bluetooth_event,
BluetoothCallbackMatcher(address=self.address),
self.mode,
)
self._cancel_track_unavailable = async_track_unavailable(
self.hass,
@ -86,7 +89,7 @@ class BasePassiveBluetoothCoordinator:
@callback
def _async_handle_bluetooth_event(
self,
service_info: BluetoothServiceInfo,
service_info: BluetoothServiceInfoBleak,
change: BluetoothChange,
) -> None:
"""Handle a Bluetooth event."""

View file

@ -1,4 +1,5 @@
"""bluetooth usage utility to handle multiple instances."""
from __future__ import annotations
import bleak
@ -10,9 +11,9 @@ ORIGINAL_BLEAK_SCANNER = bleak.BleakScanner
def install_multiple_bleak_catcher() -> None:
"""Wrap the bleak classes to return the shared instance if multiple instances are detected."""
bleak.BleakScanner = HaBleakScannerWrapper
bleak.BleakScanner = HaBleakScannerWrapper # type: ignore[misc, assignment]
def uninstall_multiple_bleak_catcher() -> None:
"""Unwrap the bleak classes."""
bleak.BleakScanner = ORIGINAL_BLEAK_SCANNER
bleak.BleakScanner = ORIGINAL_BLEAK_SCANNER # type: ignore[misc]

View file

@ -4,7 +4,6 @@ from __future__ import annotations
import asyncio
from datetime import datetime, timedelta
import logging
from typing import TYPE_CHECKING
from uuid import UUID
from bleak import BleakClient, BleakError
@ -31,9 +30,6 @@ from homeassistant.helpers.event import async_track_time_interval
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
import homeassistant.util.dt as dt_util
if TYPE_CHECKING:
from bleak.backends.device import BLEDevice
_LOGGER = logging.getLogger(__name__)
# Base UUID: 00000000-0000-1000-8000-00805F9B34FB
@ -139,15 +135,12 @@ async def async_setup_scanner( # noqa: C901
async def _async_see_update_ble_battery(
mac: str,
now: datetime,
service_info: bluetooth.BluetoothServiceInfo,
service_info: bluetooth.BluetoothServiceInfoBleak,
) -> None:
"""Lookup Bluetooth LE devices and update status."""
battery = None
ble_device: BLEDevice | str = (
bluetooth.async_ble_device_from_address(hass, mac) or mac
)
try:
async with BleakClient(ble_device) as client:
async with BleakClient(service_info.device) as client:
bat_char = await client.read_gatt_char(BATTERY_CHARACTERISTIC_UUID)
battery = ord(bat_char)
except asyncio.TimeoutError:
@ -168,7 +161,8 @@ async def async_setup_scanner( # noqa: C901
@callback
def _async_update_ble(
service_info: bluetooth.BluetoothServiceInfo, change: bluetooth.BluetoothChange
service_info: bluetooth.BluetoothServiceInfoBleak,
change: bluetooth.BluetoothChange,
) -> None:
"""Update from a ble callback."""
mac = service_info.address
@ -202,7 +196,9 @@ async def async_setup_scanner( # noqa: C901
_async_update_ble(service_info, bluetooth.BluetoothChange.ADVERTISEMENT)
cancels = [
bluetooth.async_register_callback(hass, _async_update_ble, None),
bluetooth.async_register_callback(
hass, _async_update_ble, None, bluetooth.BluetoothScanningMode.ACTIVE
),
async_track_time_interval(hass, _async_refresh_ble, interval),
]

View file

@ -3,6 +3,7 @@ from __future__ import annotations
import logging
from homeassistant.components.bluetooth import BluetoothScanningMode
from homeassistant.components.bluetooth.passive_update_processor import (
PassiveBluetoothProcessorCoordinator,
)
@ -27,6 +28,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
hass,
_LOGGER,
address=address,
mode=BluetoothScanningMode.ACTIVE,
)
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
entry.async_on_unload(

View file

@ -7,7 +7,7 @@ from govee_ble import GoveeBluetoothDeviceData as DeviceData
import voluptuous as vol
from homeassistant.components.bluetooth import (
BluetoothServiceInfo,
BluetoothServiceInfoBleak,
async_discovered_service_info,
)
from homeassistant.config_entries import ConfigFlow
@ -24,12 +24,12 @@ class GoveeConfigFlow(ConfigFlow, domain=DOMAIN):
def __init__(self) -> None:
"""Initialize the config flow."""
self._discovery_info: BluetoothServiceInfo | None = None
self._discovery_info: BluetoothServiceInfoBleak | None = None
self._discovered_device: DeviceData | None = None
self._discovered_devices: dict[str, str] = {}
async def async_step_bluetooth(
self, discovery_info: BluetoothServiceInfo
self, discovery_info: BluetoothServiceInfoBleak
) -> FlowResult:
"""Handle the bluetooth discovery step."""
await self.async_set_unique_id(discovery_info.address)

View file

@ -20,13 +20,16 @@ from homeassistant.components import zeroconf
from homeassistant.core import callback
from homeassistant.data_entry_flow import AbortFlow, FlowResult
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.service_info import bluetooth
from .connection import HKDevice
from .const import DOMAIN, KNOWN_DEVICES
from .storage import async_get_entity_storage
from .utils import async_get_controller
if TYPE_CHECKING:
from homeassistant.components import bluetooth
HOMEKIT_DIR = ".homekit"
HOMEKIT_BRIDGE_DOMAIN = "homekit"
@ -359,7 +362,7 @@ class HomekitControllerFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
return self._async_step_pair_show_form()
async def async_step_bluetooth(
self, discovery_info: bluetooth.BluetoothServiceInfo
self, discovery_info: bluetooth.BluetoothServiceInfoBleak
) -> FlowResult:
"""Handle the bluetooth discovery step."""
if not aiohomekit_const.BLE_TRANSPORT_SUPPORTED:

View file

@ -32,7 +32,7 @@ async def async_get_controller(hass: HomeAssistant) -> Controller:
controller = Controller(
async_zeroconf_instance=async_zeroconf_instance,
bleak_scanner_instance=bleak_scanner_instance,
bleak_scanner_instance=bleak_scanner_instance, # type: ignore[arg-type]
)
hass.data[CONTROLLER] = controller

View file

@ -3,6 +3,7 @@ from __future__ import annotations
import logging
from homeassistant.components.bluetooth import BluetoothScanningMode
from homeassistant.components.bluetooth.passive_update_processor import (
PassiveBluetoothProcessorCoordinator,
)
@ -24,9 +25,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
coordinator = hass.data.setdefault(DOMAIN, {})[
entry.entry_id
] = PassiveBluetoothProcessorCoordinator(
hass,
_LOGGER,
address=address,
hass, _LOGGER, address=address, mode=BluetoothScanningMode.ACTIVE
)
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
entry.async_on_unload(

View file

@ -7,7 +7,7 @@ from inkbird_ble import INKBIRDBluetoothDeviceData as DeviceData
import voluptuous as vol
from homeassistant.components.bluetooth import (
BluetoothServiceInfo,
BluetoothServiceInfoBleak,
async_discovered_service_info,
)
from homeassistant.config_entries import ConfigFlow
@ -24,12 +24,12 @@ class INKBIRDConfigFlow(ConfigFlow, domain=DOMAIN):
def __init__(self) -> None:
"""Initialize the config flow."""
self._discovery_info: BluetoothServiceInfo | None = None
self._discovery_info: BluetoothServiceInfoBleak | None = None
self._discovered_device: DeviceData | None = None
self._discovered_devices: dict[str, str] = {}
async def async_step_bluetooth(
self, discovery_info: BluetoothServiceInfo
self, discovery_info: BluetoothServiceInfoBleak
) -> FlowResult:
"""Handle the bluetooth discovery step."""
await self.async_set_unique_id(discovery_info.address)

View file

@ -3,6 +3,7 @@ from __future__ import annotations
import logging
from homeassistant.components.bluetooth import BluetoothScanningMode
from homeassistant.components.bluetooth.passive_update_processor import (
PassiveBluetoothProcessorCoordinator,
)
@ -24,9 +25,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
coordinator = hass.data.setdefault(DOMAIN, {})[
entry.entry_id
] = PassiveBluetoothProcessorCoordinator(
hass,
_LOGGER,
address=address,
hass, _LOGGER, address=address, mode=BluetoothScanningMode.PASSIVE
)
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
entry.async_on_unload(

View file

@ -7,7 +7,7 @@ from moat_ble import MoatBluetoothDeviceData as DeviceData
import voluptuous as vol
from homeassistant.components.bluetooth import (
BluetoothServiceInfo,
BluetoothServiceInfoBleak,
async_discovered_service_info,
)
from homeassistant.config_entries import ConfigFlow
@ -24,12 +24,12 @@ class MoatConfigFlow(ConfigFlow, domain=DOMAIN):
def __init__(self) -> None:
"""Initialize the config flow."""
self._discovery_info: BluetoothServiceInfo | None = None
self._discovery_info: BluetoothServiceInfoBleak | None = None
self._discovered_device: DeviceData | None = None
self._discovered_devices: dict[str, str] = {}
async def async_step_bluetooth(
self, discovery_info: BluetoothServiceInfo
self, discovery_info: BluetoothServiceInfoBleak
) -> FlowResult:
"""Handle the bluetooth discovery step."""
await self.async_set_unique_id(discovery_info.address)

View file

@ -3,6 +3,7 @@ from __future__ import annotations
import logging
from homeassistant.components.bluetooth import BluetoothScanningMode
from homeassistant.components.bluetooth.passive_update_processor import (
PassiveBluetoothProcessorCoordinator,
)
@ -24,9 +25,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
coordinator = hass.data.setdefault(DOMAIN, {})[
entry.entry_id
] = PassiveBluetoothProcessorCoordinator(
hass,
_LOGGER,
address=address,
hass, _LOGGER, address=address, mode=BluetoothScanningMode.PASSIVE
)
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
entry.async_on_unload(

View file

@ -7,7 +7,7 @@ from sensorpush_ble import SensorPushBluetoothDeviceData as DeviceData
import voluptuous as vol
from homeassistant.components.bluetooth import (
BluetoothServiceInfo,
BluetoothServiceInfoBleak,
async_discovered_service_info,
)
from homeassistant.config_entries import ConfigFlow
@ -24,12 +24,12 @@ class SensorPushConfigFlow(ConfigFlow, domain=DOMAIN):
def __init__(self) -> None:
"""Initialize the config flow."""
self._discovery_info: BluetoothServiceInfo | None = None
self._discovery_info: BluetoothServiceInfoBleak | None = None
self._discovered_device: DeviceData | None = None
self._discovered_devices: dict[str, str] = {}
async def async_step_bluetooth(
self, discovery_info: BluetoothServiceInfo
self, discovery_info: BluetoothServiceInfoBleak
) -> FlowResult:
"""Handle the bluetooth discovery step."""
await self.async_set_unique_id(discovery_info.address)

View file

@ -2,7 +2,7 @@
from __future__ import annotations
import logging
from typing import Any, cast
from typing import Any
from switchbot import SwitchBotAdvertisement, parse_advertisement_data
import voluptuous as vol
@ -15,7 +15,6 @@ from homeassistant.config_entries import ConfigEntry, ConfigFlow, OptionsFlow
from homeassistant.const import CONF_ADDRESS, CONF_NAME, CONF_PASSWORD, CONF_SENSOR_TYPE
from homeassistant.core import callback
from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers.service_info.bluetooth import BluetoothServiceInfo
from .const import CONF_RETRY_COUNT, DEFAULT_RETRY_COUNT, DOMAIN, SUPPORTED_MODEL_TYPES
@ -46,15 +45,14 @@ class SwitchbotConfigFlow(ConfigFlow, domain=DOMAIN):
self._discovered_advs: dict[str, SwitchBotAdvertisement] = {}
async def async_step_bluetooth(
self, discovery_info: BluetoothServiceInfo
self, discovery_info: BluetoothServiceInfoBleak
) -> FlowResult:
"""Handle the bluetooth discovery step."""
_LOGGER.debug("Discovered bluetooth device: %s", discovery_info)
await self.async_set_unique_id(format_unique_id(discovery_info.address))
self._abort_if_unique_id_configured()
discovery_info_bleak = cast(BluetoothServiceInfoBleak, discovery_info)
parsed = parse_advertisement_data(
discovery_info_bleak.device, discovery_info_bleak.advertisement
discovery_info.device, discovery_info.advertisement
)
if not parsed or parsed.data.get("modelName") not in SUPPORTED_MODEL_TYPES:
return self.async_abort(reason="not_supported")

View file

@ -3,7 +3,7 @@ from __future__ import annotations
import asyncio
import logging
from typing import TYPE_CHECKING, Any, cast
from typing import TYPE_CHECKING, Any
import switchbot
@ -39,7 +39,9 @@ class SwitchbotDataUpdateCoordinator(PassiveBluetoothDataUpdateCoordinator):
device: switchbot.SwitchbotDevice,
) -> None:
"""Initialize global switchbot data updater."""
super().__init__(hass, logger, ble_device.address)
super().__init__(
hass, logger, ble_device.address, bluetooth.BluetoothScanningMode.ACTIVE
)
self.ble_device = ble_device
self.device = device
self.data: dict[str, Any] = {}
@ -48,14 +50,13 @@ class SwitchbotDataUpdateCoordinator(PassiveBluetoothDataUpdateCoordinator):
@callback
def _async_handle_bluetooth_event(
self,
service_info: bluetooth.BluetoothServiceInfo,
service_info: bluetooth.BluetoothServiceInfoBleak,
change: bluetooth.BluetoothChange,
) -> None:
"""Handle a Bluetooth event."""
super()._async_handle_bluetooth_event(service_info, change)
discovery_info_bleak = cast(bluetooth.BluetoothServiceInfoBleak, service_info)
if adv := switchbot.parse_advertisement_data(
discovery_info_bleak.device, discovery_info_bleak.advertisement
service_info.device, service_info.advertisement
):
self.data = flatten_sensors_data(adv.data)
if "modelName" in self.data:

View file

@ -3,6 +3,7 @@ from __future__ import annotations
import logging
from homeassistant.components.bluetooth import BluetoothScanningMode
from homeassistant.components.bluetooth.passive_update_processor import (
PassiveBluetoothProcessorCoordinator,
)
@ -24,9 +25,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
coordinator = hass.data.setdefault(DOMAIN, {})[
entry.entry_id
] = PassiveBluetoothProcessorCoordinator(
hass,
_LOGGER,
address=address,
hass, _LOGGER, address=address, mode=BluetoothScanningMode.PASSIVE
)
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
entry.async_on_unload(

View file

@ -11,7 +11,8 @@ from xiaomi_ble.parser import EncryptionScheme
from homeassistant.components import onboarding
from homeassistant.components.bluetooth import (
BluetoothServiceInfo,
BluetoothScanningMode,
BluetoothServiceInfoBleak,
async_discovered_service_info,
async_process_advertisements,
)
@ -30,11 +31,11 @@ class Discovery:
"""A discovered bluetooth device."""
title: str
discovery_info: BluetoothServiceInfo
discovery_info: BluetoothServiceInfoBleak
device: DeviceData
def _title(discovery_info: BluetoothServiceInfo, device: DeviceData) -> str:
def _title(discovery_info: BluetoothServiceInfoBleak, device: DeviceData) -> str:
return device.title or device.get_device_name() or discovery_info.name
@ -45,18 +46,20 @@ class XiaomiConfigFlow(ConfigFlow, domain=DOMAIN):
def __init__(self) -> None:
"""Initialize the config flow."""
self._discovery_info: BluetoothServiceInfo | None = None
self._discovery_info: BluetoothServiceInfoBleak | None = None
self._discovered_device: DeviceData | None = None
self._discovered_devices: dict[str, Discovery] = {}
async def _async_wait_for_full_advertisement(
self, discovery_info: BluetoothServiceInfo, device: DeviceData
) -> BluetoothServiceInfo:
self, discovery_info: BluetoothServiceInfoBleak, device: DeviceData
) -> BluetoothServiceInfoBleak:
"""Sometimes first advertisement we receive is blank or incomplete. Wait until we get a useful one."""
if not device.pending:
return discovery_info
def _process_more_advertisements(service_info: BluetoothServiceInfo) -> bool:
def _process_more_advertisements(
service_info: BluetoothServiceInfoBleak,
) -> bool:
device.update(service_info)
return not device.pending
@ -64,11 +67,12 @@ class XiaomiConfigFlow(ConfigFlow, domain=DOMAIN):
self.hass,
_process_more_advertisements,
{"address": discovery_info.address},
BluetoothScanningMode.ACTIVE,
ADDITIONAL_DISCOVERY_TIMEOUT,
)
async def async_step_bluetooth(
self, discovery_info: BluetoothServiceInfo
self, discovery_info: BluetoothServiceInfoBleak
) -> FlowResult:
"""Handle the bluetooth discovery step."""
await self.async_set_unique_id(discovery_info.address)

View file

@ -27,12 +27,12 @@ from .util import uuid as uuid_util
from .util.decorator import Registry
if TYPE_CHECKING:
from .components.bluetooth import BluetoothServiceInfoBleak
from .components.dhcp import DhcpServiceInfo
from .components.hassio import HassioServiceInfo
from .components.ssdp import SsdpServiceInfo
from .components.usb import UsbServiceInfo
from .components.zeroconf import ZeroconfServiceInfo
from .helpers.service_info.bluetooth import BluetoothServiceInfo
from .helpers.service_info.mqtt import MqttServiceInfo
_LOGGER = logging.getLogger(__name__)
@ -1485,7 +1485,7 @@ class ConfigFlow(data_entry_flow.FlowHandler):
)
async def async_step_bluetooth(
self, discovery_info: BluetoothServiceInfo
self, discovery_info: BluetoothServiceInfoBleak
) -> data_entry_flow.FlowResult:
"""Handle a flow initialized by Bluetooth discovery."""
return await self._async_step_discovery_without_unique_id()

View file

@ -15,11 +15,11 @@ from .typing import DiscoveryInfoType
if TYPE_CHECKING:
import asyncio
from homeassistant.components.bluetooth import BluetoothServiceInfoBleak
from homeassistant.components.dhcp import DhcpServiceInfo
from homeassistant.components.ssdp import SsdpServiceInfo
from homeassistant.components.zeroconf import ZeroconfServiceInfo
from .service_info.bluetooth import BluetoothServiceInfo
from .service_info.mqtt import MqttServiceInfo
_R = TypeVar("_R", bound="Awaitable[bool] | bool")
@ -97,7 +97,7 @@ class DiscoveryFlowHandler(config_entries.ConfigFlow, Generic[_R]):
return await self.async_step_confirm()
async def async_step_bluetooth(
self, discovery_info: BluetoothServiceInfo
self, discovery_info: BluetoothServiceInfoBleak
) -> FlowResult:
"""Handle a flow initialized by bluetooth discovery."""
if self._async_in_progress() or self._async_current_entries():

View file

@ -1,4 +1,5 @@
"""The bluetooth integration service info."""
from home_assistant_bluetooth import BluetoothServiceInfo
__all__ = ["BluetoothServiceInfo"]

View file

@ -10,7 +10,7 @@ atomicwrites-homeassistant==1.4.1
attrs==21.2.0
awesomeversion==22.6.0
bcrypt==3.1.7
bleak==0.14.3
bleak==0.15.0
bluetooth-adapters==0.1.2
certifi>=2021.5.30
ciso8601==2.2.0

View file

@ -405,7 +405,7 @@ bimmer_connected==0.10.1
bizkaibus==0.1.1
# homeassistant.components.bluetooth
bleak==0.14.3
bleak==0.15.0
# homeassistant.components.blebox
blebox_uniapi==2.0.2

View file

@ -326,7 +326,7 @@ bellows==0.31.2
bimmer_connected==0.10.1
# homeassistant.components.bluetooth
bleak==0.14.3
bleak==0.15.0
# homeassistant.components.blebox
blebox_uniapi==2.0.2

View file

@ -12,6 +12,7 @@ from homeassistant.components.bluetooth import (
SOURCE_LOCAL,
UNAVAILABLE_TRACK_SECONDS,
BluetoothChange,
BluetoothScanningMode,
BluetoothServiceInfo,
async_process_advertisements,
async_track_unavailable,
@ -675,6 +676,7 @@ async def test_register_callbacks(hass, mock_bleak_scanner_start, enable_bluetoo
hass,
_fake_subscriber,
{"service_uuids": {"cba20d00-224d-11e6-9fb8-0002a5d5c51b"}},
BluetoothScanningMode.ACTIVE,
)
assert len(mock_bleak_scanner_start.mock_calls) == 1
@ -760,6 +762,7 @@ async def test_register_callback_by_address(
hass,
_fake_subscriber,
{"address": "44:44:33:11:23:45"},
BluetoothScanningMode.ACTIVE,
)
assert len(mock_bleak_scanner_start.mock_calls) == 1
@ -799,6 +802,7 @@ async def test_register_callback_by_address(
hass,
_fake_subscriber,
{"address": "44:44:33:11:23:45"},
BluetoothScanningMode.ACTIVE,
)
cancel()
@ -808,6 +812,7 @@ async def test_register_callback_by_address(
hass,
_fake_subscriber,
{"address": "44:44:33:11:23:45"},
BluetoothScanningMode.ACTIVE,
)
cancel()
@ -832,7 +837,11 @@ async def test_process_advertisements_bail_on_good_advertisement(
handle = hass.async_create_task(
async_process_advertisements(
hass, _callback, {"address": "aa:44:33:11:23:45"}, 5
hass,
_callback,
{"address": "aa:44:33:11:23:45"},
BluetoothScanningMode.ACTIVE,
5,
)
)
@ -873,7 +882,11 @@ async def test_process_advertisements_ignore_bad_advertisement(
handle = hass.async_create_task(
async_process_advertisements(
hass, _callback, {"address": "aa:44:33:11:23:45"}, 5
hass,
_callback,
{"address": "aa:44:33:11:23:45"},
BluetoothScanningMode.ACTIVE,
5,
)
)
@ -903,7 +916,9 @@ async def test_process_advertisements_timeout(
return False
with pytest.raises(asyncio.TimeoutError):
await async_process_advertisements(hass, _callback, {}, 0)
await async_process_advertisements(
hass, _callback, {}, BluetoothScanningMode.ACTIVE, 0
)
async def test_wrapped_instance_with_filter(

View file

@ -10,6 +10,7 @@ from homeassistant.components.bluetooth import (
DOMAIN,
UNAVAILABLE_TRACK_SECONDS,
BluetoothChange,
BluetoothScanningMode,
)
from homeassistant.components.bluetooth.passive_update_coordinator import (
PassiveBluetoothCoordinatorEntity,
@ -42,9 +43,9 @@ GENERIC_BLUETOOTH_SERVICE_INFO = BluetoothServiceInfo(
class MyCoordinator(PassiveBluetoothDataUpdateCoordinator):
"""An example coordinator that subclasses PassiveBluetoothDataUpdateCoordinator."""
def __init__(self, hass, logger, device_id) -> None:
def __init__(self, hass, logger, device_id, mode) -> None:
"""Initialize the coordinator."""
super().__init__(hass, logger, device_id)
super().__init__(hass, logger, device_id, mode)
self.data: dict[str, Any] = {}
def _async_handle_bluetooth_event(
@ -60,11 +61,13 @@ class MyCoordinator(PassiveBluetoothDataUpdateCoordinator):
async def test_basic_usage(hass, mock_bleak_scanner_start):
"""Test basic usage of the PassiveBluetoothDataUpdateCoordinator."""
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
coordinator = MyCoordinator(hass, _LOGGER, "aa:bb:cc:dd:ee:ff")
coordinator = MyCoordinator(
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):
def _async_register_callback(_hass, _callback, _matcher, _mode):
nonlocal saved_callback
saved_callback = _callback
return lambda: None
@ -100,11 +103,13 @@ async def test_context_compatiblity_with_data_update_coordinator(
):
"""Test contexts can be passed for compatibility with DataUpdateCoordinator."""
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
coordinator = MyCoordinator(hass, _LOGGER, "aa:bb:cc:dd:ee:ff")
coordinator = MyCoordinator(
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):
def _async_register_callback(_hass, _callback, _matcher, _mode):
nonlocal saved_callback
saved_callback = _callback
return lambda: None
@ -149,11 +154,13 @@ async def test_unavailable_callbacks_mark_the_coordinator_unavailable(
):
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
await hass.async_block_till_done()
coordinator = MyCoordinator(hass, _LOGGER, "aa:bb:cc:dd:ee:ff")
coordinator = MyCoordinator(
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):
def _async_register_callback(_hass, _callback, _matcher, _mode):
nonlocal saved_callback
saved_callback = _callback
return lambda: None
@ -208,13 +215,15 @@ async def test_unavailable_callbacks_mark_the_coordinator_unavailable(
async def test_passive_bluetooth_coordinator_entity(hass, mock_bleak_scanner_start):
"""Test integration of PassiveBluetoothDataUpdateCoordinator with PassiveBluetoothCoordinatorEntity."""
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
coordinator = MyCoordinator(hass, _LOGGER, "aa:bb:cc:dd:ee:ff")
coordinator = MyCoordinator(
hass, _LOGGER, "aa:bb:cc:dd:ee:ff", BluetoothScanningMode.ACTIVE
)
entity = PassiveBluetoothCoordinatorEntity(coordinator)
assert entity.available is False
saved_callback = None
def _async_register_callback(_hass, _callback, _matcher):
def _async_register_callback(_hass, _callback, _matcher, _mode):
nonlocal saved_callback
saved_callback = _callback
return lambda: None

View file

@ -16,6 +16,7 @@ from homeassistant.components.bluetooth import (
DOMAIN,
UNAVAILABLE_TRACK_SECONDS,
BluetoothChange,
BluetoothScanningMode,
)
from homeassistant.components.bluetooth.passive_update_processor import (
PassiveBluetoothDataProcessor,
@ -90,12 +91,12 @@ async def test_basic_usage(hass, mock_bleak_scanner_start):
return GENERIC_PASSIVE_BLUETOOTH_DATA_UPDATE
coordinator = PassiveBluetoothProcessorCoordinator(
hass, _LOGGER, "aa:bb:cc:dd:ee:ff"
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):
def _async_register_callback(_hass, _callback, _matcher, _mode):
nonlocal saved_callback
saved_callback = _callback
return lambda: None
@ -192,12 +193,12 @@ async def test_unavailable_after_no_data(hass, mock_bleak_scanner_start):
return GENERIC_PASSIVE_BLUETOOTH_DATA_UPDATE
coordinator = PassiveBluetoothProcessorCoordinator(
hass, _LOGGER, "aa:bb:cc:dd:ee:ff"
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):
def _async_register_callback(_hass, _callback, _matcher, _mode):
nonlocal saved_callback
saved_callback = _callback
return lambda: None
@ -277,12 +278,12 @@ async def test_no_updates_once_stopping(hass, mock_bleak_scanner_start):
return GENERIC_PASSIVE_BLUETOOTH_DATA_UPDATE
coordinator = PassiveBluetoothProcessorCoordinator(
hass, _LOGGER, "aa:bb:cc:dd:ee:ff"
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):
def _async_register_callback(_hass, _callback, _matcher, _mode):
nonlocal saved_callback
saved_callback = _callback
return lambda: None
@ -336,12 +337,12 @@ async def test_exception_from_update_method(hass, caplog, mock_bleak_scanner_sta
return GENERIC_PASSIVE_BLUETOOTH_DATA_UPDATE
coordinator = PassiveBluetoothProcessorCoordinator(
hass, _LOGGER, "aa:bb:cc:dd:ee:ff"
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):
def _async_register_callback(_hass, _callback, _matcher, _mode):
nonlocal saved_callback
saved_callback = _callback
return lambda: None
@ -389,12 +390,12 @@ async def test_bad_data_from_update_method(hass, mock_bleak_scanner_start):
return GENERIC_PASSIVE_BLUETOOTH_DATA_UPDATE
coordinator = PassiveBluetoothProcessorCoordinator(
hass, _LOGGER, "aa:bb:cc:dd:ee:ff"
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):
def _async_register_callback(_hass, _callback, _matcher, _mode):
nonlocal saved_callback
saved_callback = _callback
return lambda: None
@ -731,12 +732,12 @@ async def test_integration_with_entity(hass, mock_bleak_scanner_start):
return GOVEE_B5178_REMOTE_PASSIVE_BLUETOOTH_DATA_UPDATE
coordinator = PassiveBluetoothProcessorCoordinator(
hass, _LOGGER, "aa:bb:cc:dd:ee:ff"
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):
def _async_register_callback(_hass, _callback, _matcher, _mode):
nonlocal saved_callback
saved_callback = _callback
return lambda: None
@ -841,12 +842,12 @@ async def test_integration_with_entity_without_a_device(hass, mock_bleak_scanner
return NO_DEVICES_PASSIVE_BLUETOOTH_DATA_UPDATE
coordinator = PassiveBluetoothProcessorCoordinator(
hass, _LOGGER, "aa:bb:cc:dd:ee:ff"
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):
def _async_register_callback(_hass, _callback, _matcher, _mode):
nonlocal saved_callback
saved_callback = _callback
return lambda: None
@ -905,12 +906,12 @@ async def test_passive_bluetooth_entity_with_entity_platform(
return NO_DEVICES_PASSIVE_BLUETOOTH_DATA_UPDATE
coordinator = PassiveBluetoothProcessorCoordinator(
hass, _LOGGER, "aa:bb:cc:dd:ee:ff"
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):
def _async_register_callback(_hass, _callback, _matcher, _mode):
nonlocal saved_callback
saved_callback = _callback
return lambda: None
@ -992,12 +993,12 @@ async def test_integration_multiple_entity_platforms(hass, mock_bleak_scanner_st
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
coordinator = PassiveBluetoothProcessorCoordinator(
hass, _LOGGER, "aa:bb:cc:dd:ee:ff"
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):
def _async_register_callback(_hass, _callback, _matcher, _mode):
nonlocal saved_callback
saved_callback = _callback
return lambda: None

View file

@ -5,8 +5,9 @@ from datetime import timedelta
from unittest.mock import patch
from bleak import BleakError
from bleak.backends.scanner import AdvertisementData, BLEDevice
from homeassistant.components.bluetooth import BluetoothServiceInfo
from homeassistant.components.bluetooth import BluetoothServiceInfoBleak
from homeassistant.components.bluetooth_le_tracker import device_tracker
from homeassistant.components.bluetooth_le_tracker.device_tracker import (
CONF_TRACK_BATTERY,
@ -79,7 +80,7 @@ async def test_preserve_new_tracked_device_name(
device_tracker, "MIN_SEEN_NEW", 3
):
device = BluetoothServiceInfo(
device = BluetoothServiceInfoBleak(
name=name,
address=address,
rssi=-19,
@ -87,6 +88,8 @@ async def test_preserve_new_tracked_device_name(
service_data={},
service_uuids=[],
source="local",
device=BLEDevice(address, None),
advertisement=AdvertisementData(local_name="empty"),
)
# Return with name when seen first time
mock_async_discovered_service_info.return_value = [device]
@ -100,7 +103,7 @@ async def test_preserve_new_tracked_device_name(
assert result
# Seen once here; return without name when seen subsequent times
device = BluetoothServiceInfo(
device = BluetoothServiceInfoBleak(
name=None,
address=address,
rssi=-19,
@ -108,6 +111,8 @@ async def test_preserve_new_tracked_device_name(
service_data={},
service_uuids=[],
source="local",
device=BLEDevice(address, None),
advertisement=AdvertisementData(local_name="empty"),
)
# Return with name when seen first time
mock_async_discovered_service_info.return_value = [device]
@ -140,7 +145,7 @@ async def test_tracking_battery_times_out(
device_tracker, "MIN_SEEN_NEW", 3
):
device = BluetoothServiceInfo(
device = BluetoothServiceInfoBleak(
name=name,
address=address,
rssi=-19,
@ -148,6 +153,8 @@ async def test_tracking_battery_times_out(
service_data={},
service_uuids=[],
source="local",
device=BLEDevice(address, None),
advertisement=AdvertisementData(local_name="empty"),
)
# Return with name when seen first time
mock_async_discovered_service_info.return_value = [device]
@ -202,7 +209,7 @@ async def test_tracking_battery_fails(hass, mock_bluetooth, mock_device_tracker_
device_tracker, "MIN_SEEN_NEW", 3
):
device = BluetoothServiceInfo(
device = BluetoothServiceInfoBleak(
name=name,
address=address,
rssi=-19,
@ -210,6 +217,8 @@ async def test_tracking_battery_fails(hass, mock_bluetooth, mock_device_tracker_
service_data={},
service_uuids=[],
source="local",
device=BLEDevice(address, None),
advertisement=AdvertisementData(local_name="empty"),
)
# Return with name when seen first time
mock_async_discovered_service_info.return_value = [device]
@ -266,7 +275,7 @@ async def test_tracking_battery_successful(
device_tracker, "MIN_SEEN_NEW", 3
):
device = BluetoothServiceInfo(
device = BluetoothServiceInfoBleak(
name=name,
address=address,
rssi=-19,
@ -274,6 +283,8 @@ async def test_tracking_battery_successful(
service_data={},
service_uuids=[],
source="local",
device=BLEDevice(address, None),
advertisement=AdvertisementData(local_name="empty"),
)
# Return with name when seen first time
mock_async_discovered_service_info.return_value = [device]

View file

@ -17,6 +17,12 @@ def fixture_scanner(hass):
class MockScanner(BaseBleakScanner):
"""Mock Scanner."""
def __init__(self, *args, **kwargs) -> None:
"""Initialize the scanner."""
super().__init__(
detection_callback=kwargs.pop("detection_callback"), service_uuids=[]
)
async def start(self):
"""Start scanning for devices."""
for device in devices:

View file

@ -22,7 +22,7 @@ async def test_sensors(hass):
saved_callback = None
def _async_register_callback(_hass, _callback, _matcher):
def _async_register_callback(_hass, _callback, _matcher, _mode):
nonlocal saved_callback
saved_callback = _callback
return lambda: None

View file

@ -22,7 +22,7 @@ async def test_sensors(hass):
saved_callback = None
def _async_register_callback(_hass, _callback, _matcher):
def _async_register_callback(_hass, _callback, _matcher, _mode):
nonlocal saved_callback
saved_callback = _callback
return lambda: None

View file

@ -22,7 +22,7 @@ async def test_sensors(hass):
saved_callback = None
def _async_register_callback(_hass, _callback, _matcher):
def _async_register_callback(_hass, _callback, _matcher, _mode):
nonlocal saved_callback
saved_callback = _callback
return lambda: None

View file

@ -22,7 +22,7 @@ async def test_sensors(hass):
saved_callback = None
def _async_register_callback(_hass, _callback, _matcher):
def _async_register_callback(_hass, _callback, _matcher, _mode):
nonlocal saved_callback
saved_callback = _callback
return lambda: None

View file

@ -59,7 +59,9 @@ async def test_async_step_bluetooth_valid_device_but_missing_payload(hass):
async def test_async_step_bluetooth_valid_device_but_missing_payload_then_full(hass):
"""Test discovering a valid device. Payload is too short, but later we get full one."""
async def _async_process_advertisements(_hass, _callback, _matcher, _timeout):
async def _async_process_advertisements(
_hass, _callback, _matcher, _mode, _timeout
):
service_info = make_advertisement(
"A4:C1:38:56:53:84",
b"XX\xe4\x16,\x84SV8\xc1\xa4+n\xf2\xe9\x12\x00\x00l\x88M\x9e",
@ -378,7 +380,9 @@ async def test_async_step_user_short_payload_then_full(hass):
assert result["type"] == FlowResultType.FORM
assert result["step_id"] == "user"
async def _async_process_advertisements(_hass, _callback, _matcher, _timeout):
async def _async_process_advertisements(
_hass, _callback, _matcher, _mode, _timeout
):
service_info = make_advertisement(
"A4:C1:38:56:53:84",
b"XX\xe4\x16,\x84SV8\xc1\xa4+n\xf2\xe9\x12\x00\x00l\x88M\x9e",

View file

@ -22,7 +22,7 @@ async def test_sensors(hass):
saved_callback = None
def _async_register_callback(_hass, _callback, _matcher):
def _async_register_callback(_hass, _callback, _matcher, _mode):
nonlocal saved_callback
saved_callback = _callback
return lambda: None
@ -60,7 +60,7 @@ async def test_xiaomi_formaldeyhde(hass):
saved_callback = None
def _async_register_callback(_hass, _callback, _matcher):
def _async_register_callback(_hass, _callback, _matcher, _mode):
nonlocal saved_callback
saved_callback = _callback
return lambda: None
@ -107,7 +107,7 @@ async def test_xiaomi_consumable(hass):
saved_callback = None
def _async_register_callback(_hass, _callback, _matcher):
def _async_register_callback(_hass, _callback, _matcher, _mode):
nonlocal saved_callback
saved_callback = _callback
return lambda: None
@ -154,7 +154,7 @@ async def test_xiaomi_battery_voltage(hass):
saved_callback = None
def _async_register_callback(_hass, _callback, _matcher):
def _async_register_callback(_hass, _callback, _matcher, _mode):
nonlocal saved_callback
saved_callback = _callback
return lambda: None
@ -208,7 +208,7 @@ async def test_xiaomi_HHCCJCY01(hass):
saved_callback = None
def _async_register_callback(_hass, _callback, _matcher):
def _async_register_callback(_hass, _callback, _matcher, _mode):
nonlocal saved_callback
saved_callback = _callback
return lambda: None
@ -291,7 +291,7 @@ async def test_xiaomi_CGDK2(hass):
saved_callback = None
def _async_register_callback(_hass, _callback, _matcher):
def _async_register_callback(_hass, _callback, _matcher, _mode):
nonlocal saved_callback
saved_callback = _callback
return lambda: None