Controllare una candela PLAYBULB con Web Bluetooth

1. Di cosa parla?

.jpg

In questo codelab illuminato, imparerai a controllare una candela senza fiamma LED PLAYBULB solo con JavaScript grazie all'API Web Bluetooth. Lungo il percorso, imparerai anche a utilizzare le funzionalità di JavaScript ES2015 come Classi, Funzioni freccia, Mappa e Promesse.

Cosa imparerai a fare

  • Come interagire con un dispositivo Bluetooth nelle vicinanze in JavaScript
  • Come utilizzare le classi, le funzioni delle frecce, la mappa e le promesse di ES2015

Che cosa ti serve

2. Riproduci prima

Prima di iniziare questo codelab, ti consigliamo di dare un'occhiata alla versione finale dell'app che stai per creare all'indirizzo https://googlecodelabs.github.io/candle-bluetooth e provare a usare il dispositivo Bluetooth PLAYBULB Candle di cui disponi.

Puoi anche guardarmi mentre cambio colore all'indirizzo https://www.youtube.com/watch?v=fBCPA9gIxlU

3. Configurazione

Scarica il codice campione

Puoi ottenere il codice campione di questo codice scaricando il file ZIP qui:

o clonando questo repository Git:

git clone https://github.com/googlecodelabs/candle-bluetooth.git

Se hai scaricato il file di origine come file ZIP, decomprimilo dovrebbe restituire una cartella principale candle-bluetooth-master.

Installare e verificare il server web

Anche se puoi utilizzare liberamente il tuo server web, questo codelab è stato progettato per funzionare bene con il server web Chrome. Se non hai ancora installato l'app, puoi installarla dal Chrome Web Store.

Dopo aver installato l'app server web per Chrome, fai clic sulla scorciatoia App nella barra dei preferiti:

Screen Shot 16-11-2016 at 16.10.42.png

Nella finestra che viene visualizzata, fai clic sull'icona del server web:

9f3c21b2cf6cbfb5.png

Verrà visualizzata la finestra di dialogo riportata di seguito, che ti consente di configurare il server web locale:

Screen Shot 16-11-2016 at 15.40.47.png

Fai clic sul pulsante Scegli cartella e seleziona la radice del repository clonato (o rimosso dall'archivio). In questo modo potrai pubblicare il job in corso tramite l'URL evidenziato nella finestra di dialogo del server web (nella sezione URL server web).

In Opzioni, seleziona la casella accanto a "Mostra automaticamente index.html", come mostrato di seguito:

Screen Shot 16-11-2016 at 15.40.56.png

Ora visita il tuo sito nel browser web (facendo clic sull'URL del server web evidenziato). Dovresti vedere una pagina simile alla seguente:

Screen Shot 16-11-2016 at 15.20.22.png

Per vedere come si presenta questa app sul tuo telefono Android, devi attivare il Debug remoto su Android e configurare l'inoltro alla porta (il numero di porta per impostazione predefinita è 8887). Dopodiché puoi semplicemente aprire una nuova scheda di Chrome all'indirizzo http://localhost:8887 sul tuo telefono Android.

A seguire

Al momento l'applicazione web non è molto utile. Iniziamo ad aggiungere il supporto Bluetooth!

4. Scopri la candela

Inizieremo scrivendo una libreria che utilizzi una classe JavaScript ES2015 per il dispositivo Bluetooth PLAYBULB Candle.

Mantieni la calma. La sintassi delle classi non introduce un nuovo modello di ereditarietà orientato agli oggetti in JavaScript. Fornisce semplicemente una sintassi molto più chiara per creare oggetti e gestire l'ereditarietà, come puoi leggere di seguito.

Per prima cosa, definiamo una classe PlaybulbCandle in playbulbCandle.js e creiamo un'istanza playbulbCandle che sarà disponibile nel file app.js in un secondo momento.

playbulbCandle.js

(function() {
  'use strict';

  class PlaybulbCandle {
    constructor() {
      this.device = null;
    }
  }

  window.playbulbCandle = new PlaybulbCandle();

})();

Per richiedere l'accesso a un dispositivo Bluetooth nelle vicinanze, dobbiamo chiamare il numero navigator.bluetooth.requestDevice. Poiché il dispositivo PLAYBULB Candle pubblicizza in modo continuo (se non è già accoppiato) un UUID Bluetooth GATT Service costante noto nel formato breve come 0xFF02, possiamo semplicemente definire una costante e aggiungerla al parametro dei filtri per i servizi in un nuovo metodo connect pubblico della classe PlaybulbCandle.

Terremo anche traccia internamente all'oggetto BluetoothDevice in modo da potervi accedere in un secondo momento, se necessario. Poiché navigator.bluetooth.requestDevice restituisce una promessa JavaScript ES2015 Promise, lo faremo nel metodo 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();

})();

