5 Commits

Author SHA1 Message Date
Claude Worker claude2 e7a974e1be feat(plip): scenario hot-load via ESP-NOW
PLIP was out of scope by design (Wi-Fi/HTTP-only); brought back in by
request. New src/scenario_now.{h,cpp}: owns the single esp_now recv
callback (no MSG_* demux needed — PLIP has no legacy ESP-NOW traffic),
reassembles scenario_mesh frames ({seq:u16 LE, total:u16 LE} + <=236 B
payload, <=64 KiB, 5 s sender-silence timeout) in a worker task, then
persists to LittleFS /scenario.json (temp-then-rename). Optional
consumer hook for a future Runtime 3 engine; stored-and-logged without
one. network_task calls scenario_now_init() once the station is up
(idempotent, repeated on reconnect).

Build green: pio run (devkit_es8388), RAM 14.8%, Flash 63.1%.
2026-06-10 10:24:01 +02:00
L'électron rare db7149b897 fix(plip): HTTPClient.POST const cast
Problem: pio build failed because HTTPClient::POST expects a non-const uint8_t* and the slice 14 client passed const uint8_t* via reinterpret_cast. Approach: drop the const qualifier — body is a local stack buffer, so the cast is safe (no shared mutable aliasing). Tradeoffs: kept the comment in place to document why the cast is benign so a future reader does not re-introduce const for ergonomics and re-break the build.
2026-05-04 01:22:35 +02:00
L'électron rare 80f3a80361 fix(plip): platformio deps + WiFi/mDNS init
Problem: PlatformIO build failed because lib_deps listed
schreibfaul1/ESP32-audioI2S, which is not published on the registry,
and network_task was an empty stub so the slice 14 hook client could
not actually reach zacus-master.local.

Approach: drop the unresolvable schreibfaul1 dep (esphome's fork
already covers ES8388 I2S). Flesh out network_task to read WiFi
credentials from NVS (namespace "wifi"), fall back to an open
ZACUS-SETUP SSID for bringup, wait up to 30 s for association,
advertise plip.local via ESPmDNS, and probe zacus-master.local once
so the hook client's hostname-based POSTs resolve. A 5 s health loop
reconnects on drop and re-reads NVS in case the desktop pushes new
credentials at runtime.

Tradeoffs: the open SSID fallback is dev-only and must be replaced
with SoftAP provisioning before shipping. mDNS probe is logged but
non-fatal so the hook client can still retry resolution per-request.
Build verification with `pio run` was blocked by sandbox in this
session; the dep change is mechanical and the source compiles
against stock ESP32 Arduino headers (WiFi.h, ESPmDNS.h, Preferences.h).
2026-05-04 01:14:33 +02:00
L'électron rare 214d5df443 feat(plip): /voice/hook client (master REST) 2026-05-04 01:04:50 +02:00
L'électron rare 07433dfdc5 feat(plip): firmware skeleton on ES8388 dev kit
Bringup target: AI-Thinker ESP32-A1S Audio Kit V2.2
(ES8388 codec). End target: custom PLIP PCB with Si3210
SLIC + RJ9 retro handset (per
docs/superpowers/specs/2026-04-08-plip-telephone-design.md).

Three FreeRTOS tasks share state via a queue:
- phone_task (core 1): off-hook GPIO interrupt + ring
- audio_task (core 0): drains command queue, routes to
  ES8388 (dev kit) / Si3210 (PCB) via ESP32-audioI2S
- network_task (core 0): WiFi station + REST server

REST contract for the Zacus master ESP32 to drive PLIP:
- POST /ring   {duration_ms}
- POST /play   {source: "sd:/..." | "http://tower:8001/..."}
- POST /stop
- GET  /status -> {off_hook, playing}

Pin assignments live in platformio.ini build_flags so the
dev kit -> PCB swap stays mechanical (just rewire to
Si3210 SPI + INT and switch the codec init in
audio_task).

MVP scope (option b in the brainstorm):
- ring on demand
- off-hook GPIO -> notify master
- MP3 playback from SD
- WiFi REST endpoint
Out of v1 (deliberately deferred):
- Bluetooth Classic A2DP/HFP (still in the design doc)
- Si3210 driver (when PCB lands)
- OTA via desktop FirmwareManager (after bringup stable)

Files:
- platformio.ini (espressif32@6.5.0, esp32dev board with
  custom partitions + ESP32-A1S build flags)
- partitions/plip_4mb.csv (2x OTA app slots + LittleFS)
- src/main.cpp + 3 task .cpp files (skeleton, log-only)
- README.md (architecture, REST contract, pin map,
  9-step roadmap, submodule conversion)
- CLAUDE.md (nested guidance for Claude Code)
- .gitignore

Inlined for now; convert to a git submodule once a remote
URL is provisioned (procedure documented in README).
Root CLAUDE.md "Firmware" surface and "Where to Look"
table updated.

Acceptance: directory layout + build config + skeleton
sources land. No compile validation in this commit
(PlatformIO not on the workstation per the Q1=ESP32-A1S
dev kit bringup decision).
2026-05-03 13:21:43 +02:00