Commit Graph
18 Commits
Author SHA1 Message Date
jpmschweitzerandClaude Fable 5 e5c8a38f94 Stability round 2: WIFI_PS_NONE + 10MHz SDIO
Test, Build and Push / test-gateway (push) Successful in 10s
Test, Build and Push / release (push) Skipped
Test, Build and Push / build-gateway (push) Skipped
1-bit bus alone did not stop the sdio_write timeout wedge (recurred
at ~5min uptime). Modem power save is the new prime suspect: the C6
napping mid-SDIO-transaction matches the minutes-scale periodicity.
Always-powered appliance -> PS_NONE costs ~50mW and removes the
entire failure class if correct. SDIO clock also halved to 10MHz.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 01:29:33 +02:00
jpmschweitzerandClaude Fable 5 7943e0e72a 1-bit SDIO to kill the wedge-reboot loop; gong on cold boot only
Test, Build and Push / test-gateway (push) Successful in 10s
Test, Build and Push / release (push) Skipped
Test, Build and Push / build-gateway (push) Skipped
Night-watch caught the instability in the act at 7min uptime:
  E H_SDIO_DRV: sdio_write_task: Failed to send data: 258 (timeout)
  E H_SDIO_DRV: Unrecoverable host sdio state -> SW_CPU_RESET
