The Build Lamp: Lavalampe meets Ethernet meets Jenkins

Inzwischen habe ich nun endlich mal ein kleines Bastelprojekt fertigbekommen, an dem ich schon ne ganze Weile schraube. Es geht um ein Extreme Feedback Device für das Projekt, in dem ich jobmäßig gerade beschäftigt bin. In dem wird nämlich Jenkins als Continuous-Integration-Plattform eingesetzt, d.h. in regelmäßigen Abständen wird ein Software-Build automatisch ausgeführt und das Ergebnis dann getestet, wobei sich ein Status von grün (alles bestens) über gelb (Build ok, aber mindestens ein Test ist fehlgeschlagen) bis rot (Build-Fehler) ergibt. Den kann man dann im Webinterface des Jenkins sehen, was sehr praktisch ist, weil man so mit nur kurzer Verzögerung nach Code-Checkins darüber informiert wird, ob die eigenen Code-Änderungen gut mit denen anderer Entwickler harmonieren oder im Zusammenspiel mit diesen irgendetwas unerwarteterweise kaputt gegangen ist. Aber eigentlich ist das ziemlich langweilig, das immer nachzugucken, und die Mails, die das CI-System automatisch bei Problemen versendet, sind auch irgendwie nett, aber unspektakulär. Deswegen kam vor vielen Jahren mal jemand auf die geniale Idee, irgendwelche realen Gerätschaften so mit einem Rechner zu koppeln, dass sie den aktuellen Build-Zustand quasi "greifbar" in der realen Welt visualisieren - und DAS sind Extreme Feedback Devices, oder kurz XFDs.

Bevor es losgeht mit diesem doch eher länglichen Artikel zeige ich am besten zur "Motivation" mal gleich das Endergebnis :-)



Es ist eine Lava-Lampe! Eine Lava-Lampe mit Netzwerkanschluss!! Eine bunte Lava-Lampe mit Netzwerkanschluss, die ihre Farbe wechseln kann!!! Die Farben korrespondieren wie eben erklärt mit dem Zustand des zu überwachenden Builds - ist die Lampe also grün, ist alles bestens, wird sie gelb ist irgendwo mindestens ein Test fehlgeschlagen und wenn sie rot ist, ist die Kacke gewaltig am Dampfen!

Die Hardware
Grundsätzlich kann man fast alles für den Zweck eines XFDs hernehmen, was man auf irgendeinem Wege elektronisch an- und abschalten kann. Drei farbige Lampen sind immer beliebt, auch in kreativen Variationen wie z.B. in Bär-Form :-). Ebenfalls ein Klassiker sind Lava-Lampen - die Idee hat mir grundsätzlich sehr gut gefallen, aber ich fand es etwas zu simpel, einfach nur eine Lampe an- oder abzuschalten bzw. mehrere Lampen für die verschiedenen Farben hinzustellen. Warum denn nicht eine Lampe nehmen, die immer an ist, aber die Farbe wechseln kann?

Stellte sich heraus, dass es in der Tat sogar höchst passendes Rohmaterial dafür gibt. Und nicht nur irgendeine Lava-Lampe, nein, sogar ein limitiertes Original von Mathmos, dem Erfinder der Lavalampen! Mehr Style geht nun wirklich nicht mehr :-) also musste so ein Ding her!

