Skip to content

Detect the input characteristic instead of hard-coding it (v1.2.4) - #16

Merged
mlstr0m merged 1 commit into
mainfrom
fix/issue-15-input-char-detection
Aug 11, 2026
Merged

mlstr0m merged 1 commit into
mainfrom
fix/issue-15-input-char-detection

Conversation

@mlstr0m

@mlstr0m mlstr0m commented Aug 11, 2026

Copy link
Copy Markdown
Owner

Fixes #15.

The bug

The reporter's Switch 2 Pro Controller (bought in Australia) is found and connects, then every attempt dies in start_notify:

bleak.exc.BleakCharacteristicNotFoundError: Characteristic 7492866c-ec3e-4619-8258-32755ffcc0f9 was not found!

That UUID was hard-coded, so any revision that renumbers it was unusable. The log also showed each failure twice, because the teardown called stop_notify for a subscription that had never succeeded.

The fix

The input-report characteristic is now resolved at connect time:

  1. the UUID pinned in mappings.json (ble.input_char), if the device actually exposes it;
  2. otherwise the documented …f9;
  3. otherwise probe the remaining notifiable characteristics — same Nintendo vendor block first, other vendor UUIDs next, SIG-assigned ones (battery, device info) last, capped at 8 candidates.

A candidate is adopted only after it streams a report of at least MIN_REPORT_LEN (11) bytes, i.e. something the parser can actually decode — a 1-byte battery-level notification can't win. The adopted UUID is written back to mappings.json, so subsequent connects skip probing entirely.

Because some firmwares may only report on change, the menubar notice asks the user to move the sticks while identification runs, and the give-up message says the same before pointing at the log.

Also in here:

  • full GATT table logged on every connect (GATT: N characteristic(s): …) — this is exactly the information Switch 2 Pro Controller is not recognised #15 was missing to be diagnosable;
  • stop_notify is only attempted for a subscription that succeeded;
  • the mappings.json write-back is factored into _persist(), shared by the DSU toggle and the new ble.input_char.

Tests

19 new checks in tests/test_bridge.py against a fabricated GATT table: known UUID used without probing, pinned UUID honoured, stale pin falling back, renumbered characteristic adopted and persisted, short (battery-like) reports rejected, probe ordering, non-notifiable characteristics skipped, empty GATT, session failing cleanly with no stray stop_notify, plus ble.input_char parsing and persistence.

python tests/test_bridge.py && python tests/test_dsu.py

Both suites pass locally.

Caveat

If that controller exposes no notifiable characteristic streaming ≥ 11-byte reports at all — for instance if its vendor service only appears after an encrypted pairing — the probe will fail too. In that case the new GATT: log line tells us exactly what the device does expose, which is the follow-up.

🤖 Generated with Claude Code

Fixes #15: a Switch 2 Pro Controller bought in Australia connects fine but
has no 7492866c-ec3e-4619-8258-32755ffcc0f9 characteristic, so start_notify
raised BleakCharacteristicNotFoundError on every attempt.

The input-report UUID is now resolved at connect time: the UUID pinned in
mappings.json (ble.input_char) if present, else the documented one, else a
probe of the remaining notifiable characteristics — same Nintendo vendor
block first, other vendor UUIDs next, SIG-assigned ones last. A candidate is
adopted only once it streams reports of at least MIN_REPORT_LEN bytes, so a
1-byte battery-level notification can't be mistaken for input. The winner is
persisted, so later connects skip probing.

Also:
- log the full GATT table on every connect (this is what the issue was
  missing to be diagnosable)
- actionable error when nothing streams: retry moving the sticks, then
  attach the log
- don't call stop_notify for a subscription that never succeeded (it was
  doubling every failure in the log)
- factor the mappings.json write-back into _persist(), shared by the DSU
  toggle and the new ble.input_char

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@mlstr0m
mlstr0m merged commit 4121e75 into main Aug 11, 2026
2 checks passed
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.

Switch 2 Pro Controller is not recognised

1 participant