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.