Raspberry PI Lichtschalter für Shelly Geräte

Ich habe in meinem Büro/Maker Room alle Geräte mit Shelly devices gesteuert. Die Idee war, ausschließlich via Alexa die Steuerung zu gestalten. Dies hat allerdings zu diversen Wutausbrüchen und wilden Beschimpfungen geführt, da Alexa auch mal gute und schlechte Tage hat. So hat alleine das ein- und ausschalten einer Lampe zu diverse komischen Einträgen in meiner Spotify Playlist geführt. Also musste ein Schalter her. Es gibt von Shelly direkt zwar den Shelly Button *, aber den wollte ich nicht 8x mal an die Wand hängen. Unter Plus i4 Button-Projekt – Shellyparts.de findest du auch einen 4-fach Button. Da ich aber einen Raspberry nebst kleinen Bildschirm eh hier rumliegen hatte, dachte ich mir, lass doch damit was basteln. Hier nun der Walk-through, in dem ich beschreibe, wie du einen Raspberry PI Lichtschalter baust. Ich habe versucht habe alles so zu schreiben, dass du Ihn selbst als Nicht-Nerd leicht nachvollziehen kannst.

Zum Zeitaufwand: Ich habe ungefähr einen Tag benötigt um das alles zusammen zu basteln. Mit dieser Anleitung kommst du wahrscheinlich mit wenigen Stunden aus.

Vorbereitungen

Benötigte Materialien

Das 3.5 inch Display passt perfekt über den Raspberry und wird einfach auf die GPIO pins aufgesteckt.

Konfigurationsvoraussetzungen

Mindestens die Shelly Geräte sollten über eine feste IP verfügen. Entweder konfigurierst du diese in der Shelly App, oder aber du vergibst fest zugeordnete IP Adressen über deinen DHCP Server/Router/FritzBox…

Weiterhin setze ich hier voraus, dass du schon das Raspberry PI Standard 32 Bit image mit Desktop installiert hast. Wie das geht, kannst du übrigens in diesem Artikel nachlesen.

Installation der Displaytreiber

Es gibt ein eigenes Raspi-Image das auch gleich die Treiber für das Display beinhaltet. Du kannst sie aber auch selber installieren, was ich bevorzugen würde. Eine Anleitung vom Originalhersteller (die wahrscheinlich auch für andere Displays funktioniert) findest du hier. Folgend habe ich Dir das aber auch noch mal zusammengeschrieben.

Als erstes lädst du das Git repository herunter, in dem die Treiber abgelegt sind, machst die Installationsdatei ausführbar und installierst letztendlich den Treiber. Nutzt du ein anderes Display als ich hier angegeben habe, musst du einen anderen Installer (also LCDxy-show) aus dem Git-Repo ausführen.

git clone https://github.com/waveshare/LCD-show.git
cd LCD-show/
chmod +x LCD35-show
 ./LCD35-show

Der Raspi wird nun einmal neu gestartet. Nun wird ein Kalibrierungstool installiert.

sudo dpkg -i -B xinput-calibrator_0.7.5-1_armhf.deb

Die Kalibrierung kann nun im Menü unter “Preferences -> Calibrate Touchscreen” ausgeführt werden. Am Ende der Kalibrierung wird angezeigt, dass noch die Datei “/etc/X11/xorg.conf.d/99-calibration.conf” mit den Kalibrierungsdaten angelegt werden muss (Folgend mal beispielhafte Daten, die für dich richtigen werden auf deinem Bildschirm angezeigt), damit diese auch nach dem Neustart erhalten bleiben.

Section "InputClass"
        Identifier "calibration"
        MatchProduct "ADS7846 Touchscreen"
        Option "Calibration" "3925 253 302 3874"
EndSection

Du kannst das Display auch drehen, wenn du das ganze im Hochformat haben möchtest. Leider ist die eingesetzte Software “PiMenu” noch nicht so flexibel, daher habe ich mich für Querformat entschieden. Ich lasse trotzdem mal die Anleitung hier stehen. Komischerweise ist bei mir die rotate.sh im Verzeichnis LCD-Show nach der Treiberinstallation nicht mehr vorhanden gewesen. Ich habe das Verzeichnis gelöscht, neu gekloned, den Treiber neu installiert und nach einem reboot war auch die rotate.sh vorhanden. Die Rotation wird mit folgendem Befehl ausgeführt (Achtung, der raspi wird noch einmal neu gestartet):

