Channels ▼
RSS

JVM Languages

Adding REST-based Web Services to IoT Devices


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.

IoT
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.


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