L'API Web Bluetooth permet aux sites Web de communiquer avec les appareils Bluetooth.
Et si je vous disais que les sites Web peuvent communiquer avec les appareils Bluetooth à proximité de manière sécurisée et respectueuse de la confidentialité ? Ainsi, les cardiofréquencemètres, les ampoules qui chantent et même les tortues pourraient interagir directement avec un site Web.
Jusqu'à présent, il n'était possible d'interagir avec des appareils Bluetooth que pour les applications spécifiques à une plate-forme. L'API Web Bluetooth vise à changer cela et à l'étendre aux navigateurs Web.
Avant de commencer
Dans ce document, nous partons du principe que vous disposez de connaissances de base sur le fonctionnement du Bluetooth à basse consommation (BLE) et du profil d'attribut générique.
Même si la spécification de l'API Web Bluetooth n'est pas encore finalisée, les auteurs de la spécification recherchent activement des développeurs enthousiastes pour tester cette API et donner leur avis sur la spécification 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 pouvoir demander et vous connecter aux appareils Bluetooth à basse consommation à proximité, lire/écrire les caractéristiques Bluetooth, recevoir les notifications GATT, savoir quand un appareil Bluetooth est déconnecté et même lire et écrire les descripteurs Bluetooth. Pour en savoir plus, consultez le tableau de compatibilité des navigateurs de MDN.
Pour Linux et les versions antérieures de Windows, activez le flag #experimental-web-platform-features dans about://flags.
Disponible pour les versions d'essai des origines
Afin de recueillir le plus de commentaires possible de la part des développeurs utilisant l'API Web Bluetooth sur le terrain, Chrome a déjà ajouté cette fonctionnalité dans Chrome 53 en tant qu'essai Origin Trial pour ChromeOS, Android et Mac.
La période d'essai s'est terminée en janvier 2017.
Exigences de sécurité
Pour comprendre les compromis de sécurité, je vous recommande l'article Web Bluetooth Security Model de Jeffrey Yasskin, ingénieur logiciel de l'équipe Chrome, qui 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. Elle n'est donc disponible que dans les contextes sécurisés. Cela signifie que vous devrez concevoir votre application en tenant compte du TLS.
Geste de l'utilisateur requis
Pour des raisons de sécurité, la découverte des appareils Bluetooth avec navigator.bluetooth.requestDevice doit être déclenchée par un geste de l'utilisateur, comme un appui ou un clic de souris. Nous parlons d'écouter les événements pointerup, click et touchend.
button.addEventListener('pointerup', function(event) {
// Call navigator.bluetooth.requestDevice
});
Entrer dans le code
L'API Web Bluetooth s'appuie fortement sur les promesses JavaScript. Si vous ne les connaissez pas, consultez ce tutoriel sur les promesses. Dernière chose : () => {} sont des fonctions fléchées ECMAScript 2015.
Demander des appareils Bluetooth
Cette version de la spécification de l'API Web Bluetooth permet aux sites Web exécutés dans le rôle Central de se connecter à des serveurs GATT distants via une connexion BLE. Il permet la communication entre les appareils qui implémentent Bluetooth 4.0 ou version ultérieure.
Lorsqu'un site Web demande l'accès aux appareils à proximité à l'aide de navigator.bluetooth.requestDevice, le navigateur invite l'utilisateur à choisir un appareil ou à annuler la demande.
La fonction navigator.bluetooth.requestDevice() utilise un objet obligatoire qui définit les filtres. Ces filtres permettent de ne renvoyer que les appareils correspondant à certains services GATT Bluetooth annoncés et/ou au nom de l'appareil.
Filtre "Services"
Par exemple, pour demander aux appareils Bluetooth de diffuser le service de batterie Bluetooth GATT :
navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Toutefois, si votre service GATT Bluetooth ne figure pas dans la liste des services GATT Bluetooth standardisés, vous pouvez fournir l'UUID Bluetooth complet ou une forme courte de 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 de l'appareil annoncé avec la clé de filtres name, ou même un préfixe de ce nom avec la clé de filtres namePrefix. Notez que, dans ce cas, vous devrez également définir la clé optionalServices pour pouvoir accéder aux services qui ne sont pas inclus dans un filtre de service. Sinon, un message d'erreur s'affichera ultérieurement lorsque vous tenterez d'y accéder.
navigator.bluetooth.requestDevice({
filters: [{
name: 'Francois robot'
}],
optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Filtre de données du fabricant
Il est également possible de demander des appareils Bluetooth en fonction des données spécifiques au fabricant annoncées avec la clé de filtre manufacturerData. Cette clé est un tableau d'objets avec une clé Bluetooth company identifier obligatoire nommée companyIdentifier. Vous pouvez également fournir un préfixe de données qui filtre les données du fabricant provenant des appareils Bluetooth qui commencent par ce préfixe. Notez que vous devrez également définir la clé optionalServices pour pouvoir accéder aux services qui ne sont pas inclus dans un filtre de service. Si vous ne le faites pas, une erreur s'affichera ultérieurement lorsque vous tenterez 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. Pour en savoir plus, consultez l'explication sur les filtres de données Bluetooth.
Filtres d'exclusion
L'option exclusionFilters dans navigator.bluetooth.requestDevice() vous permet d'exclure certains appareils du sélecteur de navigateur. Il peut être utilisé pour exclure les 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); });
Aucun filtre
Enfin, au lieu d'utiliser filters, vous pouvez utiliser la touche acceptAllDevices pour afficher tous les appareils Bluetooth à proximité. Vous devrez également définir la clé optionalServices pour pouvoir accéder à certains services. Si vous ne le faites pas, un message d'erreur s'affichera ultérieurement lorsque vous tenterez 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 avez un BluetoothDevice ? Connectons-nous au serveur GATT de la télécommande Bluetooth, qui contient les définitions de service et de caractéristique.
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. Nous souhaitons maintenant obtenir un service GATT principal et lire une caractéristique appartenant à ce service. Essayons, par exemple, de lire le niveau de charge actuel de la batterie de l'appareil.
Dans l'exemple ci-dessous, battery_level est la caractéristique standardisée du niveau de batterie.
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 GATT Bluetooth personnalisée, vous pouvez fournir le UUID Bluetooth complet ou une forme abrégée de 16 ou 32 bits à service.getCharacteristic.
Notez que vous pouvez également ajouter un écouteur d'événements characteristicvaluechanged sur une caractéristique pour gérer la lecture de sa valeur. Consultez l'exemple de modification de la valeur caractéristique de lecture pour découvrir comment gérer également les prochaines notifications GATT (Generic Attribute Profile).
…
.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 dans une caractéristique Bluetooth
Écrire dans une caractéristique GATT Bluetooth est aussi simple que de la lire. Cette fois, utilisons le point de contrôle de la fréquence cardiaque pour réinitialiser la valeur du champ "Énergie dépensée" à 0 sur un cardiofréquencemètre.
Je vous promets qu'il n'y a rien de magique ici. Pour en savoir plus, consultez la page Caractéristiques du point de contrôle de la fréquence cardiaque.
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 caractéristique Heart Rate Measurement (Mesure de la fréquence cardiaque) change 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'exemple de notifications vous montre comment arrêter les notifications avec stopNotifications() et supprimer correctement l'écouteur d'événements characteristicvaluechanged ajouté.
Se déconnecter d'un appareil Bluetooth
Pour offrir une meilleure expérience utilisateur, vous pouvez écouter les événements de déconnexion et inviter 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 l'appareil Bluetooth. Cela déclenchera les écouteurs d'événements gattserverdisconnected existants. Notez que cela n'arrêtera PAS la communication de l'appareil Bluetooth si une autre application communique déjà avec l'appareil Bluetooth. Pour en savoir plus, consultez l'exemple de déconnexion d'appareil et l'exemple de reconnexion automatique.
Lire et écrire dans les descripteurs Bluetooth
Les descripteurs GATT Bluetooth sont des attributs qui décrivent une valeur de caractéristique. Vous pouvez les lire et les écrire de la même manière que les caractéristiques GATT Bluetooth.
Voyons par exemple comment lire la description de l'intervalle de mesure du thermomètre de santé de l'appareil.
Dans l'exemple ci-dessous, health_thermometer correspond au service de thermomètre médical, measurement_interval à la caractéristique d'intervalle de mesure et gatt.characteristic_user_description au descripteur de description de l'utilisateur de la caractéristique.
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 de l'utilisateur concernant l'intervalle de mesure du thermomètre de santé de l'appareil, voyons comment le mettre à jour et écrire une valeur personnalisée.
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émos et ateliers de programmation
Tous les exemples Web Bluetooth ci-dessous ont été testés avec succès. Pour profiter pleinement de ces exemples, je vous recommande d'installer l'application Android [BLE Peripheral Simulator] qui simule un périphérique BLE avec un service de batterie, un service de fréquence cardiaque ou un service de thermomètre médical.
Débutant
- Device Info (Infos sur l'appareil) : récupérez les informations de base sur un appareil BLE.
- Niveau de batterie : récupère les informations sur la batterie à partir d'un appareil BLE qui diffuse des informations sur la batterie.
- Réinitialiser l'énergie : réinitialise l'énergie dépensée à partir d'un appareil BLE qui diffuse la fréquence cardiaque.
- Propriétés des caractéristiques : affichez toutes les propriétés d'une caractéristique spécifique d'un appareil BLE.
- Notifications : démarrez et arrêtez les notifications caractéristiques d'un appareil BLE.
- Déconnexion de l'appareil : déconnectez-vous d'un appareil BLE après vous y être connecté et recevez une notification de déconnexion.
- Get Characteristics (Obtenir les caractéristiques) : permet d'obtenir toutes les caractéristiques d'un service annoncé à partir d'un appareil BLE.
- Obtenir les descripteurs : obtenir tous les descripteurs de caractéristiques d'un service annoncé à partir d'un appareil BLE.
- Filtre de données du fabricant : récupérez les informations de base sur un appareil BLE correspondant aux données du fabricant.
- Filtres d'exclusion : récupérez les informations de base sur l'appareil à partir d'un appareil BLE doté de filtres d'exclusion de base.
Combiner plusieurs opérations
- GAP Characteristics (Caractéristiques GAP) : obtenez toutes les caractéristiques GAP d'un appareil BLE.
- Caractéristiques des informations sur l'appareil : obtenez toutes les caractéristiques des informations sur l'appareil d'un appareil BLE.
- Perte de connexion : définit la caractéristique du niveau d'alerte d'un appareil BLE (readValue et writeValue).
- Découvrir les services et les caractéristiques : découvrez tous les services principaux accessibles et leurs caractéristiques à partir d'un appareil BLE.
- Reconnecter automatiquement : reconnectez-vous à un appareil BLE déconnecté à l'aide d'un algorithme de backoff exponentiel.
- Lecture de la valeur de la caractéristique modifiée : lire le niveau de la batterie et être informé des modifications apportées par un appareil BLE.
- Read Descriptors (Lire les descripteurs) : lire tous les descripteurs de caractéristiques d'un service à partir d'un appareil BLE.
- Write Descriptor (Descripteur d'écriture) : écrivez dans le descripteur "Characteristic User Description" (Description de l'utilisateur caractéristique) sur un appareil BLE.
Consultez également nos démonstrations Web Bluetooth et nos ateliers de programmation Web Bluetooth officiels.
Bibliothèques
- web-bluetooth-utils est un module npm qui ajoute des fonctions pratiques à l'API.
- Un shim de l'API Web Bluetooth est disponible dans noble, le module central BLE Node.js le plus populaire. Cela vous permet d'utiliser webpack/browserify noble sans avoir besoin d'un serveur WebSocket ni d'autres plug-ins.
- angular-web-bluetooth est un module pour Angular qui abstrait tout le code standard nécessaire pour configurer l'API Web Bluetooth.
Outils
- Get Started with Web Bluetooth est une application Web simple qui génère tout le code boilerplate 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 le tour est joué.
- Si vous êtes déjà un développeur Bluetooth, le plug-in Web Bluetooth Developer Studio générera également le code JavaScript Web Bluetooth pour votre appareil Bluetooth.
Conseils
Une page Bluetooth Internals est disponible dans Chrome à l'adresse about://bluetooth-internals. Elle vous permet d'inspecter tous les aspects des appareils Bluetooth à proximité : état, services, caractéristiques et descripteurs.
Je vous recommande également de consulter la page officielle How to file Web Bluetooth bugs (Comment signaler des bugs Web Bluetooth), car le débogage Bluetooth peut parfois être difficile.
Étape suivante
Consultez d'abord l'état d'implémentation du navigateur et de la plate-forme pour savoir quelles parties de l'API Web Bluetooth sont actuellement implémentées.
Bien qu'il soit encore incomplet, voici un aperçu de ce qui vous attend dans un avenir proche :
- La recherche de publicités BLE à proximité s'effectuera avec
navigator.bluetooth.requestLEScan(). - Un nouvel événement
serviceaddedpermettra de suivre les services GATT Bluetooth nouvellement découverts, tandis que l'événementserviceremovedpermettra de suivre ceux qui ont été supprimés. Un nouvel événementservicechangedse déclenche lorsqu'une caractéristique et/ou un descripteur sont ajoutés ou supprimés d'un service GATT Bluetooth.
Soutenir l'API
Comptez-vous utiliser l'API Web Bluetooth ? Votre soutien public aide l'équipe Chrome à hiérarchiser 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 dites-nous où et comment vous l'utilisez.
Ressources
- Stack Overflow
- État des fonctionnalités Chrome
- Bugs d'implémentation de Chrome
- Spécifications Web Bluetooth
- Problèmes liés aux spécifications sur GitHub
- Application BLE Peripheral Simulator
Remerciements
Merci à Kayce Basques pour son examen.