Wenn die Webseite fällt …

Letztens fragte mich eine Kundin, ob ich mir einmal ihre Webseite anschauen könnte. Klar, schnell gemacht. Dabei habe ich gleich mehrere Sicherheitslücken gefunden und nebenbei auch ein paar ergonomische Themen angesprochen.

Da sieht man wieder, wie wertvoll es sein kann, wenn jemand einmal unbedarft auf eine Webseite schaut. Wenn das dann noch mit technischem Know-how gepaart ist, steht einem professionellen und sicherem Erscheinungsbild nichts mehr im Weg.

Czaja IT Dienstleistungen und Unternehmensberatung Telefon 0177 7680425 E-Mail consulting@svenczaja.de

Angebot: Sofern Sie gerne auch Ihre Webseite einmal sicherheitstechnisch prüfen lassen wollen. Kontaktieren Sie mich gerne. Im Rahmen meiner Firmen IT-Dienstleistungen biete ich Sicherheit-Services ebenfalls an.

Gerade Schäden durch manipulierte Webseiten werden immer noch unterschätzt. Defacing, also das Verunstalten einer Webseite, ist dabei oft noch das kleinste Problem. Wenn jedoch urheberrechtlich geschützte Filme plötzlich zum Download bereitgestellt werden, während man davon auf der eigenen Webseite gar nichts mitbekommt, kann es richtig teuer werden.

Auch hinterlegte Schadsoftware, die es Angreifenden ermöglicht, die Besuchenden der Webseite zu kompromittieren, ist leider keine Seltenheit. Und wer möchte schon gerne von seinen Kunden hören:

„Das habe ich mir von deiner Webseite eingefangen.“

Dann ist die schöne Reputation schnell dahin.

Daneben habe ich bei Kunden auch schon öffentlich erreichbare Preislisten und detaillierte Produktinformationen gesehen, die eigentlich nur in einem geschützten Kundenbereich liegen sollten. Woher kommt das? Oftmals werden Webseiten irgendwann einmal bei einem Dienstleister einmalig beauftragt. Der richtet dann alles schön ein und gestaltet alles ganz toll. Vielleicht traut sich der eine oder andere das auch selbst zu, denn heute funktioniert vieles nach Baukastenprinzip.

Und dann vergisst man das Ganze. Das entspricht ungefähr einem neuen Auto, das man sich einmal kauft und denkt, das läuft jetzt erst einmal, da muss ich nichts machen. Doch auch jedes Auto braucht Wartung, Ölwechsel sowie Bremsen-, Reifen- und Flüssigkeitschecks. Daher gehört das ganz selbstverständlich auch zur IT. Und ja, das kostet Geld, mindert aber ein Risiko.

Mit dem zunehmenden Einsatz von KI wird außerdem das Unterbringen von sogenannten KI-Anweisungen (Prompt Injection) ein immer beliebterer Trend. Webseiten, die häufig von KI-Systemen besucht werden, um deren Inhalte zu verwenden, sind dafür ein besonders attraktives Ziel. Schon mal ausprobiert, wie einfach das ist? Erstaunlich einfach.

In der Debatte um OpenClaw habe ich gerade die Fantasie, einen solchen völlig autonomen KI-Agenten auf einem separaten physischen System laufen zu lassen und ihm zu sagen: „Hack die Webseite.“ Man wird überrascht sein, wie einfach dieser mal eben einen Exploit zum Ausnutzen bekannter Schwachstellen schreibt. Das Wissen dazu ist im Netz vorhanden, es muss nur kombiniert werden und genau das können diese Systeme mittlerweile sehr gut.

Bei einem Großteil der Fälle sind es ganz einfache Dinge: ungepflegte Plugins oder veraltete Software. Auf der anderen Seite findet man häufig Schnittstellen, die offen erreichbar sind, obwohl sie eigentlich gar nicht benötigt werden und somit ein unnötiges Risiko darstellen.

Dazu kommt sogenanntes Information Disclosure. Also Informationen über die Webseite, ihre Struktur oder den Login-User, die öffentlich einsehbar sind und sich für mögliche Angriffe nutzen lassen.

Gerade erst wieder gesehen: Der Benutzername der Webseite konnte mit einfachsten Methoden ermittelt werden. Danach kurz geprüft, ob automatisierte Login-Versuche möglich sind, ob es Limits gibt, und schon ist eine Brute-Force-Attacke gegen eine solche Seite vorbereitet. Dann ist es oft nur eine Frage der Zeit, bis die Webseite fällt auch ohne eine aktive CVE-Sicherheitslücke.

Auffällig finde ich auch immer noch, dass die einfachste Härtung häufig nicht umgesetzt wird: das Einschränken von Verzeichniszugriffsrechten, das Abschalten unnötiger Schnittstellen, das Verhindern der Ermittlung von Login-Namen, das Blockieren direkter Zugriffe auf sensible Dateien, Setzen von Ratelimits für Logins und das rudimentäre Ausblenden von Versionsnummern von Software oder Plugins. Ja, das ersetzt natürlich keine regelmäßigen Updates, und oftmals sind Versionsnummern so tief verdrahtet, dass das Entfernen mehr Probleme verursacht, als es löst. Viele sagen, das sei nur „Security by Obscurity“. Aber Bots durchsuchen Netze automatisiert auch nach anfälligen Versionsnummern, offenen Schnittstellen, Verzeichnisauflistungen oder ermittelbaren Benutzerkonten und führen darauf basierend automatisierte Angriffe aus. Wenn man dabei nicht gleich in der ersten Welle auftauchen möchte, macht man es den Angreifenden zumindest nicht unnötig leicht.

Daneben gehört für mich auch ein gutes Logmanagement und ein funktionierendes Reaktionssystem dazu. Wenn Angriffe stattfinden, sollte man diese erstens automatisiert in den Logs erkennen und einen Alert auslösen. Und zweitens sollte man Maßnahmen haben, um solche Angreifende beispielsweise automatisiert über eine Firewall auszusperren. Da bewegen wir uns dann allerdings schon auf der Ebene der Hoster. Typische Website-Inhabende werden sich darüber vermutlich kaum Gedanken machen. Das sehe ich auch klar in der Pflicht des technischen Betreibers.

Oft höre ich dann: „Da habe ich wohl einen wirklich schlechten Dienstleister oder Hoster, dem muss ich mal auf die Füße treten.“

Ich kenne allerdings auch die andere Seite. Software aktuell zu halten, bedeutet nicht einfach nur, automatisiert Updates einzuspielen. Kunden erwarten schließlich, dass ihre Webanwendungen weiterhin funktionieren. Spielt man Updates ein, beschwert sich der Kunde plötzlich, weil seine Seite nicht mehr funktioniert, etwa wegen Inkompatibilitäten mit Plugins, Anwendungen oder Datenbanken. Updatet man hingegen nicht, beschwert sich der Kunde über fehlende Wartung und Sicherheitsrisiken. Und gleichzeitig heißt es oft: Das darf aber fast nichts kosten.

Sicherheit, automatisierte Tests und regelmäßige Wartung kosten Geld sowie Aufwand. Wer das möchte, muss auch bereit sein, dafür zu zahlen.

Kein Mensch würde auf die Idee kommen, an der Sicherheit seiner Haustür zu sparen. Bei Webseiten sieht das leider oftmals anders aus, obwohl sie für viele Unternehmen die digitale Eingangstür darstellen.

Czaja IT Dienstleistungen und Unternehmensberatung Telefon 0177 7680425 E-Mail consulting@svenczaja.de

Angebot: Jetzt bereit für den Security Check Ihrer Webseite? Einfach unverbindlich und kostenlos anfragen.

Game Streaming mit dem Raspberry Pi

Banner Game Pads

Schon länger schwebte mir im Kopf vor, den im Keller laufenden Server eine zusätzliche Gaming-Funktion zuzuführen. Wozu 2 Rechner anschaffen, wenn einer doch eh rund um die Uhr läuft und eine leistungsstarke CPU und viel RAM enthält. Als ein guter Freund aus der Schweiz mir dann ein Spiel zeigte, welches ich recht reizvoll fand und er mir zudem eine Game-Streaming Funktion näher brachte, stand meine Entscheidung schon fast fest. Aber da mein Schweizer den Moment erkannte und mich noch mehr motivieren wollte, kaufte er einfach vor meinen Augen eine Helldivers II Lizenz bei Steam für mich. Damit stand fest, jetzt gibt es kein Zurück mehr. 😀

Meine Vision war es auf dem 65 Zoll TV in der Wohnstube mit einem kleinen Raspberry Pi zocken zu können. Während dieser also das Streaming entgegen nimmt, läuft das eigentliche Spiel auf dem Gaming-Server im Keller.

Nach einigen anfänglichen Tests mit meinem T490s Lenovo Ubuntu Notebook als Game-Streaming Empfänger, war schnell klar, dass die Technik mittels Sunshine, Moonlight und Steam auf Debian Linux sowie einer Nvidia Grafikkarte technisch funktionierte. Also hier nun mein Rezeptblock. 😀

Czaja IT Dienstleistungen und Unternehmensberatung Telefon 0177 7680425 E-Mail consulting@svenczaja.de

Angebot: Sofern das technisch für Euch zu viel ist und Ihr trotzdem gerne eine solche Funktion nutzen wollt, kontaktiert mich gerne. Im Rahmen meiner Firmen IT Dienstleistungen biete ich die Einrichtung solcher Services ebenfalls an.

Zutaten (in meinem Setup):

  • 1x TV 65 Zoll mit HDMI Anschluss
  • 1x Raspberry Pi 4 angeschlossen per LAN und HDMI (nahe TV)
  • 1x Micro HDMI Adapter für den Anschluss Raspberry Pi 4 zum TV
  • 1x Server mit Intel(R) Core(TM) i5-10400 (6 Kerne, 65W TDP), 32 GB RAM DDR4 (TIMETEC-U16G-2666), 4 TB (Samsung SSD 990 EVO Plus 4TB), 1 Gbit LAN, Grafikkarte GeForce RTX 3050 6GB (Standort egal solange LAN)
  • 1x Moonlight – Client-Streaming-Software auf dem Raspberry Pi oder auch testweise auf einem Notebook (Linux/Windows)
  • 1x Sunshine – Server-Streaming-Software auf dem Gaming Server
  • 1x Steam Software auf dem Gaming-Server
  • 1x Wine/Proton Software auf dem Gaming-Server
  • 1x X Server, xfce4 und lightdm auf dem Gaming-Server für eine grafische Oberfläche
  • 1x Server OS – Debian GNU/Linux 12 (bookworm)
  • 1x RaspberryPi OS – Debian GNU/Linux 12 (bookworm)

Aber halt, vorher noch ein bisschen Theorie. 🙂 Was ist nun dieses Moonlight/Sunshine?

Moonlight (Client) und Sunshine (Host) sind Open-Source-Programme, die Spiele mit extrem niedriger Latenz vom PC auf andere Geräte streamen, wobei sie das ursprüngliche, von NVIDIA entwickelte Gamestream-Protokoll nutzen, um Hardware-Encoding von NVIDIA-Grafikkarten (und anderen) für beste Qualität zu verwenden. 

Wichtige Fakten:

  • Funktion: Sunshine wird auf dem Gaming-PC installiert, Moonlight auf dem Empfangsgerät (Handy, TV, Laptop).
  • NVIDIA-Bezug: Moonlight entstand als Open-Source-Alternative zur NVIDIA SHIELD Software, da NVIDIA das eigene „GameStream“-Protokoll eingestellt hat.
  • Vorteil: Sunshine ermöglicht das Streaming unabhängig vom verwendeten Grafikhersteller, nutzt aber die NVENC-Technik von NVIDIA-GPUs

Ach ja und bevor es losgeht, es gibt auch noch die Möglichkeit über Steam selbst direkt zu streamen, das war zwar technisch ausgesprochen einfach einzurichten und hat gut funktioniert, war jedoch von der Performance gerade was Frameraten und Latenz angeht, doch noch deutlich schlechter als Sunshine/Moonlight. Daher tut Euch den Gefallen und investiert direkt die Zeit in Sunsine/Moonlight.

Sunshine ist hierbei die Server-Software, die das Streaming vom Gaming Server ermöglicht (Sender) und Moonlight ist die Client-Software, die auf Eurem Endgerät (bei mir der Raspberry Pi 4+TV) läuft und die gestreamten Daten erhält (Empfänger) und auf dem ihr letztendlich mit Maus und Tastatur spielen wollt.

Bezüglich der Grafikkarte hatte ich mich vorher extra schlau gemacht, welche Grafikkarten keinen externen Stromanschluss benötigen und einen niedrigen TDP Wert haben, weil diese dann einfach deutlich Strom-sparender sind. Denn das Ziel war ja, wenn nicht gespielt wird, soll der Rechner nicht Strom ohne Ende verbrennen, da er ja 24×7 läuft, summiert sich da sonst eine ganze Menge. 😉
Die hier gezeigte Hardware Konfiguration ist nur meine, es geht sicherlich mit auch zig anderer Hardware. Beim Raspberry Pi muss es dagegen schon mindestens der 4er sein, sonst reicht es von der Leistung für Full-HD 1920×1080 her nicht.

Um Steam unter Debian 12 „Bookworm“ auf dem Gaming Server zu installieren, folgst du am besten diesen Schritten:

Voraussetzungen:

  • 64-Bit-System
  • Grafikkartentreiber installiert (NVIDIA)
  • Multilib (für 32-Bit-Unterstützung, wird von Steam benötigt)

Schritt-für-Schritt-Anleitung:

1. Non-Free-Repositories aktivieren

Steam ist proprietäre Software, daher musst du „contrib“ und „non-free“ aktivieren.

Bearbeite die Datei /etc/apt/sources.list z. B. so:

sudo vi /etc/apt/sources.list

Füge bei allen Zeilen main folgendes hinzu: contrib non-free non-free-firmware

Inhalt bei mir auf dem Server:

deb http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware
deb http://ftp.de.debian.org/debian/ bookworm main contrib non-free non-free-firmware
deb http://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
deb http://ftp.de.debian.org/debian/ bookworm-updates main contrib non-free non-free-firmware

Dann:

sudo apt update
2. 32-Bit-Architektur hinzufügen (für Wine/Steam nötig)
sudo dpkg --add-architecture i386
sudo apt update
3. Steam installieren
sudo apt install steam
4. Steam (im User-Kontext, nicht als root!!!) starten
steam

