Expose bluetooth address reachability diagnostics API (#172578)

This commit is contained in:
J. Nick Koston
2026-05-30 08:49:56 -05:00
committed by GitHub
parent 0c10c2c16b
commit 02b760f142
3 changed files with 66 additions and 0 deletions
@@ -27,6 +27,7 @@ from bluetooth_data_tools import monotonic_time_coarse as MONOTONIC_TIME
from habluetooth import (
BaseHaRemoteScanner,
BaseHaScanner,
BluetoothReachabilityIntent,
BluetoothScannerDevice,
BluetoothScanningMode,
HaBluetoothConnector,
@@ -55,6 +56,7 @@ from . import passive_update_processor, websocket_api
from .api import (
_get_manager,
async_address_present,
async_address_reachability_diagnostics,
async_ble_device_from_address,
async_clear_address_from_match_history,
async_clear_advertisement_history,
@@ -108,12 +110,14 @@ __all__ = [
"BluetoothCallback",
"BluetoothCallbackMatcher",
"BluetoothChange",
"BluetoothReachabilityIntent",
"BluetoothScannerDevice",
"BluetoothScanningMode",
"BluetoothServiceInfo",
"BluetoothServiceInfoBleak",
"HaBluetoothConnector",
"async_address_present",
"async_address_reachability_diagnostics",
"async_ble_device_from_address",
"async_clear_address_from_match_history",
"async_clear_advertisement_history",
@@ -11,6 +11,7 @@ from typing import TYPE_CHECKING, cast
from bleak import BleakScanner
from habluetooth import (
BaseHaScanner,
BluetoothReachabilityIntent,
BluetoothScannerDevice,
BluetoothScanningMode,
HaBleakScannerWrapper,
@@ -108,6 +109,14 @@ def async_ble_device_from_address(
return _get_manager(hass).async_ble_device_from_address(address, connectable)
@hass_callback
def async_address_reachability_diagnostics(
hass: HomeAssistant, address: str, intent: BluetoothReachabilityIntent
) -> str:
"""Return a human readable explanation of why an address may be unreachable."""
return _get_manager(hass).async_address_reachability_diagnostics(address, intent)
@hass_callback
def async_scanner_devices_by_address(
hass: HomeAssistant, address: str, connectable: bool = True
+53
View File
@@ -10,9 +10,11 @@ from homeassistant.components.bluetooth import (
MONOTONIC_TIME,
BaseHaRemoteScanner,
BluetoothChange,
BluetoothReachabilityIntent,
BluetoothScanningMode,
BluetoothServiceInfo,
HaBluetoothConnector,
async_address_reachability_diagnostics,
async_clear_advertisement_history,
async_request_active_scan,
async_scanner_by_source,
@@ -112,6 +114,57 @@ async def test_async_scanner_devices_by_address_connectable(
cancel()
@pytest.mark.usefixtures("enable_bluetooth")
async def test_async_address_reachability_diagnostics(hass: HomeAssistant) -> None:
"""Test the address reachability diagnostics passthrough."""
# An address that was never seen reports as unknown.
assert "unknown" in async_address_reachability_diagnostics(
hass, "44:44:33:11:23:99", BluetoothReachabilityIntent.CONNECTION
)
manager = _get_manager()
class FakeInjectableScanner(BaseHaRemoteScanner):
def inject_advertisement(
self, device: BLEDevice, advertisement_data: AdvertisementData
) -> None:
"""Inject an advertisement."""
self._async_on_advertisement(
device.address,
advertisement_data.rssi,
device.name,
advertisement_data.service_uuids,
advertisement_data.service_data,
advertisement_data.manufacturer_data,
advertisement_data.tx_power,
{"scanner_specific_data": "test"},
MONOTONIC_TIME(),
)
connector = HaBluetoothConnector(MockBleakClient, "esp32", lambda: True)
scanner = FakeInjectableScanner("esp32", "esp32", connector, True)
unsetup = scanner.async_setup()
cancel = manager.async_register_scanner(scanner)
switchbot_device = generate_ble_device("44:44:33:11:23:45", "wohand", {})
switchbot_device_adv = generate_advertisement_data(local_name="wohand", rssi=-80)
scanner.inject_advertisement(switchbot_device, switchbot_device_adv)
connection_diag = async_address_reachability_diagnostics(
hass, "44:44:33:11:23:45", BluetoothReachabilityIntent.CONNECTION
)
assert "in connectable history" in connection_diag
assert "esp32" in connection_diag
# An advertisement intent does not report connectable paths or slots.
advertisement_diag = async_address_reachability_diagnostics(
hass, "44:44:33:11:23:45", BluetoothReachabilityIntent.PASSIVE_ADVERTISEMENT
)
assert "advertising" in advertisement_diag
unsetup()
cancel()
@pytest.mark.usefixtures("enable_bluetooth")
async def test_async_scanner_devices_by_address_non_connectable(
hass: HomeAssistant,