Skip to content

Commit 596a3fc

Browse files
authored
Add async_current_scanners API to Bluetooth integration (home-assistant#152122)
1 parent 0e82956 commit 596a3fc

File tree

3 files changed

+85
-0
lines changed

3 files changed

+85
-0
lines changed

homeassistant/components/bluetooth/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
_get_manager,
5858
async_address_present,
5959
async_ble_device_from_address,
60+
async_current_scanners,
6061
async_discovered_service_info,
6162
async_get_advertisement_callback,
6263
async_get_fallback_availability_interval,
@@ -114,6 +115,7 @@
114115
"HomeAssistantRemoteScanner",
115116
"async_address_present",
116117
"async_ble_device_from_address",
118+
"async_current_scanners",
117119
"async_discovered_service_info",
118120
"async_get_advertisement_callback",
119121
"async_get_fallback_availability_interval",

homeassistant/components/bluetooth/api.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,22 @@ def async_scanner_count(hass: HomeAssistant, connectable: bool = True) -> int:
6666
return _get_manager(hass).async_scanner_count(connectable)
6767

6868

69+
@hass_callback
70+
def async_current_scanners(hass: HomeAssistant) -> list[BaseHaScanner]:
71+
"""Return the list of currently active scanners.
72+
73+
This method returns a list of all active Bluetooth scanners registered
74+
with Home Assistant, including both connectable and non-connectable scanners.
75+
76+
Args:
77+
hass: Home Assistant instance
78+
79+
Returns:
80+
List of all active scanner instances
81+
"""
82+
return _get_manager(hass).async_current_scanners()
83+
84+
6985
@hass_callback
7086
def async_discovered_service_info(
7187
hass: HomeAssistant, connectable: bool = True

tests/components/bluetooth/test_api.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@
99
from homeassistant.components.bluetooth import (
1010
MONOTONIC_TIME,
1111
BaseHaRemoteScanner,
12+
BluetoothScanningMode,
1213
HaBluetoothConnector,
1314
async_scanner_by_source,
1415
async_scanner_devices_by_address,
1516
)
1617
from homeassistant.core import HomeAssistant
1718

1819
from . import (
20+
FakeRemoteScanner,
1921
FakeScanner,
2022
MockBleakClient,
2123
_get_manager,
@@ -161,3 +163,68 @@ def discovered_devices_and_advertisement_data(
161163
assert devices[0].ble_device.name == switchbot_device.name
162164
assert devices[0].advertisement.local_name == switchbot_device_adv.local_name
163165
cancel()
166+
167+
168+
@pytest.mark.usefixtures("enable_bluetooth")
169+
async def test_async_current_scanners(hass: HomeAssistant) -> None:
170+
"""Test getting the list of current scanners."""
171+
# The enable_bluetooth fixture registers one scanner
172+
initial_scanners = bluetooth.async_current_scanners(hass)
173+
assert len(initial_scanners) == 1
174+
initial_scanner_count = len(initial_scanners)
175+
176+
# Verify current_mode is accessible on the initial scanner
177+
for scanner in initial_scanners:
178+
assert hasattr(scanner, "current_mode")
179+
# The mode might be None or a BluetoothScanningMode enum value
180+
181+
# Register additional connectable scanners
182+
hci0_scanner = FakeScanner("hci0", "hci0")
183+
hci1_scanner = FakeScanner("hci1", "hci1")
184+
cancel_hci0 = bluetooth.async_register_scanner(hass, hci0_scanner)
185+
cancel_hci1 = bluetooth.async_register_scanner(hass, hci1_scanner)
186+
187+
# Test that the new scanners are added
188+
scanners = bluetooth.async_current_scanners(hass)
189+
assert len(scanners) == initial_scanner_count + 2
190+
assert hci0_scanner in scanners
191+
assert hci1_scanner in scanners
192+
193+
# Verify current_mode is accessible on all scanners
194+
for scanner in scanners:
195+
assert hasattr(scanner, "current_mode")
196+
# Verify it's None or the correct type (BluetoothScanningMode)
197+
assert scanner.current_mode is None or isinstance(
198+
scanner.current_mode, BluetoothScanningMode
199+
)
200+
201+
# Register non-connectable scanner
202+
connector = HaBluetoothConnector(
203+
MockBleakClient, "mock_bleak_client", lambda: False
204+
)
205+
hci2_scanner = FakeRemoteScanner("hci2", "hci2", connector, False)
206+
cancel_hci2 = bluetooth.async_register_scanner(hass, hci2_scanner)
207+
208+
# Test that all scanners are returned (both connectable and non-connectable)
209+
all_scanners = bluetooth.async_current_scanners(hass)
210+
assert len(all_scanners) == initial_scanner_count + 3
211+
assert hci0_scanner in all_scanners
212+
assert hci1_scanner in all_scanners
213+
assert hci2_scanner in all_scanners
214+
215+
# Verify current_mode is accessible on all scanners including non-connectable
216+
for scanner in all_scanners:
217+
assert hasattr(scanner, "current_mode")
218+
# The mode should be None or a BluetoothScanningMode instance
219+
assert scanner.current_mode is None or isinstance(
220+
scanner.current_mode, BluetoothScanningMode
221+
)
222+
223+
# Clean up our scanners
224+
cancel_hci0()
225+
cancel_hci1()
226+
cancel_hci2()
227+
228+
# Verify we're back to the initial scanner
229+
final_scanners = bluetooth.async_current_scanners(hass)
230+
assert len(final_scanners) == initial_scanner_count

0 commit comments

Comments
 (0)