mirror of
https://github.com/home-assistant/core.git
synced 2025-11-09 10:59:40 +00:00
Add async_current_scanners API to Bluetooth integration
This commit is contained in:
@@ -57,6 +57,7 @@ from .api import (
|
|||||||
_get_manager,
|
_get_manager,
|
||||||
async_address_present,
|
async_address_present,
|
||||||
async_ble_device_from_address,
|
async_ble_device_from_address,
|
||||||
|
async_current_scanners,
|
||||||
async_discovered_service_info,
|
async_discovered_service_info,
|
||||||
async_get_advertisement_callback,
|
async_get_advertisement_callback,
|
||||||
async_get_fallback_availability_interval,
|
async_get_fallback_availability_interval,
|
||||||
@@ -114,6 +115,7 @@ __all__ = [
|
|||||||
"HomeAssistantRemoteScanner",
|
"HomeAssistantRemoteScanner",
|
||||||
"async_address_present",
|
"async_address_present",
|
||||||
"async_ble_device_from_address",
|
"async_ble_device_from_address",
|
||||||
|
"async_current_scanners",
|
||||||
"async_discovered_service_info",
|
"async_discovered_service_info",
|
||||||
"async_get_advertisement_callback",
|
"async_get_advertisement_callback",
|
||||||
"async_get_fallback_availability_interval",
|
"async_get_fallback_availability_interval",
|
||||||
|
|||||||
@@ -66,6 +66,22 @@ def async_scanner_count(hass: HomeAssistant, connectable: bool = True) -> int:
|
|||||||
return _get_manager(hass).async_scanner_count(connectable)
|
return _get_manager(hass).async_scanner_count(connectable)
|
||||||
|
|
||||||
|
|
||||||
|
@hass_callback
|
||||||
|
def async_current_scanners(hass: HomeAssistant) -> list[BaseHaScanner]:
|
||||||
|
"""Return the list of currently active scanners.
|
||||||
|
|
||||||
|
This method returns a list of all active Bluetooth scanners registered
|
||||||
|
with Home Assistant, including both connectable and non-connectable scanners.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
hass: Home Assistant instance
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List of all active scanner instances
|
||||||
|
"""
|
||||||
|
return _get_manager(hass).async_current_scanners()
|
||||||
|
|
||||||
|
|
||||||
@hass_callback
|
@hass_callback
|
||||||
def async_discovered_service_info(
|
def async_discovered_service_info(
|
||||||
hass: HomeAssistant, connectable: bool = True
|
hass: HomeAssistant, connectable: bool = True
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|||||||
import logging
|
import logging
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
from habluetooth import BluetoothScanningMode
|
||||||
from switchbot import (
|
from switchbot import (
|
||||||
SwitchbotAccountConnectionError,
|
SwitchbotAccountConnectionError,
|
||||||
SwitchBotAdvertisement,
|
SwitchBotAdvertisement,
|
||||||
@@ -18,6 +19,7 @@ import voluptuous as vol
|
|||||||
|
|
||||||
from homeassistant.components.bluetooth import (
|
from homeassistant.components.bluetooth import (
|
||||||
BluetoothServiceInfoBleak,
|
BluetoothServiceInfoBleak,
|
||||||
|
async_current_scanners,
|
||||||
async_discovered_service_info,
|
async_discovered_service_info,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import (
|
from homeassistant.config_entries import (
|
||||||
@@ -323,6 +325,15 @@ class SwitchbotConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
self, user_input: dict[str, Any] | None = None
|
self, user_input: dict[str, Any] | None = None
|
||||||
) -> ConfigFlowResult:
|
) -> ConfigFlowResult:
|
||||||
"""Handle the user step to choose cloud login or direct discovery."""
|
"""Handle the user step to choose cloud login or direct discovery."""
|
||||||
|
# Check if all scanners are in active mode
|
||||||
|
# If so, skip the menu and go directly to device selection
|
||||||
|
scanners = async_current_scanners(self.hass)
|
||||||
|
if scanners and all(
|
||||||
|
scanner.current_mode == BluetoothScanningMode.ACTIVE for scanner in scanners
|
||||||
|
):
|
||||||
|
# All scanners are active, skip the menu
|
||||||
|
return await self.async_step_select_device()
|
||||||
|
|
||||||
return self.async_show_menu(
|
return self.async_show_menu(
|
||||||
step_id="user",
|
step_id="user",
|
||||||
menu_options=["cloud_login", "select_device"],
|
menu_options=["cloud_login", "select_device"],
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from homeassistant.components import bluetooth
|
|||||||
from homeassistant.components.bluetooth import (
|
from homeassistant.components.bluetooth import (
|
||||||
MONOTONIC_TIME,
|
MONOTONIC_TIME,
|
||||||
BaseHaRemoteScanner,
|
BaseHaRemoteScanner,
|
||||||
|
BluetoothScanningMode,
|
||||||
HaBluetoothConnector,
|
HaBluetoothConnector,
|
||||||
async_scanner_by_source,
|
async_scanner_by_source,
|
||||||
async_scanner_devices_by_address,
|
async_scanner_devices_by_address,
|
||||||
@@ -16,6 +17,7 @@ from homeassistant.components.bluetooth import (
|
|||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from . import (
|
from . import (
|
||||||
|
FakeRemoteScanner,
|
||||||
FakeScanner,
|
FakeScanner,
|
||||||
MockBleakClient,
|
MockBleakClient,
|
||||||
_get_manager,
|
_get_manager,
|
||||||
@@ -161,3 +163,68 @@ async def test_async_scanner_devices_by_address_non_connectable(
|
|||||||
assert devices[0].ble_device.name == switchbot_device.name
|
assert devices[0].ble_device.name == switchbot_device.name
|
||||||
assert devices[0].advertisement.local_name == switchbot_device_adv.local_name
|
assert devices[0].advertisement.local_name == switchbot_device_adv.local_name
|
||||||
cancel()
|
cancel()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("enable_bluetooth")
|
||||||
|
async def test_async_current_scanners(hass: HomeAssistant) -> None:
|
||||||
|
"""Test getting the list of current scanners."""
|
||||||
|
# The enable_bluetooth fixture registers one scanner
|
||||||
|
initial_scanners = bluetooth.async_current_scanners(hass)
|
||||||
|
assert len(initial_scanners) == 1
|
||||||
|
initial_scanner_count = len(initial_scanners)
|
||||||
|
|
||||||
|
# Verify current_mode is accessible on the initial scanner
|
||||||
|
for scanner in initial_scanners:
|
||||||
|
assert hasattr(scanner, "current_mode")
|
||||||
|
# The mode might be None or a BluetoothScanningMode enum value
|
||||||
|
|
||||||
|
# Register additional connectable scanners
|
||||||
|
hci0_scanner = FakeScanner("hci0", "hci0")
|
||||||
|
hci1_scanner = FakeScanner("hci1", "hci1")
|
||||||
|
cancel_hci0 = bluetooth.async_register_scanner(hass, hci0_scanner)
|
||||||
|
cancel_hci1 = bluetooth.async_register_scanner(hass, hci1_scanner)
|
||||||
|
|
||||||
|
# Test that the new scanners are added
|
||||||
|
scanners = bluetooth.async_current_scanners(hass)
|
||||||
|
assert len(scanners) == initial_scanner_count + 2
|
||||||
|
assert hci0_scanner in scanners
|
||||||
|
assert hci1_scanner in scanners
|
||||||
|
|
||||||
|
# Verify current_mode is accessible on all scanners
|
||||||
|
for scanner in scanners:
|
||||||
|
assert hasattr(scanner, "current_mode")
|
||||||
|
# Verify it's None or the correct type (BluetoothScanningMode)
|
||||||
|
assert scanner.current_mode is None or isinstance(
|
||||||
|
scanner.current_mode, BluetoothScanningMode
|
||||||
|
)
|
||||||
|
|
||||||
|
# Register non-connectable scanner
|
||||||
|
connector = HaBluetoothConnector(
|
||||||
|
MockBleakClient, "mock_bleak_client", lambda: False
|
||||||
|
)
|
||||||
|
hci2_scanner = FakeRemoteScanner("hci2", "hci2", connector, False)
|
||||||
|
cancel_hci2 = bluetooth.async_register_scanner(hass, hci2_scanner)
|
||||||
|
|
||||||
|
# Test that all scanners are returned (both connectable and non-connectable)
|
||||||
|
all_scanners = bluetooth.async_current_scanners(hass)
|
||||||
|
assert len(all_scanners) == initial_scanner_count + 3
|
||||||
|
assert hci0_scanner in all_scanners
|
||||||
|
assert hci1_scanner in all_scanners
|
||||||
|
assert hci2_scanner in all_scanners
|
||||||
|
|
||||||
|
# Verify current_mode is accessible on all scanners including non-connectable
|
||||||
|
for scanner in all_scanners:
|
||||||
|
assert hasattr(scanner, "current_mode")
|
||||||
|
# The mode should be None or a BluetoothScanningMode instance
|
||||||
|
assert scanner.current_mode is None or isinstance(
|
||||||
|
scanner.current_mode, BluetoothScanningMode
|
||||||
|
)
|
||||||
|
|
||||||
|
# Clean up our scanners
|
||||||
|
cancel_hci0()
|
||||||
|
cancel_hci1()
|
||||||
|
cancel_hci2()
|
||||||
|
|
||||||
|
# Verify we're back to the initial scanner
|
||||||
|
final_scanners = bluetooth.async_current_scanners(hass)
|
||||||
|
assert len(final_scanners) == initial_scanner_count
|
||||||
|
|||||||
Reference in New Issue
Block a user