docs(02-02): complete ESP32 UDP transport plan — CHR-05 fulfilled
- Add 02-02-SUMMARY.md: ESP32Transport asyncio DatagramProtocol implementation - Update STATE.md: advance to plan 3/6, 50% overall progress - Update ROADMAP.md: phase 02 in progress (1/6 summaries) - Mark CHR-05 complete in REQUIREMENTS.md
This commit is contained in:
@@ -26,7 +26,7 @@
|
|||||||
- [ ] **CHR-02**: User kann Timing-Marks setzen durch Tastendruck waehrend der Wiedergabe (Tapper)
|
- [ ] **CHR-02**: User kann Timing-Marks setzen durch Tastendruck waehrend der Wiedergabe (Tapper)
|
||||||
- [ ] **CHR-03**: User kann Animationsloops definieren (N-mal wiederholen oder bis zum naechsten Event)
|
- [ ] **CHR-03**: User kann Animationsloops definieren (N-mal wiederholen oder bis zum naechsten Event)
|
||||||
- [ ] **CHR-04**: Choreografien koennen als JSON-Dateien gespeichert und geladen werden
|
- [ ] **CHR-04**: Choreografien koennen als JSON-Dateien gespeichert und geladen werden
|
||||||
- [ ] **CHR-05**: Choreografie-Playback sendet Animationskommandos zeitgenau an den ESP32
|
- [x] **CHR-05**: Choreografie-Playback sendet Animationskommandos zeitgenau an den ESP32
|
||||||
|
|
||||||
### Live Reaktiv
|
### Live Reaktiv
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@
|
|||||||
| AUD-03 | Phase 2 | Pending |
|
| AUD-03 | Phase 2 | Pending |
|
||||||
| AUD-04 | Phase 2 | Pending |
|
| AUD-04 | Phase 2 | Pending |
|
||||||
| CHR-04 | Phase 2 | Pending |
|
| CHR-04 | Phase 2 | Pending |
|
||||||
| CHR-05 | Phase 2 | Pending |
|
| CHR-05 | Phase 2 | Complete |
|
||||||
| CHR-01 | Phase 3 | Pending |
|
| CHR-01 | Phase 3 | Pending |
|
||||||
| CHR-02 | Phase 3 | Pending |
|
| CHR-02 | Phase 3 | Pending |
|
||||||
| CHR-03 | Phase 3 | Pending |
|
| CHR-03 | Phase 3 | Pending |
|
||||||
|
|||||||
93
.planning/ROADMAP.md
Normal file
93
.planning/ROADMAP.md
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
# Roadmap: LED Sync Studio
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Four phases build a music-synchronized LED choreography system from hardware up. Phase 1 validates the ESP32 firmware and retires all hardware risks before any Pi-side code is written. Phase 2 builds the headless Pi core — audio playback, beat detection, choreography engine, and UDP transport — all CLI-testable against real hardware. Phase 3 assembles the full cyberpunk TUI on top of the stable core, delivering the choreography editor end-to-end. Phase 4 adds live-reactive mode and Spotify as a second audio source.
|
||||||
|
|
||||||
|
## Phases
|
||||||
|
|
||||||
|
**Phase Numbering:**
|
||||||
|
- Integer phases (1, 2, 3): Planned milestone work
|
||||||
|
- Decimal phases (2.1, 2.2): Urgent insertions (marked with INSERTED)
|
||||||
|
|
||||||
|
Decimal phases appear between their surrounding integers in numeric order.
|
||||||
|
|
||||||
|
- [x] **Phase 1: ESP32 Firmware** - Both LED strips driven by a WiFi-connected ESP32 that executes named animations from JSON commands (completed 2026-04-03)
|
||||||
|
- [ ] **Phase 2: App Core + Audio** - Headless Pi layer: song playback, beat detection, choreography engine, UDP transport
|
||||||
|
- [ ] **Phase 3: Choreography TUI** - Full cyberpunk terminal UI with timeline editor, event list, transport controls, and animation panel
|
||||||
|
- [ ] **Phase 4: Live Reactive + Spotify** - Beat-driven animation mode with sensitivity calibration and Spotify as audio source
|
||||||
|
|
||||||
|
## Phase Details
|
||||||
|
|
||||||
|
### Phase 1: ESP32 Firmware
|
||||||
|
**Goal**: Both LED strips are driven by one ESP32-C3 that receives JSON commands over WiFi and executes named animations autonomously
|
||||||
|
**Depends on**: Nothing (first phase)
|
||||||
|
**Requirements**: FW-01, FW-02, FW-03, FW-04, FW-05
|
||||||
|
**Success Criteria** (what must be TRUE):
|
||||||
|
1. WS2801 (160 LEDs, SPI) and SK6812 (300 LEDs, RMT/RGBW) both illuminate correctly and simultaneously with no flicker from WiFi interference
|
||||||
|
2. Sending a UDP JSON command (e.g. `{"zone":"wall","animation":"chase","speed":0.5}`) from a laptop triggers the named animation on the correct strip within 50ms
|
||||||
|
3. All 8 built-in animations (Chase, Pulse, Rainbow, Strobe, Color Wash, Breathe, Sparkle, Gradient Sweep) run on either zone without crashing
|
||||||
|
4. Each zone can be commanded independently — different animations run on Schrank and Wand simultaneously
|
||||||
|
5. Animation parameters (color/RGBW, speed, intensity) visibly change behavior when included in the JSON command
|
||||||
|
**Plans**: 4 plans
|
||||||
|
|
||||||
|
Plans:
|
||||||
|
- [x] 01-01-PLAN.md — PlatformIO scaffold, dual LED driver, WiFi+RMT coexistence validation
|
||||||
|
- [x] 01-02-PLAN.md — UDP server, JSON protocol parser, FreeRTOS command queue
|
||||||
|
- [x] 01-03-PLAN.md — Animation engine (50fps FreeRTOS), all 8 built-in animations
|
||||||
|
- [x] 01-04-PLAN.md — System integration, final wiring, hardware acceptance checkpoint
|
||||||
|
|
||||||
|
### Phase 2: App Core + Audio
|
||||||
|
**Goal**: The Pi can play songs, detect beats, schedule choreography events, and send animation commands to the ESP32 — all testable from the command line without any TUI
|
||||||
|
**Depends on**: Phase 1
|
||||||
|
**Requirements**: AUD-01, AUD-02, AUD-03, AUD-04, CHR-04, CHR-05
|
||||||
|
**Success Criteria** (what must be TRUE):
|
||||||
|
1. A local MP3, FLAC, or WAV file plays with audible output and the current playback position is readable at any moment
|
||||||
|
2. Playback can be paused, resumed, and seeked to an arbitrary timestamp via CLI commands
|
||||||
|
3. Beat events are detected from the system audio stream in real time (aubio) with visible console output per beat
|
||||||
|
4. A choreography JSON file loads and plays back: correct animations fire on the ESP32 at the timestamps specified in the file
|
||||||
|
5. Choreography edits (adding an event) save to a JSON file that reloads correctly on next run
|
||||||
|
**Plans**: 6 plans
|
||||||
|
|
||||||
|
Plans:
|
||||||
|
- [ ] 02-01-PLAN.md — Project scaffold (pyproject.toml, uv deps) + Pydantic choreography models
|
||||||
|
- [x] 02-02-PLAN.md — UDP transport client (asyncio DatagramProtocol to ESP32)
|
||||||
|
- [ ] 02-03-PLAN.md — Audio player (miniaudio playback, position tracking, pause/seek)
|
||||||
|
- [ ] 02-04-PLAN.md — Choreography scheduler (absolute monotonic clock, event dispatch)
|
||||||
|
- [ ] 02-05-PLAN.md — Beat detector (sounddevice + aubio, asyncio bridge)
|
||||||
|
- [ ] 02-06-PLAN.md — Main entry point + asyncio REPL + hardware acceptance checkpoint
|
||||||
|
|
||||||
|
### Phase 3: Choreography TUI
|
||||||
|
**Goal**: The full cyberpunk terminal UI is usable over SSH: user can load a song, place animations on the timeline, and play back a complete light show
|
||||||
|
**Depends on**: Phase 2
|
||||||
|
**Requirements**: CHR-01, CHR-02, CHR-03, UI-01, UI-02, UI-03, UI-04, UI-05, UI-06
|
||||||
|
**Success Criteria** (what must be TRUE):
|
||||||
|
1. The TUI launches over SSH with cyberpunk/neon styling — dark background, glowing colored elements — and all panels are legible in a standard terminal
|
||||||
|
2. User can select a position in the song, choose an animation with parameters, and assign it to a zone — it appears as a block on the timeline view
|
||||||
|
3. User can tap a key on the beat during playback to stamp timing marks, and those marks are visible on the timeline
|
||||||
|
4. User can switch between Timeline view (horizontal blocks) and Event List view (table of timestamps) for the same choreography
|
||||||
|
5. Pressing Play runs the full light show — animations fire on the ESP32 in sync with the song — and the playhead advances visibly on the timeline
|
||||||
|
**Plans**: TBD
|
||||||
|
**UI hint**: yes
|
||||||
|
|
||||||
|
### Phase 4: Live Reactive + Spotify
|
||||||
|
**Goal**: Users can switch into live-reactive mode where beats drive LED animations in real time, and can optionally use Spotify as the audio source
|
||||||
|
**Depends on**: Phase 3
|
||||||
|
**Requirements**: LIVE-01, LIVE-02, SPT-01
|
||||||
|
**Success Criteria** (what must be TRUE):
|
||||||
|
1. User can switch from choreography mode to live-reactive mode without restarting the app, and LEDs respond to beats within 100ms of audio onset
|
||||||
|
2. User can adjust beat-detection sensitivity in the UI and see the effect immediately — more sensitive triggers fire on quieter transients, less sensitive ignores them
|
||||||
|
3. Spotify audio passes through the system audio pipeline and triggers beat-reactive animations the same way local file playback does
|
||||||
|
**Plans**: TBD
|
||||||
|
|
||||||
|
## Progress
|
||||||
|
|
||||||
|
**Execution Order:**
|
||||||
|
Phases execute in numeric order: 1 → 2 → 3 → 4
|
||||||
|
|
||||||
|
| Phase | Plans Complete | Status | Completed |
|
||||||
|
|-------|----------------|--------|-----------|
|
||||||
|
| 1. ESP32 Firmware | 4/4 | Complete | 2026-04-03 |
|
||||||
|
| 2. App Core + Audio | 0/6 | Not started | - |
|
||||||
|
| 3. Choreography TUI | 0/? | Not started | - |
|
||||||
|
| 4. Live Reactive + Spotify | 0/? | Not started | - |
|
||||||
@@ -2,15 +2,15 @@
|
|||||||
gsd_state_version: 1.0
|
gsd_state_version: 1.0
|
||||||
milestone: v1.0
|
milestone: v1.0
|
||||||
milestone_name: milestone
|
milestone_name: milestone
|
||||||
status: verifying
|
status: executing
|
||||||
stopped_at: Phase 2 planned
|
stopped_at: Completed 02-app-core-audio-02-PLAN.md
|
||||||
last_updated: "2026-04-03T12:14:38.770Z"
|
last_updated: "2026-04-03T12:21:05.248Z"
|
||||||
last_activity: 2026-04-03
|
last_activity: 2026-04-03
|
||||||
progress:
|
progress:
|
||||||
total_phases: 4
|
total_phases: 4
|
||||||
completed_phases: 1
|
completed_phases: 1
|
||||||
total_plans: 10
|
total_plans: 10
|
||||||
completed_plans: 4
|
completed_plans: 5
|
||||||
percent: 0
|
percent: 0
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -21,13 +21,13 @@ progress:
|
|||||||
See: .planning/PROJECT.md (updated 2026-04-03)
|
See: .planning/PROJECT.md (updated 2026-04-03)
|
||||||
|
|
||||||
**Core value:** Songs mit LED-Animationen choreografieren und abspielen — der Nutzer baut Timeline-basierte Lichtshows zu seiner Musik.
|
**Core value:** Songs mit LED-Animationen choreografieren und abspielen — der Nutzer baut Timeline-basierte Lichtshows zu seiner Musik.
|
||||||
**Current focus:** Phase 01 — esp32-firmware
|
**Current focus:** Phase 02 — app-core-audio
|
||||||
|
|
||||||
## Current Position
|
## Current Position
|
||||||
|
|
||||||
Phase: 2
|
Phase: 02 (app-core-audio) — EXECUTING
|
||||||
Plan: Not started
|
Plan: 2 of 6
|
||||||
Status: Phase complete — ready for verification
|
Status: Ready to execute
|
||||||
Last activity: 2026-04-03
|
Last activity: 2026-04-03
|
||||||
|
|
||||||
Progress: [░░░░░░░░░░] 0%
|
Progress: [░░░░░░░░░░] 0%
|
||||||
@@ -58,6 +58,7 @@ Progress: [░░░░░░░░░░] 0%
|
|||||||
| Phase 01-esp32-firmware P03 | 14 | 2 tasks | 11 files |
|
| Phase 01-esp32-firmware P03 | 14 | 2 tasks | 11 files |
|
||||||
| Phase 01-esp32-firmware P04 | 5 | 1 tasks | 2 files |
|
| Phase 01-esp32-firmware P04 | 5 | 1 tasks | 2 files |
|
||||||
| Phase 01-esp32-firmware P04 | 5 | 2 tasks | 2 files |
|
| Phase 01-esp32-firmware P04 | 5 | 2 tasks | 2 files |
|
||||||
|
| Phase 02-app-core-audio P02 | 4min | 1 tasks | 4 files |
|
||||||
|
|
||||||
## Accumulated Context
|
## Accumulated Context
|
||||||
|
|
||||||
@@ -82,6 +83,7 @@ Recent decisions affecting current work:
|
|||||||
- [Phase 01-esp32-firmware]: initAnimationEngine() called before WiFi.begin() so startup breathing animation is visible during WiFi connect (D-11)
|
- [Phase 01-esp32-firmware]: initAnimationEngine() called before WiFi.begin() so startup breathing animation is visible during WiFi connect (D-11)
|
||||||
- [Phase 01-esp32-firmware]: WIFI_PS_NONE re-applied on WiFi reconnect to prevent RMT flicker after disconnect/reconnect cycle
|
- [Phase 01-esp32-firmware]: WIFI_PS_NONE re-applied on WiFi reconnect to prevent RMT flicker after disconnect/reconnect cycle
|
||||||
- [Phase 01-esp32-firmware]: Hardware acceptance test approved — all 5 FW requirements (FW-01 through FW-05) validated on physical ESP32-C3 SuperMini with both LED strips
|
- [Phase 01-esp32-firmware]: Hardware acceptance test approved — all 5 FW requirements (FW-01 through FW-05) validated on physical ESP32-C3 SuperMini with both LED strips
|
||||||
|
- [Phase 02-app-core-audio]: asyncio DatagramProtocol with fire-and-forget sendto() for ESP32 UDP transport (D-10); v:1 injected by transport layer; connected state via STATUS ok only (D-12)
|
||||||
|
|
||||||
### Pending Todos
|
### Pending Todos
|
||||||
|
|
||||||
@@ -96,6 +98,6 @@ None yet.
|
|||||||
|
|
||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-04-03T12:14:38.756Z
|
Last session: 2026-04-03T12:21:05.236Z
|
||||||
Stopped at: Phase 2 planned
|
Stopped at: Completed 02-app-core-audio-02-PLAN.md
|
||||||
Resume file: .planning/phases/02-app-core-audio/02-01-PLAN.md
|
Resume file: None
|
||||||
|
|||||||
135
.planning/phases/02-app-core-audio/02-02-SUMMARY.md
Normal file
135
.planning/phases/02-app-core-audio/02-02-SUMMARY.md
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
---
|
||||||
|
phase: 02-app-core-audio
|
||||||
|
plan: "02"
|
||||||
|
subsystem: transport
|
||||||
|
tags: [asyncio, udp, esp32, datagram-protocol, json, led-control]
|
||||||
|
|
||||||
|
# Dependency graph
|
||||||
|
requires:
|
||||||
|
- phase: 01-esp32-firmware
|
||||||
|
provides: "UDP JSON protocol spec (docs/protocol.md) — port 4210, v:1 commands, STATUS response format"
|
||||||
|
provides:
|
||||||
|
- "ESP32Transport: asyncio.DatagramProtocol for fire-and-forget UDP JSON commands to ESP32"
|
||||||
|
- "create_esp32_transport(): async factory coroutine returning ready ESP32Transport"
|
||||||
|
- "Connection state tracking (connected/disconnected) via STATUS ok responses"
|
||||||
|
- "led_sync.transport package with clean re-exports"
|
||||||
|
affects: [02-04-scheduler, 02-05-repl, 03-tui]
|
||||||
|
|
||||||
|
# Tech tracking
|
||||||
|
tech-stack:
|
||||||
|
added: [pytest-asyncio>=0.23]
|
||||||
|
patterns:
|
||||||
|
- "asyncio.DatagramProtocol for non-blocking UDP fire-and-forget"
|
||||||
|
- "v:1 protocol version injected by transport layer, not callers"
|
||||||
|
- "TDD red-green cycle for protocol-critical transport behavior"
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created:
|
||||||
|
- src/led_sync/transport/__init__.py
|
||||||
|
- src/led_sync/transport/udp_client.py
|
||||||
|
- tests/test_transport.py
|
||||||
|
modified:
|
||||||
|
- pyproject.toml
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "D-10: asyncio DatagramProtocol, fire-and-forget sendto() — no blocking anywhere in send path"
|
||||||
|
- "D-11: send_status_ping() for optional heartbeat, non-blocking"
|
||||||
|
- "D-12: connected=True set only upon STATUS ok response, not upon socket bind"
|
||||||
|
- "D-14: Minimal error handling — silent drop on oversized payload, malformed JSON, pre-connection calls"
|
||||||
|
- "Protocol version v:1 injected by send_command(), callers never need to include it"
|
||||||
|
|
||||||
|
patterns-established:
|
||||||
|
- "Pattern 1: asyncio.DatagramProtocol subclass for ESP32 UDP transport (fire-and-forget, no awaits in send path)"
|
||||||
|
- "Pattern 2: Silent drop pattern — no exceptions from transport layer, only debug/warning logs"
|
||||||
|
- "Pattern 3: on_status callback for reactive STATUS response handling without polling"
|
||||||
|
|
||||||
|
requirements-completed: [CHR-05]
|
||||||
|
|
||||||
|
# Metrics
|
||||||
|
duration: 4min
|
||||||
|
completed: 2026-04-03
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 02 Plan 02: ESP32 UDP Transport Client Summary
|
||||||
|
|
||||||
|
**asyncio DatagramProtocol UDP client for ESP32 on port 4210 — fire-and-forget JSON commands with STATUS-based connection tracking**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
- **Duration:** 4 min
|
||||||
|
- **Started:** 2026-04-03T12:15:55Z
|
||||||
|
- **Completed:** 2026-04-03T12:19:45Z
|
||||||
|
- **Tasks:** 1 (TDD: test commit + feat commit)
|
||||||
|
- **Files modified:** 4
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
|
||||||
|
- ESP32Transport implements asyncio.DatagramProtocol with all protocol behaviors matching docs/protocol.md exactly
|
||||||
|
- send_command() injects v:1, enforces 512-byte limit, silently drops if pre-connection — all non-blocking
|
||||||
|
- STATUS ok responses parsed in datagram_received() to set connected=True and store last_status
|
||||||
|
- 15 unit tests covering all public behaviors including async factory and oversized payload drop
|
||||||
|
- create_esp32_transport() async factory sends initial STATUS ping for D-12 connection bootstrap
|
||||||
|
|
||||||
|
## Task Commits
|
||||||
|
|
||||||
|
1. **RED — Failing tests for ESP32Transport** - `f10fcf0` (test)
|
||||||
|
2. **GREEN — ESP32Transport implementation** - `378620e` (feat)
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
- `src/led_sync/transport/udp_client.py` — ESP32Transport class + create_esp32_transport() factory
|
||||||
|
- `src/led_sync/transport/__init__.py` — Package marker, re-exports ESP32Transport and create_esp32_transport
|
||||||
|
- `tests/test_transport.py` — 15 unit tests covering all protocol behaviors
|
||||||
|
- `pyproject.toml` — Added pytest-asyncio to dev deps, asyncio_mode=auto
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
- Protocol version field v:1 is injected by send_command() — callers never include it (cleaner downstream API)
|
||||||
|
- on_status callback parameter in ESP32Transport constructor and create_esp32_transport() factory for reactive status handling without polling
|
||||||
|
- Silent drop on pre-connection and oversized payload (no exceptions) matches D-14 fire-and-forget philosophy
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
### Auto-fixed Issues
|
||||||
|
|
||||||
|
**1. [Rule 3 - Blocking] Added pytest-asyncio dependency for async test support**
|
||||||
|
- **Found during:** Task 1 (TDD RED phase)
|
||||||
|
- **Issue:** Tests use `@pytest.mark.asyncio` but pytest-asyncio was not in pyproject.toml dev deps; test would fail with UnknownMarkWarning and no async test support
|
||||||
|
- **Fix:** `uv add --dev pytest-asyncio` and added `asyncio_mode = "auto"` in `[tool.pytest.ini_options]`
|
||||||
|
- **Files modified:** pyproject.toml, uv.lock
|
||||||
|
- **Verification:** All 15 tests pass including async factory test
|
||||||
|
- **Committed in:** 378620e (Task 1 GREEN commit)
|
||||||
|
|
||||||
|
**2. [Rule 3 - Blocking] Discovered pyproject.toml and led_sync package already existed**
|
||||||
|
- **Found during:** Task 1 setup
|
||||||
|
- **Issue:** Plan 02-01 (scaffold) has not been committed to git yet, but the pyproject.toml and src/led_sync/ structure already existed on disk from a previous partial execution
|
||||||
|
- **Fix:** Worked with existing files; only added transport package and pytest-asyncio
|
||||||
|
- **Files modified:** None (existing structure was sufficient)
|
||||||
|
- **Verification:** `uv run python -c "from led_sync.transport import create_esp32_transport"` exits 0
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Total deviations:** 2 auto-fixed (2x Rule 3 blocking)
|
||||||
|
**Impact on plan:** Both fixes necessary for test infrastructure and working with existing project state. No scope creep.
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
|
||||||
|
None beyond the deviations documented above.
|
||||||
|
|
||||||
|
## User Setup Required
|
||||||
|
|
||||||
|
None — no external service configuration required.
|
||||||
|
|
||||||
|
## Next Phase Readiness
|
||||||
|
|
||||||
|
- `from led_sync.transport import create_esp32_transport` is importable and ready for use
|
||||||
|
- Scheduler (02-04) and REPL (02-05) can depend on `transport.send_command(dict)` and `transport.connected` interfaces
|
||||||
|
- Transport is fully tested with 15 unit tests covering all edge cases
|
||||||
|
|
||||||
|
## Self-Check: PASSED
|
||||||
|
|
||||||
|
All created files verified present. Both commits (f10fcf0, 378620e) confirmed in git log.
|
||||||
|
|
||||||
|
---
|
||||||
|
*Phase: 02-app-core-audio*
|
||||||
|
*Completed: 2026-04-03*
|
||||||
Reference in New Issue
Block a user