Wie kann ich schnell erkennen, ob in Raum frei ist, oder wann er belegt ist? Wie kann ich aus ical btw CalDav Kalendern, die sowieso gepflegt werden, Termine auslesen? Wie kann ich das leicht bedienbar in ein kleines Display einbinden? Nodered, MQTT und OpenHASP sind Teile der Antwort!
Oft komme ich in mein Kirchgebäude, was mittlerweile acht nutzbare Räume hat und frage mich, wo gerade etwas frei ist, um zu arbeiten oder ein Gespräch zu führen. Am besten wäre es, wenn im Eingangsbreich ein Dosplay hinge, mit dem ich sofort einen Überblick habe.

Das ist nicht nur für Pfarrpersonen interessant, sondern auch für Gruppenleitende, die vor der Gruppenstunde ankommen und wissen müssen, wie sehr sie sich mit Aktionen oder Spielen ausbreiten können. Ein schneller Blick und alles ist klar… Fast! Denn diese Übersicht zeigt nur den Zustand zum jetzogen Zeitpunkt an. Also was liegt näher, als noch ein paar mehr Informationen auf Anfrage zu liefern. Dazu sind die Raumnamen direkt als Buttons ausgeführt, die auf einem Touchscreen leicht zu bedienen sind.
Auf der jeweiligen Raumseite sind dann alle weiteren relevanten Informationen. Farblich eingefärbter Raumname, die nächsten zwei Termine inklusive Datum, Angangs- und Endzeit und als kleines Schmanker die aktuelle Temperatur (denn auch die kann sehr entscheidend sein, wo man mit welcher Gruppe hingeht). Mit einem Tipp auf das Häuschen gelangt man wieder zur Übersicht. Natürlich könnte man das noch weiter ausbauen, allerdings habe ich in diesem Fall nur 480×480 Pixel auf dem Display zur Verfügung, deshalb muss ich etwas sparsam mit dem Platz sein.

Warum ich keinen größeren Monitor mit einem Raspberry Pi (oder so) genommen habe und direkt einen Kalender abgebildet habe? Ganz einfach: Der fehlende Platz im Eingangsbereich. Für unser Küster-Team habe ich tatsächlich genau so eine Lösung gebaut. Wenn ihr Interesse habt, kann ich auch mal darüber etwas schreiben. Allerdings ist so ein Projekt vergleichsweise simpel.
Jetzt aber zum Projekt: Ich habe ein 4 Zoll/480x480px-Touchscreen mit eingebautem ESP32-Controller verwendet. Das kann man für relativ kleines Geld etwa bei Aliexpress oder einem anderen Onlinehandel erstehen. Ich habe im Angebot dafür etwa 17€ bezahlt. Wichtig bei der Auswahl waren für mich zwei Dinge: Es sollte erstens ein kapazitiven Touch haben (das ist eben das von den Smartphones gewohnte und verhindert in der Regel wildes Draufrumgestocher, oder -gehämmer, was ich leider schon mal bei einem resistiven Screen erlebt habe) und es muss kompatibel mit der OpenHASP-Software sein. Damit erspart man sich den tiefen Einstieg ins Microcontroller-Programmieren (ok, das habe ich zumindest oberflächlich hinter mir). Vor allem aber spart man sich den mitunter sehr frustrierenden Ausflug in die Welt der Grafik-Bibliothek LVGL und die Verzweiflung bei spärlich dokumentierten Displays die richtige Konfiguration von Touch und Anzeige herauszufinden. Ja, ich habe es ehrlich versucht und bin trotz ChatGPT, Gemini und unzähligen Ausflügen zu Reddit und Stackoverflow nicht zu einem guten Ergebnis gekommen. Vielleicht hatte ich einfach Pech oder habe zu viele Anläufe gestartet. Die teils nicht rückwärtskompatiblen Versionen machen es zusätzlich schwer… Aber nicht rumheulen, sondern Lösungen suchen!
Die Hardware und ihre Konfiguration
Für mich lautete die Lösung wie erwähnt OpenHASP. Dank einfacher Auszeichnungssprache mittels eines json-Dialekts und Weboberfläche für die Konfiguration und nicht zuletzt durch die Installation über den Webbrowser ist das keine große Sache. Ich habe ein wenig herumprobiert und wurde in der guten Dokumentation schnell fündig.
Der erste Weg führt in die Hardware-Datenbank. Ich habe ein neu unterstütztes Guition ESP32-S3 JC8048W550-kompatibles Display, deshalb musste ich den nightly-Web-Installer, nutzen. Wenn ihr ein anderes Display habt, dann nehmt lieber eine stabile Version. Die Installation per Webinstaller geht übrigens nur in Browsern, die direkt mit COM-Ports sprechen können, also bspw. Chrome oder Edge.
Wenn ihr der Anleitung gefolgt seid und das Wlan eingerichtet habt, könnt ihr das „plate“, so heißt ein Display standardmäßig im Netz, konfigurieren. MQTT-Server eintragen, Ausrichtung eures Displays und vieles mehr. Danach geht es dann richtig los: im File-Editor. Hier findet ihr die Konfigurationsdateien im jsonl-Format, die ihr auch direkt hier bearbeiten könnt. Spannend ist für uns jetzt erstmal die pages.jsonl. Sie sagt den Display, was es anzeigen und wie es auf Eingaben reagieren soll.
{"page":1,"id":8,"obj":"label","x":300,"y":250,"h":40,"w":100,"text":"frei","text_color":"#00FF00"}
Das Textbeispiel zeigt etwa auf der Seite 1 ein Beschriftungsobjekt ab der Position 300×250 mit der zulässigen Höhe und Breite von 40×100 Pixeln mit den Buchstaben „frei“ in grüner Farbe an. Für den Einstieg gibt es aber am Ende auch dem Code, den ich verwende als Beispiel.
Wenn ihr das Display schon mit eurem MQTT-Server verbunden habt, könnt ihr dann einzelne Elemente der zusammengestellten Oberfläche verändern. etwa aus dem „frei“ ein „besetzt“ machen, oder die Farbe von grün nach rot ändern. dazu sind dann nur MQTT-Payloads an solche Topics nötig:
hasp/plate1/command/pSeitennummerbObjektnummer.text
hasp/plate1/command/pSeitennummerbObjektnummer.text_color
Zu beachten ist, dass die Seite/Page 0 (Null) immer sichtbar ist. Damit kann dann zum Beispiel ein Navigationsbutton oder wie bei mir Uhrzeit und Datum angezeigt werden. Bei der Bearbeitung der pages.jsonl solltet ihr darauf achten, keine Tippfehler zu machen. Schon ein fehlendes Anführungszeichen kann dazu führen, dass alles nach diesem Fehler nicht mehr angezeigt wird, oder es komische Seiteneffekte gibt.
Für alles Weitere schaut euch die Doku oder meine Beispiel-pages.jsonl an.
Die Software und das Hirn dahinter
Zum Füttern meines Displays verwende ich wie schon in den letzten Beispielen NodeRed. Dafür gibt es ein (zwar leider schon länger nicht mehr aktualisiertes, aber zuverlässiges) Addon für CalDav: node-red-contrib-ical-events.


