Genauso wie die Espruino IDE mit einer gekoppelten Bangle.js kommuniziert, kann es auch jede andere Webseite machen - der Schlüssel dazu ist das JavaScript-Modul Puck.js.
Nach dem Einbinden von
<script src="http://www.puck-js.com/puck.js"></script>
in ein Web-Dokument stehen folgende Methoden zur Verfügung:
connect
- stellt eine explizite Bluetooth-Verbindung zu einer Uhr herisConnected
- liefert true
, falls eine Uhr (implizit) über Bluetooth verbunden istgetConnection
- liefert eine bestehende (implizite) Bluetooth-Verbindung zu einer Uhrclose
- schließt die (implizite) Bluetooth-Verbindung zur Uhrwrite
- sendet Anweisungen auf eine Uhr (über eine implizite Verbindung)eval
- führt Anweisungen auf einer Uhr aus & liefert das Ergebnis (über implizite Vbdg.)setTime
- setzt Zeit und Zeitzone auf einer Uhr (über eine implizite Verbindung)modal
Puck.js
funktionieren kann, müssen sowohl der Browser als auch das verwendete Endgerät (Desktop, Tablet, Smartphone) WebBluetooth unterstützen! Das folgende Skript ist eine vereinfachte Version der WebBT-Erkennung aus Puck.js
:
function WebBTisSupported () {
if (
(navigator.platform.indexOf('Win') >= 0) && (
(navigator.userAgent.indexOf("Chrome/54") >= 0) ||
(navigator.userAgent.indexOf("Chrome/55") >= 0) ||
(navigator.userAgent.indexOf("Chrome/56") >= 0)
)
) { return false }
return (navigator.bluetooth != null);
}
.
Leider funktioniert diese Erkennung nicht vollständig: es kann sehr wohl passieren, dass eine Unterstützung von Bluetooth angezeigt wird, aufgrund einer Benutzereinstellung aber trotzdem nicht verfügbar ist (der Opera-Browser ist solch ein Kandidat).
Nur der Anzeige, dass WebBT nicht unterstützt wird, kann stets vertraut werden.
Die Kommunikation mit einer Bangle.js kann über eine explizit hergestellte Verbindung geschehen - oder über eine implizite Verbindung, die von Puck.js
selbst verwaltet wird.
Letzteres ist einfacher, ersteres bietet mehr Kontrolle über die Kommunikation.
Eine implizite Verbindung wird von Puck.js
automatisch hergestellt, sobald (zu Beginn oder nach dem Schließen einer vorherigen impliziten Verbindung) eine der Methoden write
, eval
oder setTime
aufgerufen wird.
Die "Kommunikation mit einer Uhr" spielt sich genauso ab wie der Umgang mit dem Terminal-Fenster der Espruino-IDE.
Puck.write(text, callback)
verschickt den gegebenen Text, als hätte man ihn in den Terminal-Bereich eingetippt und ruft anschließend die callback
-Funktion mit der Terminal-Ausgabe als einzigem Argument auf.
Puck.write(`
function drawPacMan () {
Bangle.setLCDMode('80x80');
g.clear();
g.setColor(1,1,0);
var Image = Graphics.createImage(` ****\\n******\\n******\\n **\\n******\\n ****`);
g.drawImage(Image, 37,37);
g.flip();
}
drawPacMan();
`, function (Output) {
console.log(Output)
});
würde folgende Ausgabe
>function drawPacMan () {
: Bangle.setLCDMode('80x80');
: g.clear();
: g.setColor(1,1,0);
: var Image = Graphics.createImage(' ****\n******\n******\n **\n******\n ****');
: g.drawImage(Image, 37,37);
: g.flip();
:};
=function () { ... }
>drawPacMan();
=undefined
>
in die Browser-Konsole schreiben.
Sofern noch keine Verbindung zu einer Uhr besteht, wird eine solche von Puck.js
selbst hergestellt.
Die Funktion Puck.eval(expression, callback)
schickt den durch expression
gegebenen JavaScript-Ausdruck an die angeschlossene Uhr, wertet ihn dort aus und ruft anschließend die als callback
mitgegebene Funktion mit dem in einen JavaScript-Wert umgewandelten Ergebnis als einzigem Argument auf.
Puck.eval('Math.sin(30*Math.PI/180)', function (Result) {
console.log('Result = ' + Result);
console.log('Result is a ' + typeof Result);
});
würde
Result = 0.5
Result is a number
in die Browser-Konsole schreiben.
Die Funktion Puck.setTime(callback)
setzt Datum, Zeit und Zeitzone einer angeschlossenen Uhr auf die Werte, die gerade auf dem Browser-Endgerät gelten.
Puck.setTime(function (Response) {
console.log(Response);
});
würde etwas Ähnliches wie
setTime(1578815998.802);if (E.setTimeZone) E.setTimeZone(1);
=undefined
>
in die Konsole des Browsers schreiben - und natürlich die Uhr entsprechend konfigurieren.
Falls die Verbindung zur Uhr nicht automatisch geschlossen wird (z.B. weil eine andere Anwendung Verbindung zur selben Uhr aufgenommen hat) kann sie auch gezielt geschlossen werden:
Puck.close();
Auf Wunsch kann die Verbindung zu einer Bangle.js aber auch selbst verwaltet werden - z.B. wenn mehrere Uhren vorhanden sind und Verbindungen zu allen Uhren unterhalten werden sollen.
Sobald das Modul Puck.js
geladen ist, kann eine explizite Verbindung zu einer Bangle.js hergestellt werden:
Puck.connect((Connection) => {
if (Connection == null) {
console.error('no WebBT connection established');
} else {
console.log('WebBT connection is ready to be used');
}
});
Sofern Ihr Browser WebBT unterstützt, können Sie dieses Skript gleich ausprobieren:
Sobald die Verbindung zu einer Uhr besteht, kann sie mithilfe von Event-Routinen "belauscht" werden - auf diese Weise können z.B. Teile einer grafischen Benutzerschnittstelle deaktiviert werden, sobald eine Verbindung zusammenbricht.
Folgende Events werden von einer Verbindung gefeuert:
open
- informiert über die erfolgte Verbindungsaufnahmedata
- informiert über empfangene Datenclose
- informiert über das Beenden einer VerbindungPuck.connect((Connection) => {
if (Connection == null) {
console.error('no WebBT connection established');
Connection.on('open', () => { handle connection establishment });
Connection.on('data', (received) => { handle incoming data });
Connection.on('close', () => { handle connection termination });
} else {
console.log('WebBT connection is ready to be used');
}
});
Für die Kommunikation über eine explizite Verbindung steht nur die Methode write
zur Verfügung - diese funktioniert ähnlich wie ihr zuvor beschriebenes Pendant für implizite Verbindungen, ist aber an das Objekt einer expliziten Verbindung gebunden:
connection.write(text,callback);
Das folgende Beispiel bildet die für implizite Verbindungen beschriebene Funktion setTime
für explizite Verbindungen nach:
let now = new Date();
connection.write(
'\x10setTime(' + (now.getTime()/1000) + '); E.setTimeZone(' + (now.getTimezoneOffset()/-60) + ')\n',
function (Output) {
alert('function has been completed');
}
);
Eine bestehende Verbindung kann mittels
connection.close();
wieder geschlossen werden.