Add kiosk setup and deployment scripts (Phases 5 + 9)

Phase 5 — RPi Kiosk:
- setup_kiosk.sh: full RPi OS Lite setup (X11, Chromium kiosk mode,
  auto-login, DPMS disabled, GPU memory split, screen rotation)
- kiosk.service: systemd unit for reliable auto-start
- update_kiosk.sh: reconfigure URL/rotation/resolution without re-setup
- Handles both Bullseye and Bookworm RPi OS versions

Phase 9 — Hardening + Deployment:
- install.sh: full server setup (apt/pacman, vigilar user, venv,
  directories, permissions, mosquitto config, systemd units)
- gen_cert.sh: TLS cert via mkcert or openssl fallback
- gen_vapid_keys.sh: VAPID keys for Web Push notifications
- setup_nut.sh: NUT configuration with USB UPS auto-detection
- backup.sh: SQLite snapshot + config archive, cron-ready
- uninstall.sh: clean removal with data preservation option
- vigilar.service: hardened systemd unit (ProtectSystem, NoNewPrivileges,
  PrivateTmp, syscall filtering)
- vigilar-mosquitto.conf: localhost-only MQTT broker config

All scripts idempotent, bash -n validated, support Debian + Arch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Aaron D. Lee
2026-04-02 23:25:03 -04:00
parent 10b0cf4d0e
commit ebcc49b474
13 changed files with 1704 additions and 0 deletions

135
kiosk/README.md Normal file
View File

@@ -0,0 +1,135 @@
# Vigilar Kiosk — Raspberry Pi TV Display
Turn a Raspberry Pi into a dedicated security-camera display showing the
Vigilar 2x2 camera grid on any HDMI-connected TV.
## Hardware
- Raspberry Pi Zero 2W, 3, 4, or 5
- Micro-HDMI (Zero 2W) or HDMI cable to TV
- Power supply (5V, 2.5A+)
- MicroSD card (8 GB+)
## Quick Start
### 1. Flash Raspberry Pi OS
1. Download **Raspberry Pi OS Lite (64-bit)** (no desktop) from
<https://www.raspberrypi.com/software/>.
2. Flash to MicroSD with Raspberry Pi Imager.
3. In Imager's settings (gear icon), enable SSH and set a password for the
`pi` user. Optionally configure Wi-Fi.
4. Boot the Pi.
### 2. Copy kiosk files to the Pi
From the machine running Vigilar:
```bash
scp -r kiosk/ pi@<pi-ip>:~/kiosk/
```
### 3. Run setup
```bash
ssh pi@<pi-ip>
cd ~/kiosk
sudo bash setup_kiosk.sh
```
The script will:
- Install X11, Chromium, and unclutter
- Create a `vigilar` user
- Ask for the Vigilar server URL (default: `https://vigilar.local:49735/kiosk/`)
- Configure auto-login and kiosk auto-start via systemd
- Set GPU memory, screen blanking, hostname, and SSH
### 4. Reboot
```bash
sudo reboot
```
The Pi will boot directly into the fullscreen camera grid.
## Reconfiguring
Change URL, rotation, or resolution without re-running full setup:
```bash
# Interactive
sudo ./update_kiosk.sh
# Non-interactive
sudo ./update_kiosk.sh --url https://192.168.1.50:49735/kiosk/ --restart
# Change rotation (requires reboot)
sudo ./update_kiosk.sh --rotation 90
sudo reboot
```
## Files
| File | Purpose |
|------|---------|
| `setup_kiosk.sh` | Full initial setup script |
| `update_kiosk.sh` | Reconfigure URL/rotation/resolution |
| `kiosk.service` | systemd unit (installed by setup) |
| `kiosk_config.txt` | Template config (copied to Pi) |
On the Pi after setup:
| File | Purpose |
|------|---------|
| `/home/vigilar/kiosk_config.txt` | Active configuration |
| `/home/vigilar/.xinitrc` | X session startup |
| `/home/vigilar/.bash_profile` | Fallback auto-start |
| `/etc/systemd/system/vigilar-kiosk.service` | systemd service |
## Management
```bash
# Check status
sudo systemctl status vigilar-kiosk
# View logs
sudo journalctl -u vigilar-kiosk -f
# Restart kiosk
sudo systemctl restart vigilar-kiosk
# Stop kiosk
sudo systemctl stop vigilar-kiosk
# Switch from systemd to .bash_profile method
sudo systemctl disable vigilar-kiosk
# Then uncomment 'exec startx' in /home/vigilar/.bash_profile
```
## Troubleshooting
### Black screen after boot
- Check that the Vigilar server is reachable: `curl -k https://vigilar.local:49735/kiosk/`
- Check service logs: `sudo journalctl -u vigilar-kiosk --no-pager -n 50`
- Verify X can start: `sudo -u vigilar startx -- -nocursor`
### "Cannot open display" errors
- Ensure the Pi is booting to tty1 and the service has TTY access
- Check: `sudo systemctl status vigilar-kiosk`
### Certificate errors in Chromium
- The `.xinitrc` includes `--ignore-certificate-errors` for self-signed certs
- For production, use a proper certificate on the Vigilar server
### Screen stays on when it should sleep
- Screen blanking is deliberately disabled for a security kiosk
- To re-enable: remove `consoleblank=0` from cmdline.txt, remove `xset` lines from `.xinitrc`
### Resolution or rotation not applied
- Rotation and resolution set in `config.txt` require a reboot
- Check current settings: `cat /boot/firmware/config.txt` (Bookworm) or `cat /boot/config.txt`
### Low memory on Pi Zero 2W
- Chromium with `--incognito` and `--disk-cache-dir=/dev/null` minimises memory use
- The setup sets `gpu_mem=128` which is a good balance
- If OOM occurs, try `gpu_mem=64` in config.txt