sudo ./rotate.sh 90 

Konfiguration PiMenu

Nun geht es an die Einrichtung der Software “PiMenu” von Andreas, der eine einfaches Button Menü für einen ganz anderen Anwendungszweck gebaut hat. das Projekt hat er ausführlich auf seinem Blog beschrieben. Leider ist das Teil schon etwas älter und bisher nicht weiter aktualisiert. Daher sind einige Anpassungen am raspi notwendig (ich gehe am Ende noch mal auf den Security Aspekt ein). Auch hat Andreas einen ganz anderen Zweck verfolgt als einen Raspberry PI Lichtschalter zu bauen. Aber es liess sich einigermaßen gut dafür verwenden.

Voraussetzungen installieren

Als erstes muss python2.7 mit folgendem Befehl installiert werden:

sudo apt-get install python2.7

Auch “python-yaml” ist notwendig. Allerdings ist das package python-yaml in Raspberry OS 11 nicht mehr vorhanden. Eine Installation via PIP ist aber möglich, dafür muss aber erstmal pip2 her. Um dies zu installieren gibt es einen kleinen Workaround:

sudo curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py
sudo python2 get-pip.py

Nun kannst du pyyaml installieren.

 sudo pip install pyyaml

PiMenu verwendet das GUI Entwicklungspackage Tkinter. Diese wird wie folgt installiert:

sudo apt-get install python-tk 

Achtung: Bitte nicht mit “pip install tk” verwechseln. Dies installiert das package tensorkit.

Erster Test des Raspberry PI Lichtschalter

Als Button Menü für den Raspberry PI Lichtschalter nutze ich die Software “PiMenu”. Diese ist auch wieder in einem GitHub Repository abgelegt, das du wie folgt klonen kannst:

cd /home/YOURUSER
git clone https://github.com/splitbrain/pimenu

Jetzt sind alle Voraussetzungen installiert und es geht weiter mit einem ersten Test. Kopiere nun die beiden Daten “pimenu.sh.dist” und “pimenu.yaml.dist” nach “pimenu.sh” und “pimenu.yaml“.

Setze aber zuerst noch die Variable, die definiert, auf welchen Display die Oberfläche angezeigt. Dies geht mit folgenden Command:

export DISPLAY=:0.0

Bevor es richtig los geht, öffnest du nun noch eine zweite SSH Session, damit du dort die Anwendung auch beenden kannst. Dies kannst du dort ganz komfortabel lösen mit “kill $(pidof python2)“, womit der python2 Prozess gesucht und geschlossen wird.

Nun startest du PiMenu mit folgendem Command:

 python2 ./pimenu.py fs

Du solltest nun ein erstes 2 Button Menu sehen, wahrscheinlich mit anderen Beschriftungen und Icons, da ich schon erste Anpassungen gemacht habe.

Entwicklungsumgebung für den Raspberry PI Lichtschalter

“Entwicklungsumgebung” als Begriff ist ein bisschen zu hoch gegriffen, aber zum komfortablen testen vieler kleiner Änderungen, sollten wir ein bisschen was vorbereiten. Wir bauen also noch ein kleines Script, dass die 3 Schritte (Datei kopieren, python2 stoppen, pimenu.py starten) automatisiert remote von deinem Entwicklungssystem ausführt. So lässt es sich dann auch relativ schnell testen. Hier ein kleines Beispiel als Vorlage, dass einen Custom SSH Key verwendet um die Verbindung aufzubauen:

## If you have a password encrypted ssh-key
## As Admin: Get-Service ssh-agent | Set-Service -StartupType Automatic
## One time: ssh-add C:\Users\<USER>\.ssh\YOURKEY.key

scp -i C:\Users\<USER>\.ssh\YOURKEY.key <PATH>\pimenu.yaml USER@IP:/home/USER/pimenu/pimenu.yaml
scp -i C:\Users\<USER>\.ssh\YOURKEY.key <PATH>\pimenu.sh USER@IP:/home/USER/pimenu/pimenu.sh
ssh USER@IP -i C:\Users\<USER>\.ssh\YOURKEY.key 'kill $(pidof python2)'
ssh USER@IP -i C:\Users\<USER>\.ssh\YOURKEY.key 'export DISPLAY=:0.0;python2    /home/USER/pimenu/pimenu.py fs'

