From 40e8979951f8e9bca9d153349642f95bacc8d0da Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 29 Aug 2022 09:21:30 -0500 Subject: [PATCH] Add bluetooth api to get the count of connectable and non-connectable scanners (#77427) --- homeassistant/components/bluetooth/__init__.py | 7 +++++++ homeassistant/components/bluetooth/manager.py | 16 +++++++++++++--- tests/components/bluetooth/test_init.py | 16 ++++++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/bluetooth/__init__.py b/homeassistant/components/bluetooth/__init__.py index 632635f7dbc..8ba3a503a30 100644 --- a/homeassistant/components/bluetooth/__init__.py +++ b/homeassistant/components/bluetooth/__init__.py @@ -60,6 +60,7 @@ __all__ = [ "async_rediscover_address", "async_register_callback", "async_track_unavailable", + "async_scanner_count", "BaseHaScanner", "BluetoothServiceInfo", "BluetoothServiceInfoBleak", @@ -86,6 +87,12 @@ def async_get_scanner(hass: HomeAssistant) -> HaBleakScannerWrapper: return HaBleakScannerWrapper() +@hass_callback +def async_scanner_count(hass: HomeAssistant, connectable: bool = True) -> int: + """Return the number of scanners currently in use.""" + return _get_manager(hass).async_scanner_count(connectable) + + @hass_callback def async_discovered_service_info( hass: HomeAssistant, connectable: bool = True diff --git a/homeassistant/components/bluetooth/manager.py b/homeassistant/components/bluetooth/manager.py index b1193c47245..d2b59469bd9 100644 --- a/homeassistant/components/bluetooth/manager.py +++ b/homeassistant/components/bluetooth/manager.py @@ -144,7 +144,7 @@ class BluetoothManager: ] = [] self._history: dict[str, BluetoothServiceInfoBleak] = {} self._connectable_history: dict[str, BluetoothServiceInfoBleak] = {} - self._scanners: list[BaseHaScanner] = [] + self._non_connectable_scanners: list[BaseHaScanner] = [] self._connectable_scanners: list[BaseHaScanner] = [] self._adapters: dict[str, AdapterDetails] = {} @@ -153,13 +153,19 @@ class BluetoothManager: """Return if passive scan is supported.""" return any(adapter[ADAPTER_PASSIVE_SCAN] for adapter in self._adapters.values()) + def async_scanner_count(self, connectable: bool = True) -> int: + """Return the number of scanners.""" + if connectable: + return len(self._connectable_scanners) + return len(self._connectable_scanners) + len(self._non_connectable_scanners) + async def async_diagnostics(self) -> dict[str, Any]: """Diagnostics for the manager.""" scanner_diagnostics = await asyncio.gather( *[ scanner.async_diagnostics() for scanner in itertools.chain( - self._scanners, self._connectable_scanners + self._non_connectable_scanners, self._connectable_scanners ) ] ) @@ -408,7 +414,11 @@ class BluetoothManager: def _get_scanners_by_type(self, connectable: bool) -> list[BaseHaScanner]: """Return the scanners by type.""" - return self._connectable_scanners if connectable else self._scanners + return ( + self._connectable_scanners + if connectable + else self._non_connectable_scanners + ) def _get_unavailable_callbacks_by_type( self, connectable: bool diff --git a/tests/components/bluetooth/test_init.py b/tests/components/bluetooth/test_init.py index a005a71f048..ade68fdb94d 100644 --- a/tests/components/bluetooth/test_init.py +++ b/tests/components/bluetooth/test_init.py @@ -2333,6 +2333,22 @@ async def test_getting_the_scanner_returns_the_wrapped_instance(hass, enable_blu assert isinstance(scanner, models.HaBleakScannerWrapper) +async def test_scanner_count_connectable(hass, enable_bluetooth): + """Test getting the connectable scanner count.""" + scanner = models.BaseHaScanner() + cancel = bluetooth.async_register_scanner(hass, scanner, False) + assert bluetooth.async_scanner_count(hass, connectable=True) == 1 + cancel() + + +async def test_scanner_count(hass, enable_bluetooth): + """Test getting the connectable and non-connectable scanner count.""" + scanner = models.BaseHaScanner() + cancel = bluetooth.async_register_scanner(hass, scanner, False) + assert bluetooth.async_scanner_count(hass, connectable=False) == 2 + cancel() + + async def test_migrate_single_entry_macos( hass, mock_bleak_scanner_start, macos_adapter ):