Intel Edison के साथ वेब-सुविधा वाला IoT डिवाइस बनाना

Kenneth Christiansen
Kenneth Christiansen

इन दिनों इंटरनेट ऑफ़ थिंग्स की चर्चा हर जगह हो रही है. इससे, मेरे जैसे प्रोग्रामर और टेंकर बहुत उत्साहित होते हैं. अपने आविष्कारों को हक़ीक़त में बदलना और उनसे बात करना, इससे बढ़िया और क्या हो सकता है!

हालांकि, ऐसे IoT डिवाइसों से परेशानी हो सकती है जो ऐसे ऐप्लिकेशन इंस्टॉल करते हैं जिनका इस्तेमाल कभी-कभार ही किया जाता है. इसलिए, हम फ़िज़िकल वेब और वेब ब्लूटूथ जैसी नई वेब टेक्नोलॉजी का फ़ायदा लेते हैं, ताकि IoT डिवाइसों को ज़्यादा आसान और कम परेशानी वाले बनाए जा सकें.

क्लाइंट ऐप्लिकेशन

वेब और IoT, एक बेहतरीन जोड़ी

इंटरनेट ऑफ़ थिंग्स को एक बड़ी सफलता बनाने के लिए, अब भी कई समस्याओं को हल करना बाकी है. एक समस्या यह है कि कुछ कंपनियां और प्रॉडक्ट के लिए, लोगों को खरीदे गए हर डिवाइस पर ऐप्लिकेशन इंस्टॉल करने पड़ते हैं. इससे लोगों के फ़ोन में कई ऐसे ऐप्लिकेशन हो जाते हैं जिनका इस्तेमाल वे कभी-कभार ही करते हैं.

इसलिए, हम फ़िज़िकल वेब प्रोजेक्ट को लेकर काफ़ी उत्साहित हैं. इसकी मदद से, डिवाइस किसी ऑनलाइन वेबसाइट के यूआरएल को बिना किसी रुकावट के ब्रॉडकास्ट कर सकते हैं. वेब ब्लूटूथ, वेब यूएसबी, और वेब एनएफ़सी जैसी नई वेब टेक्नोलॉजी के साथ मिलकर, साइटें सीधे डिवाइस से कनेक्ट हो सकती हैं या कम से कम ऐसा करने का सही तरीका बता सकती हैं.

इस लेख में, हम मुख्य रूप से वेब ब्लूटूथ पर फ़ोकस करते हैं. हालांकि, कुछ इस्तेमाल के उदाहरण वेब एनएफ़सी या वेब यूएसबी के लिए बेहतर हो सकते हैं. उदाहरण के लिए, अगर आपको सुरक्षा से जुड़ी वजहों से फ़िज़िकल कनेक्शन की ज़रूरत है, तो वेब यूएसबी का इस्तेमाल करना बेहतर होता है.

वेबसाइट, प्रोग्रेसिव वेब ऐप्लिकेशन (पीडब्ल्यूए) के तौर पर भी काम कर सकती है. हमारा सुझाव है कि पाठक, पीएडब्ल्यू के बारे में Google की दी गई जानकारी पढ़ें. PWA ऐसी साइटें होती हैं जिन पर ऐप्लिकेशन की तरह रिस्पॉन्सिव यूज़र अनुभव मिलता है. ये साइटें ऑफ़लाइन काम करती हैं और इन्हें डिवाइस की होम स्क्रीन पर जोड़ा जा सकता है.

कॉन्सेप्ट की पुष्टि करने के लिए, मैंने Intel® Edison Arduino ब्रेकआउट बोर्ड का इस्तेमाल करके एक छोटा डिवाइस बनाया है. इस डिवाइस में, तापमान मापने वाला सेंसर (TMP36) और ऐक्चुएटर (रंगीन एलईडी कैथोड) शामिल है. इस डिवाइस के स्कीमैटिक्स, इस लेख के आखिर में देखे जा सकते हैं.

ब्रेडबोर्ड.

Intel Edison एक दिलचस्प प्रॉडक्ट है, क्योंकि यह पूरा Linux* डिस्ट्रिब्यूशन चला सकता है. इसलिए, मैं Node.js का इस्तेमाल करके, इसे आसानी से प्रोग्राम कर सकता/सकती हूं. इंस्टॉलर की मदद से, Intel* XDK इंस्टॉल किया जा सकता है. इससे, प्रोग्रामिंग शुरू करना आसान हो जाता है. हालांकि, अपने डिवाइस पर मैन्युअल तरीके से भी प्रोग्रामिंग की जा सकती है और उसे अपलोड किया जा सकता है.

