Channels ▼
RSS

Embedded Systems

Adding REST-based Web Services to IoT Devices


Using Bidirectional Event-based Communications

Socket.io is a popular Node.js module that enables real-time bidirectional event-based communications. I'll use Socket.io, Express and HTTP features to allow any client to receive push notifications with voltage measurements. In addition, each client will be able to send messages to turn on/off the onboard LED. I know it is a bit boring to change the status of a LED, but you will be able to use the code as a baseline to control other modules and work with event-based communications for more complex ideas. Sadly, one of the problems with IoT projects is that you usually require many modules to perform a more complex function, and I want to keep things simple and use only the features included in the board.

Create a new IoT project in the IDE using the Blank Template. I've provided detailed step-by-step instructions on how to do this in the first part of this series.

In this case, it is necessary to edit the contents of the package.json file to include two necessary dependencies: express and socket.io. The following lines show the edited package.json contents that indicate the project requires the latest available versions of both express and socket.io. When you build the project, the IDE will run npm install for the two modules directly on the board (the build settings to make this happen are also provided in the previous article).

{
  "name": "blankapp",
  "description": "",
  "version": "0.0.0",
  "main": "main.js",
  "engines": {
    "node": ">=0.10.0"
  },
  "dependencies": {
      "express":"latest",
      "socket.io":"latest"
  }
}

The following lines show the code in main.js that uses Socket.io, Express, and HTTP modules to generate a server that listens on port 1337. You already know how to build and upload the project to the board. In this case, a line provides some hints to JSLint to avoid the IDE displaying errors related to the use of Node.js modules and the MRAA library.

// The following line provides some hints to JSLint to avoid 
// displaying invalid errors in the IDE
/*jslint node:true,vars:true,bitwise:true */

// Require the MRAA library
var mraa = require('mraa');

// Print the MRAA library version to the IDE console
console.log('MRAA Library Version: ' + mraa.getVersion());

// The Galileo Gen 2 onboard led is mapped to pin #13
var onboardLed = new mraa.Gpio(13);
// Set the GPIO direction to output (I want to turn on and off the LED)
onboardLed.dir(mraa.DIR_OUT);
// Analog input pin #1 (A1)
var analogPin1 = new mraa.Aio(1);

/*
Receives a socket to emit voltageUpdate messages with the measured voltage 
between pin A1 and GND. The function sends messages every 5 seconds.
*/
function startVoltageNotifications(socket) {
    setInterval(function () {
        // Read the value from the analog pin (from 0 to 4096)
        var analogValue = analogPin1.read();
        // Convert the retrieved value to the appropriate voltage value
        var measuredVoltage = analogValue / 4096 * 5;
        // Write the measured voltage to the IDE console
        console.log("Measured voltage (in Volts): " + measuredVoltage.toFixed(2));
        socket.emit('voltageUpdate', measuredVoltage.toFixed(2));
    }, 5000);
}

// Create the Socket.io Server
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

app.get('/', function (request, response) {
    response.send('<h1>Socket.io Server working on the device</h1>');
});

app.get('/mraa/', function (request, response) {
    response.send('<h1>MRAA Library Version: ' + mraa.getVersion() + '</h1>');
});

// Attach many event handlers to the Server
io.on('connection', function (socket) {
    console.log('User connnected');
    // Emit an event with a welcome message
    socket.emit('connected', 'Welcome to the Server!');
    
    // Start emitting events with measured voltages
    startVoltageNotifications(socket);
    
    // Attach an event handler that will be fired when the user disconnects
    socket.on('disconnect', function () {
        console.log('User disconnected');
    });
    
    // Attach an event handler that will be fired when the user sends a turnOnboardLEDOn message
    socket.on('turnOnboardLEDOn', function () {
        // Turn on the onboard LED by writing a '1' (high)
        onboardLed.write(1);
        console.log('Onboard LED turned on');
    });

    // Attach an event handler that will be fired when the user sends a turnOnboardLEDOff message
    socket.on('turnOnboardLEDOff', function () {
        // Turn off the onboard LED by writing a '0' (low)
        onboardLed.write(0);
        console.log('Onboard LED turned off');
    });

});

// Start listening at port 1337
http.listen(1337, function () {
    console.log('Server is listening at port 1337');
});

In this case, the build process will require more time because the IDE will install the additional modules. After you start executing the project on the board, you can check whether the project is running with a Web browser. Enter the board's IP address followed by :1337 and you will see the following contents served by the function specified in app.get('/':

Socket.io Server working on the device

Enter the board's IP address followed by :1337/mraa and you will see the MRAA library version served by the function specified in app.get('/mraa/':

MRAA Library Version: v0.4.5

You can develop different types of clients: a mobile app or a Web page. The clients can receive push notifications with the measured voltage and send messages to turn on/off the onboard LED. The required client modules are compatible with Browserify.

Here, I provide an example with a Node client. You have to install the socket.io-client module to run the sample client code. After you finish the installation, you can run the following lines in Node. Don't forget to replace 192.168.2.7 with your board's IP address.

var url = 'http://192.168.2.2:1337';
var io = require('socket.io-client');
var socket = io.connect(url, { reconnection: false });

The attached 'connection' event handler will fire and you will see a User connected message on the IDE console window. The event handler calls the startVoltageNotifications function with the socket as an argument and then attaches many event handlers to the socket:

  • 'disconnect': This will write "User disconnected" to the console window when the user closes the connection.
  • 'turnOnboardLEDOn': When the user sends this message, the event turns on the onboard LED and explains what has been done in the console window.
  • 'turnOnboardLEDOff': When the user sends this message, the event turns off the onboard LED and explains what has been done in the console window.

The startVoltageNotifications function measures the voltage between pin A1 and ground, and calls the socket.emit function to emit a 'voltageUpdate' event to the socket with the measured voltage as the message. The function will measure the voltage and emit the message every five seconds.

Now, enter the following line in your Node terminal:

socket.emit('turnOnboardLEDOn');

The onboard LED will turn on. The following line will turn the onboard LED off:

socket.emit('turnOnboardLEDOn');

The following line will print the measured voltage values received every five seconds to the Node terminal:

socket.on('voltageUpdate', function (voltageValue) { console.log(voltageValue); } );

Conclusion

There are dozens of additional Node.js modules that can simplify your IoT projects. You can easily explore them with the Intel XDK IoT Edition and take advantage of your existing JavaScript and Node.js knowledge to turn your ideas into IoT prototypes. However, don't forget that you should learn or review some basics about electronics before you can make big progress with your IoT ideas.


Gastón Hillar is a senior contributing editor at Dr. Dobb's.

Related Article

Building an IoT Project with Intel Galileo and Node.js


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video