PLAYBULB-Kerze mit Web Bluetooth steuern

1. Worum geht es?

IMG_19700101_023537~2~2.jpg

In diesem Codelab erfahren Sie, wie Sie eine PLAYBULB LED-Kerze dank der Web Bluetooth API nur mit JavaScript steuern können. Dabei lernen Sie auch JavaScript ES2015-Funktionen wie Klassen, Pfeilfunktionen, Map und Promises kennen.

Lerninhalte

  • Mit einem Bluetooth-Gerät in der Nähe in JavaScript interagieren
  • How to use ES2015 Classes, Arrow functions, Map and Promises

Voraussetzungen

2. Zuerst abspielen

Bevor Sie mit diesem Codelab beginnen, können Sie sich die endgültige Version der App, die Sie erstellen werden, unter https://googlecodelabs.github.io/candle-bluetooth ansehen und mit dem PLAYBULB Candle-Bluetooth-Gerät experimentieren, das Ihnen zur Verfügung steht.

Du kannst dir auch ein Video ansehen, in dem ich die Farben ändere: https://www.youtube.com/watch?v=fBCPA9gIxlU

3. Einrichten

Beispielcode herunterladen

Sie können den Beispielcode für diesen Code abrufen, indem Sie die ZIP-Datei hier herunterladen:

oder durch Klonen dieses Git-Repositorys:

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

Wenn Sie die Quelle als ZIP-Datei heruntergeladen haben, sollten Sie nach dem Entpacken einen Stammordner candle-bluetooth-master erhalten.

Webserver installieren und prüfen

Sie können zwar Ihren eigenen Webserver verwenden, dieses Codelab ist jedoch für die Verwendung mit dem Chrome-Webserver konzipiert. Wenn Sie diese App noch nicht installiert haben, können Sie sie aus dem Chrome Web Store herunterladen.

Klicken Sie nach der Installation der App „Web Server for Chrome“ in der Lesezeichenleiste auf die Verknüpfung „Chrome-Apps“:

Screen Shot 2016-11-16 at 4.10.42 PM.png

Klicken Sie im nächsten Fenster auf das Webserver-Symbol:

9f3c21b2cf6cbfb5.png

Als Nächstes wird dieses Dialogfeld angezeigt, in dem Sie Ihren lokalen Webserver konfigurieren können:

Screen Shot 2016-11-16 at 3.40.47 PM.png

Klicken Sie auf Ordner auswählen und wählen Sie das Stammverzeichnis des geklonten (oder entpackten) Repositorys aus. So können Sie Ihre laufende Arbeit über die URL bereitstellen, die im Dialogfeld des Webservers im Abschnitt Web Server URL(s) (Webserver-URLs) hervorgehoben ist.

Klicken Sie unter „Optionen“ das Kästchen neben index.html automatisch anzeigen an, wie unten dargestellt:

Screen Shot 2016-11-16 at 3.40.56 PM.png

Rufen Sie jetzt Ihre Website in Ihrem Webbrowser auf, indem Sie auf die hervorgehobene Webserver-URL klicken. Es sollte eine Seite wie diese angezeigt werden:

Screen Shot 2016-11-16 at 3.20.22 PM.png

Wenn Sie sehen möchten, wie diese App auf Ihrem Android-Smartphone aussieht, müssen Sie das Remote-Debugging auf Android-Geräten aktivieren und die Portweiterleitung einrichten (die Portnummer ist standardmäßig 8887). Anschließend können Sie auf Ihrem Android-Smartphone einfach einen neuen Chrome-Tab mit der URL http://localhost:8887 öffnen.

Nächster Artikel

Im Moment kann diese Web-App noch nicht viel. Fügen wir Bluetooth-Unterstützung hinzu.

4. Kerze entdecken

Zuerst schreiben wir eine Bibliothek, die eine JavaScript-ES2015-Klasse für das Bluetooth-Gerät PLAYBULB Candle verwendet.

Bleiben Sie ruhig. Die Klassensyntax führt kein neues objektorientiertes Vererbungsmodell in JavaScript ein. Sie bietet lediglich eine viel klarere Syntax zum Erstellen von Objekten und zum Umgang mit Vererbung, wie Sie unten nachlesen können.