Dieses triggert einen Flow, wenn ein Kalendereintrag beginnt und endet (der trigger-Node) und kann mittels upcoming-Node eine von euch festgelegte Zeit in die Zukunft schauen und dafür Kalenderdaten holen. Diese beiden Nodes verwende ich für die beiden Aufgaben, die für das Display nötig sind. Meine Nextcloud spuckt die Caldav-Termine über den upcoming-Node so aus, dass es Objekte mit Zahlen versieht und da rein dann strukturiert die Daten packt. Der nächte Termin hat die Zahl 0, der nachfolgende die Zahl 1 usw. Um an den Namen des ersten Termins zu kommen, ändere also den payload mittel change-Node zu payload.0.summary. Diesen schicke ich dann per MQTT weiter an mein Display (im Bild auf das plate1 zu Objekt 12 auf Seite 2).
Damit Datum und Uhrzeit schön aussehen und getrennt bearbeitet werden können müssen wir etwas tricksen. Da diese Angaben aber immer gleich ausgegeben werden ist das recht einfach.
Exkurs Plugin-Konfiguration: Die Konfiguration der Nodes und vor allem des Konfigurationsnodes des Addons sind unkompliziert: https://eure Nextcloud url .de/remote.php/dav/calendars/ ist die CalDav url (zumindest falls ihr Nextcloud oder Owncloud nutzt), als Kalendertyp wählt ihr CalDAV aus und tragt eure Zugangsdaten ein (gerne mit einem User, den ihr extra dafür anlegt). Sowohl im trigger, wie auch im upcoming-Node müsst ihr nun auswählen, dass ihr events als Eventtyp wollt und welcher Kalender abgerufen werden soll. Beispiel: Ihr habt einen extra User angelegt und die Kalender werden von einem Admin-Konto (Admin2) verwaltet und an diesen User geteilt. Ihr wollt den Kaleder „Kirchraum“ abrufen. Dann heißt euer Kalender: „Kirchraum (Admin2)“. Wenn ihr euch unsicher seid, dann hängt dem upcoming-Node einen debug-Node an ohne einen Kalender einzutragen und er spuckt euch dann mit dem nächsten Abruf das aus was ihr braucht. Die nächsten Felder sind einigermaßen selbsterklärend. Wichtig sind allerdings die Einträge bei der Zeitzone (Europe/Berlin) und dem Dateformat. Dieses Format sieht bei mir so aus und wenn ihr mit meinem Beispiel folgt, dann sollte das so aussehen { "timeStyle": "short", "dateStyle": "short" }
Um das Datum zu bekommen, ändern wir unseren payload nach obigm Beispiel in payload.0.date und nehmen davon mit einem weiteres change-Node via substring-Funktion in Jasonata (das ist das J mit dem Doppelpunkt) die ersten acht Stellen: $substring(payload, 0, 8) Damit nehmen wir die ersten 8 Zeichen, angefangen an der 0. Stelle (also ganz von vorne). Falls dir ein Datum ohne Jahreszahl lieber ist, ersetze die 8 durch eine 6.
Anfangszeit des jeweiligen Termins sind $substring(payload, 10, 5) und Endzeit sind $substring(payload, 16, 5). Das kann man natürlich für jeden weiteren Termin genau so machen, es ändert sich nur die Nummer des Termins im ersten Change-Node. Und so sieht das ganze jetzt bei mir in Nodered aus:

Jetzt müssen wir nur noch zusehen, dass wir auch anzeigen, welcher Raum gerade frei und welcher besetzt ist. Dazu benutzen wir den trigger-node. Hier gibt es zwei Ausgangspunkte am Node, der obere für den Beginn, der untere für das Ende des Termins. Jetzt ändern wir wieder den Payload entsprechend unseren Vorlieben:

Statt rot und grün müssen hier natürlich die Hex-codierten Farben eingetragen werden: #FF000 für rot und #00FF00 für grün. Ich habe außerdem eine Verzögerung von 30 Sekonden für die „Besetzt“- und „Rot“-Schaltung eingebaut. Das soll verhindern, dass durch einen dummen Zufall beide Befehle gleichzeitig kommen, wenn ein zweiter Termin direkt an den ersten anschließt.
Sowohl die pages.jsonl als auch die kompletten Flows für alle sieben Räume gibt in einem github-Projekt.
Weitere Verbesserungen
Zum Schluss sollten wir noch dafür sorgen, dass wir weder unnötig Strom verbrauchen, noch dass uns Pixel auf dem Display „einbrennen“. Variante 1: Bewegungsmelder und schaltbare Steckdose. Variante 2: Hintergrundbeleuchtung ausschalten und Antiburn-Funktion (o.ä.) von OpenHASP nutzen und per Touch wieder einschalten.
Ich habe mich für eine Mischung entschieden. Da es sowieso ein Zigbee-Netzwerk im Gebäude gibt, wird ein Bewegungsmelder für das Aufwachen sorgen, das Einschlafen wird aber softwareseitig gelöst. Das hat im Gegensatz zur schaltbaren Steckdose den Vorteil, dass die Bootphase ausgeklammert wird – natürlich aber auch den Nachteil, das immer noch ein wenig Strom fließt (ob der Verbrauch der Steckdose jedoch geringer ist, habe ich nicht nachgemessen).
Konkret gucke ich, ob mein Bewegungsmelder (hier ein IKEA Vallahorn via Zigbee2MQTT) angibt, dass Bewegung stattfindet. Ich fange mit dem Ausschalten an, weil dort die eigentliche Magie passiert: Wenn 5 Minuten lang keine Bewegung stattgefunden hat, dann schaltet der Flow die Hintergrundbeleuchtung (backlight) aus und erstellt eine schwarze Fläche auf Seite 0, die den gesamten Bildschirm verdeckt (wenn ihr das übernehmt, achtet auf die richtige Größe). Damit ist sowohl die Gefahr des „Einbrennens“ von einzelnen Pixeln als auch der Energieverbrauch deutlich vermindert. Wenn dann wieder Bewegung stattfindet, wird die Hintergrundbeleuchtung wieder eingeschaltet und die Fläche wieder gelöscht. (Warum in der Vorlage das verstecken und das löschen steht, weiß ich nicht, aber es funktioniert auf jeden Fall so.)

Der switch-Node nach dem Zigbee-Eingang sollte von euch entsprechend dem Endgerät angepasst werden, weil die Bewegungsmelder durchaus unterschiedliche Dinge ausgeben. Je nach Endgerät ist z.B. auch die Zeit bis zur Änderung des Bewegungsstatus einstellbar, so dass ihr euch die Verzögerung per Node sparen könnt.
Jetzt geht es für mich ans Ausprobieren in freier Wildbahn und für euch ans Nachbauen und Rückmeldungen geben. Ich würde mich auf jeden Fall darüber und Verbesserungsvorschläge freuen.
PS: Bitte kontrolliert, ob ihr überall das gleiche Display in eurem übernommenen Code ansprecht, ich sehe gerade in den Screenshots mal plate1 und mal plate2…


Schreibe einen Kommentar
Du musst angemeldet sein, um einen Kommentar abzugeben.