30
kiosk/kiosk.service Normal file
View File

@@ -0,0 +1,30 @@
[Unit]
Description=Vigilar Kiosk (X11 + Chromium)
After=network-online.target systemd-user-sessions.service
Wants=network-online.target
[Service]
Type=simple
User=vigilar
Group=vigilar
PAMName=login
TTYPath=/dev/tty1
StandardInput=tty
StandardOutput=journal
StandardError=journal
# Ensure we have access to the display hardware
SupplementaryGroups=video input render
Environment=HOME=/home/vigilar
Environment=XDG_RUNTIME_DIR=/run/user/1001
WorkingDirectory=/home/vigilar
ExecStartPre=/bin/bash -c 'source /home/vigilar/kiosk_config.txt'
ExecStart=/usr/bin/xinit /home/vigilar/.xinitrc -- /usr/bin/X :0 vt1 -keeptty -nocursor
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target

3
kiosk/kiosk_config.txt Normal file
View File

@@ -0,0 +1,3 @@
VIGILAR_URL=https://vigilar.local:49735/kiosk/
ROTATION=0
RESOLUTION=1920x1080

385
kiosk/setup_kiosk.sh Executable file
View File

@@ -0,0 +1,385 @@
#!/usr/bin/env bash
# Vigilar Kiosk — Full Raspberry Pi setup script
# Run on a fresh Raspberry Pi OS Lite (64-bit, no desktop).
# Safe to re-run (idempotent).
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
KIOSK_USER="vigilar"
KIOSK_HOME="/home/${KIOSK_USER}"
CONFIG_FILE="${KIOSK_HOME}/kiosk_config.txt"
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
info() { printf '\n\033[1;34m>>> %s\033[0m\n' "$*"; }
warn() { printf '\033[1;33mWARN: %s\033[0m\n' "$*"; }
error() { printf '\033[1;31mERROR: %s\033[0m\n' "$*" >&2; exit 1; }
need_root() {
if [[ $EUID -ne 0 ]]; then
error "This script must be run as root (use sudo)."
fi
}
# ---------------------------------------------------------------------------
# Pre-flight
# ---------------------------------------------------------------------------
need_root
info "Vigilar Kiosk Setup"
echo "This script turns a Raspberry Pi into a dedicated security-camera display."
echo ""
# Detect Debian version
if [[ -f /etc/os-release ]]; then
# shellcheck source=/dev/null
. /etc/os-release
DEBIAN_VERSION="${VERSION_ID:-11}"
else
DEBIAN_VERSION="11"
fi
info "Detected Debian version: ${DEBIAN_VERSION} (${PRETTY_NAME:-unknown})"
# ---------------------------------------------------------------------------
# 1. Ask for Vigilar server URL
# ---------------------------------------------------------------------------
DEFAULT_URL="https://vigilar.local:49735/kiosk/"
read -r -p "Vigilar server URL [${DEFAULT_URL}]: " USER_URL
VIGILAR_URL="${USER_URL:-$DEFAULT_URL}"
# ---------------------------------------------------------------------------
# 2. Ask for display settings
# ---------------------------------------------------------------------------
read -r -p "Screen rotation (0/90/180/270) [0]: " USER_ROTATION
ROTATION="${USER_ROTATION:-0}"
read -r -p "Screen resolution (e.g. 1920x1080, 1280x720) [1920x1080]: " USER_RES
RESOLUTION="${USER_RES:-1920x1080}"
echo ""
info "Configuration summary"
echo " URL: ${VIGILAR_URL}"
echo " Rotation: ${ROTATION}"
echo " Resolution: ${RESOLUTION}"
echo ""
read -r -p "Continue? [Y/n]: " CONFIRM
if [[ "${CONFIRM,,}" == "n" ]]; then
echo "Aborted."
exit 0
fi
# ---------------------------------------------------------------------------
# 3. Install packages
# ---------------------------------------------------------------------------
info "Updating package lists"
apt-get update -qq
info "Installing X11, Chromium, and utilities"
PACKAGES=(
xserver-xorg
xinit
x11-xserver-utils
chromium-browser
unclutter
)
# On Bookworm the package may just be 'chromium'
if [[ "${DEBIAN_VERSION}" -ge 12 ]]; then
# Try chromium-browser first; fall back to chromium
if ! apt-cache show chromium-browser &>/dev/null; then
PACKAGES=("${PACKAGES[@]/chromium-browser/chromium}")
fi
fi
apt-get install -y -qq "${PACKAGES[@]}"
# ---------------------------------------------------------------------------
# 4. Create kiosk user
# ---------------------------------------------------------------------------
if id "${KIOSK_USER}" &>/dev/null; then
info "User '${KIOSK_USER}' already exists"
else
info "Creating user '${KIOSK_USER}'"
useradd -m -s /bin/bash -G video,input,render,tty "${KIOSK_USER}"
fi
# Ensure group memberships even if user existed
usermod -aG video,input,render,tty "${KIOSK_USER}"
# ---------------------------------------------------------------------------
# 5. Write config file
# ---------------------------------------------------------------------------
info "Writing ${CONFIG_FILE}"
cat > "${CONFIG_FILE}" <<CFGEOF
VIGILAR_URL=${VIGILAR_URL}
ROTATION=${ROTATION}
RESOLUTION=${RESOLUTION}
CFGEOF
chown "${KIOSK_USER}:${KIOSK_USER}" "${CONFIG_FILE}"
# ---------------------------------------------------------------------------
# 6. Write .xinitrc
# ---------------------------------------------------------------------------
info "Writing ${KIOSK_HOME}/.xinitrc"
cat > "${KIOSK_HOME}/.xinitrc" <<'XINITEOF'
#!/usr/bin/env bash
# Vigilar kiosk X session
set -euo pipefail
CONFIG="$HOME/kiosk_config.txt"
if [[ -f "$CONFIG" ]]; then
# shellcheck source=/dev/null
source "$CONFIG"
fi
URL="${VIGILAR_URL:-https://vigilar.local:49735/kiosk/}"
# Disable screen blanking and DPMS
xset s off
xset s noblank
xset -dpms
# Hide cursor after 0.5 s of inactivity
unclutter -idle 0.5 -root &
# Handle rotation
ROTATION="${ROTATION:-0}"
case "${ROTATION}" in
90) xrandr --output "$(xrandr | grep ' connected' | head -1 | awk '{print $1}')" --rotate left ;;
180) xrandr --output "$(xrandr | grep ' connected' | head -1 | awk '{print $1}')" --rotate inverted ;;
270) xrandr --output "$(xrandr | grep ' connected' | head -1 | awk '{print $1}')" --rotate right ;;
*) ;; # 0 = normal, no action needed
esac
# Determine chromium binary
CHROMIUM=""
for candidate in chromium-browser chromium; do
if command -v "$candidate" &>/dev/null; then
CHROMIUM="$candidate"
break
fi
done
if [[ -z "$CHROMIUM" ]]; then
echo "ERROR: No chromium binary found" >&2
exit 1
fi
# Launch Chromium in kiosk mode
# --ignore-certificate-errors is needed for self-signed TLS certs on vigilar.local
exec "$CHROMIUM" \
--noerrdialogs \
--disable-infobars \
--kiosk \
--incognito \
--disable-translate \
--no-first-run \
--fast \
--fast-start \
--disable-features=TranslateUI \
--disk-cache-dir=/dev/null \
--check-for-update-interval=31536000 \
--ignore-certificate-errors \
--disable-component-update \
--disable-background-networking \
--disable-sync \
--autoplay-policy=no-user-gesture-required \
"$URL"
XINITEOF
chmod +x "${KIOSK_HOME}/.xinitrc"
chown "${KIOSK_USER}:${KIOSK_USER}" "${KIOSK_HOME}/.xinitrc"
# ---------------------------------------------------------------------------
# 7. Write .bash_profile for auto-start (fallback method)
# ---------------------------------------------------------------------------
info "Writing ${KIOSK_HOME}/.bash_profile (auto-start X on tty1)"
# Preserve existing content if any
BASH_PROFILE="${KIOSK_HOME}/.bash_profile"
MARKER="# --- Vigilar kiosk auto-start ---"
# Remove old block if present
if [[ -f "${BASH_PROFILE}" ]]; then
sed -i "/${MARKER}/,/# --- end Vigilar kiosk ---/d" "${BASH_PROFILE}"
fi
cat >> "${BASH_PROFILE}" <<'BPEOF'
# --- Vigilar kiosk auto-start ---
if [[ -z "${DISPLAY:-}" ]] && [[ "$(tty)" == "/dev/tty1" ]]; then
exec startx -- -nocursor
fi
# --- end Vigilar kiosk ---
BPEOF
chown "${KIOSK_USER}:${KIOSK_USER}" "${BASH_PROFILE}"
# ---------------------------------------------------------------------------
# 8. Install systemd service (default method)
# ---------------------------------------------------------------------------
info "Installing systemd service"
SERVICE_SRC="${SCRIPT_DIR}/kiosk.service"
SERVICE_DEST="/etc/systemd/system/vigilar-kiosk.service"
if [[ -f "${SERVICE_SRC}" ]]; then
cp "${SERVICE_SRC}" "${SERVICE_DEST}"
else
# Generate inline if source file not found
cat > "${SERVICE_DEST}" <<SVCEOF
[Unit]
Description=Vigilar Kiosk (X11 + Chromium)
After=network-online.target systemd-user-sessions.service
Wants=network-online.target
[Service]
Type=simple
User=${KIOSK_USER}
Group=${KIOSK_USER}
PAMName=login
TTYPath=/dev/tty1
StandardInput=tty
StandardOutput=journal
StandardError=journal
SupplementaryGroups=video input render
Environment=HOME=${KIOSK_HOME}
WorkingDirectory=${KIOSK_HOME}
ExecStart=/usr/bin/xinit ${KIOSK_HOME}/.xinitrc -- /usr/bin/X :0 vt1 -keeptty -nocursor
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
SVCEOF
fi
systemctl daemon-reload
systemctl enable vigilar-kiosk.service
info "systemd service enabled (vigilar-kiosk.service)"
# Disable .bash_profile auto-start when using systemd (comment it out)
sed -i "s/^ exec startx/# exec startx/" "${BASH_PROFILE}"
info "Disabled .bash_profile auto-start (systemd is the default)"
# ---------------------------------------------------------------------------
# 9. Configure auto-login on tty1
# ---------------------------------------------------------------------------
info "Configuring auto-login on tty1 for '${KIOSK_USER}'"
AUTOLOGIN_DIR="/etc/systemd/system/getty@tty1.service.d"
mkdir -p "${AUTOLOGIN_DIR}"
cat > "${AUTOLOGIN_DIR}/autologin.conf" <<ALEOF
[Service]
ExecStart=
ExecStart=-/sbin/agetty --autologin ${KIOSK_USER} --noclear %I \$TERM
ALEOF
systemctl daemon-reload
# ---------------------------------------------------------------------------
# 10. Disable console blanking
# ---------------------------------------------------------------------------
info "Disabling console screen blanking"
# Kernel cmdline approach — add consoleblank=0
CMDLINE="/boot/cmdline.txt"
# On Bookworm, firmware cmdline may be at /boot/firmware/cmdline.txt
if [[ -f /boot/firmware/cmdline.txt ]]; then
CMDLINE="/boot/firmware/cmdline.txt"
fi
if [[ -f "${CMDLINE}" ]]; then
if ! grep -q 'consoleblank=0' "${CMDLINE}"; then
sed -i 's/$/ consoleblank=0/' "${CMDLINE}"
fi
fi
# ---------------------------------------------------------------------------
# 11. GPU memory split
# ---------------------------------------------------------------------------
info "Setting GPU memory to 128 MB"
CONFIG_TXT="/boot/config.txt"
if [[ -f /boot/firmware/config.txt ]]; then
CONFIG_TXT="/boot/firmware/config.txt"
fi
if [[ -f "${CONFIG_TXT}" ]]; then
if grep -q '^gpu_mem=' "${CONFIG_TXT}"; then
sed -i 's/^gpu_mem=.*/gpu_mem=128/' "${CONFIG_TXT}"
else
echo "gpu_mem=128" >> "${CONFIG_TXT}"
fi
fi
# ---------------------------------------------------------------------------
# 12. Screen rotation and resolution in config.txt
# ---------------------------------------------------------------------------
info "Configuring display rotation and resolution"
if [[ -f "${CONFIG_TXT}" ]]; then
# Rotation via display_rotate (legacy) or display_lcd_rotate
if [[ "${ROTATION}" != "0" ]]; then
ROTATE_VAL=0
case "${ROTATION}" in
90) ROTATE_VAL=1 ;;
180) ROTATE_VAL=2 ;;
270) ROTATE_VAL=3 ;;
esac
if grep -q '^display_rotate=' "${CONFIG_TXT}"; then
sed -i "s/^display_rotate=.*/display_rotate=${ROTATE_VAL}/" "${CONFIG_TXT}"
else
echo "display_rotate=${ROTATE_VAL}" >> "${CONFIG_TXT}"
fi
fi
# Resolution via hdmi_group and hdmi_mode
# Parse WxH
RES_W="${RESOLUTION%%x*}"
RES_H="${RESOLUTION##*x}"
HDMI_MODE=""
case "${RES_W}x${RES_H}" in
1920x1080) HDMI_MODE=16 ;;
1280x720) HDMI_MODE=4 ;;
1680x1050) HDMI_MODE=58 ;;
1280x1024) HDMI_MODE=35 ;;
1024x768) HDMI_MODE=16 ;; # DMT mode 16
*) warn "Unknown resolution ${RESOLUTION}, skipping hdmi_mode config" ;;
esac
if [[ -n "${HDMI_MODE}" ]]; then
# hdmi_group=1 = CEA (TVs), hdmi_group=2 = DMT (monitors)
HDMI_GROUP=1
if [[ "${RES_W}x${RES_H}" == "1680x1050" ]] || [[ "${RES_W}x${RES_H}" == "1280x1024" ]]; then
HDMI_GROUP=2
fi
for KEY_VAL in "hdmi_group=${HDMI_GROUP}" "hdmi_mode=${HDMI_MODE}"; do
KEY="${KEY_VAL%%=*}"
if grep -q "^${KEY}=" "${CONFIG_TXT}"; then
sed -i "s/^${KEY}=.*/${KEY_VAL}/" "${CONFIG_TXT}"
else
echo "${KEY_VAL}" >> "${CONFIG_TXT}"
fi
done
fi
fi
# ---------------------------------------------------------------------------
# 13. Enable SSH
# ---------------------------------------------------------------------------
info "Enabling SSH"
systemctl enable ssh 2>/dev/null || systemctl enable sshd 2>/dev/null || true
systemctl start ssh 2>/dev/null || systemctl start sshd 2>/dev/null || true
# ---------------------------------------------------------------------------
# 14. Set hostname
# ---------------------------------------------------------------------------
info "Setting hostname to 'vigilar-kiosk'"
hostnamectl set-hostname vigilar-kiosk 2>/dev/null || {
echo "vigilar-kiosk" > /etc/hostname
sed -i "s/127\.0\.1\.1.*/127.0.1.1\tvigilar-kiosk/" /etc/hosts
}
# ---------------------------------------------------------------------------
# Done
# ---------------------------------------------------------------------------
info "Setup complete!"
echo ""
echo " Kiosk URL: ${VIGILAR_URL}"
echo " User: ${KIOSK_USER}"
echo " Service: vigilar-kiosk.service (systemd, enabled)"
echo " Config: ${CONFIG_FILE}"
echo ""
echo " To start now: sudo systemctl start vigilar-kiosk"
echo " To check status: sudo systemctl status vigilar-kiosk"
echo " To view logs: sudo journalctl -u vigilar-kiosk -f"
echo " To reconfigure: sudo ./update_kiosk.sh"
echo ""
echo " A reboot is recommended: sudo reboot"

