Communiquer avec des appareils Bluetooth via JavaScript

L'API Web Bluetooth permet aux sites Web de communiquer avec des appareils Bluetooth.

François Beaufort
François Beaufort

Et si je vous disais que les sites Web pouvaient communiquer avec les appareils Bluetooth à proximité de manière sécurisée et en protégeant la confidentialité ? De cette façon, les cardiofréquencemètres, le chant des ampoules et même des tortues peuvent interagir directement avec un site Web.

Jusqu'à présent, il était possible d'interagir avec les appareils Bluetooth uniquement pour les applications spécifiques à une plate-forme. L'API Web Bluetooth vise à changer cela et les apporte également aux navigateurs Web.

Avant de commencer

Dans ce document, nous partons du principe que vous avez des connaissances de base sur le fonctionnement de la technologie Bluetooth Low La consommation d'énergie (BLE) et le profil d'attribut générique fonctionnent.

Même si les spécifications de l'API Web Bluetooth ne sont pas encore finalisées, leurs spécifications recherchent activement des développeurs enthousiastes pour essayer cette API et Envoyez des commentaires sur les spécifications et sur l'implémentation.

Un sous-ensemble de l'API Web Bluetooth est disponible dans ChromeOS, Chrome pour Android 6.0, Mac (Chrome 56) et Windows 10 (Chrome 70). Cela signifie que vous devriez être en mesure pour demander des appareils Bluetooth à basse consommation à proximité et vous y connecter, lecture/écriture des caractéristiques Bluetooth, recevoir les notifications GATT, lorsqu'un appareil Bluetooth est déconnecté, et même lire et écrire sur Descripteurs Bluetooth. Pour en savoir plus, consultez le tableau Compatibilité des navigateurs de MDN des informations.

Pour Linux et les versions antérieures de Windows, activez le L'indicateur #experimental-web-platform-features dans about://flags.

Disponible pour les phases d'évaluation

Pour obtenir un maximum de commentaires de la part des développeurs API Bluetooth dans le champ, Chrome a déjà ajouté cette fonctionnalité dans Chrome 53 en tant que phase d'évaluation pour ChromeOS, Android et Mac.

L'essai a pris fin en janvier 2017.

Exigences de sécurité

Pour bien comprendre les compromis en termes de sécurité, je vous recommande de consulter le guide Web Bluetooth Security de Jeffrey Yasskin, ingénieur logiciel dans l'équipe Chrome, je travaille sur la spécification de l'API Web Bluetooth.

HTTPS uniquement

Cette API expérimentale est une nouvelle fonctionnalité puissante ajoutée au Web. disponibles uniquement dans les contextes sécurisés. Cela signifie que vous devrez construire avec TLS à l'esprit.

Geste de l'utilisateur requis

Par mesure de sécurité, la découverte de périphériques Bluetooth avec navigator.bluetooth.requestDevice doit être déclenché par un geste de l'utilisateur tel que comme une pression ou un clic de souris. Nous parlons d’écouter Événements pointerup, click et touchend.

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

Découvrir le code

L'API Web Bluetooth s'appuie fortement sur les promesses JavaScript. Si vous n'êtes pas que vous ne les connaissez pas, consultez cet excellent tutoriel sur les promesses. Une dernière chose : () => {} sont des fonctions fléchées d'ECMAScript 2015.

Demander des appareils Bluetooth

Cette version de la spécification de l'API Web Bluetooth autorise les sites Web s'exécutant dans le rôle central, pour se connecter aux serveurs GATT distants via une connexion BLE. Il prend en charge la communication entre les appareils qui implémentent le Bluetooth 4.0 ou version ultérieure.

Lorsqu'un site Web demande l'accès à des appareils à proximité à l'aide de navigator.bluetooth.requestDevice : le navigateur invite l'utilisateur à fournir un appareil. qui leur permet de choisir un appareil ou d'annuler la demande.

