Offload platform specific bluetooth code to bluetooth-adapters (#82196)
* Offload platform specific bluetooth code to bluetooth-adapters * adjust * fix some more patch targets * more test fixes * almost there * may not be setup yet * more fixes * fixes * fix test * fix mergepull/82367/head
parent
d0efdd750f
commit
47c66dbed4
|
@ -10,6 +10,16 @@ from typing import TYPE_CHECKING, cast
|
||||||
|
|
||||||
import async_timeout
|
import async_timeout
|
||||||
from awesomeversion import AwesomeVersion
|
from awesomeversion import AwesomeVersion
|
||||||
|
from bluetooth_adapters import (
|
||||||
|
ADAPTER_ADDRESS,
|
||||||
|
ADAPTER_HW_VERSION,
|
||||||
|
ADAPTER_SW_VERSION,
|
||||||
|
DEFAULT_ADDRESS,
|
||||||
|
AdapterDetails,
|
||||||
|
adapter_human_name,
|
||||||
|
adapter_unique_name,
|
||||||
|
get_adapters,
|
||||||
|
)
|
||||||
|
|
||||||
from homeassistant.components import usb
|
from homeassistant.components import usb
|
||||||
from homeassistant.config_entries import (
|
from homeassistant.config_entries import (
|
||||||
|
@ -32,20 +42,15 @@ from homeassistant.loader import async_get_bluetooth
|
||||||
|
|
||||||
from . import models
|
from . import models
|
||||||
from .const import (
|
from .const import (
|
||||||
ADAPTER_ADDRESS,
|
|
||||||
ADAPTER_HW_VERSION,
|
|
||||||
ADAPTER_SW_VERSION,
|
|
||||||
BLUETOOTH_DISCOVERY_COOLDOWN_SECONDS,
|
BLUETOOTH_DISCOVERY_COOLDOWN_SECONDS,
|
||||||
CONF_ADAPTER,
|
CONF_ADAPTER,
|
||||||
CONF_DETAILS,
|
CONF_DETAILS,
|
||||||
CONF_PASSIVE,
|
CONF_PASSIVE,
|
||||||
DATA_MANAGER,
|
DATA_MANAGER,
|
||||||
DEFAULT_ADDRESS,
|
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS,
|
FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS,
|
||||||
LINUX_FIRMWARE_LOAD_FALLBACK_SECONDS,
|
LINUX_FIRMWARE_LOAD_FALLBACK_SECONDS,
|
||||||
SOURCE_LOCAL,
|
SOURCE_LOCAL,
|
||||||
AdapterDetails,
|
|
||||||
)
|
)
|
||||||
from .manager import BluetoothManager
|
from .manager import BluetoothManager
|
||||||
from .match import BluetoothCallbackMatcher, IntegrationMatcher
|
from .match import BluetoothCallbackMatcher, IntegrationMatcher
|
||||||
|
@ -62,7 +67,6 @@ from .models import (
|
||||||
ProcessAdvertisementCallback,
|
ProcessAdvertisementCallback,
|
||||||
)
|
)
|
||||||
from .scanner import HaScanner, ScannerStartError
|
from .scanner import HaScanner, ScannerStartError
|
||||||
from .util import adapter_human_name, adapter_unique_name, async_default_adapter
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from bleak.backends.device import BLEDevice
|
from bleak.backends.device import BLEDevice
|
||||||
|
@ -288,13 +292,14 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
"""Set up the bluetooth integration."""
|
"""Set up the bluetooth integration."""
|
||||||
integration_matcher = IntegrationMatcher(await async_get_bluetooth(hass))
|
integration_matcher = IntegrationMatcher(await async_get_bluetooth(hass))
|
||||||
integration_matcher.async_setup()
|
integration_matcher.async_setup()
|
||||||
manager = BluetoothManager(hass, integration_matcher)
|
bluetooth_adapters = get_adapters()
|
||||||
|
manager = BluetoothManager(hass, integration_matcher, bluetooth_adapters)
|
||||||
await manager.async_setup()
|
await manager.async_setup()
|
||||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, manager.async_stop)
|
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, manager.async_stop)
|
||||||
hass.data[DATA_MANAGER] = models.MANAGER = manager
|
hass.data[DATA_MANAGER] = models.MANAGER = manager
|
||||||
adapters = await manager.async_get_bluetooth_adapters()
|
adapters = await manager.async_get_bluetooth_adapters()
|
||||||
|
|
||||||
async_migrate_entries(hass, adapters)
|
async_migrate_entries(hass, adapters, bluetooth_adapters.default_adapter)
|
||||||
await async_discover_adapters(hass, adapters)
|
await async_discover_adapters(hass, adapters)
|
||||||
|
|
||||||
async def _async_rediscover_adapters() -> None:
|
async def _async_rediscover_adapters() -> None:
|
||||||
|
@ -347,17 +352,15 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
EVENT_HOMEASSISTANT_STARTED,
|
EVENT_HOMEASSISTANT_STARTED,
|
||||||
hass_callback(lambda event: _async_check_haos(hass)),
|
hass_callback(lambda event: _async_check_haos(hass)),
|
||||||
)
|
)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
@hass_callback
|
@hass_callback
|
||||||
def async_migrate_entries(
|
def async_migrate_entries(
|
||||||
hass: HomeAssistant, adapters: dict[str, AdapterDetails]
|
hass: HomeAssistant, adapters: dict[str, AdapterDetails], default_adapter: str
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Migrate config entries to support multiple."""
|
"""Migrate config entries to support multiple."""
|
||||||
current_entries = hass.config_entries.async_entries(DOMAIN)
|
current_entries = hass.config_entries.async_entries(DOMAIN)
|
||||||
default_adapter = async_default_adapter()
|
|
||||||
|
|
||||||
for entry in current_entries:
|
for entry in current_entries:
|
||||||
if entry.unique_id:
|
if entry.unique_id:
|
||||||
|
|
|
@ -3,6 +3,13 @@ from __future__ import annotations
|
||||||
|
|
||||||
from typing import TYPE_CHECKING, Any, cast
|
from typing import TYPE_CHECKING, Any, cast
|
||||||
|
|
||||||
|
from bluetooth_adapters import (
|
||||||
|
ADAPTER_ADDRESS,
|
||||||
|
AdapterDetails,
|
||||||
|
adapter_human_name,
|
||||||
|
adapter_unique_name,
|
||||||
|
get_adapters,
|
||||||
|
)
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components import onboarding
|
from homeassistant.components import onboarding
|
||||||
|
@ -11,15 +18,7 @@ from homeassistant.core import callback
|
||||||
from homeassistant.helpers.typing import DiscoveryInfoType
|
from homeassistant.helpers.typing import DiscoveryInfoType
|
||||||
|
|
||||||
from . import models
|
from . import models
|
||||||
from .const import (
|
from .const import CONF_ADAPTER, CONF_DETAILS, CONF_PASSIVE, DOMAIN
|
||||||
ADAPTER_ADDRESS,
|
|
||||||
CONF_ADAPTER,
|
|
||||||
CONF_DETAILS,
|
|
||||||
CONF_PASSIVE,
|
|
||||||
DOMAIN,
|
|
||||||
AdapterDetails,
|
|
||||||
)
|
|
||||||
from .util import adapter_human_name, adapter_unique_name, async_get_bluetooth_adapters
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from homeassistant.data_entry_flow import FlowResult
|
from homeassistant.data_entry_flow import FlowResult
|
||||||
|
@ -87,7 +86,9 @@ class BluetoothConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||||
)
|
)
|
||||||
|
|
||||||
configured_addresses = self._async_current_ids()
|
configured_addresses = self._async_current_ids()
|
||||||
self._adapters = await async_get_bluetooth_adapters()
|
bluetooth_adapters = get_adapters()
|
||||||
|
await bluetooth_adapters.refresh()
|
||||||
|
self._adapters = bluetooth_adapters.adapters
|
||||||
unconfigured_adapters = [
|
unconfigured_adapters = [
|
||||||
adapter
|
adapter
|
||||||
for adapter, details in self._adapters.items()
|
for adapter, details in self._adapters.items()
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from typing import Final, TypedDict
|
from typing import Final
|
||||||
|
|
||||||
DOMAIN = "bluetooth"
|
DOMAIN = "bluetooth"
|
||||||
|
|
||||||
|
@ -10,18 +10,6 @@ CONF_ADAPTER = "adapter"
|
||||||
CONF_DETAILS = "details"
|
CONF_DETAILS = "details"
|
||||||
CONF_PASSIVE = "passive"
|
CONF_PASSIVE = "passive"
|
||||||
|
|
||||||
WINDOWS_DEFAULT_BLUETOOTH_ADAPTER = "bluetooth"
|
|
||||||
MACOS_DEFAULT_BLUETOOTH_ADAPTER = "Core Bluetooth"
|
|
||||||
UNIX_DEFAULT_BLUETOOTH_ADAPTER = "hci0"
|
|
||||||
|
|
||||||
DEFAULT_ADAPTER_BY_PLATFORM = {
|
|
||||||
"Windows": WINDOWS_DEFAULT_BLUETOOTH_ADAPTER,
|
|
||||||
"Darwin": MACOS_DEFAULT_BLUETOOTH_ADAPTER,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Some operating systems hide the adapter address for privacy reasons (ex MacOS)
|
|
||||||
DEFAULT_ADDRESS: Final = "00:00:00:00:00:00"
|
|
||||||
|
|
||||||
SOURCE_LOCAL: Final = "local"
|
SOURCE_LOCAL: Final = "local"
|
||||||
|
|
||||||
|
@ -66,18 +54,3 @@ SCANNER_WATCHDOG_INTERVAL: Final = timedelta(seconds=30)
|
||||||
# are not present
|
# are not present
|
||||||
LINUX_FIRMWARE_LOAD_FALLBACK_SECONDS = 120
|
LINUX_FIRMWARE_LOAD_FALLBACK_SECONDS = 120
|
||||||
BLUETOOTH_DISCOVERY_COOLDOWN_SECONDS = 5
|
BLUETOOTH_DISCOVERY_COOLDOWN_SECONDS = 5
|
||||||
|
|
||||||
|
|
||||||
class AdapterDetails(TypedDict, total=False):
|
|
||||||
"""Adapter details."""
|
|
||||||
|
|
||||||
address: str
|
|
||||||
sw_version: str
|
|
||||||
hw_version: str | None
|
|
||||||
passive_scan: bool
|
|
||||||
|
|
||||||
|
|
||||||
ADAPTER_ADDRESS: Final = "address"
|
|
||||||
ADAPTER_SW_VERSION: Final = "sw_version"
|
|
||||||
ADAPTER_HW_VERSION: Final = "hw_version"
|
|
||||||
ADAPTER_PASSIVE_SCAN: Final = "passive_scan"
|
|
||||||
|
|
|
@ -10,6 +10,12 @@ from typing import TYPE_CHECKING, Any, Final
|
||||||
|
|
||||||
from bleak.backends.scanner import AdvertisementDataCallback
|
from bleak.backends.scanner import AdvertisementDataCallback
|
||||||
from bleak_retry_connector import NO_RSSI_VALUE, RSSI_SWITCH_THRESHOLD
|
from bleak_retry_connector import NO_RSSI_VALUE, RSSI_SWITCH_THRESHOLD
|
||||||
|
from bluetooth_adapters import (
|
||||||
|
ADAPTER_ADDRESS,
|
||||||
|
ADAPTER_PASSIVE_SCAN,
|
||||||
|
AdapterDetails,
|
||||||
|
BluetoothAdapters,
|
||||||
|
)
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.core import (
|
from homeassistant.core import (
|
||||||
|
@ -24,11 +30,8 @@ from homeassistant.util.dt import monotonic_time_coarse
|
||||||
|
|
||||||
from .advertisement_tracker import AdvertisementTracker
|
from .advertisement_tracker import AdvertisementTracker
|
||||||
from .const import (
|
from .const import (
|
||||||
ADAPTER_ADDRESS,
|
|
||||||
ADAPTER_PASSIVE_SCAN,
|
|
||||||
FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS,
|
FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS,
|
||||||
UNAVAILABLE_TRACK_SECONDS,
|
UNAVAILABLE_TRACK_SECONDS,
|
||||||
AdapterDetails,
|
|
||||||
)
|
)
|
||||||
from .match import (
|
from .match import (
|
||||||
ADDRESS,
|
ADDRESS,
|
||||||
|
@ -47,7 +50,7 @@ from .models import (
|
||||||
BluetoothServiceInfoBleak,
|
BluetoothServiceInfoBleak,
|
||||||
)
|
)
|
||||||
from .usage import install_multiple_bleak_catcher, uninstall_multiple_bleak_catcher
|
from .usage import install_multiple_bleak_catcher, uninstall_multiple_bleak_catcher
|
||||||
from .util import async_get_bluetooth_adapters, async_load_history_from_system
|
from .util import async_load_history_from_system
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from bleak.backends.device import BLEDevice
|
from bleak.backends.device import BLEDevice
|
||||||
|
@ -102,6 +105,7 @@ class BluetoothManager:
|
||||||
self,
|
self,
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
integration_matcher: IntegrationMatcher,
|
integration_matcher: IntegrationMatcher,
|
||||||
|
bluetooth_adapters: BluetoothAdapters,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Init bluetooth manager."""
|
"""Init bluetooth manager."""
|
||||||
self.hass = hass
|
self.hass = hass
|
||||||
|
@ -127,6 +131,7 @@ class BluetoothManager:
|
||||||
self._connectable_scanners: list[BaseHaScanner] = []
|
self._connectable_scanners: list[BaseHaScanner] = []
|
||||||
self._adapters: dict[str, AdapterDetails] = {}
|
self._adapters: dict[str, AdapterDetails] = {}
|
||||||
self._sources: set[str] = set()
|
self._sources: set[str] = set()
|
||||||
|
self._bluetooth_adapters = bluetooth_adapters
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supports_passive_scan(self) -> bool:
|
def supports_passive_scan(self) -> bool:
|
||||||
|
@ -172,21 +177,25 @@ class BluetoothManager:
|
||||||
self, cached: bool = True
|
self, cached: bool = True
|
||||||
) -> dict[str, AdapterDetails]:
|
) -> dict[str, AdapterDetails]:
|
||||||
"""Get bluetooth adapters."""
|
"""Get bluetooth adapters."""
|
||||||
if not cached or not self._adapters:
|
if not self._adapters or not cached:
|
||||||
self._adapters = await async_get_bluetooth_adapters()
|
if not cached:
|
||||||
|
await self._bluetooth_adapters.refresh()
|
||||||
|
self._adapters = self._bluetooth_adapters.adapters
|
||||||
return self._adapters
|
return self._adapters
|
||||||
|
|
||||||
async def async_get_adapter_from_address(self, address: str) -> str | None:
|
async def async_get_adapter_from_address(self, address: str) -> str | None:
|
||||||
"""Get adapter from address."""
|
"""Get adapter from address."""
|
||||||
if adapter := self._find_adapter_by_address(address):
|
if adapter := self._find_adapter_by_address(address):
|
||||||
return adapter
|
return adapter
|
||||||
self._adapters = await async_get_bluetooth_adapters()
|
await self._bluetooth_adapters.refresh()
|
||||||
|
self._adapters = self._bluetooth_adapters.adapters
|
||||||
return self._find_adapter_by_address(address)
|
return self._find_adapter_by_address(address)
|
||||||
|
|
||||||
async def async_setup(self) -> None:
|
async def async_setup(self) -> None:
|
||||||
"""Set up the bluetooth manager."""
|
"""Set up the bluetooth manager."""
|
||||||
|
await self._bluetooth_adapters.refresh()
|
||||||
install_multiple_bleak_catcher()
|
install_multiple_bleak_catcher()
|
||||||
history = await async_load_history_from_system()
|
history = async_load_history_from_system(self._bluetooth_adapters)
|
||||||
# Everything is connectable so it fall into both
|
# Everything is connectable so it fall into both
|
||||||
# buckets since the host system can only provide
|
# buckets since the host system can only provide
|
||||||
# connectable devices
|
# connectable devices
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
"requirements": [
|
"requirements": [
|
||||||
"bleak==0.19.2",
|
"bleak==0.19.2",
|
||||||
"bleak-retry-connector==2.8.4",
|
"bleak-retry-connector==2.8.4",
|
||||||
"bluetooth-adapters==0.7.0",
|
"bluetooth-adapters==0.8.0",
|
||||||
"bluetooth-auto-recovery==0.4.0",
|
"bluetooth-auto-recovery==0.4.0",
|
||||||
"bluetooth-data-tools==0.3.0",
|
"bluetooth-data-tools==0.3.0",
|
||||||
"dbus-fast==1.74.1"
|
"dbus-fast==1.74.1"
|
||||||
|
|
|
@ -16,6 +16,7 @@ from bleak.backends.bluezdbus.advertisement_monitor import OrPattern
|
||||||
from bleak.backends.bluezdbus.scanner import BlueZScannerArgs
|
from bleak.backends.bluezdbus.scanner import BlueZScannerArgs
|
||||||
from bleak.backends.device import BLEDevice
|
from bleak.backends.device import BLEDevice
|
||||||
from bleak.backends.scanner import AdvertisementData, AdvertisementDataCallback
|
from bleak.backends.scanner import AdvertisementData, AdvertisementDataCallback
|
||||||
|
from bluetooth_adapters import DEFAULT_ADDRESS, adapter_human_name
|
||||||
from dbus_fast import InvalidMessageError
|
from dbus_fast import InvalidMessageError
|
||||||
|
|
||||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback as hass_callback
|
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback as hass_callback
|
||||||
|
@ -25,14 +26,13 @@ from homeassistant.util.dt import monotonic_time_coarse
|
||||||
from homeassistant.util.package import is_docker_env
|
from homeassistant.util.package import is_docker_env
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
DEFAULT_ADDRESS,
|
|
||||||
SCANNER_WATCHDOG_INTERVAL,
|
SCANNER_WATCHDOG_INTERVAL,
|
||||||
SCANNER_WATCHDOG_TIMEOUT,
|
SCANNER_WATCHDOG_TIMEOUT,
|
||||||
SOURCE_LOCAL,
|
SOURCE_LOCAL,
|
||||||
START_TIMEOUT,
|
START_TIMEOUT,
|
||||||
)
|
)
|
||||||
from .models import BaseHaScanner, BluetoothScanningMode, BluetoothServiceInfoBleak
|
from .models import BaseHaScanner, BluetoothScanningMode, BluetoothServiceInfoBleak
|
||||||
from .util import adapter_human_name, async_reset_adapter
|
from .util import async_reset_adapter
|
||||||
|
|
||||||
OriginalBleakScanner = bleak.BleakScanner
|
OriginalBleakScanner = bleak.BleakScanner
|
||||||
MONOTONIC_TIME = monotonic_time_coarse
|
MONOTONIC_TIME = monotonic_time_coarse
|
||||||
|
|
|
@ -1,34 +1,20 @@
|
||||||
"""The bluetooth integration utilities."""
|
"""The bluetooth integration utilities."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import platform
|
from bluetooth_adapters import BluetoothAdapters
|
||||||
|
|
||||||
from bluetooth_auto_recovery import recover_adapter
|
from bluetooth_auto_recovery import recover_adapter
|
||||||
|
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.util.dt import monotonic_time_coarse
|
from homeassistant.util.dt import monotonic_time_coarse
|
||||||
|
|
||||||
from .const import (
|
|
||||||
DEFAULT_ADAPTER_BY_PLATFORM,
|
|
||||||
DEFAULT_ADDRESS,
|
|
||||||
MACOS_DEFAULT_BLUETOOTH_ADAPTER,
|
|
||||||
UNIX_DEFAULT_BLUETOOTH_ADAPTER,
|
|
||||||
WINDOWS_DEFAULT_BLUETOOTH_ADAPTER,
|
|
||||||
AdapterDetails,
|
|
||||||
)
|
|
||||||
from .models import BluetoothServiceInfoBleak
|
from .models import BluetoothServiceInfoBleak
|
||||||
|
|
||||||
|
|
||||||
async def async_load_history_from_system() -> dict[str, BluetoothServiceInfoBleak]:
|
@callback
|
||||||
|
def async_load_history_from_system(
|
||||||
|
adapters: BluetoothAdapters,
|
||||||
|
) -> dict[str, BluetoothServiceInfoBleak]:
|
||||||
"""Load the device and advertisement_data history if available on the current system."""
|
"""Load the device and advertisement_data history if available on the current system."""
|
||||||
if platform.system() != "Linux":
|
|
||||||
return {}
|
|
||||||
from bluetooth_adapters import ( # pylint: disable=import-outside-toplevel
|
|
||||||
BlueZDBusObjects,
|
|
||||||
)
|
|
||||||
|
|
||||||
bluez_dbus = BlueZDBusObjects()
|
|
||||||
await bluez_dbus.load()
|
|
||||||
now = monotonic_time_coarse()
|
now = monotonic_time_coarse()
|
||||||
return {
|
return {
|
||||||
address: BluetoothServiceInfoBleak(
|
address: BluetoothServiceInfoBleak(
|
||||||
|
@ -46,65 +32,10 @@ async def async_load_history_from_system() -> dict[str, BluetoothServiceInfoBlea
|
||||||
connectable=False,
|
connectable=False,
|
||||||
time=now,
|
time=now,
|
||||||
)
|
)
|
||||||
for address, history in bluez_dbus.history.items()
|
for address, history in adapters.history.items()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async def async_get_bluetooth_adapters() -> dict[str, AdapterDetails]:
|
|
||||||
"""Return a list of bluetooth adapters."""
|
|
||||||
if platform.system() == "Windows":
|
|
||||||
return {
|
|
||||||
WINDOWS_DEFAULT_BLUETOOTH_ADAPTER: AdapterDetails(
|
|
||||||
address=DEFAULT_ADDRESS,
|
|
||||||
sw_version=platform.release(),
|
|
||||||
passive_scan=False,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if platform.system() == "Darwin":
|
|
||||||
return {
|
|
||||||
MACOS_DEFAULT_BLUETOOTH_ADAPTER: AdapterDetails(
|
|
||||||
address=DEFAULT_ADDRESS,
|
|
||||||
sw_version=platform.release(),
|
|
||||||
passive_scan=False,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
from bluetooth_adapters import ( # pylint: disable=import-outside-toplevel
|
|
||||||
get_bluetooth_adapter_details,
|
|
||||||
)
|
|
||||||
|
|
||||||
adapters: dict[str, AdapterDetails] = {}
|
|
||||||
adapter_details = await get_bluetooth_adapter_details()
|
|
||||||
for adapter, details in adapter_details.items():
|
|
||||||
adapter1 = details["org.bluez.Adapter1"]
|
|
||||||
adapters[adapter] = AdapterDetails(
|
|
||||||
address=adapter1["Address"],
|
|
||||||
sw_version=adapter1["Name"], # This is actually the BlueZ version
|
|
||||||
hw_version=adapter1.get("Modalias"),
|
|
||||||
passive_scan="org.bluez.AdvertisementMonitorManager1" in details,
|
|
||||||
)
|
|
||||||
return adapters
|
|
||||||
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def async_default_adapter() -> str:
|
|
||||||
"""Return the default adapter for the platform."""
|
|
||||||
return DEFAULT_ADAPTER_BY_PLATFORM.get(
|
|
||||||
platform.system(), UNIX_DEFAULT_BLUETOOTH_ADAPTER
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def adapter_human_name(adapter: str, address: str) -> str:
|
|
||||||
"""Return a human readable name for the adapter."""
|
|
||||||
return adapter if address == DEFAULT_ADDRESS else f"{adapter} ({address})"
|
|
||||||
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def adapter_unique_name(adapter: str, address: str) -> str:
|
|
||||||
"""Return a unique name for the adapter."""
|
|
||||||
return adapter if address == DEFAULT_ADDRESS else address
|
|
||||||
|
|
||||||
|
|
||||||
async def async_reset_adapter(adapter: str | None) -> bool | None:
|
async def async_reset_adapter(adapter: str | None) -> bool | None:
|
||||||
"""Reset the adapter."""
|
"""Reset the adapter."""
|
||||||
if adapter and adapter.startswith("hci"):
|
if adapter and adapter.startswith("hci"):
|
||||||
|
|
|
@ -12,7 +12,7 @@ awesomeversion==22.9.0
|
||||||
bcrypt==3.1.7
|
bcrypt==3.1.7
|
||||||
bleak-retry-connector==2.8.4
|
bleak-retry-connector==2.8.4
|
||||||
bleak==0.19.2
|
bleak==0.19.2
|
||||||
bluetooth-adapters==0.7.0
|
bluetooth-adapters==0.8.0
|
||||||
bluetooth-auto-recovery==0.4.0
|
bluetooth-auto-recovery==0.4.0
|
||||||
bluetooth-data-tools==0.3.0
|
bluetooth-data-tools==0.3.0
|
||||||
certifi>=2021.5.30
|
certifi>=2021.5.30
|
||||||
|
|
|
@ -447,7 +447,7 @@ bluemaestro-ble==0.2.0
|
||||||
# bluepy==1.3.0
|
# bluepy==1.3.0
|
||||||
|
|
||||||
# homeassistant.components.bluetooth
|
# homeassistant.components.bluetooth
|
||||||
bluetooth-adapters==0.7.0
|
bluetooth-adapters==0.8.0
|
||||||
|
|
||||||
# homeassistant.components.bluetooth
|
# homeassistant.components.bluetooth
|
||||||
bluetooth-auto-recovery==0.4.0
|
bluetooth-auto-recovery==0.4.0
|
||||||
|
|
|
@ -361,7 +361,7 @@ blinkpy==0.19.2
|
||||||
bluemaestro-ble==0.2.0
|
bluemaestro-ble==0.2.0
|
||||||
|
|
||||||
# homeassistant.components.bluetooth
|
# homeassistant.components.bluetooth
|
||||||
bluetooth-adapters==0.7.0
|
bluetooth-adapters==0.8.0
|
||||||
|
|
||||||
# homeassistant.components.bluetooth
|
# homeassistant.components.bluetooth
|
||||||
bluetooth-auto-recovery==0.4.0
|
bluetooth-auto-recovery==0.4.0
|
||||||
|
|
|
@ -6,6 +6,7 @@ from typing import Any
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from bleak.backends.scanner import AdvertisementData, BLEDevice
|
from bleak.backends.scanner import AdvertisementData, BLEDevice
|
||||||
|
from bluetooth_adapters import DEFAULT_ADDRESS
|
||||||
|
|
||||||
from homeassistant.components.bluetooth import (
|
from homeassistant.components.bluetooth import (
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
@ -13,7 +14,6 @@ from homeassistant.components.bluetooth import (
|
||||||
async_get_advertisement_callback,
|
async_get_advertisement_callback,
|
||||||
models,
|
models,
|
||||||
)
|
)
|
||||||
from homeassistant.components.bluetooth.const import DEFAULT_ADDRESS
|
|
||||||
from homeassistant.components.bluetooth.manager import BluetoothManager
|
from homeassistant.components.bluetooth.manager import BluetoothManager
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""Tests for the bluetooth component."""
|
"""Tests for the bluetooth component."""
|
||||||
|
|
||||||
from unittest.mock import AsyncMock, MagicMock, patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -43,16 +43,6 @@ def mock_operating_system_90():
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="bluez_dbus_mock")
|
|
||||||
def bluez_dbus_mock():
|
|
||||||
"""Fixture that mocks out the bluez dbus calls."""
|
|
||||||
# Must patch directly since this is loaded on demand only
|
|
||||||
with patch(
|
|
||||||
"bluetooth_adapters.BlueZDBusObjects", return_value=MagicMock(load=AsyncMock())
|
|
||||||
):
|
|
||||||
yield
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="macos_adapter")
|
@pytest.fixture(name="macos_adapter")
|
||||||
def macos_adapter():
|
def macos_adapter():
|
||||||
"""Fixture that mocks the macos adapter."""
|
"""Fixture that mocks the macos adapter."""
|
||||||
|
@ -62,7 +52,7 @@ def macos_adapter():
|
||||||
"homeassistant.components.bluetooth.scanner.platform.system",
|
"homeassistant.components.bluetooth.scanner.platform.system",
|
||||||
return_value="Darwin",
|
return_value="Darwin",
|
||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.bluetooth.util.platform.system", return_value="Darwin"
|
"bluetooth_adapters.systems.platform.system", return_value="Darwin"
|
||||||
):
|
):
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
@ -71,14 +61,14 @@ def macos_adapter():
|
||||||
def windows_adapter():
|
def windows_adapter():
|
||||||
"""Fixture that mocks the windows adapter."""
|
"""Fixture that mocks the windows adapter."""
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.bluetooth.util.platform.system",
|
"bluetooth_adapters.systems.platform.system",
|
||||||
return_value="Windows",
|
return_value="Windows",
|
||||||
):
|
):
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="no_adapters")
|
@pytest.fixture(name="no_adapters")
|
||||||
def no_adapter_fixture(bluez_dbus_mock):
|
def no_adapter_fixture():
|
||||||
"""Fixture that mocks no adapters on Linux."""
|
"""Fixture that mocks no adapters on Linux."""
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.bluetooth.platform.system", return_value="Linux"
|
"homeassistant.components.bluetooth.platform.system", return_value="Linux"
|
||||||
|
@ -86,16 +76,18 @@ def no_adapter_fixture(bluez_dbus_mock):
|
||||||
"homeassistant.components.bluetooth.scanner.platform.system",
|
"homeassistant.components.bluetooth.scanner.platform.system",
|
||||||
return_value="Linux",
|
return_value="Linux",
|
||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.bluetooth.util.platform.system", return_value="Linux"
|
"bluetooth_adapters.systems.platform.system", return_value="Linux"
|
||||||
), patch(
|
), patch(
|
||||||
"bluetooth_adapters.get_bluetooth_adapter_details",
|
"bluetooth_adapters.systems.linux.LinuxAdapters.refresh"
|
||||||
return_value={},
|
), patch(
|
||||||
|
"bluetooth_adapters.systems.linux.LinuxAdapters.adapters",
|
||||||
|
{},
|
||||||
):
|
):
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="one_adapter")
|
@pytest.fixture(name="one_adapter")
|
||||||
def one_adapter_fixture(bluez_dbus_mock):
|
def one_adapter_fixture():
|
||||||
"""Fixture that mocks one adapter on Linux."""
|
"""Fixture that mocks one adapter on Linux."""
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.bluetooth.platform.system", return_value="Linux"
|
"homeassistant.components.bluetooth.platform.system", return_value="Linux"
|
||||||
|
@ -103,20 +95,17 @@ def one_adapter_fixture(bluez_dbus_mock):
|
||||||
"homeassistant.components.bluetooth.scanner.platform.system",
|
"homeassistant.components.bluetooth.scanner.platform.system",
|
||||||
return_value="Linux",
|
return_value="Linux",
|
||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.bluetooth.util.platform.system", return_value="Linux"
|
"bluetooth_adapters.systems.platform.system", return_value="Linux"
|
||||||
), patch(
|
), patch(
|
||||||
"bluetooth_adapters.get_bluetooth_adapter_details",
|
"bluetooth_adapters.systems.linux.LinuxAdapters.refresh"
|
||||||
return_value={
|
), patch(
|
||||||
|
"bluetooth_adapters.systems.linux.LinuxAdapters.adapters",
|
||||||
|
{
|
||||||
"hci0": {
|
"hci0": {
|
||||||
"org.bluez.Adapter1": {
|
"address": "00:00:00:00:00:01",
|
||||||
"Address": "00:00:00:00:00:01",
|
"hw_version": "usb:v1D6Bp0246d053F",
|
||||||
"Name": "BlueZ 4.63",
|
"passive_scan": True,
|
||||||
"Modalias": "usbid:1234",
|
"sw_version": "homeassistant",
|
||||||
},
|
|
||||||
"org.bluez.AdvertisementMonitorManager1": {
|
|
||||||
"SupportedMonitorTypes": ["or_patterns"],
|
|
||||||
"SupportedFeatures": [],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
):
|
):
|
||||||
|
@ -124,7 +113,7 @@ def one_adapter_fixture(bluez_dbus_mock):
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="two_adapters")
|
@pytest.fixture(name="two_adapters")
|
||||||
def two_adapters_fixture(bluez_dbus_mock):
|
def two_adapters_fixture():
|
||||||
"""Fixture that mocks two adapters on Linux."""
|
"""Fixture that mocks two adapters on Linux."""
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.bluetooth.platform.system", return_value="Linux"
|
"homeassistant.components.bluetooth.platform.system", return_value="Linux"
|
||||||
|
@ -132,27 +121,23 @@ def two_adapters_fixture(bluez_dbus_mock):
|
||||||
"homeassistant.components.bluetooth.scanner.platform.system",
|
"homeassistant.components.bluetooth.scanner.platform.system",
|
||||||
return_value="Linux",
|
return_value="Linux",
|
||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.bluetooth.util.platform.system", return_value="Linux"
|
"bluetooth_adapters.systems.platform.system", return_value="Linux"
|
||||||
), patch(
|
), patch(
|
||||||
"bluetooth_adapters.get_bluetooth_adapter_details",
|
"bluetooth_adapters.systems.linux.LinuxAdapters.refresh"
|
||||||
return_value={
|
), patch(
|
||||||
|
"bluetooth_adapters.systems.linux.LinuxAdapters.adapters",
|
||||||
|
{
|
||||||
"hci0": {
|
"hci0": {
|
||||||
"org.bluez.Adapter1": {
|
"address": "00:00:00:00:00:01",
|
||||||
"Address": "00:00:00:00:00:01",
|
"hw_version": "usb:v1D6Bp0246d053F",
|
||||||
"Name": "BlueZ 4.63",
|
"passive_scan": False,
|
||||||
"Modalias": "usbid:1234",
|
"sw_version": "homeassistant",
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"hci1": {
|
"hci1": {
|
||||||
"org.bluez.Adapter1": {
|
"address": "00:00:00:00:00:02",
|
||||||
"Address": "00:00:00:00:00:02",
|
"hw_version": "usb:v1D6Bp0246d053F",
|
||||||
"Name": "BlueZ 4.63",
|
"passive_scan": True,
|
||||||
"Modalias": "usbid:1234",
|
"sw_version": "homeassistant",
|
||||||
},
|
|
||||||
"org.bluez.AdvertisementMonitorManager1": {
|
|
||||||
"SupportedMonitorTypes": ["or_patterns"],
|
|
||||||
"SupportedFeatures": [],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
):
|
):
|
||||||
|
@ -160,7 +145,7 @@ def two_adapters_fixture(bluez_dbus_mock):
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="one_adapter_old_bluez")
|
@pytest.fixture(name="one_adapter_old_bluez")
|
||||||
def one_adapter_old_bluez(bluez_dbus_mock):
|
def one_adapter_old_bluez():
|
||||||
"""Fixture that mocks two adapters on Linux."""
|
"""Fixture that mocks two adapters on Linux."""
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.bluetooth.platform.system", return_value="Linux"
|
"homeassistant.components.bluetooth.platform.system", return_value="Linux"
|
||||||
|
@ -168,15 +153,17 @@ def one_adapter_old_bluez(bluez_dbus_mock):
|
||||||
"homeassistant.components.bluetooth.scanner.platform.system",
|
"homeassistant.components.bluetooth.scanner.platform.system",
|
||||||
return_value="Linux",
|
return_value="Linux",
|
||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.bluetooth.util.platform.system", return_value="Linux"
|
"bluetooth_adapters.systems.platform.system", return_value="Linux"
|
||||||
), patch(
|
), patch(
|
||||||
"bluetooth_adapters.get_bluetooth_adapter_details",
|
"bluetooth_adapters.systems.linux.LinuxAdapters.refresh"
|
||||||
return_value={
|
), patch(
|
||||||
|
"bluetooth_adapters.systems.linux.LinuxAdapters.adapters",
|
||||||
|
{
|
||||||
"hci0": {
|
"hci0": {
|
||||||
"org.bluez.Adapter1": {
|
"address": "00:00:00:00:00:01",
|
||||||
"Address": "00:00:00:00:00:01",
|
"hw_version": "usb:v1D6Bp0246d053F",
|
||||||
"Name": "BlueZ 4.43",
|
"passive_scan": False,
|
||||||
}
|
"sw_version": "homeassistant",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
):
|
):
|
||||||
|
|
|
@ -2,14 +2,14 @@
|
||||||
|
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from bluetooth_adapters import DEFAULT_ADDRESS, AdapterDetails
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.components.bluetooth.const import (
|
from homeassistant.components.bluetooth.const import (
|
||||||
CONF_ADAPTER,
|
CONF_ADAPTER,
|
||||||
CONF_DETAILS,
|
CONF_DETAILS,
|
||||||
CONF_PASSIVE,
|
CONF_PASSIVE,
|
||||||
DEFAULT_ADDRESS,
|
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
AdapterDetails,
|
|
||||||
)
|
)
|
||||||
from homeassistant.data_entry_flow import FlowResultType
|
from homeassistant.data_entry_flow import FlowResultType
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
from unittest.mock import ANY, patch
|
from unittest.mock import ANY, patch
|
||||||
|
|
||||||
from bleak.backends.scanner import BLEDevice
|
from bleak.backends.scanner import BLEDevice
|
||||||
|
from bluetooth_adapters import DEFAULT_ADDRESS
|
||||||
|
|
||||||
from homeassistant.components import bluetooth
|
from homeassistant.components import bluetooth
|
||||||
from homeassistant.components.bluetooth.const import DEFAULT_ADDRESS
|
|
||||||
|
|
||||||
from . import generate_advertisement_data, inject_advertisement
|
from . import generate_advertisement_data, inject_advertisement
|
||||||
|
|
||||||
|
@ -68,15 +68,15 @@ async def test_diagnostics(
|
||||||
"adapters": {
|
"adapters": {
|
||||||
"hci0": {
|
"hci0": {
|
||||||
"address": "00:00:00:00:00:01",
|
"address": "00:00:00:00:00:01",
|
||||||
"hw_version": "usbid:1234",
|
"hw_version": "usb:v1D6Bp0246d053F",
|
||||||
"passive_scan": False,
|
"passive_scan": False,
|
||||||
"sw_version": "BlueZ 4.63",
|
"sw_version": "homeassistant",
|
||||||
},
|
},
|
||||||
"hci1": {
|
"hci1": {
|
||||||
"address": "00:00:00:00:00:02",
|
"address": "00:00:00:00:00:02",
|
||||||
"hw_version": "usbid:1234",
|
"hw_version": "usb:v1D6Bp0246d053F",
|
||||||
"passive_scan": True,
|
"passive_scan": True,
|
||||||
"sw_version": "BlueZ 4.63",
|
"sw_version": "homeassistant",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"dbus": {
|
"dbus": {
|
||||||
|
@ -99,15 +99,15 @@ async def test_diagnostics(
|
||||||
"adapters": {
|
"adapters": {
|
||||||
"hci0": {
|
"hci0": {
|
||||||
"address": "00:00:00:00:00:01",
|
"address": "00:00:00:00:00:01",
|
||||||
"hw_version": "usbid:1234",
|
"hw_version": "usb:v1D6Bp0246d053F",
|
||||||
"passive_scan": False,
|
"passive_scan": False,
|
||||||
"sw_version": "BlueZ 4.63",
|
"sw_version": "homeassistant",
|
||||||
},
|
},
|
||||||
"hci1": {
|
"hci1": {
|
||||||
"address": "00:00:00:00:00:02",
|
"address": "00:00:00:00:00:02",
|
||||||
"hw_version": "usbid:1234",
|
"hw_version": "usb:v1D6Bp0246d053F",
|
||||||
"passive_scan": True,
|
"passive_scan": True,
|
||||||
"sw_version": "BlueZ 4.63",
|
"sw_version": "homeassistant",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"advertisement_tracker": {
|
"advertisement_tracker": {
|
||||||
|
|
|
@ -6,6 +6,7 @@ from unittest.mock import ANY, MagicMock, Mock, patch
|
||||||
|
|
||||||
from bleak import BleakError
|
from bleak import BleakError
|
||||||
from bleak.backends.scanner import AdvertisementData, BLEDevice
|
from bleak.backends.scanner import AdvertisementData, BLEDevice
|
||||||
|
from bluetooth_adapters import DEFAULT_ADDRESS
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components import bluetooth
|
from homeassistant.components import bluetooth
|
||||||
|
@ -22,7 +23,6 @@ from homeassistant.components.bluetooth import (
|
||||||
from homeassistant.components.bluetooth.const import (
|
from homeassistant.components.bluetooth.const import (
|
||||||
BLUETOOTH_DISCOVERY_COOLDOWN_SECONDS,
|
BLUETOOTH_DISCOVERY_COOLDOWN_SECONDS,
|
||||||
CONF_PASSIVE,
|
CONF_PASSIVE,
|
||||||
DEFAULT_ADDRESS,
|
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
LINUX_FIRMWARE_LOAD_FALLBACK_SECONDS,
|
LINUX_FIRMWARE_LOAD_FALLBACK_SECONDS,
|
||||||
SOURCE_LOCAL,
|
SOURCE_LOCAL,
|
||||||
|
@ -2522,7 +2522,7 @@ async def test_async_ble_device_from_address(
|
||||||
|
|
||||||
|
|
||||||
async def test_can_unsetup_bluetooth_single_adapter_macos(
|
async def test_can_unsetup_bluetooth_single_adapter_macos(
|
||||||
hass, mock_bleak_scanner_start, enable_bluetooth, macos_adapter
|
hass, mock_bleak_scanner_start, macos_adapter
|
||||||
):
|
):
|
||||||
"""Test we can setup and unsetup bluetooth."""
|
"""Test we can setup and unsetup bluetooth."""
|
||||||
entry = MockConfigEntry(domain=bluetooth.DOMAIN, data={}, unique_id=DEFAULT_ADDRESS)
|
entry = MockConfigEntry(domain=bluetooth.DOMAIN, data={}, unique_id=DEFAULT_ADDRESS)
|
||||||
|
@ -2605,12 +2605,13 @@ async def test_auto_detect_bluetooth_adapters_linux_multiple(hass, two_adapters)
|
||||||
assert len(hass.config_entries.flow.async_progress(bluetooth.DOMAIN)) == 2
|
assert len(hass.config_entries.flow.async_progress(bluetooth.DOMAIN)) == 2
|
||||||
|
|
||||||
|
|
||||||
async def test_auto_detect_bluetooth_adapters_linux_none_found(hass, bluez_dbus_mock):
|
async def test_auto_detect_bluetooth_adapters_linux_none_found(hass):
|
||||||
"""Test we auto detect bluetooth adapters on linux with no adapters found."""
|
"""Test we auto detect bluetooth adapters on linux with no adapters found."""
|
||||||
with patch(
|
with patch(
|
||||||
"bluetooth_adapters.get_bluetooth_adapter_details", return_value={}
|
"bluetooth_adapters.systems.platform.system", return_value="Linux"
|
||||||
), patch(
|
), patch("bluetooth_adapters.systems.linux.LinuxAdapters.refresh"), patch(
|
||||||
"homeassistant.components.bluetooth.util.platform.system", return_value="Linux"
|
"bluetooth_adapters.systems.linux.LinuxAdapters.adapters",
|
||||||
|
{},
|
||||||
):
|
):
|
||||||
assert await async_setup_component(hass, bluetooth.DOMAIN, {})
|
assert await async_setup_component(hass, bluetooth.DOMAIN, {})
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
@ -2620,9 +2621,7 @@ async def test_auto_detect_bluetooth_adapters_linux_none_found(hass, bluez_dbus_
|
||||||
|
|
||||||
async def test_auto_detect_bluetooth_adapters_macos(hass):
|
async def test_auto_detect_bluetooth_adapters_macos(hass):
|
||||||
"""Test we auto detect bluetooth adapters on macos."""
|
"""Test we auto detect bluetooth adapters on macos."""
|
||||||
with patch(
|
with patch("bluetooth_adapters.systems.platform.system", return_value="Darwin"):
|
||||||
"homeassistant.components.bluetooth.util.platform.system", return_value="Darwin"
|
|
||||||
):
|
|
||||||
assert await async_setup_component(hass, bluetooth.DOMAIN, {})
|
assert await async_setup_component(hass, bluetooth.DOMAIN, {})
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert not hass.config_entries.async_entries(bluetooth.DOMAIN)
|
assert not hass.config_entries.async_entries(bluetooth.DOMAIN)
|
||||||
|
@ -2632,7 +2631,7 @@ async def test_auto_detect_bluetooth_adapters_macos(hass):
|
||||||
async def test_no_auto_detect_bluetooth_adapters_windows(hass):
|
async def test_no_auto_detect_bluetooth_adapters_windows(hass):
|
||||||
"""Test we auto detect bluetooth adapters on windows."""
|
"""Test we auto detect bluetooth adapters on windows."""
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.bluetooth.util.platform.system",
|
"bluetooth_adapters.systems.platform.system",
|
||||||
return_value="Windows",
|
return_value="Windows",
|
||||||
):
|
):
|
||||||
assert await async_setup_component(hass, bluetooth.DOMAIN, {})
|
assert await async_setup_component(hass, bluetooth.DOMAIN, {})
|
||||||
|
@ -2710,23 +2709,21 @@ async def test_discover_new_usb_adapters(hass, mock_bleak_scanner_start, one_ada
|
||||||
assert not hass.config_entries.flow.async_progress(DOMAIN)
|
assert not hass.config_entries.flow.async_progress(DOMAIN)
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.bluetooth.util.platform.system", return_value="Linux"
|
"bluetooth_adapters.systems.platform.system", return_value="Linux"
|
||||||
), patch(
|
), patch("bluetooth_adapters.systems.linux.LinuxAdapters.refresh"), patch(
|
||||||
"bluetooth_adapters.get_bluetooth_adapter_details",
|
"bluetooth_adapters.systems.linux.LinuxAdapters.adapters",
|
||||||
return_value={
|
{
|
||||||
"hci0": {
|
"hci0": {
|
||||||
"org.bluez.Adapter1": {
|
"address": "00:00:00:00:00:01",
|
||||||
"Address": "00:00:00:00:00:01",
|
"hw_version": "usb:v1D6Bp0246d053F",
|
||||||
"Name": "BlueZ 4.63",
|
"passive_scan": False,
|
||||||
"Modalias": "usbid:1234",
|
"sw_version": "homeassistant",
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"hci1": {
|
"hci1": {
|
||||||
"org.bluez.Adapter1": {
|
"address": "00:00:00:00:00:02",
|
||||||
"Address": "00:00:00:00:00:02",
|
"hw_version": "usb:v1D6Bp0246d053F",
|
||||||
"Name": "BlueZ 4.63",
|
"passive_scan": False,
|
||||||
"Modalias": "usbid:1234",
|
"sw_version": "homeassistant",
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
):
|
):
|
||||||
|
@ -2768,10 +2765,10 @@ async def test_discover_new_usb_adapters_with_firmware_fallback_delay(
|
||||||
assert not hass.config_entries.flow.async_progress(DOMAIN)
|
assert not hass.config_entries.flow.async_progress(DOMAIN)
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.bluetooth.util.platform.system", return_value="Linux"
|
"bluetooth_adapters.systems.platform.system", return_value="Linux"
|
||||||
), patch(
|
), patch("bluetooth_adapters.systems.linux.LinuxAdapters.refresh"), patch(
|
||||||
"bluetooth_adapters.get_bluetooth_adapter_details",
|
"bluetooth_adapters.systems.linux.LinuxAdapters.adapters",
|
||||||
return_value={},
|
{},
|
||||||
):
|
):
|
||||||
async_fire_time_changed(
|
async_fire_time_changed(
|
||||||
hass, dt_util.utcnow() + timedelta(BLUETOOTH_DISCOVERY_COOLDOWN_SECONDS * 2)
|
hass, dt_util.utcnow() + timedelta(BLUETOOTH_DISCOVERY_COOLDOWN_SECONDS * 2)
|
||||||
|
@ -2781,23 +2778,21 @@ async def test_discover_new_usb_adapters_with_firmware_fallback_delay(
|
||||||
assert len(hass.config_entries.flow.async_progress(DOMAIN)) == 0
|
assert len(hass.config_entries.flow.async_progress(DOMAIN)) == 0
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.bluetooth.util.platform.system", return_value="Linux"
|
"bluetooth_adapters.systems.platform.system", return_value="Linux"
|
||||||
), patch(
|
), patch("bluetooth_adapters.systems.linux.LinuxAdapters.refresh"), patch(
|
||||||
"bluetooth_adapters.get_bluetooth_adapter_details",
|
"bluetooth_adapters.systems.linux.LinuxAdapters.adapters",
|
||||||
return_value={
|
{
|
||||||
"hci0": {
|
"hci0": {
|
||||||
"org.bluez.Adapter1": {
|
"address": "00:00:00:00:00:01",
|
||||||
"Address": "00:00:00:00:00:01",
|
"hw_version": "usb:v1D6Bp0246d053F",
|
||||||
"Name": "BlueZ 4.63",
|
"passive_scan": False,
|
||||||
"Modalias": "usbid:1234",
|
"sw_version": "homeassistant",
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"hci1": {
|
"hci1": {
|
||||||
"org.bluez.Adapter1": {
|
"address": "00:00:00:00:00:02",
|
||||||
"Address": "00:00:00:00:00:02",
|
"hw_version": "usb:v1D6Bp0246d053F",
|
||||||
"Name": "BlueZ 4.63",
|
"passive_scan": False,
|
||||||
"Modalias": "usbid:1234",
|
"sw_version": "homeassistant",
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
):
|
):
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""Tests for the Bluetooth integration manager."""
|
"""Tests for the Bluetooth integration manager."""
|
||||||
|
|
||||||
import time
|
import time
|
||||||
from unittest.mock import AsyncMock, MagicMock, patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from bleak.backends.scanner import BLEDevice
|
from bleak.backends.scanner import BLEDevice
|
||||||
from bluetooth_adapters import AdvertisementHistory
|
from bluetooth_adapters import AdvertisementHistory
|
||||||
|
@ -275,8 +275,8 @@ async def test_restore_history_from_dbus(hass, one_adapter):
|
||||||
}
|
}
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"bluetooth_adapters.BlueZDBusObjects",
|
"bluetooth_adapters.systems.linux.LinuxAdapters.history",
|
||||||
return_value=MagicMock(load=AsyncMock(), history=history),
|
history,
|
||||||
):
|
):
|
||||||
assert await async_setup_component(hass, bluetooth.DOMAIN, {})
|
assert await async_setup_component(hass, bluetooth.DOMAIN, {})
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
|
@ -1041,18 +1041,15 @@ async def mock_enable_bluetooth(
|
||||||
def mock_bluetooth_adapters():
|
def mock_bluetooth_adapters():
|
||||||
"""Fixture to mock bluetooth adapters."""
|
"""Fixture to mock bluetooth adapters."""
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.bluetooth.util.platform.system", return_value="Linux"
|
"bluetooth_adapters.systems.platform.system", return_value="Linux"
|
||||||
), patch(
|
), patch("bluetooth_adapters.systems.linux.LinuxAdapters.refresh"), patch(
|
||||||
"bluetooth_adapters.BlueZDBusObjects", return_value=MagicMock(load=AsyncMock())
|
"bluetooth_adapters.systems.linux.LinuxAdapters.adapters",
|
||||||
), patch(
|
{
|
||||||
"bluetooth_adapters.get_bluetooth_adapter_details",
|
|
||||||
return_value={
|
|
||||||
"hci0": {
|
"hci0": {
|
||||||
"org.bluez.Adapter1": {
|
"address": "00:00:00:00:00:01",
|
||||||
"Address": "00:00:00:00:00:01",
|
"hw_version": "usb:v1D6Bp0246d053F",
|
||||||
"Name": "BlueZ 4.63",
|
"passive_scan": False,
|
||||||
"Modalias": "usbid:1234",
|
"sw_version": "homeassistant",
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
):
|
):
|
||||||
|
|
Loading…
Reference in New Issue