Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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 for the vocabulary.
How it fits together:
- The ESPHome RFID reader sends
tag_scannedto Home Assistant, as before. - HA's
Play album by tagscript callsPOST /api/scans. The service records the Scan and answers with the album, orassigned: false. - 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.
- When a card is removed, HA's
Stop album by tagscript callsGET /api/tags/{tag_id}. It stops the player only if that tag has an album.
Demo
A card is scanned while the page is open, shows up under Unassigned tags, and gets an album from a live search of the Music Assistant library:
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
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:
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
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:
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: tworest_commands,tag_albums_scanandtag_albums_lookup, pointing athttp://tag-albums.home.knbg:8087.secrets.yaml:tag_albums_auth: "Bearer <API_TOKEN>".scripts.yaml:play_album_by_tagandstop_album_by_tagcall those commands.
If the service is down, a scan plays nothing and play_album_by_tag writes a warning to the HA log.