<ph type="x-smartling-placeholder">
</ph>
Invite de l'utilisateur d'un appareil Bluetooth.

La fonction navigator.bluetooth.requestDevice() utilise un objet obligatoire qui définit des filtres. Ces filtres sont utilisés pour afficher uniquement les appareils correspondant à certains les services Bluetooth GATT annoncés et/ou le nom de l'appareil.

Filtre de services

Par exemple, pour demander des appareils Bluetooth faisant la promotion de l'API Bluetooth GATT Service de la batterie:

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

Si votre service Bluetooth GATT ne figure pas sur la liste des appareils Bluetooth standardisés services GATT, vous pouvez fournir soit l'UUID Bluetooth complet, soit un court Format 16 ou 32 bits.

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

Filtre par nom

Vous pouvez également demander des appareils Bluetooth en fonction du nom d'appareil annoncé. avec la clé de filtres name, ou même un préfixe de ce nom avec le namePrefix . Notez que dans ce cas, vous devez également définir optionalServices pour pouvoir accéder aux services non inclus dans un filtre de service. Sinon, un message d'erreur s'affichera lorsque vous tenterez d'accéder de l'IA générative.

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

Filtre des données du fabricant

Il est également possible de demander des appareils Bluetooth en fonction du fabricant. des données spécifiques annoncées avec la clé de filtres manufacturerData. Cette clé est un tableau d'objets avec une clé d'identifiant d'entreprise Bluetooth obligatoire, nommée companyIdentifier Vous pouvez également fournir un préfixe de données qui filtre les données du fabricant des périphériques Bluetooth qui commencent par elle. Notez que vous devrez doivent également définir la clé optionalServices pour pouvoir accéder à tous les services non incluses dans un filtre de service. Sinon, un message d'erreur s'affichera lorsque pour tenter d'y accéder.

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

Un masque peut également être utilisé avec un préfixe de données pour correspondre à certains modèles dans les données du fabricant. Consultez l'explication sur les filtres de données Bluetooth pour en savoir plus. plus encore.

Filtres d'exclusion

L'option exclusionFilters dans navigator.bluetooth.requestDevice() permet vous excluez certains appareils du sélecteur de navigateur. Il peut être utilisé pour exclure appareils qui correspondent à un filtre plus large, mais qui ne sont pas compatibles.

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

Évitez les filtres

Enfin, au lieu de filters, vous pouvez utiliser la touche acceptAllDevices pour afficher appareils Bluetooth à proximité. Vous devez également définir optionalServices pour accéder à certains services. Sinon, un message d'erreur s'affichera plus tard lorsque vous essayez d'y accéder.

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

Se connecter à un appareil Bluetooth

Que faire maintenant que vous disposez d'un BluetoothDevice ? Connectons-nous Serveur GATT distant Bluetooth, qui contient le service et la caractéristique et définitions.

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

Lire une caractéristique Bluetooth

Ici, nous nous connectons au serveur GATT de l'appareil Bluetooth distant. Maintenant, voulez obtenir un service GATT principal et lire une caractéristique appartenant à ce service. Essayons, par exemple, de lire le niveau de charge actuel la batterie de votre appareil.

Dans l'exemple qui suit, battery_level correspond au niveau de batterie standardisé. Caractéristique.

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

Si vous utilisez une caractéristique Bluetooth GATT personnalisée, vous pouvez indiquer un UUID complet Bluetooth ou une version courte de 16 ou 32 bits pour service.getCharacteristic

Notez que vous pouvez également ajouter un écouteur d'événements characteristicvaluechanged sur une pour gérer la lecture de sa valeur. Vérifiez la caractéristique de lecture Exemple de valeur modifiée pour voir comment gérer éventuellement la prochaine session GATT des notifications.

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

Écrire à une caractéristique Bluetooth

Écrire sur une caractéristique GATT Bluetooth est aussi facile que de le lire. Cette fois, utilisons le point de contrôle de la fréquence cardiaque pour réinitialiser la valeur de l'énergie dépensée sur 0 sur un moniteur de fréquence cardiaque.