Beim ersten Start lädt Steam ggf. Updates herunter und installiert zusätzliche Bibliotheken. Zu beachten ist hier, das Steam einen laufenden X Server benötigt. Bei mir habe ich einen leichtgewichtigen lightdm und xfce4 dafür installiert. Mit Wayland soll es auch funktionieren, das habe ich jedoch nicht getestet. Achtet darauf das ihr steam im User Kontext startet und nicht mit root.

Hier die Pakete die ich auf dem Gaming Server für Steam danach installiert gefunden habe.

# dpkg -l | grep -i steam
ii  steam:i386                                  1:1.0.0.75+ds-6                          i386         Transitional package for Steam
ii  steam-devices                               1:1.0.0.75+ds-6                          all          Device support for Steam-related hardware
ii  steam-installer                             1:1.0.0.75+ds-6                          amd64        Valve's Steam digital software delivery system
ii  steam-libs:amd64                            1:1.0.0.75+ds-6                          amd64        Metapackage for Steam dependencies
ii  steam-libs:i386                             1:1.0.0.75+ds-6                          i386         Metapackage for Steam dependencies
ii  steam-libs-i386:i386                        1:1.0.0.75+ds-6                          i386         Metapackage for 32-bit Steam dependencies
ii  steamcmd:i386                               0~20180105-5                             i386         Command-line interface for Valve's Steam
5. NVIDIA-Treiber installieren (falls noch nicht geschehen)

Sofern ihr noch keinen Nvidia Grafikkarten Treiber installiert habt, installiert diesen. Ich habe den aus den offiziellen Debian Repositories genutzt. Zudem tut Euch einen gefallen und werft den nouveau Treiber runter, weil damit wird es zum Einen nichts und zum anderen hatte ich viele Wechselwirkungen damit. Daher besser gleich richtig mit sudo apt remove entfernen.

sudo apt install nvidia-driver firmware-misc-nonfree
sudo reboot

Bei mir sah es nach der Installation wie folgt aus auf dem System.

# dpkg -l | grep -i nvidia
ii  firmware-nvidia-gsp                         535.261.03-1                             amd64        NVIDIA GSP firmware
ii  glx-alternative-nvidia                      1.2.2                                    amd64        allows the selection of NVIDIA as GLX provider
ii  libcuda1:amd64                              535.261.03-1                             amd64        NVIDIA CUDA Driver Library
ii  libcuda1:i386                               535.261.03-1                             i386         NVIDIA CUDA Driver Library
ii  libegl-nvidia0:amd64                        535.261.03-1                             amd64        NVIDIA binary EGL library
ii  libegl-nvidia0:i386                         535.261.03-1                             i386         NVIDIA binary EGL library
ii  libgl1-nvidia-glvnd-glx:amd64               535.261.03-1                             amd64        NVIDIA binary OpenGL/GLX library (GLVND variant)
ii  libgl1-nvidia-glvnd-glx:i386                535.261.03-1                             i386         NVIDIA binary OpenGL/GLX library (GLVND variant)
ii  libgles-nvidia1:amd64                       535.261.03-1                             amd64        NVIDIA binary OpenGL|ES 1.x library
ii  libgles-nvidia1:i386                        535.261.03-1                             i386         NVIDIA binary OpenGL|ES 1.x library
ii  libgles-nvidia2:amd64                       535.261.03-1                             amd64        NVIDIA binary OpenGL|ES 2.x library
ii  libgles-nvidia2:i386                        535.261.03-1                             i386         NVIDIA binary OpenGL|ES 2.x library
ii  libglx-nvidia0:amd64                        535.261.03-1                             amd64        NVIDIA binary GLX library
ii  libglx-nvidia0:i386                         535.261.03-1                             i386         NVIDIA binary GLX library
ii  libnvcuvid1:amd64                           535.261.03-1                             amd64        NVIDIA CUDA Video Decoder runtime library
ii  libnvcuvid1:i386                            535.261.03-1                             i386         NVIDIA CUDA Video Decoder runtime library
ii  libnvidia-allocator1:amd64                  535.261.03-1                             amd64        NVIDIA allocator runtime library
ii  libnvidia-allocator1:i386                   535.261.03-1                             i386         NVIDIA allocator runtime library
ii  libnvidia-cfg1:amd64                        535.261.03-1                             amd64        NVIDIA binary OpenGL/GLX configuration library
ii  libnvidia-egl-gbm1:amd64                    1.1.0-2                                  amd64        GBM EGL external platform library for NVIDIA
ii  libnvidia-egl-gbm1:i386                     1.1.0-2                                  i386         GBM EGL external platform library for NVIDIA
ii  libnvidia-egl-wayland1:amd64                1:1.1.10-1                               amd64        Wayland EGL External Platform library -- shared library
ii  libnvidia-egl-wayland1:i386                 1:1.1.10-1                               i386         Wayland EGL External Platform library -- shared library
ii  libnvidia-eglcore:amd64                     535.261.03-1                             amd64        NVIDIA binary EGL core libraries
ii  libnvidia-eglcore:i386                      535.261.03-1                             i386         NVIDIA binary EGL core libraries
ii  libnvidia-encode1:amd64                     535.261.03-1                             amd64        NVENC Video Encoding runtime library
ii  libnvidia-encode1:i386                      535.261.03-1                             i386         NVENC Video Encoding runtime library
ii  libnvidia-glcore:amd64                      535.261.03-1                             amd64        NVIDIA binary OpenGL/GLX core libraries
ii  libnvidia-glcore:i386                       535.261.03-1                             i386         NVIDIA binary OpenGL/GLX core libraries
ii  libnvidia-glvkspirv:amd64                   535.261.03-1                             amd64        NVIDIA binary Vulkan Spir-V compiler library
ii  libnvidia-glvkspirv:i386                    535.261.03-1                             i386         NVIDIA binary Vulkan Spir-V compiler library
ii  libnvidia-ml1:amd64                         535.261.03-1                             amd64        NVIDIA Management Library (NVML) runtime library
ii  libnvidia-pkcs11-openssl3:amd64             535.261.03-1                             amd64        NVIDIA PKCS #11 Library (OpenSSL 3)
ii  libnvidia-ptxjitcompiler1:amd64             535.261.03-1                             amd64        NVIDIA PTX JIT Compiler library
ii  libnvidia-ptxjitcompiler1:i386              535.261.03-1                             i386         NVIDIA PTX JIT Compiler library
ii  libnvidia-rtcore:amd64                      535.261.03-1                             amd64        NVIDIA binary Vulkan ray tracing (rtcore) library
ii  nvidia-alternative                          535.261.03-1                             amd64        allows the selection of NVIDIA as GLX provider
ii  nvidia-driver                               535.261.03-1                             amd64        NVIDIA metapackage
ii  nvidia-driver-bin                           535.261.03-1                             amd64        NVIDIA driver support binaries
ii  nvidia-driver-libs:amd64                    535.261.03-1                             amd64        NVIDIA metapackage (OpenGL/GLX/EGL/GLES libraries)
ii  nvidia-driver-libs:i386                     535.261.03-1                             i386         NVIDIA metapackage (OpenGL/GLX/EGL/GLES libraries)
ii  nvidia-egl-common                           535.261.03-1                             amd64        NVIDIA binary EGL driver - common files
ii  nvidia-egl-icd:amd64                        535.261.03-1                             amd64        NVIDIA EGL installable client driver (ICD)
ii  nvidia-egl-icd:i386                         535.261.03-1                             i386         NVIDIA EGL installable client driver (ICD)
ii  nvidia-installer-cleanup                    20220217+3~deb12u1                       amd64        cleanup after driver installation with the nvidia-installer
ii  nvidia-kernel-common                        20220217+3~deb12u1                       amd64        NVIDIA binary kernel module support files
ii  nvidia-kernel-dkms                          535.261.03-1                             amd64        NVIDIA binary kernel module DKMS source
ii  nvidia-kernel-support                       535.261.03-1                             amd64        NVIDIA binary kernel module support files
ii  nvidia-legacy-check                         535.261.03-1                             amd64        check for NVIDIA GPUs requiring a legacy driver
ii  nvidia-modprobe                             535.161.07-1~deb12u1                     amd64        utility to load NVIDIA kernel modules and create device nodes
ii  nvidia-persistenced                         535.171.04-1~deb12u1                     amd64        daemon to maintain persistent software state in the NVIDIA driver
ii  nvidia-settings                             535.247.01-1~deb12u1                     amd64        tool for configuring the NVIDIA graphics driver
ii  nvidia-smi                                  535.261.03-1                             amd64        NVIDIA System Management Interface
ii  nvidia-support                              20220217+3~deb12u1                       amd64        NVIDIA binary graphics driver support files
ii  nvidia-suspend-common                       535.261.03-1                             amd64        NVIDIA driver - systemd power management scripts
ii  nvidia-vdpau-driver:amd64                   535.261.03-1                             amd64        Video Decode and Presentation API for Unix - NVIDIA driver
ii  nvidia-vulkan-common                        535.261.03-1                             amd64        NVIDIA Vulkan driver - common files
ii  nvidia-vulkan-icd:amd64                     535.261.03-1                             amd64        NVIDIA Vulkan installable client driver (ICD)
ii  nvidia-vulkan-icd:i386                      535.261.03-1                             i386         NVIDIA Vulkan installable client driver (ICD)
ii  xserver-xorg-video-nvidia                   535.261.03-1                             amd64        NVIDIA binary Xorg driver
6. Kernel Parameter setzen

Was noch wichtig ist im Zusammenhang mit Steam.
In Debian Bookworm (und generell in Debian/Linux) muss für Steam

kernel.unprivileged_userns_clone = 1

gesetzt werden, um nicht-privilegierten Benutzern permanent das Erstellen von User Namespaces zu erlauben. Ich habe mir dies unter /etc/sysctl.d/99-enable-unpriv-userns.conf angelegt. Aktivieren könnt ihr dass dann sofort mit

sudo sysctl -p /etc/sysctl.d/99-enable-unpriv-userns.conf

Warum ist das für Steam und NVIDIA wichtig?

Steam & Proton (Bubblewrap): Steam nutzt intern das Tool bubblewrap (bwrap), um Spiele in einer isolierten Laufzeitumgebung (Steam Runtime) auszuführen. Ohne aktivierte User Namespaces kann bwrap diese Sandbox nicht erstellen, wodurch Steam-Spiele (insbesondere via Proton) nicht starten.

Für die Sicherheitsbewußten unter Euch besteht die Möglickeit, dass Ihr diese Option nur startet, bevor Steam gestartet wird und nach Ende von Steam wieder beendet. Etwa so wie in diesem Script:

#!/bin/bash
sudo sysctl -w kernel.unprivileged_userns_clone=1
# Steam starten und warten, bis es beendet wird
steam
# Deaktivieren nach Beenden von Steam
sudo sysctl -w kernel.unprivileged_userns_clone=0

Da Steam bei mir dauerhauft im Hintergrund läuft, habe ich die Option dauerhaft aktiv. Denn Steam zieht regelmäßig teilweise mehrmals am Tag Updates. Wer Steam nicht dauerhaft laufen lassen will, hat dann häufig den Spaß, das erstmal teilweise mehrere GB aus dem Netz geladen werden und man lange warten muss, bis die Updates alle durch sind. Jeder kennt das, man will mal eben zocken und dann erstmal 1h Updates ziehen, ist alles andere als witzig. Daher findet einen Kompromis aus Sicherheit und Komfort.

7. Spiel installieren

Jetzt könnt ihr erstmal in Steam Euer Spiel unter Linux installieren. Ich hatte hier ein paar Probleme, daher prüft am Besten vorher, ob Euer Spiel unterstützt ist. Dies könnt ihr am Besten auf dieser Webseite hier https://www.protondb.com.
Bei mir war z.B. die Installation nicht gleich möglich, da ich nur angezeigt bekommen habe Available for Windows. Nach einigem Suchen, habe ich dann die Compatibility Option im Steam namens „Steam Play is enabled for all titles“ gefunden und schon konnte ich Helldivers II auch unter Linux installieren. In den Einstellungen direkt für das Spiel Helldivers II (rechte Maustaste klicken auf dem Spiel und Einstellungen/Properties drücken) habe ich dann ebenfalls noch „Force the use of a specific Steam Play compatibility tool“ ausgewählt. Als Proton Version habe ich aktuell GE-Proton9-27 im Einsatz, kann dort ebenfalls eingestellt werden.

Wenn ihr bis hier her gekommen seid: Glückwunsch. 🙂 Dann testet jetzt bitte erst ob euer Spiel läuft, funktioniert alles, läuft es performant. Es ist wichtig, dass das Spiel erstmal richtig im Steam läuft, denn ansonsten sucht ihr nachher beim Streaming an 2 Stellen.

8. Sunshine installieren

OK, das Spiel läuft, dann der nächste Schritt. Wir installieren Sunshine auf dem Gaming Server. Dazu habe ich das Debian Paket von https://github.com/LizardByte/Sunshine heruntergeladen. Dort findet ihr auch jede Menge Infos zu System Requirements, ob eure Hardware oder euer Betriebssystem unterstützt wird usw. Die verschiedenen Releases mit den unterschiedlichen Softwarepaketen findet ihr hier https://github.com/LizardByte/Sunshine/releases. Schaut unter Assets. Leider gibt es noch kein Debian Repository, daher gilt hier, selbst runterladen und selbst regelmäßig aktualiseren.

# dpkg -l | grep -i sunshine
ii  sunshine                                    2025.122.141614                          amd64        Self-hosted game stream host for Moonlight

Meinen verwendeten Versionsstand findet ihr als direkten Link noch hier:
https://github.com/LizardByte/Sunshine/releases/download/v2025.122.141614/sunshine-debian-bookworm-amd64.deb
Aber schaut ruhig nach neueren Versionen.

Installiert das Paket am besten mit apt damit alle fehlenden abnhängigen Pakete gleich automatisch mit installiert werden.

# sudo apt install ./sunshine-debian-bookworm-amd64.deb 

Im Idealfall habt ihr jetzt Sunshine auf dem Gaming Server installiert. Also los, einmal als User (nicht root!!!) starten. Dafür müssen ein paar Umgebungsvariaben gesetzt werden, damit ihr es bequem aus einer Remote SSH Session starten könnt. Denn ich sitze in der Regel nicht an meinem Server vor dem Monitor. 😉 Ich habe das Script sunshine.sh genannt.

