1. De quoi s'agit-il ?

Dans cet atelier de programmation, vous allez apprendre à contrôler une bougie LED sans flamme PLAYBULB uniquement avec JavaScript grâce à l'API Web Bluetooth. Vous découvrirez également les fonctionnalités JavaScript ES2015 telles que les classes, les fonctions fléchées, les cartes et les promesses.
Points abordés
- Interagir avec un appareil Bluetooth à proximité en JavaScript
- Utiliser les classes, les fonctions fléchées, les objets Map et les promesses ES2015
Prérequis
- Connaissances de base en développement Web
- Connaissances de base sur le Bluetooth à basse consommation (BLE) et le profil d'attribut générique (GATT)
- Un éditeur de texte de votre choix
- Un Mac, un Chromebook ou un appareil Android M avec l'application du navigateur Chrome et un câble micro-USB vers USB.
2. Lire en premier
Avant de vous lancer dans cet atelier de programmation, vous pouvez consulter la version finale de l'application que vous allez créer sur https://googlecodelabs.github.io/candle-bluetooth et tester l'appareil Bluetooth PLAYBULB Candle dont vous disposez.
Vous pouvez également me voir changer de couleur sur https://www.youtube.com/watch?v=fBCPA9gIxlU.
3. Configuration
Télécharger l'exemple de code
Vous pouvez obtenir l'exemple de code pour cet atelier en téléchargeant le fichier ZIP ici :
ou en clonant ce dépôt Git :
git clone https://github.com/googlecodelabs/candle-bluetooth.git
Si vous avez téléchargé la source sous forme de fichier ZIP, vous devriez obtenir un dossier racine candle-bluetooth-master après l'avoir décompressé.
Installer et vérifier le serveur Web
Vous êtes libre d'utiliser votre propre serveur Web, mais cet atelier de programmation est conçu pour fonctionner de manière optimale avec le serveur Web Chrome. Si l'application n'est pas encore installée, vous pouvez le faire depuis le Chrome Web Store.
Après avoir installé l'application de serveur Web pour Chrome, cliquez sur le raccourci "Applications" dans la barre de favoris :

Dans la fenêtre qui s'affiche, cliquez sur l'icône du serveur Web :

La boîte de dialogue suivante s'affiche. Elle vous permet de configurer votre serveur Web local :

Cliquez sur le bouton choose folder (choisir un dossier), puis sélectionnez la racine du dépôt cloné (ou désarchivé). Cela vous permettra de diffuser votre travail en cours via l'URL indiquée dans la boîte de dialogue du serveur Web (dans la section Web Server URL(s)).
Sous "Options", cochez la case Automatically show index.html (Afficher automatiquement index.html), comme illustré ci-dessous :

