Bring the docs in line with the code

- python-backend/README: track analysis is implemented (2e0e6ad); the cache layout,
  the module table (lirc, screen, timers, podcasts, tippen) and the route table
  (track analysis, HA proxy, typing game) were missing pieces.
- docs/REPO_OVERVIEW: Mein Zimmer and the clock are implemented; Home Assistant is
  also reached over HTTP through the room page's proxy, not MQTT only; the IR remote,
  scripts/, the optional config sections and figure kind were not mentioned.
- web/README: the key table was the mockup's (Ctrl transport keys, TAB over 'all');
  ?pi=1 is now a preset with per-browser overrides, not a read-once flag; the room
  page and the typing game exist; eslint is part of the checks.
- Docstrings that described earlier designs: HaConfig (written as browser-direct in
  the same commit that built the proxy, a8ed350), services/__init__, events,
  playback, media, colors, tippen progress and AppHeader, lowPower.ts, and the
  'Hoerbuecher' spelling.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-04 00:28:37 +02:00
parent a0ac48ccbf
commit a737ccf108
12 changed files with 105 additions and 77 deletions

View File

@@ -20,7 +20,9 @@ Assistant integration.
| `web/` | React + TypeScript front-end (Vite). Browse the whole library and play any of it from a browser. Built output is served by `python-backend` itself. |
| `esp-firmware/` | ESP32 firmware (C++, Arduino framework via PlatformIO). Reads the RFID reader and buttons, drives the LED strips, talks to `python-backend` over serial. |
| `hardware/` | 3D-print models for the figurines and enclosure (FreeCAD/Blender/OBJ/STL), a Fritzing electronics sketch, datasheets, and `pinout.md` (RFID reader + button-board wiring). |
| `claude-design/` | The interaction and visual spec the web front-end was built from ("Dolphin Beats"), as a standalone HTML mockup with hardcoded data. `web/` is the real implementation; the mockup is kept as the reference for the keyboard model and the styling. It also contains a second page, "Mein Zimmer" (room lights), which is **not** implemented. |
| `claude-design/` | The interaction and visual specs the web front-end was built from, as standalone HTML mockups with hardcoded data: "Dolphin Beats" (the player), "Mein Zimmer" (the room page) and "Delphin Uhr" (the clock overlay). `web/` is the real implementation of all three; the mockups are kept as the reference for the keyboard model and the styling. |
| `scripts/` | `check.sh` (every check, see below) and `sync-library.sh` (seed a device's library and analysis cache). |
| `docs/` | This file. |
## How the pieces talk to each other
@@ -41,12 +43,18 @@ Assistant integration.
out of step with a figure someone puts on the reader. See
`python-backend/README.md` for the endpoint list.
- **`python-backend` ↔ Home Assistant**: MQTT only. The backend publishes three
discoverable lights, a player sensor, a volume number, transport buttons, device
triggers for every button and touch area, and a tag scanner for the RFID reader. It
does *not* call Home Assistant services directly any more; behaviour like "the left
ear turns the room light pink" is an HA automation. See `python-backend/README.md`
for the trigger topics and the old colour mapping.
- **`python-backend` ↔ Home Assistant**: two separate paths.
- MQTT, for the mouse itself. The backend publishes three discoverable lights, a
player sensor, a volume number, transport buttons, device triggers for every button
and touch area, and a tag scanner for the RFID reader. Behaviour like "the left ear
turns the room light pink" is an HA automation, not backend code. See
`python-backend/README.md` for the trigger topics and the old colour mapping.
- HTTP, for the web front-end's room page only: `/api/ha/...` proxies state reads and
service calls to Home Assistant's REST API with the token from `general.ha`, so the
token never reaches the browser.
- **`python-backend` ↔ IR remote**: a TCP client for lircd (`general.lirc`), turned into
the same intents as every other front-end.
## Running it
@@ -89,10 +97,13 @@ production so one process serves both the UI and the API.
- `general.{library.*, serial_port, baudrate, reconnect_interval, alsa_device,
min_volume, max_volume, initial_volume, volume_increment, button_leds_brightness,
audio_extensions, mqtt.*, web.*}`
- `figures.<name>.{id, colors}` — `id` is a 5-byte hex RFID tag, unique per figure;
`colors` is exactly four (`primary, secondary, bg, accent`), each `"#rrggbb"` or
`"wNN"`.
audio_extensions, podcast_episode_limit}`, plus optional sections `mqtt`, `web`, `ha`
(room page), `lirc` (IR remote), `screen` (monitor on/off), `tippen` (typing game)
and `clock` (school bus countdown).
- `figures.<name>.{id, colors, kind}` — `id` is a 5-byte hex RFID tag, unique per
figure; `colors` is exactly four (`primary, secondary, bg, accent`), each `"#rrggbb"`
or `"wNN"`; `kind` is `music` (default) or `book`.
- `remote.<digit>` — what each IR-remote number key plays. Written by the web UI.
`general.library.root` is the one path to the music. The shelves under it are fixed
names, not settings, because each has quirks the scanner knows about:
@@ -118,9 +129,8 @@ reported at once.
the behaviour is end-to-end — those files are executed by the test suite.
- `python-backend/notebooks/` is LED-effect scratch work, not part of the app.
- The firmware has no automated tests beyond a PlatformIO `native` env for LED effects.
- The front-end has `vitest` over the pure modules (`web/src/lib/`) and `tsc --noEmit`;
there is no component-level test harness. `npm run test` and `npx tsc --noEmit` are
the two checks.
- The front-end has `vitest` over the pure modules (`web/src/lib/`), `tsc` and `eslint`;
there is no component-level test harness.
- The library index is cached under `general.library.cache`. It is keyed by file mtime
and size, so **a change to how the scanner derives a title, artist or series is
invisible until the cache is invalidated** — bump `_INDEX_VERSION` in