Annotated walkthrough · for review
The Magic Lantern whip driver — 135 lines, written 2 September 2026. Every other family module on Eagle is a copy-forward of this file. It is where the locked mechanism came from, and it carries two scars in its own comments.
6WHY THIS EXISTS (Zora, 2026-09-02):7 Every failing run on 09-02 called Device1.Connect() -- asking bluetoothd to establish the link.8 Measured: the link forms and the daemon aborts it at 0.7s; discovery never completes (tested to 120s).9 Ray's own banked maintain.py:166 never does that. It registers the MAC in the CONTROLLER's10 filter-accept-list (btmgmt add-device -a 2) and the HARDWARE completes the link the instant the11 device advertises -- the same mechanism a phone uses. D-Bus is then used ONLY for reads/writes.
Mechanism lines 9–11
This is the whole idea. We stop asking bluetoothd to connect and instead
hand the MAC to the controller's filter-accept-list, then let the radio complete the link in
hardware when the device next advertises. D-Bus is demoted to reads and writes only.
The prior art was already on the box — your own maintain.py:166. Line 9
says so explicitly.
Measurement line 8, line 12
| Path | Result |
|---|---|
| Device1.Connect() | link forms, daemon aborts at 0.7 s |
| discovery | never completes, tested to 120 s |
| accept-list connect | ~1 s |
| services resolve | ~5 s strong · ~15 s weak |
| warm command | ~8 ms |
14⛔ RESOLVE TIMEOUT IS SET FROM THE WEAKEST DEVICE, NOT THE STRONGEST.15 E9 (~-32 dBm) resolves in ~5s; D2 (~-56 dBm) takes ~15s. A ceiling tuned on E9 makes D2 fail16 forever. See feedback_threshold_tuned_on_the_best_case_sample.27RESOLVE_TIMEOUT = 45.0 # generous ON PURPOSE -- see the header note
Mechanism line 27
45 s looks lazy and is not. The passenger whip sits 24 dB down on the driver whip and takes three times as long to resolve. Tune the ceiling on the strong one and the weak one never works again — and it fails in a way that looks like broken hardware rather than a bad constant.
Worth your eye: this is the same trap that got rack written off
as dead hardware in August.
33# ---- frames, byte-exact from wl.smartled.rgb (Magic Lantern) ------------------34def rgb(r, g, b): return bytes([0x7E, 0x07, 0x05, 0x03, r & 255, g & 255, b & 255, 0x10, 0xEF])35def power(on): return bytes([0x7E, 0x04, 0x04, 1 if on else 0, 0x00, 1 if on else 0, 0xFF, 0x00, 0xEF])36def melk_login(): return bytes([0x7E, 0x07, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF])
Mechanism line 33
Line 33 is where the app name has been recorded all along —
wl.smartled.rgb. Every frame is byte-exact from the vendor app, not inferred.
All three share the 0x7E … 0xEF envelope.
84# ⛔ 2026-09-02: THE MELK LOGIN IS MANDATORY AND I SHIPPED WITHOUT IT.85# My first manual run sent login -> power -> red -> green and Ray SAW the whip86# change. send_many() then defaulted login=False, so every UI command after that87# was ACCEPTED at GATT (rc=0) and silently IGNORED by the device. Ray saw nothing.88# ⭐ I made it fast by removing the thing that made it work -- and rc=0 hid it.89# Login belongs on the LINK, not on every write: send it once per new link so the90# warm path stays ~8 ms.
Scar lines 84–90
The manual run worked because it sent the login. The optimisation then defaulted
login=False, and from that point every command was accepted at the GATT layer and
thrown away by the device. The return code stayed 0 the whole time. Your eyes
caught it; nothing in the software could have.
The fix is on line 89 and it is the right shape: login belongs to the link, not to the write, so it costs one round trip per connection and the warm path stays at 8 ms.
Pattern four families, one symptom
Magic Lantern needs melk_login. Grill needs the 2A… knock.
Triones and Suparee each need a handshake. Four different unlock rituals, one identical
failure: the write succeeds and the light does nothing.
119def _write(cpath, payload):120 """⛔ 2026-09-02: busctl PRINTS 'Call failed: Not connected' AND EXITS 0.121 This function used to `return rc == 0` -- a success check that could not fail, in the one122 place it mattered. It reported OK for every write to a disconnected device, all afternoon,123 and Ray's eyes were the only thing that caught it. PARSE THE OUTPUT, NEVER THE EXIT CODE."""128 blob = (r.stdout or "") + (r.stderr or "")129 if r.returncode != 0 or "Call failed" in blob or "Error" in blob:
Scar lines 120–123
“A success check that could not fail, in the one place it mattered.”
busctl prints Call failed: Not connected and then exits 0. Checking
rc == 0 therefore returns success for every write to a dead link. Line 129 is the
fix: the exit code is still checked, but the output is parsed too, and either one can fail the write.
107# ⛔ re-verify the link IMMEDIATELY before writing. "Linked 20 s ago" is not "linked108# now" -- these links do not reliably hold, and a write to a dropped link reports OK.109if not _prop(mac, "Connected"):110 out[k] = (False, "%s LINK DROPPED before write (not connected)" % k); continue
Mechanism lines 107–110
A freshness check immediately before the write, because a link that resolved twenty seconds ago may be gone. Cheap — one property read on the warm path.
This is the line the current question turns on. It treats currently connected as a precondition for sending — and the vendor app has no such precondition. It finds, sends, and lets go. The direction under discussion is subtraction, and this is the code it would subtract from.
Read across all six modules rather than taking this file alone. The tidy version of this table — one family, one characteristic — is not what the code says.
| Family | Service | Write | Notify | Unlock ritual |
|---|---|---|---|---|
| magic_lantern | — | fff3 | none | melk_login |
| elk | — | fff3 | none | melk_login |
| grill | ffe0 | ffe1 | none | 2A… knock |
| triones | ffd5 | ffd9 | ffd4 in ffd0 | notify-gated |
| suparee | service000c | ffd9 | — | handshake |
| nova | ae00 | ae01 | ae02 | none |
Two collisions read from the modules, not from notes
Magic Lantern and elk share fff3 and the
melk_login unlock — two different vendors, two different sets of
hardware, identical transport and identical ritual. Triones and suparee share
ffd9 but it lives in different services
(ffd5 vs service000c).
So the characteristic alone tells you neither the family nor the protocol. Six families, five characteristics, two collisions.
This also explains the docstring bug. elk_control.py genuinely
is this file with a different DEVICES dict — same characteristic, same
login, same transport. A header reading “eagle_auto.py” never looked wrong to anyone
editing it, because functionally it was not wrong. (Caught by Solace against the module;
my first version of this table had elk's unlock as “none”.)
Why it still works suparee_control.py line 19
Because _char() resolves by UUID across the whole tree rather than
walking a fixed service path — the module says so explicitly. That single choice, inherited
from this file's line 59–66, is what lets suparee's ffd9 be found in a service
nobody expected it in.
It is also a latent trap: a tree-wide UUID search on a device exposing
fff3 twice would take whichever came first.
For the review
Lines 9–11 — the mechanism, the one thing locked on 08-18.
Line 27 — the timeout, and why the weakest device sets it.
Lines 107–110 — the precondition that no vendor app has.
Lines 120–123 — the check that could not fail.