amyboard: unified amyboard.encoder() API across all rotary encoders#1063
Conversation
Add a single, hardware-agnostic rotary-encoder API so sketches (and the sketch generator) no longer have to special-case each accessory. The three supported devices have different encoder counts, LED layouts and I2C protocols: - Adafruit I2C QT Rotary Encoder (0x36): 1 encoder, 1 LED - Adafruit Quad Rotary Encoder Breakout (0x49): 4 encoders, 4 LEDs - M5Stack Unit 8Encoder (0x41): 8 encoders, 8 LEDs + toggle switch amyboard.encoder() autodetects whichever is connected (or the web simulator's emulated encoder) and returns an Encoder with one API: read(i)/button(i)/led(i,r,g,b)/reset(i)/switch(), plus .type/.encoders/.leds. Positions are zeroed at construction, buttons are normalized to True==pressed (the M5 register is active-low: 0==pressed), and every method returns a safe default when no hardware is present, so a sketch written for one device runs unchanged on another or on none. The legacy per-device helpers are untouched. Steer the sketch generator toward it: document encoder() in the system prompt and add an AMY_AGENTS.md section with a verified example. Update the user docs (accessories.md, python.md) and fix the wrong M5 button-polarity comment. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
🔌 AMYboard PR previewEditor + flasher: https://amyboard-pr-1063.vercel.app/editor/ This preview bundles this PR's firmware — its flasher only flashes this build (not the release). Rebuilt on every push; removed when the PR closes. The hardware CI has been kicked off and should return within a few minutes, stand by! |
🌷 Tulip Web PR previewTulip Web: https://tulip-pr-1063.vercel.app/run/ Flash a Tulip to this build: on-device run Rebuilt on every push; removed when the PR closes. |
…27da1 # Conflicts: # tulip/server/amyboardworld_db_api.py
🎛️ HW CI (physical bench)AMYboard (USB-MIDI + AMY Tulip (TULIP4_R11; serial-REPL audio + WiFi screenshot): ✅ PASS — flashed this PR’s firmware; all checks matched the references. ⬇️ Artifacts: recordings · screenshot · serial logs · run logs Self-hosted bench. Audio spectral-compared to |
|
Tested on hardware, works |
What
Adds a single, hardware-agnostic rotary-encoder API to AMYboard so sketches — and the "prompt to sketch" generator — no longer have to special-case each accessory.
The three supported devices differ in encoder count, LED layout, and I2C protocol:
0x360x490x41Every method returns a safe default when no hardware is present (
enc.encoders == 0), so a sketch written for 8 knobs still runs on 1 knob or none. The legacy per-device helpers (read_encoder(),read_buttons(),m5_8encoder,patch_selector()) are untouched.Correctness note
The M5Stack 8Encoder button register is active-low (0 = pressed), verified against the M5 vendor library (
if (!btn_status[i])). The unifiedbutton()normalizes everything toTrue == pressed. The repo's ownaccessories.mdpreviously documented this backwards — fixed here.Sketch generator
amyboardworld_db_api.py— system prompt now documentsamyboard.encoder()and tells the model to loop overrange(enc.encoders), guard LEDs withenc.leds, and drive params from the delta.AMY_AGENTS.md— new section with a verified example (appended to the generator prompt at request time).No
refdocssync needed — the generator's reference tools readdocs/amyboard/andtulip/shared/amyboard-py/straight from the repo.Testing
A CPython harness with stubbed I2C exercised all four device types (detection, offset-zeroed reads, button polarity, RGB-vs-GRB LED routing, reset, switch, out-of-range safety, forced type) — 31/31 pass.
🤖 Generated with Claude Code