JavaScript und das Internet of Things, Teil 1: Espruino und Tessel

Sprachen  –  3 Kommentare

JavaScript, die Lingua franca des Web, kommt mittlerweile auch im Bereich des Internet der Dinge zum Einsatz, insbesondere bei der Entwicklung prototypischer Anwendungen.

Statt sich mit Sprachen wie C und Assembler "herumplagen" zu müssen, wenn man noch nie damit zu tun hatte, fällt der Einstieg in die hardwarenahe Programmierung Webentwicklern dank JavaScript um einiges leichter. Dieser Mehrteiler gibt einen kurzen Überblick über eine Auswahl existierender Projekte.

Espruino – ganz JavaScript

Beim Espruino (s. Abb. 1) handelt es sich um einen Mikrocontroller, der nicht (wie man es von anderen gewohnt ist) C- oder Assembler-Code ausführt, sondern JavaScript. Hierfür hat er einen Interpreter an Bord, der sich prinzipiell auch auf anderen Geräten installieren und nutzen lässt und dem 128KByte Flash-Speicher und 8 KByte RAM als Grundlage ausreichen. Viel mehr wäre auf einem Espruino zudem gar nicht möglich, verfügt er doch gerade mal über 48 KByte RAM und einen 256 KByte großen Flash-Speicher. Nicht viel für den industriellen Einsatz, aber für die prototypische Entwicklung durchaus ausreichend. Unter der Haube werkelt zudem ein ARM-Cortex-M3-Prozessor mit 72 MHz.

Darüber hinaus stellt der Espruino einen Micro-SD-Karten-Slot, einen Micro-USB-Anschluss, zwei Drucktaster, drei LED-Leuchten (Rot, Grün und Blau) sowie 44 GPIO-Pins bereit, über die sich externe Komponenten wie Sensoren und Aktoren anschließen lassen (weitere Details findet man in der Produktbeschreibung). Von der Größe her ist der Espruino mit 54mm x 41mm nur in etwa halb so groß wie eine Kreditkarte, weswegen er für die prototypische Entwicklung in IoT-Projekten hervorragend geeignet ist, beispielsweise, um das Zusammenspiel verschiedener Sensoren zu testen und zu evaluieren.

Das Espruino-Board ist gerade mal halb so groß wie eine Kreditkarte (Abb. 1).


Für die Entwicklung verbindet man das Espruino-Board per Micro-USB-Kabel mit dem PC oder Mac. Unter Windows sind anschließend noch spezielle Treiber zu installieren, unter Linux müssen ein paar Berechtigungen vergeben werden, Mac OS X dagegen stellt das Board direkt per Plug-and-Play zur Verfügung. Prinzipiell lässt sich nach erfolgreicher Verbindung mit jedem beliebigen Terminalprogramm auf den Espruino zugreifen.

Insbesondere während der Entwicklung bietet sich allerdings die Chrome Web IDE an. Dabei handelt es sich um ein Browser-Plug-in, das der Hersteller auf seiner Webseite zur Verfügung stellt (Abb. 2). Mit der IDE lässt sich JavaScript-Code relativ einfach auf das Espruino-Board laden und dort testweise ausführen.

Die Espruino Chrome Web IDE erleichtert die Programmierung des Espruinos (Abb. 2).


Nachdem man sich per Terminalprogramm oder Web IDE mit dem Espruino-Board verbunden hat, befindet man sich auf seiner Kommandozeile, über die sich prinzipiell direkt beliebige JavaScript-Anweisungen ausführen lassen. Komplexere Programme lädt man dagegen manuell oder über die IDE auf das Board.

