- event bus systen - all components are independent - preparation for web frontend
83 lines
4.0 KiB
Markdown
83 lines
4.0 KiB
Markdown
# MusicMouse — repo overview
|
|
|
|
Orientation doc for AI agents (or humans) working on this repo for the first time.
|
|
|
|
## What this is
|
|
|
|
MusicMouse is a DIY, Toniebox-style physical music player for kids, shaped like a mouse
|
|
and living on a shelf. Small 3D-printed animal figurines (fox, owl, dog, elephant,
|
|
squirrel, crocodile, rabbit, snowman, puppy — see `hardware/3dprints/figures/`) each
|
|
carry an RFID tag. Placing a figurine on the mouse starts that figure's playlist. The
|
|
mouse also has a rotary encoder and capacitive touch areas (ears/feet) for
|
|
volume/skip control, addressable RGBW LED rings with animated effects, and MQTT/Home
|
|
Assistant integration.
|
|
|
|
## Repo layout
|
|
|
|
| Path | What it is |
|
|
|---|---|
|
|
| `python-backend/` | Python host application — the main runtime. Has its own `README.md` with the architecture; start there for backend work. |
|
|
| `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/` | An unrelated exploratory web-UI mockup ("Dolphin Beats"). Not integrated with anything — no build system ties it in. Don't assume it reflects current product direction. |
|
|
|
|
## How the pieces talk to each other
|
|
|
|
- **ESP32 firmware ↔ `python-backend`**: a length-prefixed binary protocol over serial.
|
|
Frames are `uint32 magic | uint8 type | uint16 size | payload`, little-endian, with
|
|
firmware log text interleaved on the same link. The Python side lives in
|
|
`python-backend/musicmouse/devices/wire.py`, the firmware side in
|
|
`esp-firmware/src/Messages.h`.
|
|
|
|
The contract is hand-duplicated in two languages. `tests/test_wire.py` parses
|
|
`Messages.h` and fails if the message ids drift, and `tests/test_effects.py` pins the
|
|
exact bytes of every effect payload — so a firmware change that breaks the host now
|
|
breaks a test instead of just the LEDs.
|
|
|
|
- **`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.
|
|
|
|
## Running it
|
|
|
|
```sh
|
|
python -m musicmouse --config /media/musicmouse/config.yml
|
|
```
|
|
|
|
Or, with no hardware and no audio:
|
|
|
|
```sh
|
|
python -m musicmouse --config ./config.yml --simulate
|
|
```
|
|
|
|
The simulator runs the whole app against a fake serial link and a fake player, either
|
|
interactively or from a scenario file. `python-backend/musicmouse.service` is the
|
|
systemd unit for the device.
|
|
|
|
## Config
|
|
|
|
`python-backend/config.yml.example` documents the schema. In short:
|
|
|
|
- `general.{figure_folder, serial_port, baudrate, reconnect_interval, alsa_device,
|
|
min_volume, max_volume, initial_volume, volume_increment, button_leds_brightness,
|
|
audio_extensions, mqtt.*}`
|
|
- `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"`.
|
|
|
|
Each figure plays `<figure_folder>/<figure name>`, alphabetically by filename. Config is
|
|
validated with pydantic: unknown keys are errors, and every problem is reported at once.
|
|
|
|
## Notes for agents
|
|
|
|
- The backend has `pytest`, `ruff` and `mypy --strict` configured in
|
|
`python-backend/pyproject.toml`, and no CI. Run all three before proposing changes.
|
|
- Prefer adding a scenario in `python-backend/scenarios/` over a hand-rolled test when
|
|
the behaviour is end-to-end — those files are executed by the test suite.
|
|
- `python-backend/notebooks/` is university course material on chord recognition, not
|
|
part of the app.
|
|
- The firmware has no automated tests beyond a PlatformIO `native` env for LED effects.
|