#!/bin/bash
export XDG_RUNTIME_DIR=/run/user/$(id -u)
export DISPLAY=:0
export XAUTHORITY=/home/$(id -u)/.Xauthority
/usr/bin/sunshine

Zudem sollte Euer User in den Gruppen video, render und input Mitglied sein, damit es auf die entsprechenden Geräte zugreifen kann. Dies könnt ihr mit dem Befehl groups prüfen und mit usermod die Gruppenrechte hinzufügen, falls sie noch nicht da sind.

# groups
eueruser cdrom floppy dip plugdev netdev kismet
# sudo usermod -aG audio, video,render,input eueruser
# exit
 .... neu anmelden ...
# groups
eueruser cdrom floppy dip plugdev netdev kismet audio video render input

Wen es interessiert zum Vergleich, hier mein Output nach dem Starten von sunhine.sh. Solltet ihr andere Fehlermeldungen im Log /home/eueruser/.config/sunshine/sunshine.log finden oder auf der Console sehen, als die bei mir zu sehen sind (denn die sind OK), dann müsst ihr diese erstmal bereinigen.

[2026-01-17 23:16:06.567]: Info: Sunshine version: v2025.122.141614
[2026-01-17 23:16:06.569]: Info: Package Publisher: LizardByte
[2026-01-17 23:16:06.569]: Info: Publisher Website: https://app.lizardbyte.dev
[2026-01-17 23:16:06.569]: Info: Get support: https://app.lizardbyte.dev/support
[2026-01-17 23:16:06.655]: Info: System tray created
[2026-01-17 23:16:06.660]: Error: Couldn't find any of the following libraries: [libnvidia-fbc.so.1, libnvidia-fbc.so]
[2026-01-17 23:16:06.662]: Info: /dev/dri/card0 -> nvidia-drm
[2026-01-17 23:16:06.662]: Error: GPU driver doesn't support universal planes: /dev/dri/card0
[2026-01-17 23:16:06.662]: Error: Environment variable WAYLAND_DISPLAY has not been defined
[2026-01-17 23:16:06.662]: Info: Detecting displays
[2026-01-17 23:16:06.669]: Info: Detected display: DVI-D-0 (id: 0)DVI-D-0 connected: false
[2026-01-17 23:16:06.669]: Info: Detected display: HDMI-0 (id: 1)HDMI-0 connected: true
[2026-01-17 23:16:06.669]: Info: Detected display: DP-0 (id: 2)DP-0 connected: false
[2026-01-17 23:16:06.669]: Info: Detected display: DP-1 (id: 3)DP-1 connected: false
[2026-01-17 23:16:06.906]: Warning: Gamepad ds5 is disabled due to Permission denied
[2026-01-17 23:16:06.906]: Info: Trying encoder [nvenc]
[2026-01-17 23:16:06.906]: Info: Screencasting with X11
[2026-01-17 23:16:06.907]: Info: Creating encoder [h264_nvenc]
[2026-01-17 23:16:06.907]: Info: Color coding: SDR (Rec. 601)
[2026-01-17 23:16:06.907]: Info: Color depth: 8-bit
[2026-01-17 23:16:06.907]: Info: Color range: JPEG
[2026-01-17 23:16:07.115]: Info: Creating encoder [hevc_nvenc]
[2026-01-17 23:16:07.115]: Info: Color coding: SDR (Rec. 601)
[2026-01-17 23:16:07.115]: Info: Color depth: 8-bit
[2026-01-17 23:16:07.115]: Info: Color range: JPEG
[2026-01-17 23:16:07.140]: Info: Creating encoder [av1_nvenc]
[2026-01-17 23:16:07.140]: Info: Color coding: SDR (Rec. 601)
[2026-01-17 23:16:07.140]: Info: Color depth: 8-bit
[2026-01-17 23:16:07.140]: Info: Color range: JPEG
[2026-01-17 23:16:07.142]: Warning: [av1_nvenc @ 0x5637e5204e00] Codec not supported
[2026-01-17 23:16:07.142]: Error: [av1_nvenc @ 0x5637e5204e00] Provided device doesn't support required NVENC features
[2026-01-17 23:16:07.142]: Error: Could not open codec [av1_nvenc]: Function not implemented
[2026-01-17 23:16:07.142]: Info: Screencasting with X11
[2026-01-17 23:16:07.143]: Info: Creating encoder [hevc_nvenc]
[2026-01-17 23:16:07.143]: Info: Color coding: SDR (Rec. 709)
[2026-01-17 23:16:07.143]: Info: Color depth: 10-bit
[2026-01-17 23:16:07.143]: Info: Color range: JPEG
[2026-01-17 23:16:07.153]: Error: cuda::cuda_t doesn't support any format other than AV_PIX_FMT_NV12
[2026-01-17 23:16:07.160]: Info: // Testing for available encoders, this may generate errors. You can safely ignore those errors. //
[2026-01-17 23:16:07.160]: Info:
[2026-01-17 23:16:07.160]: Info: // Ignore any errors mentioned above, they are not relevant. //
[2026-01-17 23:16:07.160]: Info:
[2026-01-17 23:16:07.160]: Info: Found H.264 encoder: h264_nvenc [nvenc]
[2026-01-17 23:16:07.160]: Info: Found HEVC encoder: hevc_nvenc [nvenc]
[2026-01-17 23:16:07.162]: Info: Adding avahi service gamingserver
[2026-01-17 23:16:07.164]: Info: Configuration UI available at [https://localhost:47990]
[2026-01-17 23:16:07.942]: Info: Avahi service gamingserver successfully established.
[2026-01-17 23:16:15.315]: Info: Trying encoder [nvenc]
[2026-01-17 23:16:15.315]: Info: Screencasting with X11
[2026-01-17 23:16:15.316]: Info: Creating encoder [h264_nvenc]
[2026-01-17 23:16:15.316]: Info: Color coding: SDR (Rec. 601)
[2026-01-17 23:16:15.316]: Info: Color depth: 8-bit
[2026-01-17 23:16:15.316]: Info: Color range: JPEG
[2026-01-17 23:16:15.343]: Info: Creating encoder [hevc_nvenc]
[2026-01-17 23:16:15.343]: Info: Color coding: SDR (Rec. 601)
[2026-01-17 23:16:15.343]: Info: Color depth: 8-bit
[2026-01-17 23:16:15.343]: Info: Color range: JPEG
[2026-01-17 23:16:15.365]: Info: Creating encoder [av1_nvenc]
[2026-01-17 23:16:15.366]: Info: Color coding: SDR (Rec. 601)
[2026-01-17 23:16:15.343]: Info: Color depth: 8-bit
[2026-01-17 23:16:15.343]: Info: Color range: JPEG
[2026-01-17 23:16:15.365]: Info: Creating encoder [av1_nvenc]
[2026-01-17 23:16:15.366]: Info: Color coding: SDR (Rec. 601)
[2026-01-17 23:16:15.366]: Info: Color depth: 8-bit
[2026-01-17 23:16:15.366]: Info: Color range: JPEG
[2026-01-17 23:16:15.367]: Warning: [av1_nvenc @ 0x7f302841b600] Codec not supported
[2026-01-17 23:16:15.367]: Error: [av1_nvenc @ 0x7f302841b600] Provided device doesn't support required NVENC features
[2026-01-17 23:16:15.367]: Error: Could not open codec [av1_nvenc]: Function not implemented
[2026-01-17 23:16:15.367]: Info: Screencasting with X11
[2026-01-17 23:16:15.368]: Info: Creating encoder [hevc_nvenc]
[2026-01-17 23:16:15.368]: Info: Color coding: SDR (Rec. 709)
[2026-01-17 23:16:15.368]: Info: Color depth: 10-bit
[2026-01-17 23:16:15.368]: Info: Color range: JPEG
[2026-01-17 23:16:15.377]: Error: cuda::cuda_t doesn't support any format other than AV_PIX_FMT_NV12
[2026-01-17 23:16:15.383]: Info: // Testing for available encoders, this may generate errors. You can safely ignore those errors. //
[2026-01-17 23:16:15.383]: Info:
[2026-01-17 23:16:15.383]: Info: // Ignore any errors mentioned above, they are not relevant. //
[2026-01-17 23:16:15.383]: Info:
[2026-01-17 23:16:15.383]: Info: Found H.264 encoder: h264_nvenc [nvenc]
[2026-01-17 23:16:15.383]: Info: Found HEVC encoder: hevc_nvenc [nvenc]
[2026-01-17 23:16:15.383]: Info: Spawning [setsid steam steam://open/bigpicture] in ["/usr/bin"]
[2026-01-17 23:16:15.389]: Info: Executing [Desktop]
[2026-01-17 23:16:15.402]: Info: New streaming session started [active sessions: 1]
[2026-01-17 23:16:15.478]: Info: CLIENT CONNECTED
[2026-01-17 23:16:15.480]: Info: Detecting displays
[2026-01-17 23:16:15.730]: Info: Detected display: DVI-D-0 (id: 0)DVI-D-0 connected: false
[2026-01-17 23:16:15.730]: Info: Detected display: HDMI-0 (id: 1)HDMI-0 connected: true
[2026-01-17 23:16:15.730]: Info: Detected display: DP-0 (id: 2)DP-0 connected: false
[2026-01-17 23:16:15.730]: Info: Detected display: DP-1 (id: 3)DP-1 connected: false
[2026-01-17 23:16:15.730]: Info: Screencasting with X11
[2026-01-17 23:16:15.736]: Info: Configuring selected display (0) to stream
[2026-01-17 23:16:15.736]: Warning: Couldn't get requested display info, defaulting to recording entire virtual desktop
[2026-01-17 23:16:15.736]: Info: Creating encoder [hevc_nvenc]
[2026-01-17 23:16:15.736]: Info: Color coding: SDR (Rec. 601)
[2026-01-17 23:16:15.736]: Info: Color depth: 8-bit
[2026-01-17 23:16:15.736]: Info: Color range: MPEG
[2026-01-17 23:16:15.973]: Info: Setting default sink to: [sink-sunshine-stereo]
[2026-01-17 23:16:15.974]: Info: Found default monitor by name: sink-sunshine-stereo.monitor
[2026-01-17 23:16:15.980]: Info: Opus initialized: 48 kHz, 2 channels, 512 kbps (total), LOWDELAY

Vielleicht als Codec Erklärung, es gibt veschiedene Codecs die Sunshine verwenden kann. Hier seht ihr im Log 3 Encoder, von denen ich 2 verwenden kann.

Info: Creating encoder [hevc_nvenc]
Info: Creating encoder [h264_nvenc]
Warning: [av1_nvenc @ 0x5637e5204e00] Codec not supported

Kurz: Vergleich HEVC vs H.264

CodecVorteilNachteil
H.264Schärfer, schneller, überall unterstütztHöherer Datenverbrauch
HEVCEffizienter, bessere KompressionEher schwammig bei schwacher Hardware oder wenig Bitrate

Ich haben relativ lange mit den Codecs experimentiert, um herauszufinden was bessere Frameraten bringt und auch noch gut über die LAN-Bandbreite funktioniert sowie den Raspberry Pi 4 CPU-technisch nicht überfordert. Am Ende war der HEVC die optimale Lösung.

Warum HEVC (H.265) besser ist:

  • LAN-Vorteil: Da per LAN angebunden, kann man die Bitrate hoch ansetzen (z.B. 30–50 Mbps), was in Kombination mit HEVC eine exzellente Bildqualität ohne spürbare Verzögerung liefert. 
  • Hardware-Dekodierung: Der Raspberry Pi 4 verfügt über einen dedizierten Hardware-Dekoder für HEVC, der 4K-Inhalte mit bis zu 60 FPS verarbeiten kann. Das entlastet die CPU, daher deutlich besser.
  • Geringe Latenz: Bei 1080p60 liegt die Dekodierlatenz auf dem Pi 4 oft unter einem Frame (~4-5ms), was für Gaming ideal ist.
  • Bessere Bildqualität bei gleicher Bandbreite: HEVC ist bis zu 50% effizienter als H.264. Das bedeutet, dass bei gleicher Bitrate ein deutlich schärferes Bild mit weniger Kompressionsartefakten ensteht.

Ich habe gesehen, dass ich in meiner /home/user/.config/sunshinesunshine.conf die Option encoder = nvenc stehen habe, damit scheinbar hevc aktiviert wird, bin mir aber unsicher, ob das so ausreicht. Soweit ich mich erinnern kann, konnte man das in der grafischen Web-Oberfläche von Sunshine eintellen. Dazu später mehr.

Noch ein kleiner Ausflug zum Thema AV1 Codec. Bekannt ist:

  • AV1 (AOMedia Video 1) ist der modernste Videocodec der aktuellen Generation (Stand 2026).
  • Überlegene Kompression: AV1 ist etwa 30 % bis 50 % effizienter als HEVC (H.265) und deutlich besser als das alte H.264. Das bedeutet, man erhält bei einer sehr niedrigen Bitrate eine Bildqualität, für die andere Codecs viel mehr Daten benötigen würden.
  • Hoher Rechenaufwand: Die Komplexität des Codecs ist sehr hoch. Das Enkodieren (Erzeugen des Streams) dauert ohne spezialisierte Hardware extrem lange.
  • Hardware-Anforderungen: Damit AV1 für Gaming-Streaming (niedrige Latenz) nutzbar ist, benötigen sowohl der Sender (GPU) als auch der Empfänger (Client) einen dedizierten Hardware-Chip für AV1.

Warum AV1 auf dem Pi 4 keine gute Idee ist:

  • Fehlende Hardware-Beschleunigung: Der Raspberry Pi 4 besitzt keinen Hardware-Decoder für AV1. Das bedeutet, die CPU müsste das Video rein über Software dekodieren.
  • Hohe CPU-Last & Ruckeln: Selbst bei 1080p erreicht die CPU des Pi 4 bei AV1-Inhalten schnell ihre Grenzen. Dies führt zu massiven Frame-Drops und Rucklern, was für flüssiges Gaming unbrauchbar ist.
  • Enorme Latenz: Da die Software-Dekodierung viel langsamer ist als die dedizierte Hardware-Einheit, steigt die Verzögerung (Input-Lag) drastisch an.
  • Nur für neuere Hardware: AV1-Streaming via Moonlight macht erst Sinn, wenn auch der Client (der Empfänger) AV1 in Hardware unterstützt (wie z. B. ein Raspberry Pi 5 bedingt, moderne PCs mit RTX 30/40-Serie oder High-End-Smartphones).

Einschränkungen meiner Server Grafikkarte Nvidia RTX 3050 bei AV1:

Die NVIDIA RTX 30-Serie (Ampere-Architektur) war Nvidias erste Generation, die Hardware-Unterstützung für den AV1-Codec bot. Diese Unterstützung beschränkt sich jedoch ausschließlich auf den NVDEC-Decoder. 

  • Dekodierung (NVDEC): Die Karte kann AV1-Videos effizient abspielen, wodurch die CPU entlastet wird.
  • Kodierung (NVENC): Der dedizierte Video-Encoder-Chip (NVENC) in der RTX 3050 unterstützt nur H.264 und HEVC (H.265), aber nicht AV1. 

Welche Hardware AV1 kodieren kann:

Die Hardware-Kodierung von AV1 wurde von NVIDIA erst mit der nachfolgenden RTX 40-Serie (Ada Lovelace-Architektur) eingeführt. Wenn du AV1 zum Streamen mit Sunshine nutzen möchten, benötigst du eine Grafikkarte dieser neueren Generation (z.B. RTX 4060, 4070, etc.) oder alternativ eine Intel Arc GPU, die ebenfalls AV1-Encoding unterstützt.

So genug Theorie, wieso, weshalb, warum. 🙂

Sunshine Configuration:

Nachdem wir Sunshine jetzt gestartet haben, können wir die Weboberfläche (Port 47990) auf dem Gaming Server über einen Browser im gleichen Netz erreichen. Hier die Ports die Sunshine aufmacht.

root@gamingserver:~# netstat -anp | grep -i sunshine
tcp        0      0 0.0.0.0:48010           0.0.0.0:*               LISTEN      2487719/sunshine    
tcp        0      0 0.0.0.0:47989           0.0.0.0:*               LISTEN      2487719/sunshine    
tcp        0      0 0.0.0.0:47990           0.0.0.0:*               LISTEN      2487719/sunshine    
tcp        0      0 0.0.0.0:47984           0.0.0.0:*               LISTEN      2487719/sunshine

Bei der ersten Anmeldung http://EURE.SERVER.IP:47990 vergibt man dann User und Passwort und kann diese später mit sunshine --creds username password auch wieder auf der Console anpassen, sofern notwendig.
Beim ersten Aufruf werdet ihr vermutlich einen https Fehler bekommen, weil Sunshine ein selbstsigniertes Zertifikat verwendet, daher packt es erstmal auf die Ausnahmeliste. Ein sauberes Zertifikat Eurer CA könnt ihr später generieren und konfigurieren.

Sunshine Security Warning
Sunshine Security Warning

Danach erhaltet ihr in der Regel den Welcome Screen und könnt den Benutzernamen (default: sunshine) anpassen und ein Passwort vergeben.

Sunshine Welcome Page und User Anlage

Das ist schon recht intuitiv und dann noch mit den eben erstellten Credentials anmelden. Bei mir sieht das Ganze so aus.

Sunshine Anmeldebildschirm mit Benutzername und Passwort

Geschafft. 😀 Im Idealfall seht ihr jetzt die Oberfläche und könnt Euch durch die Menüs klicken. yeahhhh

Sunshine_Startbildschirm

Solltet ihr solche roten Fenster auf Eurem Welcome Bildschirm von Sunshine sehen, dann müsst ihr erst die Fehler analysieren und bereinigen. Am besten dazu in das Sunshine Log /home/eueruser/.config/sunshine/sunshine.log schauen, alternativ auf die Console oder einfach auf „View Logs“ drücken.

Sunschine Welcome Seite mit Fehlermeldung

Macht Euch ruhig mit den verschiedenen Einstellungen unter Configuration vertraut. Ich habe das meiste erstmal auf Default gelassen, dass würde ich Euch auch empfehlen. Und unter Advanced findet ihr dann die vorhin angsprochene Force Option für den HEVC Codec. So sehen meine Einstellungen aus.

Sunshine Configurations Menü Reiter

Besondere Einstellungen für den NVIDIA NVENC Encoder könnte ihr ebenfalls in dem so beschriebenen Reiter machen. Den Reiter VA-API Encoder könnt ihr links liegen lassen, außer ihr habt Intel- oder AMD-GPU auf Eurem Gaming Server.
Ich habe Euch hier die Config meiner NVIDIA NVENC Encoder Einstellungen auch noch mal dargestellt, obwohl ich der Meinung bin, dass ich da keine Veränderungen vorgenommen habe.

Sunshine NVENC Menü Reiter

Unter Applications findet man dann alle per Sunshine streambaren Anwendungen, dürfte daher vermutlich bei Euch noch nur Desktop und Low Res zu finden sein. Bei mir existieren da schon ein paar und eine davon (Steam Big Picture) verwenden wir später auch automatisiert, um das Game-Streaming zu starten.

Sunshine Menü Reiter Applications

Eine Sache ist mir noch eingefallen, auf dem Gaming Server müsst ihr mit eurem Benutzer an einer X Session angemeldet sein. Es kam bei mir einige Male dazu, dass die automatische Bildschirmsperre zuschlug.

OK, soweit alles gut? Dann können wir nun auf den Raspberry Pi springen und Moonlight installieren/konfigurieren. Ich würde Euch jedoch empfehlen für einen Test, Moonlight erstmal auf einem Client – Notebook/PC mit Windows oder Linux auszuprobieren. Damit könnt ihr auf die Schnelle schauen, ob die Kommunikation sauber läuft. Denn die Konfiguration auf dem Raspberry Pi ist etwas weniger komfortabel und Fehlersuche bedeutet dann immer an 2 Stellen schauen (Server oder Raspi), um den Fehler einzugrenzen. Ich habe auf meinem T490s Notebook mit Ubuntu einfach Moonlight als snap installiert und konnte daduch erstmal relativ einfach die Funktionsweise testen. Dies würde ich Euch auf jeden Fall nahe legen.

Unter Ubuntu kann man sich hierfür einfach den Moonlight Client als Snap installieren. Dazu zuerst das Paket suchen und wenn es gefunden wird, einfach mit snap installieren.

# sudo snap search moonlight
Name Version Herausgeber Hinweise Zusammenfassung
moonlight 6.1.0 maxiberta✪ - Stream games and other applications from another PC running Sunshine or GeForce Experience
heads-tails 1.0.13 technolog - Heads or Tails Multiplayer Crypto DexGames
# sudo install moonlight

Danach könnt ihr Moonlight einfach aus dem Ubuntu Menü oder per Console starten. Parallel habe ich auf der Console im Hintergrund Sunshine auf dem Streaming Gaming Server gestartet.

Start von Sunshine in der der Console und Start von Moonlight auf dem Client

Rechts unten seht ihr Moonlight und er scant autoamtisch das Netz nach Sunshine Servern. Hier hat er sofort meinen Gaming Server gefunden. Ihr seht das Schloss, was so viel heißt wie: Zu diesem Server gab es noch nie eine Verbindung und diese muss erstmal authentifiziert werden. Wenn Ihr also auf das Schloss klickt, wird über eine Pin Generierung eine Authentifzierung gestartet.

Moonlight Pin Authentifizierungsabfrage

Also als Nächstes die Sunshine Weboberfläche im Browser öffnen, dort auf den PIN Reiter klicken, damit wir die Verbindung genehmigen können. Dieser Check sichert ab, dass nur authorisierte Verbindungen erlaubt sind.

Sunshine Web Authentifizierung eines neuen Moonlight Gerätes

Jetzt einfach den angezeigten PIN in der Sunshine Oberfläche eingeben und einen Gerätenamen vergeben, damit wir später Wissen, welches Gerät das war, welches wir hier freigegeben haben. Nach Bestätigung sieht das Ganze dann so aus.

Erfolgreiche Authentifizierung eines neuen Moonlight Gerätes in der Sunshine Web Oberfläche

Nach dem erfolgreichen Pairing sieht man, dass das Schloss im Monitor verschwunden ist. Mit einem Klick auf den Monitor erscheinen die zu streamenden Möglichkeiten.

Moonlight mit aufgebauter Verbindung zum Streaming Server

Ihr erinnert Euch sicherlich noch an das Applikations Menü in der Sunshine Web Oberfläche? Hier könnt ihr genau die 3 sehen, die dort bei mir hinterlegt waren. Oben rechts beim Zahnrad habt ihr noch die Möglichkeit Einstellungen für Moonlight vorzunehmen.

Config Menü von Moonlight client

Hier kann man so einiges einstellen und wenn die Verbindung, das Streaming und das Spiel erstmal laufen, dann findet hier das Fine-Tuning statt. Damit könnt ihr das Maximum aus der Verbindung und Eurer Hardware rausholen. Entscheidend sind hier in der Tat die Parameter Video Bitrate, Auflösung und FPS. Denn alles 3 zusammen sorgt dafür, das Euer Datenstream entsprechend groß wird und dieser sollte nur so groß werden, wie Eure Leitung es hergibt. Dies kann natürlich daheim über LAN oder WLAN eine andere sein als z.B. weit entfernt über das Internet.

Jetzt aber zurück zum Streaming. Wir klicken jetzt auf den Desktop im Moonlight Client. Dieser baut dann eine Verbindung zu Sunshine auf und streamt den Bildshirm vom Gaming Server zum Moonlight Client (hier Ubuntu Notebook aktuell). Der Verbindungsaufbau sieht dann so aus.

Streaming gestartet Moonlight Desktop

Wichtig ist an dieser Stelle kurz zu sehen, dass STRG+ALT+SHIFT+Q Euch aus der Streaming Session wieder zurück auf Euren Client bringt und die Verbindung wieder beendet. Das ist keine einfache Kombination, daher merkt Sie Euch :D. So sieht jetzt der erfolgreiche Desktop Stream aus.

Gestreamter Desktop vom Streaming Server angezeigt auf dem Client durch Moonlight Verbindung zu Sunshine

In diesem Fall läuft sogar gerade ein Steam im Fenster, wie man sieht. Das was ihr seht, ist also die Desktop Oberfläche des Streaming Gaming Server. Sofern ihr nicht an Eurem Server an der grafischen Oberfläche angemeldet seid oder der Bildschirmschoner läuft oder die Bildschirmsperre an ist, werdet ihr vermutlich nur ein schwarzes Bild sehen. Daher der Hinweis am Anfang von mir. Stellt somit am besten Auto-Logon an, Auto-Bildschirmsperre und Bildschirmschoner Funktionen aus. Wie ihr das später im produktiven Einsatz einstellen wollt, hängt von Eurem Sicherheitsbewußtsein und eurem Komfort-Wunsch ab.
Jetzt könnt ihr ebenfalls Steam einmal streamen, der Eintrag „Steam Big Picture“ wird in Sunshine in den meisten Fällen automatisch erkannt bzw. automatisch vorgeschlagen.

Wie Sunshine zu „Steam Big Picture“ kommt?
Sunshine bringt vordefinierte App-Templates mit, u. a. für:

  • Steam
  • Steam Big Picture
  • Teilweise auch generische „Desktop“- oder „Steam Game“-Einträge

Sobald Sunshine bei dir eine Steam-Installation findet (typisch: /usr/bin/steam, ~/.steam, ~/.local/share/Steam), passiert eines von zwei Dingen – je nach Version/Konfig:

Gerade bei neueren Sunshine-Versionen taucht der Eintrag einfach in der App-Liste auf, ohne dass man aktiv etwas klickt.

Automatisches Vorbelegen

  • Sunshine legt beim ersten Start oder nach einem Update bekannte Apps automatisch an.
  • „Steam Big Picture“ ist ein Klassiker, weil es für Game-Streaming ideal ist.

Müsst ihr in der Sunshine Weboberfläche doch die Applikation einmal manuell anlegen, drückt Ihr dazu in der Oberfläche einfach auf + Add New.

Sunshine Menü Reiter Applications

Hier sind meine Einstellungen für Steam Big Picture, diese könnt ihr übernehmen oder selbst zum Teil anpassen.

Anzeige der Einstellung für die Applikation Steam Big Picture 1. Seite
Anzeige der Einstellung für die Applikation Steam Big Picture 2. Seite
Jetzt aber Raspberry Pi

Soweit bis hier hin. Wenn jetzt alles funktioniert, ihr schon ein Spiel streamen konntet, Steam funktioniert, Proton/Wine funktioniert, Nvidia Treiber sauber, Sunshine einwandfrei läuft, dann seid ihr bereit für Schritt 2 mit Moonlight auf dem Raspberry Pi am TV. Schließt dazu Euren Raspberry Pi an Euren TV an. Ich brauchte dafür erstmal einen Micro HDMI Adapter, da mein TV nur mehrere normale HDMI Anschlüsse hat und der Raspberry Pi 4 mit 2 Micro HDMI Anschlüssen daherkommt. Die Teile bekommt ihr bei den üblichen Online Händlern zu kaufen.

Micro HDMI Adapter

Als nächstes brauchen wir ein aktuelles Debian auf dem Raspberry Pi. Dafür habe ich Debian 12 Bookworm verwendet. Für den Download des Image habe ich die Seite https://raspi.debian.net/ verwendet. Dort ist auch die Installation auf der SD Karte beschrieben. Ist ja auch nur ein einfaches DD. 😉 Daher erspare ich mir die detaillierte Erkärung, ihr bekommt das schon hin. Es ist nur wichtig das ihr kein komplettes X und grafische Oberfläche usw. installiert. Also nehmt am besten das BasisImage und installiert die fehlenden Pakete nach. Ich verlinke Euch hier noch die Ausgabe von dpkg -l auf meinem System, damit ihr diese mit Eurem System vergleichen könnt, ob alle Pakete vorhanden sind, falls etwas nicht funktioniert. dpkg_output_raspberrypi.txt
Warum ist das mit dem X wichtig? Wir werden den Framebuffer des Raspberryi Pi für die Ausgabe beim Streaming nutzen. Der X Server oder gar Wayland sind recht praktisch, jedoch wenn wir Moonlight darauf grafisch laufen lassen und streamen, reicht die Performance eines Raspberry Pi 4 nicht aus.

Als nächstes installieren wir nun Moonlight auf dem Raspberry Pi. Es existieren 2 Varianten für den Raspberryi Pi -moonlight-embedded und moonlight-qt. Ich habe zuerst mit moonlight-embedded gearbeitet. Dies hat den Vorteil, dass man gar keine grafischen Tools braucht und ein Streaming rein auf der Console funktionert. Es ist optimiert für den Raspberryi Pi. Leider hat das einen Haken, den ich nach Stunden Konfiguration erst rausgefunden habe. HEVC ist in der Version moonlight-embedded 2.7.0-1, die ich verwendet hatte, nicht vollständig umgesetzt und nutzte die Hardware HEVC Decodierung des RPI nicht. Das führte zur Software Decodierung, wofür der Raspberry Pi 4 einfach zu schwach ist. Oder alternativ bleibt man bei h264. Das kann der RaspberryPI auch in Hardware und funktioniert auch mit dem moonlight-embedded. Ich wollte das maximale an Performance rausholen und daher der Weg zu moonlight-qt. Darum erstpart Euch Experimente und startet direkt mit moonlight-qt. Dafür sind nur zusätzlich ein paar QT Bibliotheken notwendig. Ich hatte damals die Software aus https://github.com/moonlight-stream/moonlight-docs/wiki/Installing-Moonlight-Qt-on-Raspberry-Pi-4 heruntergeladen. Dort gibt es eine ausführliche Anleitung, wie die Installation abläuft.

OK, Moonlight-QT ist auf Eurem Raspberry Pi installiert? Ihr braucht dann noch einige Einstellungen in der config.txt auf Eurem Raspberry Pi.

# cat /boot/firmware/config.txt# For more options and information see
# http://rptl.io/configtxt
# Some settings may impact device functionality. See link above for details

# Uncomment some or all of these to enable the optional hardware interfaces
#dtparam=i2c_arm=on
#dtparam=i2s=on
#dtparam=spi=on

# Enable audio (loads snd_bcm2835)
dtparam=audio=on

# Additional overlays and parameters are documented
# /boot/firmware/overlays/README

# Automatically load overlays for detected cameras
camera_auto_detect=1

# Automatically load overlays for detected DSI displays
display_auto_detect=1

# Automatically load initramfs files, if found
auto_initramfs=1

# Enable DRM VC4 V3D driver
#dtoverlay=vc4-kms-v3d
dtoverlay=vc4-fkms-v3d
dtoverlay=rpivid-v4l2
max_framebuffers=2
cma=320M

# Don't have the firmware create an initial video= setting in cmdline.txt.
# Use the kernel's default instead.
disable_fw_kms_setup=1

# Run in 64-bit mode
arm_64bit=1

# Disable compensation for displays with overscan
disable_overscan=1

# Run as fast as firmware / board allows
arm_boost=1

gpu_mem=256
usbhid.mousepoll=0

[all]
# Immer HDMI erzwingen
hdmi_force_hotplug=1

# Feste Auflösung auf 1920x1080 @ 60 Hz
hdmi_group=1
hdmi_mode=16

# Kein 4K aktivieren
hdmi_enable_4kp60=0

# HDMI-Signal verstärken (Adapter-Sicherheit)
config_hdmi_boost=7

# Framebuffer hart auf FullHD begrenzen
max_framebuffer_width=1920
max_framebuffer_height=1080

# Overscan deaktivieren (saubere Bildausgabe)
disable_overscan=1

hdmi_force_edid_3d=0

Die wichtigsten Optionen hier sind dtoverlay=vc4-fkms-v3d und dtoverlay=rpivid-v4l2, sowie die Deaktivierung von dtoverlay=vc4-kms-v3d.

Hier ist die genaue Bedeutung der Optionen:

  • dtoverlay=vc4-fkms-v3d (Fake KMS): Moonlight benötigt diesen Treiber, um direkt auf die Video-Hardware zuzugreifen. Während das neuere „Full KMS“ (vc4-kms-v3d) der aktuelle Standard für den Desktop ist, unterstützt es oft nicht die spezifischen Schnittstellen, die Moonlight für eine latenzfreie Dekodierung nutzt.
  • dtoverlay=rpivid-v4l2: Dies aktiviert den spezifischen Kernel-Treiber für den HEVC (H.265) Hardware-Decoder des Raspberry Pi 4. Ohne diesen Treiber muss die CPU das Video dekodieren, was zu Rucklern und hoher Latenz führt.
  • Deaktivierung von dtoverlay=vc4-kms-v3d (Full KMS): Dieser Treiber wird standardmäßig in neueren OS-Versionen (wie Bullseye oder Bookworm) verwendet, blockiert aber oft den Zugriff auf die für Moonlight notwendigen Low-Level-Funktionen oder führt zu einem schwarzen Bildschirm beim Streaming.

Die anderen Optionen habe ich hauptsächlich gesetzt, da ich Probleme mit der Anzeige an meinem TV hatte, weil ich unten am Streaming Gaming Server einen 4:3 Monitor angeschlossen habe und der TV ein 16:9 Format hat. Das gab dann Anzeige Probleme. Daher behaltet die anderen Optionen im Hinterkopf, falls etwas nicht funktioniert und prüft ob eine der Optionen Euch bei Eurem Problem hilft.

In der /boot/firmware/cmdline.txt habe ich dann noch zusätzlich 2 Parameter gesetzt usbhid.mousepoll und video=HDMI-A-1:1920x1080M@60

# cat cmdline.txt 
console=serial0,115200 console=tty1 root=PARTUUID=9566be13-02 rootfstype=ext4 fsck.repair=yes rootwait usbhid.mousepoll=0 video=HDMI-A-1:1920x1080M@60

Der Parameter usbhid.mousepoll=0 in der Datei /boot/cmdline.txt optimiert die Abfragerate (Polling Rate) der Maus und ist für ein flüssiges Streaming-Erlebnis mit Moonlight oft entscheidend.

Der Parameter video=HDMI-A-1:1920x1080M@60 in der /boot/firmware/cmdline.txt erzwingt eine feste Videoausgabe für den ersten HDMI-Anschluss. 

Im Detail:

  • HDMI-A-1: Identifiziert den primären HDMI-Port (beim Pi 4/5 der Anschluss direkt neben dem USB-C Stromeingang).
  • 1920×1080: Legt die Full-HD-Auflösung fest. Dies ist oft notwendig, da der Pi ohne diese Angabe bei manchen Monitoren auf eine niedrigere Standard-Auflösung (z.B. 640×480) zurückfällt, wenn das Display beim Booten nicht rechtzeitig erkannt wird.
  • M: Steht für CVT-Timing (Coordinated Video Timings). Es weist den Kernel an, die Modelline für diese Auflösung dynamisch zu berechnen, anstatt nur in den fest hinterlegten EDID-Daten des TV-Monitors zu suchen.
  • @60: Erzwingt eine Bildwiederholrate von 60 Hz. Das ist für Moonlight essenziell, da Streaming mit 60 FPS bei einer 30-Hz-Ausgabe zu extremem Ruckeln führt. 

Warum ist das für Moonlight wichtig? Vermeidung von Auflösungsfehlern: Ohne diesen Eintrag kann es passieren, dass der Pi eine Auflösung wählt, die nicht zum Moonlight-Stream passt. Das führt zu schwarzen Balken oder einem verzerrten Bild.

Noch ein Hinweis zum Thema Audio. Da Alsa mir massiv Probleme bei der Audioübertragung bereitet hat, habe ich pulseaudio installiert (sudo apt install pulseaudio) und die Alsa Software deinstalliert. Dann habe ich noch wie folgt eingestellt, dass Pulse Audio über HDMI zum TV läuft.

#pulse Audio über HDMI konfigurieren 
pactl list short sinks | grep -q alsa_output.platform-bcm2835_audio.digital-stereo && pactl set-default-sink alsa_output.platform-bcm2835_audio.digital-stereo

Dann fallen mir noch die User Gruppen ein. Diese sind wie folgt bei mir für den User pi konfiguriert, der Moonlight startet.

# groups
pi adm dialout cdrom sudo audio video plugdev games users input render netdev gpio i2c spi

Ich würde sagen, für einen ersten Versuch starten wir einmal Moonlight. Da ich meinen Raspberry Pi per ssh remote administriere, habe ich eine SSH Session mit X Forwarding zum Raspberry Pi geöffnet und starte in dieser Moonlight. So kann ich erstmal prüfen, ob Moonlight sauber aufgerufen wird und auch Konfigurationen vom Notebook aus vornehmen.

ssh -A -X -l pi raspberrypi.local moonlight-qt
Moonlight_raspberry_ssh_x_session

Sunshine hatte ich hier für einen Test noch nicht gestartet, daher normal das er das Ausrufezeichen anzeigt. Mit dem Zahnrad oben rechts könnt ihr dadurch erstmal Remote Eure Einstellungen für Moonlight vornehmen.

Moonlight-QT Config Oberfläche auf dem RaspberryPi gestartet

Die Moonlight Config Daten werden unter Eurem User (bei mir pi) gespeichert. Ich poste Euch ebenfalls meine Einstellungen, damit ihr im Notfall etwas vergleichen könnt. Wie Ihr bei mir sehen könnt, habe ich die Video Bitrate auf 50 Mbit gestellt. Der Raspi ist bei mir per LAN angebunden und bei der Einstellung hatte ich das Gefühl die besten Frameraten zu haben und den Raspi nicht zu überlasten.

# cat /home/pi/.config/Moonlight Game Streaming Project/Moonlight.conf 
[General]
abstouchmode=true
audiocfg=0
backgroundgamepad=false
bitrate=50000
capturesyskeys=0
certificate="..."
connwarnings=true
defaultver=2
detectnetblocking=true
fps=60
framepacing=false
gameopts=true
gamepadmouse=true
hdr=false
height=1080
hostaudio=false
keepawake=true
key="..."
language=0
latestsupportedversion-v1=99.99.99.99
mdns=true
mouseacceleration=false
multicontroller=true
muteonfocusloss=false
packetsize=0
quitAppAfter=false
reversescroll=false
richpresence=true
showperfoverlay=false
swapfacebuttons=false
swapmousebuttons=false
uidisplaymode=0
unlockbitrate=false
videocfg=2
videodec=1
vsync=true
width=1920
windowmode=1
yuv444=false

[gcmapping]
size=0

[hosts]
1\apps\1\appcollector=false
1\apps\1\directlaunch=false
1\apps\1\hdr=false
1\apps\1\hidden=false
1\apps\1\id=881448767
1\apps\1\name=Desktop
1\apps\2\appcollector=false
1\apps\2\directlaunch=false
1\apps\2\hdr=false
1\apps\2\hidden=false
1\apps\2\id=303580669
1\apps\2\name=Low Res Desktop
1\apps\3\appcollector=false
1\apps\3\directlaunch=false
1\apps\3\hdr=false
1\apps\3\hidden=false
1\apps\3\id=1093255277
1\apps\3\name=Steam Big Picture
1\apps\size=3
1\customname=false
1\hostname=gamingserver
1\ipv6address=
1\ipv6port=0
1\localaddress=192.168.1.X
1\localport=47989
1\mac=@ByteArray()
1\manualaddress=gamingserver.local
1\manualport=47989
1\nvidiasw=false
1\remoteaddress="..."
1\remoteport=47989
1\srvcert="..."
1\uuid="...."
size=1

Sofern das funktionert hat, könnt ihr jetzt den Moonlight-Client wieder wie gehabt koppeln, so wie wir es schon mal mit dem Notebook als Test gemacht haben. Sprich auch hier bekommt ihr, wenn ihr Sunshine gestartet habt, wieder einen Monitor mit Schloss. Diesen einfach drücken und den Pin auf der Weboberfläche von Sunshine eingeben, schon ist die Verbindung ebenfalls authorisiert. Wenn das jetzt funktioniert hat, macht nicht den Fehler über die SSH X Session das Streaming einmal auszuprobieren. Sondern Moonlight in der SSH Session wieder beenden und das Ganze nativ auf dem Raspberry Pi zu tun. Sprich Tastatur und Maus an den Raspberry Pi anschließen und den TV anschalten, sofern das nicht längst alles läuft. Ihr müsstet jetzt die Text Console von Eurem Raspberry Pi auf dem TV sehen. Anmelden mit Eurem User und dann direkt auf der Text-Console moonlight-qt eingeben. Schon müsste das bekannte Moonlight-Fenster wieder kommen und Ihr könnt auf den virtuellen Monitor drücken, um das Streaming zu starten.

Grundsätzlich lohnt es sich immer auf die Console von Moonlight auf dem Raspberryi Pi Client zu schauen oder auch in das Sunshine Log (~/.config/sunshine/sunshine.log) auf dem Streaming Server. Denn Fehlermeldungen sieht man dort als erstes.

Da mir das manuelle Starten von Sunshine und Moonlight per Hand zu aufwändig wurde und ich jedoch den Sunshine Server nicht die ganze Zeit laufen lassen wollte, habe ich mir ein kleines Script geschrieben, dass auf dem Raspberry Pi gestartet wird. Dieses eröffnet eine SSH Session zum Streaming Server, eröffnet eine Screen-Session, startet dann den Sunshine Server, setzt dann auf dem Raspberry Pi alle notwendigen Variablen, konfiguriert Audio und startet dann direkt Steam mit Big Picture. Somit brauche ich nur einen einzigen Befehl auf der Console des Raspberry Pi eingeben und alles startet vollautomatisiert, um sofort gestreamt Gamen zu können. Hier das Script falls Ihr es zum Teil verwenden oder anpassen wollt.

# cat start_moonlight.sh 
#!/bin/bash

REMOTE_HOST="gamingserver.local"
REMOTE_USER="user"
REMOTE_SUNSHINE="~/scripts/sunshine.sh"
SCREEN_NAME="sunshine"

echo "Verbinde mit $REMOTE_HOST und starte lightdm + sunshine..."

# Starte lightdm + sunshine in screen auf dem Remote-Host
ssh ${REMOTE_USER}@${REMOTE_HOST} bash -c "'
  set -x
  if ! pgrep -x lightdm >/dev/null; then
    echo \"Starte lightdm...\"
    sudo systemctl start lightdm
    sleep 3
  else
    echo \"lightdm läuft bereits.\"
  fi

  #Stromsparfunktion aus
  echo "Bildshirm an"
  xset -display :0 dpms force on

  if ! screen -list | grep -q ${SCREEN_NAME}; then
    echo "Starte sunshine.sh in screen..."
    screen -dmS ${SCREEN_NAME} ${REMOTE_SUNSHINE}
  else
    echo "screen '${SCREEN_NAME}' läuft bereits."
  fi
'"

#pulse Audio über HDMI konfigurieren 
pactl list short sinks | grep -q alsa_output.platform-bcm2835_audio.digital-stereo && pactl set-default-sink alsa_output.platform-bcm2835_audio.digital-stereo

# Zurück auf dem Pi: Starte moonlight-qt (blockierend)
echo "Starte moonlight-qt lokal auf dem RPi4 mit direkten Stream von Steam..."
#moonlight-qt
moonlight-qt stream gamingserver.local "Steam Big Picture"

# Wenn moonlight-qt beendet wurde:
echo "moonlight-qt wurde beendet. Clean all in $REMOTE_HOST..."

ssh ${REMOTE_USER}@${REMOTE_HOST} bash -c "'
  #echo \"Stoppe lightdm...\"
  #sudo systemctl stop lightdm
  #
  #echo "stoppe Steam"
  #pkill steam

  echo \"Beende screen '${SCREEN_NAME}'...\"
  screen -S ${SCREEN_NAME} -X quit

  #verbesserter Stromspar Effekt der Grafikkarte durch Restart
  echo "Restart nvidia-persistenced"
  sudo systemctl restart nvidia-persistenced

  #echo "Restart lightdm"
  #sudo systemctl restart lightdm

  sleep 3

  #Stromsparfunktion an
  echo "Bildshirm aus - Stromsparen"
  xset -display :0 dpms force off
'"

Ich hoffe Euer Streaming funktionert und bestimmt stoßt Ihr auf die eine oder andere unerwartete Hürde. Vielleicht hat Euch die Anleitung soweit geholfen, das alles einwandfrei funktioniert oder Euch die Einrichtung erleichtert hat. 🙂

Czaja IT Dienstleistungen und Unternehmensberatung Telefon 0177 7680425 E-Mail consulting@svenczaja.de

Für Alle die sich jetzt sagen:
Boah, das ist mir echt eine Nummer zu Hardcore, aber ich würde trotzdem super gerne, ein solches Streaming Setup haben.
Ich biete in meinen IT-Dienstleistungen ebenfalls die Einrichtung eines solchen Gaming-Streaming an. Daher scheut Euch nicht, Kontakt mit mir aufzunehmen.

Tesvor schweig!

Tesvor_X500_Staubsaugrobotoer_Schriftzug

Da mir mein Staubsaugroboter Tesvor x500 schon längere Zeit mit seiner Sprachausgabe auf die Nerven ging und jetzt mit schwächelndem Akku seinen Höhepunkt erreichte, war es Zeit zu handeln. Ich will nicht mehr Nacht für Nacht geweckt werden mit dem Satz. „Charging Starts“ 😀

Klar ein neuer Akku könnte her, jedoch soll der Staubsaugroboter hier nur meinen Mini Vorflur von 2x2m regelmäßig reinigen und da dieser per Stufe von dem Rest der Wohnung abgetrennt ist, braucht es keinen leistungsfähigen Akku. Zudem müssen wir auch mal an die Umwelt denken. 😉

Los geht’s:
Also Tesvor umgedreht, Staubbehälter entfernt. Akkuklappe 2x Schrauben gelöst und den Akku entfernt. Nun die anderen 8 Schrauben auf der Rückseite entfernt. Dann noch die 6 kleinen Schrauben von der Stoßleiste entfernt, Stoßleiste abgenommen und schon kann das Gesamtgehäuse abgenommen werden. Ein kurzer Blick an die Seiten wird schnell klar, wo der Lautsprecher sitzt. Ein schwarz/rotes verdrilltes Kabel ist das Richtige. Den Verlauf zur Platine verfolgt und den Stecker abgezogen. YES 🙂

Den Tesvor dann wieder in umgekehrter Reihenfolge zusammengebaut. Eingeschaltet und die Ruhe genossen :D. Schön wenn so ein Gerät stillschweigend seinen Dienst vollbringt, einfach Anweisungen per Fernbedienung geben und er macht was gewünscht. Herrlich diese Ruhe. 🙂

Ich frage mich schon länger, warum dieser Trend der ganzen Smart Homegeräte mit immer mehr Leuchtdioden, Beep und Sprache. Die Geräte sollen unauffällig Ihren Dienst vollbringen. Ich spreche ja auch nicht den ganzen Tag vor mich hin: „Jetzt gehe ich die Treppe hoch“, „Jetzt trinke ich ein Glas Wasser“, „Jetzt öffne ich die Tür“ … 😀

FuckUp:
Beim Zusammensetzen ist mir ein kleiner Fehler passiert, weil ich die kleinen Akkuklappeschrauben aus Versehen in die großen Schraubverbindungen eingebracht hatte. Die Schrauben wollten sich trotz hartnäckiger Bearbeitung und Klopfen auf der Rückseite nicht mehr entfernen lassen. Daher musste ein kleiner Trick her. Da ich noch ein paar kleinere Neodymmagneten herumliegen hatte, hab ich diese kurz an den Stab des Schraubdreher angehaftet und schon hat man einen stark magnetischen Schraubendreher. Dann war es ein Kinderspiel, die Schrauben aus den engen Schraubvertiefungen wieder zu befreien. Hier ein kleines Video für den Interessierten. 🙂

Signal Gruppe am Start …

Signal_Logo_Banner

Da ich schon länger darüber nachgedacht habe, eine Signal Gruppe zu gründen, hab ich dies nun einfach mal getan. Inhalt sind Themen rund um IT, quasi die Gruppe zum Blog. 🙂 Den Link findet ihr immer auf der Hauptseite inkl. QR Code, für alle die dem QR Code Scanning mächtig sind. 😉

Als Hintergrund zum Signal Messenger. Signal ist Open Source und hat einen richtigen Schub bekommen als einer der Mitgründer von WhatsApp, damals WhatsApp gewinnbringend an Facebook alias nun Meta verkauft hat und mit einem Teil des Geldes die Weiter-Entwicklung des Signal Messengers finanzierte. Daher ist Signal WhatsApp auch so ähnlich. Dafür muss ich mir um Datenschutz, Zweckentfremdung meiner Daten und Sicherheit keine Gedanken machen.

Details findet ihr bei Wikipedia Signal Messenger

Für alle Bequemen verlinke ich hier die IT Blog Gruppe nochmal 😀

Signal Gruppe

Unendliche Weiten … Zeit FuckUP Raspberry PI

Gerade eben bemerkte ich auf Einem meiner vielen Raspberry PIs, dass die Zeit nicht stimmt. Also mal geschaut was da los ist.

pi@raspbirrypi:~ $ ntpq
-bash: ntpq: command not found

Befehl ntpq Fehlanzeige! Ist ntp denn überhaupt installiert?

pi@raspbirrypi:~ $ dpkg -l | grep -i ntp
pi@raspbirrypi:~ $

Nö 😀

Da ich schon länger darüber nachdachte, dass eigentlich jeder Raspberry Pi bei mir im Netz eine gleiche Grundconfig benötigt, fangen wir doch jetzt damit an. 🙂 Und so sieht das initiale Ansible Playbook aus.

root@netbase:/etc/ansible# cat raspberry_base.yml 
---
- name: installiert die Basis Software auf alle Raspberries damit die Grundpakete alle gleich sind.  
  hosts: raspi
  become: yes
  tasks:
     - name: Install ntp
       apt:
        name: ntp
        state: present
     - name: Set Timezone to Europe/Berlin
       shell: "timedatectl set-timezone Europe/Berlin"

Dies werde ich dann in Zukunft immer mehr erweitern. Neben dem NTP Dienst habe ich auch gleich noch die Zeitzone gesetzt, da ich teilweise Raspberries mit UTC und andere mit CET gefunden habe. BTW -> become: yes <- steht dafür, dass wir den root brauchen. Ist ja logisch, ein „normaler“ User kann in der Regel keine Softwarepakete installieren.

Ansible Playbook abgefeuert und fertig. 🙂

root@netbase:/etc/ansible# ansible-playbook -u pi raspberry_base.yml 

PLAY [installiert die Basis Software auf alle Raspberries damit die Grundpakete alle gleich sind.] ******************************************************************

TASK [Gathering Facts] ******************************************************************
ok: [raspbirrypi.home]
ok: [raspburrypi.home]
ok: [raspbarrypi.home]
ok: [raspborrypi.home]
ok: [raspberrypi.home]
ok: [blackberrypi.home]
ok: [raspstrompi.home]

TASK [Install ntp] ******************************************************************
ok: [raspburrypi.home]
ok: [raspbarrypi.home]
ok: [raspbirrypi.home]
ok: [raspborrypi.home]
ok: [blackberrypi.home]
ok: [raspberrypi.home]
ok: [raspstrompi.home]

TASK [Set Timezone to Europe/Berlin] ******************************************************************
changed: [raspbarrypi.home]
changed: [raspburrypi.home]
changed: [raspbirrypi.home]
changed: [raspborrypi.home]
changed: [blackberrypi.home]
changed: [raspberrypi.home]
changed: [raspstrompi.home]

PLAY RECAP ******************************************************************
blackberrypi.home          : ok=3    changed=1    unreachable=0    failed=0   
raspbarrypi.home           : ok=3    changed=1    unreachable=0    failed=0   
raspberrypi.home           : ok=3    changed=1    unreachable=0    failed=0   
raspbirrypi.home           : ok=3    changed=1    unreachable=0    failed=0   
raspborrypi.home           : ok=3    changed=1    unreachable=0    failed=0   
raspburrypi.home           : ok=3    changed=1    unreachable=0    failed=0   
raspstrompi.home           : ok=3    changed=1    unreachable=0    failed=0 

Wer sich noch fragt, was in meinem playbook hosts: raspi bedeutet. Der findet die Antwort hier.

root@netbase:/etc/ansible# cat hosts 
# This is the default ansible 'hosts' file.
#
# It should live in /etc/ansible/hosts
#
#   - Comments begin with the '#' character
#   - Blank lines are ignored
#   - Groups of hosts are delimited by [header] elements
#   - You can enter hostnames or ip addresses
#   - A hostname/ip can be a member of multiple groups

# Ex 1: Ungrouped hosts, specify before any group headers.

#green.example.com
#blue.example.com
#192.168.100.1
#192.168.100.10

netbase.home ansible_connection=local

# All RaspberrPis
[raspi]
raspberrypi.home
raspborrypi.home
raspbirrypi.home
raspburrypi.home
raspbarrypi.home
blackberrypi.home
raspstrompi.home

Kleiner Sidehack noch am Rande; sollte Euch mal die Zeit völlig aus dem Ruder laufen und diese sich trotz hinterlegtem NTP Server nicht mehr einstellen, könnt ihr mit den folgenden Befehlen das Ganze per Workaround erstmal lösen.

pi@raspberrypi ~ $ sudo service ntp stop
pi@raspberrypi ~ $ sudo ntpd -gq
22 Feb 01:50:18 ntpd[21891]: ntpd 4.2.8p10@1.3728-o Sat Mar 10 18:03:33 UTC 2018 (1): Starting
22 Feb 01:50:18 ntpd[21891]: Command line: ntpd -gq
22 Feb 01:50:18 ntpd[21891]: proto: precision = 1.145 usec (-20)
22 Feb 01:50:18 ntpd[21891]: Listen and drop on 0 v6wildcard [::]:123
22 Feb 01:50:18 ntpd[21891]: Listen and drop on 1 v4wildcard 0.0.0.0:123
22 Feb 01:50:18 ntpd[21891]: Listen normally on 2 lo 127.0.0.1:123
22 Feb 01:50:18 ntpd[21891]: Listen normally on 3 eth0 192.168.1.113:123
22 Feb 01:50:18 ntpd[21891]: Listen normally on 4 lo [::1]:123
22 Feb 01:50:18 ntpd[21891]: Listen normally on 5 eth0 [2003:c9:b702:26be:ba27:ebff:fec6:809c]:123
22 Feb 01:50:18 ntpd[21891]: Listen normally on 6 eth0 [fe80::ba27:ebff:fec6:809c%2]:123
22 Feb 01:50:18 ntpd[21891]: Listening on routing socket on fd #23 for interface updates
22 Feb 01:50:19 ntpd[21891]: Soliciting pool server 173.212.192.154
22 Feb 01:50:20 ntpd[21891]: Soliciting pool server 195.201.163.190
22 Feb 01:50:20 ntpd[21891]: Soliciting pool server 144.76.0.164
22 Feb 01:50:21 ntpd[21891]: Soliciting pool server 46.165.252.57
22 Feb 01:50:21 ntpd[21891]: Soliciting pool server 176.9.166.35
22 Feb 01:50:21 ntpd[21891]: Soliciting pool server 2001:418:3ff::53
22 Feb 01:50:22 ntpd[21891]: Soliciting pool server 2001:638:504:2000::34
22 Feb 01:50:22 ntpd[21891]: Soliciting pool server 194.25.134.196
22 Feb 01:50:22 ntpd[21891]: Soliciting pool server 80.153.195.191
22 Feb 01:50:22 ntpd[21891]: Soliciting pool server 37.221.193.210
22 Feb 01:50:23 ntpd[21891]: Soliciting pool server 116.202.222.249
22 Feb 01:50:23 ntpd[21891]: Soliciting pool server 2a01:4f9:c010:bf3::2
22 Feb 01:50:23 ntpd[21891]: Soliciting pool server 3.121.254.221
22 Feb 01:50:23 ntpd[21891]: Soliciting pool server 162.159.200.123
22 Feb 01:50:24 ntpd[21891]: Soliciting pool server 185.11.138.90
22 Feb 01:50:24 ntpd[21891]: Soliciting pool server 2a03:4000:27:602:d4cf:50ff:fedb:b65a
22 Feb 01:50:24 ntpd[21891]: Soliciting pool server 213.209.109.44
22 Feb 01:50:27 ntpd[21891]: ntpd: time slew +0.009508 s
ntpd: time slew +0.009508s
pi@raspberrypi ~ $ sudo service ntp start

Das -gq weist den ntp-Daemon an, die Zeit ungeachtet des Offsets (g) zu korrigieren und sofort zu beenden (q), nachdem die Zeit eingestellt wurde.

Bei Wiederholung der Zeitprobleme müsst ihr in die Analyse gehen, wo die eigentliche Ursache für das Problem liegt.

Luftfeuchtigkeits- und Temperaturmessung

Wetter_Sensor_Bild

sensor_ash2200_temp_luftfeuchtigkeit

In meinem Haus kam recht früh das Bedürfnis auf, die Luftfeuchtigkeit und Temperatur an vielen Stellen zu messen und grafisch darzustellen. Da ein Raspberry PI bereits als Kamera Überwachung zum Einsatz kam, musste etwas her, dass einfach an dem Raspberry PI zu betreiben ist. Die Batterielaufzeit der Sensoren sollte hoch sein und eine hohe Reichweite ermöglichen, da auch die Garage ca 35m vom Haus entfernt, gemessen werden sollte. Nach einiger Suche bin ich auf den ELV USB-Wetterdaten-Empfänger USB-WDE1-2 gestoßen. Dazu der Temperatur und Luftfeuchtigkeitssensor ASH 2200.

Der USB Wetterempfänger wird einfach per USB an den Raspberry Pi angeschlossen. Der ASH 2200 Sensor funkt mit 868,35 MHz und funktioniert mit 2 x LR6 Batterien. Dieser ist wetterfest und kann innen wie außen verwenden werden. Für drinnen nehme ich die Kappe ab, weil einen Regenschutz braucht man dort nicht und der Sensor reagiert noch etwas schneller. Ich habe den Sensor testweise aus einem warmen Raum mit 23 Grad in den Kühlschrank mit 5 Grad gelegt. Die Temperatur fiel dann ziemlich gleichmäßig und es hat ca 30 Minuten gedauert bis die Temperatur erreicht war. Die Batterien halten in dem Sensor mehrere Jahre. Sind wirklich sehr zuverlässig und jetzt schon seit 2014 im Einsatz.

usb_wetterdaten_empfaenger_wde1_2_elv

Unter Linux meldet sich der Empfänger im dmesg Ouput wie folgt:

[17592970.864446] usbcore: registered new interface driver cp210x
[17592970.869275] usbserial: USB Serial support registered for cp210x
[17592970.874246] cp210x 1-1.5:1.0: cp210x converter detected
[17592970.884531] usb 1-1.5: cp210x converter now attached to ttyUSB0

Wie wird der Empfänger nun ausgelesen?

Dazu verwende ich die usb-wde-tools von Christian Weiske.

https://github.com/cweiske/usb-wde1-tools

Dabei nehme ich das Script usb-wde1-log-last.sh, welches ich etwas bezüglich USB Device angepasst habe. Dieses lässt man einfach im Hintergrund laufen.

pi@raspberrypi /usr/local/bin $ cat usb-wde1-log-last.sh 
#!/bin/sh
# logs the last line. usable via nohup on the server
#
# run this script as follows:
# $ nohup ./usb-wde1-log-last.sh &
#
# Use --dummy-data as parameter to log dummy data only
#
# License: http://www.gnu.org/licenses/agpl.html AGPL
# Author: Christian Weiske <cweiske@cweiske.de>
#
# FIXME: send RESET or INIT and M2

DEVUSB="/dev/ttyUSB_cp210x"

stty < $DEVUSB 9600 -brkint -opost -onlcr -echo

curdir="$(dirname "$0")"
if [ "$1" = "--dummy-data" ]; then
    $curdir/../dummy-data-generator.php\
     | $curdir/log-single-line.sh /tmp/usb-wde1-last
else
    if [ ! -r $DEVUSB ]; then
        echo "Device $DEVUSB is not readable"
        exit 1
    fi

    #socat breaks something that leads to
    # WRONG VAL, WRONG CMD and FullBuff->Reset
    # errors
    socat $DEVUSB,b9600,min=1,time=1,brkint=0,icrnl=0,ixoff=1,imaxbel=0,opost=0,isig=0,icanon=0,iexten=0,echo=0,echoe=0,echok=0 STDOUT\
     | $curdir/log-single-line.sh /tmp/usb-wde1-last
fi

Ich hab für das Device auch gleich eine UDEV Rule geschrieben, damit findet man das Gerät immer unter dem festen Namen /dev/ttyUSB_cp210x. Die sieht wie folgt aus:

pi@raspberrypi /etc/udev/rules.d $ cat 77-cp210x.rules 
ACTION=="add", ATTRS{serial}=="XVSEF80M6D3DGCJX", SYMLINK+="ttyUSB_cp210x"

Die Seriennummer wurde mit folgendem Befehl ermittelt.

udevadm info --attribute-walk -n /dev/ttyUSB0

Aktivieren lässt sich die Rule dann wie immer mit:

pi@raspberrypi:~ $ sudo udevadm control --reload

Danach ist der Sensor immer unter /dev/ttyUSB_cp210x zu finden. Nach einiger Zeit kann man sich nun die Datei /tmp/usb-wde1-last anschauen. Diese sieht wie folgt aus.

pi@raspberrypi ~ $ cat /tmp/usb-wde1-last 
$1;1;1642979529;22,4;16,8;23,0;14,0;22,1;24,1;15,7;5,2;49;54;48;67;49;49;60;96;;;;;;0

Hier sind nun mit ; von einander getrennt, die verschiedenen Sensoren im Haus und außerhalb zu finden. Die Codierung der Sensoren geschieht über ein paar kleine Dipschalter, dafür muss der Sensor auseinander geschraubt werden. Somit sind max 8 Sensoren gleichzeitig verwendbar.

Hier mal die Werte auseinander genommen zum besseren Verständnis.

22,4; = Sensor 1 = 22,4 Grad Temperatur
16,8; = Sensor 2 = 16,8 Grad Temperatur
23,0; = Sensor 3 = 23,0 Grad Temperatur
14,0; = Sensor 4 = 14,0 Grad Temperatur
22,1; = Sensor 5 = 22,1 Grad Temperatur
24,1; = Sensor 6 = 24,1 Grad Temperatur
15,7; = Sensor 7 = 15,7 Grad Temperatur
 5,2; = Sensor 8 =  5,2 Grad Temperatur

49; = Sensor 1 = 49% Luftfeuchtigkeit
54; = Sensor 2 = 54% Luftfeuchtigkeit
48; = Sensor 3 = 48% Luftfeuchtigkeit
67; = Sensor 4 = 67% Luftfeuchtigkeit
49; = Sensor 5 = 49% Luftfeuchtigkeit
49; = Sensor 6 = 49% Luftfeuchtigkeit
60; = Sensor 7 = 60% Luftfeuchtigkeit
96; = Sensor 8 = 96% Luftfeuchtigkeit

Um die Werte auch für andere Programme und auch Zabbix zu verwenden, habe ich dazu ein Script zum splitten der Werte geschrieben. Dieses Script kann einfach mit einem Parameter aufgerufen werden und man bekommt immer den entsprechenden Wert zurückgeliefert.

pi@raspberrypi ~ $ cat /usr/local/bin/split_usb_wde2.sh
#!/bin/bash
#Beispielwerte
#18,4;15,6;18,7;15,6;13,9;18,8;15,8;9,1;48;71;48;68;54;47;53;77

#Temperatur
#1 - 18,4 - Küche (4)
#2 - 15,6 - Keller (5)
#3 - 18,7 - Obergeschoss (6)
#4 - 15,6 - Anbau (7)
#5 - 13,9 - Bad oben (8) 
#6 - 18,8 - Bad unten (9)
#7 - 15,8 - Garage (10)
#8 -  9,1 - Außen (11)
#
#Luftfeuchtigkeit
#9  - 48 - Küche (12)
#10 - 71 - Keller (13)
#11 - 48 - Obergeschoss (14)
#12 - 68 - Anbau (15)
#13 - 54 - Bad oben (16)
#14 - 47 - Bad unten (17)
#15 - 53 - Garage (18)
#16 - 77 - Außen (19)

werte=$(cat /tmp/usb-wde1-last | tr "," ".") 

case $1 in 
     
     kueche_temp)
             echo $werte | cut -f 4 -d ";"
             ;;
     keller_temp)
             echo $werte | cut -f 5 -d ";"
             ;;
     obergeschoss_temp)
             echo $werte | cut -f 6 -d ";" 
             ;;
     anbau_temp)
             echo $werte | cut -f 7 -d ";" 
             ;;
     bad_oben_temp)
             echo $werte | cut -f 8 -d ";"
             ;;
     bad_unten_temp)
             echo $werte | cut -f 9 -d ";"
             ;;
     garage_temp)
             echo $werte | cut -f 10 -d ";"
             ;;
     aussen_temp)
             echo $werte | cut -f 11 -d ";"
             ;;
     kueche_lf)
             echo $werte | cut -f 12 -d ";"
             ;;
     keller_lf)
             echo $werte | cut -f 13 -d ";"
             ;;
     obergeschoss_lf)
             echo $werte | cut -f 14 -d ";" 
             ;;
     anbau_lf)
             echo $werte | cut -f 15 -d ";"
             ;;
     bad_oben_lf)
             echo $werte | cut -f 16 -d ";"
             ;;
     bad_unten_lf)
             echo $werte | cut -f 17 -d ";"
             ;;
     garage_lf)
             echo $werte | cut -f 18 -d ";"
             ;;
     aussen_lf)
             echo $werte | cut -f 19 -d ";"
             ;;
     *)
             echo 0
             ;;