Als nächstes war zu klären, wie die Lampe beleuchtet und der Farbwechsel gesteuert werden sollte. Da die Lampe von sich aus schon auf LED-Technologie basiert, war die Leuchtmittelfrage schnell geklärt - LEDs sind simpel zu schalten, billig, brauchen wenig Strom und in jeder Farbe zu bekommen, ich würde also entweder die eingebauten LEDs dafür hernehmen oder eigene stattdessen einbauen, je nachdem was praktikabler ist. Beim ersten Öffnen der Lampe stellte sich dann raus, dass wohl letzteres der Fall ist: es sind zwar nur zwei unterschiedliche LED-Farben verbaut, nämlich blau und rot (blau wird durch die Eigenfarbe der "Lava" optisch zu grünem Licht, und durch Mischung mit Rot kann man ein Gelborange erzeugen), aber die LEDs saßen direkt auf einer kleinen Platine, welche die Heizung für die Lava steuert - da kann ich mich nicht so einfach mit meiner eigenen Steuerung dazwischenklemmen. Es würde also eine eigene "Beleuchtungseinheit" erforderlich werden - und wenn ich das eh schon mache, kann ich auch gleich noch ein paar mehr LEDs für mehr Power verbauen und zudem gelbe LEDs dazunehmen, um die gelbe Farbe intensiver hinzubekommen als nur durch die Mischung. Gelb ist immerhin wichtig, zeigt es doch an, dass die Tests fehlgeschlagen sind, also den Hauptfehlerfall bei einer vorbildlich guten Testabdeckung *räusper* ;-).

Gut, Beleuchtung geklärt, bleibt die Steuerung. Die meisten Selbstbau-XFDs, die man im Web so findet, hängen einfach an irgendeinem alten Rechner, der dann die CI-Webseite pollt, den Status ausliest und dann per USB-Steckerleiste oder ähnlichem Strom ein und aus schaltet. Das hat den Vorteil, dass es simpel zu bauen und zu programmieren ist, aber man hat eben ständig einen Rechner mehr laufen - irgendwie unelegant. Wollte ich so nicht haben - meine Idealvorstellung war mehr sowas wie eine Netzwerkbuchse an der Lampe, die darüber selbsttätig den Status abfragt und das Licht dann sanft zur neuen Farbe überblendet. Ein Mikrocontroller musste also her, und ein Netzwerkinterface dafür! Damit war auch gleich sichergestellt, dass die Lampe nicht nur einen hohen Style-, sondern auch einen ausreichend hohen Nerd-Faktor haben würde :-)

Praktischerweise bietet Pollin da einen schönen Bausatz unter dem Namen AVR NET-IO an, der für günstiges Geld ziemlich genau das enthält, was ich brauchte: einen ausreichend potenten Mikrocontroller, ein Ethernet-Interface (zwar nur 10 MBit, aber die Datenrate bekommt man mit einem 8-Bit-Mikrocontroller eh nicht mal ansatzweise ausgereizt), direkte Kompatibilität mit den 12V Spannung, mit der auch die Lavalampe läuft und mehr als genug steuerbare Ausgänge. Zwar ist die Platine relativ groß, so dass diese definitiv nicht ins Lampengehäuse passen würde, aber immerhin hat sie Europakartenformat, so dass man dafür viele passende Gehäuse findet. Oh, und es gibt im Wiki von mikrocontroller.net eine Menge Infos zu dem recht beliebten Bausatz und auch einiges an Code im Netz, der dafür geschrieben wurde, was immer praktisch ist, weil man dann nicht ganz von Null anfangen muss. Den Bausatz habe ich dann letztlich in ein schlichtes schwarzes Kunststoffgehäuse gesteckt, in dessen Blenden ich Löcher für das Netzwerkkabel, den seriellen Port (nutze ich im Moment gar nicht, aber just in case...) und einen Taster gesägt habe - und natürlich für das fünfadrige Kabel zur LED-Einheit, über welches die Schaltung auch mit Strom aus der Lampe versorgt werden würde. Das Ganze sah dann in verbauter Form wie auf folgendem Bild aus:



