Files
tag-albums/README.md
T
2026-09-25 17:46:06 +00:00

117 lines
4.6 KiB
Markdown

# Tag albums
Tells Home Assistant which album to play when an RFID card (a **Tag**) is scanned, and provides a web page to give new cards an album (an **Assignment**). See [CONTEXT.md](CONTEXT.md) for the vocabulary.
How it fits together:
1. The ESPHome RFID reader sends `tag_scanned` to Home Assistant, as before.
2. HA's `Play album by tag` script calls `POST /api/scans`. The service records the **Scan** and answers with the album, or `assigned: false`.
3. A card the service hasn't seen before becomes an **Unassigned tag**. It appears on the web page within a few seconds, where you search the Music Assistant library and assign an album.
4. When a card is removed, HA's `Stop album by tag` script calls `GET /api/tags/{tag_id}`. It stops the player only if that tag has an album.
## Demo
The main page lists unassigned tags (a card scanned while the page is open appears within a few seconds) and every assignment:
![Unassigned tags and assignments](docs/screenshots/tags.png)
Assigning a tag: search the Music Assistant library and pick an album. Albums without a cover show a grey placeholder.
![Searching the library for a tag](docs/screenshots/assign.png)
The page follows the system's dark mode and works on a phone:
<img src="docs/screenshots/tags-dark-mobile.png" alt="Dark mode on a phone" width="320">
## API
Both endpoints need `Authorization: Bearer <API_TOKEN>`.
| Endpoint | Purpose |
|---|---|
| `POST /api/scans` `{"tag_id": "53-13-0B-2A"}` | Record a Scan; creates the Tag on first sight. Returns `{"tag_id", "assigned": true, "artist", "album"}` or `{"tag_id", "assigned": false}`. |
| `GET /api/tags/{tag_id}` | Read-only lookup, same response. `404` if the tag has never been seen. |
Tag IDs are normalised to upper case.
The web page (`/`) has no login: keep the service on the LAN.
## Configuration
Environment variables:
| Variable | Meaning |
|---|---|
| `API_TOKEN` | Shared secret Home Assistant sends in the `Authorization` header |
| `HA_URL` | Home Assistant base URL, e.g. `https://ha.home.knbg` |
| `HA_TOKEN` | HA long-lived access token, used to search the Music Assistant library |
| `DB_PATH` | SQLite file (default `tag_albums.sqlite3`); its directory must be writable |
HTTPS to HA is verified against the system trust store, so a home CA must be installed on the host. If it isn't, point `SSL_CERT_FILE` at the CA bundle.
## Development
```sh
uv sync
uv run pytest
API_TOKEN=dev HA_URL=https://ha.home.knbg HA_TOKEN=... uv run tag-albums serve --port 8087
```
## Running with Docker
For local testing. The container has to trust the home CA to reach HA, so mount the CA certificate and point `SSL_CERT_FILE` at it:
```sh
docker build -t tag-albums .
docker run --rm -p 8087:8087 -v tag-albums-data:/data \
-e API_TOKEN=dev -e HA_URL=https://ha.home.knbg -e HA_TOKEN=... \
-v /usr/local/share/ca-certificates/KNBG_Root_CA_306526670621344964268144771797781855543.crt:/ca.crt:ro \
-e SSL_CERT_FILE=/ca.crt \
tag-albums
```
To import assignments, run `tag-albums import-yaml` inside the container, e.g. `docker run --rm -v tag-albums-data:/data -v $PWD/tag_albums.yaml:/import.yaml:ro tag-albums tag-albums import-yaml /import.yaml`.
## Deploying in a FreeBSD jail
```sh
pkg install python311 py311-uv git # or any Python >= 3.11
pw useradd tagalbums -d /nonexistent -s /usr/sbin/nologin
git clone <repo> /usr/local/tag-albums && cd /usr/local/tag-albums && uv sync --no-dev
install -d -o tagalbums /var/db/tag_albums
cat > /usr/local/etc/tag_albums.env <<'EOF'
API_TOKEN=<random, e.g. openssl rand -hex 32>
HA_URL=https://ha.home.knbg
HA_TOKEN=<HA long-lived token>
DB_PATH=/var/db/tag_albums/tag_albums.sqlite3
EOF
chmod 600 /usr/local/etc/tag_albums.env
install -m 755 deploy/rc.d/tag_albums /usr/local/etc/rc.d/tag_albums
sysrc tag_albums_enable=YES
service tag_albums start
```
Logs go to syslog with the tag `tag_albums`. The port defaults to 8087 (`sysrc tag_albums_port=...`).
### Importing the old tag_albums.yaml
One time, before switching Home Assistant over:
```sh
cd /usr/local/tag-albums
env DB_PATH=/var/db/tag_albums/tag_albums.sqlite3 \
su -m tagalbums -c '.venv/bin/tag-albums import-yaml /path/to/tag_albums.yaml'
```
## Home Assistant side
These pieces live in the `home-assistant-config` repo:
- `configuration.yaml`: two `rest_command`s, `tag_albums_scan` and `tag_albums_lookup`, pointing at `http://tag-albums.home.knbg:8087`.
- `secrets.yaml`: `tag_albums_auth: "Bearer <API_TOKEN>"`.
- `scripts.yaml`: `play_album_by_tag` and `stop_album_by_tag` call those commands.
If the service is down, a scan plays nothing and `play_album_by_tag` writes a warning to the HA log.