Kommunikation mit Bluetooth-Geräten über JavaScript

Über die Web Bluetooth API können Websites mit Bluetooth-Geräten kommunizieren.

François Beaufort
François Beaufort

Was wäre, wenn ich dir sagen würde, dass Websites mit Bluetooth-Geräten in der Nähe kommunizieren könnten? auf sichere und datenschutzfreundliche Weise? Auf diese Weise werden die Herzfrequenz überwacht, Glühbirnen und sogar Schildkröten direkt mit einer Website interagieren.

Bisher war es möglich, mit Bluetooth-Geräten zu interagieren. nur für plattformspezifische Apps. Mit der Web Bluetooth API möchten wir auch in Webbrowsern verfügbar.

Bevor es losgeht

In diesem Dokument wird vorausgesetzt, dass Sie Grundkenntnisse über Bluetooth Low haben Energy (BLE) und das allgemeine Attributprofil funktionieren.

Auch wenn die Web Bluetooth API-Spezifikation noch nicht finalisiert ist, Autoren suchen aktiv nach begeisterten Entwicklern, die diese API ausprobieren Gib uns Feedback zur Spezifikation und Feedback zur Implementierung.

Ein Teil der Web Bluetooth API ist in ChromeOS und Chrome für Android verfügbar 6.0, Mac (Chrome 56) und Windows 10 (Chrome 70). Das heißt, Sie sollten um Bluetooth Low Energy-Geräte in der Nähe zu anfragen und verbinden, Bluetooth-Eigenschaften lesen/schreiben, GATT-Benachrichtigungen empfangen, wissen wenn die Verbindung eines Bluetooth-Geräts getrennt wird, und es kann sogar Lese- und Schreibzugriff Bluetooth-Deskriptoren. Weitere Informationen finden Sie in der Tabelle Browserkompatibilität von MDN. Informationen.

Aktivieren Sie für Linux und frühere Windows-Versionen die Flag #experimental-web-platform-features in about://flags.

Verfügbar für Ursprungstests

Um so viel Feedback wie möglich von Entwicklern zu erhalten, die das Web nutzen Bluetooth API im Einsatz, Chrome hat diese Funktion bereits hinzugefügt 53 als Ursprungstest für ChromeOS, Android und Mac.

Der Testzeitraum ist im Januar 2017 abgelaufen.

Sicherheitsanforderungen

Um die Sicherheitsrisiken zu verstehen, empfehle ich den Artikel Web Bluetooth Security Model-Beitrag von Jeffrey Yasskin, Software Engineer im Chrome-Team, die an der Web Bluetooth API-Spezifikation arbeiten.

Nur HTTPS

Da es sich bei diesem experimentellen API um eine leistungsstarke neue Funktion handelt, die im Web hinzugefügt wurde, nur für sichere Kontexte verfügbar gemacht werden. Das bedeutet, dass Sie mit TLS im Hinterkopf.

Nutzergeste erforderlich

Die Erkennung von Bluetooth-Geräten mit navigator.bluetooth.requestDevice muss durch eine Nutzergeste wie als Berührung oder Mausklick. Wir sprechen über das Anhören von pointerup-, click- und touchend-Ereignisse.

button.addEventListener('pointerup', function(event) {
  // Call navigator.bluetooth.requestDevice
});

Code eingeben

Die Web Bluetooth API basiert stark auf JavaScript-Promise-Objekten. Wenn Sie nicht können Sie sich diese Anleitung ansehen. Noch etwas: () => {} sind Pfeilfunktionen aus ECMAScript 2015.

Bluetooth-Geräte anfordern

Diese Version der Web Bluetooth API-Spezifikation ermöglicht Websites, die in die zentrale Rolle haben, um über eine BLE-Verbindung eine Verbindung zu GATT-Remoteservern herzustellen. Es unterstützt die Kommunikation zwischen Geräten, die Bluetooth 4.0 oder höher implementieren.

Wenn eine Website mit der folgenden Methode Zugriff auf Geräte in der Nähe anfordert: navigator.bluetooth.requestDevice – der Browser fordert den Nutzer mit einem Gerät auf über die er ein Gerät auswählen oder die Anfrage abbrechen kann.

Nutzeraufforderung für Bluetooth-Geräte