Zurück also zur Beleuchtung. Die LEDs sollten auf möglichst einfache Weise angeschlossen werden, also versuchte ich es im ersten Schritt mit einer simplen Reihenschaltung von drei (blau) bzw. 5 (gelb und rot) 3mm-LEDs sowie pro Farbe einem Transistor zum Schalten. Vorwiderstände hatte ich keine eingeplant, und um maximale Helligkeit zu erhalten waren die Reihenschaltungen so ausgelegt, dass die LEDs an ihrer Maximalspannung laufen würden. Das sah erst ganz gut aus: die resultierende Platine hatte gerade mal 3cm im Durchmesser, die LEDs leuchteten kräftig. Aber nach dem Einbau in die Lampe wie auf dem folgenden Bild gezeigt - der Einfachheit halber setzte ich die LED-Platine direkt auf die Originalplatine, die senkrecht in der Lampe steckt - erwies sich die Schaltung als problematisch.



Die LEDs erzeugen durch die hohe Spannung und den daher hohen Strom einiges an Wärme, und zusammen mit der Hitze von der Heizeinheit, die direkt über der Platine montiert war, knockte das die LEDs der Reihe nach aus. Nach einer halben Stunde Testbetrieb flackerte alles nur noch, und als ich die Platine dann anschließend wieder ausbaute waren deutliche Flecken darauf zu erkennen. Das Ding war reif für den Müll.

