Add --hci-id argument to python_ble_proxy#746
Conversation
There was a problem hiding this comment.
Pull request overview
This PR aims to add a --hci-id <id> option to the Python matter-ble-proxy CLI, aligning it with the existing Node.js noble-based proxy by allowing selection of a specific Bluetooth adapter (e.g., hci0).
Changes:
- Adds
--hci-idto the Python BLE proxy CLI argument parser. - Extends the Bleak scanning backend to support selecting a BlueZ adapter via
BleakScanner(..., bluez={adapter: ...}).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| python_ble_proxy/matter_ble_proxy/cli.py | Adds --hci-id and threads it into the CLI entrypoint (currently not fully wired into the scanner). |
| python_ble_proxy/matter_ble_proxy/bleak_backend.py | Adds adapter-selection support to BleakScanSource via BlueZ scanner args. |
Note the OS/BLE backend limitation in the --hci-id argument description, and only pass bluez_args to BleakScanner if a hci id was provided
Pass hci id into the 'adapter' argument of BleakScanner for bleak versions < 3.0.0, and pass it into the 'adapter' key of BlueZScannerArgs for bleak versions >= 3.0.0. Move the creation of the BleakScanner to its own method. Use cast() to get past type-checker errors when type-checking on bleak < 3.0.0, where the 'adapter' key does not exist on BlueZScannerArgs.
| try: | ||
| return asyncio.run(_run(args.server)) | ||
| return asyncio.run(_run(args.server, args.hci_id)) |
zigpy-review-bot
left a comment
There was a problem hiding this comment.
This adds the missing --hci-id parity with the JS noble-ble-proxy, and the tricky part — bleak's 2.x→3.x API break for selecting a BlueZ adapter — is handled correctly. I verified the branching against real bleak releases and ran the package's CI checks on the PR (details below). A few small suggestions inline; none blocking.
One behavioral caveat worth acknowledging (not necessarily fixing here): the adapter pin applies to scanning only. Connections are made in client.py:438 via BleakClient(target). When the resolver returns a cached BLEDevice, BlueZ connects through that device's D-Bus path (which lives under the scanned adapter), so the normal flow is correct. But on a cache miss the resolver falls back to the raw address, and bleak then scans + connects on the default adapter — on a machine where the user chose --hci-id 1 precisely because hci0 is unusable, that fallback would fail confusingly. Bleak 3's BlueZClientArgs also supports "adapter", so this is plumbable in a follow-up.
Verification performed
- bleak 3.0.2 (current):
BlueZScannerArgshas anadapterkey, and the BlueZ scanner backend reads the adapter only frombluez={"adapter": ...}— a bareadapter=kwarg is silently ignored. So the>= 3branch is correct and necessary. - bleak 1.x / 2.x:
BlueZScannerArgshas noadapterkey; the backend readskwargs.get("adapter")instead. So the fallback branch is also correct. - Smoke test with bleak 3.0.2:
BleakScanSource(hci_device=1)._get_bleak_scanner()yields a BlueZ backend with_adapter == "hci1"; the default path staysNone. ruff checkclean,mypyclean (theTYPE_CHECKING-onlybleak.args.bluezimport exists since bleak 1.0, and CI installs latest bleak), all 6 unit tests pass.- Non-Linux: on bleak 3 the
bluez=args are ignored by the other backends, so passing the flag on macOS/Windows is harmless, matching the help text.
Optional polish, take or leave:
- A small unit test that monkeypatches
importlib.metadata.versionand asserts which kwargsBleakScannerreceives in each branch would lock in the version-gating behavior. - The README's standalone-CLI section only shows
--server; a one-line--hci-idexample there would help discoverability.
| """ | ||
|
|
||
| def __init__(self) -> None: | ||
| def __init__(self, hci_device: int | None = None) -> None: |
There was a problem hiding this comment.
Nit: the flag is --hci-id and the argparse dest is hci_id, but this parameter is hci_device. Renaming it to hci_id would keep one name end-to-end (BleakScanSource(hci_id=args.hci_id)).
| "--hci-id", | ||
| default=None, | ||
| type=int, | ||
| help="Bluetooth adapter HCI ID (e.g., 0 for hci0). Use only on Linux with BlueZ.", |
There was a problem hiding this comment.
Since the adapter pin currently only affects scanning (see main comment re: the address-fallback connect path), consider hinting at that here, e.g. "Bluetooth adapter HCI ID used for scanning (e.g., 0 for hci0). Linux/BlueZ only." — or just leave as-is if the connect path gets plumbed later.
This adds the
--hci-id <id>argument to the python matter-ble-proxy package.The argument is available on the nodejs noble-ble-proxy, but previously not on the python package