Die Funktion navigator.bluetooth.requestDevice() verwendet ein obligatorisches Objekt, das Filter definiert. Mit diesen Filtern werden nur Geräte zurückgegeben, die bestimmten beworbene Bluetooth GATT-Dienste und/oder den Gerätenamen.

Filter für Dienste

Beispiel: Für die Anforderung von Bluetooth-Geräten, die das Bluetooth GATT bewerben Batteriebetrieb:

navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => { /* … */ })
.catch(error => { console.error(error); });

Wenn Ihr Bluetooth GATT-Dienst nicht auf der Liste der standardisierten Bluetooth- GATT-Dienste enthalten. Sie können jedoch entweder die vollständige Bluetooth-UUID oder einen kurzen 16- oder 32-Bit-Format.

navigator.bluetooth.requestDevice({
  filters: [{
    services: [0x1234, 0x12345678, '99999999-0000-1000-8000-00805f9b34fb']
  }]
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });

Namensfilter

Sie können auch basierend auf dem beworbenen Gerätenamen Bluetooth-Geräte anfordern. name-Filterschlüssel oder sogar ein Präfix dieses Namens mit namePrefix Filtertaste. Beachten Sie, dass Sie in diesem Fall auch die optionalServices-Schlüssel, um auf alle Dienste zugreifen zu können, die nicht in einem Dienstfilter. Andernfalls erhalten Sie später beim Zugriff auf .

navigator.bluetooth.requestDevice({
  filters: [{
    name: 'Francois robot'
  }],
  optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });

Herstellerdatenfilter

Bluetooth-Geräte können auch auf Basis des Herstellers angefordert werden. Bestimmte Daten, die mit dem Filterschlüssel manufacturerData beworben werden Dieser Schlüssel ist ein Array von Objekten mit einem obligatorischen Bluetooth-Unternehmens-ID-Schlüssel namens companyIdentifier Sie können auch ein Datenpräfix angeben, Herstellerdaten von Bluetooth-Geräten, die damit beginnen. Beachten Sie, dass Sie Außerdem muss der Schlüssel optionalServices definiert werden, um auf Dienste zugreifen zu können nicht in einem Dienstfilter enthalten sind. Andernfalls erhalten Sie später eine Fehlermeldung, versuchen, darauf zuzugreifen.

// 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 einige Muster in Herstellerdaten. Weitere Informationen zu Bluetooth-Datenfiltern mehr.

Ausschlussfilter

Mit der Option exclusionFilters in navigator.bluetooth.requestDevice() können schließen Sie einige Geräte aus der Browserauswahl aus. Damit lassen sich Geräte, die einem weiter gefassten 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); });

Keine Filter anwenden

Schließlich können Sie anstelle von filters die Taste acceptAllDevices verwenden, um alle Bluetooth-Geräten in der Nähe. Sie müssen auch die optionalServices definieren um auf einige Dienste zuzugreifen. Andernfalls erhalten Sie später eine Fehlermeldung. wenn Sie versuchen, darauf zuzugreifen.

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 machen Sie jetzt, nachdem Sie eine BluetoothDevice haben? Verbinden wir uns mit dem Bluetooth-Remote-GATT-Server, der den Dienst und die Eigenschaft enthält Definitionen.

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-Merkmal lesen

Hier wird eine Verbindung zum GATT-Server des Remote-Bluetooth-Geräts hergestellt. Jetzt haben wir einen primären GATT-Dienst abrufen und ein Merkmal lesen möchten, für diesen Dienst. Versuchen wir zum Beispiel, den aktuellen Akkustand des den Akku des Geräts zu laden.

Im folgenden Beispiel steht battery_level für den standardisierten Akkustand Charakteristik.

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 ein benutzerdefiniertes Bluetooth-GATT-Merkmal verwenden, können Sie entweder das vollständige Bluetooth-UUID oder eine kurze 16- oder 32-Bit-Form, service.getCharacteristic

Beachten Sie, dass Sie einem characteristicvaluechanged-Event-Listener auch charakteristisch für das Lesen ihres Werts. Sehen Sie sich die Leseeigenschaften Beispiel für Wertänderung, um zu sehen, wie Sie optional mit dem bevorstehenden GATT umgehen können Benachrichtigungen erhalten.

…
.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 ein Bluetooth-Merkmal schreiben

