Raspberry Pi: Client einrichten (Kiosk Modus)

Der CometVisu Client läuft in einem üblichen Web-Browser. Soll dieser jedoch nicht auf einem „normalen“ Gerät wie PC, Tablet oder Smartphone laufen, sondern auf einem Touch-Panel wie einem in die Wand eingelassenem Display, so wünscht man sich eine Darstellung im Vollbild ohne weitere, externe Navigations- und Kontrollelemente. Eine solche Darstellung läuft auch unter der Bezeichnung „Kiosk Modus“.

Als Basis bietet sich ein Raspberry Pi (RPi) an, da dieser von der Performance absolut ausreichend ist und nur einen sehr geringen Stromverbrauch aufweist.

Durch die beiden HDMI Ports eines Raspberry Pi 4 können bei geschickter Konfiguration auch zwei Touch-Panels gleichzeitig und unabhängig voneinander angesteuert werden, was hier im zweiten Teil umgesetzt wird.

Bemerkung

Für dieses Tutorial wird ein Raspberry Pi vorausgesetzt, der wie im ersten Teil dieser Tutorial-Serie vorbereitet wurde. Es sind aber auch ganz andere Systeme, wie z.B. ein NUC, möglich.

Als Server für die CometVisu kann ein Raspberry Pi wie aus dem Tutorial-Teil CometVisu in Docker installieren verwendet werden. Es ist dabei möglich, dass dies gleichzeitig genau der gleiche Raspberry Pi ist, auf dem nun der Kiosk-Modus eingerichtet wird. Als Server kann aber auch ein beliebiges anderes System dienen, wie beispielsweise der Timberwolf Server, bei dem die CometVisu als vorbereitete App verfügbar ist.

Der Kiosk-Modus ist aber so universell, der kann auch 1:1 für beliebige andere Anwendungen genutzt werden bei denen ein Browser im Vollbild laufen soll.

Einrichten des Kiosk-Modus

Ergebnis dieses Tutorials ist ein Kiosk Modus mit Chrome als Browser und nur der minimal notwendigen Umgebung. Daher wird bewusst auf einen Windowmanager verzichtet und eine reine X11 Umgebung verwendet.

Als erstes sind dazu die notwendigen Software-Komponenten zu installieren:

sudo apt-get update
sudo apt-get install --no-install-recommends xorg xinput chromium-browser

Hardware einrichten

Auch wenn die Hardware (das Display und das Touch Interface) in der Regel sehr gut automatisch erkannt werden, so gibt es manchmal Kleinigkeiten die angepasst werden müssen.

Beispiel: eGalax TouchScreen

Der eGalax TouchScreen eines HomeCockpit Minor von 2009 wird leicht falsch erkannt, was sich durch eine udev Regel schnell lösen lässt. Hierzu wird die neue Datei /etc/udev/rules.d/91-libinput-egalax-local.rules angelegt und befüllt mit dem Inhalt:

ACTION=="add|change", KERNEL=="event[0-9]*", ENV{ID_VENDOR_ID}=="0eef", ENV{ID_MODEL_ID}=="0001", ENV{ID_INPUT_TABLET}="", ENV{ID_INPUT_TOUCHSCREEN}="1"

Dieses Vorgehen ist ein Beispiel für genau diese Hardware. Sollte andere Hardware verwendet werden und dort Probleme auftreten, so lässt sich meist über eine Internet-Recherche eine ähnliche Lösung finden.

Touchscreen kalibrieren

Sollte der Touchscreen die Berührungen nicht richtig an die Bildschirm-Koordinaten übertragen, so muss dieser kalibriert werden. Hierzu muss xinput_calibrator installiert werden:

sudo apt-get install --no-install-recommends xinput_calibrator

Dies wird nun gestartet:

sudo xinit xinput_calibrator

Nach erfolgter Kalibrierung werden auf der Konsole die neuen Kalibrierdaten ausgegeben.

Beispiel:

pi@visu:~ $ sudo xinit xinput_calibrator
Calibrating EVDEV driver for "eGalax Inc. USB TouchController Touchscreen" id=9
        current calibration values (from XInput): min_x=2058, max_x=3998 and min_y=120, max_y=3952

