Web Bluetooth ile PLAYBULB mumu kontrol edin

1. Neyle ilgili?

IMG_19700101_023537~2~2.jpg

Bu aydınlatıcı codelab'de, Web Bluetooth API sayesinde PLAYBULB LED alevsiz mum'u yalnızca JavaScript ile nasıl kontrol edeceğinizi öğreneceksiniz. Bu süreçte Classes, Arrow functions, Map ve Promises gibi JavaScript ES2015 özelliklerini de kullanacaksınız.

Neler öğreneceksiniz?

  • JavaScript'te yakındaki bir Bluetooth cihazıyla nasıl etkileşim kurulur?
  • ES2015 sınıflarını, ok işlevlerini, haritayı ve sözleri kullanma

Gerekenler

2. Önce oynat

Oluşturmak üzere olduğunuz uygulamanın son sürümünü https://googlecodelabs.github.io/candle-bluetooth adresinde inceleyebilir ve bu codelab'e başlamadan önce elinizdeki PLAYBULB Candle Bluetooth cihazıyla oynayabilirsiniz.

Renkleri değiştirmemi https://www.youtube.com/watch?v=fBCPA9gIxlU adresinden de izleyebilirsiniz.

3. Hazırlanın

Örnek kodu indirme

Bu kodun örnek kodunu almak için ZIP dosyasını buradan indirebilirsiniz:

veya bu Git deposunu klonlayarak:

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

Kaynağı zip olarak indirdiyseniz dosyayı açtığınızda bir kök klasör candle-bluetooth-master elde edersiniz.

Web sunucusunu yükleme ve doğrulama

Kendi web sunucunuzu kullanmakta serbest olsanız da bu codelab, Chrome Web Sunucusu ile iyi çalışacak şekilde tasarlanmıştır. Bu uygulama henüz yüklü değilse Chrome Web Mağazası'ndan yükleyebilirsiniz.

Chrome için Web Sunucusu uygulamasını yükledikten sonra yer işareti çubuğundaki Uygulamalar kısayolunu tıklayın:

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

Açılan pencerede Web Sunucusu simgesini tıklayın:

9f3c21b2cf6cbfb5.png

Ardından, yerel web sunucunuzu yapılandırmanıza olanak tanıyan bu iletişim kutusunu görürsünüz:

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

Klasör seç düğmesini tıklayın ve klonlanan (veya arşivden çıkarılan) deponun kökünü seçin. Bu işlem, web sunucusu iletişim kutusunda (Web Sunucusu URL'leri bölümünde) vurgulanan URL aracılığıyla devam eden çalışmalarınızı yayınlamanızı sağlar.

Seçenekler bölümünde, aşağıdaki resimde gösterildiği gibi "index.html dosyasını otomatik olarak göster" seçeneğinin yanındaki kutuyu işaretleyin:

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

Şimdi web tarayıcınızda sitenizi ziyaret edin (vurgulanan web sunucusu URL'sini tıklayarak). Aşağıdaki gibi bir sayfa görmelisiniz:

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

Bu uygulamanın Android telefonunuzda nasıl göründüğünü görmek istiyorsanız Android'de uzaktan hata ayıklamayı etkinleştirmeniz ve bağlantı noktası yönlendirmeyi ayarlamanız gerekir (varsayılan olarak bağlantı noktası numarası 8887'dir). Ardından, Android telefonunuzda http://localhost:8887 adresine gitmek için yeni bir Chrome sekmesi açmanız yeterlidir.

Sıradaki

Bu web uygulaması şu anda pek bir şey yapmıyor. Bluetooth desteği eklemeye başlayalım.

4. Mumu keşfedin

PLAYBULB Candle Bluetooth cihazı için JavaScript ES2015 sınıfını kullanan bir kitaplık yazarak başlayacağız.

Sakin olun. Sınıf söz dizimi, JavaScript'e yeni bir nesne yönelimli devralma modeli sunmaz. Aşağıda da görebileceğiniz gibi, nesneler oluşturmak ve devralma ile ilgilenmek için çok daha net bir söz dizimi sağlar.

Öncelikle playbulbCandle.js içinde bir PlaybulbCandle sınıfı tanımlayalım ve daha sonra app.js dosyasında kullanılabilecek bir playbulbCandle örneği oluşturalım.

playbulbCandle.js

(function() {
  'use strict';

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

  window.playbulbCandle = new PlaybulbCandle();

})();

Yakındaki bir Bluetooth cihazına erişim isteğinde bulunmak için navigator.bluetooth.requestDevice numaralı telefonu aramamız gerekiyor. PLAYBULB Candle cihazı sürekli reklam yayınladığından (daha önce eşlenmediyse) 0xFF02 kısa adıyla bilinen sabit bir Bluetooth GATT Hizmeti UUID'si kullanır. Bu nedenle, basitçe bir sabit tanımlayabilir ve bunu PlaybulbCandle sınıfının yeni bir genel connect yöntemindeki filtre hizmetleri parametresine ekleyebiliriz.

Ayrıca, gerekirse daha sonra erişebilmemiz için BluetoothDevice nesnesini dahili olarak takip edeceğiz. navigator.bluetooth.requestDevice, JavaScript ES2015 Promise döndürdüğünden bu işlemi then yönteminde yapacağız.

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

})();

Güvenlik özelliği olarak, navigator.bluetooth.requestDevice ile yakındaki Bluetooth cihazları keşfetme işlemi dokunma veya fare tıklaması gibi bir kullanıcı hareketiyle çağrılmalıdır. Bu nedenle, kullanıcı app.js dosyasındaki "Bağlan" düğmesini tıkladığında connect yöntemini çağırırız:

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

Uygulamayı çalıştırma

Bu noktada, web tarayıcınızda sitenizi ziyaret edin (web sunucusu uygulamasında vurgulanan web sunucusu URL'sini tıklayarak) veya mevcut sayfayı yenileyin. Yeşil "Bağlan" düğmesini tıklayın, seçicide cihazı belirleyin ve Ctrl + Üst Karakter + J klavye kısayoluyla en sevdiğiniz geliştirici araçları konsolunu açın. BluetoothDevice nesnesinin kaydedildiğini fark edeceksiniz.

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

Bluetooth kapalıysa ve/veya PLAYBULB Candle Bluetooth cihazı kapalıysa hata alabilirsiniz. Bu durumda, Bluetooth'u ve cihazı açıp tekrar deneyin.

Zorunlu Bonus

Seni bilmem ama bu kodda çok fazla function() {} görüyorum. Bunun yerine () => {} JavaScript ES2015 Arrow Functions'a geçelim. Bu işlevler hayat kurtarıcıdır: Anonim işlevlerin tüm güzelliği, bağlamanın üzüntüsü olmadan.

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

Sıradaki

- Tamam... Bu mumla gerçekten konuşabilir miyim?

- Elbette... sonraki adıma geçin

Sık Sorulan Sorular

5. Bir şey okuma

Peki, navigator.bluetooth.requestDevice'in sözünden dönmesi nedeniyle BluetoothDevice iade edildiğinde ne yapmanız gerekir? device.gatt.connect()'yı çağırarak Bluetooth hizmeti ve karakteristik tanımlarını içeren Bluetooth uzaktan kumanda GATT sunucusuna bağlanalım:

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

Cihaz adını okuma

Burada PLAYBULB Candle Bluetooth cihazının GATT sunucusuna bağlıyız. Şimdi birincil GATT hizmetini (daha önce 0xFF02 olarak reklamı yapılıyordu) almak ve bu hizmete ait cihaz adı karakteristiğini (0xFFFF) okumak istiyoruz. Bu, PlaybulbCandle sınıfına yeni bir yöntem getDeviceName eklenerek ve device.gatt.getPrimaryService ile service.getCharacteristic kullanılarak kolayca elde edilebilir. characteristic.readValue yöntemi aslında DataView döndürür. Bunu TextDecoder ile kodunu çözerek kullanırız.

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

Bağlandıktan sonra playbulbCandle.getDeviceName'ı arayarak ve cihaz adını göstererek bunu app.js'ya ekleyelim.

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

Bu noktada, web tarayıcınızda sitenizi ziyaret edin (web sunucusu uygulamasında vurgulanan web sunucusu URL'sini tıklayarak) veya mevcut sayfayı yenileyin. PLAYBULB Candle'ın açık olduğundan emin olun, ardından sayfadaki "Bağlan" düğmesini tıklayın. Cihaz adını renk seçicinin altında görmeniz gerekir.

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

Pil seviyesini okuma

PLAYBULB Candle Bluetooth cihazında, cihazın pil seviyesini içeren standart pil seviyesi Bluetooth özelliği de bulunur. Bu nedenle, Bluetooth GATT Hizmeti UUID'si için battery_service, Bluetooth GATT Karakteristik UUID'si için ise battery_level gibi standart adlar kullanabiliriz.

PlaybulbCandle sınıfına yeni bir getBatteryLevel yöntemi ekleyelim ve pil seviyesini yüzde olarak okuyalım.

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

Ayrıca, PLAYBULB Candle Bluetooth cihazı tarafından reklamı yapılmadığı ancak yine de erişmek için zorunlu olduğu için options JavaScript nesnesini optionalServices anahtarına pil hizmetini içerecek şekilde güncellememiz gerekiyor.

playbulbCandle.js

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

Daha önce olduğu gibi, cihaz adını aldıktan sonra playbulbCandle.getBatteryLevel'i bir kez çağırarak bunu app.js'ya bağlayalım ve pil seviyesini gösterelim.

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

Bu noktada, web tarayıcınızda sitenizi ziyaret edin (web sunucusu uygulamasında vurgulanan web sunucusu URL'sini tıklayarak) veya mevcut sayfayı yenileyin. Sayfadaki "Bağlan" düğmesini tıkladığınızda hem cihaz adını hem de pil seviyesini görürsünüz.

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

Sıradaki

- Bu ampulün rengini nasıl değiştirebilirim? Ben de bunun için buradayım.

- Çok yaklaştınız, söz veriyorum...

Sık Sorulan Sorular

6. Rengi değiştirme

Rengi değiştirmek, 0xFF02 olarak reklamı yapılan birincil GATT hizmetindeki bir Bluetooth özelliğine (0xFFFC) belirli bir komut grubu yazmak kadar kolaydır. Örneğin, PLAYBULB Candle'ı kırmızıya çevirmek, [0x00, 255, 0, 0] değerine eşit 8 bitlik işaretsiz tam sayılardan oluşan bir dizi yazmak anlamına gelir. Burada 0x00 beyaz doygunluk, 255, 0, 0 ise sırasıyla kırmızı, yeşil ve mavi değerleridir.

characteristic.writeValue, PlaybulbCandle sınıfının yeni setColor genel yönteminde Bluetooth özelliğine bazı verileri yazmak için kullanılacak. Ayrıca, söz yerine getirildiğinde gerçek kırmızı, yeşil ve mavi değerlerini de döndüreceğiz. Böylece bu değerleri daha sonra app.js içinde kullanabiliriz:

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

"Efekt Yok" radyo düğmesi işaretlendiğinde playbulbCandle.setColor işlevini çağırmak için app.js içindeki changeColor işlevini güncelleyelim. Kullanıcı renk seçici tuvalini tıkladığında genel r, g, b renk değişkenleri zaten ayarlanmış olur.

app.js

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

Bu noktada, web tarayıcınızda sitenizi ziyaret edin (web sunucusu uygulamasında vurgulanan web sunucusu URL'sini tıklayarak) veya mevcut sayfayı yenileyin. Sayfadaki "Bağlan" düğmesini ve PLAYBULB Candle'ınızın rengini istediğiniz kadar değiştirmek için renk seçiciyi tıklayın.

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

Moar candle effects

Daha önce mum yaktıysanız ışığın sabit olmadığını bilirsiniz. Neyse ki Primary GATT Service'te, 0xFF02 olarak reklamı yapılan ve kullanıcının bazı mum efektleri ayarlamasına olanak tanıyan başka bir Bluetooth özelliği (0xFFFB) var.

Örneğin, [0x00, r, g, b, 0x04, 0x00, 0x01, 0x00] yazarak "mum efekti" ayarlanabilir. Ayrıca [0x00, r, g, b, 0x00, 0x00, 0x1F, 0x00] ile "yanıp sönme efektini" de ayarlayabilirsiniz.

PlaybulbCandle sınıfına setCandleEffectColor ve setFlashingColor yöntemlerini ekleyelim.

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

Ayrıca, app.js içindeki changeColor işlevini, "Mum efekti" radyo düğmesi işaretlendiğinde playbulbCandle.setCandleEffectColor'yi, "Yanıp sönme" radyo düğmesi işaretlendiğinde ise playbulbCandle.setFlashingColor'ü çağıracak şekilde güncelleyelim. Bu sefer, sizin için uygunsa switch özelliğini kullanacağız.

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

Bu noktada, web tarayıcınızda sitenizi ziyaret edin (web sunucusu uygulamasında vurgulanan web sunucusu URL'sini tıklayarak) veya mevcut sayfayı yenileyin. Sayfadaki "Bağlan" düğmesini tıklayın ve Mum ile Yanıp Sönen Efektler'i kullanın.

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

Sıradaki

- Bu kadar mı? 3 kötü mum efekti mi? Is this why I'm here?

- Daha fazla var ancak bu sefer kendi başınıza olacaksınız.

7. Gerekenden fazlasını yapın

İşte karşınızdayız. Neredeyse sonuna geldiğinizi düşünebilirsiniz ancak uygulama henüz bitmemiştir. Bu kod laboratuvarında kopyalayıp yapıştırdığınız şeyleri gerçekten anlayıp anlamadığınızı kontrol edelim. Bu uygulamanın parlaması için şimdi kendiniz yapmanız gerekenler şunlardır.

Eksik efektleri ekleme

Eksik efektlerin verileri aşağıda verilmiştir:

  • Nabız: [0x00, r, g, b, 0x01, 0x00, 0x09, 0x00] (r, g, b değerlerini buradan ayarlayabilirsiniz)
  • Gökkuşağı: [0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00] (Epilepsi hastaları bu efekti kullanmamalıdır.)
  • Gökkuşağı Soldurma: [0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x26, 0x00]

Bu temelde, PlaybulbCandle sınıfına yeni setPulseColor, setRainbow ve setRainbowFade yöntemleri ekleyip bunları changeColor içinde çağırmak anlamına gelir.

"Efekt yok" sorununu düzeltme

Fark etmiş olabileceğiniz gibi, "etkisiz" seçeneği devam eden efektleri sıfırlamıyor. Bu küçük bir sorun olsa da yine de belirtmek istedik. Şimdi bu sorunu çözelim. setColor yönteminde, öncelikle yeni bir sınıf değişkeni _isEffectSet aracılığıyla bir efektin devam edip etmediğini kontrol etmeniz ve true ise şu verilerle yeni renk ayarlamadan önce efekti devre dışı bırakmanız gerekir: [0x00, r, g, b, 0x05, 0x00, 0x01, 0x00].

Cihaz adını yazın

Bu çok kolay! Özel bir cihaz adı yazmak, önceki Bluetooth cihaz adı özelliğine yazmak kadar basittir. Cihaz adını içeren bir Uint8Array almak için TextEncoder encode yöntemini kullanmanızı öneririz.

Ardından, eventListener girişini document.querySelector('#deviceName')'ye ekleyip playbulbCandle.setDeviceName'yi çağırarak basit tutarım.

Benimkinin adını PLAY💡 CANDLE koydum.

8. İşte bu kadar.

Öğrendikleriniz

  • JavaScript'te yakındaki bir Bluetooth cihazıyla nasıl etkileşim kurulur?
  • ES2015 sınıflarını, ok işlevlerini, haritayı ve sözleri kullanma

Sonraki Adımlar