Contrôler une bougie PLAYBULB via Bluetooth Web

1. De quoi s'agit-il ?

IMG_19700101_023537~2~2.jpg

Dans cet atelier de programmation éclairé, vous allez apprendre à contrôler une bougie LED PLAYBULB sans flamme avec uniquement JavaScript grâce à l'API Web Bluetooth. En cours de route, vous vous amuserez également avec les fonctionnalités JavaScript ES2015 telles que les classes, les fonctions fléchées, la carte et les promesses.

Points abordés

  • Interagir avec un appareil Bluetooth à proximité en JavaScript
  • Utiliser les classes ES2015, les fonctions fléchées, les cartes et les promesses

Prérequis

2. À jouer en premier

Vous pouvez essayer la version finale de l'application que vous êtes sur le point de créer à l'adresse https://googlecodelabs.github.io/candle-bluetooth et jouer avec l'appareil Bluetooth PLAYBULB Candle dont vous disposez avant de vous plonger dans cet atelier de programmation.

Vous pouvez également me regarder 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 ce code 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 en tant que fichier ZIP, la décompression devrait vous donner un dossier racine candle-bluetooth-master.

Installer et vérifier le serveur Web

Bien que vous soyez libre d'utiliser votre propre serveur Web, cet atelier de programmation est conçu pour fonctionner correctement avec le serveur Web Chrome. Si vous n'avez pas encore installé cette application, vous pouvez l'installer depuis le Chrome Web Store.

Après avoir installé l'application serveur Web pour Chrome, cliquez sur le raccourci des applications dans la barre de favoris:

Capture d'écran 16/11/2016 à 16.10.42.png

Dans la fenêtre suivante, cliquez sur l'icône de serveur Web:

9f3c21b2cf6cbfb5.png

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

Capture d'écran 16/11/2016 à 15:40:47.png

Cliquez sur le bouton 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 mise en surbrillance dans la boîte de dialogue du serveur Web (dans la section URL du ou des serveurs Web).

Sous "Options", cochez la case Afficher automatiquement index.html comme indiqué ci-dessous:

Capture d'écran 16/11/2016 à 15:40:56.png

Accédez maintenant à votre site dans votre navigateur Web (en cliquant sur l'URL du serveur Web mise en surbrillance). Une page semblable à la suivante doit s'afficher:

Capture d'écran 16/11/2016 à 15:20.22.png

Pour 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 suffira d'ouvrir un nouvel onglet Chrome sur http://localhost:8887 sur votre téléphone Android.

Étape suivante

À ce stade, cette application Web ne fait pas grand-chose. Commençons à ajouter la compatibilité Bluetooth !

4. Découvrir la bougie

Nous allons commencer par écrire une bibliothèque qui utilise une classe ES2015 JavaScript pour l'appareil Bluetooth Candle PLAYBULB.

Restez calme. La syntaxe de la classe n'introduit pas un nouveau modèle d'héritage orienté objet dans JavaScript. Il 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.

Tout d'abord, définissons une classe PlaybulbCandle dans playbulbCandle.js et créons 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 Candle PLAYBULB annonce en continu (s'il n'est pas déjà associé) un UUID constant du service GATT Bluetooth, connu sous sa forme abrégée 0xFF02, nous pouvons simplement définir une constante et l'ajouter au paramètre des services de filtres dans une nouvelle méthode connect publique de la classe PlaybulbCandle.

Nous effectuerons également le suivi en interne de l'objet BluetoothDevice afin de pouvoir y accéder ultérieurement si nécessaire. Comme navigator.bluetooth.requestDevice renvoie une promesse JavaScript ES2015, nous le ferons 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();

})();

Pour des raisons de sécurité, la détection des appareils Bluetooth à proximité avec navigator.bluetooth.requestDevice doit être appelée à l'aide d'un geste de l'utilisateur, comme une pression ou un clic de souris. C'est pourquoi nous appellerons la méthode connect lorsque l'utilisateur clique sur le bouton "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 surbrillance dans l'application de serveur Web) ou actualisez simplement la page existante. Cliquez sur le bouton vert "Connecter" , choisissez l'appareil dans le sélecteur et ouvrez votre console d'outils de développement préférée à l'aide du raccourci clavier Ctrl+Maj+J. Vous remarquerez que l'objet BluetoothDevice est enregistré.

Capture d'écran 16/11/2016 à 15:27:12.png

Un message d'erreur peut s'afficher si le Bluetooth est désactivé et/ou si l'appareil Bluetooth Bougie PLAYBULB est désactivé. Dans ce cas, rallumez-la et réessayez.

Bonus obligatoire

Je ne sais pas pour vous, mais je vois déjà trop de function() {} dans ce code. Passons plutôt aux fonctions fléchées JavaScript ES2015 () => {}. Ils vous sauvegardaient toute la beauté des fonctions anonymes, sans la tristesse d'un lien.

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... puis-je parler à cette bougie ?

- Bien sûr... Passez à l'étape suivante.

Questions fréquentes

5. Lire quelque chose

Maintenant que vous avez obtenu un BluetoothDevice renvoyé par la promesse de navigator.bluetooth.requestDevice, que faire ? Connectez-vous au serveur GATT distant Bluetooth qui contient le service Bluetooth et les définitions des caractéristiques 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