Das Schreiben in ein Bluetooth GATT-Merkmal ist so einfach wie das Lesen. Dieses Mal den Kontrollpunkt der Herzfrequenz, um den Wert des Energieverbrauchs Feld zur Messung der Herzfrequenz auf 0.

Ich bin mir sicher, dass es hier keine Magie gibt. Diese Funktion wird unter Herzfrequenz-Steuerung Seite „Punkteigenschaften“.

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 nun an, wie du benachrichtigt wirst, wenn die Herzfrequenzmessung Änderungen der Eigenschaften auf dem Gerät:

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
}

Das Benachrichtigungsbeispiel zeigt Ihnen, wie Sie Benachrichtigungen mit stopNotifications() und entfernen Sie die hinzugefügten characteristicvaluechanged ordnungsgemäß. Event-Listener.

Verbindung zu einem Bluetooth-Gerät trennen

Für eine bessere Nutzererfahrung sollten Sie auf Verbindungsabbrüche achten und laden Sie den Nutzer ein, die Verbindung wiederherzustellen:

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() aufrufen, um die Verbindung zwischen Ihrer Web-App und dem Bluetooth-Gerät Dadurch wird das vorhandene gattserverdisconnected-Ereignis ausgelöst zu hören. Beachte, dass die Kommunikation mit dem Bluetooth-Gerät NICHT beendet wird, wenn ein anderes App kommuniziert bereits mit dem Bluetooth-Gerät. Sehen Sie sich das Gerät „Trennen Sample“ und das Automatic Reconnect Sample, um mehr zu erfahren.

Lese- und Schreibzugriff auf Bluetooth-Deskriptoren

Bluetooth GATT-Deskriptoren sind Attribute, die einen charakteristischen Wert beschreiben. Sie können sie ähnlich wie über Bluetooth GATT lesen und schreiben. Eigenschaften.

Sehen wir uns zum Beispiel an, wie die Nutzerbeschreibung Intervall des Gesundheitsthermometers des Geräts.

Im folgenden Beispiel ist health_thermometer der Gesundheitsthermometer-Dienst, measurement_interval das Merkmal des Messintervalls und gatt.characteristic_user_description – Beschreibung des Merkmals für Nutzer Deskriptor.

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 nun die Nutzerbeschreibung des Messintervalls wie Sie es aktualisieren, und erstellen Sie ein benutzerdefiniertes Wert.

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); });

Beispiele, Demos und Codelabs

Alle Web-Bluetooth-Beispiele unten wurden erfolgreich getestet. So genießen Sie diese vollständig analysieren, empfehle ich Ihnen, den [BLE Peripheral Simulator Android-App], die ein BLE-Peripheriegerät mit einem Akkudienst, einer Herzfrequenz oder einen Gesundheitsthermometer-Dienst.

Anfänger

  • Geräteinformationen – Rufen Sie grundlegende Geräteinformationen von einem BLE-Gerät ab.
  • Akkustand: Rufen Sie Informationen zum Akku von einem BLE-Gerät ab, das Akkuinformationen bewirbt.
  • Energie zurücksetzen: Setzen Sie den Energieverbrauch eines BLE-Geräts zurück, mit dem die Herzfrequenz angezeigt wird.
  • Merkmalseigenschaften - zeigen alle Eigenschaften einer bestimmten Eigenschaft eines BLE-Geräts an.
  • Benachrichtigungen – Benachrichtigungen zu Eigenschaften von einem BLE-Gerät starten und stoppen
  • Verbindung des Geräts getrennt: Wenn die Verbindung zu einem BLE-Gerät getrennt wurde, wird eine Benachrichtigung gesendet.
  • Eigenschaften abrufen: Rufen Sie alle Merkmale eines beworbenen Dienstes von einem BLE-Gerät ab.
  • Deskriptoren abrufen – alle Eigenschaften abrufen Beschreibungen eines beworbenen Dienstes von einem BLE-Gerät aus.
  • Manufacturer Data Filter (Herstellerdatenfilter): Hiermit können grundlegende Geräteinformationen von einem BLE-Gerät abgerufen werden, die mit den Herstellerdaten übereinstimmen.
  • Ausschlussfilter: Rufen Sie grundlegende Geräteinformationen von einem BLE-Gerät mit einfachen Ausschlussfiltern ab.

