Eine Einführung in WebBluetooth

Veröffentlicht: 2022-03-10
Kurze Zusammenfassung ↬ Mit Progressive Web Apps können Sie jetzt das Web nutzen, um ausgewachsene Apps zu erstellen. Dank einer enormen Menge neuer Spezifikationen und Funktionen können wir Dinge mit dem Web machen, für die Sie früher native Apps schreiben mussten. Allerdings war das Gespräch mit Hardware-Geräten bisher noch eine Brücke zu weit. Dank WebBluetooth können wir jetzt PWAs bauen, die Ihre Lichter steuern, ein Auto fahren oder sogar eine Drohne steuern können.

Mit Progressive Web Apps bewegt sich das Web immer mehr in Richtung nativer Apps. Allerdings mit den zusätzlichen Vorteilen, die dem Web innewohnen, wie Datenschutz und plattformübergreifende Kompatibilität.

Das Web war traditionell fantastisch darin, mit Servern im Netzwerk und insbesondere mit Servern im Internet zu kommunizieren. Jetzt, da sich das Web in Richtung Anwendungen bewegt, brauchen wir auch die gleichen Fähigkeiten, die native Apps haben.

Die Menge an neuen Spezifikationen und Funktionen, die in den letzten Jahren in Browsern implementiert wurden, ist überwältigend. Wir haben Spezifikationen für den Umgang mit 3D wie WebGL und der kommenden WebGPU. Wir können Audio streamen und generieren, Videos ansehen und die Webcam als Eingabegerät verwenden. Mit WebAssembly können wir Code auch mit nahezu nativer Geschwindigkeit ausführen. Darüber hinaus hat sich das Web, obwohl es ursprünglich ein reines Netzwerkmedium war, in Richtung Offline-Support mit Servicemitarbeitern entwickelt.

Das ist großartig und alles, aber ein Bereich war fast die ausschließliche Domäne für native Apps: die Kommunikation mit Geräten. Das ist ein Problem, das wir seit langem zu lösen versuchen, und es ist etwas, dem wahrscheinlich jeder schon einmal begegnet ist. Das Internet eignet sich hervorragend für die Kommunikation mit Servern, aber nicht für die Kommunikation mit Geräten . Denken Sie zum Beispiel daran, einen Router in Ihrem Netzwerk einzurichten. Wahrscheinlich mussten Sie eine IP-Adresse eingeben und eine Webschnittstelle über eine einfache HTTP-Verbindung ohne jegliche Sicherheit verwenden. Das ist nur eine schlechte Erfahrung und schlechte Sicherheit. Außerdem, woher wissen Sie, was die richtige IP-Adresse ist?

Mehr nach dem Sprung! Lesen Sie unten weiter ↓

HTTP ist auch das erste Problem, auf das wir stoßen, wenn wir versuchen, eine Progressive Web App zu erstellen, die versucht, mit einem Gerät zu kommunizieren. PWAs sind nur HTTPS, und lokale Geräte sind immer nur HTTP. Sie benötigen ein Zertifikat für HTTPS, und um ein Zertifikat zu erhalten, benötigen Sie einen öffentlich verfügbaren Server mit einem Domänennamen (ich spreche von Geräten in unserem lokalen Netzwerk, die außerhalb der Reichweite liegen).

Für viele Geräte benötigen Sie also native Apps, um die Geräte einzurichten und zu verwenden, da native Apps nicht an die Einschränkungen der Webplattform gebunden sind und ihren Benutzern ein angenehmes Erlebnis bieten können. Allerdings möchte ich dafür keine 500 MB große App herunterladen. Vielleicht ist Ihr Gerät schon ein paar Jahre alt und die App wurde nie aktualisiert, um auf Ihrem neuen Telefon zu laufen. Vielleicht möchten Sie einen Desktop- oder Laptop-Computer verwenden, und der Hersteller hat nur eine mobile App entwickelt. Auch keine ideale Erfahrung.

