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

Kenneth Christiansen
Kenneth Christiansen

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

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

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

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

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

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

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

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

कॉन्सेप्ट की पुष्टि करने के लिए, मैंने 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 सेवा से कनेक्ट करते हैं और मुख्य सेवा और उससे जुड़ी विशेषताओं को पाते हैं. इसके बाद, हम वैल्यू पढ़ते हैं और सूचना कॉलबैक सेट अप करते हैं.

नीचे दिए गए हमारे कोड का आसान वर्शन सिर्फ़ नए Web Bluetooth API के साथ काम करता है. इसलिए, 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 डिवाइस को ढूंढता है और उपयोगकर्ता को उससे आसानी से कनेक्ट करने की अनुमति देता है. इसके लिए, उपयोगकर्ता को कभी-कभी इस्तेमाल होने वाले ऐसे ऐप्लिकेशन इंस्टॉल करने की ज़रूरत नहीं होती जिन्हें शायद वह न चाहे और जो समय-समय पर अपडेट हो सकते हैं.

डेमो

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

सोर्स कोड

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

स्केच

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

स्केच