Je vous garantis qu'il n'y a pas de magie dans ce cas. Tout est expliqué dans la section Contrôle de la fréquence cardiaque Page de caractéristiques du point.

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

Recevoir des notifications GATT

Voyons maintenant comment être averti lorsque la mesure de la fréquence cardiaque changements caractéristiques sur l’appareil:

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
}

L'onglet Notifications Sample vous montre comment arrêter les notifications avec stopNotifications() et supprimez correctement la characteristicvaluechanged ajoutée écouteur d'événements.

Se déconnecter d'un appareil Bluetooth

Pour améliorer l'expérience utilisateur, vous pouvez écouter les événements de déconnexion et invitez l'utilisateur à se reconnecter:

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

Vous pouvez également appeler device.gatt.disconnect() pour déconnecter votre application Web de la Appareil Bluetooth. Cela déclenchera l'événement gattserverdisconnected existant pour les auditeurs. Notez que cela n'interrompt PAS la communication de l'appareil Bluetooth si l'application communique déjà avec l'appareil Bluetooth. Découvrez l'Appareil Dissociez l'échantillon et l'échantillon de reconnexion automatique pour approfondir le sujet.

Lire et écrire dans des descripteurs Bluetooth

Les descripteurs GATT Bluetooth sont des attributs qui décrivent une valeur caractéristique. Vous pouvez les lire et les écrire comme avec Bluetooth GATT. caractéristiques.

Voyons, par exemple, comment lire la description de la mesure du thermomètre de l'appareil.

Dans l'exemple ci-dessous, health_thermometer correspond au service Thermomètres de santé. measurement_interval la caractéristique de l'intervalle de mesure ; gatt.characteristic_user_description la description utilisateur caractéristique descripteur.

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

Maintenant que nous avons lu la description utilisateur de l'intervalle de mesure le thermomètre de santé de l'appareil, voyons comment le mettre à jour et écrire un .

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

Exemples, démonstrations et ateliers de programmation

Tous les exemples Bluetooth Web ci-dessous ont été testés avec succès. Pour en profiter d'exemples de code, nous vous conseillons d'installer Android App] qui simule un périphérique BLE avec un service de batterie, une fréquence cardiaque ou un service de thermomètre médical.

Débutant

  • Informations sur l'appareil : permet de récupérer des informations de base provenant d'un appareil BLE.
  • Niveau de la batterie : récupérez des informations sur la batterie à partir d'un appareil BLE qui annonce des informations sur la batterie.
  • Réinitialiser l'énergie : réinitialisez l'énergie dépensée par un appareil BLE annonçant la fréquence cardiaque.
  • Propriétés caractéristiques : affiche toutes les propriétés d'une caractéristique spécifique à partir d'un appareil BLE.
  • Notifications : permet de lancer et d'arrêter les notifications relatives aux caractéristiques d'un appareil BLE.
  • Déconnexion de l'appareil : déconnectez-vous d'un appareil BLE et recevez une notification en cas de déconnexion après s'y être connecté.
  • Obtenir les caractéristiques : obtenez toutes les caractéristiques d'un service annoncé à partir d'un appareil BLE.
  • Get Descriptors (Obtenir des descripteurs) : obtenez toutes les caractéristiques. d'un service annoncé à partir d'un appareil BLE.
  • Filtre de données fabricant : récupérez des informations de base sur l'appareil à partir d'un appareil BLE correspondant aux données du fabricant.
  • Filtres d'exclusion : récupérez des informations de base sur l'appareil à partir d'un appareil BLE doté de filtres d'exclusion de base.

Combiner plusieurs opérations

  • Caractéristiques GAP : obtenez toutes les caractéristiques GAP d'un appareil BLE.
  • Device Information Characteristics (Caractéristiques des informations sur l'appareil) : obtenez toutes les caractéristiques des informations provenant d'un appareil BLE.
  • Link Loss (Perte de lien) : définissez le niveau d'alerte caractéristique d'un appareil BLE (readValue et writeValue).
  • Découvrir les services Caractéristiques : découvrez tous les services principaux accessibles et leurs caractéristiques à partir d'un appareil BLE.
  • Reconnexion automatique : reconnectez-vous à un appareil BLE déconnecté à l'aide d'un algorithme d'intervalle exponentiel entre les tentatives.
  • Lire la valeur de caractéristique modifiée : permet de lire le niveau de la batterie et d'être informé des changements apportés par un appareil BLE.
  • Read Descriptors (Lire les descripteurs) : permet de lire tous les descripteurs de caractéristiques d'un service à partir d'un appareil BLE.
  • Écrire le descripteur : écrivez le descripteur "Description de l'utilisateur caractéristique". sur un appareil BLE.

Découvrez également nos démonstrations Web Bluetooth sélectionnées et nos ateliers de programmation Web Bluetooth officiels.

Bibliothèques

  • web-bluetooth-utils est un module npm qui ajoute quelques fonctions pratiques l'API.
  • Un shim pour API Web Bluetooth est disponible en noble, la technologie Node.js BLE la plus populaire. dans le module central. Cela vous permet de créer des webpacks/navigateurs noble sans avoir besoin pour un serveur WebSocket ou d'autres plug-ins.
  • angular-web-bluetooth est un module pour Angular qui élimine tous les Code récurrent nécessaire pour configurer l'API Web Bluetooth.

Outils

  • Get Started with Web Bluetooth (Premiers pas avec Web Bluetooth) est une application Web simple qui génère le code récurrent JavaScript pour commencer à interagir avec un appareil Bluetooth. Saisissez un nom d'appareil, un service ou une caractéristique, définissez ses propriétés et vous pouvez passer.
  • Si vous êtes déjà un développeur Bluetooth, l'application Web Bluetooth Developer Studio du plug-in génère également le code Web Bluetooth JavaScript pour votre Appareil Bluetooth.

Conseils

Une page Internes Bluetooth est disponible dans Chrome à l'adresse about://bluetooth-internals afin d'inspecter tous les éléments à proximité Appareils Bluetooth: état, services, caractéristiques et descripteurs

<ph type="x-smartling-placeholder">
</ph> Capture d&#39;écran de la page interne de débogage du Bluetooth dans Chrome
Page interne dans Chrome pour le débogage des appareils Bluetooth.

Nous vous invitons également à consulter le guide officiel Comment signaler des bugs Bluetooth sur le Web car le débogage du Bluetooth peut parfois être difficile.

Étape suivante

Vérifiez d'abord l'état d'implémentation du navigateur et de la plate-forme pour savoir quels éléments de l'API Web Bluetooth sont en cours de mise en œuvre.

Il n'est pas encore terminé, mais voici un aperçu de ce qui vous attend futur:

  • Recherche d'annonces BLE à proximité aura lieu avec navigator.bluetooth.requestLEScan().
  • Un nouvel événement serviceadded suivra les services Bluetooth GATT récemment détectés tandis que serviceremoved événement suivra les événements supprimés. Un nouveau servicechanged est déclenché lorsqu'une caractéristique et/ou un descripteur sont ajoutés ou supprimé d'un service GATT Bluetooth.

Apportez votre soutien à l'API

Prévoyez-vous d'utiliser l'API Web Bluetooth ? Votre assistance publique aide l'équipe Chrome hiérarchisent les fonctionnalités et montre aux autres fournisseurs de navigateurs à quel point il est essentiel de les prendre en charge.

Envoyez un tweet à @ChromiumDev en utilisant le hashtag. #WebBluetooth et n'hésitez pas à nous dire où et comment vous l'utilisez.

Ressources

Remerciements

Merci à Kayce Basque d'avoir lu cet article. Image principale créée par SparkFun Electronics de Boulder, aux États-Unis.