Skip to content

Add BleakAdapter.get_connected_devices()#1979

Merged
dlech merged 4 commits into
developfrom
bleak-adapter
May 4, 2026
Merged

Add BleakAdapter.get_connected_devices()#1979
dlech merged 4 commits into
developfrom
bleak-adapter

Conversation

@dlech
Copy link
Copy Markdown
Collaborator

@dlech dlech commented May 3, 2026

This is splitting out part of #1966 to make it easier to review, test and get merged.

I took ab05a28 and split it into a few commits, fixed them up a bit and added one more commit with tests.

I dropped the example since that requires further changes before it actually works.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 3, 2026

Codecov Report

❌ Patch coverage is 73.02632% with 41 lines in your changes missing coverage. Please review.
✅ Project coverage is 52.06%. Comparing base (9de261d) to head (d4ef045).
⚠️ Report is 1 commits behind head on develop.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
bleak/backends/winrt/adapter.py 51.42% 17 Missing ⚠️
bleak/backends/corebluetooth/adapter.py 59.25% 11 Missing ⚠️
bleak/backends/bluezdbus/manager.py 64.70% 3 Missing and 3 partials ⚠️
bleak/backends/adapter.py 80.00% 4 Missing and 1 partial ⚠️
bleak/__init__.py 85.71% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #1979      +/-   ##
===========================================
+ Coverage    51.26%   52.06%   +0.79%     
===========================================
  Files           39       43       +4     
  Lines         3940     4091     +151     
  Branches       487      503      +16     
===========================================
+ Hits          2020     2130     +110     
- Misses        1794     1830      +36     
- Partials       126      131       +5     
Flag Coverage Δ
bluez-integration-py3.10 38.74% <46.71%> (+0.29%) ⬆️
bluez-integration-py3.11 38.74% <46.71%> (+0.29%) ⬆️
bluez-integration-py3.12 38.74% <46.71%> (+0.29%) ⬆️
bluez-integration-py3.13 38.74% <46.71%> (+0.29%) ⬆️
bluez-integration-py3.14 37.22% <46.35%> (+0.34%) ⬆️
macos-latest-py3.10 20.06% <26.31%> (+0.22%) ⬆️
macos-latest-py3.11 20.06% <26.31%> (+0.22%) ⬆️
macos-latest-py3.12 20.06% <26.31%> (+0.22%) ⬆️
macos-latest-py3.13 20.06% <26.31%> (+0.22%) ⬆️
macos-latest-py3.14 19.87% <25.82%> (+0.21%) ⬆️
ubuntu-latest-py3.10 23.95% <28.28%> (+0.14%) ⬆️
ubuntu-latest-py3.11 23.95% <28.28%> (+0.14%) ⬆️
ubuntu-latest-py3.12 23.95% <28.28%> (+0.14%) ⬆️
ubuntu-latest-py3.13 23.95% <28.28%> (+0.14%) ⬆️
ubuntu-latest-py3.14 22.06% <27.81%> (+0.20%) ⬆️
windows-latest-py3.10 18.74% <27.63%> (+0.32%) ⬆️
windows-latest-py3.11 18.74% <27.63%> (+0.32%) ⬆️
windows-latest-py3.12 18.74% <27.63%> (+0.32%) ⬆️
windows-latest-py3.13 18.74% <27.63%> (+0.32%) ⬆️
windows-latest-py3.14 18.47% <27.15%> (+0.32%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@dlech dlech force-pushed the bleak-adapter branch 2 times, most recently from 6570921 to bdd7a36 Compare May 3, 2026 20:15
Simply creating new arrays by calling the class method instead of
alloc().initWithArray_().
@dlech dlech force-pushed the bleak-adapter branch from bdd7a36 to 068c631 Compare May 3, 2026 20:20
We will want to reuse this logic in a future new module, so it makes
sense to extract it into a helper function.
@dlech dlech force-pushed the bleak-adapter branch 9 times, most recently from 3ca6f7c to c71fa1b Compare May 4, 2026 00:38
@dlech
Copy link
Copy Markdown
Collaborator Author

dlech commented May 4, 2026

I ended up having to make major changes to the winrt backend to get it to pass the tests.

Should be ready to merge now.

@dlech dlech requested a review from Copilot May 4, 2026 00:42
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR splits out part of the broader connected-device work from #1966 by introducing a new public BleakAdapter API for retrieving BLE devices that are already connected at the OS level, without starting a scan. It extends Bleak’s backend abstraction alongside the existing scanner/client layers, with desktop backend implementations, docs, typings, and integration tests.

Changes:

  • Added a new public BleakAdapter facade plus backend-selection plumbing and Linux-specific adapter args.
  • Implemented get_connected_devices() for BlueZ, CoreBluetooth, and WinRT backends.
  • Added documentation, platform-detection coverage, integration tests, and a small CoreBluetooth/Foundation typing update needed by the new code.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
typings/Foundation/__init__.pyi Tightens NSArray typing and adds arrayWithArray_ for CoreBluetooth calls.
tests/test_platform_detection.py Extends backend-detection test coverage to adapter backend selection.
tests/integration/test_adapter.py Adds integration tests for retrieving connected devices and UUID filtering.
docs/api/index.rst Adds the new adapter API page to the docs toctree.
docs/api/adapter.rst Documents BleakAdapter.get() and get_connected_devices().
bleak/backends/winrt/adapter.py Implements Windows adapter lookup for connected BLE devices.
bleak/backends/corebluetooth/client.py Switches requested-service array construction to the new NSArray helper.
bleak/backends/corebluetooth/adapter.py Implements macOS adapter lookup via retrieveConnectedPeripheralsWithServices_.
bleak/backends/corebluetooth/CentralManagerDelegate.py Uses the new NSArray.arrayWithArray_ helper in scan setup.
bleak/backends/bluezdbus/utils.py Extracts BlueZ device-name normalization into a reusable helper.
bleak/backends/bluezdbus/scanner.py Reuses the new BlueZ device-name helper during scan updates.
bleak/backends/bluezdbus/manager.py Adds manager-side filtering for connected BlueZ devices by adapter and UUIDs.
bleak/backends/bluezdbus/adapter.py Implements Linux adapter lookup on top of the BlueZ manager.
bleak/backends/adapter.py Introduces the base adapter abstraction and platform backend resolver.
bleak/args/bluez.py Adds BlueZAdapterArgs for Linux adapter selection.
bleak/__init__.py Exposes the public BleakAdapter class and input normalization logic.
CHANGELOG.rst Records the new BleakAdapter capability in the unreleased changelog.
AUTHORS.rst Adds a contributor entry.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread bleak/backends/adapter.py
Comment thread bleak/backends/bluezdbus/adapter.py
Comment thread tests/integration/test_adapter.py
@dlech dlech force-pushed the bleak-adapter branch 4 times, most recently from 42d3ae5 to f84fa69 Compare May 4, 2026 01:02
@dlech dlech requested a review from Copilot May 4, 2026 01:07
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread bleak/__init__.py
Comment on lines +471 to +475
get_platform_adapter_backend_type()
if backend is None
else (backend, backend.__name__)
)
return cls(await PlatformBleakAdapter.get(bluez=bluez))
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can always add this later.

