یک شمع PLAYBULB را با بلوتوث وب کنترل کنید

1. در مورد چیست؟

IMG_19700101_023537~2~2.jpg

در این آزمایشگاه کد روشن، شما یاد خواهید گرفت که چگونه یک شمع بدون شعله LED PLAYBULB را با چیزی جز جاوا اسکریپت به لطف Web Bluetooth API کنترل کنید. در طول مسیر، شما همچنین با ویژگی‌های جاوا اسکریپت ES2015 مانند کلاس‌ها ، عملکردهای پیکان ، نقشه و وعده‌ها بازی خواهید کرد.

چیزی که یاد خواهید گرفت

  • نحوه تعامل با دستگاه بلوتوث نزدیک در جاوا اسکریپت
  • نحوه استفاده از کلاس های ES2015، توابع پیکان، نقشه و وعده ها

آنچه شما نیاز دارید

2. ابتدا بازی کنید

ممکن است بخواهید نسخه نهایی برنامه ای را که می خواهید ایجاد کنید در https://googlecodelabs.github.io/candle-bluetooth بررسی کنید و قبل از اینکه واقعاً وارد این دستگاه شوید با دستگاه بلوتوث PLAYBULB Candle که در اختیار دارید بازی کنید. نرم افزار کد.

همچنین می توانید تغییر رنگ من را در https://www.youtube.com/watch?v=fBCPA9gIxlU تماشا کنید

3. راه اندازی شوید

نمونه کد را دانلود کنید

می توانید کد نمونه این کد را با دانلود فایل فشرده از اینجا دریافت کنید:

یا با شبیه سازی این مخزن git:

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

اگر منبع را به صورت فشرده دانلود کرده اید، باز کردن آن باید یک پوشه root candle-bluetooth-master به شما بدهد.

وب سرور را نصب و تأیید کنید

در حالی که شما آزاد هستید که از وب سرور خود استفاده کنید، این کد لبه برای کار با وب سرور کروم طراحی شده است. اگر هنوز آن برنامه را نصب نکرده‌اید، می‌توانید آن را از فروشگاه وب Chrome نصب کنید.

پس از نصب وب سرور برای برنامه کروم، روی میانبر Apps در نوار نشانک ها کلیک کنید:

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

در پنجره بعدی، روی نماد وب سرور کلیک کنید:

9f3c21b2cf6cbfb5.png

در ادامه این گفتگو را خواهید دید که به شما امکان می دهد وب سرور محلی خود را پیکربندی کنید:

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

روی دکمه انتخاب پوشه کلیک کنید و ریشه مخزن کلون شده (یا بایگانی نشده) را انتخاب کنید. این به شما امکان می‌دهد تا کارهای در حال انجام خود را از طریق URL مشخص شده در گفتگوی وب سرور (در بخش URL(های) وب سرور ) ارائه دهید.

در زیر گزینه‌ها، کادر کنار « نمایش خودکار index.html » را علامت بزنید، همانطور که در زیر نشان داده شده است:

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

اکنون از سایت خود در مرورگر وب خود بازدید کنید (با کلیک بر روی URL وب سرور برجسته شده) و باید صفحه ای را مشاهده کنید که به شکل زیر است:

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

اگر می‌خواهید ببینید این برنامه در تلفن اندرویدی شما چگونه به نظر می‌رسد، باید Remote debugging را در Android فعال کنید و Port Forwarding را تنظیم کنید (شماره پورت به طور پیش‌فرض 8887 است). پس از آن، به سادگی می توانید یک تب جدید کروم را به آدرس http://localhost:8887 در تلفن اندرویدی خود باز کنید.

بعدی

در این مرحله این برنامه وب کار زیادی انجام نمی دهد. بیایید شروع به اضافه کردن پشتیبانی بلوتوث کنیم!

4. شمع را کشف کنید

ما با نوشتن کتابخانه ای شروع می کنیم که از کلاس JavaScript ES2015 برای دستگاه بلوتوث PLAYBULB Candle استفاده می کند.

آرامش خود را حفظ کنید. سینتکس کلاس یک مدل ارثی شی گرا جدید را به جاوا اسکریپت معرفی نمی کند. همانطور که در زیر می توانید بخوانید، به سادگی یک نحو بسیار واضح برای ایجاد اشیاء و مقابله با وراثت ارائه می دهد.

ابتدا، بیایید یک کلاس PlaybulbCandle در playbulbCandle.js تعریف کنیم و یک نمونه playbulbCandle ایجاد کنیم که بعداً در فایل app.js در دسترس خواهد بود.

playbulbCandle.js

(function() {
  'use strict';

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

  window.playbulbCandle = new PlaybulbCandle();

})();

برای درخواست دسترسی به یک دستگاه بلوتوث نزدیک، باید با navigator.bluetooth.requestDevice تماس بگیرید. از آنجایی که دستگاه PLAYBULB Candle به طور مداوم (اگر قبلاً جفت نشده است) یک UUID سرویس GATT Bluetooth ثابت که به شکل کوتاه آن به عنوان 0xFF02 شناخته می شود، تبلیغ می کند، می توانیم به سادگی یک ثابت تعریف کرده و آن را به پارامتر خدمات فیلترها در روش connect عمومی جدید PlaybulbCandle اضافه کنیم. کلاس

ما همچنین شیء BluetoothDevice را به صورت داخلی پیگیری خواهیم کرد تا در صورت نیاز بتوانیم بعداً به آن دسترسی داشته باشیم. از آنجایی که navigator.bluetooth.requestDevice یک JavaScript ES2015 Promise را برمی گرداند، ما این کار را در روش 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();

})();

به عنوان یک ویژگی امنیتی، کشف دستگاه‌های بلوتوث نزدیک با navigator.bluetooth.requestDevice باید از طریق یک حرکت کاربر مانند لمس یا کلیک ماوس فراخوانی شود. به همین دلیل است که وقتی کاربر روی دکمه «اتصال» در فایل app.js کلیک می‌کند، روش connect فراخوانی می‌کنیم:

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

برنامه را اجرا کنید

در این مرحله، از سایت خود در مرورگر وب خود بازدید کنید (با کلیک بر روی URL سرور وب مشخص شده در برنامه وب سرور) یا به سادگی صفحه موجود را بازخوانی کنید. روی دکمه سبز "Connect" کلیک کنید، دستگاه را در انتخابگر انتخاب کنید و کنسول Dev Tools مورد علاقه خود را با میانبر صفحه کلید Ctrl + Shift + J باز کنید و متوجه شوید که شئ BluetoothDevice ثبت شده است.

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

اگر بلوتوث خاموش باشد و/یا دستگاه بلوتوث PLAYBULB Candle خاموش باشد، ممکن است با خطا مواجه شوید. در این صورت، آن را روشن کرده و دوباره ادامه دهید.

پاداش اجباری

من در مورد شما نمی دانم اما من قبلاً تعداد زیادی function() {} در این کد می بینم. اجازه دهید به جای () => {} جاوا اسکریپت ES2015 توابع پیکان. آنها نجات دهندگان مطلق زندگی هستند: تمام زیبایی های عملکردهای ناشناس، هیچ یک از غم و اندوه الزام آور.

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

بعدی

- باشه... میتونم با این شمع حرف بزنم یا چی؟

- حتما... برو به مرحله بعد

سوالات متداول

5. چیزی بخوانید

پس اکنون که یک BluetoothDevice از وعده navigator.bluetooth.requestDevice بازگشته است، چه می کنید؟ بیایید با فراخوانی 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();
      });
    }
  }

نام دستگاه را بخوانید

در اینجا ما به سرور GATT دستگاه بلوتوث PLAYBULB Candle متصل هستیم. اکنون می‌خواهیم سرویس اولیه گات را دریافت کنیم (که قبلاً با عنوان 0xFF02 تبلیغ می‌شد) و مشخصه نام دستگاه ( 0xFFFF ) را که متعلق به این سرویس است، بخوانیم. با افزودن متد جدید getDeviceName به کلاس PlaybulbCandle و استفاده از device.gatt.getPrimaryService و service.getCharacteristic به راحتی می توان به این امر دست یافت. متد characteristic.readValue در واقع یک DataView برمی گرداند که به سادگی با 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);
      });
    }

بیایید با فراخوانی playbulbCandle.getDeviceName پس از اتصال و نمایش نام دستگاه، این را به app.js اضافه کنیم.

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

در این مرحله، از سایت خود در مرورگر وب خود بازدید کنید (با کلیک بر روی URL سرور وب مشخص شده در برنامه وب سرور) یا به سادگی صفحه موجود را بازخوانی کنید. مطمئن شوید که PLAYBULB Candle روشن است، سپس روی دکمه "اتصال" در صفحه کلیک کنید و نام دستگاه را در زیر انتخابگر رنگ ببینید.

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

سطح باتری را بخوانید

همچنین یک مشخصه استاندارد بلوتوث سطح باتری در دستگاه بلوتوث PLAYBULB Candle موجود است که حاوی سطح باتری دستگاه است. این بدان معناست که می‌توانیم از نام‌های استاندارد مانند battery_service برای UUID سرویس بلوتوث گات و battery_level برای ویژگی UUID GATT بلوتوث استفاده کنیم.

بیایید یک متد getBatteryLevel جدید به کلاس PlaybulbCandle اضافه کنیم و سطح باتری را به درصد بخوانیم.

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

همچنین باید شی جاوا اسکریپت options به‌روزرسانی کنیم تا سرویس باتری به کلید optionalServices اضافه شود، زیرا توسط دستگاه بلوتوث PLAYBULB Candle تبلیغ نمی‌شود، اما دسترسی به آن همچنان اجباری است.

playbulbCandle.js

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

مانند قبل، بیایید با فراخوانی playbulbCandle.getBatteryLevel این را به app.js وصل کنیم که نام دستگاه را داشته باشیم و سطح باتری را نمایش دهیم.

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

در این مرحله، از سایت خود در مرورگر وب خود بازدید کنید (با کلیک بر روی URL سرور وب مشخص شده در برنامه وب سرور) یا به سادگی صفحه موجود را بازخوانی کنید. روی دکمه "اتصال" در صفحه کلیک کنید و نام دستگاه و سطح باتری

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

بعدی

- چگونه می توانم رنگ این لامپ را تغییر دهم؟ برای همین اینجا هستم!

-تو خیلی نزدیکی قول میدم...

سوالات متداول

6. رنگ را تغییر دهید

تغییر رنگ به آسانی نوشتن مجموعه ای خاص از دستورات بر روی یک مشخصه بلوتوث ( 0xFFFC ) در سرویس اولیه گات که به عنوان 0xFF02 تبلیغ می شود، است. برای مثال، تبدیل کردن PLAYBULB Candle به قرمز، نوشتن آرایه ای از اعداد صحیح بدون علامت 8 بیتی برابر با [0x00, 255, 0, 0] که در آن 0x00 اشباع سفید و 255, 0, 0 به ترتیب قرمز هستند. مقادیر سبز و آبی

ما از characteristic.writeValue استفاده می کنیم تا در واقع برخی از داده ها را در مشخصه بلوتوث در متد جدید setColor عمومی کلاس PlaybulbCandle بنویسیم. و همچنین مقادیر واقعی قرمز، سبز و آبی را در صورت تحقق وعده برمی گردانیم تا بتوانیم بعداً از آنها در 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]);
    }

بیایید تابع changeColor را در app.js به روز کنیم تا playbulbCandle.setColor را با علامت زدن دکمه رادیویی "بدون اثر" فراخوانی کنیم. زمانی که کاربر روی بوم انتخابگر رنگ کلیک می‌کند، متغیرهای رنگی r, g, b جهانی از قبل تنظیم شده‌اند.

app.js

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

در این مرحله، از سایت خود در مرورگر وب خود بازدید کنید (با کلیک بر روی URL سرور وب مشخص شده در برنامه وب سرور) یا به سادگی صفحه موجود را بازخوانی کنید. روی دکمه "اتصال" در صفحه کلیک کنید و بر روی انتخابگر رنگ کلیک کنید تا هر چند بار که می خواهید رنگ PLAYBULB Candle خود را تغییر دهید.

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

جلوه های شمع Moar