esac

Hier ein Beispiel: z.B. Luftfeuchtigkeit der Küche anzeigen.

pi@raspberrypi ~ $ split_usb_wde2.sh kueche_lf
49

Die Zabbix Config sieht dann z.B. so aus

zabbix_item_kueche_luftfeuchtigkeit

Grafisch sieht das Ganze im Zabbix dann z.B. so aus.

Im Zabbix kann man dann mehrere Werte in einem Graph zusammenbringen. So kann dass dann beispielhaft für das ganze Haus aussehen.

zabbix_graph_alle_luftfeuchtigkeit
zabbix_graph_alle_temperatur

Wer sich jetzt hier wundert. Da sind doch mehr als 8 Werte. Ja da habe ich mit einigen zusätzlichen Shelly HT-Sensoren experimentiert, gerne dazu mehr in einem anderen Blog. 🙂

Und was ist mit Ansible zur automatischen Verteilung? 🙂

# cat /etc/ansible/usb-wde.yml 
---
- name: Transfer usb-wde Scripts and execute the script with user pi
  hosts: raspberrypi.home
  become: yes
  tasks:
     - name: Transfer the usb-wde scripts  
       copy: src={{ item }} dest=/usr/local/bin/
       with_fileglob:
         - usb-wde1-tools/*
     - name: Changing Permissions shell script
       file: dest=/usr/local/bin/log-single-line.sh owner=root group=root mode=0755
     - name: Changing Permissions shell script
       file: dest=/usr/local/bin/split_usb_wde2.sh owner=root group=root mode=0755
     - name: Changing Permissions shell script
       file: dest=/usr/local/bin/usb-wde1-log-last.sh owner=root group=root mode=0755
     - name: Transfer cron.d Entry for automatic start at reboot
       copy: src=/etc/ansible/cron.d/usb-wde dest=/etc/cron.d/
     - name: Transfer cp210x tty Symlink UDEV Rule in rules.d (/dev/ttyUSB_cp210x)
       copy: src=/etc/ansible/udev/rules.d/77-cp210x.rules dest=/etc/udev/rules.d/
     - name: reload udev
       command: "udevadm control --reload-rules"
     - name: kill all running usb-wde process
       shell: "killall usb-wde1-log-last.sh log-single-line.sh --wait"
       ignore_errors: true # In case there is no process
     - name: Start usb-wde1-log-last.sh in Backgroud
       become_user: pi
       shell: "(/usr/local/bin/usb-wde1-log-last.sh >/dev/null 2>&1 &)"
       async: 10
       poll: 0

Der Cron Eintrag für das automatische Starten beim Neustart sieht dabei relativ einfach aus.

# cat /etc/ansible/cron.d/usb-wde 
PATH=/bin:/usr/bin:/sbin:/usr/sbin

# at reboot start usb-wde1-log-last.sh
@reboot		pi	/usr/local/bin/usb-wde1-log-last.sh &

Vollständigkeitshalber hier auch noch das log-single-line.sh von Christian Weiske

pi@raspberrypi ~ $ cat /usr/local/bin/log-single-line.sh
#!/bin/sh
# Logs a single line into the log file passed as script parameter
#  and adds timestamp to the logview openformat lines
#
# License: http://www.gnu.org/licenses/agpl.html AGPL
# Author: Christian Weiske <cweiske@cweiske.de>

file="$1"
if [ "x$file" = "x" ]; then
    echo Please pass a file name to log the line into
    exit 1
fi

# $1;1;;13,8;22,7;22,6;17,8;22,2;21,2;22,9;;59;35;38;49;38;40;35;;;;;;;0
while read -r line
do
    beginning=`echo "$line"|cut -b 1-3`
    if [ "$beginning" = '$1;' ]; then
        timestamp=`date +%s`
        echo $line|sed "s/\$1;1;;/\$1;1;$timestamp;/" > "$file"
    fi
done

Das Projekt startete bei mir im Jahr 2014. Mittlerweile gibt es die Sensoren nicht mehr bei ELV direkt zu kaufen. Den USB WDE Empfänger hingegen schon noch. Die Sensoren kosteten damals 29 Euro neu. Was sicherlich kein Schnäppchen ist, jedoch für Ihre Haltbarkeit (kein einziger Ausfall bis heute) und die hohe Reichweite + Batterielaufzeit sprechen für sich. Aktuell bekommt man die Sensoren nur noch in einigen Auktionshäusern oder in Kleinanzeigen. Für innen funktioniert ebenfalls der S300TH Sensor oder S555TH. Es gibt von mir schon einige Experimente mit Shelly HT Sensoren … more soon.

Daher never touch a running system. 🙂

Medion Wischroboter im Test

Medion_wischroboter_p10w_2021

Vor kurzem habe ich mir einen MEDION Wischroboter mit Wassertank P10W (Modell 2021) zugelegt. Da mein Haus hauptsächlich aus Vinyl und Fliesen am Boden besteht und ich von dem Wischrollenkonzept überzeugt war, gab ich dem Ganzen eine Chance. Ich befülle den Roboter immer mit destilliertem Wasser (aus dem Wäschetrockner) und einem Tropfen Neutralreiniger, so entstehen keine Kalkstreifen auf den schwarzen Fliesen und es wird schön sauber. Anbei daher ein kleines 5 Minuten Video zum Befüllen, Nutzen, Reinigen, Lautstärke für alle Interessierten. Viel Spaß dabei. 🙂

Feinstaubmessung mit dem Raspberry Pi

Luftfiltergeräte hört man aktuell an allen Ecken, die Corona Pandemie hat dies deutlich befördert. Da ich im Mai immer mal für 4 Wochen an einer Pollenallergie leide und ich schon einen Tipp für ein Luftfiltergerät bekommen habe, habe ich mich mit den Geräten etwas mehr auseinander gesetzt. Die Geräte messen in der Regel die Feinstaubmenge in der Luft und sind dann in verschiedenen Stufen unterwegs. Also dachte ich mir, messen wir doch erst mal den Feinstaub in der Wohnung, bevor wir Geräte aufstellen. 😉

Auf die Suche gegangen, bin ich dann auf den PM-Sensor SDS011 gestoßen, dieser kann per USB angeschlossen werden und misst in PM 2,5 und PM 10. Infos zu diesen Werten findet ihr in Wikipedia beim Suchbegriff Feinstaub. Auch die europäischen Grenzwerte findet Ihr dort. Hier nun der Sensor.

Das kleine eckige oben drauf ist ein kleiner Lüfter, dieser ist auch leicht zu hören. Also Obacht wenn ihr das Teil im Wohnzimmer aufstellen wollt. Bei mir steht er im Esszimmer und stört mich von der Geräuschkulisse nicht. Man kann das Teil jedoch auch gut in einen Schrank verlegen, denn es hat diesen silbernen Anschluss. Dort kann ein Schlauch angeschlossen werden, dieser muss am Ende eben nur die zu testende Luft frei ansaugen können. Dies gibt einem vielfältige Möglichkeiten das Teil auch verdeckt zu verbauen.

Nach dem Einstecken im Raspberry PI meldet sich dieses mit (Befehloutput -> dmesg)

[ 8.003492] usbcore: registered new interface driver ch341
[ 8.003588] usbserial: USB Serial support registered for ch341-uart
[ 8.003704] ch341 1-1.3:1.0: ch341-uart converter detected
[ 8.026555] usb 1-1.3: ch341-uart converter now attached to ttyUSB0

Zum Auslesen des Sensors nutze ich das Python Programm von marw -> https://gist.github.com/marw/ read_nova_pm_sensor.py

Ich habe das Python Programm leicht angepasst, sodass statt ttyUSB0 ein fester Name verwendet wird, den ich per UDEV Rule definiert habe. Soll einfach dafür sorgen, wenn sich ein 2. Gerät im System befindet, dass es immer das Richtige für den Sensor verwendet.

pi@blackberrypi:~ $ cat /usr/local/bin/feinstaub.py#!/usr/bin/env python3

"""
Get reading from Nova PM Sensor SDS011
(dust sensor, air quality sensor, PM10, PM2,5)
Designed to run from cron and append CSV file.
Script tested using Python3.4 on Ubuntu 14.04.
TODO: choose by dev name using udev, add dev id info, python package pyudev
    udevadm info -q property --export /dev/ttyUSB_ch341
"""

import os
import csv
import io

import logging
import datetime
import argparse

try:
    import serial
except ImportError:
    print('Python serial library required, on Ubuntu/Debian:')
    print('    apt-get install python-serial python3-serial')
    raise


LOG_FORMAT = '%(asctime)-15s %(levelname)-8s %(message)s'


def append_csv(filename, field_names, row_dict):
    """
    Create or append one row of data to csv file.
    """
    file_exists = os.path.isfile(filename)
    with io.open(filename, 'a', encoding='utf-8') as csvfile:
        writer = csv.DictWriter(csvfile,
                                delimiter=',',
                                lineterminator='\n',
                                fieldnames=field_names)
        if not file_exists:
            writer.writeheader()
        writer.writerow(row_dict)


def read_nova_dust_sensor(device='/dev/ttyUSB_ch341'):
    dev = serial.Serial(device, 9600)

    if not dev.isOpen():
        dev.open()

    msg = dev.read(10)
    assert msg[0] == ord(b'\xaa')
    assert msg[1] == ord(b'\xc0')
    assert msg[9] == ord(b'\xab')
    pm25 = (msg[3] * 256 + msg[2]) / 10.0
    pm10 = (msg[5] * 256 + msg[4]) / 10.0
    checksum = sum(v for v in msg[2:8]) % 256
    assert checksum == msg[8]
    return {'PM10': pm10, 'PM2_5': pm25}


def main():
    logging.basicConfig(format=LOG_FORMAT, level=logging.INFO)

    parser = argparse.ArgumentParser(description='Read data from Nova PM sensor.')
    parser.add_argument('--device', default='/dev/ttyUSB_ch341',
                        help='Device file of connected by USB RS232 Nova PM sensor')
    parser.add_argument('--csv', default=None,
                        help='Append results to csv, you can use year, month, day in format')
    args = parser.parse_args()

    data = read_nova_dust_sensor(args.device)
    logging.info('PM10=% 3.1f ug/m^3 PM2.5=% 3.1f ug/m^3', data['PM10'], data['PM2_5'])

    if args.csv:
        field_list = ['date', 'PM10', 'PM2_5']
        today = datetime.datetime.today()
        data['date'] = today.strftime('%Y-%m-%d %H:%M:%S')
        csv_file = args.csv % {'year': today.year,
                               'month': '%02d' % today.month,
                               'day': '%02d' % today.day,
                               }
        append_csv(csv_file, field_list, data)

if __name__ == '__main__':
    main()

Damit das Programm funktioniert, müssen die Pakete python-serial und python3-serial installiert sein.

pi@blackberrypi:~ $ sudo apt install python-serial python3-serial

Beim Aufruf des Python Programm ergibt sich folgender Output.

pi@blackberrypi:~ $ feinstaub.py
2022-01-15 02:09:03,905 INFO PM10= 10.7 ug/m^3 PM2.5= 3.0 ug/m^3

Die UDEV Rule sieht wie folgt aus.

pi@blackberrypi:~ $ cat /etc/udev/rules.d/88-ch341.rules
ACTION=="add", ATTRS{serial}=="3f980000.usb", SYMLINK+="ttyUSB_ch341"

Der folgende Befehl aktiviert die Rule

pi@blackberrypi:~ $ sudo udevadm control --reload

Danach ist der Sensor immer unter /dev/ttyUSB_ch341 zu finden.

Um die Werte aus dem Python Programm für mein Zabbix einfacher lesbar zu machen, habe ich dafür ein kleines Shell Script geschrieben. Diese liegt zwei Dateien /tmp/pm10 und /tmp/pm25 ab und liest den Wert jede Minute aus. Das Programm läuft dann dauerhaft im Hintergrund.

pi@blackberrypi:~ $ cat /usr/local/bin/feinstaub.sh
#!/bin/bash
# Script das feinstaub.py aufruft und die beiden Werte in pm10 und pm25 teilt um diese dann aus zabbix auszulesen 
# pm10 steht für partikel 10 und pm25 für partikel 2,5
while true
do
    feinstaub.py 2>&1 | cut -f 9,12 -d ' '| { read pm10 pm25; 
    echo $pm10 > /tmp/pm10;
    echo $pm25 > /tmp/pm25; }
    sleep 60
done

Die Zabbix Config hierfür sieht wie folgt aus.

Sidetip: Wem vielleicht in meinen Zabbix Configs die History storage period und der 0 Wert bei Trend storage period aufgefallen ist. Diese habe ich bewusst so gewählt. Ich möchte eine lange Zeit Echtwerte (vollständig Detailtiefe). Daher habe ich Trend völlig abgeschaltet und die History auf 8 Jahre (8×365 = 2920) hoch gesetzt.

So sieht nun ein ganz „normaler“ Tag im Haus im Zabbix Graph aus. 🙂

feinstaubgraphzabbixnormalertaginnen

BTW bei diesen Feinstaubwerten wäre kein einziger Luftfilter angelaufen, da sich die Feinstaubwerte völlig im Normalbereich befinden.

Automatisierung? Dann los mit Ansible.

# cat /etc/ansible/feinstaub.yml
---
- name: Transfer feinstaub.sh Script and feinstaub.py Python PGM and execute the script with user pi
  hosts: blackberrypi.home,raspberrypi.home
  become: yes
  tasks:
     - name: Install python3-serial python-serial 
       apt:
        pkg:
        - python3-serial
        - python-serial
     - name: Transfer the feinstaub.sh script and feinstaub.py python PGM Code and check_feinstaub.sh for cron.d  
       copy: src={{ item }} dest=/usr/local/bin/
       with_fileglob:
         - feinstaub/*
     - name: Changing Permissions shell script
       file: dest=/usr/local/bin/feinstaub.sh owner=root group=root mode=0755
     - name: Changing Permissions feinstaub.py python pgm
       file: dest=/usr/local/bin/feinstaub.py owner=root group=root mode=0755
     - name: Transfer cron.d Entry for automatic start at reboot and check script
       copy: src=/etc/ansible/cron.d/feinstaub dest=/etc/cron.d/
     - name: Transfer feinstaub tty Symlink UDEV Rule in  rules.d (/dev/ttyUSB_ch341)
       copy: src=/etc/ansible/udev/rules.d/88-ch341.rules dest=/etc/udev/rules.d/
     - name: reload udev
       command: "udevadm control --reload-rules"
     - name: kill all running feinstaub process
       shell: "killall feinstaub.sh --wait"
       ignore_errors: true # In case there is no process
     - name: Start feinstaub.sh in Backgroud
       become_user: pi
       shell: "(/usr/local/bin/feinstaub.sh >/dev/null 2>&1 &)"
       async: 10
       poll: 0

Das Ansible Playbook (YML) kann dann einfach mit folgendem Befehl verteilt werden.

ansible-playbook -u pi feinstaub.yml

Wer das Ansible Playbook genau betrachtet, dem ist sicherlicht nicht entgangen, dass 2 Zielhosts hier hinterlegt sind. Das ist richtig. Nachdem der 1. Feinstaubsensor so erfolgreich in meinem Heim lief, fragte ich mich, welche Feinstaubwerte denn draußen existieren und welchen Einfluß diese wiederum auf meine Werte im Haus haben. Lohnt es sich bei schlechten Werten im Haus zu lüften oder sind draußen gar noch schlechterer Werte?

Durch Ansible ist dies schnell auf einen 2. Raspberry bei mir in der Garage neben dem Haus verteilt. Den 2. gekauften Sensor einfach angesteckt und mit einem kleinen Schlauch an die Außenluft verbunden. Zu beachten ist bei den Sensoren, dass diese auch bei Nebel reagieren und bei ganz feinem Nieselregen. Daher nicht gleich in Panik verfallen, wenn die Werte mal explodieren und es einfach nur regnet draußen. 😉

Feinstaubsensoraussen
feinstaubansaugschlauch

So sieht das dann zusammen im Zabbix Graph aus.

feinstaubmessung_aussen_innen

Bei der Spitze morgens um 7 Uhr sieht man, was passiert wenn einer der Nachbarn seinen Kamin anwirft. 😀

Sideinfo: Wußtet Ihr, dass beim Kochen massiv Feinstaub entsteht (weit über die Grenzwerte)? Hier mal ein Graph wo in der Pfanne 10 Minuten etwas Gemüse angebraten wurde. Seitdem ist bei mir die Dunstabzugshaube immer an. 🙂 Die gute Nachricht: Mit Lüften konnte das Problem relativ schnell entschärft werden. Und nein die Küche war nicht blau. 😀

Hier noch ein Link zu einem wissenschaftlichen Bericht dazu.

https://www.leibniz-gemeinschaft.de/ueber-uns/neues/forschungsnachrichten/forschungsnachrichten-single/newsdetails/mehr-feinstaub-durch-kochen-und-heizen

Wenn Ihr Fragen oder Anmerkungen habt, schreibt mir gerne eine Mail -> info AT svenczaja.de

Umstieg Blog auf SSL

Da heute nichts mehr ohne Verschlüsselung geht, habe ich nun auch meinen Blog umgestellt. Offizielle Zertifikate gibt es gratis von Let’s Encrypt. Dies hat mich zwar einmal den Blog gekostet, aber mit Hilfe des Supports und dem Zurücksetzen der WordPress Installation ging es dann doch recht flott. Es brauchte dann noch einen Eintrag in der wp-config.php von

define( 'FORCE_SSL_ADMIN', true );

und dann innerhalb der WordPress Einstellungen Allgemein alles dort von http:// auf auf https:// umstellen.

Was lernen wir daraus? 1. Backup machen, 2. SSL besser gleich beim Start einschalten bevor Inhalte erfasst werden. 🙂

Daher Willkommen in einer nun sicheren Variante 😉

PS. Den GoogleBot hab ich dann auch mal um Indizierung gebeten. 😀

1. Blogpost … es geht los

Mein erster Blogpost. 🙂

Sven

Nachdem mir das selbst gecode in html doch irgendwie selbst mit bluefish zu mühselig war und ich merkte, dass ich eigentlich Inhalte erfassen will und nicht Stunden mit Coden beschäftigt sein möchte. Die Hürde HTML würde dann zu einem „och ich lass es sein“ führen. Daher nach Alternativen umgeschaut und mit WordPress recht schnell eine passable Möglichkeit gefunden. Mein Webspace Anbieter unterstützt dies und so ging die Einrichtung schnell. WordPress scheint mir recht intuitiv, obwohl der Webseiten Hauptlink nicht geklappt hat, aber das hab ich schnell noch in der index.html auch selbst gezaubert bekommen. 😉

Daher habe ich nun meine beiden in HTML produzierten Inhalte hier nach WordPress portiert. Das ging erstaunlich schnell und sogar rückdatieren lies sich das. 🙂

BTW: Die Kommentarfunktion hab ich erst mal deaktiviert, nicht weil ich kein Feedback will. Ich hab Angst vor SPAM 😀 … daher kommt evtl. noch später. Solange nutzt bitte E-Mail. Ich weiß, ist ein wenig old-school 😀