Zuerst definieren wir eine PlaybulbCandle-Klasse in playbulbCandle.js und erstellen eine playbulbCandle-Instanz, die später in der Datei app.js verfügbar ist.

playbulbCandle.js

(function() {
  'use strict';

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

  window.playbulbCandle = new PlaybulbCandle();

})();

Wenn wir Zugriff auf ein Bluetooth-Gerät in der Nähe anfordern möchten, müssen wir navigator.bluetooth.requestDevice aufrufen. Da das PLAYBULB Candle-Gerät kontinuierlich (wenn es nicht bereits gekoppelt ist) eine konstante Bluetooth GATT-Dienst-UUID mit der Kurzform 0xFF02 sendet, können wir einfach eine Konstante definieren und diese dem Parameter „filters services“ in einer neuen öffentlichen connect-Methode der Klasse PlaybulbCandle hinzufügen.

Wir behalten das BluetoothDevice-Objekt auch intern im Auge, damit wir später bei Bedarf darauf zugreifen können. Da navigator.bluetooth.requestDevice ein JavaScript ES2015-Promise zurückgibt, verwenden wir dafür die Methode 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();

})();

Als Sicherheitsfunktion muss die Suche nach Bluetooth-Geräten in der Nähe mit navigator.bluetooth.requestDevice über eine Nutzergeste wie eine Berührung oder einen Mausklick aufgerufen werden. Deshalb rufen wir die Methode connect auf, wenn der Nutzer in der Datei app.js auf den Button „Verbinden“ klickt:

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

App ausführen

Rufen Sie jetzt Ihre Website im Webbrowser auf, indem Sie auf die in der Webserver-App hervorgehobene Webserver-URL klicken, oder aktualisieren Sie einfach die vorhandene Seite. Klicke auf die grüne Schaltfläche „Connect“ (Verbinden), wähle das Gerät aus und öffne deine bevorzugte DevTools-Konsole mit der Tastenkombination „Strg + Umschalttaste + J“. Beachte das protokollierte BluetoothDevice-Objekt.

Screen Shot 2016-11-16 at 3.27.12 PM.png

Wenn Bluetooth und/oder das Bluetooth-Gerät PLAYBULB Candle ausgeschaltet ist, wird möglicherweise ein Fehler angezeigt. Schalten Sie es in diesem Fall ein und versuchen Sie es noch einmal.

Obligatorischer Bonus

Ich weiß nicht, wie es Ihnen geht, aber ich sehe in diesem Code bereits zu viele function() {}. Wechseln wir stattdessen zu () => {} JavaScript ES2015-Pfeilfunktionen. Sie sind ein absoluter Lebensretter: Alle Vorteile anonymer Funktionen, keine der Nachteile der Bindung.

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

Nächster Artikel

– Ok… kann ich jetzt mit dieser Kerze sprechen oder was?

- Klar, springen wir zum nächsten Schritt.

Häufig gestellte Fragen

5. Etwas lesen

Was machen Sie jetzt, da Sie ein BluetoothDevice aus dem Promise von navigator.bluetooth.requestDevice zurückerhalten haben? Stellen wir eine Verbindung zum Bluetooth-Remote-GATT-Server her, der die Bluetooth-Dienst- und ‑Merkmaldefinitionen enthält, indem wir device.gatt.connect() aufrufen:

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

Gerätenamen lesen

Hier sind wir mit dem GATT-Server des Bluetooth-Geräts PLAYBULB Candle verbunden. Jetzt möchten wir den primären GATT-Dienst (zuvor als 0xFF02 beworben) abrufen und das zu diesem Dienst gehörende Merkmal für den Gerätenamen (0xFFFF) lesen. Dazu fügen Sie der Klasse PlaybulbCandle die neue Methode getDeviceName hinzu und verwenden device.gatt.getPrimaryService und service.getCharacteristic. Die Methode characteristic.readValue gibt ein DataView zurück, das wir einfach mit TextDecoder decodieren.

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

Fügen wir dies zu app.js hinzu, indem wir playbulbCandle.getDeviceName aufrufen, sobald die Verbindung hergestellt ist, und den Gerätenamen anzeigen.

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

