Membuat perangkat IoT yang mendukung web dengan Intel Edison

Kenneth Christiansen
Kenneth Christiansen

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.

Aplikasi klien

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.

{i>Breadboard<i}.

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.

Chrome mengumumkan beacon Web Fisik terdekat.
URL aplikasi web dicantumkan.

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.

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

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

Sketsa