Commit Graph
14 Commits
Author SHA1 Message Date
jpmschweitzerandClaude ff193203c9 refactor: merge the component Makefiles into one at the root
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
desklock is a three-component repo and only the gateway had a Makefile, so
make test meant "the gateway suite" or "no such target" depending on which
directory you happened to be standing in. One root Makefile makes it mean the
same thing everywhere (D-27), and gateway/Makefile is removed rather than
delegated to, so there is one place to look.

The firmware targets now source ~/esp-idf/export.sh themselves. Verified that
idf.py does not resolve on PATH without it and does after — the same class of
failure that has cost time on four other tools on this host, and the reason
D-10 puts path resolution in the Makefile rather than in callers. They fail
loudly with a hint when the toolchain is absent instead of reporting command
not found.

make test never reports green for the firmware. It has no suite, so it prints
undetermined rather than skipping silently — a no-op target that exits 0 would
claim a pass for something never run (D-26).

Verified: make test runs the real 9-test gateway suite, make lint passes, the
missing-toolchain guard fires, and make help lists every target. The firmware
build itself was not run.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-09 15:03:58 +02:00
jpmschweitzerandClaude Fable 5 7c7ce1541c release v0.2.2
Test, Build and Push / test-gateway (push) Successful in 9s
Test, Build and Push / release (push) Successful in 3s
Test, Build and Push / build-gateway (push) Successful in 48s
Network migration: the gateway's default Tatlock URL is now the docker
container name (http://tatlock:8000); the retiring tatlock.schweitz.internal
domain is gone from config and docs. Deployments that set
DESKLOCK_TATLOCK_BASE_URL are unaffected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 12:32:13 +02:00
jpmschweitzerandClaude Fable 5 014c86f51e chore(gateway): drop schweitz.internal, default to http://tatlock:8000
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
The homelab is retiring the *.schweitz.internal domain; in-network
machine-to-machine traffic uses docker container names on the
docker-dataplane network. The deployed tatlock-ui stack already overrides
DESKLOCK_TATLOCK_BASE_URL (Tatlock runs on the host), so only the
fallback default changes.

Docs follow: AGENTS.md M2M guidance now points at container names with
*.schweitz.net reserved for browsers, architecture.md drops the retired
domain (the registry name now matches what CI actually pushes since
c477019), and the README diagram loses the stale hostname.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 12:22:25 +02:00
jpmschweitzerandClaude Opus 4.8 ccb46d45b4 release v0.2.1
Test, Build and Push / test-gateway (push) Successful in 11s
Test, Build and Push / release (push) Successful in 2s
Test, Build and Push / build-gateway (push) Successful in 1m27s
Fixes: volume voice command no longer hangs in the thinking spinner (gong
stops holding the busy state), and the butler filler is reworded to avoid
a text-to-speech mid-phrase pause.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LKPbR6DY2JygHbyLjxm7Uu
2026-07-15 22:39:46 +02:00
jpmschweitzerandClaude Opus 4.8 9a62233775 fix(gateway): reword butler filler to avoid a TTS mid-phrase pause
Kokoro inserts an unnatural ~0.2s pause before "for you", so "Let me check
on that for you, sir." came out as two phrases. Reword to "Let me check on
that, sir." — same intent, clean pacing (measured: no internal silence gap).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LKPbR6DY2JygHbyLjxm7Uu
2026-07-15 22:39:03 +02:00
jpmschweitzerandClaude Opus 4.8 e3021baf4d release v0.2.0
Test, Build and Push / test-gateway (push) Successful in 10s
Test, Build and Push / release (push) Successful in 3s
Test, Build and Push / build-gateway (push) Successful in 1m48s
Volume goes to eleven (0–11 scale, gong feedback, mute), a voice command
service that handles volume/mute without the LLM, and an immediate butler
filler line with a spinner during the Tatlock wait.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LKPbR6DY2JygHbyLjxm7Uu
2026-07-15 21:32:31 +02:00
jpmschweitzerandClaude Opus 4.8 09f8afcadd feat(gateway): butler filler line while Tatlock works
Tatlock turns take 10-25s, which is a long silence after a request. Speak
a canned "Let me check on that for you, sir" immediately (synthesized once
and cached), then re-assert the thinking state so the device keeps its
effort-face spinner up until the real reply arrives. On the device, guard
the playback-done handler so the filler audio finishing doesn't drop the
spinner back to idle.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LKPbR6DY2JygHbyLjxm7Uu
2026-07-15 21:29:35 +02:00
jpmschweitzerandClaude Opus 4.8 6b7fbb60c9 feat(gateway): voice command service
Recognize simple device commands in the transcript and act on them without
a Tatlock round-trip. commands.match() maps volume up/down, mute/unmute,
"set volume to N", and "goes to eleven"/max to a "command" message sent
straight to the device; the utterance never reaches the LLM. Matching is
deliberately precise so real requests ("set an alarm for a quarter to
eleven") are not hijacked. Adds the "command" message to the device
protocol in docs/architecture.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LKPbR6DY2JygHbyLjxm7Uu
2026-07-15 21:29:00 +02:00
jpmschweitzerandClaude Fable 5 395e05343d gateway: handle websocket.disconnect in receive loop
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
Stops the RuntimeError spam ('Cannot call receive once a disconnect
message has been received') every time the device's watchdog reboots.
Redeployed to the tatlock-ui stack.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 02:29:10 +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 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 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