Nous sommes connectés au serveur GATT de l'appareil Bluetooth Candle PLAYBULB. Nous voulons maintenant obtenir le service GATT principal (annoncé précédemment sous le nom 0xFF02) et lire la caractéristique du nom de l'appareil (0xFFFF) qui appartient à ce service. Pour ce faire, il vous 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 allons simplement décoder 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 et que nous avons affiché 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 surbrillance dans l'application de serveur Web) ou actualisez simplement la page existante. Assurez-vous que la bougie PLAYBULB est allumée, puis cliquez sur le bouton sur la page. Vous devriez voir le nom de l'appareil sous le sélecteur de couleur.

Capture d'écran 16/11/2016 à 15:29:21.png

Lire le niveau de la batterie

Une caractéristique Bluetooth de niveau de batterie standard est également disponible dans l'appareil Bluetooth PLAYBULB Candle. Elle indique 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 caractéristique GATT Bluetooth.

Ajoutons une nouvelle méthode getBatteryLevel à la classe PlaybulbCandle et lisons le niveau de la 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 sur la clé optionalServices, car il n'est pas annoncé par l'appareil Bluetooth PLAYBULB Candle, mais il reste 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 affiché 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 de serveur Web) ou actualisez simplement la page existante. Cliquez sur le bouton « Connecter » sur la page. Vous devriez voir le nom de l'appareil et le niveau de batterie.

Capture d'écran 16/11/2016 à 15:29:21.png

Étape suivante

- Comment changer la couleur de cette ampoule ? C'est pour ça que je suis là !

- Vous y êtes presque, promis...

Questions fréquentes

6. Modifier la couleur

Pour modifier la couleur, il vous suffit d'écrire un ensemble spécifique de commandes pour une caractéristique Bluetooth (0xFFFC) dans le service GATT principal annoncé comme 0xFF02. Par exemple, si vous activez le rouge de votre bougie PLAYBULB, vous écrivez un tableau d'entiers non signés de 8 bits égaux à [0x00, 255, 0, 0], où 0x00 correspond à la saturation en blanc et 255, 0, 0 représentent respectivement les valeurs rouge, vert et bleu .

Nous utiliserons characteristic.writeValue pour écrire des données dans la caractéristique Bluetooth dans la nouvelle méthode publique setColor de la classe PlaybulbCandle. Nous renvoyons également les valeurs rouge, verte et bleue réelles lorsque la promesse est 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 "Aucun effet" est cochée. Les variables de couleur globales r, g, b 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 surbrillance dans l'application de serveur Web) ou actualisez simplement la page existante. Cliquez sur le bouton « Connecter » sur la page et cliquez sur le sélecteur de couleur pour changer la couleur de la bougie PLAYBULB autant de fois que vous le souhaitez.

Capture d'écran 16/11/2016 à 15:31:37.png

Effets de bougie sur les bougies

Si vous avez déjà allumé une bougie, vous savez que la lumière n'est pas statique. Heureusement pour nous, il existe une autre caractéristique Bluetooth (0xFFFB) dans le service GATT principal, annoncée en tant que 0xFF02, qui permet à l'utilisateur de définir des effets bougie.

Régler un "effet bougie" par exemple, en écrivant [0x00, r, g, b, 0x04, 0x00, 0x01, 0x00]. Vous pouvez aussi définir l'effet "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 l'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 surbrillance dans l'application de serveur Web) ou actualisez simplement la page existante. Cliquez sur le bouton « Connecter » sur la page et jouez avec les bougies et les effets de clignotement.

Capture d'écran 16/11/2016 à 15:33.23.png

Étape suivante

- C'est tout ? 3 mauvais effets de bougies ? C'est pour ça que je suis ici ?

- Il y en a d'autres, mais vous serez tout seul cette fois-ci.

7. Allez plus loin

Nous y voilà ! Vous pensez peut-être qu'elle est presque terminée, mais l'application n'est pas encore terminée. Vérifions que vous avez bien compris ce que vous avez copié et collé au cours de cet atelier de programmation. Voici ce que vous souhaitez faire par vous-même pour mettre en valeur cette application.

Ajouter les effets manquants

Voici les données concernant les effets manquants:

  • Pulsation: [0x00, r, g, b, 0x01, 0x00, 0x09, 0x00] (vous voudrez peut-être régler les valeurs r, g, b à cet endroit)
  • Arc-en-ciel: [0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00] (Les personnes épileptiques voudront peut-être éviter celui-ci.)
  • Fondu arc-en-ciel: [0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x26, 0x00]

Cela signifie essentiellement ajouter de nouvelles méthodes setPulseColor, setRainbow et setRainbowFade à la classe PlaybulbCandle et les appeler dans changeColor.

Corriger l'option "Aucun effet"

Comme vous l'avez peut-être remarqué, l'option "Aucun effet" ne réinitialise aucun effet en cours, c'est mineur, mais toujours. 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 et, si true, désactiver l'effet avant de définir une nouvelle couleur avec les données suivantes: [0x00, r, g, b, 0x05, 0x00, 0x01, 0x00].

Saisir le nom de l'appareil

Celle-ci est facile ! Pour créer un nom d'appareil personnalisé, il vous suffit d'écrire la caractéristique précédente du nom de l'appareil Bluetooth. Je vous recommande d'utiliser la méthode encode de TextEncoder pour obtenir un Uint8Array contenant le nom de l'appareil.

Ensuite, j'ajouterais une « entrée » eventListener à document.querySelector('#deviceName') et appelez playbulbCandle.setDeviceName pour simplifier les choses.

J'ai personnellement nommé ma BOUCHE PLAY💡 !

8. Et voilà !

Connaissances acquises

  • Interagir avec un appareil Bluetooth à proximité en JavaScript
  • Utiliser les classes ES2015, les fonctions fléchées, les cartes et les promesses

Étapes suivantes