Wir besitzen seit Anfang 2024 eine Photovoltaik-Anlage mit Energiespeicher. Seit diese in Bebtrieb gegangen ist, schauen wir ständig in die Hersteller-App auf dem Smartphone (bzw. dessen Webseiten-Äquivalent) um herauszufinden, ob wir Überschuss produzieren und es eigentlich schlau wäre, zeitlich unabhängige Verbraucher wie Waschmaschine, Spülmaschine, Wallbox etc. anzuwerfen. Dabei sind es im wesentlichen zwei Parameter, die uns interessieren:
Bei der ins Netz abgegebenen Leistung ist der Momentanwert zwar ein guter Indikator, aber eigentlich will man ja wissen, wie der Verlauf in den nächsten 1-2 Stunden aussehen wird (also insbesondere bei ständig wechselnder Bewölkung). Da ein Blick in die Zukunft schwierig ist, bedienen wir uns an der jüngeren Vergangenheit und gehen davon aus, dass es ungefähr so weiter gehen wird. An sich funktioniert das ganz gut, aber: die in der Hersteller-Cloud gespeicherte Historie hinkt oft mehrere Stunden hinterher.
In einem ersten Schritt habe ich mir eine lokale Datenbank aufgesetzt, in die ich die Werte der Anlage
füttere (zumindest die Werte, an die ich komme; dazu später mehr). Ein paar Grafana-Dashboards
beantworten nun die Frage ziemlich gut, erfordern aber immer noch mit einem Smartphone oder Computer die
Webseite zu öffnen und die Informationen mental zu verarbeiten. Mein Kumpel Markus würde das eine 2+
nennen, aber mir hat das noch nicht gereicht; ich wollte eine kleine Box haben, die ich mir ins Wohnzimmer
stellen kann und die mir auf einen Blick sagt, was Sache ist: ein energy-display
.
Die für mich wichtigste Eigenschaft dieser Box war eine schnell erfassbare Anzeige. Ich möchte aus fünf Metern Entfernung drauf schauen können und innerhalb einer Sekunde wissen: sind wir glücklich? Nachdem ich kurze Zeit nach Displays für Arduino und Raspberry Pi recherchiert hatte, habe ich die Gedanken an TFT oder OLED verworfen. Auch einen ausrangierten Bildschirm rund um die Uhr laufen zu lassen erschien mir ungeeignet. Stattdessen kam ich bei dem Thema RGB-LEDs heraus, insbesondere bei den Neopixel-kompatiblen Display-Modulen die ich bei roboter-bausatz.de gefunden habe. Ich habe mich für den 12Bit RGB LED Ring WS2812 und das 64Bit RGB LED Panel WS2812 entschieden, die derzeit beide jeweils nur 2-3 Euro kosten und damit konkurrenzlos günstig sind.
Der LED-Ring besitzt 12 Segmente und einen Außendurchmesser von ca. 50 Millimetern. Diesen benutze ich zur Anzeige des Batteriefüllstands, und zwar desjenigen Anteils, den man auch real nutzen kann: unter 10% gibt die Batterie nämlich nichts mehr her. Das macht also 90% / 12 = 7,5% pro Segment. Um die Unschärfe zu reduzieren nutze ich ein Ampel-Farbschema: rot = unteres Drittel, gelb = mittleres Drittel, grün = oberes Drittel. Damit besitzt die Anzeige eine Auflösung von 2,5%.
Die Matrix ist quadratisch mit einer Kantenlänge von 65 Millimetern und beherbergt 8 x 8 LEDs. Diese benutze ich zur Visualisierung der ans Netz abgegebenen Leistung. Jedes Segment stellt ein Kilowatt dar, mit der gleichen Drittel-Aufteilung wie beim Segmentring, wodurch sich eine Auflösung von 333 Watt ergibt. Pro Spalte bilde ich einen gleitenden Mittelwert über 5 Minuten der Einspeisehistorie, wobei die rechteste Spalte den Momentanwert abbildet (also 7 x 5 = 35 Minuten Historie + aktueller Wert).
Ich war anfangs unentschlossen, ob ich einen Raspberry Pi Zero oder einen Raspberry Pi Pico einsetzen möchte. Mit letzterem hatte ich noch gar keine Erfahrung und wollte ihn endlich mal in einem Projekt verwenden, aber nachdem ich mir die APIs der beteiligten Komponenten angesehen und ein Gefühl für die Komplexität gewonnen hatte, habe ich (zumindest für den Prototyp) dem Pi Zero den Zuschlag erteilt. Um genau zu sein dem Raspberry Pi Zero 2 W. Auf der Software-Seite hat mir der NeoPixel-Treiber aus der CircuitPython-Bibliothek von Adafruit die meiste Arbeit abgenommen. Damit stellt sich das NeoPixel-Modul wie ein Array aus Pixeln dar, die jweils durch ein Tupel aus Rot, Grün und Blau (Werte zwischen 0 und 255) beschrieben werden:
import board import neopixel pixels = neopixel.NeoPixel(board.D18, 1) pixels[0] = (255, 0, 255)
Hinter den Kulissen passiert da ziemlich viel. Die 1
im Aufruf des
NeoPixel
-Konstruktors teilt der Bibliothek mit, wie viele Pixel in der Kette vorhanden sind.
NeoPixel (bzw. WS2812-LEDs) funktionieren im Prinzip ähnlich wie Shiftregister: jedes Element besitzt einen
DIN
-Pin (Data In) und einen DOUT
-Pin (Data Out); teilt man einem Pixel einen neuen
Wert mit, so gibt er seinen bisherigen Wert an seinen Nachfolger weiter. Im Kommunikationsprotokoll besitzt ein
Bit eine zeitliche Ausdehnung von 1,25µs (entspricht einer Datenrate von 800 kBit/s), wobei das Timing der
einzelnen Flanken auf 150ns genau eingehalten werden muss. Das schafft ein Multitasiking-Betriebssystem wie
Linux natürlich nicht ohne Hardwareunterstützung. Die NeoPixel-Bibliothek (bzw.
CircuitPython/Adafruit-Blinka) verwendet dafür eine PWM-Einheit mit DMA (Puls-Width Modulation, Direct
Memory Access). Das ist auch die Erklärung dafür, warum nicht jeder beliebige GPIO-Pin benutzt werden
kann, sondern nur GPIO10
, GPIO12
, GPIO18
und GPIO21
. Ich
habe im ersten Anlauf GPIO18
benutzt, weil dieser von der Dokumentation als Standard gepriesen
wurde; wir kommen gleich noch dazu, warum GPIO10
die bessere Wahl ist.
Auf Modulebene gibt es ebenfalls das Konzept von Data In und Data Out, sodass mehrere Module aneinander gereiht
werden können. Für Ring + Matrix ergibt sich dabei ein Array aus 76 Pixeln. Diese Struktur wird bei
mir allerdings durch eine Abstraktion in der Software verborgen, was insbesondere bei der Matrix Sinn ergibt,
weil diese auf Grund der Einbaurichtung von rechts unten nach links oben gezählt hatte; nicht direkt
intuitiv. Der Vollständigkeit halber sei erwähnt, dass die NeoPixel-Bibliothek einen internen Puffer
nutzt und diesen per Default bei jeder Aktualisierung mit den NeoPixeln synchronisiert (d.h. Änderungen
schlagen sofort durch). Es gibt allerdings auch die Option auto_write=False
, bei der erst ein
manueller Aufruf von show()
zur Aktualisierung führt. Ich hatte bei meinen Experimenten keine
Probleme mit dem automatischen Schreiben, also habe ich es dabei belassen.
Wie erwähnt sehen der LED-Ring und die LED-Matrix aus Software-Sicht wie ein Array aus 76 Pixeln aus. In
der praktischen Ansteuerung will man aber nicht so etwas wie pixels[33] = (255, 255, 0)
schreiben.
Dort möchte man eher mit einem Kreis zu tun haben, den man bis auf 8 Elemente auffüllt, oder eine
Matrix, deren vierte Spalte man auf drei grüne und eine rote LED setzen möchte. Also muss irgendeine
Form der Abstraktion her, die aus der linearen Pixelkette so etwas wie Objekte schafft. Ein weiteres
Ärgernis hatte sich aus der Übernahme der Code-Beispiele ergeben: der defaultmäßig
verwendete Pin board.D18
kann nur von Programmen verwendet werden, die mit root-Rechten laufen.
Erst viel später habe ich den Abschnitt
Setup
for sudo-less usage on Raspberry Pi boards in der Dokumentation gesehen, bei der Pin
board.D10
benutzt wird, zusammen mit einer manuellen Anpassung von /boot/config.txt
um
SPI sowie das Hardware-UART zu aktivieren (dtparam=spi=on
und enable_uart=1
).
In der Annahme, dass eine Ansteuerung nur für ein Programm mit root-Rechten möglich ist, habe ich eine
Komponente gebaut, die ich led-server
genannt habe. Diese wird als root gestartet und lauscht auf
einem TCP-Port, über den sie HTTP-Requests entgegen nimmt. Ich habe das ganze mit
FastAPI realisiert, was ich mir ohnehin schon seit einiger Zeit mal
anschauen wollte. Auch unabhängig von der root-Problematik, die sich nun scheinbar doch einfacher
lösen lässt (noch hab ich es nicht ausprobiert...), hat sich die Auslagerung der Hardware-Ansteuerung
in einen eigenen Dienst als praktisch erwiesen.
led-server
in einem Loopback-Modus gebaut werden, der nur auf die
Konsole schreibt was er tun würde, anstatt tatsächlich Hardware anzusteuern. Zugegeben: das
hätte wahrscheinlich jede Form der Abstraktion hergegeben.
Unterm Strich betrachtet hätte ich es wahrscheinlich nicht so gemacht, wenn ich den Abschnitt über den sudo-losen Betrieb früher gesehen hätte. Vielleicht baue ich es noch mal zurück, vielleicht auch nicht. Was diese Form der Entkopplung jedenfalls erlaubt: die Hauptanwendung, welche die eigentliche Logik und Datenbank-Abfragerei beinhaltet, kann als Docker-Container laufen und somit alle Abhängigkeiten für sich behalten; ersten Versuchen zufolge zickt Adafruit-Blinka selbst nämlich innerhalb von Docker herum (evtl. #342). Aber auch das ist kein Killerargument, mit den Virtual Environments von Python ist es eigentlich nicht mehr so schlimm, Abhängigkeiten im Hauptsystem zu installieren; nicht dass es auf einem Raspberry Pi, der einer Aufgabe exklusiv gewidmet ist, überhaupt ein Problem wäre...
In der eigentlichen Anwendung (display-updater
) habe ich eine Python-Klasse ColorBar
gebaut, die im Konstruktor-Aufruf die Zahl der Segmente sowie einen Maximalwert entgegennimmt. Im späteren
Verlauf kann dann ein Wert gesetzt werden, woraufhin die Klasse austüftelt, wie viele Segmente voll sind
und welche Farbe das angeknapste Segment haben soll. Anwendungsbeispiel:
bar = ColorBar(number_of_circle_segments, max_value=100) bar.set_value(current_soc) display.set_circle(bar.pixels)
Logisch betrachtet ist für mich der Kreis auch nur eine Balkenanzeige, deren LEDs halt "zufällig" kreisförmig angeordnet sind. (Sieht man auch gut auf dem Screenshot, bei der Anzeige des Pixelpuffers habe ich es bei einem Balken belassen.)
Unsere Anlage besteht größtenteils aus SMA-Komponenten, wobei der Energiespeicher von BYD stammt. Die
SMA-Komponenten könnte man via Modbus TCP abfragen, aber dieser Zugang ist per Default deaktiviert
und bietet auch ein gewisses Potenzial die Anlage kaputtzufrickeln (schreibender Zugriff auf Register).
Stattdessen nutze ich das Multicast-Datagramm (Speedwire), das der Home Manager freiwillig und
ungefragt ins Heimnetzwerk pumpt. Die Dokumentationslage bei Speedwire ist etwas dürftig, aber unter der
Bezeichnung "SMA ENERGY METER Meter Protocol" (Dateiname EMETER-Protokoll-TI-en-10.pdf
) findet man
ein Dokument, das den Aufbau der Datagramme und die Bedeutung der einzelnen Datenkanäle beschreibt. Der
Energiespeicher hingegen hat einen offenen TCP-Port (8080) auf dem irgendein seltsames Binärprotokoll
gesprochen wird. Hier hat mit das Projekt
solar-manager von Robert Diers auf die
Sprünge geholfen, wobei es im Netz diverse Implementierungen dieses "BYD-Protokolls" gibt.
Das Gesamt-Setup ist eigentlich einen eigenen Artikel wert, aber für das bessere Verständnis hier eine Zusammenfassung:
Das energy-display
sieht von der ganzen Datenverarbeitung nur einen kleinen Ausschnitt:
Theoretisch können alle Daten direkt von der InfluxDB abgefragt werden, aber gerade beim Momentanwert
für die rechteste Matrix-Spalte, die alle 5 Sekunden aktualisiert wird, erschien mir das etwas viel
Last zu erzeugen. Ich habe im display-updater
eine Klasse DbSource
gebaut, die
mehrere Instanzen vom Typ DbConnector
kennt. Wenn ein Wert abgefragt wird (z.B. via
get_current_soc
), dann klappert DbSource
alle DbConnector
-Instanzen ab,
bis eine mit einem Ergebnis antwortet. Die Reihenfolge ist so gewählt, dass zuerst der MQTT-Broker und dann
erst die Datenbank gefragt wird. Die Werte für die momentane Einspeisung und für den Batteriestand
kommen in der Regel vom MQTT-Broker, die Einspeisehistorie kommt immer von der Datenbank (wird aber auch nur ein
mal pro Minute aktualisiert). "In der Regel" deshalb, weil der MQTT-Broker direkt nach dem Aufstarten noch
keinen Batteriestand kennt, weil dieser nur alle 60 Sekunden bekanntgegeben wird; in dem Fall schlägt die
Anfrage bei der Datenbank auf. Kann keine Quelle die gewünschte Auskunft geben, wird ein individuell
vorgegebener Default-Wert benutzt.
Ich hatte ein paar Wochen zuvor meinen ersten 3D-Drucker gekauft (einen
FlashForge
Adventurer 3) und mir den Bau eines Gehäuses für das energy-display
als erstes
richtiges Projekt vorgenommen. Das war extrem lehrreich und hat insgesamt bestimmt 60 Stunden in Anspruch
genommen. Ich habe dafür OpenSCAD benutzt, wobei ich als Editor
VS Code mit der Extension
OpenSCAD
Language Support verwende. Eine Kombination die ich sehr empfehlen kann, insbesondere weil sich die
OpenSCAD-Dateien hervorragend mit Git versionieren lassen und man genau sehen kann, wo sich zwischen zwei
Versionsständen etwas getan hat.
Die Vorderseite ("Screen") wollte ich im ersten Anlauf als Lochplatte drucken, was allerdings daran scheiterte, dass die vom Drucker ausgelegten Ringe mit 4 Millimeter Durchmesser weder wirklich kreisförmig wurden, noch zuverlässig auf dem Druckbett haften wollten. Stattdessen habe ich dann eine durchgängige Fläche gedruckt und darauf aufgebaut (man nennt das offenbar Sacklöcher), was im Gesamtergebnis noch viel besser aussieht als ich erwartet habe: eine gleichförmige, glatte Fläche, die von hinten punktuell durchleuchtet wird. Die LED-Module selbst werden mit Plastiknasen festgeklemmt und können so exakt zu den Löchern ausgerichtet werden.
Beim Gehäuseunterteil ("Base") musste ich vorausplanen, welche Komponenten untergebracht werden müssen und wie sie sich fixieren lassen. Ich habe mich für ein Steckkartensystem entschieden, bei dem jeder Einschub eine Karte mit 80 Millimeter Länge aufnehmen kann. Davon passen drei Stück hinein, wobei bis dahin nur zwei verplant waren: der Raspberry Pi selbst und eine Hilfs-Leiterplatte mit einem Pegelwandler (der Pi spricht 3,3 Volt, die WS2812-LEDs erwarten 5 Volt). Das gibt noch etwas Luft für künftige Erweiterungen und nutzt den Platz gut aus (das Gehäuseunterteil kann nicht beliebig kurz sein, weil das Gerät sonst zu leicht kippt; wobei der Pi ganz gut beschwert). Ich habe noch drüber nachgedacht, den Hohlstecker für die Spannungsversorgung ebenfalls als eigenes Modul einzusetzen, bin dann aber bei dem klassischen Loch in der Rückwand geblieben, weil es mir sonst zu wackelig und kompliziert geworden wäre.
Dem Gehäuseoberteil ("Cover") habe ich Lüftungsschlitze spendiert, weil ich keine Vorstellung hatte,
wie warm es dem Pi werden könnte. Ebenfalls aus Gründen der Abwärme habe ich das Gehäuse
hinter den LED-Panels offen gelassen, weil ich hier die größte Temperaturentwicklung erwartet habe.
Mit diesem Design meldet vcgencmd measure_temp
eine Temperatur von ca. 48°C (bei 22°C
Umgebungstemperatur).
Deutlich länger getüftelt habe ich an der Art der Verbindung von Oberteil, Unterteil und Screen. Das Oberteil habe ich von Beginn an mit einem Schienensystem auf das Unterteil aufgeschoben, aber den Screen hatte ich im ersten Entwurf mit drei Schrauben befestigen wollen. Das sah zunächst gut aus und hatte in einem kleinen Testdruck auch prima funktioniert, aber beim Zusammenbau des Prototypen haben zum einen die Schrauben ihre Gegenstücke gesprengt, zum anderen hat sich die Handhabung als unglaublich fummelig erwiesen, weshalb ich nun auch diese Verbindung durch ein Stecksystem ersetzt habe. Das hält insgesamt phänomenal gut und man kommt beim Zusammenbau bzw. Zerlegen gänzlich ohne Werkzeug aus.
Die Riefen zwischen den einzelnen Gehäuseteile habe ich absichtlich eingefügt, weil ich mal gehört habe, "dass man das so macht". Ich meine das war noch aus der Ben Heck Show und der Grund war der, dass man zwangsläufig keine sauberen Kanten hinbekommen kann (Materialverzug, Toleranz) und es "wie gewollt und nicht gekonnt" aussieht, wenn man es doch versucht. Wenn man stattdessen aber eine absichtliche Lücke von z.B. einem Millimeter lässt, dann fällt es dem Auge nicht weiter auf, wenn das mal 0,9 und mal 1,1 Millimeter sind. Bei den Übergängen von grün nach weiß gefällt mir das tatsächlich ganz gut, aber von den Stellen, wo weiß an weiß stößt, bin ich nicht mehr voll überzeugt. Es hilft auf jeden Fall dabei zu identifizieren, welche Teile zusammenhängen und wo man ziehen muss, um das Gehäuse zu öffnen.
Was mich als 3D-Druck-Neuling verwundert hat, war die lange Druckzeit. Jedes der drei Teile braucht circa 3-4 Stunden, die Basis etwas länger als der Deckel.
Bereits beim Zusammenbau des Geräts konnte ich viele Erkentnisse gewinnen, die auf meine bis dahin kaum vorhandenen Erfahrungen mit PLA (das Material, das ich für den 3D-Druck verwende) zurückzuführen sind und sich zusammenfassen lassen mit: PLA ist verdammt spröde. Ich hatte sowohl die Schraubverbindungen als auch die Leiterplatten-Halter und Plastiknasen vorher getestet, aber immer auf einem recht dünnen Untergrund (der offenbar flexibler war als das echte Werkstück) und mit dem rot-transparenten Demo-Filament, das FlashForge mitgeliefert hatte, und welches zumindest meinem Gefühl nach weniger spröde ist, als die nicht-transparenten Sorten. Am Ende ist trotz intensiven Einsatzes meines Schlüsselfeilen-Sets einiges abgebrochen und teilweise mit Tesafilm stabilisiert worden (ich wollte es nach der Inbetriebnahme durch Heißleim ersetzen, aber noch hält es...). Diese Erkentnisse sind in Anpassungen des 3D-Modells und letztendlich in die zweite Iteration des Gehäuses eingeflossen.
Die Verdrahtung habe ich fliegend und überwiegend mit fest eingelöteten Kabeln realisiert. Nur die Verbindung mit dem Raspberry Pi Zero läuft über Steckverbinder (landläufig als Dupont-Stecker bezeichnet) um dieses vergleichsweise teure Bauteil ggf. später leichter plündern und anderweitig verwenden zu können. Dabei ist mir wieder einmal aufgefallen, wie ätzend es ist, Kabel direkt zu verlöten, wenn das andere Teil bereits ungünstig eingebaut ist (hier: die Hohlsteckerbuchse in der Ecke). Das werde ich beim nächsten mal auch mit Steckverbindern machen, vor allem, weil bei diesem Buchsen-Typ von Innen geschraubt wird, d.h. die Kabel müssen durch das Gehäuseloch gefädelt werden, was natürlich nicht klappt, wenn am anderen Ende bereits was hängt.
Warum habe ich die "Stromverkabelung" überhaupt mit Litze gemacht und nicht gleich Steckboard-Verbindungsleitungen wie bei den Signalleitungen benutzt? Weil die Leitungen sich nicht nur billig angefühlt haben, sondern innendrin noch weniger Kupfer enthielten als ohnehin erwartet. Ich bin nach dem Verzinnen auf einen Durchmesser von ca. 0,25 mm gekommen, das sind 0,05 mm2 Querschnitt und entspricht AWG 30 (was man auch als "wire wrapping wire" kennt). Für Signalleitungen okay, aber nicht für mehr als vielleicht 150 Milliampere geeignet und schon gar nicht um eine Hohlsteckerbuchse für ein 2-Ampere-Netzteil anzuschließen. Die "Reichelt-Litze", die ich stattdessen verwendet habe, hat immerhin einen Querschnitt von 0,14 mm2 und ist für 0,8 Ampere geeignet. Eigentlich bräuchte man so etwas wie 0,5 mm2 um das Netzteil voll nutzen zu können. Meine Recherche hat übrigens dutzende Tabellen mit teils widersprüchlichen Werten ergeben, die aber ungefähr auf folgende Faustformel hinauslaufen: 6 A/mm2 bei Litze, 10 A/mm2 bei Einzelader.
Die LED-Panels habe ich sehr großzügig angeschlossen: jeder VCC-Pin hat ein Kabel zur Hauptverteilung bekommen. Ich war mir nicht sicher, wie viel Spannungsabfall zu erwarten ist, wenn man nur das eine Ende anschließt, an dem auch die Daten rein gehen, und das zweite Modul hinten mit dran hängt. Ich bin erst mal konservativ von voller LED-Leistung ausgegangen, was laut Hersteller einer Stromaufnahme von 20 mA pro Farbe = 60 mA pro weißem Segment entspricht; bei 76 LEDs schwindelerregende 4,5 Ampere. Weil mir das viel zu hoch erschien habe ich ein paar Annahmen bezüglich gleichzeitig leuchtender LEDs und ihrer Farben getroffen (ca. 60 LEDs an, davon 50 einfarbig => 1,6 Ampere) und habe im Verlauf auch festgestellt, dass die LEDs brutal hell sind und eine deutlich geringere Helligkeit (und damit verbunden geringere Stromaufnahme) ausreicht. Wenn es dann am Ende nur noch ein paar hundert Milliampere sind, die benötigt werden, dann sollte auch ein Anschluss ausreichen; vielleicht der in der Mitte.
Auf dem letzten Bild sieht man gut, wie hell diese LEDs sind. Das Gerät steht in der Ecke unseres
Wohnzimmers, in dem auch Fernseher, Spielkonsolen, usw. stehen; also schon leicht gedämpft (man will ja was
auf dem Fernseher sehen können), aber keineswegs Kinosaal-Atmosphäre. Hier ist die LED-Helligkeit
schon auf nur 5% gesetzt und die Kamera hat Probleme, die Lichtränder sauber aufzulösen. Wenn es
abends richtig dunkel ist, dann empfinde ich die Helligkeit bereits als störend und käme mit 1% aus
(Minimum ist 1/255 = 0,4%). Realisiert wird die Dimmung in der NeoPixel-Bibliothek über das Attribut
brightness
, das einen Wert zwischen 0.0
und 1.0
annehmen kann und mit den
RGB-Werten der Pixel multipliziert wird, um auf die Anzeige-Werte zu kommen. Dabei schrumpft übrigens der
Farbraum: statt 2563 = 16,7 Millionen sind bei 1% Helligkeit z.B. nur noch (1 + 255 *
0,01)3 = 9 Farben darstellbar. Diese Erkenntnis ist auch in eine Änderung am Gehäuse
eingeflossen: ich habe die Dicke der Frontplatte vor den LEDs von 0,5 auf 0,75 Millimeter erhöht, in der
Hoffnung, dass das Licht etwas stärker gedämpft wird und ich beim Dimmen nicht zu weit runter gehen
muss.
Im Praxiseinsatz hat sich das energy-display
absolut bewährt. Ich habe auch gar nicht mehr
viel an der Software geschraubt, seit ich das LED-Farbschema fertig ausgetüftelt habe. Momentan startet
es sogar nach einem Stromausfall nicht einmal von selbst auf, sondern alles ist manuell gestartet... der Fluch
eines gut funktionierenden Prototyps, der die akuten Bedürfnisse adäquat befriedigt. Damit wirkt auch
der Einsatz von Docker mit Hinblick auf einfachere Software-Updates etwas fragwürdig. Ich gehe sogar noch
weiter und stelle in Frage, ob wirklich ein Raspberry Pi Zero notwendig ist, oder ob es der Pico ebenfalls getan
hätte (auch in Hinblick auf die Erweiterungen; siehe nächster Abschnitt).
Eine weitere Frage, die mich umtreibt, betrifft die externen Abhängigkeiten. Das jetzige System erfordert als Infrastruktur die InfluxDB und den MQTT-Broker auf einem externen System, das ständig erreichbar ist. In Hinblick auf einen Standalone-Betrieb bei anderen (dem Produktgedanken folgend) wäre es natürlich toll, wenn man einfach nur die Box ans Wifi hängen, ggf. IP-Adressen konfigurieren müsste, und schwupps ginge alles. Aber ohne Datenbank im Rücken gäbe es natürlich nur die Historie, die das Gerät selbst erlebt hat; anders gesagt: frisch angeschlossen muss man eine gute halbe Stunde warten, bis die Matrix-Anzeige was hergibt. Andererseits -- wäre das schlimm?
Eine mögliche Erweiterung, die mir seit Beginn vorschwebt, betrifft die Steuerung der LED-Helligkeit. Wenn die Umgebungshelligkeit per LDR (Light Dependent Resistor aka. Fotowiderstand) erfasst würde, dann könnte man leicht eine adaptive Helligkeitssteuerung implementieren, welche die Helligkeit in den Abendstunden zurückfährt und bei direkter Sonneneinstrahlung aufdreht. Während der Umsetzung ist mir aufgefallen, dass der Raspberry Pi Zero keine Analogeingänge besitzt. Hier muss man zu einem externen A/D-Wandler greifen, in den meisten Tutorials wird auf den MCP3008 verwiesen (10-Bit, 8 Kanäle, SPI), der hierzulande für ca. 3 Euro zu haben ist. Bei Verwendung eines Raspberry Pi Picos würde die Notwendigkeit für einen externen Baustein entfallen, da dieser bereits 3 Analogeingänge besitzt.
Nachdem ich zufällig gesehen habe, wie einfach es ist mit IoT-Geräten in Discord zu posten, habe ich auch über eine solche Anbindung nachgedacht. Damit ließen sich vergleichsweise leicht Push-Benachrichtigungen auf ein Smartphone schicken, ohne dass man die Tortur durchlaufen muss, eine eigene Anwendung zu entwickeln und zu verteilen. Diese Funktion könnte man nutzen, um beim Eintreten bestimmter Bedingungen (z.B. mehr als 3,5 kW Einspeisung für mindestens 20 Minuten) aktiv darauf aufmerksam zu machen, dass energiehungrige Verbraucher eingeschaltet werden könnten. Hier wäre noch eine interessante Herausforderung, einen ansprechenden Ansatz zur Definition solcher Bedingungen zu finden. Vielleicht eine Art Mini-DSL oder so etwas wie EduBlocks.
Ähnlich, aber viel rudimentärer, wäre ein Piezo-Buzzer. Dieser könnte ebenfalls auf Situationen aufmerksam machen, die eine Benutzerinteraktion erfordern. Der Vorteil hier wäre die geringere Abhängigkeit von externen Diensten (Discord bzw. Account dort) und Geräten (PC, Smartphone); der Aufwand zur Definition der Bedingungen wäre der gleiche. Durch die geringeren Abhängigkeiten könnte solch ein Mechanismus auch ähnlich zu den BIOS-Signaltönen auf Wehwehchen mit der Netzwerkonfiguration oder Hardware aufmerksam machen, die eine wortreichere Form der Verständigung verhindern.
Datum | Version | Datei | Beschreibung |
---|---|---|---|
2024-09-04 | 1.0 | energy-display-1.0.tar.gz | Quellcode, 3D-Modelle (OpenSCAD), Dokumentation |