मेरे Node.js ऐप्लिकेशन के लिए, मुझे तीन नोड मॉड्यूल के साथ-साथ उनकी डिपेंडेंसी की ज़रूरत थी:

  • eddystone-beacon
  • parse-color
  • johnny-five

पहला, noble को अपने-आप इंस्टॉल करता है. यह एक नोड मॉड्यूल है, जिसका इस्तेमाल ब्लूटूथ कम ऊर्जा टेक्नोलॉजी के ज़रिए बातचीत करने के लिए किया जाता है.

जाएं

प्रोजेक्ट के लिए package.json फ़ाइल कुछ ऐसी दिखती है:

{
    "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"
    }
}

वेबसाइट का एलान

Android पर Chrome के 49 वर्शन से, फ़िज़िकल वेब की सुविधा काम करती है. इसकी मदद से, Chrome आस-पास मौजूद डिवाइसों से ब्रॉडकास्ट किए जा रहे यूआरएल देख सकता है. डेवलपर को कुछ ज़रूरी शर्तों के बारे में पता होना चाहिए. जैसे, साइटों को सार्वजनिक तौर पर ऐक्सेस किया जा सकता हो और वे एचटीटीपीएस का इस्तेमाल करती हों.

Eddystone प्रोटोकॉल के यूआरएल का साइज़, 18 बाइट से ज़्यादा नहीं होना चाहिए. इसलिए, अपने डेमो ऐप्लिकेशन (https://webbt-sensor-hub.appspot.com/) के यूआरएल को काम करने के लिए, मुझे यूआरएल छोटा करने वाले टूल का इस्तेमाल करना होगा.

यूआरएल को ब्रॉडकास्ट करना बहुत आसान है. इसके लिए, आपको ज़रूरी लाइब्रेरी इंपोर्ट करनी होंगी और कुछ फ़ंक्शन को कॉल करना होगा. ऐसा करने का एक तरीका यह है कि BLE चिप चालू होने पर, advertiseUrl को कॉल करें:

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

यह वाकई बहुत आसान है. यहां दी गई इमेज में, आपको दिख रहा है कि Chrome डिवाइस को आसानी से ढूंढता है.

Chrome, आस-पास मौजूद फ़िज़िकल वेब बीकन के बारे में सूचना देता है.
वेब ऐप्लिकेशन का यूआरएल सूची में शामिल है.

सेंसर/ऐक्ट्यूएटर से बातचीत करना

हम बोर्ड के बेहतर वर्शन से बातचीत करने के लिए, Johnny-Five* का इस्तेमाल करते हैं. TMP36 सेंसर से बात करने के लिए, Johnny-Five में एक अच्छा एब्स्ट्रैक्शन है.

यहां आपको तापमान में होने वाले बदलावों की सूचना पाने के लिए, आसान कोड मिल सकता है. साथ ही, शुरुआती एलईडी रंग को सेट करने का तरीका भी मिल सकता है.

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

फ़िलहाल, ऊपर दिए गए *Characteristic वैरिएबल को अनदेखा किया जा सकता है. इनके बारे में, ब्लूटूथ के साथ इंटरफ़ेस करने के बारे में अगले सेक्शन में बताया जाएगा.

जैसा कि आपको Thermometer ऑब्जेक्ट के इंस्टैंशिएशन में दिख सकता है, मैं एनालॉग A0 पोर्ट के ज़रिए TMP36 से बात करता/करती हूं. कलर एलईडी कैथोड पर मौजूद वोल्टेज लेग, डिजिटल पिन 3, 5, और 6 से कनेक्ट होते हैं. ये पिन, Edison Arduino ब्रेकआउट बोर्ड पर मौजूद, पल्स-विड्थ मॉड्यूलेशन (पीडब्ल्यूएम) पिन होते हैं.

एडिसन बोर्ड

ब्लूटूथ से बात करना

noble की मदद से, ब्लूटूथ से बात करना बहुत आसान है.

यहां दिए गए उदाहरण में, हमने दो ब्लूटूथ स्मार्टवॉच की सुविधाएं बनाई हैं: एक एलईडी के लिए और एक तापमान सेंसर के लिए. पहले सेट की गई वैल्यू की मदद से, एलईडी का मौजूदा रंग पढ़ा जा सकता है और नया रंग सेट किया जा सकता है. तापमान में बदलाव होने के इवेंट की सदस्यता लेने के लिए, हमें बाद वाले का इस्तेमाल करना होगा.

noble की मदद से, कोई विशेषता बनाना काफ़ी आसान है. आपको सिर्फ़ यह तय करना होगा कि विशेषता कैसे कम्यूनिकेट करती है और यूयूआईडी तय करना होगा. कम्यूनिकेशन के विकल्पों में, पढ़ना, लिखना, सूचना देना या इनमें से कोई भी कॉम्बिनेशन शामिल है. ऐसा करने का सबसे आसान तरीका है कि नया ऑब्जेक्ट बनाएं और bleno.Characteristic से इनहेरिट करें.

इससे मिलने वाला चैरेक्टरिस्टिक ऑब्जेक्ट कुछ ऐसा दिखता है:

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

हम this._lastValue वैरिएबल में मौजूदा तापमान की वैल्यू सेव कर रहे हैं. "रीड" के काम करने के लिए, हमें onReadRequest तरीका जोड़ना होगा और वैल्यू को कोड में बदलना होगा.

TemperatureCharacteristic.prototype.onReadRequest = function(offset, callback) {
    var data = new Buffer(8);
    data.writeDoubleLE(this._lastValue, 0);
    callback(this.RESULT_SUCCESS, data);
};

"सूचना" के लिए, हमें सदस्यताओं और सदस्यता छोड़ने की प्रोसेस को मैनेज करने का तरीका जोड़ना होगा. हम सिर्फ़ कॉलबैक स्टोर करते हैं. जब हमें तापमान में बदलाव की कोई नई वजह भेजनी होती है, तो हम उस कॉलबैक को नई वैल्यू के साथ कॉल करते हैं. यह वैल्यू, ऊपर बताए गए तरीके से कोड में बदली जाती है.

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

वैल्यू में थोड़ा उतार-चढ़ाव हो सकता है. इसलिए, हमें TMP36 सेंसर से मिली वैल्यू को ठीक करना होगा. मैंने 100 सैंपल का औसत निकालने का विकल्प चुना है. साथ ही, तापमान में कम से कम एक डिग्री का बदलाव होने पर ही अपडेट भेजने का विकल्प चुना है.

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

यह तापमान मापने वाला सेंसर था. कलर एलईडी का इस्तेमाल करना आसान है. ऑब्जेक्ट के साथ-साथ "read" तरीका भी यहां दिखाया गया है. इस विशेषता को "रीड" और "लिखें" ऑपरेशन की अनुमति देने के लिए कॉन्फ़िगर किया गया है. साथ ही, इसका यूयूआईडी, तापमान की विशेषता से अलग है.

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

ऑब्जेक्ट से एलईडी को कंट्रोल करने के लिए, मैंने एक this._led सदस्य जोड़ा है. इसका इस्तेमाल, Johnny-Five एलईडी ऑब्जेक्ट को स्टोर करने के लिए किया जाता है. मैंने एलईडी का रंग भी डिफ़ॉल्ट वैल्यू (सफ़ेद यानी #ffffff) पर सेट किया है.

board.on("ready", function() {
    ...
    colorCharacteristic._led = led;
    led.color(colorCharacteristic._value);
    led.intensity(30);
    ...
}

"write" तरीके को एक स्ट्रिंग मिलती है (जैसे कि "read" एक स्ट्रिंग भेजता है), जिसमें सीएसएस कलर कोड हो सकता है. उदाहरण के लिए: rebeccapurple जैसे सीएसएस नाम या #ff00bb जैसे हेक्स कोड. मैं हमेशा हेक्स वैल्यू पाने के लिए, parse-color नाम के नोड मॉड्यूल का इस्तेमाल करता हूं, जो 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);
};

अगर bleno मॉड्यूल शामिल नहीं किया जाता है, तो ऊपर बताई गई कोई भी सुविधा काम नहीं करेगी. eddystone-beacon, bleno के साथ तब तक काम नहीं करेगा, जब तक इसके साथ डिस्ट्रिब्यूट किए गए noble वर्शन का इस्तेमाल नहीं किया जाता. ऐसा करना काफ़ी आसान है:

var bleno = require('eddystone-beacon/node_modules/bleno');
var util = require('util');

अब हमें बस यह देखना है कि यह हमारे डिवाइस (यूयूआईडी) और उसकी विशेषताओं (अन्य यूयूआईडी) का विज्ञापन दिखाता है या नहीं

bleno.on('advertisingStart', function(error) {
    ...
    bleno.setServices([
        new bleno.PrimaryService({
        uuid: 'fc00',
        characteristics: [
            temperatureCharacteristic, colorCharacteristic
        ]
        })
    ]);
});

क्लाइंट वेब ऐप्लिकेशन बनाना

क्लाइंट ऐप्लिकेशन के ऐसे हिस्सों के काम करने के तरीके के बारे में ज़्यादा जानकारी दिए बिना जो ब्लूटूथ के साथ काम नहीं करते, हम उदाहरण के तौर पर Polymer* में बनाए गए रिस्पॉन्सिव यूज़र इंटरफ़ेस को दिखा सकते हैं. इससे मिलने वाला ऐप्लिकेशन यहां दिखाया गया है:

फ़ोन पर क्लाइंट ऐप्लिकेशन.
गड़बड़ी का मैसेज.

दाईं ओर, एक पुराना वर्शन दिख रहा है. इसमें एक आसान गड़बड़ी का लॉग दिख रहा है, जिसे मैंने डेवलपमेंट को आसान बनाने के लिए जोड़ा था.

वेब ब्लूटूथ की मदद से, ब्लूटूथ स्मार्ट डिवाइसों से आसानी से संपर्क किया जा सकता है. इसलिए, आइए मेरे कनेक्शन कोड के आसान वर्शन पर नज़र डालें. अगर आपको नहीं पता कि वादे कैसे काम करते हैं, तो आगे पढ़ने से पहले यह संसाधन देखें.

किसी ब्लूटूथ डिवाइस से कनेक्ट करने के लिए, एक सिलसिलेवार तरीके से काम किया जाता है. सबसे पहले, हम डिवाइस (यूयूआईडी: FC00, नाम: Edison) के लिए फ़िल्टर करते हैं. इससे एक डायलॉग बॉक्स दिखता है, ताकि उपयोगकर्ता फ़िल्टर किए गए डिवाइस को चुन सके. इसके बाद, हम GATT सेवा से कनेक्ट करते हैं और मुख्य सेवा और उससे जुड़ी विशेषताओं को पाते हैं. इसके बाद, हम वैल्यू पढ़ते हैं और सूचना कॉलबैक सेट अप करते हैं.

यहां दिया गया कोड, सिर्फ़ वेब ब्लूटूथ एपीआई के सबसे नए वर्शन के साथ काम करता है. इसलिए, Android पर Chrome Dev (M49) की ज़रूरत होती है.

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

DataView / ArrayBuffer (WebBluetooth API का इस्तेमाल करता है) से स्ट्रिंग को पढ़ना और लिखना उतना ही आसान है जितना कि Node.js साइड पर Buffer का इस्तेमाल करना. इसके लिए, हमें सिर्फ़ TextEncoder और 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);
},