Rufen Sie jetzt Ihre Website im Webbrowser auf, indem Sie auf die in der Webserver-App hervorgehobene Webserver-URL klicken, oder aktualisieren Sie einfach die vorhandene Seite. Achte darauf, dass die PLAYBULB Candle eingeschaltet ist, und klicke dann auf der Seite auf die Schaltfläche „Verbinden“. Der Gerätename sollte unter der Farbauswahl angezeigt werden.

Screen Shot 2016-11-16 at 3.29.21 PM.png

Akkustand vorlesen lassen

Das Bluetooth-Gerät PLAYBULB Candle verfügt auch über ein Standard-Bluetooth-Merkmal für den Akkustand, das den Akkustand des Geräts enthält. Das bedeutet, dass wir Standardnamen wie battery_service für die Bluetooth-GATT-Dienst-UUID und battery_level für die Bluetooth-GATT-Merkmal-UUID verwenden können.

Fügen wir der Klasse PlaybulbCandle eine neue Methode getBatteryLevel hinzu und lesen den Akkustand in Prozent aus.

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

Außerdem müssen wir das JavaScript-Objekt options aktualisieren, um den Batteriedienst in den Schlüssel optionalServices aufzunehmen, da er vom PLAYBULB Candle-Bluetooth-Gerät nicht beworben wird, aber dennoch für den Zugriff darauf erforderlich ist.

playbulbCandle.js

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

Wie zuvor fügen wir dies in app.js ein, indem wir playbulbCandle.getBatteryLevel aufrufen, sobald wir den Gerätenamen haben, und den Akkustand anzeigen.

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

Rufen Sie jetzt Ihre Website im Webbrowser auf, indem Sie auf die in der Webserver-App hervorgehobene Webserver-URL klicken, oder aktualisieren Sie einfach die vorhandene Seite. Klicke auf der Seite auf die Schaltfläche „Verbinden“. Daraufhin sollten sowohl der Gerätename als auch der Akkustand angezeigt werden.

Screen Shot 2016-11-16 at 3.29.21 PM.png

Nächster Artikel

– Wie kann ich die Farbe dieser Lampe ändern? Deshalb bin ich hier.

- Du bist fast am Ziel, versprochen…

Häufig gestellte Fragen

6. Farbe ändern

Die Farbe lässt sich ganz einfach ändern, indem du eine bestimmte Reihe von Befehlen in ein Bluetooth-Merkmal (0xFFFC) im primären GATT-Dienst schreibst, der als 0xFF02 beworben wird. Wenn du deine PLAYBULB Candle beispielsweise auf Rot einstellen möchtest, wird ein Array von vorzeichenlosen 8-Bit-Ganzzahlen geschrieben, das [0x00, 255, 0, 0] entspricht, wobei 0x00 die weiße Sättigung und 255, 0, 0 die Werte für Rot, Grün und Blau sind .

Wir verwenden characteristic.writeValue, um in der neuen öffentlichen Methode setColor der Klasse PlaybulbCandle Daten in das Bluetooth-Merkmal zu schreiben. Außerdem geben wir die tatsächlichen Rot-, Grün- und Blauwerte zurück, wenn das Promise erfüllt ist, damit wir sie später in app.js verwenden können:

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

Aktualisieren Sie die Funktion changeColor in app.js, um playbulbCandle.setColor aufzurufen, wenn das Optionsfeld „Kein Effekt“ ausgewählt ist. Die globalen Farbvariablen r, g, b sind bereits festgelegt, wenn der Nutzer auf den Canvas der Farbauswahl klickt.

app.js

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

Rufen Sie jetzt Ihre Website im Webbrowser auf, indem Sie auf die in der Webserver-App hervorgehobene Webserver-URL klicken, oder aktualisieren Sie einfach die vorhandene Seite. Klicken Sie auf der Seite auf den Button „Verbinden“ und dann auf die Farbauswahl, um die Farbe Ihrer PLAYBULB Candle beliebig oft zu ändern.

Screen Shot 2016-11-16 at 3.31.37 PM.png

Mehr Kerzeneffekte

