Internet of Things menjadi topik yang banyak dibicarakan akhir-akhir ini, dan hal ini membuat para tinkerer dan programmer seperti saya sangat antusias. Tidak ada yang lebih keren daripada mewujudkan penemuan Anda sendiri dan dapat berbicara dengannya.
Namun, perangkat IoT yang menginstal aplikasi yang jarang Anda gunakan dapat mengganggu, jadi kami memanfaatkan teknologi web mendatang seperti Web Fisik dan Web Bluetooth untuk membuat perangkat IoT lebih intuitif dan tidak mengganggu.
Web dan IoT, kecocokan untuk
Masih ada banyak rintangan yang harus diatasi sebelum Internet of Things dapat meraih kesuksesan besar. Salah satu kendalanya adalah perusahaan dan produk yang mengharuskan orang menginstal aplikasi untuk setiap perangkat yang mereka beli, sehingga memenuhi ponsel pengguna dengan banyak aplikasi yang jarang mereka gunakan.
Oleh karena itu, kami sangat antusias dengan project Physical Web, yang memungkinkan perangkat menyiarkan URL ke situs online, dengan cara yang tidak mengganggu. Dalam kombinasi dengan teknologi web yang baru muncul seperti Web Bluetooth, Web USB, dan Web NFC, situs dapat terhubung langsung ke perangkat atau setidaknya menjelaskan cara yang tepat untuk melakukannya.
Meskipun kita terutama berfokus pada Web Bluetooth dalam artikel ini, beberapa kasus penggunaan mungkin lebih cocok untuk Web NFC atau Web USB. Misalnya, USB Web lebih disukai jika Anda memerlukan koneksi fisik karena alasan keamanan.
Situs juga dapat berfungsi sebagai Progressive Web App (PWA). Sebaiknya pembaca membaca penjelasan Google tentang PWA. PWA adalah situs yang memiliki pengalaman pengguna seperti aplikasi yang responsif, dapat berfungsi secara offline, dan dapat ditambahkan ke layar utama perangkat.
Sebagai bukti konsep, saya telah membuat perangkat kecil menggunakan papan grup Intel® Edison Arduino. Perangkat ini berisi sensor suhu (TMP36) serta aktuator (katode LED berwarna). Skema untuk perangkat ini dapat ditemukan di akhir artikel ini.
Intel Edison adalah produk yang menarik karena dapat menjalankan distribusi Linux* lengkap. Oleh karena itu, saya dapat memprogramnya dengan mudah menggunakan Node.js. Penginstal memungkinkan Anda menginstal Intel* XDK yang memudahkan Anda memulai, meskipun Anda juga dapat memprogram dan mengupload ke perangkat secara manual.
Untuk aplikasi Node.js, saya memerlukan tiga modul node, serta dependensinya:
eddystone-beacon
parse-color
johnny-five
Yang pertama otomatis menginstal noble
, yang merupakan modul node
yang saya gunakan untuk berkomunikasi melalui Bluetooth Hemat Energi.
File package.json
untuk project akan terlihat seperti ini:
{
"name": "edison-webbluetooth-demo-server",
"version": "1.0.0",
"main": "main.js",
"engines": {
"node": ">=0.10.0"
},
"dependencies": {
"eddystone-beacon": "^1.0.5",
"johnny-five": "^0.9.30",
"parse-color": "^1.0.0"
}
}
Mengumumkan situs
Mulai versi 49, Chrome di Android mendukung Physical Web, yang memungkinkan Chrome melihat URL yang disiarkan oleh perangkat di sekitarnya. Ada beberapa persyaratan yang harus diketahui developer, seperti kebutuhan agar situs dapat diakses secara publik dan menggunakan HTTPS.
Protokol Eddystone memiliki batas ukuran 18 byte pada URL. Jadi, agar URL untuk aplikasi demo saya berfungsi (https://webbt-sensor-hub.appspot.com/), saya perlu menggunakan penyingkat URL.
Menyiarkan URL cukup mudah. Yang perlu Anda lakukan adalah mengimpor
library yang diperlukan dan
memanggil beberapa fungsi. Salah satu cara untuk melakukannya adalah dengan memanggil advertiseUrl
saat chip BLE diaktifkan:
var beacon = require("eddystone-beacon");
var bleno = require('eddystone-beacon/node_modules/bleno');
bleno.on('stateChange', function(state) {
if (state === 'poweredOn') {
beacon.advertiseUrl("https://goo.gl/9FomQC", {name: 'Edison'});
}
}
Caranya sangat mudah. Anda melihat pada gambar di bawah bahwa Chrome menemukan perangkat dengan baik.
Berkomunikasi dengan sensor/aktuator
Kita menggunakan Johnny-Five* untuk berbicara dengan peningkatan board kami. Johnny-Five memiliki abstraksi yang bagus untuk berkomunikasi dengan sensor TMP36.
Di bawah ini, Anda dapat menemukan kode sederhana untuk mendapatkan notifikasi tentang perubahan suhu serta menetapkan warna LED awal.
var five = require("johnny-five");
var Edison = require("edison-io");
var board = new five.Board({
io: new Edison()
});
board.on("ready", function() {
// Johnny-Five's Led.RGB class can be initialized with
// an array of pin numbers in R, G, B order.
// Reference: http://johnny-five.io/api/led.rgb/#parameters
var led = new five.Led.RGB([ 3, 5, 6 ]);
// Johnny-Five's Thermometer class provides a built-in
// controller definition for the TMP36 sensor. The controller
// handles computing a Celsius (also Fahrenheit & Kelvin) from
// a raw analog input value.
// Reference: http://johnny-five.io/api/thermometer/
var temp = new five.Thermometer({
controller: "TMP36",
pin: "A0",
});
temp.on("change", function() {
temperatureCharacteristic.valueChange(this.celsius);
});
colorCharacteristic._led = led;
led.color(colorCharacteristic._value);
led.intensity(30);
});
Untuk saat ini, Anda dapat mengabaikan variabel *Characteristic
di atas; variabel ini
akan ditentukan di bagian berikutnya tentang antarmuka dengan Bluetooth.
Seperti yang mungkin Anda lihat dalam pembuatan instance objek Termometer, saya berbicara dengan
TMP36 melalui port A0
analog. Kaki voltase pada katode LED
warna terhubung ke pin digital 3, 5, dan 6, yang kebetulan
adalah pin modulasi lebar pulsa (PWM) pada papan breakout
Arduino Edison.
Berbicara dengan Bluetooth
Berbicara dengan Bluetooth tidak bisa lebih mudah daripada dengan noble
.
Pada contoh berikut, kita membuat dua karakteristik Bluetooth Low Energy: satu untuk LED dan satu untuk sensor suhu. Yang pertama memungkinkan kita membaca warna LED saat ini dan menetapkan warna baru. Peristiwa ini memungkinkan kita berlangganan peristiwa perubahan suhu.
Dengan noble
, membuat karakteristik cukup mudah. Yang perlu Anda lakukan
adalah menentukan cara karakteristik berkomunikasi dan menentukan UUID. Opsi
komunikasi adalah baca, tulis, beri tahu, atau kombinasi dari opsi tersebut.
Cara termudah untuk melakukannya adalah dengan membuat objek baru dan mewarisi dari
bleno.Characteristic
.
Objek karakteristik yang dihasilkan akan terlihat seperti berikut:
var TemperatureCharacteristic = function() {
bleno.Characteristic.call(this, {
uuid: 'fc0a',
properties: ['read', 'notify'],
value: null
});
this._lastValue = 0;
this._total = 0;
this._samples = 0;
this._onChange = null;
};
util.inherits(TemperatureCharacteristic, bleno.Characteristic);
Kita menyimpan nilai suhu saat ini dalam variabel
this._lastValue
. Kita perlu menambahkan metode onReadRequest
dan mengenkode nilai
agar "baca" berfungsi.
TemperatureCharacteristic.prototype.onReadRequest = function(offset, callback) {
var data = new Buffer(8);
data.writeDoubleLE(this._lastValue, 0);
callback(this.RESULT_SUCCESS, data);
};
Untuk "notifikasi", kita perlu menambahkan metode untuk menangani langganan dan pembatalan langganan. Pada dasarnya, kita hanya menyimpan callback. Jika kita memiliki alasan suhu baru yang ingin dikirim, kita akan memanggil callback tersebut dengan nilai baru (dienkode seperti di atas).
TemperatureCharacteristic.prototype.onSubscribe = function(maxValueSize, updateValueCallback) {
console.log("Subscribed to temperature change.");
this._onChange = updateValueCallback;
this._lastValue = undefined;
};
TemperatureCharacteristic.prototype.onUnsubscribe = function() {
console.log("Unsubscribed to temperature change.");
this._onChange = null;
};
Karena nilai dapat berfluktuasi sedikit, kita perlu meratakan nilai yang kita dapatkan dari sensor TMP36. Saya memilih untuk mengambil rata-rata 100 sampel dan hanya mengirim pembaruan saat suhu berubah setidaknya 1 derajat.
TemperatureCharacteristic.prototype.valueChange = function(value) {
this._total += value;
this._samples++;
if (this._samples < NO_SAMPLES) {
return;
}
var newValue = Math.round(this._total / NO_SAMPLES);
this._total = 0;
this._samples = 0;
if (this._lastValue && Math.abs(this._lastValue - newValue) < 1) {
return;
}
this._lastValue = newValue;
console.log(newValue);
var data = new Buffer(8);
data.writeDoubleLE(newValue, 0);
if (this._onChange) {
this._onChange(data);
}
};
Itu adalah sensor suhu. LED warna lebih sederhana. Objek serta metode "read" ditampilkan di bawah ini. Karakteristik dikonfigurasi untuk memungkinkan operasi "baca" dan "tulis" dan memiliki UUID yang berbeda dengan karakteristik suhu.
var ColorCharacteristic = function() {
bleno.Characteristic.call(this, {
uuid: 'fc0b',
properties: ['read', 'write'],
value: null
});
this._value = 'ffffff';
this._led = null;
};
util.inherits(ColorCharacteristic, bleno.Characteristic);
ColorCharacteristic.prototype.onReadRequest = function(offset, callback) {
var data = new Buffer(this._value);
callback(this.RESULT_SUCCESS, data);
};
Untuk mengontrol LED dari objek, saya menambahkan
anggota this._led
yang saya gunakan untuk menyimpan objek LED
Johnny-Five. Saya juga menetapkan warna LED ke nilai defaultnya (putih, alias #ffffff
).
board.on("ready", function() {
...
colorCharacteristic._led = led;
led.color(colorCharacteristic._value);
led.intensity(30);
...
}
Metode "write" menerima string (sama seperti "read" yang mengirim
string), yang dapat terdiri dari kode warna CSS (Misalnya: nama CSS
seperti rebeccapurple
atau kode hex seperti #ff00bb
). Saya menggunakan modul node
yang disebut parse-color
untuk selalu mendapatkan nilai hex yang diharapkan Johnny-Five.
ColorCharacteristic.prototype.onWriteRequest = function(data, offset, withoutResponse, callback) {
var value = parse(data.toString('utf8')).hex;
if (!value) {
callback(this.RESULT_SUCCESS);
return;
}
this._value = value;
console.log(value);
if (this._led) {
this._led.color(this._value);
}
callback(this.RESULT_SUCCESS);
};
Semua hal di atas tidak akan berfungsi jika kita tidak menyertakan modul bleno.
eddystone-beacon
tidak akan berfungsi dengan bleno kecuali jika Anda menggunakan versi noble
yang didistribusikan dengannya. Untungnya, kita bisa melakukannya dengan mudah:
var bleno = require('eddystone-beacon/node_modules/bleno');
var util = require('util');
Sekarang, yang kita perlukan hanyalah untuk mengiklankan perangkat kita (UUID) dan karakteristiknya (UUID lainnya)
bleno.on('advertisingStart', function(error) {
...
bleno.setServices([
new bleno.PrimaryService({
uuid: 'fc00',
characteristics: [
temperatureCharacteristic, colorCharacteristic
]
})
]);
});
Membuat aplikasi web klien
Tanpa membahas terlalu banyak defail tentang cara kerja bagian non-bluetooth dari aplikasi klien, kita dapat menunjukkan antarmuka pengguna responsif yang dibuat di Polymer* sebagai contoh. Aplikasi yang dihasilkan ditampilkan di bawah ini:
Sisi kanan menunjukkan versi sebelumnya, yang menampilkan log error sederhana yang saya tambahkan untuk memudahkan pengembangan.
Bluetooth Web memudahkan komunikasi dengan perangkat Bluetooth Hemat Energi, jadi mari kita lihat versi kode koneksi saya yang disederhanakan. Jika Anda tidak tahu cara kerja promise, lihat referensi ini sebelum membaca lebih lanjut.
Menghubungkan ke perangkat Bluetooth melibatkan rantai promise.
Pertama, kita memfilter perangkat (UUID: FC00
, nama: Edison
). Tindakan ini
akan menampilkan dialog untuk memungkinkan pengguna memilih perangkat berdasarkan
filter. Kemudian, kita terhubung ke layanan GATT dan mendapatkan layanan
utama serta karakteristik terkait, lalu kita membaca
nilai dan menyiapkan callback notifikasi.
Versi sederhana kode kami di bawah hanya berfungsi dengan Web Bluetooth API terbaru, sehingga memerlukan Chrome Dev (M49) di Android.
navigator.bluetooth.requestDevice({
filters: [{ name: 'Edison' }],
optionalServices: [0xFC00]
})
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService(0xFC00))
.then(service => {
let p1 = () => service.getCharacteristic(0xFC0B)
.then(characteristic => {
this.colorLedCharacteristic = characteristic;
return this.readLedColor();
});
let p2 = () => service.getCharacteristic(0xFC0A)
.then(characteristic => {
characteristic.addEventListener(
'characteristicvaluechanged', this.onTemperatureChange);
return characteristic.startNotifications();
});
return p1().then(p2);
})
.catch(err => {
// Catch any error.
})
.then(() => {
// Connection fully established, unless there was an error above.
});
Membaca dan menulis string dari DataView
/ ArrayBuffer
(yang
digunakan WebBluetooth API) sama mudahnya seperti menggunakan Buffer
di
sisi Node.js. Yang perlu kita gunakan adalah TextEncoder
dan TextDecoder
:
readLedColor: function() {
return this.colorLedCharacteristic.readValue()
.then(data => {
// In Chrome 50+, a DataView is returned instead of an ArrayBuffer.
data = data.buffer ? data : new DataView(data);
let decoder = new TextDecoder("utf-8");
let decodedString = decoder.decode(data);
document.querySelector('#color').value = decodedString;
});
},
writeLedColor: function() {
let encoder = new TextEncoder("utf-8");
let value = document.querySelector('#color').value;
let encodedString = encoder.encode(value.toLowerCase());
return this.colorLedCharacteristic.writeValue(encodedString);
},
Menangani peristiwa characteristicvaluechanged
untuk sensor
suhu juga cukup mudah:
onTemperatureChange: function(event) {
let data = event.target.value;
// In Chrome 50+, a DataView is returned instead of an ArrayBuffer.
data = data.buffer ? data : new DataView(data);
let temperature = data.getFloat64(0, /*littleEndian=*/ true);
document.querySelector('#temp').innerHTML = temperature.toFixed(0);
},
Ringkasan
Itu saja, teman-teman. Seperti yang dapat Anda lihat, berkomunikasi dengan Bluetooth Hemat Energi menggunakan Web Bluetooth di sisi klien dan Node.js di Edison cukup mudah dan sangat canggih.
Dengan menggunakan Physical Web dan Web Bluetooth, Chrome menemukan perangkat dan memungkinkan pengguna terhubung dengan mudah tanpa menginstal aplikasi yang jarang digunakan yang mungkin tidak diinginkan pengguna, dan yang dapat diupdate dari waktu ke waktu.
Demo
Anda dapat mencoba klien untuk mendapatkan inspirasi tentang cara membuat aplikasi web sendiri untuk terhubung ke perangkat Internet of Things kustom.
Kode sumber
Kode sumber tersedia di sini. Jangan ragu untuk melaporkan masalah atau mengirim patch.
Sketsa
Jika Anda benar-benar ingin bereksperimen dan ingin mereproduksi apa yang telah saya lakukan, lihat sketsa Edison dan breadboard di bawah: