Internet of Things ada di bibir semua orang saat ini, dan itu membuat tinkerer dan {i>programmer<i} seperti saya sangat bersemangat. Tidak ada yang lebih keren daripada mewujudkan penemuan Anda sendiri dan mampu berbicara dengannya.
Namun, perangkat IoT yang menginstal aplikasi yang jarang Anda gunakan dapat mengganggu. Oleh karena itu, kami memanfaatkan teknologi web mendatang seperti Web Fisik dan Bluetooth Web untuk menjadikan perangkat IoT lebih intuitif dan tidak terlalu mengganggu.
Web dan IoT, keduanya cocok
Masih ada banyak rintangan yang harus diatasi sebelum {i>Internet of Things<i} dapat menjadi sukses besar. Salah satu kendalanya adalah perusahaan dan produk yang mengharuskan orang menginstal aplikasi untuk setiap perangkat yang mereka beli, mengacaukan ponsel pengguna dengan banyak aplikasi yang jarang mereka gunakan.
Karena alasan ini, kami sangat antusias dengan project Web Fisik, yang memungkinkan perangkat menyiarkan URL ke situs online dengan cara yang tidak mengganggu. Dalam kombinasi dengan teknologi web yang sedang berkembang seperti Bluetooth Web, USB Web, dan Web NFC, situs dapat terhubung langsung ke perangkat atau setidaknya menjelaskan cara yang tepat untuk melakukannya.
Meskipun dalam artikel ini kami berfokus terutama pada Web Bluetooth, beberapa kasus penggunaan mungkin lebih cocok untuk Web NFC atau Web USB. Misalnya, USB Web lebih diutamakan jika Anda memerlukan koneksi fisik untuk 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 yang responsif seperti aplikasi, dapat berfungsi secara offline, dan dapat ditambahkan ke layar utama perangkat.
Sebagai bukti konsep, saya telah membuat perangkat kecil menggunakan papan kerja kelompok Intel® Edison Arduino. Perangkat berisi sensor suhu (TMP36) serta aktuator (katoda 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 untuk memulai, meskipun Anda juga dapat memprogram dan menguploadnya 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 Web Fisik, yang memungkinkan Chrome melihat URL yang disiarkan oleh perangkat di sekitarnya. Ada beberapa persyaratan yang harus diperhatikan developer, seperti perlunya situs harus 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. Anda hanya perlu 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'});
}
}
Itu sangat mudah. Anda melihat pada gambar di bawah ini bahwa Chrome menemukan perangkat dengan baik.
Berkomunikasi dengan sensor/aktuator
Kami menggunakan Johnny-Five* untuk berbicara dengan penyempurnaan papan kami. Johnny-Five memiliki abstraksi yang bagus untuk berbicara dengan sensor TMP36.
Di bawah ini, Anda dapat menemukan kode sederhana untuk mendapatkan notifikasi tentang perubahan suhu serta menyetel 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 selanjutnya tentang interaksi dengan Bluetooth.
Seperti yang mungkin Anda lihat saat membuat instance objek Termometer, saya
berbicara dengan TMP36 melalui port A0
analog. Kaki tegangan pada katoda LED warna
terhubung ke pin digital 3, 5, dan 6, yang kebetulan
adalah pin pulse-width modulation (PWM) pada papan
terobosan Arduino Edison.
Berbicara dengan Bluetooth
Berbicara dengan Bluetooth menjadi lebih mudah dibandingkan dengan noble
.
Pada contoh berikut, kita membuat dua karakteristik Bluetooth Hemat Energi: satu untuk LED dan satu untuk sensor suhu. Yang pertama memungkinkan kita membaca warna LED saat ini dan menetapkan warna baru. Yang terakhir memungkinkan kita untuk 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 membaca, menulis, memberi tahu, atau kombinasinya.
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 "bacaan" berfungsi.
TemperatureCharacteristic.prototype.onReadRequest = function(offset, callback) {
var data = new Buffer(8);
data.writeDoubleLE(this._lastValue, 0);
callback(this.RESULT_SUCCESS, data);
};
Untuk "pemberitahuan", kita perlu menambahkan metode untuk menangani langganan dan pembatalan langganan. Pada dasarnya, kita cukup menyimpan callback. Jika kita memiliki alasan suhu baru yang ingin dikirim, kita kemudian 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 sedikit berfluktuasi, kita perlu memuluskan nilai yang diperoleh dari sensor TMP36. Saya memilih untuk mengambil rata-rata 100 sampel dan hanya mengirim pembaruan saat suhu berubah minimal 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. Warna LED lebih sederhana. Objek serta metode "baca" ditampilkan di bawah ini. Karakteristik dikonfigurasi untuk memungkinkan operasi "baca" dan "tulis" serta memiliki UUID yang berbeda dari 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 digunakan untuk menyimpan objek LED
Johnny-Five. Saya juga menyetel warna LED ke nilai
defaultnya (putih, alias #ffffff
).
board.on("ready", function() {
...
colorCharacteristic._led = led;
led.color(colorCharacteristic._value);
led.intensity(30);
...
}
Metode "tulis" menerima string (sama seperti "baca" 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 oleh 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 bersamanya. Untungnya melakukan hal itu cukup sederhana:
var bleno = require('eddystone-beacon/node_modules/bleno');
var util = require('util');
Sekarang yang kita butuhkan hanyalah memberitahukan 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 terlalu banyak defails terkait cara kerja bagian non-bluetooth dari aplikasi klien, kita dapat mendemonstrasikan 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 sederhana dari kode koneksi saya. Jika Anda tidak mengetahui cara kerja promise, lihat referensi ini sebelum membaca lebih lanjut.
Menghubungkan ke perangkat Bluetooth memerlukan rantai promise.
Pertama, kita memfilter perangkat (UUID: FC00
, nama: Edison
). Tindakan ini
akan menampilkan dialog untuk memungkinkan pengguna memilih perangkat dengan
filter. Kemudian, kita terhubung ke layanan GATT dan mendapatkan layanan
utama serta karakteristik terkait, lalu membaca
nilainya dan menyiapkan callback notifikasi.
Versi yang disederhanakan dari kode kami di bawah ini 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 oleh WebBluetooth API) semudah menggunakan Buffer
di sisi Node.js. Yang perlu kita gunakan hanyalah 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 Web Fisik dan Bluetooth Web, Chrome menemukan perangkat dan memungkinkan pengguna terhubung dengan mudah tanpa perlu 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 Anda sendiri agar 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 bertualang dan ingin mereproduksi apa yang telah saya lakukan, lihat sketsa Edison dan papan tempat roti di bawah ini: