Skip to content

fix(hal): keep what a BLE scan discovers, and find a device by its service - #142

Merged
gbradham merged 1 commit into
mainfrom
fix/ble-find-by-service
Aug 21, 2026
Merged

fix(hal): keep what a BLE scan discovers, and find a device by its service#142
gbradham merged 1 commit into
mainfrom
fix/ble-find-by-service

Conversation

@gbradham

Copy link
Copy Markdown
Member

Stacked on #141 — retarget to main once that lands.

From the bench: GLIDER's scan named a lab chair and never named the Maimu, while nRF Connect showed it fine.

The scan wasn't missing it — it was throwing away what identifies it

A peripheral advertising no usable name came back as ("(unknown)", address) and appeared in the picker as a bare MAC among other bare MACs. That is indistinguishable from not being there, which is exactly how it looked.

Zephyr devices put their name in the scan response, and Windows drops that often enough that a working stimulator routinely appears nameless. The ble_board docstring already knew this; the code just discarded everything that would have let you identify one anyway.

What the scan keeps now

  • Advertised service UUIDs — what the thing is
  • RSSI — which of several identical units is on the bench in front of you

Results sort strongest-first, the picker shows signal strength beside the address, and services go in the tooltip. An empty name now stays empty rather than becoming the literal string "(unknown)", so callers can tell nameless from named "(unknown)".

Finding a device by its service

BLEDevice resolves by service UUID as a last resort, after address and advertised name. It's the sturdiest identifier available: unlike a resolvable private address it doesn't rotate (#141), and unlike a name it doesn't depend on a scan response surviving the trip.

The Maimu's settings already carry its service UUID, so this costs its users no configuration at all.

It refuses to guess. When several peripherals advertise the service — six identical stimulators on a bench is the normal case, not an exotic one — it logs what it saw and declines, because connecting to whichever answered first would be the wrong animal's. A configured name is tried first for the same reason: a name identifies one unit, a service UUID identifies a model.

Tests — 10 new

Scan: each peripheral reported; an unnamed one labelled by address; the label carrying signal strength; strongest-first ordering; service UUIDs kept and matched case-insensitively (advertisements and config disagree on case routinely).

Device: a nameless peripheral found by its service after a stale address; several matches refused rather than guessed; and the name preferred over the service when both are configured, asserting the service scan never even runs.

Verification

PYTHONPATH=src QT_QPA_PLATFORM=offscreen pytest tests/3648 passed, 4 skipped, ruff and black clean.

…rvice

From the bench: GLIDER's scan named a lab chair and never named the Maimu,
while nRF Connect showed it fine. The scan was not missing the device -- it was
discarding what identifies it. A peripheral advertising no usable name came
back as ("(unknown)", address) and appeared in the picker as a bare MAC among
other bare MACs, which is indistinguishable from not being there.

Zephyr devices put their name in the SCAN RESPONSE, and Windows drops that
often enough that a working stimulator routinely appears nameless. So the scan
now keeps the two things that identify one anyway: the advertised service UUIDs
and the RSSI. Results are sorted strongest-first, the picker shows signal
strength beside the address, and the services go in the tooltip -- which is how
you tell which bare MAC is the stimulator you are holding.

An empty name stays empty rather than becoming the string "(unknown)", so a
caller can tell a nameless peripheral from one that is genuinely named that.

BLEDevice can now resolve by service UUID as a last resort, after the address
and the advertised name. It is the sturdiest identifier available: unlike a
resolvable private address it does not rotate, and unlike a name it does not
depend on a scan response surviving the trip. The Maimu's settings carry its
service UUID already, so this costs its users no configuration.

It refuses to guess. When several peripherals advertise the service -- six
identical stimulators on a bench is the normal case, not an exotic one -- it
logs what it saw and declines, because connecting to whichever answered first
would be the wrong animal's. A configured name is tried first for the same
reason: a name identifies one unit, a service UUID identifies a model.
Base automatically changed from fix/ble-reresolve-by-name to main August 21, 2026 15:26
@gbradham
gbradham merged commit 3bb10da into main Aug 21, 2026
@gbradham
gbradham deleted the fix/ble-find-by-service branch August 21, 2026 15:26
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.

1 participant