# 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 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: ![Scanning a new card and assigning it an album](docs/assign-demo.gif) ## API Both endpoints need `Authorization: Bearer `. | 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 python313 py313-sqlite3 py313-uv git rust # any Python >= 3.11; sqlite3 is a separate package # uv compiles pydantic-core (Rust) and a few C extensions from source, since # FreeBSD has no prebuilt wheels. The jail needs the base system's development # files for that (e.g. /usr/lib/Scrt1.o, crti.o, libc): on a pkgbase jail, # install the FreeBSD-*-dev packages (or the devel set) from the FreeBSD-base repo. pw useradd tagalbums -d /nonexistent -s /usr/sbin/nologin git clone /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= HA_URL=https://ha.home.knbg HA_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 `https://tag-albums.home.knbg` (a reverse proxy in front of port 8087). They set `verify_ssl: false`, because the certificate comes from the home CA and HA only trusts its built-in list of public CAs. - `secrets.yaml`: `tag_albums_auth: "Bearer "`. - `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.