i.e. esp-hosted-mcu#167. Known mitigation: 1-bit SDIO bus (#148),
still ~80x voice bandwidth. Also: recovery reboots no longer ring
the gong (esp_reset_reason gate) - a butler doesn't bong at 3am.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 01:19:52 +02:00
jpmschweitzerandClaude Fable 5 b8974ec84f Wi-Fi data path FIXED: esp_hosted 2.12 on both chips + C6 SDIO auto-OTA
Test, Build and Push / test-gateway (push) Successful in 10s
Test, Build and Push / release (push) Skipped
Test, Build and Push / build-gateway (push) Skipped
Root cause of the dead data path (assoc/scan/RPC fine, zero data
frames): esp-hosted 1.4.x is formally incompatible with IDF 5.5
(esp-hosted-mcu#47) and the factory C6 slave firmware was ancient
(couldn't even answer a version RPC). Waveshare's examples pin 1.4.* —
do not follow them.

Fix:
- host: espressif/esp_hosted ^2.12 (+ esp_wifi_remote 1.6)
- slave: 2.12.11 network_adapter.bin embedded in the app (c6_ota.c
  streams it to the C6 over the SDIO RPC channel at boot when the
  reported version is < 2.x; ~10s, no wires, idempotent)
- RAM diet for hosted 2.x's footprint (MEMPOOL_PREFER_SPIRAM,
  reduced WIFI_RMT buffers) — without it internal SRAM famine
  boot-loops in xTaskCreateStaticPinnedToCore before app_main
- conservative 20MHz SDIO clock for first verified data path

Verified on hardware: DHCP lease (even that healed), 8/8 pings to
router and tower-of-joy at 1-5ms, WebSocket to the gateway connected,
device registered at /devices as desklock-p4 with fw version.

Also: wifi_diag.c L1 SoftAP diagnostic mode (DESKLOCK-DIAG) with
review fixes, boot ping ladder in net.c, static-IP fallback,
face_status() line, docs for the whole failure taxonomy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 00:26:28 +02:00
jpmschweitzerandClaude Fable 5 3a402220b0 Device registry (/devices + hello), static-IP fallback, WS keepalive, uncompressed fonts
Test, Build and Push / test-gateway (push) Successful in 11s
Test, Build and Push / release (push) Skipped
Test, Build and Push / build-gateway (push) Skipped
- gateway: GET /devices registry (per-IP connect count, timestamps,
  device/fw from new 'hello' protocol event); graceful utterance
  errors -> error event; uvicorn ws-ping-timeout 120s
- firmware: hello on WS connect; static 192.168.86.53 fallback after
  15s without DHCP; scan-on-boot removed (kept for diagnostics);
  ping_interval 8s; fonts regenerated --no-compress (compressed
  glyphs render blank with LV_USE_FONT_COMPRESSED off); 8MB factory
  partition; montserrat_28; LVGL lock timeout semantics fixed
- docs: sauron endpoint plan, power ladder, versioning policy

Known issue: 'Outside' AP association succeeds but no L2 traffic
flows (no DHCP, no ARP) — worked once at 22:05 then never again;
ToJ side verified clean. Investigation ongoing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 22:34:57 +02:00
jpmschweitzerandClaude Fable 5 ed0e8221f1 Phase 2: full LVGL face + Wi-Fi + gateway WebSocket + touch-to-talk
Test, Build and Push / test-gateway (push) Successful in 10s
Test, Build and Push / release (push) Skipped
Test, Build and Push / build-gateway (push) Skipped
The device now runs the complete face contract on glass: seven states
with glyph expressions (custom 140px face font), matrix rain as pooled
label streams (22px DejaVu+Noto katakana font), rage kaomoji frames
(64px), orbit arc + elapsed counter wait cues, blink/talk/thought
animations, idle clock (SNTP, Europe/Amsterdam), and the power ladder
(active/ambient 35%/dormant 5% with rain parked).

Voice path: ES7210 mic capture task streams 16k PCM over
esp_websocket_client to the gateway; reply PCM buffers to PSRAM and
plays via the audio task; touch-to-talk (tap to speak, tap to send).
Protocol mapping per docs: thinking->effort, audio->speaking,
error event->rage (auto-composes after 2 loops), WS loss->error face.

Bring-up fixes: 8MB factory partition (fonts overflowed 1.5M),
bsp_display_lock(0) is try-lock in this adapter (use UINT32_MAX),
gong synth yields to feed IDLE0, wifi scan diagnostics (found SSID
case mismatch), esp_websocket_client pinned ~1.3 (1.4 needs IDF>5.5).

Verified on hardware: boots, connects to Wi-Fi and holds an open
WebSocket to the gateway. Sauron (iMac TTY endpoint + ops console)
planned in architecture.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 21:42:51 +02:00
jpmschweitzerandClaude Fable 5 ae9f6e0abb Approved gong voicing: 220Hz fundamental, fatter mids, -7dBFS at vol 75
Test, Build and Push / test-gateway (push) Successful in 11s
Test, Build and Push / release (push) Skipped
Test, Build and Push / build-gateway (push) Skipped
User verdict: audible and butler-non-intrusive on the bare 2W speaker.
Recorded as the house sound signature in architecture.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 20:44:30 +02:00
jpmschweitzerandClaude Fable 5 bfe792f006 Replace beeps with a cathedral gong
Test, Build and Push / test-gateway (push) Successful in 10s
Test, Build and Push / release (push) Skipped
Test, Build and Push / build-gateway (push) Skipped
Additive gong synthesis: seven inharmonic partials with per-partial
decay (fundamental 165Hz rings 2.6s, highs die in 0.2s), a detuned
pair for shimmer, 45ms distant attack, and three feedback-comb
reflections (95/210/370ms, net gain .93) for a dense stone-space tail.
Normalized to -12dBFS at codec volume 58: quiet but voluminous.
Synthesized into PSRAM at boot (~4s), plays 5s, blocking is fine for
bring-up — audio moves to its own task in phase 2.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 20:41:02 +02:00
jpmschweitzerandClaude Fable 5 60c73e135c Boot chime through ES8311: audio-out path verified on hardware
Test, Build and Push / test-gateway (push) Successful in 10s
Test, Build and Push / release (push) Skipped
Test, Build and Push / build-gateway (push) Skipped
C5->E5 half-second chime with fade-out at boot, right after the face
renders. Codec opens in slave mode, esp_codec_dev write path works.
Phase 1 bring-up is now complete: display, touch, audio, 200MHz PSRAM.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 20:34:59 +02:00
jpmschweitzerandClaude Fable 5 450bac1c81 First successful flash: placeholder face live; fix 20MHz PSRAM trap; power ladder
Test, Build and Push / test-gateway (push) Successful in 10s
Test, Build and Push / release (push) Skipped
Test, Build and Push / build-gateway (push) Skipped
- firmware boots to a rendered LVGL face in 1.57s (eyes + smile + tag)
- sdkconfig: CONFIG_IDF_EXPERIMENTAL_FEATURES=y unlocks SPIRAM 200MHz
  (silently degraded to 20MHz before -> MIPI-DSI underrun -> LVGL lock
  starvation -> task watchdog); mirrors official 08_lvgl_demo_v9 config
- architecture.md: power management section (user prime concern) —
  active/ambient/dormant/night ladder, levers, hard edges, <=300ms wake
- AGENTS/CLAUDE: replace stale bring-up warnings with verified commands

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 20:31:25 +02:00
jpmschweitzerandClaude Fable 5 2d5cbd1174 Document versioning policy: 0.x per roadmap phase, 1.0.0 = wall milestone
Test, Build and Push / test-gateway (push) Successful in 10s
Test, Build and Push / release (push) Skipped
Test, Build and Push / build-gateway (push) Skipped
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 20:17:55 +02:00
jpmschweitzerandClaude Fable 5 550db5a0ef CI: use WATCHTOWER_HTTP_API_TOKEN secret name as set on the repo
Test, Build and Push / test-gateway (push) Successful in 11s
Test, Build and Push / release (push) Skipped
Test, Build and Push / build-gateway (push) Skipped
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 20:04:29 +02:00
jpmschweitzerandClaude Fable 5 79d43ec199 Deployment home is the tatlock-ui Portainer stack, not a standalone file
Test, Build and Push / test-gateway (push) Successful in 10s
Test, Build and Push / release (push) Successful in 2s
Test, Build and Push / build-gateway (push) Failing after 8s
The gateway service now lives in system-admin-toj/containers/stacks/
tatlock-ui.yml (shared docker-dataplane network: speaches by service
name, host-run Tatlock by LAN IP). Drop deploy/desklock-gateway.yml.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v0.1.0
2026-07-14 19:08:50 +02:00
jpmschweitzerandClaude Fable 5 15b8a1b900 Strip Tatlock <think> reasoning before TTS and history
Test, Build and Push / test-gateway (push) Successful in 10s
Test, Build and Push / release (push) Skipped
Test, Build and Push / build-gateway (push) Skipped
Live smoke test showed /v1/chat/completions replies open with the
Steward's <think> block (Open WebUI convention) — without stripping,
the device would speak the internal monologue aloud.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 18:15:36 +02:00
jpmschweitzerandClaude Fable 5 22f00fda0f Drop audioop: request 16 kHz directly via Speaches sample_rate extension
Test, Build and Push / test-gateway (push) Successful in 33s
Test, Build and Push / release (push) Skipped
Test, Build and Push / build-gateway (push) Skipped
Settles the Python version question: floor >=3.11, no ceiling.
Container moves to python:3.13-slim, CI tests on 3.13. The embedded
Piper fallback resamples with numpy (already present via [speech]).
Verified with a live round trip at 16 kHz.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 18:13:58 +02:00
jpmschweitzerandClaude Fable 5 f5df5049db Add rage table-flip state; wire gateway to live Speaches; add CI pipeline
Test, Build and Push / test-gateway (push) Successful in 1m2s
Test, Build and Push / release (push) Skipped
Test, Build and Push / build-gateway (push) Skipped
- Face: new 'rage' state — 3-frame kaomoji loop (stare, flip the table,
  put it back) for in-flight request failures; 'error' stays the quiet
  persistent face for a dead link. Sim + artifact + design doc updated.
- Gateway: stt.py/tts.py are now pluggable backends. Default 'speaches'
  talks OpenAI-format HTTP to the live container on :8601
  (faster-whisper-small STT, Kokoro bm_george TTS with 24->16 kHz
  audioop resample); 'embedded' fallback kept behind the [speech] extra.
  Verified with a live TTS->STT round trip (warm: STT 0.27s, TTS 1.9s).
  Docker image is now slim (no CUDA/ML deps). Python pinned to 3.12
  (system 3.8 too old, audioop gone in 3.13).
- CI: .gitea/workflows/build.yml — lint+test on main pushes; on v* tags
  test, build gateway image, push to registry, release, and trigger
  Watchtower (tatlock pattern; needs REGISTRY_USER/REGISTRY_PASSWORD/
  WATCHTOWER_TOKEN secrets). Runtime stack in deploy/desklock-gateway.yml.
- architecture.md: measured speech latencies, deployed-Speaches status,
  CI & deployment section.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 17:54:30 +02:00
jpmschweitzerandClaude Fable 5 42b988b7ef Add face design: ASCII expressions + matrix rain simulator, wait cues, fresh latency numbers
- sim/face/index.html: browser simulator of the 800x800 round panel with
  six states (idle/listening/pensive/effort/speaking/error), state-driven
  rain density, blink/talk/thought animations, idle clock
- effort state gets hard-required wait cues: orbiting bezel arc, elapsed
  counter, max rain (Tatlock turns run 10-25s)
- rain driven by setInterval, not rAF: renders under the screenshot
  tool's --virtual-time-budget and mirrors LVGL lv_timer
- architecture.md: Face design contract (state table, protocol mapping,
  LVGL port notes) + latency table updated to GPU-era benchmarks
  (Steward ~6s warm, full flow 11-25s; old CPU-era figures retired)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 17:32:16 +02:00
jpmschweitzerandClaude Fable 5 0886c84d5e Document Speaches speech layer, on-device processing limits, latency constraints
- STT/TTS move to a shared Speaches container (OpenAI-format, GPU, port
  8601 proposed); gateway becomes a thin orchestrator with pluggable
  speech backends (speaches default, embedded fallback)
- Record the on-device ceiling: WakeNet wake word, VAD, ES7210 AEC,
  optional MultiNet fixed commands; open-vocabulary STT permanently out
- Record the real latency bottleneck (Tatlock ~2 min full local flow):
  gateway must stream chat tokens and synthesize sentence-by-sentence
- Plan reply_delta + barge-in protocol additions

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 17:14:44 +02:00
jpmschweitzerandClaude Fable 5 576fd7d237 Initial scaffold: ESP32-P4 firmware + voice gateway for Tatlock endpoint
DeskLock gives the Tatlock butler a face and voice on a Waveshare
ESP32-P4-WIFI6-Touch-LCD-3.4C round display in the living room.

- firmware/: ESP-IDF project targeting esp32p4 with the Waveshare XC BSP
- gateway/: FastAPI voice bridge (faster-whisper STT, Tatlock chat, Piper TTS)
- docs/architecture.md: component design and device<->gateway WS protocol

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 16:58:59 +02:00