Accédez maintenant à votre site dans votre navigateur Web (en cliquant sur l'URL du serveur Web mise en surbrillance). Vous devriez voir une page semblable à celle-ci :

Si vous souhaitez voir à quoi ressemble cette application sur votre téléphone Android, vous devez activer le débogage à distance sur Android et configurer le transfert de port (le numéro de port par défaut est 8887). Ensuite, il vous suffit d'ouvrir un nouvel onglet Chrome sur votre téléphone Android et d'accéder à http://localhost:8887.
Étape suivante
Pour l'instant, cette application Web ne fait pas grand-chose. Commençons par ajouter la compatibilité Bluetooth.
4. Découvrez la bougie
Nous allons commencer par écrire une bibliothèque qui utilise une classe JavaScript ES2015 pour l'appareil Bluetooth PLAYBULB Candle.
Restez calme. La syntaxe de classe n'introduit pas de nouveau modèle d'héritage orienté objet dans JavaScript. Elle fournit simplement une syntaxe beaucoup plus claire pour créer des objets et gérer l'héritage, comme vous pouvez le lire ci-dessous.
Commençons par définir une classe PlaybulbCandle dans playbulbCandle.js et par créer une instance playbulbCandle qui sera disponible ultérieurement dans le fichier app.js.
playbulbCandle.js
(function() {
'use strict';
class PlaybulbCandle {
constructor() {
this.device = null;
}
}
window.playbulbCandle = new PlaybulbCandle();
})();
Pour demander l'accès à un appareil Bluetooth à proximité, nous devons appeler navigator.bluetooth.requestDevice. Étant donné que l'appareil PLAYBULB Candle annonce en continu (s'il n'est pas déjà associé) un UUID de service GATT Bluetooth constant, connu sous sa forme abrégée 0xFF02, nous pouvons simplement définir une constante et l'ajouter au paramètre de services de filtres dans une nouvelle méthode publique connect de la classe PlaybulbCandle.
Nous allons également conserver une trace interne de l'objet BluetoothDevice afin de pouvoir y accéder ultérieurement si nécessaire. Étant donné que navigator.bluetooth.requestDevice renvoie une promesse JavaScript ES2015, nous allons procéder dans la méthode then.
playbulbCandle.js
(function() {
'use strict';
const CANDLE_SERVICE_UUID = 0xFF02;
class PlaybulbCandle {
constructor() {
this.device = null;
}
connect() {
let options = {filters:[{services:[ CANDLE_SERVICE_UUID ]}]};
return navigator.bluetooth.requestDevice(options)
.then(function(device) {
this.device = device;
}.bind(this));
}
}
window.playbulbCandle = new PlaybulbCandle();
})();
Par mesure de sécurité, la détection des appareils Bluetooth à proximité avec navigator.bluetooth.requestDevice doit être appelée par un geste de l'utilisateur, comme un appui ou un clic de souris. C'est pourquoi nous appellerons la méthode connect lorsque l'utilisateur cliquera sur le bouton "Connect" (Se connecter) dans le fichier app.js :
app.js
document.querySelector('#connect').addEventListener('click', function(event) {
document.querySelector('#state').classList.add('connecting');
playbulbCandle.connect()
.then(function() {
console.log(playbulbCandle.device);
document.querySelector('#state').classList.remove('connecting');
document.querySelector('#state').classList.add('connected');
})
.catch(function(error) {
console.error('Argh!', error);
});
});
Exécuter l'application
À ce stade, accédez à votre site dans votre navigateur Web (en cliquant sur l'URL du serveur Web mise en évidence dans l'application du serveur Web) ou actualisez simplement la page existante. Cliquez sur le bouton vert "Connect" (Se connecter), sélectionnez l'appareil dans le sélecteur, ouvrez votre console d'outils de développement préférée à l'aide du raccourci clavier Ctrl+Maj+J et observez l'objet BluetoothDevice consigné.

Une erreur peut s'afficher si le Bluetooth est désactivé et/ou si l'appareil Bluetooth PLAYBULB Candle est éteint. Dans ce cas, activez-le et recommencez.
Bonus obligatoire
Je ne sais pas ce que vous en pensez, mais je vois déjà trop de function() {} dans ce code. Passons plutôt aux () => {} fonctions fléchées JavaScript ES2015. Elles sont d'une aide précieuse : elles offrent tous les avantages des fonctions anonymes, sans les inconvénients de la liaison.
playbulbCandle.js
(function() {
'use strict';
const CANDLE_SERVICE_UUID = 0xFF02;
class PlaybulbCandle {
constructor() {
this.device = null;
}
connect() {
let options = {filters:[{services:[ CANDLE_SERVICE_UUID ]}]};
return navigator.bluetooth.requestDevice(options)
.then(device => {
this.device = device;
});
}
}
window.playbulbCandle = new PlaybulbCandle();
})();
app.js
document.querySelector('#connect').addEventListener('click', event => {
playbulbCandle.connect()
.then(() => {
console.log(playbulbCandle.device);
document.querySelector('#state').classList.remove('connecting');
document.querySelector('#state').classList.add('connected');
})
.catch(error => {
console.error('Argh!', error);
});
});
Étape suivante
- OK... Je peux vraiment parler à cette bougie ou quoi ?
- Oui, passer à l'étape suivante
Questions fréquentes
5. Lire quelque chose
Que faire maintenant que vous avez un BluetoothDevice renvoyé par la promesse de navigator.bluetooth.requestDevice ? Connectons-nous au serveur GATT Bluetooth distant qui contient les définitions de service et de caractéristique Bluetooth en appelant device.gatt.connect() :
playbulbCandle.js
class PlaybulbCandle {
constructor() {
this.device = null;
}
connect() {
let options = {filters:[{services:[ CANDLE_SERVICE_UUID ]}]};
return navigator.bluetooth.requestDevice(options)
.then(device => {
this.device = device;
return device.gatt.connect();
});
}
}
Lire le nom de l'appareil
Ici, nous sommes connectés au serveur GATT de l'appareil Bluetooth PLAYBULB Candle. Nous voulons maintenant obtenir le service GATT principal (annoncé précédemment comme 0xFF02) et lire la caractéristique du nom de l'appareil (0xFFFF) qui appartient à ce service. Pour ce faire, il suffit d'ajouter une nouvelle méthode getDeviceName à la classe PlaybulbCandle et d'utiliser device.gatt.getPrimaryService et service.getCharacteristic. La méthode characteristic.readValue renvoie un DataView que nous décoderons simplement avec TextDecoder.
playbulbCandle.js
const CANDLE_DEVICE_NAME_UUID = 0xFFFF;
...
getDeviceName() {
return this.device.gatt.getPrimaryService(CANDLE_SERVICE_UUID)
.then(service => service.getCharacteristic(CANDLE_DEVICE_NAME_UUID))
.then(characteristic => characteristic.readValue())
.then(data => {
let decoder = new TextDecoder('utf-8');
return decoder.decode(data);
});
}
Ajoutons cela à app.js en appelant playbulbCandle.getDeviceName une fois que nous sommes connectés, puis affichons le nom de l'appareil.
app.js
document.querySelector('#connect').addEventListener('click', event => {
playbulbCandle.connect()
.then(() => {
console.log(playbulbCandle.device);
document.querySelector('#state').classList.remove('connecting');
document.querySelector('#state').classList.add('connected');
return playbulbCandle.getDeviceName().then(handleDeviceName);
})
.catch(error => {
console.error('Argh!', error);
});
});
function handleDeviceName(deviceName) {
document.querySelector('#deviceName').value = deviceName;
}
À ce stade, accédez à votre site dans votre navigateur Web (en cliquant sur l'URL du serveur Web mise en évidence dans l'application du serveur Web) ou actualisez simplement la page existante. Assurez-vous que la PLAYBULB Candle est allumée, puis cliquez sur le bouton "Connect" (Se connecter) sur la page. Le nom de l'appareil devrait s'afficher sous le sélecteur de couleur.

Lire le niveau de batterie
Il existe également une caractéristique Bluetooth standard de niveau de batterie disponible dans l'appareil Bluetooth PLAYBULB Candle qui contient le niveau de batterie de l'appareil. Cela signifie que nous pouvons utiliser des noms standards tels que battery_service pour l'UUID du service GATT Bluetooth et battery_level pour l'UUID de la caractéristique GATT Bluetooth.
Ajoutons une nouvelle méthode getBatteryLevel à la classe PlaybulbCandle et lisons le niveau de batterie en pourcentage.
playbulbCandle.js
getBatteryLevel() {
return this.device.gatt.getPrimaryService('battery_service')
.then(service => service.getCharacteristic('battery_level'))
.then(characteristic => characteristic.readValue())
.then(data => data.getUint8(0));
}
Nous devons également mettre à jour l'objet JavaScript options pour inclure le service de batterie dans la clé optionalServices, car il n'est pas annoncé par l'appareil Bluetooth PLAYBULB Candle, mais il est toujours obligatoire pour y accéder.
playbulbCandle.js
let options = {filters:[{services:[ CANDLE_SERVICE_UUID ]}],
optionalServices: ['battery_service']};
return navigator.bluetooth.requestDevice(options)
Comme précédemment, connectons-le à app.js en appelant playbulbCandle.getBatteryLevel une fois que nous avons le nom de l'appareil et affichons le niveau de batterie.
app.js
document.querySelector('#connect').addEventListener('click', event => {
playbulbCandle.connect()
.then(() => {
console.log(playbulbCandle.device);
document.querySelector('#state').classList.remove('connecting');
document.querySelector('#state').classList.add('connected');
return playbulbCandle.getDeviceName().then(handleDeviceName)
.then(() => playbulbCandle.getBatteryLevel().then(handleBatteryLevel));
})
.catch(error => {
console.error('Argh!', error);
});
});
function handleDeviceName(deviceName) {
document.querySelector('#deviceName').value = deviceName;
}
function handleBatteryLevel(batteryLevel) {
document.querySelector('#batteryLevel').textContent = batteryLevel + '%';
}
À ce stade, accédez à votre site dans votre navigateur Web (en cliquant sur l'URL du serveur Web mise en surbrillance dans l'application du serveur Web) ou actualisez simplement la page existante. Cliquez sur le bouton "Connecter" sur la page. Le nom de l'appareil et le niveau de batterie devraient s'afficher.
Étape suivante
- Comment changer la couleur de cette ampoule ? C'est pour ça que je suis là !
- Tu y es presque, je te promets...
Questions fréquentes
6. Modifier la couleur
Pour changer la couleur, il suffit d'écrire un ensemble spécifique de commandes dans une caractéristique Bluetooth (0xFFFC) du service GATT principal annoncé comme 0xFF02. Par exemple, pour que votre bougie PLAYBULB s'allume en rouge, vous devez écrire un tableau d'entiers non signés de 8 bits égal à [0x00, 255, 0, 0], où 0x00 correspond à la saturation du blanc et 255, 0, 0 aux valeurs de rouge, de vert et de bleu, respectivement .
Nous allons utiliser characteristic.writeValue pour écrire des données dans la caractéristique Bluetooth dans la nouvelle méthode publique setColor de la classe PlaybulbCandle. Nous renverrons également les valeurs réelles de rouge, de vert et de bleu lorsque la promesse sera remplie, afin de pouvoir les utiliser ultérieurement dans app.js :
playbulbCandle.js
const CANDLE_COLOR_UUID = 0xFFFC;
...
setColor(r, g, b) {
let data = new Uint8Array([0x00, r, g, b]);
return this.device.gatt.getPrimaryService(CANDLE_SERVICE_UUID)
.then(service => service.getCharacteristic(CANDLE_COLOR_UUID))
.then(characteristic => characteristic.writeValue(data))
.then(() => [r,g,b]);
}
Mettons à jour la fonction changeColor dans app.js pour appeler playbulbCandle.setColor lorsque la case d'option "No Effect" (Aucun effet) est cochée. Les variables de couleur r, g, b globales sont déjà définies lorsque l'utilisateur clique sur le canevas du sélecteur de couleur.
app.js
function changeColor() {
var effect = document.querySelector('[name="effectSwitch"]:checked').id;
if (effect === 'noEffect') {
playbulbCandle.setColor(r, g, b).then(onColorChanged);
}
}
À ce stade, accédez à votre site dans votre navigateur Web (en cliquant sur l'URL du serveur Web mise en évidence dans l'application du serveur Web) ou actualisez simplement la page existante. Cliquez sur le bouton "Connect" (Se connecter) sur la page, puis sur le sélecteur de couleur pour changer la couleur de votre PLAYBULB Candle autant de fois que vous le souhaitez.
Effets de bougie supplémentaires
Si vous avez déjà allumé une bougie, vous savez que la lumière n'est pas statique. Heureusement, il existe une autre caractéristique Bluetooth (0xFFFB) dans le service GATT principal annoncé comme 0xFF02 qui permet à l'utilisateur de définir des effets de bougie.
Par exemple, pour définir un "effet bougie", vous pouvez écrire [0x00, r, g, b, 0x04, 0x00, 0x01, 0x00]. Vous pouvez également définir l'effet de clignotement avec [0x00, r, g, b, 0x00, 0x00, 0x1F, 0x00].
Ajoutons les méthodes setCandleEffectColor et setFlashingColor à la classe PlaybulbCandle.
playbulbCandle.js
const CANDLE_EFFECT_UUID = 0xFFFB;
...
setCandleEffectColor(r, g, b) {
let data = new Uint8Array([0x00, r, g, b, 0x04, 0x00, 0x01, 0x00]);
return this.device.gatt.getPrimaryService(CANDLE_SERVICE_UUID)
.then(service => service.getCharacteristic(CANDLE_EFFECT_UUID))
.then(characteristic => characteristic.writeValue(data))
.then(() => [r,g,b]);
}
setFlashingColor(r, g, b) {
let data = new Uint8Array([0x00, r, g, b, 0x00, 0x00, 0x1F, 0x00]);
return this.device.gatt.getPrimaryService(CANDLE_SERVICE_UUID)
.then(service => service.getCharacteristic(CANDLE_EFFECT_UUID))
.then(characteristic => characteristic.writeValue(data))
.then(() => [r,g,b]);
}
Mettons à jour la fonction changeColor dans app.js pour appeler playbulbCandle.setCandleEffectColor lorsque la case d'option "Effet bougie" est cochée et playbulbCandle.setFlashingColor lorsque la case d'option "Clignotement" est cochée. Cette fois, nous utiliserons switch si cela vous convient.
app.js
function changeColor() {
var effect = document.querySelector('[name="effectSwitch"]:checked').id;
switch(effect) {
case 'noEffect':
playbulbCandle.setColor(r, g, b).then(onColorChanged);
break;
case 'candleEffect':
playbulbCandle.setCandleEffectColor(r, g, b).then(onColorChanged);
break;
case 'flashing':
playbulbCandle.setFlashingColor(r, g, b).then(onColorChanged);
break;
}
}
À ce stade, accédez à votre site dans votre navigateur Web (en cliquant sur l'URL du serveur Web mise en évidence dans l'application du serveur Web) ou actualisez simplement la page existante. Cliquez sur le bouton "Connect" (Se connecter) sur la page et testez les effets "Candle" (Bougie) et "Flashing" (Clignotement).
Étape suivante
- C'est tout ? 3 effets de bougie de mauvaise qualité ? Est-ce pour cela que je suis ici ?
- Il y en a d'autres, mais vous devrez les trouver vous-même cette fois.
7. Allez plus loin
Et voilà ! Vous pensez peut-être que vous avez presque terminé, mais l'application n'est pas encore finalisée. Voyons si vous avez bien compris ce que vous avez copié-collé au cours de cet atelier de programmation. Voici ce que vous devez faire par vous-même pour que cette application soit parfaite.
Ajouter les effets manquants
Voici les données pour les effets manquants :
- Pulse :
[0x00, r, g, b, 0x01, 0x00, 0x09, 0x00](vous pouvez ajuster les valeursr, g, bici) [0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00](les personnes épileptiques devraient éviter ce mode)- Dégradé arc-en-ciel :
[0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x26, 0x00]
Cela signifie que vous devez ajouter de nouvelles méthodes setPulseColor, setRainbow et setRainbowFade à la classe PlaybulbCandle, puis les appeler dans changeColor.
Résoudre le problème "Aucun effet"
Comme vous l'avez peut-être remarqué, l'option "Aucun effet" ne réinitialise pas l'effet en cours. C'est un problème mineur, mais un problème quand même. Résolvons à présent ce problème. Dans la méthode setColor, vous devez d'abord vérifier si un effet est en cours via une nouvelle variable de classe _isEffectSet. Si true, désactivez l'effet avant de définir une nouvelle couleur avec ces données : [0x00, r, g, b, 0x05, 0x00, 0x01, 0x00].
Saisissez le nom de l'appareil
C'est facile ! Pour écrire un nom d'appareil personnalisé, il suffit d'écrire dans la caractéristique du nom de l'appareil Bluetooth précédent. Je vous recommande d'utiliser la méthode TextEncoder encode pour obtenir un Uint8Array contenant le nom de l'appareil.
Ensuite, j'ajouterais une eventListener "input" à document.querySelector('#deviceName') et j'appellerais playbulbCandle.setDeviceName pour simplifier les choses.
J'ai personnellement nommé le mien PLAY💡 CANDLE!
8. Et voilà !
Connaissances acquises
- Interagir avec un appareil Bluetooth à proximité en JavaScript
- Utiliser les classes, les fonctions fléchées, les objets Map et les promesses ES2015
Étapes suivantes
- En savoir plus sur l'API Web Bluetooth
- Parcourez les exemples et démos Web Bluetooth officiels.
- Découvrez le chat grincheux volant