Beim zweiten Versuch war ich dann vorsichtiger:

  • Mehr LEDs pro Reihenschaltung und ein 20-Ohm-Vorwiderstand sollten den Strom und damit auch die Verlustwärme begrenzen.

  • Statt 3mm-LEDs kamen 5mm-LEDs zum Einsatz - dadurch wird zwar die Platine größer (5cm Durchmesser statt 3cm), aber die größeren LEDs sind robuster und außerdem auch heller, was den geringeren Strom ausgleichen sollte.

  • Statt einer Montage auf der bestehenden Steuer-Platine der Lampe entschied ich mich dafür, diese Platine flach auf den Boden der Lampe zu legen und in die Halterung stattdessen ein Stückchen Holz zu stecken. Auf diesem wiederum klebt, durch Zweikomponentenkleber befestigt, eine Münze, deren Oberfläche mit schwarzem Lack isolierend lackiert ist und die dann die LED-Platine trägt. Da sind gleich mehrere Ideen zusammengekommen: die Metallmünze sollte Wärme besser nach unten ableiten als der Kork, mit dem ich vorher gearbeitet hatte, und das Holz statt der Original-Platine erlaubte es mir, die Befestigungshöhe frei zu wählen, so dass die LED-Platine nun einige Zentimeter weiter entfernt vom im Betrieb sehr heißen Heizelement sitzt.

  • Dieser neue Aufbau funktionierte dann problemlos. Im Schaltplan und auf dem Board sieht das folgendermaßen aus...





    ...und in montierter Form dann so:



    Im Betrieb ergibt das ein wunderbares Farbenspiel :-)



    Und auch nach Aufsetzen des Lampengehäuses mit der Heizplatte kommt das Licht noch problemlos wie geplant durch das Loch in der Mitte:



    Also nichts wie ins Büro damit! Der erste Praxistest war dann aber leider sehr ernüchternd :( es stellte sich raus, dass die ambiente Helligkeit da doch ein klein wenig höher ist wie in meiner dunklen Bude, mit dem Effekt, dass man die Farbe der Lampe selbst ohne direkte Sonneneinstrahlung kaum erkennen konnte. Daraufhin hab ich die Lampe dann erst mal aus akutem Frust ein paar Monate in die Ecke gepfeffert.

    Irgendwann wollt ich es dann aber doch nochmal probieren, diesmal mit den richtig dicken Brocken unter den LEDs: 1- bzw. 3-Watt-Brummer sollten die Milliwatt-Funzeln ablösen. Da ich davon max. 3 unter das Loch bekommen würde, und zwei rote in Reihe grad passend an 5V betrieben werden konnten entschied ich mich dafür, die gelbe Variante auszulassen und Gelb stattdessen durch gleichzeitiges Aktivieren der einen blauen 3-Watt-LED und der zwei roten 1-Watt-LEDs zu bilden, wie das die Originalschaltung der Lampe auch getan hat.

    Zur Stromversorgung kommt ein 7805 (in der Variante 78S05 für größere Stromstärken) zum Einsatz, der die 12V auf 5V runterregelt. Im Foto sieht man vor allem den Aufsteckkühlkörper, der das Ding auf Betriebstemperatur halten soll. Aufgebaut ist alles auf der guten alten Lochrasterplatine :) ja, ich war faul, insbesondere zu faul, mein Platinen-Ätz-Werkzeug rauszukramen.



    Aber: es funktioniert! Und die Helligkeit ist "augenlichtraubend"!



    Weil die neuen LEDs leider anders wie die kleinen einen sehr breiten Abstrahlwinkel von 120 Grad haben, musste ich mir allerdings noch was einfallen lassen, um möglichst alles Licht nach oben durch das Loch zu kanalisieren. Die Lösung ist pragmatisch simpel: ein Lichttunnel aus Pappe, innen ausgekleidet mit Alufolie. Der hat auch noch den angenehmen Nebeneffekt, dass er einiges an Wärmestrahlung von den LEDs, die ja selber genug Wärme produzieren, fernzuhalten scheint. Da hätte ich mal früher drauf kommen sollen ;-)



    In dieser Variante war die Lampe dann auch hell genug für die typische Tageslichtsituation im Büro, wenngleich die kräftigen Farben nach wie vor erst bei Einbrechen der Dämmerung so richtig zur Geltung kommen.

    Die Software
    Auf Softwareseite begann ich mit einem von Simon K. veröffentlichten Opensource-Projekt, das einen sehr simplen Webserver auf dem Net-IO implementiert und seinerseits auf einer angepassten Version des uIP-Protokollstacks basiert. Dabei handelt es sich um einen speziell für den Einsatz in kleinen 8-Bit-Mikrocontrollern entwickelten, aufs Nötigste reduzierten TCP/UDP/IP-Stack. Ein solcher ist erforderlich, weil diese kleinen, simplen und billigen Controller dem Entwickler in Zeiten von Gigabyte-RAM-Riegeln, Terabyte-Festplatten und Gigahertz-CPUs geradezu absurd wirkende Limitationen aufzwingen: der auf der Net-IO standardmäßige Atmel-Controller AtMega32 z.B. besitzt 32 Kilobyte Flash-Speicher für Programm und statische Daten, 2 Kilobyte RAM, 1 Kilobyte EEPROM und läuft mit 16 MHz. Würde man einen gewöhnlichen TCP/IP-Stack darauf einsetzen, wäre der RAM schon mit einem Paket der gängigen Paketgröße von 1400 Byte fast zugekleistert - mal ganz davon abgesehen, dass der Stack-Code niemals in den Flash-Speicher passen würde. Der uIP-Stack umgeht diese Probleme z.B. dadurch, dass er erlaubt, unnötige Teile "auszuklammern", die dann gar nicht erst einkompiliert werden - ich benötige keine UDP-Unterstützung, also kompiliere ich sie gar nicht erst mit. Außerdem arbeitet er mit sehr viel kleineren Paketgrößen und ACK-Window-Sizes wie normale Stacks, um weniger kostbaren RAM als Puffer zu beanspruchen, hat gewisse Einschränkungen hinsichtlich der Fehlerkorrektur im TCP-Protokoll und bietet leider auch nicht die vom PC her gewohnte Abstraktion durch das Modell des Sockets. Das drückt alles gewaltig auf die erreichbare Übertragungsrate und macht die Softwareentwicklung auf Basis dieses Stacks nicht eben einfacher, aber hey, dafür kann man TCP/IP so in weniger als 12 Kilobyte Flash und 1 Kilobyte RAM quetschen :-)

    Dass in besagtem Sourcecode nicht nur das nackte TCP/IP-Protokoll, sondern auch gleich noch ein rudimentärer Webserver mit GET- und POST-Request-Verarbeitung implementiert war, machte mir das Erreichen eines der eher ambitionierteren Ziele meines Projekts erheblich einfacher: meine XFD-Lampe sollte ein Webinterface haben, über welches sie konfiguriert und auch direkt gesteuert werden kann. Also bohrte ich den Webserver entsprechend auf, erstellte eine Konfigurationsseite (unnötigen Schnickschnack wie User-Authentifizierung habe ich im Interesse eines kompakten Ergebnisses weggelassen, so dass am Ende wirklich eine Seite für das ganze Interface genügte) und schrieb einen ganzen Batzen Code zur dynamischen Erzeugung dieser Seite bzw. zum Parsen von POST-Antworten, wenn der User über die Seite irgendwas ändern will. Dabei lernt man eine ganz andere Seite der Webentwicklung kennen: so Krempel wie Rails oder Java Servlets oder PHP hat man auf einem Mikrocontroller natürlich nicht zur Verfügung - da muss wirklich jedes Zeichen händisch in C-Code an seine Stelle in der fertigen Seite gesetzt und die Seite dabei parallel schon mal an den Empfänger rausgesendet werden (denn in die verbliebenen paar hundert Byte RAM auf dem Controller passt nicht einmal meine spartanische Konfigurationsseite in ihrer Gänze hinein!) - Antworten vom Webbrowser werden ebenso Zeichen für Zeichen durchgeackert.

    Aber die ganze Mühe wurde belohnt: Nicht nur funktioniert das Webinterface einwandfrei mit allen Browsern auf meinem Rechner, nein, sogar mit dem iPhone kann die Lampe gleich out-of-the-box gesteuert werden :-)



    Damit die Lampe ihren eigentlichen Zweck erfüllen konnte, brauchte sie jedoch noch eine letzte Komponente: einen HTTP-Client, der den Jenkins-Server nach dem RSS-Feed des gewünschten Projekts fragen und anschließend daraus den Status des letzten Builds extrahieren könnte. Auch für diese Aufgabe fand sich in einem der Beispielprojekte aus der uIP-Original-Release-Version praktischerweise eine Vorlage, die mit einigen Handgriffen für meine Zwecke angepasst werden konnte - na ja gut, ein paar mehr Handgriffe waren nötig, denn speziell das Parsen des RSS-Feeds, das auch wieder komplett Low-Level Zeichen für Zeichen vonstatten gehen muss, war schon eine gewisse Aufgabe. Aber schlussendlich war alles Nötige beisammen und der erste Funktionstest bestanden. Sicher befindet sich noch der ein oder andere Bug in der Software, aber wer Interesse haben sollte und nicht vor meinem hässlichen, irgendwie zusammengestöpselten und großteils mies kommentierten C-Code zurückschreckt kann sich das ganze Paket im Quellcode gern hier herunterladen.

    Ich geh jetzt jedenfalls erst mal ein paar Builds schrotten, um die roten LEDs "lastzutesten" ;-)

    Kommentare
    Hier wurden noch keine Kommentare verfasst.
    Neuen Kommentar schreiben
    Autor
    Du musst einen Autor angeben
    E-Mail-Adresse
    Du musst eine valide E-Mail-Adresse angeben (diese wird nur gespeichert und nicht veröffentlicht).
    Website
    Kommentar
    Ein leerer Kommentar kann nicht abgesendet werden
    [b]...[/b] für fetten, [i]...[/i] für kursiven, [u]...[/u] für unterstrichenen und [c]...[/c] für durchgestrichenen Text. [quote]...[/quote] erzeugt Zitate, [quote=Quelle]...[/quote] Zitate mit Quellenangabe. [url=http://www.beispiel.de]...[/url] und [url]http://www.beispiel.de[/url] erzeugen Links mit und ohne Ankertext. [code]...[/code] bewirkt eine spezielle Formatierung für Quellcode.