zurück zum Artikel

Ausprobiert: Javascript fürs Handgelenk mit der Smartwatch Bangle.js

Maik Schmidt
Eine Hand hält das runde Display einer schwarzen Smartwatch. Darauf steht: Bangle.js.

(Bild: Espruino)

Die Bangle.js bringt Javascript auf die Smartwatch. Mit wenig Aufwand lassen sich eigene Apps schreiben.

Smartwatches erfreuen sich immer größerer Beliebtheit, aber die meisten lassen sich nur schwer oder gar nicht um eigene Apps erweitern. Googles Wear OS und WatchOS von Apple sind nicht besonders einsteigerfreundlich und die Produkte mancher Hersteller kommen gar mit gänzlich proprietärer Software daher.

Von dieser Situation war Gordon Williams, der Vater des Espruino-Projekts [1], wenig begeistert und setzte sich daher zum Ziel, eine Smartwatch zu entwerfen, die sich in JavaScript programmieren lässt. Das Ganze hat er wieder einmal im Rahmen einer Kickstarter-Kampagne erfolgreich finanziert [2] und sein neuestes Baby auf den Namen Bangle.js getauft. Künftig soll die Bangle im Espruino-Shop erhältlich sein [3].

Aus dem Make-Testlabor

Die Make-Redaktion probiert viel mehr aus, als ins alle zwei Monate erscheinende Heft passt. Deshalb veröffentlichen wir auf unserer Webseite in loser Folge weitere Testberichte.

Statt eine komplett neue Uhr zu entwerfen, hat Williams sich bestehende Produkte angesehen und sie einem Reverse Engineering unterzogen. Auf diese Weise musste er anschließend "nur noch" die Firmware des Geräts austauschen.

Er hat sich letzten Endes für das Modell F18 des chinesischen Herstellers DT No.1 entschieden. Diese Uhr ist bis zu 10 Metern Tiefe wasserdicht und basiert auf dem Nordic-Chip nRF52832. Angetrieben wird sie durch eine ARM Cortex-M4 CPU mit einer Taktrate von 64MHz. Dem Prozessor stehen 64kB RAM und 512kB Flash-Speicher direkt auf dem Chip zur Verfügung. Darüber hinaus gibt es noch 4MB externen Flash-Speicher.

Das farbige LC-Display bietet 240 × 240 Pixel bei einer Diagonale von 1,3". Ferner verfügt es über zwei berührungsempfindliche Zonen. Neben diesen dienen drei Tasten auf der rechten Seite der Uhr als Eingabemedien. Die Kommunikation mit der Außenwelt ist auch per Bluetooth Low Energy (BLE) möglich. Die Ausstattung in Bezug auf Sensoren ist üppig. Neben einem GPS/Glonass-Empfänger gibt es einen Puls-Monitor, ein 3-Achsen-Magnetometer und einen 3-Achsen-Beschleunigungssensor. Ein Piezo-Lautsprecher und ein Vibrationsmotor können zur Ausgabe von Benachrichtigungen verwendet werden.

Der 350mAh-Akku betreibt die Hardware circa eine Woche lang im Stand-By. Schaltet man hingegen GPS und den Bildschirm permanent ein, ist nach knapp drei Stunden Schluss, denn beide zusammen verbrauchen ungefähr 100mA.

Wie es sich für ein Bastler-Produkt gehört, kann man die Uhr mit nur vier Schrauben öffnen und für viele Projekte kann es von Vorteil sein, dass sich auch das Armband leicht entfernen lässt.

Das Geheimnis liegt im Wesentlichen in der Firmware der Uhr. Die hat nämlich mit dem Original des Herstellers nichts mehr zu tun. Williams hat sie kurzerhand durch den JavaScript-Interpreter Espruino ersetzt, der auch schon seine anderen Kickstarter-Projekte antreibt.

Espruino hat er dafür an die Gegebenheiten der Uhr angepasst, so dass eigene Programm alle Eigenschaften der Hardware nutzen können. Der Zugriff auf die Sensoren und Aktoren könnte dank ausgefeilter Bibliotheken bequemer kaum sein [5]. So gibt es zum Beispiel eine umfangreiche Grafik-API, die neben Vektor- und Bitmap-Zeichensätzen auch Funktionen zur Manipulation von Bitmap-Grafiken bietet. Als besonderes Schmankerl gibt es obendrein noch die Möglichkeit, TensorFlow Lite für Mikrocontroller [6] zu nutzen. Damit kann Bangle.js Machine Learning-Modelle ausführen, die zuvor auf größerer Hardware berechnet wurden.