Führe das Script nun mit in einer Powershell Konsole mit einem abschließenden “&” aus, so wird der Task asynchron im Hintergrund gestartet und wartet nicht auf die Rückgabe von “pimenu.py” (die ja im Prinzip nicht stattfindet). Willst du hingegen Fehler direkt in der Konsole ausgegeben bekommen, lässt du das “&” einfach weg. Die Dateien “pimenu.yaml” und “pimenu.sh” werden dabei auf deinen Raspi kopiert und PiMenu neu gestartet.

Anpassen der Buttons

Der Rest ist quasi nur noch ein bisschen Spielerei mit der “yaml” und “sh” Datei. In der pimenu.yaml Datei deklarierst du deine Buttons und deren Eigenschaften “name“, “label“, “color” und “icon“. Ein einzelner Button könnte z.B. so aussehen:

name: "officedesk on"
label: "Büro \n Licht \n an"
color: "#00a52a"
icon: "_lightbulb_on_48"

Bei Klick auf einen der Buttons werden die Inhalte von “name” an das “pimenu.sh” Script übergeben wo du sie dann auswerten kann (mehr gleich). Das “label” ist ein frei definierbarer Anzeigename. Mit den “\n” baust du einen Zeilenumbruch ein. Die Farbe ist die Farbe im Hex-code. Die Farben kannst du z.B. hier anschauen. Das Icon verweist auf eine GIF Datei mit der Größe von 48×48 Pixel im Unterverzeichnis “ico”. Bitte beachte, das Unterverzeichnis “ico” habe ich nicht mit in das oben gezeigte Script aufgenommen, hier musst entweder das Script erweitern oder die Dateien manuell kopieren.

Bei den Icons ist noch wichtig zu wissen: Du solltest immer einen “cancel.gif” Datei vorhalten, diese wird vom python code per default verwendet, wenn die in deiner yaml Datei referenzierte GIF Datei nicht gefunden wird.

Die fertige yaml Datei, so wie ich zum Zeitpunkt dieses Artikels geschrieben und eingesetzt habe, findest du rechts. Hier sind 7 Schaltungen definiert, jeweils mit einem An- und Aus Button (PiMenu unterstützt leider keine Umschaltbuttons).

Zudem ist der 3D Drucker mit einer zusätzlichen Sicherheitsfunktion versehen. Es ist nämliches folgendes: Der raspi schaltet nach x Minuten automatisch den Bildschirmschoner an. drückst du nun auf den Bildschirm, wird der Button an der Stelle an der du gedrückt hast, auch automatisch mit gedrückt. Wenn dann versehentlich in der 22sten Stunde eines 23 Stunden Druckjobs der 3D Drucker abgeschaltet wird, ist dies natürlich mehr als ärgerlich. Daher habe ich hier die Möglichkeit verwendet, Submenüs zu gestaltet.

Bei Klick auf 3D Drucker-Off wird erst noch einmal abgefragt, ob man sich da auch ganz sicher ist.

Vielleicht sind dir auch die “x” in den Namen der Buttons aufgefallen? Dies ist ein kleiner Workaround, erkläre ich folgend.