Come funzionalità di sicurezza, il rilevamento di dispositivi Bluetooth nelle vicinanze con navigator.bluetooth.requestDevice deve essere chiamato tramite un gesto dell'utente, ad esempio un tocco o un clic del mouse. Ecco perché chiameremo il metodo connect quando l'utente fa clic sul pulsante "Connetti" nel file 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);
  });
});

Esegui l'app

A questo punto, visita il tuo sito nel browser web (facendo clic sull'URL del server web evidenziato nell'app server web) o aggiorna semplicemente la pagina esistente. Fai clic sul pulsante verde "Connetti". seleziona il dispositivo nel selettore e apri la tua console preferita di DevTools con la scorciatoia da tastiera Ctrl + Maiusc + J. Noterai che l'oggetto BluetoothDevice viene registrato.

Screen Shot 16-11-2016 at 15.27.12.png

Potresti visualizzare un errore se il Bluetooth è disattivato e/o il dispositivo Bluetooth PLAYBULB Candle è spento. In tal caso, attivala e procedi di nuovo.

Bonus obbligatorio

Non so tu, ma vedo già troppi function() {} in questo codice. Passiamo alle funzioni freccia di () => {} JavaScript ES2015. Sono una salvezza assoluta: la bellezza delle funzioni anonime, nessuna della tristezza del legame.

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

A seguire

- Ok... posso parlare con questa candela o cosa?

- Certo... vai al passaggio successivo

Domande frequenti

5. Leggi qualcosa

Che cosa fai ora che hai ricevuto un BluetoothDevice restituito dalla promessa di navigator.bluetooth.requestDevice? Connettiti al server GATT remoto Bluetooth che contiene il servizio Bluetooth e le definizioni delle caratteristiche chiamando 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();
      });
    }
  }

Leggere il nome del dispositivo

Qui siamo collegati al server GATT del dispositivo Bluetooth PLAYBULB Candle. Ora vogliamo ottenere il servizio GATT principale (pubblicizzato in precedenza come 0xFF02) e leggere la caratteristica del nome del dispositivo (0xFFFF) che appartiene a questo servizio. Per farlo, puoi facilmente aggiungere un nuovo metodo getDeviceName alla classe PlaybulbCandle e utilizzare device.gatt.getPrimaryService e service.getCharacteristic. Il metodo characteristic.readValue restituisce effettivamente un valore DataView che decodificheremo semplicemente con 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);
      });
    }

Aggiungiamo questo elemento a app.js chiamando il numero playbulbCandle.getDeviceName quando siamo connessi e mostriamo il nome del dispositivo.

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

A questo punto, visita il tuo sito nel browser web (facendo clic sull'URL del server web evidenziato nell'app server web) o aggiorna semplicemente la pagina esistente. Assicurati che la candela PLAYBULB sia accesa, quindi fai clic sul pulsante "Connetti" della pagina e dovresti vedere il nome del dispositivo sotto il selettore colori.

Screen Shot 16-11-2016 at 15.29.21.png

Leggere il livello della batteria

Nel dispositivo Bluetooth PLAYBULB Candle è disponibile anche una caratteristica Bluetooth standard del livello della batteria che contiene il livello della batteria del dispositivo. Ciò significa che possiamo utilizzare nomi standard come battery_service per l'UUID del servizio GATT Bluetooth e battery_level per l'UUID della caratteristica GATT Bluetooth.

Aggiungiamo un nuovo metodo getBatteryLevel alla classe PlaybulbCandle e leggiamo il livello della batteria in percentuale.

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

Dobbiamo anche aggiornare l'oggetto JavaScript options per includere il servizio per la batteria alla chiave optionalServices, in quanto non è pubblicizzato dal dispositivo Bluetooth PLAYBULB Candle, ma è comunque obbligatorio per accedervi.

playbulbCandle.js

      let options = {filters:[{services:[ CANDLE_SERVICE_UUID ]}],
                     optionalServices: ['battery_service']};
      return navigator.bluetooth.requestDevice(options)

Come prima, colleghiamo questo dispositivo a app.js chiamando il numero playbulbCandle.getBatteryLevel una volta che abbiamo il nome del dispositivo e visualizzato il livello della batteria.

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 + '%';
}

A questo punto, visita il tuo sito nel browser web (facendo clic sull'URL del server web evidenziato nell'app server web) o aggiorna semplicemente la pagina esistente. Fai clic sul pulsante "Connetti" nella pagina, dovresti vedere sia il nome del dispositivo sia il livello della batteria.

Screen Shot 16-11-2016 at 15.29.21.png

A seguire

- Come faccio a cambiare il colore di questa lampadina? Ecco perché sono qui.

- Ci sei quasi, prometto...

Domande frequenti

6. Cambiare il colore

Cambiare colore è facile come scrivere un insieme specifico di comandi in una caratteristica Bluetooth (0xFFFC) nel servizio GATT principale pubblicizzato come 0xFF02. Ad esempio, se converti in rosso la candela PLAYBULB, scrivi un array di numeri interi senza segno a 8 bit uguali a [0x00, 255, 0, 0], dove 0x00 è la saturazione del bianco e 255, 0, 0 sono, rispettivamente, i valori rosso, verde e blu .