196
kiosk/update_kiosk.sh Executable file
View File

@@ -0,0 +1,196 @@
#!/usr/bin/env bash
# Vigilar Kiosk — Update/reconfigure script
# Change the URL, rotation, or resolution without re-running full setup.
set -euo pipefail
KIOSK_USER="vigilar"
KIOSK_HOME="/home/${KIOSK_USER}"
CONFIG_FILE="${KIOSK_HOME}/kiosk_config.txt"
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
info() { printf '\n\033[1;34m>>> %s\033[0m\n' "$*"; }
warn() { printf '\033[1;33mWARN: %s\033[0m\n' "$*"; }
error() { printf '\033[1;31mERROR: %s\033[0m\n' "$*" >&2; exit 1; }
need_root() {
if [[ $EUID -ne 0 ]]; then
error "This script must be run as root (use sudo)."
fi
}
# ---------------------------------------------------------------------------
# Load current config
# ---------------------------------------------------------------------------
need_root
CURRENT_URL=""
CURRENT_ROTATION="0"
CURRENT_RESOLUTION="1920x1080"
if [[ -f "${CONFIG_FILE}" ]]; then
# shellcheck source=/dev/null
source "${CONFIG_FILE}"
CURRENT_URL="${VIGILAR_URL:-}"
CURRENT_ROTATION="${ROTATION:-0}"
CURRENT_RESOLUTION="${RESOLUTION:-1920x1080}"
fi
info "Vigilar Kiosk — Update Configuration"
echo ""
echo "Current settings:"
echo " URL: ${CURRENT_URL:-<not set>}"
echo " Rotation: ${CURRENT_ROTATION}"
echo " Resolution: ${CURRENT_RESOLUTION}"
echo ""
# ---------------------------------------------------------------------------
# Parse arguments or ask interactively
# ---------------------------------------------------------------------------
usage() {
echo "Usage: $0 [--url URL] [--rotation 0|90|180|270] [--resolution WxH]"
echo ""
echo "Options:"
echo " --url URL Vigilar server URL"
echo " --rotation DEGREE Screen rotation (0, 90, 180, 270)"
echo " --resolution WxH Screen resolution (e.g. 1920x1080)"
echo " --restart Restart the kiosk service after update"
echo " -h, --help Show this help"
exit 0
}
NEW_URL=""
NEW_ROTATION=""
NEW_RESOLUTION=""
DO_RESTART=false
while [[ $# -gt 0 ]]; do
case "$1" in
--url) NEW_URL="$2"; shift 2 ;;
--rotation) NEW_ROTATION="$2"; shift 2 ;;
--resolution) NEW_RESOLUTION="$2"; shift 2 ;;
--restart) DO_RESTART=true; shift ;;
-h|--help) usage ;;
*) warn "Unknown option: $1"; shift ;;
esac
done
# If no arguments given, ask interactively
if [[ -z "${NEW_URL}" && -z "${NEW_ROTATION}" && -z "${NEW_RESOLUTION}" ]]; then
read -r -p "Vigilar URL [${CURRENT_URL}]: " NEW_URL
read -r -p "Rotation (0/90/180/270) [${CURRENT_ROTATION}]: " NEW_ROTATION
read -r -p "Resolution [${CURRENT_RESOLUTION}]: " NEW_RESOLUTION
fi
# Fall back to current values
VIGILAR_URL="${NEW_URL:-$CURRENT_URL}"
ROTATION="${NEW_ROTATION:-$CURRENT_ROTATION}"
RESOLUTION="${NEW_RESOLUTION:-$CURRENT_RESOLUTION}"
# Validate rotation
case "${ROTATION}" in
0|90|180|270) ;;
*) error "Invalid rotation: ${ROTATION}. Must be 0, 90, 180, or 270." ;;
esac
# Validate resolution format
if [[ ! "${RESOLUTION}" =~ ^[0-9]+x[0-9]+$ ]]; then
error "Invalid resolution format: ${RESOLUTION}. Expected WxH (e.g. 1920x1080)."
fi
# ---------------------------------------------------------------------------
# Write config
# ---------------------------------------------------------------------------
info "Writing ${CONFIG_FILE}"
cat > "${CONFIG_FILE}" <<CFGEOF
VIGILAR_URL=${VIGILAR_URL}
ROTATION=${ROTATION}
RESOLUTION=${RESOLUTION}
CFGEOF
chown "${KIOSK_USER}:${KIOSK_USER}" "${CONFIG_FILE}"
echo ""
echo " URL: ${VIGILAR_URL}"
echo " Rotation: ${ROTATION}"
echo " Resolution: ${RESOLUTION}"
# ---------------------------------------------------------------------------
# Update boot config.txt if rotation or resolution changed
# ---------------------------------------------------------------------------
CONFIG_TXT="/boot/config.txt"
if [[ -f /boot/firmware/config.txt ]]; then
CONFIG_TXT="/boot/firmware/config.txt"
fi
BOOT_CHANGED=false
if [[ -f "${CONFIG_TXT}" ]]; then
# Rotation
if [[ "${ROTATION}" != "${CURRENT_ROTATION}" ]]; then
ROTATE_VAL=0
case "${ROTATION}" in
90) ROTATE_VAL=1 ;;
180) ROTATE_VAL=2 ;;
270) ROTATE_VAL=3 ;;
esac
if grep -q '^display_rotate=' "${CONFIG_TXT}"; then
sed -i "s/^display_rotate=.*/display_rotate=${ROTATE_VAL}/" "${CONFIG_TXT}"
else
echo "display_rotate=${ROTATE_VAL}" >> "${CONFIG_TXT}"
fi
BOOT_CHANGED=true
fi
# Resolution
if [[ "${RESOLUTION}" != "${CURRENT_RESOLUTION}" ]]; then
RES_W="${RESOLUTION%%x*}"
RES_H="${RESOLUTION##*x}"
HDMI_MODE=""
case "${RES_W}x${RES_H}" in
1920x1080) HDMI_MODE=16 ;;
1280x720) HDMI_MODE=4 ;;
1680x1050) HDMI_MODE=58 ;;
1280x1024) HDMI_MODE=35 ;;
*) warn "Unknown resolution ${RESOLUTION}, skipping hdmi_mode" ;;
esac
if [[ -n "${HDMI_MODE}" ]]; then
HDMI_GROUP=1
if [[ "${RES_W}x${RES_H}" == "1680x1050" ]] || [[ "${RES_W}x${RES_H}" == "1280x1024" ]]; then
HDMI_GROUP=2
fi
for KEY_VAL in "hdmi_group=${HDMI_GROUP}" "hdmi_mode=${HDMI_MODE}"; do
KEY="${KEY_VAL%%=*}"
if grep -q "^${KEY}=" "${CONFIG_TXT}"; then
sed -i "s/^${KEY}=.*/${KEY_VAL}/" "${CONFIG_TXT}"
else
echo "${KEY_VAL}" >> "${CONFIG_TXT}"
fi
done
BOOT_CHANGED=true
fi
fi
fi
# ---------------------------------------------------------------------------
# Restart service if requested
# ---------------------------------------------------------------------------
if [[ "${DO_RESTART}" == true ]]; then
info "Restarting vigilar-kiosk service"
systemctl restart vigilar-kiosk.service
echo "Service restarted."
fi
# ---------------------------------------------------------------------------
# Done
# ---------------------------------------------------------------------------
info "Configuration updated!"
if [[ "${BOOT_CHANGED}" == true ]]; then
echo ""
echo " Boot config was changed. A reboot is required for display changes."
echo " Run: sudo reboot"
elif [[ "${DO_RESTART}" != true ]]; then
echo ""
echo " To apply URL changes: sudo systemctl restart vigilar-kiosk"
echo " For display changes: sudo reboot"
fi