Der Funktionsumfang des JavaScript-Interpreters ist erstaunlich groß und umfasst den Standard EcmasScript 5 und weite Teile von EcmasScript 6. Ein kleiner Wermutstropfen ist, dass der eigene Code inklusive Variablen nur bis zu 40kB Hauptspeicher belegen darf. Das ist aber deutlich mehr als es zunächst scheint, denn naturgemäß bieten die meisten Apps nur wenige Funktionen und JavaScript ist eine ausdrucksstarke Sprache, in der wenige Zeilen schon viel bewirken können.

Vor der Programmierung ist es wichtig, ein paar Einstellungen in der Uhr zu überprüfen. In den System-Einstellungen (Settings) müssen die Optionen BLE, Programmable und Make Discoverable jeweils den Wert On haben. Die Option HID muss hingegen den Wert Off haben. Die Programmierung der Bangle.js unterscheidet sich nicht von der Programmierung anderer Espruino-Boards und es kommen auch dieselben Werkzeuge zum Einsatz.

Zentral ist die Espruino Web-IDE [7], die Code via Bluetooth auf Espruino-Geräte wie Bangle.js übertragen kann. Sie funktioniert in allen Browsern, die Web-Bluetooth unterstützen. Momentan sind das Google Chrome, Opera und Microsoft Edge. Beim ersten Aufruf der IDE sollte man in den Einstellungen prüfen, ob die Option "Save on Send" den Wert "To RAM" hat. Der ist in der Regel voreingestellt, aber wer in der Vergangenheit mit anderen Espruino-Boards gearbeitet hat, hat ihn vielleicht geändert.

Screenshot der Einstellungen in der Espruino IDE.

Die Option "Save on Send" im Bereich Communications muss den Wert "To RAM" haben.

Sind alle Vorbereitungen getroffen, steht einem ersten Experiment nichts mehr im Weg.

Die Übertragung von Code auf die Bangle.js erfolgt grundsätzlich drahtlos. Daher muss man zunächst die Espruino Web-IDE mit der Bangle.js koppeln. Dies geschieht über das Connect-Icon links oben in der IDE. Nach einem Klick auf das Icon fragt der Browser nach der zu verwendenden Bluetooth-Schnittstelle. Anschließend muss man das Gerät auswählen, mit dem die IDE gekoppelt werden soll. Die Bangle.js meldet sich mit dem Namen "Bangle.js" und einer eindeutigen Kennung.

Screenshot der Espruino-IDE mit der Meldung "Select a Port: Web Bluetooth, Bluetooth Low Energy".

Der Browser fragt nach der zu verwendenden Bluetooth-Schnittstelle.

Nach der Kopplung wird das Connect-Icon der IDE grün und zeigt zwei verbundene Stecker. Ferner erscheint eine Erfolgsnachricht im linken Teil der IDE. Ab diesem Moment kann man JavaScript-Code auf der rechten Seite der IDE eingeben und mit dem "Send to Espruino"-Button in der Mitte an die Bangle.js senden.

Screenshot der Espruino-IDE mit der Meldung "Connected to Web Bluetooth".

So sieht es aus, wenn Browser und Bangle.js gekoppelt wurden.

Der Beispiel-Quelltext, den die IDE per Voreinstellung einblendet, funktioniert auf der Bangle.js leider nicht, weil er eine LED einschaltet und die Uhr keine LED hat. Zwar führt er zu keinem Fehler, aber sonderlich erhellend ist er auch nicht. Besser ist es daher, den Code zu löschen und zum Beispiel durch die folgende Anweisung zu ersetzen: Bangle.beep();

Screenshot der Espruino-IDE mit nur einer Zeile Code.

So entlockt man der Bangle.js ein erstes Piepen.

Sendet man diese an die Bangle.js, so gibt sie einen kurzen Piep-Ton von sich. Die Uhr lässt sich also interaktiv programmieren. Ein Blick auf die erste Anweisung legt die Vermutung nahe, dass Bangle der Name einer Klasse ist, die eine Funktion namens beep() anbietet. Genau das ist der Fall und die Bangle-Klasse spielt eine zentrale Rolle [8] bei der Programmierung der Uhr. Sie bietet Zugang zu fast all ihren Funktionen.

