- SUMMARY.md with protocol schema documentation for Phase 2 Pi-side reference - STATE.md: advanced to plan 4/4, progress 50%, decisions logged - ROADMAP.md: phase 1 updated (2/4 summaries complete) - REQUIREMENTS.md: FW-02 and FW-05 marked complete
7.4 KiB
7.4 KiB
phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, duration, completed
| phase | plan | subsystem | tags | requires | provides | affects | tech-stack | key-files | key-decisions | patterns-established | requirements-completed | duration | completed | ||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 01-esp32-firmware | 02 | firmware |
|
|
|
|
|
|
|
|
|
3min | 2026-04-03 |
Phase 01 Plan 02: UDP Command Receiver and JSON Protocol Parser Summary
AsyncUDP listener with two-queue FreeRTOS pattern — raw bytes via xQueueSendFromISR, JSON deserialized in parseTask, LedCommand structs dispatched to commandQueue for animation engine
Performance
- Duration: 3 min
- Started: 2026-04-03T11:22:48Z
- Completed: 2026-04-03T11:25:43Z
- Tasks: 2
- Files modified: 5
Accomplishments
- Full protocol type system: LedCommand, AnimParams, Zone, CmdType enums with all fields from interface spec
- parseCommand() implements version check (v:1), zone routing (schrank/wand/all), full animation params parsing including RGBW color arrays
- wifi_server.cpp uses the two-queue pattern from RESEARCH.md Pattern 2: AsyncUDP callback never parses JSON, only copies bytes via xQueueSendFromISR
- STATUS command handled immediately in parseTask with UDP reply to sender — no animation engine needed
- main.cpp updated to call startUdpServer() after WIFI_PS_NONE
Protocol Schema (for Phase 2 Pi-side reference)
UDP Port: 4210
Animation command:
{"v":1, "zone":"schrank"|"wand"|"all", "animation":"chase", "params":{"speed":0.5, "intensity":1.0, "direction":0, "colors":[[255,0,0,0]]}}
Stop command:
{"v":1, "cmd":"stop", "zone":"schrank"|"wand"|"all"}
Brightness command:
{"v":1, "cmd":"brightness", "zone":"schrank"|"wand"|"all", "value":40}
Valid range: 0-60 (firmware clamps to 60 max per D-09).
Status command:
{"v":1, "cmd":"status"}
Response: {"v":1, "status":"ok", "wand":"chase", "schrank":"breathe", "brightness":40}
Protocol rules:
- Every command must include
"v":1version field (D-08) - Zone field mandatory for ANIMATION, STOP, BRIGHTNESS commands
- Unknown extra fields silently ignored (D-07)
- Malformed JSON logged to Serial, packet dropped — no UDP error response (D-07)
- Colors array format:
[[R,G,B,W], ...](up to 8 RGBW tuples) - Default color when params.colors absent:
[255,255,255,255](warm white)
commandQueue Location (for Plan 03)
// In firmware/src/wifi_server.h:
extern QueueHandle_t commandQueue; // declare to consume
// In firmware/src/wifi_server.cpp:
QueueHandle_t commandQueue; // definition
// Plan 03 includes:
#include "wifi_server.h" // access commandQueue
Queue depth: 8 LedCommand structs. Plan 03 animation engine reads from this queue.
Task Commits
Each task was committed atomically:
- Task 1: protocol.h/.cpp — JSON parsing into LedCommand -
3323a87(feat) - Task 2: wifi_server.h/.cpp — AsyncUDP listener with FreeRTOS queue -
230be99(feat)
Files Created/Modified
firmware/src/protocol.h- LedCommand, AnimParams, Zone, CmdType types; parseCommand() and buildStatusResponse() declarationsfirmware/src/protocol.cpp- parseCommand() implementation with ArduinoJson v7; buildStatusResponse() using serializeJson()firmware/src/wifi_server.h- commandQueue extern declaration; startUdpServer() declarationfirmware/src/wifi_server.cpp- RawPacket struct; rawQueue + commandQueue creation; AsyncUDP callback (ISR-safe); parseTask FreeRTOS taskfirmware/src/main.cpp- Added wifi_server.h include; startUdpServer() call after WIFI_PS_NONE
Decisions Made
- Two-queue pattern chosen: AsyncUDP callback only copies bytes via xQueueSendFromISR, separate parseTask handles JSON. This is mandatory — JSON heap allocation in WiFi task callback causes watchdog resets.
- STATUS command fully handled in parseTask without routing through commandQueue — it needs sender IP/port from the raw packet context, and doesn't need the animation engine.
- Brightness clamped in parseCommand() to enforce D-09 hardware safety cap (max 60%).
- Zone field treated as optional only for STATUS command; required for all other commands with explicit Serial log and packet drop if missing.
Deviations from Plan
None — plan executed exactly as written.
Issues Encountered
- animation_engine.h/.cpp and animations/animation_base.h were present as untracked files (pre-created scaffold) and were included in Task 2's commit. These belong to Plan 03 scope but their presence does not harm Plan 02 — they will be naturally used in Plan 03. No functional impact on this plan's deliverables.
Known Stubs
- buildStatusResponse() in parseTask uses hardcoded "unknown"/"unknown"/40 for wand/schrank animation names and brightness. These will be wired to actual ZoneState in Plan 03 when the animation engine has live state. Plan 03 must update this call.
Next Phase Readiness
- Plan 03 (animation engine) can immediately consume commandQueue via
#include "wifi_server.h"andextern QueueHandle_t commandQueue - LedCommand struct is the complete data contract — animation engine reads CmdType, Zone, animName, AnimParams
- Protocol schema above is the definitive reference for Phase 2 Pi-side transport implementation
Phase: 01-esp32-firmware Completed: 2026-04-03