اگر قبلاً یک شمع روشن کرده اید، می دانید که نور ثابت نیست. خوشبختانه برای ما، مشخصه بلوتوث دیگری ( 0xFFFB ) در سرویس اولیه گات وجود دارد که به عنوان 0xFF02 تبلیغ می‌شود که به کاربر امکان می‌دهد جلوه‌های شمعی را تنظیم کند.

برای مثال می‌توان با نوشتن [0x00, r, g, b, 0x04, 0x00, 0x01, 0x00] به تنظیم یک «افکت شمع» دست یافت. و همچنین می توانید "اثر چشمک زن" را با [0x00, r, g, b, 0x00, 0x00, 0x1F, 0x00] تنظیم کنید.

بیایید متدهای setCandleEffectColor و setFlashingColor را به کلاس 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]);
    }

و اجازه دهید تابع changeColor در app.js به روز کنیم تا playbulbCandle.setCandleEffectColor را زمانی که دکمه رادیویی "Candle Effect" علامت زده می شود و playbulbCandle.setFlashingColor را هنگامی که دکمه رادیویی "Flashing" علامت زده می شود، فراخوانی کنیم. این بار، اگر برای شما مشکلی ندارد، 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;
  }
}

در این مرحله، از سایت خود در مرورگر وب خود بازدید کنید (با کلیک بر روی URL سرور وب مشخص شده در برنامه وب سرور) یا به سادگی صفحه موجود را بازخوانی کنید. روی دکمه "اتصال" در صفحه کلیک کنید و با Candle و Flashing Effects بازی کنید.

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

بعدی

- همین؟ 3 جلوه ضعیف شمع؟ برای همین اینجا هستم؟

- تعداد بیشتری وجود دارد، اما این بار تنها خواهید بود.

7. مایل اضافی را طی کنید

پس ما اینجا هستیم! ممکن است فکر کنید تقریباً به پایان رسیده است، اما برنامه هنوز تمام نشده است. بیایید ببینیم آیا واقعاً متوجه شده‌اید که در طول این کد لبه چه چیزی را کپی پیست کرده‌اید یا خیر. در اینجا کاری است که می‌خواهید به تنهایی انجام دهید تا این برنامه بدرخشد.

افکت های از دست رفته را اضافه کنید

در اینجا داده های مربوط به اثرات از دست رفته است:

  • پالس: [0x00, r, g, b, 0x01, 0x00, 0x09, 0x00] (شاید بخواهید مقادیر r, g, b را در آنجا تنظیم کنید)
  • رنگین کمان: [0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00] (افراد صرعی ممکن است بخواهند از این مورد اجتناب کنند)
  • محو شدن رنگین کمان: [0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x26, 0x00]

این اساساً به معنای افزودن متدهای جدید setPulseColor ، setRainbow و setRainbowFade به کلاس PlaybulbCandle و فراخوانی آنها در changeColor است.

رفع "بدون اثر"

همانطور که ممکن است متوجه شده باشید، گزینه "بدون اثر" هیچ اثری را در حال انجام بازنشانی نمی کند، این جزئی است اما همچنان. بیایید این را درست کنیم. در متد setColor ، ابتدا باید بررسی کنید که آیا یک افکت از طریق متغیر کلاس جدید _isEffectSet در حال انجام است یا خیر و اگر true ، قبل از تنظیم رنگ جدید با این داده ها، افکت را خاموش کنید: [0x00, r, g, b, 0x05, 0x00, 0x01, 0x00] .

نام دستگاه را بنویسید

این یکی آسان است! نوشتن نام دستگاه سفارشی به سادگی نوشتن بر روی مشخصه نام دستگاه بلوتوث قبلی است. من توصیه می کنم از روش encode TextEncoder برای دریافت Uint8Array حاوی نام دستگاه استفاده کنید.

سپس، یک eventListener "ورودی" را به document.querySelector('#deviceName') اضافه می کنم و playbulbCandle.setDeviceName را فراخوانی می کنم تا ساده بماند.

من شخصا اسمم را PLAY💡 CANDLE گذاشتم!

8. همین!

چیزی که یاد گرفتی

  • نحوه تعامل با دستگاه بلوتوث نزدیک در جاوا اسکریپت
  • نحوه استفاده از کلاس های ES2015، توابع پیکان، نقشه و وعده ها

مراحل بعدی