Refactor first-boot rotation setup to use kernel command line for persistent display rotation. Update documentation to clarify the new method of setting screen orientation (90° clockwise) via cmdline.txt, eliminating the need for one-shot scripts. Enhance logging and user guidance for rotation and wallpaper configuration during first boot.
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=Set rotation at login
|
||||||
|
Exec=/home/pi/set-rotation-at-login.sh
|
||||||
|
X-GNOME-Autostart-enabled=true
|
||||||
@@ -119,14 +119,13 @@ These changes take effect after a reboot.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Screen rotation (portrait → landscape, “Left”)
|
## Screen rotation (portrait → landscape, 90° clockwise)
|
||||||
|
|
||||||
The reTerminal DM default is portrait. Rotation is set using **wlr-randr** (labwc/Wayland), so nothing is written to `/boot/firmware/config.txt`.
|
The reTerminal DM default is portrait. Rotation is set **persistently** via the kernel command line (KMS driver), so it survives reboots and does not depend on the desktop session.
|
||||||
|
|
||||||
- **One-shot autostart** — A small script runs once when user `pi` first logs into the graphical session:
|
- **Kernel cmdline** — First-boot appends **`video=DSI-1:rotate=90`** to **`/boot/firmware/cmdline.txt`** (or `/boot/cmdline.txt`). The file must remain **one single line** with no line breaks.
|
||||||
- **`/home/pi/set-rotation-once.sh`** — Waits 5 seconds, detects the output name with `wlr-randr`, then runs `wlr-randr --output <name> --transform 270` (Left / 90° counter-clockwise). Falls back to `DSI-1` if detection fails.
|
- **90° clockwise** — The value `90` gives 90° clockwise rotation. Other valid values: `180`, `270` (90° counter-clockwise).
|
||||||
- **`/home/pi/.config/autostart/set-rotation-once.desktop`** — Autostart entry that runs the script once at first login. Both the script and this desktop file **delete themselves** after a successful run, so rotation is applied only on first boot and never again.
|
- **Effect** — Rotation is applied by the kernel at boot; no one-shot script or wlr-randr needed.
|
||||||
- **Effect** — Same as choosing “Left” in display settings. Rotation applies after the first login; no reboot needed for rotation (only for the Seeed drivers).
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -144,7 +143,7 @@ If **`rpi-eeprom-config`** and **`rpi-eeprom-update`** are present (Pi 4/CM4), t
|
|||||||
|
|
||||||
## Reboot
|
## Reboot
|
||||||
|
|
||||||
Runs **`reboot`** so the kernel and display stack load the new Seeed drivers. After reboot, the screen and touch work; on **pi**’s first login the one-shot sets rotation to “Left” (landscape), and the Chromium kiosk and Maliit start via autostart.
|
Runs **`reboot`** so the kernel and display stack load the new Seeed drivers and the cmdline rotation. After reboot, the screen and touch work with rotation applied (video=DSI-1:rotate=90), and the Chromium kiosk and Maliit start via autostart on **pi**'s login.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -153,5 +152,5 @@ Runs **`reboot`** so the kernel and display stack load the new Seeed drivers. Af
|
|||||||
- **File server** — Edit `FILE_SERVER` if your assets are served from another host/port. Host all files listed in **`files-from-guard/README.md`** and **`config-files/README.md`** (kiosk, splash, Plymouth, LightDM, Maliit, one-shots and their .desktop files).
|
- **File server** — Edit `FILE_SERVER` if your assets are served from another host/port. Host all files listed in **`files-from-guard/README.md`** and **`config-files/README.md`** (kiosk, splash, Plymouth, LightDM, Maliit, one-shots and their .desktop files).
|
||||||
- **Kiosk URL** — The URL Chromium opens is defined in `start-chromium.sh` on your file server (e.g. `--app=http://127.0.0.1:8080`); change it there.
|
- **Kiosk URL** — The URL Chromium opens is defined in `start-chromium.sh` on your file server (e.g. `--app=http://127.0.0.1:8080`); change it there.
|
||||||
- **User** — If you use a user other than `pi`, replace `pi` in this script and in the files on the file server (paths and ownership).
|
- **User** — If you use a user other than `pi`, replace `pi` in this script and in the files on the file server (paths and ownership).
|
||||||
- **Screen rotation** — The one-shot runs `wlr-randr --output <name> --transform 270` (Left). To use another orientation, change `270` to `90` (right), `180` (inverted), or `normal`.
|
- **Screen rotation** — Set in `/boot/firmware/cmdline.txt`: `video=DSI-1:rotate=90` (90° clockwise). Use `180` or `270` for other orientations. Keep the file one single line.
|
||||||
- **Desktop wallpaper** — First-boot writes `wallpaper=` and `wallpaper_mode=crop` into pcmanfm’s `desktop-items-0.conf`. To change later: `pcmanfm --set-wallpaper /path/to/image --wallpaper-mode=crop`. **Other pcmanfm options:** `pcmanfm --desktop` (start desktop manager), `pcmanfm --desktop-pref` (open desktop preferences GUI), `pcmanfm --desktop-off` (stop desktop manager), `pcmanfm -w FILE` (short form of --set-wallpaper). Wallpaper modes: `crop`, `stretch`, `fit`, `center`, `tile`, `screen`, `color`.
|
- **Desktop wallpaper** — First-boot writes `wallpaper=` and `wallpaper_mode=crop` into pcmanfm’s `desktop-items-0.conf`. To change later: `pcmanfm --set-wallpaper /path/to/image --wallpaper-mode=crop`. **Other pcmanfm options:** `pcmanfm --desktop` (start desktop manager), `pcmanfm --desktop-pref` (open desktop preferences GUI), `pcmanfm --desktop-off` (stop desktop manager), `pcmanfm -w FILE` (short form of --set-wallpaper). Wallpaper modes: `crop`, `stretch`, `fit`, `center`, `tile`, `screen`, `color`.
|
||||||
|
|||||||
@@ -182,12 +182,19 @@ fi
|
|||||||
log "Running update-initramfs to apply Plymouth theme ..."
|
log "Running update-initramfs to apply Plymouth theme ..."
|
||||||
update-initramfs -u -k all 2>/dev/null || true
|
update-initramfs -u -k all 2>/dev/null || true
|
||||||
|
|
||||||
# --- 6b2. Kernel cmdline: swiotlb for vc4-drm (avoids "swiotlb buffer is full" / blank DSI on CM4) ---
|
# --- 6b2. Kernel cmdline: swiotlb + DSI rotation (KMS, persistent across reboots) ---
|
||||||
CMDLINE_PATH="/boot/firmware/cmdline.txt"
|
CMDLINE_PATH="/boot/firmware/cmdline.txt"
|
||||||
[[ -f "$CMDLINE_PATH" ]] || CMDLINE_PATH="/boot/cmdline.txt"
|
[[ -f "$CMDLINE_PATH" ]] || CMDLINE_PATH="/boot/cmdline.txt"
|
||||||
if [[ -f "$CMDLINE_PATH" ]] && ! grep -q 'swiotlb=' "$CMDLINE_PATH"; then
|
if [[ -f "$CMDLINE_PATH" ]]; then
|
||||||
sed -i 's/rootwait/rootwait swiotlb=65536/' "$CMDLINE_PATH"
|
if ! grep -q 'swiotlb=' "$CMDLINE_PATH"; then
|
||||||
log "Added swiotlb=65536 to kernel cmdline (vc4-drm / DSI)"
|
sed -i 's/rootwait/rootwait swiotlb=65536/' "$CMDLINE_PATH"
|
||||||
|
log "Added swiotlb=65536 to kernel cmdline (vc4-drm / DSI)"
|
||||||
|
fi
|
||||||
|
# Persistent rotation for DSI-1 (KMS): append at end of single line. 90 = 90° clockwise.
|
||||||
|
if ! grep -q 'video=DSI-1:rotate=' "$CMDLINE_PATH"; then
|
||||||
|
sed -i 's/$/ video=DSI-1:rotate=90/' "$CMDLINE_PATH"
|
||||||
|
log "Added video=DSI-1:rotate=90 to kernel cmdline (DSI rotation)"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- 6c. CM4: enable rpi-eeprom-update so boot order can be set ---
|
# --- 6c. CM4: enable rpi-eeprom-update so boot order can be set ---
|
||||||
@@ -274,10 +281,10 @@ SVCEOF
|
|||||||
systemctl enable set-cm4-boot-order-once.service 2>/dev/null && log "Enabled set-cm4-boot-order-once.service to set boot order after next boot"
|
systemctl enable set-cm4-boot-order-once.service 2>/dev/null && log "Enabled set-cm4-boot-order-once.service to set boot order after next boot"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- 7. One-shots (rotation at first login; wallpaper already set in pcmanfm config above) ---
|
# --- 7. One-shots (wallpaper already set in pcmanfm config above; rotation is via cmdline.txt) ---
|
||||||
log "--- One-shot scripts (run at pi first login) ---"
|
log "--- One-shot scripts (if any) ---"
|
||||||
install_oneshot set-rotation-once || true
|
# Rotation is set persistently in cmdline.txt (video=DSI-1:rotate=90), not via one-shot script.
|
||||||
log "One-shots will append to $LOGFILE when they run at first login"
|
log "Rotation is set via kernel cmdline (video=DSI-1:rotate=90)"
|
||||||
|
|
||||||
# --- 8. Allow pi to append to first-boot.log (for one-shot scripts) ---
|
# --- 8. Allow pi to append to first-boot.log (for one-shot scripts) ---
|
||||||
chmod 666 "$LOGFILE"
|
chmod 666 "$LOGFILE"
|
||||||
|
|||||||
@@ -26,11 +26,18 @@ if [[ -f /etc/plymouth/plymouthd.conf ]]; then
|
|||||||
fi
|
fi
|
||||||
update-initramfs -u -k all 2>/dev/null || true
|
update-initramfs -u -k all 2>/dev/null || true
|
||||||
|
|
||||||
echo "=== Rotation and wallpaper (rpd-labwc / labwc Wayland) ==="
|
echo "=== Rotation (persistent via kernel cmdline) ==="
|
||||||
echo "To set rotation and wallpaper now (in a labwc session), run as $PI_USER:"
|
CMDLINE_PATH="/boot/firmware/cmdline.txt"
|
||||||
echo " wlr-randr --output \$(wlr-randr | awk '/^[A-Za-z0-9_-]+ /{print \$1; exit}') --transform 270"
|
[[ -f "$CMDLINE_PATH" ]] || CMDLINE_PATH="/boot/cmdline.txt"
|
||||||
|
if [[ -f "$CMDLINE_PATH" ]] && ! grep -q 'video=DSI-1:rotate=' "$CMDLINE_PATH"; then
|
||||||
|
sed -i 's/$/ video=DSI-1:rotate=90/' "$CMDLINE_PATH"
|
||||||
|
echo "Added video=DSI-1:rotate=90 to $CMDLINE_PATH (90° clockwise). Reboot to apply."
|
||||||
|
else
|
||||||
|
echo "Rotation already set in cmdline or file missing. Current: $(grep -o 'video=DSI-1:rotate=[^ ]*' "$CMDLINE_PATH" 2>/dev/null || true)"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
echo "=== Wallpaper (in labwc session, as $PI_USER) ==="
|
||||||
echo " pcmanfm --set-wallpaper /usr/share/rpd-wallpaper/splash.png --wallpaper-mode=crop"
|
echo " pcmanfm --set-wallpaper /usr/share/rpd-wallpaper/splash.png --wallpaper-mode=crop"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Or ensure one-shots run at next login (they are in autostart if still present)."
|
echo "=== Reboot to apply splash, initramfs and rotation ==="
|
||||||
echo "=== Reboot to apply splash and initramfs ==="
|
|
||||||
echo " sudo reboot"
|
echo " sudo reboot"
|
||||||
|
|||||||
13
emmc-provisioning/cloud-init/set-rotation-at-login.sh
Normal file
13
emmc-provisioning/cloud-init/set-rotation-at-login.sh
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Set reTerminal DM (labwc/Wayland) rotation to Left at every login.
|
||||||
|
# Runs from autostart when user pi logs in; does not remove itself.
|
||||||
|
# Use this when wlr-randr transform does not persist across reboots.
|
||||||
|
sleep 5
|
||||||
|
OUTPUT=""
|
||||||
|
if command -v wlr-randr &>/dev/null; then
|
||||||
|
OUTPUT=$(wlr-randr 2>/dev/null | awk '/^[A-Za-z0-9_-]+ /{print $1; exit}')
|
||||||
|
fi
|
||||||
|
[[ -z "$OUTPUT" ]] && OUTPUT="DSI-1"
|
||||||
|
if [[ -n "$OUTPUT" ]] && command -v wlr-randr &>/dev/null; then
|
||||||
|
wlr-randr --output "$OUTPUT" --transform 270
|
||||||
|
fi
|
||||||
@@ -20,7 +20,13 @@ from flask import Flask, render_template, jsonify, request, send_file, redirect,
|
|||||||
|
|
||||||
from werkzeug.security import generate_password_hash, check_password_hash
|
from werkzeug.security import generate_password_hash, check_password_hash
|
||||||
|
|
||||||
|
try:
|
||||||
|
from itsdangerous import BadSignature
|
||||||
|
except ImportError:
|
||||||
|
BadSignature = Exception # noqa: disable invalid-name
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
# Set CM4_DASHBOARD_SECRET_KEY in env (e.g. via /opt/cm4-provisioning/dashboard.env) so sessions persist across restarts
|
||||||
app.secret_key = os.environ.get("CM4_DASHBOARD_SECRET_KEY", os.urandom(24).hex())
|
app.secret_key = os.environ.get("CM4_DASHBOARD_SECRET_KEY", os.urandom(24).hex())
|
||||||
|
|
||||||
# --- Paths ---
|
# --- Paths ---
|
||||||
@@ -90,7 +96,16 @@ def admin_log(action, details=None):
|
|||||||
def require_admin(f):
|
def require_admin(f):
|
||||||
@wraps(f)
|
@wraps(f)
|
||||||
def wrapped(*args, **kwargs):
|
def wrapped(*args, **kwargs):
|
||||||
if not session.get("admin_logged_in"):
|
try:
|
||||||
|
logged_in = session.get("admin_logged_in")
|
||||||
|
except (BadSignature, ValueError, OSError):
|
||||||
|
# Invalid/rotated secret key or corrupted session cookie → treat as not logged in
|
||||||
|
try:
|
||||||
|
session.clear()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
logged_in = False
|
||||||
|
if not logged_in:
|
||||||
if request.is_json or request.path.startswith("/api/"):
|
if request.is_json or request.path.startswith("/api/"):
|
||||||
return jsonify({"ok": False, "error": "Login required"}), 401
|
return jsonify({"ok": False, "error": "Login required"}), 401
|
||||||
return redirect(url_for("login", next=request.url))
|
return redirect(url_for("login", next=request.url))
|
||||||
@@ -154,6 +169,26 @@ def no_cache(response):
|
|||||||
response.headers["Pragma"] = "no-cache"
|
response.headers["Pragma"] = "no-cache"
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
@app.errorhandler(500)
|
||||||
|
def handle_500(err):
|
||||||
|
"""Log 500 and return a simple response so the user is not left with a blank error."""
|
||||||
|
import traceback
|
||||||
|
try:
|
||||||
|
traceback.print_exc()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if request.path.startswith("/api/"):
|
||||||
|
return jsonify({"ok": False, "error": "Internal server error"}), 500
|
||||||
|
return (
|
||||||
|
"<!DOCTYPE html><html><head><meta charset='utf-8'><title>Error</title></head><body>"
|
||||||
|
"<h1>Something went wrong</h1><p>Try <a href='/login'>logging in again</a> or <a href='/'>going home</a>.</p>"
|
||||||
|
"</body></html>",
|
||||||
|
500,
|
||||||
|
{"Content-Type": "text/html; charset=utf-8"},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Default cloud-init user-data for Raspberry Pi OS (NoCloud on boot partition)
|
# Default cloud-init user-data for Raspberry Pi OS (NoCloud on boot partition)
|
||||||
DEFAULT_USER_DATA = """#cloud-config
|
DEFAULT_USER_DATA = """#cloud-config
|
||||||
package_update: true
|
package_update: true
|
||||||
|
|||||||
Reference in New Issue
Block a user