WebBluetooth ist eine neue Spezifikation, die in Chrome und Samsung Internet implementiert wurde und die es uns ermöglicht, vom Browser aus direkt mit Bluetooth Low Energy-Geräten zu kommunizieren. Progressive Web Apps in Kombination mit WebBluetooth bieten die Sicherheit und den Komfort einer Webanwendung mit der Möglichkeit, direkt mit Geräten zu kommunizieren.

Bluetooth hat aufgrund der begrenzten Reichweite, der schlechten Audioqualität und der Kopplungsprobleme einen ziemlich schlechten Ruf. Aber so ziemlich alle diese Probleme gehören der Vergangenheit an. Bluetooth Low Energy ist eine moderne Spezifikation, die mit den alten Bluetooth-Spezifikationen wenig zu tun hat , abgesehen davon, dass sie das gleiche Frequenzspektrum verwenden. Jeden Tag werden mehr als 10 Millionen Geräte mit Bluetooth-Unterstützung ausgeliefert. Dazu gehören Computer und Telefone, aber auch eine Vielzahl von Geräten wie Herzfrequenz- und Glukosemessgeräte, IoT-Geräte wie Glühbirnen und Spielzeug wie fernsteuerbare Autos und Drohnen.

Empfohlene Lektüre : API-basierte Plattformen verstehen: Ein Leitfaden für Produktmanager

Der langweilige theoretische Teil

Da Bluetooth selbst keine Webtechnologie ist, verwendet es einige Vokabeln, die uns vielleicht ungewohnt erscheinen. Lassen Sie uns also die Funktionsweise von Bluetooth und einige der Terminologien durchgehen.

Jedes Bluetooth-Gerät ist entweder ein „Zentralgerät“ oder ein „Peripheriegerät“. Nur zentrale Geräte können eine Kommunikation initiieren und nur mit Peripheriegeräten sprechen. Ein Beispiel für ein zentrales Gerät wäre ein Computer oder ein Mobiltelefon.

Ein Peripheriegerät kann keine Kommunikation initiieren und kann nur mit einem zentralen Gerät sprechen. Außerdem kann ein Peripheriegerät gleichzeitig nur mit einem zentralen Gerät sprechen. Ein Peripheriegerät kann nicht mit einem anderen Peripheriegerät kommunizieren.

ein Telefon in der Mitte, das mit mehreren Peripheriegeräten wie einer Drohne, einem Spielzeugroboter, einem Herzfrequenzmesser und einer Glühbirne spricht
Ein zentrales Gerät kann mit mehreren Peripheriegeräten kommunizieren. (Große Vorschau)

Ein zentrales Gerät kann gleichzeitig mit mehreren Peripheriegeräten sprechen und Nachrichten weiterleiten, wenn es dies wünscht. Ein Herzfrequenzmesser könnte also nicht mit Ihren Glühbirnen kommunizieren, aber Sie könnten ein Programm schreiben, das auf einem zentralen Gerät läuft, das Ihre Herzfrequenz empfängt und die Lichter rot schaltet, wenn die Herzfrequenz einen bestimmten Schwellenwert überschreitet.

Wenn wir über WebBluetooth sprechen, sprechen wir über einen bestimmten Teil der Bluetooth-Spezifikation namens Generic Attribute Profile, der die sehr offensichtliche Abkürzung GATT trägt. (Anscheinend war GAP bereits vergeben.)

Im Zusammenhang mit GATT sprechen wir nicht mehr von zentralen Geräten und Peripheriegeräten, sondern von Clients und Servern. Ihre Glühbirnen sind Server. Das mag kontraintuitiv erscheinen, aber es macht tatsächlich Sinn, wenn man darüber nachdenkt. Die Glühbirne bietet eine Dienstleistung an, nämlich Licht. Genau wie wenn der Browser eine Verbindung zu einem Server im Internet herstellt, ist Ihr Telefon oder Computer ein Client, der sich mit dem GATT-Server in der Glühbirne verbindet.