Neben Objekten und Funktionen, die man aus dem Standard für JavaScript kennt, stellt Espruino eigene Objekte und Funktionen bereit, über die sich das Board steuern lässt. Für das Ansprechen der einzelnen Pins (z.B. GPIO-Pins, LEDs und Drucktaster) stehen beispielsweise jeweils entsprechende globale Objekte zur Verfügung (beispielsweise LED1, LED2 und LED3), die allesamt Instanzen der "Klasse" Pin sind, in Anführungszeichen deswegen, weil JavaScript genau genommen bis ECMAScript 2015 keine Klassen kennt). Letztere verfügt über unterschiedliche Methoden: mit read() beispielsweise lässt sich der Wert beziehungsweise Pegel des entsprechenden Pins auslesen, über write() der Wert des Pins schreiben, über set() direkt auf den Wert 1 setzen, über reset() direkt auf den Wert 0:

LED1.set();           // rote LED an
LED1.read(); // Ausgabe: true
LED1.reset(); // rote LED aus
LED1.read(); // Ausgabe: false
LED1.write(1); // rote LED an
LED1.write(0); // rote LED aus
LED1.write(true); // rote LED an
LED1.write(false); // rote LED aus
LED1.write(HIGH); // rote LED an, Konstante HIGH hat Wert 1
LED1.write(LOW); // rote LED aus, Konstante LOW hat Wert 0
LED2.write(1); // grüne LED an
LED3.write(1); // blaue LED an

Ein einfaches Beispiel, das in kurzen Intervallen die drei eingebauten LEDs aufleuchten lässt – sozusagen das "Hello World"-Beispiel in der IoT-Welt – zeigt Listing 2. Definiert werden hier zunächst die drei Funktionen toggleRed(), toggleGreen() und toggleBlue(), die jeweils alternierend die entsprechenden LEDs an- beziehungsweise ausschalten. Mit setInterval() lässt sich festlegen, in welchem zeitlichen Intervall die Funktionen aufzurufen sind. Diesen Befehl kennen JavaScript-Entwickler bereits aus Browser-Laufzeitumgebungen und Node.js/io.js. Im Beispiel wird die rote LED auf die Weise alle 400 Millisekunden an- beziehungsweise ausgeschaltet, die grüne LED alle 420 Millisekunden und die blaue LED alle 440 Millisekunden.

var red = true;
var green = true;
var blue = true;

function toggleRed() {
red = !red;
LED1.write(red);
}
function toggleGreen() {
green = !green;
LED2.write(green);
}
function toggleBlue() {
blue = !blue;
LED3.write(blue);
}
setInterval(toggleRed, 400);
setInterval(toggleGreen, 420);
setInterval(toggleBlue, 440);

Alternativ zu den Methoden der "Klasse" Pin stehen die beiden globalen Funktionen digitalWrite() und digitalRead() für das Schreiben beziehungsweise Auslesen der Pins zur Verfügung, wie man sie eventuell aus der Arduino-Entwicklung kennt. Der Funktion digitalWrite() übergibt man die Pin-Nummer und den Wert beziehungsweise den Pegel, der an den jeweiligen Pin zu "schreiben" ist. Das Beispiel von eben ließe sich demnach unter Verwendung von digitalWrite() wie folgt umformen:

var red = true;
var green = true;
var blue = true;

function toggle1() {
red = !red;
digitalWrite(LED1, red);
}
function toggle2() {
green = !green;
digitalWrite(LED2, green);
}
function toggle3() {
blue = !blue;
digitalWrite(LED3, blue);
}
setInterval(toggle1, 400);
setInterval(toggle2, 420);
setInterval(toggle3, 440);

Lesen und Schreiben

Analog zum Schreiben von Werten per digitalWrite() dient die Funktion digitalRead() dem Auslesen der Werte einzelner Pins. Übergibt man ihr die Nummer des Pins, erhält man den aktuell dort gemessenen Pegel. Ein Beispiel, in dem eine LED per Drucktaster an- beziehungsweise ausgeschaltet wird, soll dies illustrieren:

var red = true;
setWatch(function() {
if (digitalRead(BTN1) === 1) {
digitalWrite(LED1, red);
red = !red;
}
}, BTN1, true);

