#!/usr/bin/env bash # # Smart Home Kitchen-Display ISO Builder # Target: builds a Debian 12 (Bookworm) live ISO on a Debian/Ubuntu build machine # # Drives `lb config && lb build` over hosts/kitchen-display/live-build/ to produce # the fridge/pantry camera-cataloguing display described in docs/project-plan.md # Phase 17: # - greetd autologin straight into a kiosk Sway session (no greeter UI) # - ONE Chromium kiosk window pointed at pantry-web's frontend (Scan / Inventory / # Recipes is in-page tab navigation, not separate Sway workspaces) # - kitchen-display-agent (Python, systemd) — HA MQTT "Show scan/inventory/recipes/ # registration" buttons only; the actual camera capture, Grocy read/write, and # identity registration paths are pantry-vision's/identity's own published APIs, # called directly by the browser # - identity's registration page (Phase 6) — voice ("register me as ", needs # ENABLE_VOICE_SATELLITE=true and a real mic) or the touchscreen form either way # # Reuses hosts/thin-client's live-build toolchain and directory-split convention, not # its live-build tree — same relationship hosts/touch-panel and hosts/audio-endpoint # already have to the thin client's. # # Run as: sudo ./build-kitchen-display-iso.sh # # EDIT THE VARIABLES BELOW BEFORE RUNNING. set -euo pipefail # --------------------------------------------------------------------------- # CONFIGURATION — edit these before running # --------------------------------------------------------------------------- DEBIAN_RELEASE="bookworm" KIOSK_USERNAME="kiosk" IMAGE_HOSTNAME="kitchen-display" KITCHEN_DISPLAY_NAME="Kitchen fridge display" KEYBOARD_LAYOUT="de" ENABLE_INSTALLER="false" # --- Where the kitchen display talks to ------------------------------------- MQTT_BROKER_HOST="192.168.1.10" # <-- EDIT: container-host IP running Mosquitto MQTT_BROKER_PORT="1883" MQTT_USERNAME="" MQTT_PASSWORD="" # pantry-web (nginx, serves pantry-vision/frontend/) and pantry-vision (the API the # frontend calls directly from the browser) — both from ENABLE_PANTRY_VISION in # setup-container-host.sh. Placeholders until that's deployed; the image builds and # boots fine without it, the kiosk window just shows a connection error. PANTRY_WEB_URL="http://192.168.1.10:8096" # <-- EDIT once pantry-web is deployed PANTRY_VISION_URL="http://192.168.1.10:8095" # <-- EDIT once pantry-vision is deployed # Same value as PANTRY_VISION_TOKEN in pantry-vision/pantry-vision.env — there is no # way for this repo to push it between the two hosts for you, same as every other # credential pair that spans two machines in this project. PANTRY_VISION_TOKEN="" # <-- EDIT: must match pantry-vision's own token # identity's registration page (Phase 6) — ENABLE_IDENTITY in setup-container-host.sh. # Same placeholder handling as the pantry-vision block above. IDENTITY_WEB_URL="http://192.168.1.10:8098" # <-- EDIT once identity-web is deployed IDENTITY_URL="http://192.168.1.10:8097" # <-- EDIT once identity is deployed IDENTITY_TOKEN="" # <-- EDIT: must match identity's own token # --- Voice registration ("register me as ") — OFF BY DEFAULT until a real mic # --- is attached to this specific unit. Same per-image opt-in shape as the thin # --- client's ENABLE_VOICE_SATELLITE (project-plan Phase 11.8). ENABLE_VOICE_SATELLITE="false" VOICE_SATELLITE_NAME="Kitchen display" VOICE_WAKE_WORD="ok_nabu" SSH_AUTHORIZED_KEY="" # --------------------------------------------------------------------------- # Paths # --------------------------------------------------------------------------- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" KITCHEN_DISPLAY_DIR="$(dirname "$SCRIPT_DIR")" CONFIGS_DIR="${KITCHEN_DISPLAY_DIR}/configs" AGENT_DIR="${KITCHEN_DISPLAY_DIR}/agent" LIVE_BUILD_DIR="${KITCHEN_DISPLAY_DIR}/live-build" INCLUDES="${LIVE_BUILD_DIR}/config/includes.chroot" PACKAGE_LIST="${LIVE_BUILD_DIR}/config/package-lists/kitchen-display.list.chroot" # --------------------------------------------------------------------------- # Sanity checks # --------------------------------------------------------------------------- if [[ $EUID -ne 0 ]]; then echo "Warning: not running as root. 'lb build' needs root; re-run with: sudo $0" echo " Continuing anyway so you can at least regenerate includes.chroot..." 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 — edit it before building." fi if [[ -z "$PANTRY_VISION_TOKEN" ]]; then echo "Warning: PANTRY_VISION_TOKEN is empty. The kiosk window will load but every" echo " call to pantry-vision will fail (401) until this matches the token in" echo " pantry-vision/pantry-vision.env on the container host." fi if [[ -z "$IDENTITY_TOKEN" ]]; then echo "Warning: IDENTITY_TOKEN is empty. 'Show registration' will load but every" echo " call to identity will fail (401) until this matches the token in" echo " identity/identity.env on the container host." fi if [[ "$ENABLE_VOICE_SATELLITE" == "true" ]]; then echo "Note: ENABLE_VOICE_SATELLITE=true — this image expects a real microphone on" echo " the physical unit. Don't flash it to hardware that doesn't have one." fi echo echo "=== Smart Home Kitchen-Display 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 "pantry-web : $PANTRY_WEB_URL" echo "pantry-vision : $PANTRY_VISION_URL" echo "identity-web : $IDENTITY_WEB_URL" echo "identity : $IDENTITY_URL" echo "Voice satellite : $ENABLE_VOICE_SATELLITE" 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/kitchen-display-agent" \ "$INCLUDES/usr/local/bin" \ "$INCLUDES/opt/kitchen-display-agent" \ "$INCLUDES/home/${KIOSK_USERNAME}/.config/sway" \ "$INCLUDES/home/${KIOSK_USERNAME}/.ssh" 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}/kitchen-display-agent.service" "$INCLUDES/opt/kitchen-display-agent/kitchen-display-agent.service" install -m 0755 "${CONFIGS_DIR}/greetd/kiosk-session" "$INCLUDES/usr/local/bin/kiosk-session" install -m 0755 "${CONFIGS_DIR}/sway/pantry-kiosk" "$INCLUDES/usr/local/bin/pantry-kiosk" install -m 0755 "${CONFIGS_DIR}/sway/identity-kiosk" "$INCLUDES/usr/local/bin/identity-kiosk" 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 # --------------------------------------------------------------------------- echo "--- Writing /etc/kitchen-display-agent/config.env into includes.chroot ---" cat > "$INCLUDES/etc/kitchen-display-agent/config.env" <' and confirm the same" echo " result happens via voice." fi echo echo "Then pull the power on the container host and re-check: the kiosk must still" echo "boot (Scan/Inventory/Recipes will show connection errors, which is the expected" echo "degraded state — this device has no local fallback data source, same acceptance" echo "already documented for hosts/touch-panel's Home workspace)." echo echo "Rebuilding later: edit hosts/kitchen-display/configs/* or agent/*, then re-run" echo "this script — includes.chroot is regenerated from them every time."