#!/usr/bin/env bash # # Smart Home Touch-Panel ISO Builder # Target: builds a Debian 12 (Bookworm) live ISO on a Debian/Ubuntu build machine # # Drives `lb config && lb build` over hosts/touch-panel/live-build/ to produce the # Sway touch-panel image described in docs/project-plan.md Phase 16: # - greetd autologin straight into a kiosk Sway session (no greeter UI) # - touchpanel-agent (Python, systemd) — HA MQTT-discovery entities + swaymsg control # - workspaces 1:spotify (full Spotify GUI, Flathub) / 2:home (Chromium kiosk # pointed at Home Assistant) / 3:web (general Firefox browsing) # - an always-visible eww touch dock for on-screen app switching # - a toggleable on-screen keyboard (wvkbd) # # Reuses hosts/thin-client's own live-build toolchain and directory-split convention, # NOT its live-build tree — this is a different device (touched directly, not # remote-controlled from the couch) with a different app set, so it gets its own # smaller config/, agent/, and live-build/, same relationship as # hosts/audio-endpoint's amd64 build to the thin client's. # # This script is also the single point that keeps configs/ (the human-edited source of # truth, reviewed in git) in sync with live-build/config/includes.chroot/ (the # generated tree that actually gets baked into the image). Never hand-edit anything # under includes.chroot — it is wiped and regenerated on every run. # # Run as: sudo ./build-touch-panel-iso.sh # # EDIT THE VARIABLES BELOW BEFORE RUNNING. set -euo pipefail # --------------------------------------------------------------------------- # CONFIGURATION — edit these before running # --------------------------------------------------------------------------- DEBIAN_RELEASE="bookworm" # Matches the container host's OS KIOSK_USERNAME="kiosk" # The autologin account the whole image is built around IMAGE_HOSTNAME="touch-panel" # Hostname baked into the image TOUCHPANEL_NAME="Kitchen touch panel" # Friendly name shown on the HA device KEYBOARD_LAYOUT="de" # xkb layout name (`localectl list-x11-keymap-layouts`) ENABLE_INSTALLER="false" # "true" adds a debian-installer to the ISO (install to disk) # --- Where the touch panel talks to ----------------------------------------- MQTT_BROKER_HOST="192.168.1.10" # <-- EDIT: container-host IP running Mosquitto MQTT_BROKER_PORT="1883" MQTT_USERNAME="" # Leave empty while Mosquitto runs allow_anonymous MQTT_PASSWORD="" # Never commit a real value here HA_URL="http://192.168.1.10:8123" # <-- EDIT: Home Assistant URL — the "Home" workspace # Optional: an SSH public key to bake into the kiosk account for out-of-band admin. # The image ships with password auth disabled and no wayvnc (see README's scope note), # so without this the only admin path is the local console. SSH_AUTHORIZED_KEY="" # --------------------------------------------------------------------------- # Paths # --------------------------------------------------------------------------- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" TOUCH_PANEL_DIR="$(dirname "$SCRIPT_DIR")" CONFIGS_DIR="${TOUCH_PANEL_DIR}/configs" AGENT_DIR="${TOUCH_PANEL_DIR}/agent" LIVE_BUILD_DIR="${TOUCH_PANEL_DIR}/live-build" INCLUDES="${LIVE_BUILD_DIR}/config/includes.chroot" PACKAGE_LIST="${LIVE_BUILD_DIR}/config/package-lists/touch-panel.list.chroot" # --------------------------------------------------------------------------- # Sanity checks # --------------------------------------------------------------------------- if [[ $EUID -ne 0 ]]; then echo "Warning: not running as root. 'lb build' needs root to bootstrap and chroot," echo " and will fail partway through. Re-run with: sudo $0" echo " Continuing anyway so you can at least regenerate includes.chroot..." fi if ! grep -qi "debian\|ubuntu" /etc/os-release; then echo "Warning: live-build targets a Debian/Ubuntu build host. Proceeding anyway..." fi if ! command -v lb &> /dev/null; then if [[ $EUID -eq 0 ]]; then echo "--- Installing live-build ---" apt-get update apt-get install -y live-build else echo "live-build is not installed and this script is not running as root." >&2 echo " Install it first: sudo apt-get install live-build" >&2 exit 1 fi else echo "--- live-build already installed, skipping ---" fi if [[ ! -f "$PACKAGE_LIST" ]]; then echo "Missing package list: $PACKAGE_LIST" >&2 exit 1 fi if [[ "$MQTT_BROKER_HOST" == "192.168.1.10" ]]; then echo "Warning: MQTT_BROKER_HOST is still the placeholder IP." echo " Edit it at the top of this script to your container host's real LAN address," echo " or the touch panel won't show up as Home Assistant entities." fi if [[ "$HA_URL" == "http://192.168.1.10:8123" ]]; then echo "Warning: HA_URL is still the placeholder." echo " The image builds and boots fine, but the Home workspace will show a" echo " connection error until this points at a real Home Assistant." fi echo echo "=== Smart Home Touch-Panel ISO Builder ===" echo "Debian release : $DEBIAN_RELEASE" echo "Kiosk user : $KIOSK_USERNAME" echo "Image hostname : $IMAGE_HOSTNAME" echo "MQTT broker : ${MQTT_BROKER_HOST}:${MQTT_BROKER_PORT}" echo "Home Assistant : $HA_URL" echo "Keyboard layout : $KEYBOARD_LAYOUT" echo # --------------------------------------------------------------------------- # 1. Regenerate includes.chroot from configs/ and agent/ # --------------------------------------------------------------------------- echo "--- Regenerating $INCLUDES ---" rm -rf "$INCLUDES" mkdir -p \ "$INCLUDES/etc/greetd" \ "$INCLUDES/etc/touchpanel-agent" \ "$INCLUDES/etc/firefox/policies" \ "$INCLUDES/etc/touchpanel-firefox" \ "$INCLUDES/etc/udev/rules.d" \ "$INCLUDES/usr/local/bin" \ "$INCLUDES/opt/touchpanel-agent" \ "$INCLUDES/home/${KIOSK_USERNAME}/.config/sway" \ "$INCLUDES/home/${KIOSK_USERNAME}/.config/eww" \ "$INCLUDES/home/${KIOSK_USERNAME}/.ssh" # @KIOSK_USERNAME@ and @KEYBOARD_LAYOUT@ are the only templated tokens in the configs. # Everything else the hooks need is read at build time from # /etc/touchpanel-agent/config.env (written below), which live-build copies in # (chroot_local-includes) before it runs the hooks (chroot_local-hooks). subst() { sed -e "s/@KIOSK_USERNAME@/${KIOSK_USERNAME}/g" \ -e "s/@KEYBOARD_LAYOUT@/${KEYBOARD_LAYOUT}/g" "$1" > "$2" } subst "${CONFIGS_DIR}/greetd/config.toml" "$INCLUDES/etc/greetd/config.toml" subst "${CONFIGS_DIR}/sway/config" "$INCLUDES/home/${KIOSK_USERNAME}/.config/sway/config" subst "${AGENT_DIR}/touchpanel-agent.service" "$INCLUDES/opt/touchpanel-agent/touchpanel-agent.service" install -m 0755 "${CONFIGS_DIR}/greetd/kiosk-session" "$INCLUDES/usr/local/bin/kiosk-session" install -m 0755 "${CONFIGS_DIR}/sway/ha-kiosk" "$INCLUDES/usr/local/bin/ha-kiosk" install -m 0755 "${CONFIGS_DIR}/spotify/spotify-launch" "$INCLUDES/usr/local/bin/spotify-launch" install -m 0755 "${CONFIGS_DIR}/keyboard/toggle-keyboard" "$INCLUDES/usr/local/bin/toggle-keyboard" # Touchscreen misclassification override (inert 0000:0000 template until the real # hardware's vendor/product ID is filled in — see that file's own setup steps). install -m 0644 "${CONFIGS_DIR}/udev/99-touchscreen-override.rules" \ "$INCLUDES/etc/udev/rules.d/99-touchscreen-override.rules" # Console (VT/TTY) keymap — separate from Sway's own xkb_layout, since greetd briefly # owns the console before Sway starts. mkdir -p "$INCLUDES/etc/default" cat > "$INCLUDES/etc/default/keyboard" < "$INCLUDES/home/${KIOSK_USERNAME}/.ssh/authorized_keys" chmod 600 "$INCLUDES/home/${KIOSK_USERNAME}/.ssh/authorized_keys" echo " Baked an SSH authorized_keys entry for ${KIOSK_USERNAME}." else echo " No SSH_AUTHORIZED_KEY set — SSH admin access will not be possible on this image." fi # --------------------------------------------------------------------------- # 2. Runtime config, read by touchpanel-agent, the sway session wrapper, and hooks # --------------------------------------------------------------------------- echo "--- Writing /etc/touchpanel-agent/config.env into includes.chroot ---" cat > "$INCLUDES/etc/touchpanel-agent/config.env" < touchpanel-agent's MPRIS bridge — needs Spotify's own MPRIS bus name to" echo " actually be 'spotify', unverified against the real Flatpak build)." echo " 7. Tap the dock's Keyboard button over a text field (Spotify search, the browser" echo " address bar) and confirm wvkbd shows/hides. There is no auto-show — see README." echo echo "Then pull the power on the container host and re-check: the panel must still boot" echo "and show Spotify/the browser (Home will show a connection error, which is" echo "expected) with the container host powered off — same reactive-path philosophy as" echo "hosts/thin-client's Phase 11.10." echo echo "Rebuilding later: edit hosts/touch-panel/configs/* or agent/*, then re-run this" echo "script — includes.chroot is regenerated from them every time."