Wenn du schon einmal eine Kerze angezündet hast, weißt du, dass das Licht nicht statisch ist. Glücklicherweise gibt es im primären GATT-Dienst, der als 0xFF02 beworben wird, ein weiteres Bluetooth-Merkmal (0xFFFB), mit dem der Nutzer einige Kerzeneffekte einstellen kann.

Wenn du beispielsweise einen „Kerzeneffekt“ einstellen möchtest, kannst du [0x00, r, g, b, 0x04, 0x00, 0x01, 0x00] schreiben. Mit [0x00, r, g, b, 0x00, 0x00, 0x1F, 0x00] kannst du auch den „Blinkeffekt“ festlegen.

Fügen wir der Klasse PlaybulbCandle die Methoden setCandleEffectColor und setFlashingColor hinzu.

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

Aktualisieren wir die Funktion changeColor in app.js, um playbulbCandle.setCandleEffectColor aufzurufen, wenn das Optionsfeld „Candle Effect“ aktiviert ist, und playbulbCandle.setFlashingColor, wenn das Optionsfeld „Flashing“ aktiviert ist. Dieses Mal verwenden wir switch, wenn das für dich in Ordnung ist.

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

Rufen Sie jetzt Ihre Website im Webbrowser auf, indem Sie auf die in der Webserver-App hervorgehobene Webserver-URL klicken, oder aktualisieren Sie einfach die vorhandene Seite. Klicke auf der Seite auf die Schaltfläche „Verbinden“ und spiele mit den Effekten „Kerze“ und „Blinken“.

Screen Shot 2016-11-16 at 3.33.23 PM.png

Nächster Artikel

- Das ist alles? 3 schlechte Kerzeneffekte? Bin ich deshalb hier?

- Es gibt noch mehr, aber dieses Mal musst du sie selbst finden.

7. Fans miteinbeziehen

Und hier sind wir! Sie denken vielleicht, dass Sie fast am Ende sind, aber die App ist noch nicht fertig. Mal sehen, ob Sie wirklich verstanden haben, was Sie in diesem Codelab kopiert und eingefügt haben. Hier sind die Schritte, die Sie jetzt selbst ausführen müssen, um diese App zum Glänzen zu bringen.

Fehlende Effekte hinzufügen

Hier sind die Daten für die fehlenden Effekte:

  • Pulse: [0x00, r, g, b, 0x01, 0x00, 0x09, 0x00] (möglicherweise müssen Sie die r, g, b-Werte dort anpassen)
  • Regenbogen: [0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00] (Menschen mit Epilepsie sollten diesen Effekt vermeiden)
  • Regenbogen-Farbverlauf: [0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x26, 0x00]

Dazu müssen Sie der Klasse PlaybulbCandle die neuen Methoden setPulseColor, setRainbow und setRainbowFade hinzufügen und sie in changeColor aufrufen.

„Keine Auswirkung“ beheben

Wie Sie vielleicht bemerkt haben, wird mit der Option „Kein Effekt“ kein laufender Effekt zurückgesetzt. Das ist zwar nur ein kleines Problem, aber immerhin. Lass uns das beheben. In der Methode setColor musst du zuerst über eine neue Klassenvariable _isEffectSet prüfen, ob ein Effekt aktiv ist. Wenn true, deaktiviere den Effekt, bevor du mit diesen Daten eine neue Farbe festlegst: [0x00, r, g, b, 0x05, 0x00, 0x01, 0x00].

Gerätenamen eingeben

Das ist einfach. Das Schreiben eines benutzerdefinierten Gerätenamens ist so einfach wie das Schreiben in das vorherige Bluetooth-Gerätenamen-Attribut. Ich empfehle, die Methode TextEncoder encode zu verwenden, um ein Uint8Array mit dem Gerätenamen abzurufen.

Dann würde ich document.querySelector('#deviceName') eine „Eingabe“ eventListener hinzufügen und sie playbulbCandle.setDeviceName nennen, um es einfach zu halten.

Ich habe meine PLAY💡 CANDLE! genannt.

8. Geschafft!

Das haben Sie gelernt

  • Mit einem Bluetooth-Gerät in der Nähe in JavaScript interagieren
  • How to use ES2015 Classes, Arrow functions, Map and Promises

Nächste Schritte