Membuat perangkat IoT yang mendukung web dengan Intel Edison

Kenneth Christiansen
Kenneth Christiansen

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.

Aplikasi klien

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.

Breadboard.

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.

Chrome mengumumkan beacon Physical Web di sekitar.
URL aplikasi web tercantum.

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.

Papan 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:

Aplikasi klien di ponsel.
Pesan error.

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:

Sketsa