VoxIP Kiosk OS 1.0.0: Raspberry Pi kiosk with web management
Chromium kiosk without a desktop for the Raspberry Pi 3, a Flask web interface on port 8080 (kiosk, system and network management), a restricted root helper, network changes with automatic rollback, a healthcheck timer, install/update/uninstall scripts and a pi-gen image build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
a33c4822bf
96 files changed
+7535
No files matched your search
@@ -0,0 +1,35 @@
|
||||
VoxIP Kiosk OS — bestanden op deze bootpartitie
|
||||
================================================
|
||||
|
||||
Je kunt een kiosk vooraf instellen door vóór de eerste start bestanden op
|
||||
deze partitie te zetten (bijvoorbeeld direct na het flashen). Ze worden bij
|
||||
het opstarten verwerkt en daarna hernoemd naar *.applied (of *.rejected bij
|
||||
een fout; de reden staat dan in voxip-config.error.txt).
|
||||
|
||||
voxip-config.json
|
||||
Instellingen voor deze kiosk. Zie voxip-config.example.json. Toegestaan:
|
||||
alle sleutels uit /etc/voxip-kiosk/config.json plus "hostname" en
|
||||
"wifi_country". Voorbeeld:
|
||||
|
||||
{
|
||||
"device_name": "Hal begane grond",
|
||||
"url": "https://schermen-klant.voxip.nl/display/hal?token=…",
|
||||
"hostname": "hal-bg",
|
||||
"rotation": 90
|
||||
}
|
||||
|
||||
voxip-authorized_keys
|
||||
Openbare SSH-sleutels (één per regel). SSH wordt dan ingeschakeld, alleen
|
||||
met sleutel-login, voor de beheerder (voxipadmin of de gebruiker die je
|
||||
in Raspberry Pi Imager hebt aangemaakt).
|
||||
|
||||
voxip-network-reset
|
||||
Leeg bestand. Verwijdert bij de volgende start alle via de
|
||||
beheerinterface ingestelde netwerkprofielen (terug naar DHCP). Gebruik
|
||||
dit als de kiosk na een netwerkwijziging onbereikbaar is.
|
||||
|
||||
Wifi, gebruikersnaam/wachtwoord en SSH stel je het makkelijkst in met de
|
||||
"OS-aanpassingen" van Raspberry Pi Imager.
|
||||
|
||||
Beheerinterface: http://kiosk.local:8080 (of http://<hostname>.local:8080).
|
||||
De setupcode voor het eerste wachtwoord staat op het scherm.
|
||||
Executable
+123
@@ -0,0 +1,123 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Build a flashable VoxIP Kiosk OS image (.img.xz) with pi-gen.
|
||||
#
|
||||
# ./image/build.sh # build in Docker (recommended)
|
||||
# sudo ./image/build.sh --native # build directly on a Debian/Ubuntu host
|
||||
#
|
||||
# Environment (all optional):
|
||||
# PI_GEN_REF pi-gen tag/branch (32-bit armhf). Default: pinned Bookworm release.
|
||||
# RELEASE bookworm | trixie (must match PI_GEN_REF). Default: bookworm.
|
||||
# VOXIP_DEFAULT_URL kiosk URL baked into the default config.
|
||||
# VOXIP_DEVICE_NAME default device name.
|
||||
# TARGET_HOSTNAME default hostname (the admin UI is at http://<hostname>.local:8080).
|
||||
# ALLOW_DIRTY=1 build from the working tree instead of the committed HEAD.
|
||||
#
|
||||
# Output: image/deploy/<date>-voxip-kiosk-os-<version>.img.xz (+ .sha256)
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
WORK="${WORK_DIR:-$ROOT/image/work}"
|
||||
OUT="$ROOT/image/deploy"
|
||||
PI_GEN_REPO="${PI_GEN_REPO:-https://github.com/RPi-Distro/pi-gen.git}"
|
||||
PI_GEN_REF="${PI_GEN_REF:-2024-11-19-raspios-bookworm-armhf}"
|
||||
RELEASE="${RELEASE:-bookworm}"
|
||||
VOXIP_DEFAULT_URL="${VOXIP_DEFAULT_URL:-https://schermen-ijsselflat.voxip.nl}"
|
||||
VOXIP_DEVICE_NAME="${VOXIP_DEVICE_NAME:-VoxIP Kiosk}"
|
||||
TARGET_HOSTNAME="${TARGET_HOSTNAME:-kiosk}"
|
||||
NATIVE=0
|
||||
[[ ${1:-} == "--native" ]] && NATIVE=1
|
||||
[[ ${1:-} == "-h" || ${1:-} == "--help" ]] && { sed -n '3,18p' "$0" | sed 's/^# \{0,1\}//'; exit 0; }
|
||||
|
||||
VERSION="$(tr -d '[:space:]' < "$ROOT/VERSION")"
|
||||
command -v git >/dev/null || { echo "git is vereist" >&2; exit 1; }
|
||||
if [[ $NATIVE -eq 0 ]]; then
|
||||
command -v docker >/dev/null || { echo "Docker is vereist (of gebruik --native op Debian/Ubuntu)" >&2; exit 1; }
|
||||
else
|
||||
[[ $EUID -eq 0 ]] || { echo "--native moet met sudo" >&2; exit 1; }
|
||||
fi
|
||||
|
||||
echo "==> pi-gen $PI_GEN_REF ophalen"
|
||||
mkdir -p "$WORK" "$OUT"
|
||||
rm -rf "$WORK/pi-gen"
|
||||
git clone --quiet --depth 1 --branch "$PI_GEN_REF" "$PI_GEN_REPO" "$WORK/pi-gen"
|
||||
PI_GEN_COMMIT="$(git -C "$WORK/pi-gen" rev-parse HEAD)"
|
||||
PIGEN="$WORK/pi-gen"
|
||||
|
||||
# Do not export the plain Lite image from stage2; ours is exported after stage-voxip.
|
||||
touch "$PIGEN/stage2/SKIP_IMAGES"
|
||||
rm -f "$PIGEN/stage2/EXPORT_NOOBS"
|
||||
|
||||
echo "==> VoxIP-stage voorbereiden"
|
||||
cp -a "$ROOT/image/stage-voxip" "$PIGEN/stage-voxip"
|
||||
PAYLOAD="$PIGEN/stage-voxip/00-voxip/files/voxip-kiosk"
|
||||
mkdir -p "$PAYLOAD"
|
||||
if [[ ${ALLOW_DIRTY:-0} == 1 ]] || ! git -C "$ROOT" rev-parse --git-dir >/dev/null 2>&1; then
|
||||
echo " (werkmap wordt gebruikt, niet de laatste commit)"
|
||||
tar -C "$ROOT" --exclude=./image/work --exclude=./image/deploy --exclude=./.git --exclude=./.venv \
|
||||
--exclude='__pycache__' --exclude=.pytest_cache -cf - . | tar -C "$PAYLOAD" -xf -
|
||||
SOURCE_REV="werkmap"
|
||||
else
|
||||
if [[ -n "$(git -C "$ROOT" status --porcelain)" ]]; then
|
||||
echo " Let op: niet-gecommitte wijzigingen worden NIET meegenomen (ALLOW_DIRTY=1 om dat wel te doen)."
|
||||
fi
|
||||
git -C "$ROOT" archive HEAD | tar -C "$PAYLOAD" -xf -
|
||||
SOURCE_REV="$(git -C "$ROOT" rev-parse HEAD)"
|
||||
fi
|
||||
|
||||
BUILD_DATE="$(date -u +%Y-%m-%d)"
|
||||
cat > "$PIGEN/stage-voxip/00-voxip/files/build.env" <<EOF
|
||||
VOXIP_DEFAULT_URL=$(printf %q "$VOXIP_DEFAULT_URL")
|
||||
VOXIP_DEVICE_NAME=$(printf %q "$VOXIP_DEVICE_NAME")
|
||||
EOF
|
||||
cat > "$PAYLOAD/BUILD-INFO" <<EOF
|
||||
voxip_kiosk_os=$VERSION
|
||||
source_revision=$SOURCE_REV
|
||||
pi_gen_ref=$PI_GEN_REF
|
||||
pi_gen_commit=$PI_GEN_COMMIT
|
||||
release=$RELEASE
|
||||
build_date=$BUILD_DATE
|
||||
EOF
|
||||
|
||||
# The image has no usable default password: the first user is locked and is
|
||||
# only unlocked by credentials from Raspberry Pi Imager (or SSH keys placed
|
||||
# on the boot partition, see README).
|
||||
FIRST_USER_PASS="$(openssl rand -base64 33 | tr -d '\n/+=')"
|
||||
|
||||
cat > "$PIGEN/config" <<EOF
|
||||
IMG_NAME=voxip-kiosk-os-$VERSION
|
||||
IMG_DATE=$BUILD_DATE
|
||||
RELEASE=$RELEASE
|
||||
DEPLOY_COMPRESSION=xz
|
||||
COMPRESSION_LEVEL=6
|
||||
LOCALE_DEFAULT=nl_NL.UTF-8
|
||||
KEYBOARD_KEYMAP=us
|
||||
KEYBOARD_LAYOUT="English (US)"
|
||||
TIMEZONE_DEFAULT=Europe/Amsterdam
|
||||
WPA_COUNTRY=NL
|
||||
TARGET_HOSTNAME=$TARGET_HOSTNAME
|
||||
FIRST_USER_NAME=voxipadmin
|
||||
FIRST_USER_PASS=$FIRST_USER_PASS
|
||||
DISABLE_FIRST_BOOT_USER_RENAME=1
|
||||
ENABLE_SSH=0
|
||||
STAGE_LIST="stage0 stage1 stage2 stage-voxip"
|
||||
EOF
|
||||
|
||||
echo "==> Image bouwen (dit duurt 30–90 minuten)"
|
||||
cd "$PIGEN"
|
||||
if [[ $NATIVE -eq 1 ]]; then
|
||||
./build.sh
|
||||
else
|
||||
CONTINUE=0 PRESERVE_CONTAINER=0 ./build-docker.sh
|
||||
fi
|
||||
|
||||
shopt -s nullglob
|
||||
images=("$PIGEN"/deploy/*.img.xz)
|
||||
[[ ${#images[@]} -gt 0 ]] || { echo "Geen image gevonden in $PIGEN/deploy" >&2; exit 1; }
|
||||
for img in "${images[@]}"; do
|
||||
cp "$img" "$OUT/"
|
||||
(cd "$OUT" && sha256sum "$(basename "$img")" > "$(basename "$img").sha256")
|
||||
echo "==> Klaar: $OUT/$(basename "$img")"
|
||||
done
|
||||
cp "$PAYLOAD/BUILD-INFO" "$OUT/BUILD-INFO-$VERSION.txt"
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash -e
|
||||
# Install VoxIP Kiosk OS into the image with the same install.sh that is
|
||||
# used on existing Raspberry Pi OS installations.
|
||||
|
||||
# shellcheck disable=SC1091
|
||||
source files/build.env
|
||||
|
||||
rm -rf "${ROOTFS_DIR}/usr/src/voxip-kiosk"
|
||||
install -d "${ROOTFS_DIR}/usr/src/voxip-kiosk"
|
||||
cp -a files/voxip-kiosk/. "${ROOTFS_DIR}/usr/src/voxip-kiosk/"
|
||||
|
||||
on_chroot << EOF_CHROOT
|
||||
/usr/src/voxip-kiosk/install.sh --image --url $(printf %q "${VOXIP_DEFAULT_URL}") --name $(printf %q "${VOXIP_DEVICE_NAME}")
|
||||
install -m 0644 /usr/src/voxip-kiosk/BUILD-INFO /usr/share/voxip-kiosk/BUILD-INFO
|
||||
# No usable default password: unlocked only by Raspberry Pi Imager credentials.
|
||||
passwd -l ${FIRST_USER_NAME}
|
||||
systemctl disable ssh.service 2>/dev/null || true
|
||||
apt-get clean
|
||||
EOF_CHROOT
|
||||
|
||||
# Instructions next to config.txt for whoever opens the boot partition.
|
||||
install -m 0644 files/voxip-kiosk/image/boot-README.txt "${ROOTFS_DIR}/boot/firmware/VOXIP-LEESMIJ.txt"
|
||||
install -m 0644 files/voxip-kiosk/image/voxip-config.example.json "${ROOTFS_DIR}/boot/firmware/voxip-config.example.json"
|
||||
@@ -0,0 +1,4 @@
|
||||
IMG_SUFFIX=""
|
||||
if [ "${USE_QEMU}" = "1" ]; then
|
||||
export IMG_SUFFIX="${IMG_SUFFIX}-qemu"
|
||||
fi
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash -e
|
||||
# Start from the root filesystem of the previous stage (stage2 = Raspberry Pi OS Lite).
|
||||
if [ ! -d "${ROOTFS_DIR}" ]; then
|
||||
copy_previous
|
||||
fi
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"device_name": "Hal begane grond",
|
||||
"url": "https://schermen-ijsselflat.voxip.nl",
|
||||
"hostname": "hal-bg",
|
||||
"wifi_country": "NL",
|
||||
"refresh_interval": 0,
|
||||
"rotation": 0,
|
||||
"resolution": "auto",
|
||||
"screen_always_on": true
|
||||
}
|
||||
Reference in new issue
Block a user