Jeder Server bietet einen oder mehrere Dienste an. Einige dieser Dienste sind offiziell Teil des Standards, aber Sie können auch Ihre eigenen definieren. Im Fall des Pulsmessers ist ein offizieller Dienst in der Spezifikation definiert. Im Falle der Glühbirne gibt es das nicht, und so ziemlich jeder Hersteller versucht, das Rad neu zu erfinden. Jeder Dienst hat eine oder mehrere Eigenschaften. Jedes Merkmal hat einen Wert, der gelesen oder geschrieben werden kann. Im Moment ist es am besten, es sich als ein Array von Objekten vorzustellen, wobei jedes Objekt Eigenschaften mit Werten hat.

die Hierarchie von Diensten und Merkmalen im Vergleich zu bekannteren Konstrukten aus JavaScript - ein Server ähnelt einem Array von Objekten, ein Dienst einem Objekt in diesem Array, ein Merkmal einer Eigenschaft dieses Objekts und beide haben Werte
Eine vereinfachte Hierarchie von Diensten und Merkmalen. (Große Vorschau)

Im Gegensatz zu Eigenschaften von Objekten werden die Dienste und Merkmale nicht durch eine Zeichenfolge identifiziert. Jeder Dienst und jede Eigenschaft hat eine eindeutige UUID, die 16 oder 128 Bit lang sein kann. Offiziell ist die 16-Bit-UUID für offizielle Standards reserviert, aber so gut wie niemand hält sich an diese Regel. Schließlich ist jeder Wert ein Array von Bytes. Es gibt keine ausgefallenen Datentypen in Bluetooth.

Ein genauerer Blick auf eine Bluetooth-Glühbirne

Schauen wir uns also ein echtes Bluetooth-Gerät an: eine Mipow Playbulb Sphere. Sie können eine App wie BLE Scanner oder nRF Connect verwenden, um eine Verbindung zum Gerät herzustellen und alle Dienste und Eigenschaften anzuzeigen. In diesem Fall verwende ich die BLE Scanner-App für iOS.

Das erste, was Sie sehen, wenn Sie sich mit der Glühbirne verbinden, ist eine Liste von Diensten. Es gibt einige standardisierte wie den Geräteinformationsdienst und den Batteriedienst. Aber es gibt auch einige kundenspezifische Dienste. Mich interessiert besonders der Dienst mit der 16-Bit-UUID von 0xff0f . Wenn Sie diesen Dienst öffnen, sehen Sie eine lange Liste von Merkmalen. Ich habe keine Ahnung, was die meisten dieser Merkmale bewirken, da sie nur durch eine UUID identifiziert werden und weil sie leider Teil eines benutzerdefinierten Dienstes sind; sie sind nicht standardisiert, und der Hersteller hat keine Dokumentation zur Verfügung gestellt.

Besonders interessant erscheint das erste Merkmal mit der UUID von 0xfffc . Es hat einen Wert von vier Bytes. Wenn wir den Wert dieser Bytes von 0x00000000 auf 0x00ff0000 , wird die Glühbirne rot. Wenn Sie es auf 0x0000ff00 , wird die Glühbirne grün und 0x000000ff blau. Dies sind RGB-Farben und entsprechen genau den Hex-Farben, die wir in HTML und CSS verwenden.

Was macht das erste Byte? Nun, wenn wir den Wert auf 0xff000000 , wird die Glühbirne weiß. Die Glühbirne enthält vier verschiedene LEDs, und indem wir den Wert jedes der vier Bytes ändern, können wir jede einzelne Farbe erzeugen, die wir wollen.

Die WebBluetooth-API