Ein etwas komplexeres Beispiel zeigt, wie einfach die Implementierung einer durchaus nützlichen Anwendung ist, die auf GPS-Daten zugreift und damit die aktuelle Geschwindigkeit ermittelt.

Bangle.setGPSPower(1);
Bangle.setLCDMode("doublebuffered");

function onGPS(fix) {
g.clear();
g.setFontAlign(0, 0);
g.setFont("6x8");
g.drawString(fix.satellites + " satellites", 120, 6);
if (fix.fix) {
const txt = (fix.speed < 20) ? fix.speed.toFixed(1) : Math.round(fix.speed);
g.setFontVector(80);
g.drawString(txt, 120, 80);
g.setFont("6x8", 2);
g.drawString("km/h", 120, 136);
} else {
g.setFont("6x8", 2);
g.drawString("Warte auf GPS", 120, 80);
}
g.flip();
}

Bangle.on('GPS', onGPS);

Das Programm startet mit ein paar Initialisierungen und schaltet zuerst mit der Funktion setGPSPower() das GPS ein. Per Voreinstellung ist es nämlich abgeschaltet, um den Akku zu schonen. Das ist auch sinnvoll, weil GPS circa 20mA verbraucht.

Ebenfalls abgeschaltet ist der Double-Buffer-Modus des Displays und die Funktion setLCDMode() aktiviert ihn. Ohne Double-Buffering kann es bei der Darstellung von Daten auf dem Display zu einem leichten Flackern kommen. Mit Double-Buffering passiert das nicht, denn bei diesem Verfahren wird ein neuer Bildschirminhalt zunächst unsichtbar im Hintergrund aufgebaut. Erst wenn er fertig ist, wird er gegen den aktuellen Bildschirminhalt ausgetauscht. Der Nachteil des Double-Bufferings ist, dass die darstellbare Fläche nur 240 × 160 statt 240 × 240 Pixel umfasst und dass das vertikale Scrolling nicht funktioniert.

Wie die meisten JavaScript-Interpreter arbeitet auch Espruino ereignisgesteuert. Das heißt, man kann den Aufruf von Funktionen mit bestimmten Ereignissen verknüpfen. Zum Beispiel soll die Funktion onGPS immer dann aufgerufen werden, wenn neue GPS-Daten vorliegen. Die Funktion erhält beim Aufruf automatisch ein Objekt, das die Daten des aktuellen GPS-Fixings enthält. Darin finden sich dann Attribute wie Longitude und Latitude, aber auch Informationen wie die Anzahl der derzeit sichtbaren Satelliten oder die aktuelle Geschwindigkeit.

Innerhalb der Funktion wird zunächst der Bildschirm vorbereitet. Sämtliche Display-Operationen erfolgen auf dem globalen Objekt g und die Funktion clear() löscht erst einmal den gesamten Bildschirm. Der Aufruf von setFontAlign() sorgt dafür, dass Texte sowohl horizontal als auch vertikal zentriert ausgegeben werden. Die Funktion setFont() wählt anschließend den Bitmap-Zeichensatz mit dem Namen "6×8" aus, der – wenig überraschend – sechs Pixel breit und acht Pixel hoch ist.

Mit drawString() wird schließlich die aktuelle Anzahl sichtbarer Satelliten an den Koordinaten (120, 6) ausgegeben.

Die Anzahl der Satelliten ist immer definiert und falls keine in Sicht sind, hat das Attribut den Wert 0. Die meisten anderen Attribute des Objekts fix sind nur dann sinnvoll belegt, wenn tatsächlich gültige GPS-Daten vorliegen. Ob das der Fall ist, kann man im Attribut fix ablesen.

Sobald gültige Daten empfangen wurden, gibt das Programm die aktuelle Geschwindigkeit aus. Geschwindigkeiten unter 20 km/h haben eine Nachkommastelle, alles darüber hat keine. Die Ausgabe der Geschwindigkeit erfolgt mit einem Vektor-Zeichensatz, der 80 Pixel hoch ist. Die Einheit "km/h" wird wieder mit einem Bitmap-Zeichensatz ausgegeben. Solange keine Satelliten in Sicht sind, gibt das Programm die Nachricht "Warte auf GPS" aus.