तापमान सेंसर के लिए characteristicvaluechanged इवेंट को मैनेज करना भी काफ़ी आसान है:

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

खास जानकारी

बस इतना ही, दोस्तों! जैसा कि आप देख सकते हैं, क्लाइंट साइड पर वेब ब्लूटूथ और Edison पर Node.js का इस्तेमाल करके, ब्लूटूथ स्मार्टवॉच के साथ कम ऊर्जा खर्च करने वाले ब्लूटूथ का इस्तेमाल करना काफ़ी आसान और असरदार है.

फ़िज़िकल वेब और वेब ब्लूटूथ का इस्तेमाल करके, Chrome डिवाइस को ढूंढता है और उपयोगकर्ता को उससे आसानी से कनेक्ट करने की अनुमति देता है. इसके लिए, उपयोगकर्ता को कभी-कभी इस्तेमाल होने वाले ऐसे ऐप्लिकेशन इंस्टॉल करने की ज़रूरत नहीं होती जिन्हें शायद वह न चाहे और जो समय-समय पर अपडेट हो सकते हैं.

डेमो

क्लाइंट को आज़माकर, यह जानें कि अपने कस्टम इंटरनेट ऑफ़ थिंग्स डिवाइसों से कनेक्ट करने के लिए, वेब ऐप्लिकेशन कैसे बनाए जा सकते हैं.

सोर्स कोड

सोर्स कोड यहां उपलब्ध है. समस्याओं की शिकायत करने या पैच भेजने के लिए, बेझिझक संपर्क करें.

स्केच

अगर आपको भी यह एक्सपेरिमेंट करना है, तो यहां दिए गए एडिसन और ब्रेडबोर्ड स्केच को देखें:

स्केच