Wir basteln blinkende Lichter mit dem Raspberry Pi und Kotlin Native

Die Tage werden kürzer und ungemütlicher. Das beutetet nicht nur, dass Weihnachten naht, sondern dass wir bei Dr. Windows wieder etwas basteln! Dieses Mal mit einem Raspberry Pi, leuchtenden LEDs des Pimoroni Blinkt! HATs und Kotlin Native.
Das aktuelle Projekt kann man als gedanklichen Nachfolger zu unseren Windows 10 IoT Core Apps sehen, welche wir vor etlichen Jahren entwickelt haben. Und all das, obwohl ich keine blasse Ahnung habe.
Wieso keine Microsoft-Plattform mehr?
Eine sehr berechtigte Frage. Vor allem, weil wir uns ja auf einer den Redmondern eher nahestehenden Nachrichtenseite befinden. Um ehrlich zu sein, ich würde gerne weiterhin für Windows IoT Core entwickeln, wenn es das denn noch geben würde. Microsoft hat es vor sich hin sterben lassen, und in dem Status, in dem es derzeit befindet, kann ich einfach niemandem mehr raten, sich mit diesem Betriebs- oder Ökosystem in der Freizeit zu beschäftigen.
Wieso Kotlin Native?
Nachdem Microsoft nicht nur das Betriebssystem für die Raspberry Pis eingestellt hat, sondern kürzlich auch noch Visual Studio for Mac abgekündigt wurde, sind für mich .NET und C# im Hobbyumfeld kein Weg mehr, den ich gehen möchte. Ich liebe die Freiheit, mir mein Host-Betriebssystem und eventuell auch meine Entwicklungsumgebung so auszusuchen, dass ich mich nicht eingeengt fühle. Kotlin und auch die IDEs von JetBrains laufen auf dem Mac sowie auch auf Linux- und Windows-Maschinen und sind für den von uns anvisierten Anwendungsfall auch in kostenfreien Versionen verfügbar.
Des Weiteren ist für mich persönlich Kotlin die Sprache der Wahl, wenn es um Plattformunabhängigkeit und Vielseitigkeit geht. Sei es App- und Desktop-Entwicklung mittels Compose Multiplatform, Serversachen mit Ktor oder eben nun auch Raspberry Pi mit Kotlin Native.
Dies führt selbstverständlich zu ganz eigenen Problemen, vor allem, wenn man diese Sprache lernen möchte. Denn Kotlin ist nicht gleich Kotlin, was den Funktionsumfang betrifft. Das gilt umso mehr, wenn man wie wir in dieser Bastelei den “nativen” Weg gehen möchte. Da gibt es dann keine JVM, welche uns sonst schön bequem die Eigenheiten des Betriebssystems weg abstrahiert.
Pluspunkt ist, dass man Kotlin Code auf Plattformen ausführen kann, welche über keine JVM verfügen, wie etwa iOS, oder auf jenen, die dafür einfach zu schwach sind, wie ältere Raspberry Pis und andere Einplatinenrechner.
Was Kotlin Native gegenüber dem Standard-Kotlin auszeichnet, ist, dass wie bei einem C# Programm eine einzelne ausführbare Datei erstellt wird, welche wie eine *.exe unter Windows angesehen werden kann. Diese hat natürlich wie vieles im Kotlin Universum ein “k”-Prefix und nennt sich *.kexe – ideal zur Plätzchenzeit im Winter.
Was basteln wir?
Wir bauen ein Programm, mit dem wir exemplarisch für spätere Einsatzzwecke die Pixel des Pimoroni Blinkt! HATs eines Raspberry Pis ansteuern können. Nicht nur hart verdrahtet via Quelltext, sondern auch über eine Weboberfläche. Anstelle von nur acht Pixeln könnte man auch hiermit eine Christbaumbeleuchtung realisieren. APA102-basierte Lichter gibt es auch als Meterware.
Technisch ausgedrückt, kontrollieren wir mittels GPIO Spannungsänderungen an acht AP102-Pixeln, welche jeweils eine rote, grüne und blaue LED steuert. Für die curl-API beziehungsweise die Weboberfläche nutzen wir einen im Programm eingebetteten Webserver auf Basis von Ktor, welcher wie Kotlin an sich ebenfalls von JetBrains stammt.
Anders als damals bei unseren Windows 10 IoT Core Apps müssen wir uns dieses Mal selbst um das Ausspielen und Starten der App aus unserer Entwicklungsumgebung heraus kümmern. Dies ist einfacher als gedacht, da wir einerseits auf dem Host-Rechner entweder ein eingebaute Shell haben, wenn wir unter Mac oder Linux unterwegs sind, oder diese unter Windows mit dem WSL nachrüsten können.
Somit kümmert sich ein kleines Bash-Skript um das Bauen, das Hochladen auf den Pi und das Starten des Programmes. Bei diesem simplen Ansatz büßen wir die Fähigkeit ein, das auf dem Mini-Rechner laufende Programm während der Ausführung anhalten und untersuchen – sprich debuggen – zu können.
Der Quellcode sowie eine erklärende Readme-Datei sind in dem entsprechenden GitHub Repository abgelegt. Wie es am Ende aussieht, könnt ihr im Video am Ende dieses Artikels begutachten.
Eingesetzte Abhängigkeiten
Wir erfinden das Rad nicht neu, deswegen setzen wir bei dieser Bastelei auf das Framework KtGpio, welches wiederum auf den C-Bibliotheken aufsetzt, die wir im Bauprozess der App ganz klassisch verlinken müssen. Es wäre schlichtweg zuviel, bei dieser Art von Entwicklung bei Null anzufangen. Genauso verhält es sich mit Ktor, welche unsere Bibliothek für den Webserver ist.
Es ist schön, wenn man Dinge von Grund auf verstehen und begreifen möchte. Deshalb aber erst einmal Monate investieren, um das eigentliche Ziel zu erreichen, halte ich bei diesem Rumgewerkel für wenig zielführend.
Wer ebenfalls mit dem Pi basteln möchte, aber nicht auf die JVM verzichten mag, dem sei die Library Pi4J mit dem Kotlin DSL Plugin empfohlen.
Projektstruktur & wichtige Abschnitte
Da es sich bei unserer Bastelei um ein kleines Programm handelt, ist auch die Projektstruktur sehr simpel. Neben der Main.kt, um das Programm zu starten, gibt es die selbstbeschreibenden Packages “APA102” und “Server”. Die Kommunikation zwischen Server und dem achtfachen APA102-Controller findet über einen MutableStateFlow statt, der sozusagen die “Commando”s einseitig übermittelt.
APA102.kt
Dies ist der Manager (GitHub Datei), welcher mittels GPIO-Verbindungen die Lichter zum Leuchten bringt. In diesem werden am unteren Ende der Kotlin-Klasse die entsprechenden Pin-Nummern definiert als auch die Anzahl benötigter Pulse, um gewisse Reaktionen des Chips auszulösen. Dies ist eine gängige Praxis, wenn man “low-level” unterwegs ist. Hinzu kommen folgende essenzielle Funktionen zur Steuerung der APA102:
writeLedValues()
Wir können unsere Kotlin-Objekte verändern, wie wir wollen, schlussendlich müssen wir diese aber auch dem jeweiligen APA102 Chip mitteilen. Dies geschieht mit etwas Bitshifting und der writeByte-Funktion für jeden der acht zur Verfügung stehenden APA102 Chips.
Damit die Bausteine die von uns gewünschte Konfiguration annehmen, muss zuerst die Uhr, also der Clock-Pin, gesperrt oder entsperrt werden.
SetClockState()
Mittels einer genauen Anzahl an Impulsen bringen wir die Chips dazu, auf Änderungen zu hören. Je nach Bauteil ist das eine andere Zahl, in unserem Beispiel sind es 36, um die Uhr zu sperren, und 32, um diese wieder zu entsperren. Falls mein Verständnis falsch sein sollte, berichtigt mich bitte in den Kommentaren.
writeByte(input: Byte)
Nachdem die Chips auf Änderungen hören, können die eigentlichen Informationen als Bytes geschrieben werden. Diese für mich als Hochsprachenentwickler komplexe Logik habe ich nicht erfunden, sondern die offizielle Pimoroni Python Bibliothek als starke Inspiration hergenommen.
Server.kt
Im eigentlichen Sinn ist dieser keine eigenständige Klasse (GitHub Datei), sondern eine Funktion, welche ein entsprechendes Interface eines erstellten Webservers zurückliefert. So einfach kann es heutzutage sein.
runServer(actions: MutableSharedFlow<Command>)
Die namensgebende Aufgabe der Funktion ist es, einen eingebetteten Webserver zu starten. Dieser hört auf den Port 8080 und bietet ein GET- sowie mehrere POST-Requests an.
Ein Beispiel für einen POST-Request, der vom Benutzer definierte Inhalte enthält, ist der für die “morse” Funktionalität. Hierbei wird durch die von Ktor bereitgestellte Methode “call.receiveText()” der vom Absender bereitgestellte Payload ausgewertet, welcher in unserem Falle das Wort, welches gemorst werden soll, beinhaltet.
val template
Da wir in Kotlin Native keinen Zugang zu den Resourcen haben beziehungsweise die Datenein- und –ausgabe sehr komplex ist, entschied ich mich, das Web-Interface als Kotlin String zu hinterlegen. Dieses wird im GET auf “/” an den anfragenden Browser zurückgegeben.
Damit ich das html anständig bearbeiten kann, liegt mit der Datei “index-raw-template.html” das Template als einfache *.html Seite vor, in welcher der Editor seine volle Kraft in Sachen Syntaxhervorhebung und Code Completion ausspielen kann.
Fazit
Der Einstieg in Kotlin Native war sehr holprig, weil es nicht JVM-basiert ist und bei meiner Recherche für mich als Anfänger oft nicht sichtbar war, ob die von mir gesuchte Funktion nun nur in der JVM, im JavaScript-Bereich oder als native Variante zur Verfügung steht.
Dennoch hat mir es Spaß gemacht und mir gezeigt, dass man nicht immer Python verwenden muss, falls man Spaß mit einem Raspberry Pi haben möchte – auch wenn dieser bereits in die Jahre gekommen ist.
Thema:
- Entwicklung
Über den Autor

Tobias Scholze
Bayrischer Open Source- und Community-Enthusiast, Verfechter des neuen Microsoft und Wandler zwischen den Betriebssystemwelten. #communityrocks Von Herzen ein Nerd mit der festen Überzeugung, dass man gemeinsam und durch den Einsatz von moderner IT die Welt für jeden ein Stückchen besser machen kann.