Die Web Bluetooth API ermöglicht es Websites, mit Bluetooth-Geräten zu kommunizieren.
Was wäre, wenn ich Ihnen sagen würde, dass Websites auf sichere und datenschutzfreundliche Weise mit Bluetooth-Geräten in der Nähe kommunizieren könnten? So können Herzfrequenzmesser, singende Glühbirnen und sogar Schildkröten direkt mit einer Website interagieren.
Bisher war die Interaktion mit Bluetooth-Geräten nur für plattformspezifische Apps möglich. Die Web Bluetooth API soll dies ändern und wird auch für Webbrowser eingeführt.
Bevor es losgeht
In diesem Dokument wird davon ausgegangen, dass Sie Grundkenntnisse zur Funktionsweise von Bluetooth Low Energy (BLE) und dem Generic Attribute Profile haben.
Auch wenn die Web Bluetooth API-Spezifikation noch nicht fertig ist, suchen die Autoren der Spezifikation aktiv nach begeisterten Entwicklern, die diese API ausprobieren und Feedback zur Spezifikation und Feedback zur Implementierung geben.
Ein Teil der Web Bluetooth API ist in ChromeOS, Chrome für Android 6.0, Mac (Chrome 56) und Windows 10 (Chrome 70) verfügbar. Das bedeutet, dass Sie in der Lage sein sollten, Bluetooth Low Energy-Geräte in der Nähe anzufordern und zu verbinden, Bluetooth-Attribute zu lesen/zu schreiben, GATT-Benachrichtigungen zu empfangen, zu erkennen, wann eine Bluetooth-Verbindung getrennt wird, und sogar Bluetooth-Beschreibungen zu lesen und zu schreiben. Weitere Informationen finden Sie in der Tabelle Browserkompatibilität der MDN.
Aktivieren Sie unter Linux und früheren Windows-Versionen das Flag #experimental-web-platform-features
in about://flags
.
Verfügbar für Ursprungstests
Um möglichst viel Feedback von Entwicklern zu erhalten, die die Web Bluetooth API in der Praxis verwenden, wurde diese Funktion in Chrome 53 als Origin Trial für ChromeOS, Android und Mac hinzugefügt.
Der Test wurde im Januar 2017 erfolgreich abgeschlossen.
Sicherheitsanforderungen
Wenn Sie mehr über die Sicherheitsabwägungen erfahren möchten, empfehle ich den Artikel Web Bluetooth Security Model von Jeffrey Yasskin, einem Softwareentwickler im Chrome-Team, der an der Web Bluetooth API-Spezifikation arbeitet.
Nur HTTPS
Da diese experimentelle API eine leistungsstarke neue Funktion für das Web ist, wird sie nur für sichere Kontexte verfügbar gemacht. Das bedeutet, dass Sie Ihre App mit TLS entwickeln müssen.
Nutzergeste erforderlich
Aus Sicherheitsgründen muss die Suche nach Bluetooth-Geräten mit navigator.bluetooth.requestDevice
durch eine Nutzergeste wie ein Tippen oder Mausklick ausgelöst werden. Es geht um das Überwachen von pointerup
-, click
- und touchend
-Ereignissen.
button.addEventListener('pointerup', function(event) {
// Call navigator.bluetooth.requestDevice
});
Code
Die Web Bluetooth API setzt stark auf JavaScript-Promises. Wenn Sie mit Promises nicht vertraut sind, sehen Sie sich dieses Tutorial zu Promises an. Noch etwas: () => {}
sind ECMAScript 2015-Funktionen.
Bluetooth-Geräte anfordern
Mit dieser Version der Web Bluetooth API-Spezifikation können Websites, die in der Rolle „Zentrale“ ausgeführt werden, über eine BLE-Verbindung eine Verbindung zu Remote-GATT-Servern herstellen. Sie unterstützt die Kommunikation zwischen Geräten, die Bluetooth 4.0 oder höher implementieren.
Wenn eine Website über navigator.bluetooth.requestDevice
Zugriff auf Geräte in der Nähe anfordert, wird der Nutzer vom Browser aufgefordert, ein Gerät auszuwählen oder die Anfrage abzubrechen.
Für die Funktion navigator.bluetooth.requestDevice()
ist ein obligatorisches Objekt erforderlich, das Filter definiert. Mit diesen Filtern werden nur Geräte zurückgegeben, die mit einigen beworbenen Bluetooth-GATT-Diensten und/oder dem Gerätenamen übereinstimmen.
Dienstfilter
So fordern Sie beispielsweise Bluetooth-Geräte an, die den Bluetooth GATT-Akkudienst anbieten:
navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Wenn sich Ihr Bluetooth-GATT-Dienst jedoch nicht in der Liste der standardisierten Bluetooth-GATT-Dienste befindet, können Sie entweder die vollständige Bluetooth-UUID oder eine kurze 16- oder 32-Bit-Form angeben.
navigator.bluetooth.requestDevice({
filters: [{
services: [0x1234, 0x12345678, '99999999-0000-1000-8000-00805f9b34fb']
}]
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Name filter
Sie können Bluetooth-Geräte auch anhand des angegebenen Gerätenamens mit dem Filterschlüssel name
oder sogar eines Präfixes dieses Namens mit dem Filterschlüssel namePrefix
anfordern. In diesem Fall müssen Sie auch den Schlüssel optionalServices
definieren, um auf Dienste zugreifen zu können, die nicht in einem Dienstfilter enthalten sind. Andernfalls wird beim Zugriff auf die Daten später eine Fehlermeldung angezeigt.
navigator.bluetooth.requestDevice({
filters: [{
name: 'Francois robot'
}],
optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Herstellerdatenfilter
Es ist auch möglich, Bluetooth-Geräte anhand der herstellerspezifischen Daten anzufordern, die mit dem Filterschlüssel manufacturerData
beworben werden. Dieser Schlüssel ist ein Array von Objekten mit einem obligatorischen Schlüssel Bluetooth-Unternehmenskennung mit dem Namen companyIdentifier
. Sie können auch ein Datenpräfix angeben, mit dem Herstellerdaten von Bluetooth-Geräten gefiltert werden, die damit beginnen. Sie müssen auch den Schlüssel optionalServices
definieren, um auf Dienste zugreifen zu können, die nicht in einem Dienstfilter enthalten sind. Andernfalls erhalten Sie später beim Zugriff auf die Dateien eine Fehlermeldung.
// Filter Bluetooth devices from Google company with manufacturer data bytes
// that start with [0x01, 0x02].
navigator.bluetooth.requestDevice({
filters: [{
manufacturerData: [{
companyIdentifier: 0x00e0,
dataPrefix: new Uint8Array([0x01, 0x02])
}]
}],
optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Eine Maske kann auch mit einem Datenpräfix verwendet werden, um bestimmte Muster in Herstellerdaten abzugleichen. Weitere Informationen finden Sie im Hilfeartikel Erläuterung zu Bluetooth-Datenfiltern.
Ausschlussfilter
Mit der Option exclusionFilters
in navigator.bluetooth.requestDevice()
können Sie einige Geräte von der Browserauswahl ausschließen. Damit können Geräte ausgeschlossen werden, die zwar einem umfassenderen Filter entsprechen, aber nicht unterstützt werden.
// Request access to a bluetooth device whose name starts with "Created by".
// The device named "Created by Francois" has been reported as unsupported.
navigator.bluetooth.requestDevice({
filters: [{
namePrefix: "Created by"
}],
exclusionFilters: [{
name: "Created by Francois"
}],
optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Ohne Filter
Stattdessen können Sie die Taste acceptAllDevices
verwenden, um alle Bluetooth-Geräte in der Nähe anzeigen zu lassen.filters
Außerdem müssen Sie den Schlüssel optionalServices
definieren, um auf einige Dienste zugreifen zu können. Andernfalls erhalten Sie später beim Zugriff auf die Dateien eine Fehlermeldung.
navigator.bluetooth.requestDevice({
acceptAllDevices: true,
optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Herstellen von Verbindungen zu Bluetooth-Geräten
Was tun Sie jetzt, nachdem Sie eine BluetoothDevice
haben? Stellen Sie eine Verbindung zum Bluetooth-Remote-GATT-Server her, der die Dienst- und Eigenschaftendefinitionen enthält.
navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => {
// Human-readable name of the device.
console.log(device.name);
// Attempts to connect to remote GATT Server.
return device.gatt.connect();
})
.then(server => { /* … */ })
.catch(error => { console.error(error); });
Bluetooth-Attribut lesen
Hier stellen wir eine Verbindung zum GATT-Server des Remote-Bluetooth-Geräts her. Jetzt möchten wir einen primären GATT-Dienst abrufen und ein Attribut lesen, das zu diesem Dienst gehört. Versuchen wir beispielsweise, den aktuellen Akkustand des Geräts abzurufen.
Im folgenden Beispiel ist battery_level
die standardisierte Akkustand-Eigenschaft.
navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => device.gatt.connect())
.then(server => {
// Getting Battery Service…
return server.getPrimaryService('battery_service');
})
.then(service => {
// Getting Battery Level Characteristic…
return service.getCharacteristic('battery_level');
})
.then(characteristic => {
// Reading Battery Level…
return characteristic.readValue();
})
.then(value => {
console.log(`Battery percentage is ${value.getUint8(0)}`);
})
.catch(error => { console.error(error); });
Wenn Sie eine benutzerdefinierte Bluetooth-GATT-Eigenschaft verwenden, können Sie für service.getCharacteristic
entweder die vollständige Bluetooth-UUID oder eine kurze 16- oder 32-Bit-Form angeben.
Sie können auch einen characteristicvaluechanged
-Ereignis-Listener für ein Attribut hinzufügen, um den Wert abzurufen. Im Beispiel Wert der Eigenschaft „Read Characteristic“ geändert erfahren Sie, wie Sie optional auch anstehende GATT-Benachrichtigungen verarbeiten.
…
.then(characteristic => {
// Set up event listener for when characteristic value changes.
characteristic.addEventListener('characteristicvaluechanged',
handleBatteryLevelChanged);
// Reading Battery Level…
return characteristic.readValue();
})
.catch(error => { console.error(error); });
function handleBatteryLevelChanged(event) {
const batteryLevel = event.target.value.getUint8(0);
console.log('Battery percentage is ' + batteryLevel);
}
In eine Bluetooth-Eigenschaft schreiben
Das Schreiben in eine Bluetooth-GATT-Eigenschaft ist genauso einfach wie das Lesen. Verwenden wir diesmal den Kontrollpunkt „Herzfrequenz“, um den Wert des Felds „Verbostene Energie“ auf einem Herzfrequenzmesser auf 0 zurückzusetzen.
Ich verspreche, dass hier keine Magie im Spiel ist. Weitere Informationen finden Sie auf der Seite Punkteigenschaft „Herzfrequenzsteuerung“.
navigator.bluetooth.requestDevice({ filters: [{ services: ['heart_rate'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('heart_rate'))
.then(service => service.getCharacteristic('heart_rate_control_point'))
.then(characteristic => {
// Writing 1 is the signal to reset energy expended.
const resetEnergyExpended = Uint8Array.of(1);
return characteristic.writeValue(resetEnergyExpended);
})
.then(_ => {
console.log('Energy expended has been reset.');
})
.catch(error => { console.error(error); });
GATT-Benachrichtigungen erhalten
Sehen wir uns an, wie Sie benachrichtigt werden, wenn sich das Merkmal „Herzfrequenzmessung“ auf dem Gerät ändert:
navigator.bluetooth.requestDevice({ filters: [{ services: ['heart_rate'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('heart_rate'))
.then(service => service.getCharacteristic('heart_rate_measurement'))
.then(characteristic => characteristic.startNotifications())
.then(characteristic => {
characteristic.addEventListener('characteristicvaluechanged',
handleCharacteristicValueChanged);
console.log('Notifications have been started.');
})
.catch(error => { console.error(error); });
function handleCharacteristicValueChanged(event) {
const value = event.target.value;
console.log('Received ' + value);
// TODO: Parse Heart Rate Measurement value.
// See https://github.com/WebBluetoothCG/demos/blob/gh-pages/heart-rate-sensor/heartRateSensor.js
}
Im Beispiel für Benachrichtigungen wird gezeigt, wie Sie Benachrichtigungen mit stopNotifications()
beenden und den hinzugefügten characteristicvaluechanged
-Ereignis-Listener ordnungsgemäß entfernen.
Verbindung zu einem Bluetooth-Gerät trennen
Für eine bessere Nutzerfreundlichkeit solltest du auf Verbindungsunterbrechungen achten und den Nutzer auffordern, sich wieder zu verbinden:
navigator.bluetooth.requestDevice({ filters: [{ name: 'Francois robot' }] })
.then(device => {
// Set up event listener for when device gets disconnected.
device.addEventListener('gattserverdisconnected', onDisconnected);
// Attempts to connect to remote GATT Server.
return device.gatt.connect();
})
.then(server => { /* … */ })
.catch(error => { console.error(error); });
function onDisconnected(event) {
const device = event.target;
console.log(`Device ${device.name} is disconnected.`);
}
Sie können auch device.gatt.disconnect()
eingeben, um die Verbindung Ihrer Webanwendung mit dem Bluetooth-Gerät zu trennen. Dadurch werden vorhandene gattserverdisconnected
-Ereignis-Listener ausgelöst. Hinweis: Die Bluetooth-Kommunikation wird NICHT beendet, wenn bereits eine andere App mit dem Bluetooth-Gerät kommuniziert. Weitere Informationen finden Sie in den Beispielen DeviceDisconnect und AutomaticReconnect.
Bluetooth-Beschreibungen lesen und schreiben
Bluetooth-GATT-Deskriptoren sind Attribute, die einen charakteristischen Wert beschreiben. Sie können sie ähnlich wie Bluetooth-GATT-Attribute lesen und darauf schreiben.
Sehen wir uns beispielsweise an, wie Sie die Nutzerbeschreibung des Messintervalls des Gerätestatus-Thermometers lesen.
Im folgenden Beispiel ist health_thermometer
der Gesundheitsthermometer-Dienst, measurement_interval
das Messintervall-Attribut und gatt.characteristic_user_description
der Beschreibungs-Descriptor für das Nutzerattribut.
navigator.bluetooth.requestDevice({ filters: [{ services: ['health_thermometer'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('health_thermometer'))
.then(service => service.getCharacteristic('measurement_interval'))
.then(characteristic => characteristic.getDescriptor('gatt.characteristic_user_description'))
.then(descriptor => descriptor.readValue())
.then(value => {
const decoder = new TextDecoder('utf-8');
console.log(`User Description: ${decoder.decode(value)}`);
})
.catch(error => { console.error(error); });
Nachdem wir die Beschreibung des Nutzers für das Messintervall des Gesundheitsthermometers des Geräts gelesen haben, sehen wir uns an, wie Sie es aktualisieren und einen benutzerdefinierten Wert schreiben.
navigator.bluetooth.requestDevice({ filters: [{ services: ['health_thermometer'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('health_thermometer'))
.then(service => service.getCharacteristic('measurement_interval'))
.then(characteristic => characteristic.getDescriptor('gatt.characteristic_user_description'))
.then(descriptor => {
const encoder = new TextEncoder('utf-8');
const userDescription = encoder.encode('Defines the time between measurements.');
return descriptor.writeValue(userDescription);
})
.catch(error => { console.error(error); });
Samples, Demos und Codelabs
Alle folgenden Web Bluetooth-Beispiele wurden erfolgreich getestet. Damit Sie diese Samples optimal nutzen können, empfehle ich Ihnen, die [BLE Peripheral Simulator Android App] zu installieren. Diese App simuliert ein BLE-Peripheriegerät mit einem Akkudienst, einem Herzfrequenzdienst oder einem Gesundheitsthermometerdienst.
Anfänger
- Geräteinformationen: Hiermit können Sie grundlegende Geräteinformationen von einem BLE-Gerät abrufen.
- Akkustand: Akkuinformationen von einem BLE-Gerät abrufen, das Akkuinformationen sendet.
- Energie zurücksetzen: Energie, die von einem BLE-Gerät verbraucht wurde, das die Herzfrequenz sendet, zurücksetzen.
- Eigenschaften der Merkmale: Hier werden alle Eigenschaften eines bestimmten Merkmals eines BLE-Geräts angezeigt.
- Benachrichtigungen: Sie können damit Eigenschaftenbenachrichtigungen von einem BLE-Gerät starten und beenden.
- Device Disconnect: Sie können die Verbindung zu einem BLE-Gerät trennen und sich benachrichtigen lassen, wenn die Verbindung getrennt wird.
- Get Characteristics (Eigenschaften abrufen): Hiermit werden alle Eigenschaften eines beworbenen Dienstes von einem BLE-Gerät abgerufen.
- Descriptors abrufen: Hiermit werden alle Descriptors der Eigenschaften eines beworbenen Dienstes von einem BLE-Gerät abgerufen.
- Herstellerdatenfilter: Hiermit werden grundlegende Geräteinformationen von einem BLE-Gerät abgerufen, die mit den Herstellerdaten übereinstimmen.
- Ausschlussfilter: Hiermit können Sie grundlegende Geräteinformationen von einem BLE-Gerät mit einfachen Ausschlussfiltern abrufen.
Mehrere Vorgänge kombinieren
- GAP-Eigenschaften: Hiermit werden alle GAP-Eigenschaften eines BLE-Geräts abgerufen.
- Geräteinformationen-Eigenschaften: Hiermit werden alle Geräteinformationen-Eigenschaften eines BLE-Geräts abgerufen.
- Link Loss: Legen Sie das Attribut „Alert Level“ eines BLE-Geräts fest (readValue und writeValue).
- Dienste und Eigenschaften ermitteln: Hiermit können Sie alle zugänglichen primären Dienste und ihre Eigenschaften von einem BLE-Gerät ermitteln.
- Automatische Wiederverbindung: Mit einem exponentiellen Backoff-Algorithmus wird eine Verbindung zu einem getrennten BLE-Gerät wiederhergestellt.
- Read Characteristic Value Changed (Wert der Eigenschaft wurde geändert lesen): Sie können den Akkustand lesen und über Änderungen von einem BLE-Gerät benachrichtigt werden.
- Descriptors lesen: Liest alle Descriptors der Merkmale eines Dienstes von einem BLE-Gerät.
- Write Descriptor: Schreibt auf dem BLE-Gerät in den Descriptor „Characteristic User Description“.
Sehen Sie sich auch unsere ausgewählten Web Bluetooth-Demos und offiziellen Web Bluetooth-Codelabs an.
Bibliotheken
- web-bluetooth-utils ist ein npm-Modul, das der API einige praktische Funktionen hinzufügt.
- Ein Web Bluetooth API-Shim ist in noble verfügbar, dem beliebtesten Node.js-BLE-Zentralmodul. So kannst du Noble mit Webpack/Browserify kompilieren, ohne einen WebSocket-Server oder andere Plug-ins zu benötigen.
- angular-web-bluetooth ist ein Modul für Angular, das die gesamte Boilerplate abstrahiert, die zum Konfigurieren der Web Bluetooth API erforderlich ist.
Tools
- Erste Schritte mit Web Bluetooth ist eine einfache Webanwendung, die den gesamten JavaScript-Boilerplate-Code generiert, um mit einem Bluetooth-Gerät zu interagieren. Geben Sie einen Gerätenamen, einen Dienst und ein Merkmal ein, definieren Sie die Eigenschaften und schon ist alles bereit.
- Wenn Sie bereits Bluetooth-Entwickler sind, generiert das Web Bluetooth Developer Studio-Plug-in auch den Web Bluetooth-JavaScript-Code für Ihr Bluetooth-Gerät.
Tipps
In Chrome ist unter about://bluetooth-internals
die Seite Bluetooth Internals verfügbar. Dort finden Sie alle Informationen zu Bluetooth-Geräten in der Nähe: Status, Dienste, Eigenschaften und Descriptors.
Außerdem empfehle ich Ihnen, sich die offizielle Seite So melden Sie Bluetooth-Fehler im Web anzusehen, da die Fehlerbehebung bei Bluetooth manchmal schwierig sein kann.
Nächste Schritte
Prüfen Sie zuerst den Implementierungsstatus von Browser und Plattform, um zu erfahren, welche Teile der Web Bluetooth API derzeit implementiert werden.
Die Funktion ist noch nicht vollständig, aber hier ist schon mal ein kleiner Vorgeschmack auf die nächsten Schritte:
navigator.bluetooth.requestLEScan()
sucht nach BLE-Werbung in der Nähe.- Ein neues
serviceadded
-Ereignis erfasst neu erkannte Bluetooth-GATT-Dienste, während dasserviceremoved
-Ereignis entfernte Dienste erfasst. Ein neuesservicechanged
-Ereignis wird ausgelöst, wenn einer Eigenschaft und/oder einem Descriptor ein Bluetooth-GATT-Dienst hinzugefügt oder daraus entfernt wird.
Unterstützung für die API anzeigen
Beabsichtigen Sie, die Web Bluetooth API zu verwenden? Ihre öffentliche Unterstützung hilft dem Chrome-Team, Funktionen zu priorisieren, und zeigt anderen Browseranbietern, wie wichtig es ist, sie zu unterstützen.
Senden Sie einen Tweet an @ChromiumDev mit dem Hashtag #WebBluetooth
und teilen Sie uns mit, wo und wie Sie ihn verwenden.
Ressourcen
- Stack Overflow
- Status von Chrome-Funktionen
- Fehler bei der Chrome-Implementierung
- Web Bluetooth-Spezifikation
- Probleme mit Spezifikationen auf GitHub
- BLE Peripheral Simulator App
Danksagungen
Vielen Dank an Kayce Basques für die Überprüfung dieses Artikels. Hero-Image von SparkFun Electronics aus Boulder, USA.