# Menu-Setup.
#
# name and label are required for each item
# color and icon are optional
# only gifs (48x48) are supported
#
---
  - 
    name: "x officeepoxylight on"
    label: "Werkstatt \n Licht \n an"
    color: "#00a52a"
    icon: "_lightbulb_on_48"
  - 
    name: "x officeepoxylight off"
    label: "Werkstatt \n Licht \n aus"
    color: "#00a52a"
    icon: "_lightbulb_off_48"
  - 
    name: "x officeshop on"
    label: "Werkstatt \n an"
    color: "#f71a5b"
    icon: "_lightbulb_on_48"
  - 
    name: "x officeshop off"
    label: "Werkstatt \n aus"
    color: "#f71a5b"
    icon: "_lightbulb_off_48"
  -
    name: "x officedesk on"
    label: "Arbeitsplatz an"
    color: "#386087"
    icon: "_lightbulb_on_48"
  - 
    name: "x officedesk off"
    label: "Arbeitsplatz aus"
    color: "#386087"
    icon: "_lightbulb_off_48"
  - 
    name: "x officedesklight on"
    label: "Arbeitsplatz \n Licht \n an"
    color: "#fb0400"
    icon: "_lightbulb_on_48"
  - 
    name: "x officedesklight off"
    label: "Arbeitsplatz \n Licht \n aus"
    color: "#fb0400"
    icon: "_lightbulb_off_48"
  -
    name: "x officevideolight on"
    label: "Video \n Licht \n an"
    color: "#999fff"
    icon: "_lightbulb_on_48"
  -
    name: "x officevideolight off"
    label: "Video \n Licht \n aus"
    color: "#999fff"
    icon: "_lightbulb_off_48"
  - 
    name: "x office3dprinter on"
    label: "3D \n Printer \n on"
    color: "#476547"
    icon: "_lightbulb_on_48"
  - 
    name: "3dprinteroffsub"
    label: "3D \n Printer \n aus"
    color: "#476547"
    icon: "_lightbulb_off_48"
    items:
      - 
        name : "office3dprinter off"
        label: "Switch off"
        color: "#476547"
        icon : "_lightbulb_off_48"
  - 
    name: "x officelaser on"
    label: "Laser \n an"
    color: "#386087"
    icon: "_lightbulb_on_48"
  -
    name: "x officelaser off"
    label: "Laser \n off"
    color: "#386087"
    icon: "_lightbulb_off_48"

Anpassen des Shell scripts

#!/bin/bash
# Split input parameter in 2 parts
param1=$(cut -d ' ' -f 1 <<< $*)
param2=$(cut -d ' ' -f 2 <<< $*)

# Transform on to true and off to false
if [ "$param2" == "on" ]
then 
    _switch="true"
elif [ "$param2" == "off" ]
then
    _switch="false"
else
    echo "unkown switch \"$param2\" given" >> /home/dave/pimenu/pimenu.log
    exit 1;
fi

# Set IP address for the given device
case $param1 in
    officeepoxylight)
        _ip="192.168.55.213";
        ;;
    officeshop)
        _ip="192.168.55.112";
        ;;
    officedesk)
        _ip="aaa.bbb.ccc.ddd";
        exit 0;
        ;;
    officedesklight)
        _ip="192.168.55.231";
        ;;
    officevideolight)
        _ip="aaa.bbb.ccc.ddd";
        exit 0;
        ;;
    office3dprinter)
        _ip="192.168.55.151";
        ;;
    officelaser)
        _ip="aaa.bbb.ccc.ddd";
        exit 0;
        ;;
    *)
        echo "unkown device \"$param1\" given" >> /home/dave/pimenu/pimenu.log
        exit 1
        ;;
esac

# Send API request to shelly device
echo "send curl to http://$_ip/rpc/Switch.Set?id=0&on=$_switch" >> /home/dave/pimenu/pimenu.log
curl "http://$_ip/rpc/Switch.Set?id=0&on=$_switch"

Das Shell script gestaltet sich denkbar einfach, es gibt nur eine kleine Stolperfalle:

Nehmen wir als Beispiel den Button “officeepoxylight on“. Die Erwartung wäre, es gibt einen ersten Parameter ($1) mit Inhalt “officeepoxylight” der im Script abfragbar ist und einen zweiten ($2) mit dem Inhalt “on“. Leider ist dem nicht so. Es kommt nur ein Parameter an mit dem Inhalt “officeepoxylight on“. Nun gut, also wird dieser erstmal im Script zerlegt.

Guter Pfusch ist keine schlechte Arbeit

Wir nutzen hier den 2ten und 3ten Teil des Namens. Mit dem Menupunkten unterhalb von “3dprinteroffsub” wird nämlich auch “3dprinteroffsub” mit geliefert, der gesamte String der beim Shell Script ankommt ist also “3dprinteroffsub office3dprinter off“. Weil ich keine Lust mehr hatte mir was vernünftiges einfallen zu lassen, habe ich also vor alle anderen Einträge das zuvor erwähnte “x” eingetragen, so dass alle strings (sofern ich nicht weitere sub-menus baue) immer die gleiche Anzahl von Parameters aufweisen.