Mehrere Vorgänge kombinieren

  • GAP-Eigenschaften: Rufen Sie alle GAP-Eigenschaften eines BLE-Geräts ab.
  • Geräteinformationsmerkmale: Rufen Sie alle Eigenschaften der Geräteinformationen eines BLE-Geräts ab.
  • Link Loss (Linkverlust): Legen Sie die Eigenschaft der Warnungsebene eines BLE-Geräts fest (readValue und writeValue).
  • Dienste entdecken und Merkmale – Hier können Sie alle zugänglichen primären Dienste und ihre Merkmale von einem BLE-Gerät ausfindig machen.
  • Automatisch neu verbinden: Stellen Sie mithilfe eines exponentiellen Backoff-Algorithmus eine neue Verbindung zu einem nicht verbundenen BLE-Gerät her.
  • Leseeigenschaftswert geändert – Der Akkustand wird gelesen und Sie werden bei Änderungen durch ein BLE-Gerät benachrichtigt.
  • Deskriptoren lesen: Lesen aller Merkmalsdeskriptoren eines Dienstes aus einem BLE-Gerät.
  • Deskriptor schreiben: Schreiben Sie in den Deskriptor "Characteristic User Description" (Merkmalsbeschreibung für den Nutzer). auf einem BLE-Gerät.

Außerdem kannst du dir unsere ausgewählten Web Bluetooth-Demos und offiziellen Web Bluetooth-Codelabs ansehen.

Bibliotheken

  • web-bluetooth-utils ist ein npm-Modul, das die API verwenden.
  • Ein Web Bluetooth API-Shim ist in noble verfügbar, dem beliebtesten Node.js-BLE zentrales Modul. So kannst du Noise ohne zusätzlichen für einen WebSocket-Server oder andere Plug-ins.
  • angular-web-bluetooth ist ein Modul von Angular, das alle Boilerplate, der zum Konfigurieren der Web Bluetooth API erforderlich ist.

Tools

  • Erste Schritte mit Web Bluetooth ist eine einfache Web-App, die alle um mit einem Bluetooth-Gerät zu interagieren. Geben Sie einen Gerätenamen, einen Dienst, ein Merkmal ein, definieren Sie seine Eigenschaften und schon kann es losgehen.
  • Wenn Sie bereits Bluetooth-Entwickler sind, zeigt das Web Bluetooth Developer Studio Das Plug-in generiert auch den Web Bluetooth-JavaScript-Code für Ihr Bluetooth-Gerät

Tipps

Die Seite Bluetooth Internals ist in Chrome unter about://bluetooth-internals, damit du alles in der Nähe prüfen kannst Bluetooth-Geräte: Status, Dienste, Eigenschaften und Beschreibungen.

Screenshot der internen Seite zum Debuggen von Bluetooth in Chrome
Interne Seite in Chrome zum Debuggen von Bluetooth-Geräten.

Außerdem solltest du dir die offiziellen Informationen zum Melden von Web Bluetooth-Fehlern ansehen. da die Bluetooth-Fehlerbehebung manchmal schwierig sein kann.

Nächste Schritte

Prüfen Sie zuerst den Implementierungsstatus des Browsers und der Plattform, um herauszufinden, welche Teile davon betroffen sind. der Web Bluetooth API werden derzeit implementiert.

Hier ist ein kleiner Vorgeschmack, was dich demnächst erwartet Zukunft:

  • Nach BLE-Werbung in der Nähe suchen mit navigator.bluetooth.requestLEScan().
  • Ein neues serviceadded-Ereignis erfasst neu erkannte Bluetooth-GATT-Dienste während serviceremoved entfernte Ereignisse erfasst. Ein neues servicechanged wird ausgelöst, wenn ein Merkmal und/oder eine Beschreibung aus einem Bluetooth GATT-Dienst entfernt wurden.

Unterstützung für die API anzeigen

Möchten Sie die Web Bluetooth API verwenden? Ihre öffentliche Unterstützung hilft dem Chrome-Team Funktionen priorisieren und anderen Browseranbietern zeigen, wie wichtig es für ihre Unterstützung ist.

Sende einen Tweet mit dem Hashtag an @ChromiumDev #WebBluetooth und teilen Sie uns mit, wo und wie Sie sie nutzen.

Ressourcen

Danksagungen

Vielen Dank an Kayce Basques für die Rezension dieses Artikels. Hero-Image von SparkFun Electronics aus Boulder, USA.