Doing dynamic recalibration:
        Setting calibration data: 62, 4004, 143, 3949
        --> Making the calibration permanent <--
  copy the snippet below into '/etc/X11/xorg.conf.d/99-calibration.conf' (/usr/share/X11/xorg.conf.d/ in some distro's)
Section "InputClass"
        Identifier      "calibration"
        MatchProduct    "eGalax Inc. USB TouchController Touchscreen"
        Option  "Calibration"   "62 4004 143 3949"
        Option  "SwapAxes"      "1"
EndSection

Wie bereits aus der Ausgabe von xinput_calibrator angegeben muss nun in die neue Datei /etc/X11/xorg.conf.d/99-calibration.conf der ganze Bereich ab Section kopiert werden. Hier können auch weitere Anpassungen vorgenommen werden, wie beispielsweise auf einen anderen Treiber zu wechseln. So muss bei dem konkreten Touch-Display die Datei 99-calibration.conf lauten:

Section "InputClass"
        Identifier      "calibration"
        MatchProduct    "eGalax Inc. USB TouchController Touchscreen"
        Option  "Calibration"   "62 4004 143 3949"
        Option  "SwapAxes"      "1"
        Driver "evdev"
EndSection

Software einrichten

Erster Test

Für einen ersten Test kann nun bereits zum ersten mal der Web-Browser gestartet werden:

sudo xinit chromium-browser

Um den Test zu beenden lässt sich der Browser über Strg + C auf der Konsole wieder beenden.

Sollte bei diesem Test der Bildschirm, bzw. das Touch Interface nicht korrekt reagiert haben, so ist dies mit einer der weiter oben beschriebenen Methoden zu korrigieren. Erst wenn der Browser sich erfolgreich bedienen lässt kann in diesem Tutorial zum nächsten Punkt weiter gegangen werden.

Browser einrichten

Als root wird nun die Datei /root/start_browser.sh mit diesem Inhalt angelegt:

#!/bin/sh

# DEBUG
xsetroot -solid green

# allow any local user to use the X server
/usr/bin/xhost local:

# run the browser as the user "pi"
/usr/bin/sudo -H -u pi -- /usr/bin/chromium-browser \
  --window-position=0,0            \
  --window-size=1024,769           \
  --no-first-run                   \
  -disable-dev-tools               \
  -disable-hang-monitor            \
  -disable-java                    \
  -disable-logging                 \
  -disable-metrics                 \
  -disable-metrics-reporting       \
  -disable-plugins                 \
  -disable-popup-blocking          \
  -disable-prompt-on-repost        \
  -start-maximized                 \
  --disable-popup-blocking         \
  --disable-infobars               \
  --disable-session-crashed-bubble \
  --incognito                      \
  --kiosk                          \
  --user-data-dir=/tmp/browser     \
  http://192.168.0.30/cometvisu/

Die Zeile --window-size=1024,769 ist entsprechend der Bildschirmauflösung anzupassen. Der Wert 1024,769 hat sich als geeignet für Bildschirme mit einer Auflösung von 1024x768 herausgestellt, d.h. einen Wert für die Höhe der um einen Pixel größer ist als die Bildschirmauflösung. Durch das xsetroot -solid green am Anfang lässt sich leicht testen ob der Browser ausreichend groß ist, da ein nicht abgedeckter Bildschirmbereich grün sichtbar bleibt. Wenn alles zur Zufriedenheit läuft kann diese Zeile mit einem # am Anfang auskommentiert werden, so dass in Zukunft kein grünes Aufblinken sichtbar ist.

Außerdem ist die letzte Zeile (http://193.168.0.30/cometvisu/) auf die URL anzupassen, die der Browser anzeigen soll.

Über sudo chmod a+x /root/start_browser.sh wird die Datei nun noch als ausführbar markiert.

Ob die Einrichtung erfolgreich ist lässt sich mit

sudo xinit /root/start_browser.sh

testen.

Zertifikate installieren (optional)

Wenn die CometVisu über eine TLS verschlüsselte Verbindung (also mit dem HTTPS-Protokoll) ausgeliefert wird, was dringend empfohlen wird um die erweiterten Browser-Features frei zu schalten, so muss der Browser das Zertifikat kennen. Für eine Anwendung im Intranet können jedoch nur selbst signierte Zertifikate zum Einsatz kommen, die der Browser prinzipbedingt nicht kennen kann.

Als erstes ist die Software für der Zertifikate-Management zu installieren:

sudo apt-get install --no-install-recommends libnss3-tools

Nun muss das Zertifikat auf den Raspberry Pi übertragen werden. Wenn die CometVisu auf dem Raspberry Pi selbst gehostet wird, so ist von dort das Zertifikat zu besorgen. Wenn die CometVisu beispielsweise auf dem Timberwolf Server läuft, so kann das notwendige Zertifikat über

wget https://update.timberwolf.io/timberwolf%20web%20ca.crt

in das aktuelle Arbeitsverzeichnis geladen werden. Über einen Befehl wie

certutil -d sql:/home/pi/.pki/nssdb -A -t "CT,C,C" -n "Timberwolf Web CA - Elaborated Networks GmbH" -i timberwolf\ web\ ca.crt

lässt sich dieses nun für den User pi installieren.

Automatischer Start einrichten

Wenn der Browser sich manuell erfolgreich starten lässt, so kann nun eingerichtet werden, dass dieser nach einem Boot-Vorgang automatisch gestartet wird. Hierzu muss der systemd ein entsprechendes Ziel bekommen.

Als root muss daher die Datei /etc/systemd/system/display-manager.service mit diesem Inhalt erstellt werden:

[Unit]
Description=Direct browser starter
After=network.target

# Ordering
Conflicts=plymouth-quit-wait.service
After=systemd-user-sessions.service plymouth-start.service plymouth-quit-wait.service
OnFailure=plymouth-quit.service

[Service]
ExecStart=/usr/bin/xinit /root/start_browser.sh -- -background none vt7
Restart=always
RestartSec=1s
EnvironmentFile=-/etc/default/locale

[Install]
WantedBy=multi-user.target

Mit systemctl start display-manager.service lässt sich das neue Target testen.

Aktiviert wird es mit:

systemctl enable display-manager.service

Nach einem Neustart sollte nun wie gewünscht der Browser mit der richtigen URL im Vollbild erscheinen. Die grundlegende Kiosk-Einrichtung ist hiermit abgeschlossen.

Powermanagement

Neben allgemeinen Einstellungen, die je nach System bisschen Energie sparen können (bei dem Raspberry Pi aber nur sehr geringe Auswirkung haben), ist das wichtigste Thema das Powermanagement des Displays. Neben dem Stromverbrauch kann auch durch das Deaktivieren des Displays auch dessen Lebensdauer verlängert werden.

Ob das Ausschalten des Displays eine Option ist oder nicht hängt vom Anwendungsfall ab. Eine Anzeigetafel in einem 24/7 benutzten Raum (z.B. im Passagierbereich eines Flughafens) wird in der Regel durchlaufen. Aber bereits Anzeigen in einem Museum müssen nur während der Öffnungszeiten aktiv sein, d.h. hier kann mit einer Zeitsteuerung gearbeitet werden. Im Bereich der Gebäudeautomatisierung, wie eben auch im Smart Home, bietet es sich an die Bildschirmaktivierung mit einem Bewegungsmelder oder Präsenzmelder zu verknüpfen.

Automatisches Bildschirmabschalten verhindern

Wenn nur über externe Quellen der Bildschirm geschaltet werden soll, so muss verhindert werden, dass sich dieser über einen Bildschirmschoner selber ausschaltet.

Hierzu ist die Datei /root/start_browser.sh am Anfang (nach der Zeile #!/bin/sh um diese Zeilen zu erweitern:

# disable screen saver and simple timeout based display power management
/usr/bin/xset dpms 0 0 0
/usr/bin/xset s off
/usr/bin/xset -dpms

Bildschirm aktivieren und deaktivieren

Da ein Raspberry Pi selbst keinen Schlafzustand kennt und aus einem Halt nicht über ein Wake on LAN aufgeweckt werden kann bietet sich nur ein Powermanagement der Bildschirme über DPMS an.

Alternative 1: Manuelle Steuerung

Grundsätzlich kann der Bildschirm mit dem Befehl

xset -display :0 dpms force off

ausgeschaltet werden und mit

xset -display :0 dpms force on

wieder angeschaltet werden. Um ein selbständiges Ausschalten zu verhindern sollten dabei noch die vier Zeilen aus dem Abschnitt „Automatisches Bildschirmabschalten verhindern“ eingefügt werden.

Alternative 2: Halbautomatische Steuerung

Gerade im Bereich der Heimautomatisierung bietet sich jedoch die halbautomatische Variante an. Hier wird der Bildschirm nach einem Timeout ausgeschaltet. Eingeschaltet wird er von einem extern gesendetem Kommando (das z.B. von einem Bewegungsmelder oder Präsenzmelder getriggert wird). Außerdem lässt sich hier der Bildschirm über eine Berührung aktivieren, falls der Bewegungsmelder nicht reagieren sollte.

Für den Timer ist die Datei /root/start_browser.sh am Anfang (nach der Zeile #!/bin/sh um diese Zeilen zu erweitern:

/usr/bin/xset s off
/usr/bin/xset +dpms
# schalte nach 5 Minuten aus
/usr/bin/xset dpms 0 0 300

Die letzte Zeile kann je nach Bedarf angepasst werden: die 300 sind in Sekunden die Dauer die nach der letzten Bedienung (oder des externen Triggers) abgewartet wird bis der Bildschirm abgeschaltet wird.

Um extern triggern zu können wird auf dem Raspberry Pi das Programm xdotool benötigt, dass noch installiert werden muss:

sudo apt-get install --no-install-recommends xdotool

Von einem Automatisierungsserver muss nun zum Aktivieren des Bildschirms über SSH als root der Befehl

DISPLAY=:0 xdotool mousemove_relative 1 0 mousemove_relative -- -1 0

gesendet werden.

Rechner schlafen legen und aufwecken

Bemerkung

Dieser Abschnitt eignet sich nicht für einen Raspberry Pi (zumindest nicht für die Versionen 1 bis 4, die bei Erstellung dieses Tutorials aktuell waren). Jedoch bei anderen Kiosk-Rechnern, insbesondere welchen die auf PC Technik basieren, kann als Alternative zum Powermanagement mit DPMS auch der ganze Rechner schlafen gelegt werden (Suspend to RAM) um Strom zu sparen und den Bildschirm zu deaktivieren.

Für den Schlaf-Befehl muss vom Kontroll-Rechner (der Automatisierungs-Server) über SSH als root der Befehl

systemctl suspend

gesendet werden. Ein komplettes Herunterfahren wäre über den Befehl

systemctl poweroff

möglich.

Ein Aufwecken wäre dann über Wake on LAN (WOL) möglich.

Start-Animation

Damit bei einem Start des Raspberry Pi die für Nicht-Techniker unschönen Boot-Meldungen hinter einen schönen Animation versteckt werden kann der plymouth Service eingerichtet werden. Hier gibt es auch eine Animation extra für die CometVisu.

Zum Installieren werden diese Befehle benötigt:

sudo apt-get install --no-install-recommends plymouth
wget -O CometVisu_Misc.zip https://github.com/CometVisu/Misc/archive/refs/heads/master.zip
unzip CometVisu_Misc.zip "Misc-master/plymouth/cometvisu/*"
sudo mv Misc-master/plymouth/cometvisu /usr/share/plymouth/themes/
rm -rf Misc-master/ CometVisu_Misc.zip

Ob die Installation funktioniert hat sieht man über plymouth-set-default-theme -l, wenn in der Liste cometvisu auftaucht. Aktiviert wird nun das CometVisu Plymouth Theme über

sudo plymouth-set-default-theme -R cometvisu

Damit beim Boot-Vorgang der Plymouth Bootscreen angezeigt wird muss noch in die Datei /boot/cmdline.txt die Zeile um diese Einträge verlängert werden:

logo.nologo loglevel=1 quiet splash vt.global_cursor_default=0 plymouth.ignore-serial-consoles

Um den „Regenboden-Screen“ beim Start des Raspberry Pi zu unterdrücken kann außerdem (als root) in der Datei /boot/config.txt am Ende diese Zeile angehängt werden:

disable_splash=1

Bemerkung

Da der Boot-Vorgang am Raspberry Pi sehr schnell passiert ist es gut möglich, dass der Plymouth Splash Screen nur kurz sichtbar ist.

Erweiterung auf zwei unabhängige Touch Panels

Durch die bei dem Raspberry Pi vorhandenen doppelten HDMI Ausgänge bietet es sich an zwei Touch Screens mit nur einem Raspberry Pi zu betreiben. Hierdurch kann Strom, aber auch Administrationsaufwand und Anschaffungskosten eingespart werden. Die große Flexibilität von Linux kann hier auch ihre Stärke ausspielen, da es bei X11 möglich ist zwei unabhängige Cursor gleichzeitig zu nutzen.

Die allgemeine Einrichtung von zwei Displays folgt dem im vorderen Teil beschriebenen Vorgehen.

Mit zwei Displays erweitert der Raspberry Pi beide zu einem großen Bildschirm. Für einen Arbeitsplatz ist dieses Verhalten gewünscht, bei zwei getrennt montierten Displays ist dieses Vorgehen jedoch nicht von Vorteil, bei der Analyse von Problemen hilft es jedoch dieses Verhalten im Hinterkopf zu behalten.

In dem Tutorial werden nun beide Displays aus Sicht des Raspberry Pi direkt nebeneinander als ein großer, virtueller Bildschirm positioniert, auch wenn die beiden Touch Screens natürlich getrennt voneinander montiert werden.

Um nun die richtige Reihenfolge festzulegen wird die Datei /etc/X11/xorg.conf.d/90-dualscreen.conf angelegt und befüllt mit:

Section "Monitor"
        Identifier "HDMI-1"
        Option     "Primary" "true"
EndSection

Section "Monitor"
        Identifier "HDMI-2"
        Option     "LeftOf" "HDMI-1"
EndSection

Mit dieser Datei wird das Display an HDMI Ausgang 2 links von dem am HDMI Ausgang 1 dargestellt.

Als zweites sollen auf beiden Displays jeweils ein eigener Browser erscheinen. Hierzu ist die Datei /root/start_browser.sh am Ende um einen weiteren Aufruf des Browser zu erweitern. Wichtig: da der Aufruf des Browsers nicht sofort „zurückkehrt“ muss der erste(!) Browser nach seinem Aufruf sofort in den Hintergrund geschickt werden. Dies erreicht man, in dem am Ende des Aufrufs ein & angehängt wird. Somit könnte die Datei z.B. so aussehen:

#!/bin/sh

# DEBUG
xsetroot -solid green

# allow any local user to use the X server
/usr/bin/xhost local:

# run the first browser as the user "pi"
/usr/bin/sudo -H -u pi -- /usr/bin/chromium-browser \
  --window-position=0,0            \
  --window-size=1024,769           \
  --no-first-run                   \
  -disable-dev-tools               \
  -disable-hang-monitor            \
  -disable-java                    \
  -disable-logging                 \
  -disable-metrics                 \
  -disable-metrics-reporting       \
  -disable-plugins                 \
  -disable-popup-blocking          \
  -disable-prompt-on-repost        \
  -start-maximized                 \
  --disable-popup-blocking         \
  --disable-infobars               \
  --disable-session-crashed-bubble \
  --incognito                      \
  --kiosk                          \
  --user-data-dir=/tmp/browser1    \
  http://192.168.0.30/cometvisu/ &

# run the second browser as the user "pi"
/usr/bin/sudo -H -u pi -- /usr/bin/chromium-browser \
  --window-position=1024,0         \
  --window-size=1024,769           \
  --no-first-run                   \
  -disable-dev-tools               \
  -disable-hang-monitor            \
  -disable-java                    \
  -disable-logging                 \
  -disable-metrics                 \
  -disable-metrics-reporting       \
  -disable-plugins                 \
  -disable-popup-blocking          \
  -disable-prompt-on-repost        \
  -start-maximized                 \
  --disable-popup-blocking         \
  --disable-infobars               \
  --disable-session-crashed-bubble \
  --incognito                      \
  --kiosk                          \
  --user-data-dir=/tmp/browser2    \
  http://192.168.0.30/cometvisu/

Auch wichtig ist, dass --user-data-dir auf zwei unterschiedliche Verzeichnisse verweist, da sonst Chrome seine beiden Fenster nur übereinander legen würde. Neben diesem Parameter muss auch noch --window-position basierend der konkreten Bildschirmgröße angepasst werden, da hiermit das zweite Browserfenster auf den zweiten Bildschirm verschoben wird.