Anschließend wird “on” oder “off” in “true” oder “false” umgewandelt, da dies für den Aufruf der shelly API gefordert wird. Finden wir weder “on” noch “off” wird das script verlassen.

Dann wird in einer case Anweisung der Input des Gerätenamens abgefragt und eine Variable mit der richtigen IP Adresse des Shelly Gerätes definiert oder das Script wieder verlassen, wenn der Gerätenamen unbekannt ist.

Zu guter letzt wird curl aufgerufen und der request abgesendet.

Autostart

jetzt sollten wir noch schauen, dass das Menu nach dem Reboot automatisch startet. Im ersten Schritt habe ich versucht den Start von PiMenu einfach in die “.xsessionrc” einzutragen, das funktioniert allerdings weniger gut, da die Auflösung des Display noch nicht initialisiert ist und PiMenu in einer viel zu kleinen Auflösung skaliert wird. Demzufolge wird in die “.xsessionrc” Datei nur folgendes Kommando eingetragen:

/home/USER/.startpimenu &

Damit startest du beim Start von X (der GUI) ein anderes bash script (Dank des “&” Zeichen am Ende) asynchron. “Asynchron” ist hier das richtige Stichwort. Wir bauen in das Bash Script nämlich noch einen “sleep” ein. Würdest du den sleep direkt in die “.xsessionrc” eintragen oder das bash script synchron starten, würde einfach nur dein ganzes X den sleep abwarten und PiMenu kommt immer noch falsch skaliert hoch. Hier nun der Inhalt des bash scriptes “.startpimenu“:

sleep 60
python2 /home/USER/pimenu/pimenu.py fs

Vergiß nicht, das Script am Ende noch ausführbar zu machen.

chmod +x .startpimenu

Startest du jetzt deinen raspi neu, sollte automatisch dein Menu erscheinen.

Fazit

Wie du siehst, es ist gar nicht schwer, dieses kleine Raspberry PI Lichtschalter Projekt auf Basis eines Raspberry PI und Shelly umzusetzen. Im Prinzip funktioniert dies auch mit anderen Geräten die python unterstützen und auch nicht nur mit Shelly Devices.

Es fehlt nun noch eine sinnvolle Befestigung an der Wand, entsprechende Bilder werde ich bei Zeiten mal nachliefern.

Ein paar finale Hinweise will ich noch loswerden:

  • Du solltest Dir bewusst sein, dass du eine veraltete und nicht mehr gewartet python2.x Version einsetzt. Das ist definitiv ein Sicherheitsrisiko. Möchtest du das trotzdem tun, empfehle ich Dir, die Shelly Geräte und den raspi in ein eigenen separiertes VLAN zu packen und dieses zu zu machen (mind. kein Internet).
  • Zudem kann es sein, dass die ganze Geschichte (nach einem Update des OS) irgendwann einfach nicht mehr funktioniert.
  • Ich habe hier der Einfachheit halber nicht beschrieben, wie die Verschlüsselung und Authentifizierung auf den Shelly Geräten funktioniert. Dies solltest du aber dringend aktivieren. Wie das geht, findest du in der Shelly Dokumentation beschrieben.
  • Die PiMenu Software ist nicht perfekt. Das ist kein Vorwurf, der Entwickler hat dies schliesslich als Teil eines anderes Projektes geschrieben und nicht versucht einen Lichtschalter zu bauen. Daher gibt es so einiges Dinge die mir noch fehlen, im Wesentlichen sind dies:
    • Feedback bei Druck/ Klick
    • Gleichmäßige Verteilung der Buttons
    • Hochkantformat
    • Umschaltbutton
    • Beim ersten Touch auf das Display sollte beim Abschalten des Screensavers kein Button gedrückt werden

Vielleicht werde ich mich irgendwann mal hinsetzen und eine eigene Version implementieren. Oder Andreas macht doch mal irgednwann ein Update ;-). Wir werden sehen. Auf jeden Fall funktioniert das jetzt schon mal super, ich habe endlich einen Lichtschalter und den Amazon DEVs klingeln nicht mehr die Ohren wegen meines ständigen Geschimpfes auf die Alexa ;-).

Schreibe einen Kommentar

WordPress Cookie Hinweis von Real Cookie Banner