The role ran no window manager on the theory that Firefox is the only X client and --kiosk makes it full-screen by itself. It doesn't: --kiosk *asks* to be full-screen over EWMH, and with no WM running nobody answers. Firefox kept its default window size in the top-left corner - on musicdolphin's 1920x1080 monitor, a 1280x972 window with black bands down the right edge and along the bottom, which looks exactly like an overscan problem and isn't one. Openbox answers the request and does nothing else. pi_kiosk_mode=debug then turns the attached screen into something workable: Firefox as an ordinary window that is not relaunched when you close it, a visible pointer, Openbox as the session leader with a root menu offering a terminal, and xterm, x11-utils and mesa-utils installed. musicdolphin is set to debug for now. The templates notify the getty handler, so a mode switch restarts the session on its own - Xorg lives in that unit's cgroup. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ansible
Personal Ansible setup for provisioning and maintaining a fleet of Raspberry Pis (audio players, sensors, music mouse, etc.) plus one home server.
Layout
inventory.yml— hosts and group vars (Pis underiot, plusserver).group_vars/andhost_vars/hold vars for themediapisgroup (the four parallel audio-player Pis) and their host-specific overrides.mediapis.yml,working.yml,server.yml,newrpi-provisioning.yml,octopisetup.yml— top-level playbooks.mediapis.ymlis the canonical playbook for themediapisgroup (musicdolphin,kitchenpi,bedroompi,musicmouse); the others are narrower/ad-hoc runs kept around for specific hosts or one-off tasks.roles/— one role per piece of functionality (audio backends, sensors, bluetooth monitoring, server basics, etc.). Each has a shortREADME.md.update-packages.yml— deliberate, fleet-wide package update (see "Keeping packages up to date" below).update-packages-pinned-example.ymlis a template for pinning or bumping a single package outside that.lookup_plugins/keepass.py— custom lookup plugin that fetches secrets (device passwords, wifi passphrase) from a running KeePassXC instance via its browser-integration protocol, instead of storing them in the repo.pis/— loose config files/scripts used when provisioning Pis by hand.scripts/— standalone helper scripts (Raspbian image creation, a network logger) that aren't Ansible roles.archive/— retired setups kept for reference (not actively maintained).
Setup
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
Secrets are pulled from KeePassXC at run time via the keepass lookup
plugin — see the header of lookup_plugins/keepass.py for how to enable
Browser Integration in KeePassXC. Freshly-flashed Raspberry Pis are reached
first with the OS-default pi/raspberry credentials (see
roles/pi_standard_setup), which the role then rotates to a KeePassXC-managed
password.
Running a playbook
ansible-playbook mediapis.yml --limit <host>
ansible.cfg points Ansible at inventory.yml and roles/ by default, so
no extra flags are needed for those.
Keeping packages up to date
Regular playbook runs (mediapis.yml, server.yml, etc.) use state: present
for packages, so they only install what's missing — they never upgrade
anything as a side effect of an unrelated config change. Two separate,
deliberate mechanisms handle upgrades instead:
Security patches — automatic. The unattended_upgrades role (applied
to every host in mediapis.yml/server.yml) configures unattended-upgrades
to install security-origin updates automatically, with a scheduled reboot
window (default 03:00, see roles/unattended_upgrades/defaults/main.yml)
for patches that need one. Not scoped to full dist-upgrades.
Everything else — deliberate, ad hoc.
just update <host_or_group> # e.g. `just update kitchenpi` or `just update`
venv/bin/ansible-playbook update-packages.yml --limit <host> --check --diff # dry run first
Defaults to upgrade: safe (upgrades in place, never installs/removes
packages to resolve dependencies — see the comment header in
update-packages.yml for the tradeoff against dist). There is no cron/
schedule wired up for this yet; run it ad hoc when you want the fleet
updated, or add a crontab entry yourself (a starting point is documented in
update-packages.yml's header).
To pin a package to an exact version, or deliberately bump one named
package to latest outside this schedule, copy the pattern in
update-packages-pinned-example.yml.