In the first article in this two-part series on the Internet of Things (IoT) with Node.js and Intel Galileo Gen 2, I explained how to prepare the board to work with Intel XDK IoT Edition; and I reviewed basic use of the MRAA library. In this article, I explain how to use Node.js to add REST interfaces and real-time notifications that enable an IoT board to communicate with other applications.
Providing a REST API
In the previous article, I provided an example of a few lines of JavaScript code that could measure a rechargeable battery voltage by using the MRAA library. However, IoT projects require "things" to communicate with other "things" or applications. The huge number of modules available in Node.js makes it easier to generate interfaces. For example, the HTTP module allows you to create an HTTP server to generate a REST API to interact with the Intel Galileo Gen 2 board.
The following lines show a new version of main.js
that uses the HTTP module to create an HTTP server that listens on port 1337 and provides a response for the GET
method with a specific URL. (For all this work, I will continue using Intel XDK IoT Edition as the IDE. I described its use in the previous article.)
// Require the HTTP library var http = require("http"); // 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); var server = http.createServer(function(request, response) { if ((request.method == 'GET') && (request.url = '/batteryVoltage')) { // Turn on the LED by writing a '1' (high) onboardLed.write(1); // 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)); // Write the response HEAD response.writeHead(200, {"Content-Type": "text/plain"}); // Write the response body response.write("Measured voltage A1 (in Volts): " + measuredVoltage.toFixed(2)); // End of the response response.end(); // Turn off the LED by writing a '0' onboardLed.write(0); } }); // Start listening at port 1337 server.listen(1337); console.log("Server is listening at port 1337");
The call to the require
method loads the HTTP module. Notice that this module is included with Node.js installations, so it isn't necessary to make changes to the package.json
file to add an entry to dependencies.
var http = require("http");
The interaction with the MRAA library is very similar to the code explained in the previous article. The call to the http.createServer
method creates the HTTP server and takes a callback function as an argument. Whenever the server receives a new request, the callback function that takes two arguments (request
and response
) will be executed.
The request
object contains information about the client's request. In this case, the code just checks the method
and the URL
. If the client's request is a GET
method with /batteryVoltage
as the URL, the code turns on the onboard LED, uses the code from the previous example to measure the voltage on analog pin A1, and calls many methods of the response
object to write a plaintext (text/plain
) response to the client with the measured voltage in A1.
response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Measured voltage A1 (in Volts): " + measuredVoltage.toFixed(2)); response.end();
Then, the code turns off the onboard LED. This way, whenever a client makes an HTTP GET
request with /batteryVoltage
as the URL, you will see some blinking activity on the onboard LED. In addition, the code writes some output to the console each time a response is built, so that you can see the activity in the IDE within the console window. The call to server.listen
with 1337
as an argument makes the HTTP server start listening for incoming requests at port 1337
.
Build and upload the project with the IDE as explained in the previous article. You will see the following messages in the console window.
MRAA Library Version: v0.4.5 Server is listening at port 1337
At this time, your Galileo Gen 2 board is listening at port 1337 for incoming HTTP requests. You can use either Telerik Fiddler or the curl utility to compose and send a GET
request to the board's IP address, then check the results returned by the HTTP server running on the Galileo Gen 2 board. Telerik Fiddler is a free Web debugging proxy with a GUI. The curl utility is an open source command line tool to transfer data to/from a server (and it supports a large number of protocols). If you are working on either Mac OS X or Linux, you can open a Terminal and start using curl
from the command line. If you are working on Windows, you can easily install curl from the Cygwin package installation option, and execute it from the Cygwin terminal.
I'll provide examples for both Fiddler and curl. I'll always use 192.168.2.7
as my board's IP address in the samples (don't forget to replace it with your board's IP in your own code).
If you send an HTTP GET
request to http://192.168.2.7:1337/batteryVoltage
, you will receive a plaintext response with the measured voltage on the board's analog pin A1. You can execute the following line in a terminal on either Mac OS X or Linux to interact with the HTTP server running on the board and retrieve the measured voltage with curl. In Windows, you can execute the line on the Cygwin terminal.
curl -X GET 192.168.2.7:1337/batteryVoltage
The following lines show the an example of the text response:
Measured voltage A1 (in Volts): 1.24
In Fiddler, click Composer
or press F9
, select GET
in the dropdown menu in the Parsed
tab, and enter 192.168.2.7:1337/batteryVoltage
in the textbox at the right-hand side of the dropdown (don't forget to replace the IP with your board's IP). Then, click Execute
and double click on the 200
result that appears on the capture log. If you want to see the raw response, just click on the Raw
button below the Request Headers
panel.
In this example, the HTTP server just runs code for a very simple GET
method with a parameterless URL. However, you can take full advantage of the HTTP module to create a complete REST API that allows any client to interact with the board. If you add a WiFi module to the board, you can use a REST API to allow any app to control your board while it is moving.
Working with the Remote Debugger
I'll use this example to explain how you can use the remote debugger in Intel's XDK IoT Edition. After you build and upload a project, you can remotely debug the project installed on the board. First, you must click the Stop
button on the panel located at the bottom. Then, click on the Debug
button, and the IDE will launch the remote debugger in a new window (see Figure 1). Notice that it takes some time for the remote debugger to launch. You don't need to plug any additional cable to the board because the remote debugger works through the network.
Figure 1: The remote debugger displaying the main.js source code with two breakpoints.
If you've worked with Google Chrome developer tools, you will notice the debugger uses the same UI. You have two main tabs: Sources
and Console
. You can easily establish breakpoints by clicking on the line numbers. However, if you want to establish a breakpoint at one of the lines within the callback function specified as an argument of the http.createServer
method, you won't be able to do so until the server
object has been created.
You can press F10 to step over next function call and check the messages printed with console.log
calls on the IDE main window. Press F8 to resume script execution until any breakpoint is hit. Make sure you set a breakpoint at the line that starts listening at port 1337:
server.listen(1337);
When the remote debugger hits the breakpoint, you can switch to the Console
tab and evaluate JavaScript expressions that can use the different objects the code has been creating. For example, you can use the mraa
object to check whether the board is an Intel Galileo Gen 2 device. If you enter the following line, the expression will evaluate to true
after a few seconds. (It takes a little time to evaluate expressions.)
mraa.mraa_get_platform_type() == mraa.MRAA_INTEL_GALILEO_GEN2
However, the main goal here is to set a breakpoint at the line that checks the properties of the request
object within the callback function for http.createServer
. Now that the server
object has been created, it is possible to go back to the Sources
tab and set a breakpoint at the following line in main.js
:
if ((request.method == 'GET') && (request.url = '/batteryVoltage')) {
Now, you can press F8 and the debugger will hit the breakpoint whenever a client performs a request to the HTTP server running at the board. You can use either the previously explained curl or Fiddler to send any HTTP request or the same GET
request and the debugger will hit the breakpoint. You will be able to run your code step-by-step, inspect the variables, and evaluate expressions that can interact with the board elements. The remote debugger is extremely helpful to learn how the different libraries work (you can use it as an interactive expression evaluator). I found it extremely useful for learning how the mraa
library works with the different board features.