Utilizzeremo characteristic.writeValue per scrivere alcuni dati nella caratteristica Bluetooth nel nuovo metodo pubblico setColor della classe PlaybulbCandle. Quando la promessa viene mantenuta, ti restituiremo anche i valori rosso, verde e blu effettivi, in modo da poterli utilizzare in app.js in un secondo momento:

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

Aggiorniamo la funzione changeColor in app.js per chiamare playbulbCandle.setColor quando viene visualizzato il messaggio "Nessun effetto" sia selezionata. Le variabili colore r, g, b globali sono già impostate quando l'utente fa clic sul canvas del selettore colori.

app.js

function changeColor() {
  var effect = document.querySelector('[name="effectSwitch"]:checked').id;
  if (effect === 'noEffect') {
    playbulbCandle.setColor(r, g, b).then(onColorChanged);
  }
}

A questo punto, visita il tuo sito nel browser web (facendo clic sull'URL del server web evidenziato nell'app server web) o aggiorna semplicemente la pagina esistente. Fai clic sul pulsante "Connetti" nella pagina e fai clic sul selettore colori per cambiare il colore della candela PLAYBULB tutte le volte che vuoi.

Screen Shot 16-11-2016 at 15.31.37.png

Effetti a candela moar

Se hai già acceso una candela, sai che la luce non è statica. Fortunatamente per noi, c'è un'altra caratteristica Bluetooth (0xFFFB) nel servizio GATT principale pubblicizzato come 0xFF02 che consente all'utente di impostare alcuni effetti a candela.

Impostazione di un "effetto candela" ad esempio può essere ottenuta scrivendo [0x00, r, g, b, 0x04, 0x00, 0x01, 0x00]. Puoi anche impostare l'"effetto lampeggiante" con [0x00, r, g, b, 0x00, 0x00, 0x1F, 0x00].

Aggiungiamo i metodi setCandleEffectColor e setFlashingColor alla 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]);
    }

Inoltre aggiorniamo la funzione changeColor in app.js per chiamare playbulbCandle.setCandleEffectColor quando l'"Effetto candela" sia selezionato e playbulbCandle.setFlashingColor quando la dicitura "lampeggiante" sia selezionata. Questa volta, se ti va bene, useremo switch.

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

A questo punto, visita il tuo sito nel browser web (facendo clic sull'URL del server web evidenziato nell'app server web) o aggiorna semplicemente la pagina esistente. Fai clic sul pulsante "Connetti" sulla pagina e divertiti con gli effetti a candela e lampeggianti.

Screen Shot 16-11-2016 at 15.33.23.png

A seguire

- È tutto? Tre effetti negativi sulle candele? È per questo che sono qui?

- Ce ne sono altri, ma questa volta sarai da solo.

7. Fai uno sforzo in più

Eccoci qui! Forse pensi che sia quasi la fine del gioco, ma che l'app non è ancora finita. Vediamo se hai davvero compreso cosa hai copiato e incollato durante questo codelab. Ecco cosa vuoi fare autonomamente per far risaltare questa app.

Aggiungere effetti mancanti

Ecco i dati relativi agli effetti mancanti:

  • Pulse: [0x00, r, g, b, 0x01, 0x00, 0x09, 0x00] (puoi modificare i valori di r, g, b lì)
  • Arcobaleno: [0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00] (le persone epilettiche potrebbero voler evitare questo)
  • Dissolvenza arcobaleno: [0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x26, 0x00]

Ciò significa sostanzialmente aggiungere nuovi metodi setPulseColor, setRainbow e setRainbowFade alla classe PlaybulbCandle e chiamarli in changeColor.

Correggere l'errore "Nessun effetto"

Come avrai notato, il "nessun effetto" non reimposta alcun effetto in corso, si tratta di un comportamento minimo, ma comunque. Risolviamo il problema. Nel metodo setColor, dovrai prima verificare se è in corso un effetto tramite una nuova variabile di classe _isEffectSet e, in caso di true, disattivare l'effetto prima di impostare un nuovo colore con questi dati: [0x00, r, g, b, 0x05, 0x00, 0x01, 0x00].

Scrittura nome dispositivo

Questa è facile! Scrivere un nome di dispositivo personalizzato è semplice come scrivere nella precedente caratteristica del nome del dispositivo Bluetooth. Ti consiglio di utilizzare il metodo encode TextEncoder per ottenere un Uint8Array contenente il nome del dispositivo.

Quindi, aggiungo un "input" eventListener a document.querySelector('#deviceName') e chiama playbulbCandle.setDeviceName per semplificare le cose.

Ho chiamato personalmente il mio PLAY💡 CANDLE!

8. È tutto.

Cosa hai imparato

  • Come interagire con un dispositivo Bluetooth nelle vicinanze in JavaScript
  • Come utilizzare le classi, le funzioni delle frecce, la mappa e le promesse di ES2015

Passaggi successivi