Sterowanie świecą PLAYBULB przez Web Bluetooth

1. O czym jest ta gra?

IMG_19700101_023537~2~2.jpg

Dzięki tym ćwiczeniom z programowania dowiesz się, jak sterować płomieniową świecą LED PLAYBULB wyłącznie za pomocą JavaScriptu dzięki interfejsowi Web Bluetooth API. Podczas nauki będziesz też korzystać z funkcji języka JavaScript ES2015, takich jak klasy, funkcje strzałek, Mapa i Promises.

Czego się nauczysz

  • Jak wchodzić w interakcję z urządzeniem Bluetooth w pobliżu w języku JavaScript
  • Jak korzystać z klas, funkcji strzałek, map i obietnic ES2015

Czego potrzebujesz

2. Odtwórz jako pierwszy

Przed rozpoczęciem tego ćwiczenia z programowania warto zapoznać się z ostateczną wersją aplikacji, którą zamierzasz utworzyć, na stronie https://googlecodelabs.github.io/candle-bluetooth i pobawić się dostępnego urządzenia Bluetooth PLAYBULB Candle.

Możesz też zobaczyć, jak zmieniam kolory, na stronie https://www.youtube.com/watch?v=fBCPA9gIxlU

3. Konfiguracja

Pobierz przykładowy kod

Przykładowy kod dla tego kodu możesz pobrać, pobierając plik ZIP tutaj:

lub sklonując to repozytorium Git:

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

Jeśli źródło zostało pobrane w postaci pliku ZIP, po rozpakowaniu powinien pojawić się folder główny candle-bluetooth-master.

Instalowanie i weryfikacja serwera WWW

Możesz wykorzystać własny serwer WWW, ale to ćwiczenie w Codelabs działa dobrze z serwerem Chrome Web Server. Jeśli nie masz jeszcze zainstalowanej tej aplikacji, możesz ją zainstalować ze sklepu Chrome Web Store.

Po zainstalowaniu aplikacji Serwer internetowy dla Chrome kliknij skrót Aplikacje na pasku zakładek:

Zrzut ekranu 2016-11-16 o 4.10.42 PM.png

W wyświetlonym oknie kliknij ikonę Serwer WWW:

9f3c21b2cf6cbfb5.png

Zostanie wyświetlone następujące okno dialogowe, które umożliwia skonfigurowanie lokalnego serwera WWW:

Zrzut ekranu 2016-11-16 o 3.40.47 PM.png

Kliknij przycisk Wybierz folder i wybierz katalog główny sklonowanego (lub przywróconego z archiwum) repozytorium. Umożliwi Ci to udostępnianie tworzonej pracy pod adresem URL wyróżnionym w oknie serwera WWW (w sekcji Adresy URL serwera WWW).

W sekcji Opcje zaznacz pole „Automatycznie pokazuj index.html”, jak pokazano poniżej:

Zrzut ekranu 2016-11-16 o 3.40.56 PM.png

Teraz otwórz swoją witrynę w przeglądarce (klikając wyróżniony adres URL serwera WWW). Wyświetli się strona podobna do tej:

Zrzut ekranu 2016-11-16 o 3.20.22 PM.png

Jeśli chcesz zobaczyć, jak ta aplikacja wygląda na Twoim telefonie z Androidem, włącz Zdalne debugowanie na Androidzie i skonfiguruj przekierowanie portów (domyślnie numer portu to 8887). Gdy to zrobisz, na telefonie z Androidem możesz po prostu otworzyć nową kartę Chrome na stronie http://localhost:8887.

Dalsze czynności

Obecnie aplikacja internetowa nie robi zbyt wielu zadań. Rozpocznijmy dodawanie obsługi Bluetooth!

4. Odkryj świecę

Zaczniemy od utworzenia biblioteki korzystającej z klasy JavaScript ES2015 na potrzeby urządzenia Bluetooth PLAYBULB Candle.

Zachowaj spokój. Składnia klas nie wprowadza do JavaScriptu nowego modelu dziedziczenia zorientowanego na obiekt. Zapewnia po prostu znacznie bardziej przejrzystą składnię umożliwiającą tworzenie obiektów i obsługę dziedziczenia, jak pokazano poniżej.

Najpierw zdefiniujmy klasę PlaybulbCandle w narzędziu playbulbCandle.js i utwórz instancję playbulbCandle, która będzie dostępna później w pliku app.js.

playbulbCandle.js

(function() {
  'use strict';

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

  window.playbulbCandle = new PlaybulbCandle();

})();

Aby poprosić o dostęp do urządzenia Bluetooth w pobliżu, musimy zadzwonić pod numer navigator.bluetooth.requestDevice. Urządzenie PLAYBULB Candle reklamuje stale (jeśli nie jest jeszcze sparowane) stały identyfikator UUID usługi Bluetooth GATT znany w skrócie 0xFF02, możemy więc po prostu zdefiniować stałą i dodać ją do parametru usług filtrów w nowej publicznej metodzie connect klasy PlaybulbCandle.

Będziemy też monitorować obiekt BluetoothDevice wewnętrznie, aby w razie potrzeby mieć do niego dostęp później. Ponieważ funkcja navigator.bluetooth.requestDevice zwraca JavaScript ES2015 Promise, zrobimy to w metodzie 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();

})();

W ramach funkcji zabezpieczeń wykrywanie urządzeń Bluetooth w pobliżu za pomocą funkcji navigator.bluetooth.requestDevice musi być wywoływane gestem użytkownika, takim jak dotknięcie lub kliknięcie myszy. Dlatego po kliknięciu przycisku „Połącz” przez użytkownika będziemy nazywać metodę connect. przycisk w pliku 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);
  });
});

Uruchom aplikację

W tym momencie odwiedź swoją witrynę w przeglądarce (klikając adres URL serwera WWW zaznaczony w aplikacji serwera WWW) lub po prostu odśwież istniejącą stronę. Kliknij zielony przycisk „Połącz”, , wybierz urządzenie z selektora i otwórz ulubioną konsolę Narzędzi deweloperskich za pomocą skrótu klawiszowego Ctrl + Shift + J. Zauważ, że został zarejestrowany obiekt BluetoothDevice.

Zrzut ekranu 2016-11-16 o 3.27.12 PM.png

Jeśli Bluetooth jest wyłączony lub urządzenie Bluetooth Świeca PLAYBULB jest wyłączone, może pojawić się błąd. W takim przypadku włącz je i kontynuuj jeszcze raz.

Obowiązkowy bonus

Nie wiem jak Ty, ale w tym kodzie widzę już za dużo elementów typu function() {}. Przełączmy się na funkcje strzałek () => {} JavaScript ES2015. To absolutnie ratowanie życia: wszystkie uroki funkcji anonimowych, zero smutku związanego z wiązaniem.

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

Dalsze czynności

– OK... Mogę mówić do tej świecy czy co?

- Jasne... przejdź do następnego kroku

Najczęstsze pytania

5. Czytaj coś

Co zrobić teraz, gdy otrzymasz zwrot BluetoothDevice z oferty, którą przygotował(a) navigator.bluetooth.requestDevice? Połączmy się ze zdalnym serwerem GATT Bluetooth, który zawiera usługę Bluetooth i definicje cech, wywołując funkcję 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();
      });
    }
  }

Odczytywanie nazwy urządzenia

Nawiązaliśmy połączenie z serwerem GATT urządzenia Bluetooth PLAYBULB Candle. Teraz chcemy pobrać podstawową usługę GATT (reklamowaną wcześniej jako 0xFF02) i odczytać cechę nazwy urządzenia (0xFFFF), która należy do tej usługi. Można to łatwo osiągnąć, dodając nową metodę getDeviceName do klasy PlaybulbCandle oraz używając tagów device.gatt.getPrimaryService i service.getCharacteristic. Metoda characteristic.readValue zwraca tak naprawdę obiekt DataView, który po prostu zdekodujemy za pomocą funkcji 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);
      });
    }

Dodajmy to do urządzenia app.js, dzwoniąc pod numer playbulbCandle.getDeviceName, gdy już się połączysz i wyświetlimy nazwę urządzenia.

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

W tym momencie odwiedź swoją witrynę w przeglądarce (klikając adres URL serwera WWW zaznaczony w aplikacji serwera WWW) lub po prostu odśwież istniejącą stronę. Upewnij się, że świeca PLAYBULB jest włączona, a następnie kliknij „Połącz”. na stronie. Pod selektorem kolorów powinna się pojawić nazwa urządzenia.

Zrzut ekranu 2016-11-16 o 3.29.21 PM.png

Odczytywanie poziomu baterii

Urządzenie Bluetooth PLAYBULB Candle zawiera standardową charakterystykę Bluetooth poziomu baterii, która określa poziom baterii urządzenia. Oznacza to, że możemy używać standardowych nazw, takich jak battery_service dla identyfikatora UUID usługi Bluetooth GATT oraz battery_level dla identyfikatora UUID o charakterze GATT Bluetooth.

Dodajmy nową metodę getBatteryLevel do klasy PlaybulbCandle i odczytujemy poziom baterii w procentach.

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

Musimy również zaktualizować obiekt JavaScript options, dodając do klucza optionalServices usługę baterii, ponieważ nie jest on rozgłaszany przez urządzenie Bluetooth PLAYBULB Candle, ale i tak jest wymagany, aby uzyskać do niego dostęp.

playbulbCandle.js

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

Tak jak poprzednio, podłączmy to do urządzenia app.js, dzwoniąc pod playbulbCandle.getBatteryLevel, gdy otrzymamy nazwę urządzenia i wyświetlimy poziom baterii.

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

W tym momencie odwiedź swoją witrynę w przeglądarce (klikając adres URL serwera WWW zaznaczony w aplikacji serwera WWW) lub po prostu odśwież istniejącą stronę. Kliknij przycisk „Połącz”. na stronie, zobaczysz nazwę urządzenia i poziom baterii.

Zrzut ekranu 2016-11-16 o 3.29.21 PM.png

Dalsze czynności

- Jak zmienić kolor tej żarówki? Dlatego tu jestem.

– Jesteś już tak blisko...

Najczęstsze pytania

6. Zmiana koloru

Aby zmienić kolor, wystarczy wpisać określony zestaw poleceń na cechę Bluetooth (0xFFFC) w podstawowej usłudze GATT reklamowanej jako 0xFF02. Na przykład zmiana koloru świecy PLAYBULB na czerwony spowoduje zapisanie tablicy 8-bitowych liczb całkowitych równą [0x00, 255, 0, 0], gdzie 0x00 to nasycenie białego, a 255, 0, 0 to odpowiednio wartości czerwone, zielone i niebieskie .

Wykorzystamy characteristic.writeValue, aby zapisać część danych o charakterze Bluetooth w nowej metodzie publicznej setColor klasy PlaybulbCandle. Po spełnieniu obietnicy zwrócimy również rzeczywiste wartości czerwonego, zielonego i niebieskiego, aby można było ich później użyć w 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]);
    }

Zaktualizujmy funkcję changeColor w narzędziu app.js, tak aby wywoływała funkcję playbulbCandle.setColor w przypadku parametru „Brak efektu” jest zaznaczony. Globalne zmienne kolorów r, g, b są już ustawione, gdy użytkownik kliknie obszar roboczy selektora kolorów.

app.js

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

W tym momencie odwiedź swoją witrynę w przeglądarce (klikając adres URL serwera WWW zaznaczony w aplikacji serwera WWW) lub po prostu odśwież istniejącą stronę. Kliknij przycisk „Połącz”. na stronie. Kliknij selektor kolorów, by zmieniać kolor świecy PLAYBULB świeci tak często, jak tylko chcesz.

Zrzut ekranu 2016-11-16 o 3.31.37 PM.png

Efekty świec moarnych

Jeśli udało Ci się już zapalić świecę, oznacza to, że światło nie jest statyczne. Na szczęście w podstawowej usłudze GATT występuje jeszcze jedna cecha Bluetooth (0xFFFB), która pozwala użytkownikowi ustawić niektóre efekty świec.0xFF02

Ustawianie „efektu świecy” na przykład przez wpisanie [0x00, r, g, b, 0x04, 0x00, 0x01, 0x00]. Możesz też ustawić „efekt migania” dzięki [0x00, r, g, b, 0x00, 0x00, 0x1F, 0x00].

Dodajmy do klasy PlaybulbCandle metody setCandleEffectColor i setFlashingColor.

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

Zaktualizujmy też funkcję changeColor w app.js, tak aby wywoływała funkcję playbulbCandle.setCandleEffectColor, gdy „Efekt świecowy” jest zaznaczona opcja playbulbCandle.setFlashingColor, a opcja „Migające” jest zaznaczony. Tym razem, jeśli nie masz na to zgody, użyjemy domeny 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;
  }
}

W tym momencie odwiedź swoją witrynę w przeglądarce (klikając adres URL serwera WWW zaznaczony w aplikacji serwera WWW) lub po prostu odśwież istniejącą stronę. Kliknij przycisk „Połącz”. kliknij przycisk Świeca i Migające efekty.

Zrzut ekranu 2016-11-16 o 3.33.23 PM.png

Dalsze czynności

– To wszystko? 3 słabe efekty świec? Dlaczego tu jestem?

– Jest ich więcej, ale tym razem będziesz na swoim miejscu.

7. Dołóż dodatkowych starań

I o to chodzi! Może Ci się wydawać, że to już prawie koniec, a aplikacja jeszcze trwa. Sprawdźmy, czy rozumiesz treść skopiowaną i wklejoną podczas tego ćwiczenia z programowania. Oto, co chcesz zrobić teraz, aby ta aplikacja się wyróżniała.

Dodaj brakujące efekty

Oto dane dotyczące brakujących efektów:

  • Puls: [0x00, r, g, b, 0x01, 0x00, 0x09, 0x00] (tam warto dostosować wartości r, g, b)
  • Tęcza: [0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00] (osoby padaczkowe mogą lepiej jej unikać)
  • Tęczowe zanikanie: [0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x26, 0x00]

Oznacza to dodanie nowych metod setPulseColor, setRainbow i setRainbowFade do klasy PlaybulbCandle i wywoływanie ich w changeColor.

Rozwiązywanie problemu „Brak efektu”

Jak być może zauważyliście, opcja „Brak efektu” nie powoduje zresetowania żadnego trwającego efektu. Jest to mało istotne, ale nadal. Naprawmy to. W metodzie setColor musisz najpierw sprawdzić, czy efekt jest generowany za pomocą nowej zmiennej klasy _isEffectSet, a jeśli true, wyłącz efekt, zanim ustawisz nowy kolor na podstawie tych danych: [0x00, r, g, b, 0x05, 0x00, 0x01, 0x00].

Zapisz nazwę urządzenia

To proste! Aby wpisać własną nazwę urządzenia, wystarczy wpisać poprzednią nazwę urządzenia Bluetooth. Zalecamy użycie metody TextEncoder encode, aby uzyskać Uint8Array z nazwą urządzenia.

Następnie dodaj „wejściowe” eventListener do usługi document.querySelector('#deviceName') i wywołaj playbulbCandle.setDeviceName.

Moja nazwa to PLAY💡 CANDLE!

8. Znakomicie.

Czego się dowiedziałeś(-aś)

  • Jak wchodzić w interakcję z urządzeniem Bluetooth w pobliżu w języku JavaScript
  • Jak korzystać z klas, funkcji strzałek, map i obietnic ES2015

Następne kroki