Comment thread bleak/__init__.py
Comment on lines +477 to +480
async def get_connected_devices(
self,
service_uuids: Iterable[str] = ["1801"],
) -> list[BLEDevice]:
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the others are list already, we can go with that. We can always relax them later if needed.

Comment thread docs/api/adapter.rst
Comment on lines +25 to +27
On Linux, a specific adapter can be selected via the ``bluez`` argument::

adapter = await BleakAdapter.get(bluez={"adapter": "hci1"})
Comment thread docs/api/adapter.rst
Comment on lines +39 to +50
from bleak import BleakAdapter, BleakClient

adapter = await BleakAdapter.get()
devices = await adapter.get_connected_devices()

for d in devices:
print(d.name, d.address)

# Use an existing connection without scanning
async with BleakClient(devices[0]) as client:
...

Comment thread bleak/backends/winrt/adapter.py Outdated
Comment on lines +53 to +54
# Don't waste time if the default ("Generic Access") service is the only
# one we're looking for since that should always match.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, 0x1800 is Generic Access and 0x1801 is Generic Attribute.

Comment on lines +29 to +31
adapter_path = (
f"/org/bluez/{adapter}" if adapter else manager.get_default_adapter()
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, would save users from silent empty-list bugs.
Could check manager.get_adapter_path in BleakAdapterBlueZDBus.get().

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have similar logic in BleakScannerBlueZDBus.start(). I don't recall any reported issues with this. So think we should defer fixing this.

Comment thread bleak/__init__.py Outdated

async def get_connected_devices(
self,
service_uuids: Iterable[str] = ["1801"],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Iterable[str] is too broad.
await get_connected_devices("180F") would silently iterate characters. Worth tightening to Collection[str].

@Vodur
Copy link
Copy Markdown
Contributor

Vodur commented May 4, 2026

Ran a Windows smoke test against this branch with my BLE Device (random-static address, GATT 0x1801 default filter). get_connected_devices() correctly returns it, BleakDevice round-trips into BleakClient, empty/string service_uuids both surface errors.
The Iterable[str] string-footgun does raise - ValueError: badly formed hexadecimal UUID string from normalize_uuid_str - so it's not silent, just opaque.

Vodur and others added 2 commits May 4, 2026 18:02
Add a new BleakAdapter class for OS-level adapter operations that don't
require scanning. The first capability is get_connected_devices(), which
queries the OS for BLE devices that are already connected. The returned
BLEDevice objects can be passed directly to BleakClient to use the
existing OS-level connection without scanning.

Instances are obtained via the async BleakAdapter.get() factory.

Platform implementations:

- Windows: Uses BluetoothLEDevice.get_device_selector_from_connection_status()
  with DeviceInformation.find_all_async() to enumerate connected devices.
  service_uuids is currently ignored since BluetoothLEDevice already
  excludes Bluetooth Classic devices.

- macOS: Uses CBCentralManager.retrieveConnectedPeripheralsWithServices()
  to get connected peripherals filtered by service UUID.

- Linux: Adds BlueZManager.get_connected_devices() to query D-Bus for
  connected BLE devices on the selected adapter, filtered by service
  UUID. The adapter can be selected via the BlueZAdapterArgs typed dict
  (e.g. bluez={"adapter": "hci1"}).

Other backends raise NotImplementedError.

Co-developed-by: David Lechner <david@pybricks.com>
Add a test for BleakAdapter.get_connected_devices(). This needs to test
that the service UUID filter is working.
@dlech dlech force-pushed the bleak-adapter branch from f84fa69 to d4ef045 Compare May 4, 2026 23:02
@dlech dlech merged commit 8ba2718 into develop May 4, 2026
23 checks passed
@dlech dlech deleted the bleak-adapter branch May 4, 2026 23:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants