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 yalnızca JavaScript kullanarak PLAYBULB LED alevsiz mumu 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 cihazla etkileşim kurma
  • ES2015 sınıfları, ok işlevleri, harita ve Promise'leri kullanma

Gerekenler

2. İlk olarak oynat

Bu codelab'e başlamadan önce, oluşturmak üzere olduğunuz uygulamanın son sürümüne https://googlecodelabs.github.io/candle-bluetooth adresinden göz atabilir ve elinizdeki PLAYBULB Candle Bluetooth cihazıyla denemeler yapabilirsiniz.

Renk değiştirdiğim videoyu https://www.youtube.com/watch?v=fBCPA9gIxlU adresinden de izleyebilirsiniz.

3. Kurun

Örnek kodu indirme

Bu kodun örnek kodunu, ZIP dosyasını buradan indirerek alabilirsiniz:

veya şu Git deposunu klonlayarak:

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

Kaynağı ZIP dosyası olarak indirdiyseniz paketi açtığınızda candle-bluetooth-master kök klasörü oluşturulur.

Web sunucusunu yükleme ve doğrulama

Kendi web sunucunuzu kullanmakta özgür 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şaretleri çubuğundaki Chrome Uygulamaları kısayolunu tıklayın:

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

Açılan pencerede Web Server (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 sayede, devam eden çalışmanızı web sunucusu iletişim kutusunda (Web Sunucusu URL'leri bölümünde) vurgulanan URL üzerinden yayınlayabilirsiniz.

Seçenekler bölümünde, aşağıda 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). Şuna benzer bir sayfa göreceksiniz:

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 (bağlantı noktası numarası varsayılan olarak 8887'dir). Ardından, Android telefonunuzda http://localhost:8887 adresine giden yeni bir Chrome sekmesi açabilirsiniz.

Sıradaki

Bu aşamada bu web uygulaması pek bir şey yapmaz. 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 getirmez. Aşağıda okuyabileceğiniz gibi, nesne 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ılacak 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 cihaza erişim isteğinde bulunmak için navigator.bluetooth.requestDevice yöntemini çağırmamız gerekir. PLAYBULB Candle cihazı, kısa biçimi 0xFF02 olan sabit bir Bluetooth GATT Hizmeti UUID'sini sürekli olarak bildirdiğinden (henüz eşlenmemişse) basit bir sabit tanımlayabilir ve bunu PlaybulbCandle sınıfının yeni bir herkese açık connect yöntemindeki filtre hizmetleri parametresine ekleyebiliriz.

Ayrıca, gerektiğinde daha sonra erişebilmek için BluetoothDevice nesnesini dahili olarak takip ederiz. navigator.bluetooth.requestDevice bir JavaScript ES2015 Promise döndürdüğünden bunu 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ğıracağı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ı seçin ve Ctrl + Üst Karakter + J klavye kısayoluyla favori Geliştirici Araçları konsolunuzu açın ve günlüğe kaydedilen BluetoothDevice nesnesine dikkat edin.

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 cihazı açıp tekrar devam edin.

Zorunlu Bonus

Sizi bilmem ama ben bu kodda çok fazla function() {} görüyorum. Bunun yerine () => {} JavaScript ES2015 ok işlevlerine geçelim. Bunlar hayat kurtarıcıdır: Anonim işlevlerin tüm güzelliği, bağlamanın hiçbir üzüntüsü yoktur.

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 konuşabilir miyim?

- Tabii, sonraki adıma geçelim

Sık Sorulan Sorular

5. Bir şeyler okuma

navigator.bluetooth.requestDevice tarafından döndürülen bir BluetoothDevice nesnesi aldığınızda ne yaparsınız? device.gatt.connect() yöntemini çağırarak Bluetooth hizmetini ve özellik tanımlarını barındıran Bluetooth uzak 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 Hizmeti'ni (daha önce 0xFF02 olarak bildirilmişti) almak ve bu hizmete ait cihaz adı özelliğini (0xFFFF) okumak istiyoruz. Bu işlem, PlaybulbCandle sınıfına yeni bir getDeviceName yöntemi ekleyerek ve device.gatt.getPrimaryService ile service.getCharacteristic kullanılarak kolayca yapılabilir. characteristic.readValue yöntemi, TextDecoder ile kolayca kodunu çözeceğimiz bir DataView döndürür.

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ğlantı kurulduktan sonra playbulbCandle.getDeviceName yöntemini çağırarak bunu app.js öğesine ekleyelim ve cihaz adını 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);
  })
  .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. Renk seçicinin altında cihaz adını görürsünüz.

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 bir pil seviyesi Bluetooth özelliği de bulunur. Bu, Bluetooth GATT Hizmeti UUID'si için battery_service ve Bluetooth GATT Özelliği UUID'si için battery_level gibi standart adlar kullanabileceğimiz anlamına gelir.

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 tanıtılmadığı ancak erişim için hâlâ zorunlu olduğu için options JavaScript nesnesini, pil hizmetini optionalServices anahtarına dahil edecek şekilde güncellememiz gerekir.

playbulbCandle.js

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

Daha önce yaptığımız gibi, cihaz adını aldıktan sonra playbulbCandle.getBatteryLevel işlevini çağırarak bunu app.js işlevine 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 tanıtılan Birincil GATT Hizmeti'ndeki bir Bluetooth Özelliği'ne (0xFFFC) belirli bir komut grubu yazmak kadar kolaydır. Örneğin, PLAYBULB Candle'ınızı kırmızıya çevirmek, [0x00, 255, 0, 0] değerine eşit 8 bitlik işaretsiz tam sayı dizisi yazmak anlamına gelir. Burada 0x00 beyaz doygunluğu, 255, 0, 0 ise sırasıyla kırmızı, yeşil ve mavi değerleridir.

PlaybulbCandle sınıfının yeni setColor herkese açık yönteminde Bluetooth özelliğine veri yazmak için characteristic.writeValue kullanacağız. Ayrıca, söz yerine getirildiğinde gerçek kırmızı, yeşil ve mavi değerlerini de döndürürüz. Böylece bunları 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]);
    }

"No Effect" 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 global r, g, b renk değişkenleri zaten ayarlanmıştır.

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 tıklayın 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

Daha fazla mum efekti

Daha önce mum yaktıysanız ışığın sabit olmadığını bilirsiniz. Neyse ki birincil GATT hizmetinde 0xFF02 olarak tanıtılan başka bir Bluetooth özelliği (0xFFFB) var. Bu özellik, kullanıcının bazı mum efektleri ayarlamasına olanak tanıyor.

Örneğin, [0x00, r, g, b, 0x04, 0x00, 0x01, 0x00] yazarak "mum efekti" ayarlayabilirsiniz. Ayrıca [0x00, r, g, b, 0x00, 0x00, 0x1F, 0x00] ile "yanıp sönme efekti" 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]);
    }

Şimdi de app.js içindeki changeColor işlevini, "Mum Efekti" radyo düğmesi işaretlendiğinde playbulbCandle.setCandleEffectColor işlevini, "Yanıp Sönme" radyo düğmesi işaretlendiğinde ise playbulbCandle.setFlashingColor işlevini çağıracak şekilde güncelleyelim. Sizin için de uygunsa bu kez switch 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 ve yanıp sönme efektleriyle oynayın.

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

Sıradaki

- Bu kadar mı? 3 zayıf mum efekti mi? Burada olmamın nedeni bu mu?

- Daha fazlası var ama bu sefer yalnız olacaksınız.

7. Gerekenden fazlasını yapın

İşte buradayız. Neredeyse bittiğini düşünebilirsiniz ancak uygulama henüz tamamlanmadı. Bu codelab'de kopyalayıp yapıştırdığınız kodları gerçekten anlayıp anlamadığınızı görelim. Bu uygulamanın öne çıkması için şimdi kendi başınıza yapmanız gerekenler şunlardır.

Eksik efektleri ekleme

Eksik efektlerle ilgili veriler aşağıda verilmiştir:

  • Pulse: [0x00, r, g, b, 0x01, 0x00, 0x09, 0x00] (burada r, g, b değerlerini ayarlamanız gerekebilir)
  • Gökkuşağı: [0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00] (Epilepsi hastaları bu efekti kullanmaktan kaçınabilir.)
  • Gökkuşağı Geçişi: [0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x26, 0x00]

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

"Etki yok" sorununu düzeltme

Fark etmiş olabileceğiniz gibi, "efekt yok" seçeneği devam eden efektleri sıfırlamıyor. Bu küçük bir sorun olsa da yine de belirtmek istedim. Şimdi bu sorunu çözelim. setColor yönteminde, önce 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 rengi ayarlamadan önce efekti kapatmanı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 elde etmek için TextEncoder encode yöntemini kullanmanızı öneririz.

Ardından, document.querySelector('#deviceName') için bir "giriş" eventListener ekleyip basit olması için playbulbCandle.setDeviceName işlevini çağırırım.

Ben kendi mumuma PLAY💡 CANDLE adını verdim.

8. İşte bu kadar.

Öğrendikleriniz

  • JavaScript'te yakındaki bir Bluetooth cihazla etkileşim kurma
  • ES2015 sınıfları, ok işlevleri, harita ve Promise'leri kullanma

Sonraki Adımlar