Um den Status des Drucktasters auszulesen ("gedrückt" oder "nicht gedrückt",) bedient man sich der Methode digitalRead(). Die Funktion setWatch() dient dabei dazu, kontinuierlich den Status eines Pins zu beobachten. Ändert er sich, führt das Programm die übergebene Callback-Funktion aus. Im Beispiel wird auf die Weise der Status des Drucktasters beobachtet (BTN1) und sobald er gedrückt wird (was am Rückgabewert 1 zu erkennen ist), die rote LED an- beziehungsweise ausgeschaltet. Dafür sorgt der Code innerhalb der Callback-Funktion.

Eine Übersicht über die zur Verfügung stehenden Funktionen und Objekte (darunter für JavaScript-Entwickler alte Bekannte wie das JSON- oder das console-Objekt) findet man in der Espruino-Dokumentation. Darüber hinaus stehen eine Reihe von JavaScript-Modulen ab Werk zur Verfügung. Beispielsweise lässt sich ein Espruino-Board über das http-Modul auch als HTTP-Client:

var http = require("http");
http.get("http://www.espruino.com", function(res) {
res.on('data', function(data) {
console.log(data);
});
});

oder HTTP-Server:

var http = require("http");
http.createServer(function (req, res) {
res.writeHead(200);
res.end("Hello World");
}).listen(8080);

verwenden. Über das Modul fs können Entwickler zudem auf das Dateisystem der
Micro-SD-Karte zugreifen:

var fs = require("fs");
fs.writeFileSync("datei.txt", "Hallo Welt");
console.log(fs.readFileSync("datei.txt"));

Aber auch zusätzliche externe Module lassen sich einbinden, um beispielsweise auf Sensoren, Aktoren oder andere angeschlossene Komponenten zugreifen zu können. Installiert werden sie alle über den Node.js Package Manager (NPM). Verwendet man die Chrome Web IDE, lädt sie die Module beim Code-Upload automatisch mit auf das Espruino. Alternativ lassen sich die Module im Ordner node_modules auf die SD-Karte kopieren oder – sofern das Espruino eine WLAN-Verbindung hat – direkt aus dem Internet laden.

Eine komplette Übersicht zur Verfügung stehender Module ist ebenfalls auf der Projektseite zu finden. Unter anderem gibt es eins zum Auslesen eines Temperatursensors:

var ow = new OneWire(A1);
var sensor = require("DS18B20").connect(ow);
setInterval(function() {
// Ausgabe des gemessenen Temparaturwertes
console.log(sensor.getTemp());
}, 1000);

Am Namen (hier "DS18B20") lässt sich bereits erkennen, dass die einzelnen Module in der Regel sehr hardwarespezifisch sind. Das bedeutet, dass es beispielsweise kein generisches Modul gibt, das sich mit beliebigen Temperatursensoren verwenden lässt. Das Beispiel zeigt zwar lediglich, wie der Wert des Temperatursensors ausgelesen werden kann, es lässt sich aber - entsprechende Kenntnisse in der Elektrotechnik - relativ einfach erweitern, um beispielsweise abhängig von diesem Wert einen angeschlossenen Heizer an- bzw. auszuschalten.

Ist der Espruino schon ein Winzling, geht der Espruino Pico noch einen Schritt weiter: mit einer Abmessung von 33mm x 15mm umfasst er gerade mal ein Viertel der Größe seines älteren Bruders. Allerdings geht das auf Kosten der Hardware: statt drei LEDs gibt es beim Espruino Pico lediglich zwei (Rot und Grün), statt zwei Drucktastern einen einzigen und statt 44 GPIO-Pins lediglich 22. Bezüglich des Speichers hingegen wurde aufgerüstet: zum Einsatz kommen ein 84 MHz ARM-Cortex-M4-Prozessor, 384 KByte Flash und 96 KByte RAM. Preislich gesehen ist der Espruino Pico mit etwa 25 Euro sogar etwas günstiger als der Espruino mit rund 35 Euro.