Es ist fantastisch, dass wir eine native App verwenden können, um die Farbe einer Glühbirne zu ändern, aber wie machen wir das vom Browser aus? Es stellt sich heraus, dass dies mit dem gerade erlernten Wissen über Bluetooth und GATT dank der WebBluetooth-API relativ einfach ist. Es dauert nur ein paar Zeilen JavaScript, um die Farbe einer Glühbirne zu ändern.

Lassen Sie uns die WebBluetooth-API durchgehen.

Verbinden mit einem Gerät

Als erstes müssen wir eine Verbindung vom Browser zum Gerät herstellen. Wir rufen die Funktion navigator.bluetooth.requestDevice() auf und stellen der Funktion ein Konfigurationsobjekt zur Verfügung. Dieses Objekt enthält Informationen darüber, welches Gerät wir verwenden möchten und welche Dienste für unsere API verfügbar sein sollen.

Im folgenden Beispiel filtern wir nach dem Namen des Geräts, da wir nur Geräte sehen möchten, die das Präfix PLAYBULB im Namen enthalten. Wir geben auch 0xff0f als Dienst an, den wir verwenden möchten. Da die Funktion requestDevice() ein Promise zurückgibt, können wir das Ergebnis abwarten.

 let device = await navigator.bluetooth.requestDevice({ filters: [ { namePrefix: 'PLAYBULB' } ], optionalServices: [ 0xff0f ] });

Wenn wir diese Funktion aufrufen, erscheint ein Fenster mit der Liste der Geräte, die den von uns angegebenen Filtern entsprechen. Jetzt müssen wir das Gerät, mit dem wir uns verbinden möchten, manuell auswählen. Dies ist ein wesentlicher Schritt für Sicherheit und Datenschutz und gibt dem Benutzer die Kontrolle. Der Benutzer entscheidet, ob sich die Web-App verbinden darf und natürlich mit welchem ​​Gerät sie sich verbinden darf. Die Web-App kann keine Geräteliste abrufen oder eine Verbindung herstellen, ohne dass der Benutzer manuell ein Gerät auswählt.

der Chrome-Browser mit dem Fenster, das der Benutzer verwenden muss, um eine Verbindung zu einem Gerät herzustellen, wobei die Glühbirne in der Liste der Geräte sichtbar ist
Der Benutzer muss manuell eine Verbindung herstellen, indem er ein Gerät auswählt. (Große Vorschau)

Nachdem wir Zugriff auf das Gerät erhalten haben, können wir uns mit dem GATT-Server verbinden, indem wir die Funktion connect() für die Eigenschaft gatt des Geräts aufrufen und auf das Ergebnis warten.

 let server = await device.gatt.connect();

Sobald wir den Server haben, können wir getPrimaryService() auf dem Server mit der UUID des Dienstes aufrufen, den wir als Parameter verwenden möchten, und auf das Ergebnis warten.

 let service = await server.getPrimaryService(0xff0f);

Rufen Sie dann getCharacteristic() auf dem Dienst mit der UUID des Merkmals als Parameter auf und warten Sie erneut auf das Ergebnis.

Wir haben jetzt unsere Eigenschaften, mit denen wir Daten schreiben und lesen können:

 let characteristic = await service.getCharacteristic(0xfffc);

Schreiben von Daten

Um Daten zu schreiben, können wir die Funktion writeValue() für das Merkmal mit dem Wert aufrufen, den wir als ArrayBuffer schreiben möchten, was eine Speichermethode für binäre Daten ist. Der Grund, warum wir kein reguläres Array verwenden können, ist, dass reguläre Arrays Daten verschiedener Typen enthalten und sogar leere Löcher haben können.

Da wir einen ArrayBuffer nicht direkt erstellen oder ändern können, verwenden wir stattdessen ein „typisiertes Array“. Jedes Element eines typisierten Arrays ist immer vom gleichen Typ und hat keine Löcher. In unserem Fall verwenden wir ein Uint8Array , das unsigniert ist und daher keine negativen Zahlen enthalten kann. eine ganze Zahl, kann also keine Brüche enthalten; und es ist 8 Bit und kann nur Werte von 0 bis 255 enthalten. Mit anderen Worten: ein Array von Bytes.

 characteristic.writeValue( new Uint8Array([ 0, r, g, b ]) );