Eine Arm, der eine schwarze Smartwatch am Handgelenk trägt. Auf dem Display steht: Wait for GPS.

Bangle.js wartet geduldig auf Satelliten.


Erst am Ende der Funktion erfolgt der Aufruf von flip(), der zwischen dem sichtbaren und unsichtbaren Grafikspeicher wechselt. Erst in diesem Moment haben alle vorhergehenden Aufrufe auf dem Objekt g einen Effekt. Die letzte Anweisung des Programms sorgt dafür, dass die Funktion onGPS bei jedem neuen GPS-Ereignis aufgerufen wird. Das ist ungefähr einmal pro Sekunde der Fall.

Eine Arm, der eine schwarze Smartwatch am Handgelenk trägt. Auf dem Display steht: 6,1 km/h.

Eine GPS-gestützte Geschwindigkeitsanzeige in knapp 20 Zeilen Code.

Überträgt man das Programm mit der Espruino-IDE aufs Gerät, beginnt es sofort mit der Arbeit. Solange nicht genug Satelliten in Reichweite sind, wird nur die Anzahl der sichtbaren Satelliten ausgegeben. Danach gibt die App kontinuierlich die aktuelle Geschwindigkeit aus.

Bis zu diesem Zeitpunkt wurde die App gar nicht als wirkliche App auf der Uhr installiert, sondern lief im interaktiven Modus. Um sie im Menü der Uhr zu verewigen, müssen ein paar Meta-Informationen zur App im Gerät gespeichert werden. Zwingend notwendig sind dabei eine eindeutige Kennung und ein Name. In diesem Fall sind das speedo und Speedometer. Die Daten werden wie folgt in den Flash-Speicher geschrieben:

require("Storage").write("+speedo", {
"name": "Speedometer",
"src": "-speedo"
});

Anschließend muss noch der Code der gesamten App in den Flash-Speicher übertragen werden und das geht analog:

require("Storage").write("-speedo",`
// Hier den Code der App einfügen.
`);

Zu beachten ist hier die Verwendung von Backticks (`) zur Begrenzung von mehrzeiligen Zeichenketten.

Sobald die Daten gespeichert wurden, steht die Speedometer-App wie alle anderen Apps im Menü zur Auswahl.

Für die Bangle.js existiert auch ein kostenloser App Store [9], in dem man mit wenig Aufwand seine eigenen Kreationen veröffentlichen kann. In diesem Fall sollte man den Meta-Informationen noch ein Icon und eine etwas ausführlichere Beschreibung hinzufügen. Das ganze Prozedere ist in der Dokumentation des Projekts ausführlich beschrieben [10].

Die finale Version der Software der Uhr soll zwar erst im März 2020 fertig sein, aber sie ist schon jetzt erstaunlich stabil und umfangreich. Dasselbe gilt für die Dokumentation der JavaScript-Klassen.

Vor diesem Hintergrund macht die Programmierung der Bangle.js ganz einfach Spaß und die interaktive Art der Entwicklung ist um Längen effizienter als bei der Konkurrenz. Wer die Programmierung im Browser nicht mag, kann die Uhr über ein paar Node.js-Werkzeuge auch über die Kommandozeile ansprechen.

Die Hardware, insbesondere das Display, kann natürlich immer besser sein, aber dafür stimmt der Preis und die Leistung reicht für viele Spiele, Sport-Anwendungen und Heim-Automation locker aus. Was mit TensorFlow Lite so alles möglich sein wird, dürfte die Entwicklergemeinde in den kommenden Monaten zeigen.

(hch [11])


URL dieses Artikels:
https://www.heise.de/-4597599

Links in diesem Artikel:
[1] https://www.heise.de/tests/Espruino-JavaScript-ganz-weit-unten-2132781.html
[2] https://www.heise.de/news/Bangle-js-die-Smartwatch-die-gehackt-werden-will-4584614.html
[3] https://shop.espruino.com/
[4] https://www.heise.de/hintergrund/Ausprobiert-Kurztests-auf-make-magazin-de-2772998.html
[5] https://banglejs.com/reference
[6] https://www.tensorflow.org/lite/microcontrollers
[7] https://www.espruino.com/ide
[8] https://banglejs.com/reference#Bangle
[9] https://banglejs.com/apps
[10] https://github.com/espruino/BangleApps
[11] mailto:hch@make-magazin.de