Skip to content

Commit 15ca6d3

Browse files
authored
feat: support bleak 2.0 (#334)
1 parent 30c3fa0 commit 15ca6d3

File tree

2 files changed

+118
-5
lines changed

2 files changed

+118
-5
lines changed

src/habluetooth/wrappers.py

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ class _HaWrappedBleakBackend:
6161
scanner: BaseHaScanner
6262
client: type[BaseBleakClient]
6363
source: str | None
64+
backend_name: str | None = None
6465

6566

6667
class HaBleakScannerWrapper(BaseBleakScanner):
@@ -334,8 +335,17 @@ async def connect(self, **kwargs: Any) -> None:
334335
assert device_adv is not None
335336
adv = device_adv[1]
336337
rssi = adv.rssi
338+
backend_name = (
339+
f" [{wrapped_backend.backend_name}]"
340+
if wrapped_backend.backend_name
341+
else ""
342+
)
337343
_LOGGER.debug(
338-
"%s: Connecting via %s (last rssi: %s)", description, scanner.name, rssi
344+
"%s: Connecting via %s%s (last rssi: %s)",
345+
description,
346+
scanner.name,
347+
backend_name,
348+
rssi,
339349
)
340350

341351
# Load fast connection parameters before connecting if mgmt API is available
@@ -376,10 +386,11 @@ async def connect(self, **kwargs: Any) -> None:
376386

377387
if debug_logging:
378388
_LOGGER.debug(
379-
"%s: %s via %s (last rssi: %s)",
389+
"%s: %s via %s%s (last rssi: %s)",
380390
description,
381391
"Connected" if connected else "Failed to connect",
382392
scanner.name,
393+
backend_name,
383394
rssi,
384395
)
385396
return
@@ -415,16 +426,28 @@ def _async_get_backend_for_ble_device(
415426
# its the client for this platform
416427
if not manager.async_allocate_connection_slot(ble_device):
417428
return None
418-
cls = get_platform_client_backend_type()
419-
return _HaWrappedBleakBackend(ble_device, scanner, cls, source)
429+
backend = get_platform_client_backend_type()
430+
# bleak 2.0.0+ returns a tuple (backend_class, backend_id)
431+
if isinstance(backend, tuple):
432+
cls, backend_name = backend
433+
else:
434+
cls = backend
435+
backend_name = type(cls).__name__
436+
return _HaWrappedBleakBackend(
437+
ble_device, scanner, cls, source, backend_name
438+
)
420439

421440
# Make sure the backend can connect to the device
422441
# as some backends have connection limits
423442
if not scanner.connector or not scanner.connector.can_connect():
424443
return None
425444

426445
return _HaWrappedBleakBackend(
427-
ble_device, scanner, scanner.connector.client, source
446+
ble_device,
447+
scanner,
448+
scanner.connector.client,
449+
source,
450+
type(scanner.connector.client).__name__,
428451
)
429452

430453
def _async_get_best_available_backend_and_device(

tests/test_wrappers.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1954,3 +1954,93 @@ async def connect_device(address: str) -> tuple[str, str | None]:
19541954
cancel1()
19551955
cancel2()
19561956
cancel3()
1957+
1958+
1959+
@pytest.mark.asyncio
1960+
async def test_backend_name_from_tuple(
1961+
enable_bluetooth: None,
1962+
install_bleak_catcher: None,
1963+
mock_platform_client: None,
1964+
) -> None:
1965+
"""Test that backend name is extracted from tuple (bleak 2.0.0+)."""
1966+
manager = _get_manager()
1967+
hci0_device_advs, cancel_hci0, _ = _generate_scanners_with_fake_devices()
1968+
1969+
with patch(
1970+
"habluetooth.wrappers.get_platform_client_backend_type",
1971+
return_value=(FakeBleakClient, "TestBackend"),
1972+
):
1973+
ble_device = hci0_device_advs["00:00:00:00:00:01"][0]
1974+
client = bleak.BleakClient(ble_device)
1975+
1976+
# Access the wrapped backend through the client
1977+
# The backend name should be extracted from the tuple
1978+
wrapped_backend = client._async_get_best_available_backend_and_device(manager)
1979+
assert wrapped_backend.backend_name == "TestBackend"
1980+
assert wrapped_backend.client == FakeBleakClient
1981+
1982+
cancel_hci0()
1983+
1984+
1985+
@pytest.mark.asyncio
1986+
async def test_backend_name_from_class(
1987+
enable_bluetooth: None,
1988+
install_bleak_catcher: None,
1989+
mock_platform_client: None,
1990+
) -> None:
1991+
"""Test that backend name is derived from class name (pre-bleak 2.0.0)."""
1992+
manager = _get_manager()
1993+
hci0_device_advs, cancel_hci0, _ = _generate_scanners_with_fake_devices()
1994+
1995+
with patch(
1996+
"habluetooth.wrappers.get_platform_client_backend_type",
1997+
return_value=FakeBleakClient,
1998+
):
1999+
ble_device = hci0_device_advs["00:00:00:00:00:01"][0]
2000+
client = bleak.BleakClient(ble_device)
2001+
2002+
# Access the wrapped backend through the client
2003+
# The backend name should be derived from the class name
2004+
wrapped_backend = client._async_get_best_available_backend_and_device(manager)
2005+
assert wrapped_backend.backend_name == "type"
2006+
assert wrapped_backend.client == FakeBleakClient
2007+
2008+
cancel_hci0()
2009+
2010+
2011+
@pytest.mark.asyncio
2012+
async def test_backend_name_in_logs(
2013+
enable_bluetooth: None,
2014+
install_bleak_catcher: None,
2015+
mock_platform_client: None,
2016+
caplog: pytest.LogCaptureFixture,
2017+
) -> None:
2018+
"""Test that backend name appears in debug logs."""
2019+
caplog.set_level(logging.DEBUG)
2020+
2021+
hci0_device_advs, cancel_hci0, _ = _generate_scanners_with_fake_devices()
2022+
2023+
with patch(
2024+
"habluetooth.wrappers.get_platform_client_backend_type",
2025+
return_value=(FakeBleakClient, "TestBackend"),
2026+
):
2027+
ble_device = hci0_device_advs["00:00:00:00:00:01"][0]
2028+
with patch.object(FakeBleakClient, "is_connected", return_value=True):
2029+
client = bleak.BleakClient(ble_device)
2030+
await client.connect()
2031+
2032+
# Check that the backend name appears in the logs
2033+
assert any(
2034+
"[TestBackend]" in record.message
2035+
for record in caplog.records
2036+
if "Connecting via" in record.message
2037+
), f"Backend name not found in logs: {[r.message for r in caplog.records]}"
2038+
assert any(
2039+
"[TestBackend]" in record.message
2040+
for record in caplog.records
2041+
if "Connected via" in record.message
2042+
), f"Backend name not found in logs: {[r.message for r in caplog.records]}"
2043+
2044+
await client.disconnect()
2045+
2046+
cancel_hci0()

0 commit comments

Comments
 (0)