Wir wissen bereits, wie diese spezielle Glühbirne funktioniert. Wir müssen vier Bytes bereitstellen, eines für jede LED. Jedes Byte hat einen Wert zwischen 0 und 255, und in diesem Fall wollen wir nur die roten, grünen und blauen LEDs verwenden, also lassen wir die weiße LED aus, indem wir den Wert 0 verwenden.

Lesen von Daten

Um die aktuelle Farbe der Glühbirne auszulesen, können wir die Funktion readValue() verwenden und auf das Ergebnis warten.

 let value = await characteristic.readValue(); let r = value.getUint8(1); let g = value.getUint8(2); let b = value.getUint8(3);

Der Wert, den wir zurückbekommen, ist ein DataView eines ArrayBuffer und bietet eine Möglichkeit, die Daten aus dem ArrayBuffer zu bekommen. In unserem Fall können wir die Funktion getUint8() mit einem Index als Parameter verwenden, um die einzelnen Bytes aus dem Array herauszuziehen.

Über Änderungen benachrichtigt werden

Schließlich gibt es auch eine Möglichkeit, benachrichtigt zu werden, wenn sich der Wert eines Geräts ändert. Für eine Glühbirne ist das nicht wirklich sinnvoll, aber für unsere Pulsuhr haben wir ständig wechselnde Werte und wollen nicht jede Sekunde den aktuellen Wert manuell abfragen.

 characteristic.addEventListener( 'characteristicvaluechanged', e => { let r = e.target.value.getUint8(1); let g = e.target.value.getUint8(2); let b = e.target.value.getUint8(3); } ); characteristic.startNotifications();

Um einen Rückruf zu erhalten, wenn sich ein Wert ändert, müssen wir die Funktion addEventListener() für das Merkmal mit dem Parameter characteristicvaluechanged und einer Rückruffunktion aufrufen. Immer wenn sich der Wert ändert, wird die Callback-Funktion mit einem Ereignisobjekt als Parameter aufgerufen, und wir können die Daten aus der Eigenschaft value des Ziels des Ereignisses abrufen. Und extrahieren Sie schließlich die einzelnen Bytes wieder aus dem DataView des ArrayBuffer.

Da die Bandbreite im Bluetooth-Netzwerk begrenzt ist, müssen wir diesen Benachrichtigungsmechanismus manuell starten, indem startNotifications() für die Eigenschaft aufrufen. Andernfalls wird das Netzwerk mit unnötigen Daten überschwemmt. Da diese Geräte normalerweise eine Batterie verwenden, wird jedes einzelne Byte, das wir nicht senden müssen, die Batterielebensdauer des Geräts definitiv verbessern, da das interne Funkgerät nicht so oft eingeschaltet werden muss.

Fazit

Wir haben jetzt über 90 % der WebBluetooth-API durchlaufen. Mit nur wenigen Funktionsaufrufen und dem Senden von 4 Bytes können Sie eine Web-App erstellen, die die Farben Ihrer Glühbirnen steuert. Wenn Sie ein paar Zeilen mehr hinzufügen, können Sie sogar ein Spielzeugauto steuern oder eine Drohne fliegen. Da immer mehr Bluetooth-Geräte auf den Markt kommen, sind die Möglichkeiten endlos.

Weitere Ressourcen

  • Bluetooth.rockt! Demos | (Quellcode auf GitHub)
  • „Web-Bluetooth-Spezifikation“, Web-Bluetooth-Community-Gruppe
  • Open GATT Registry Eine inoffizielle Sammlung von Dokumentationen für generische Attributdienste für Bluetooth Low Energy-Geräte.