Arduino and the Web using NodeJS and SerialPort2

By Bangon Kali, 18 Aug 2012

Download demo project - 2.43 KB

 


Introduction

This article provides the necessary steps in allowing your Arduino board to be interfaced to the web using novel but Open Source technologies everyone can use. This has long been available but using other alternative ways of doing things by using LAN, or Zigbee modules/shields for Arduino, and they can be quite expensive. However, depending on the purpose, this simple solution may be sufficient enough. 

You can watch this simple video as a simple demonstration of what can be done using your Arduino and the Web. 

Background 

Using the USB, the Arduino Board is connected to the PC serially to a certain COM port which the OS allocates. Node.JS, the asynchronous server side JavaScript engine then listens for the port using a Node.JS module called SerialPort2. When a signal is received, using the Node.JS Socket.IO module, data is then served also asynchronously to the web providing a real time feed of the Arduino signal.

The following are the key technologies being used to present the feasibility of this approach to the particular problem:

  • Arduino - A small electronics prototyping board. Available in multiple versions but in this article the one being used is the Arduino Mega 2560 Version 1. The same methods can be applied to other versions of the Arduino as long as it has means to output data serially.
  • NodeJS - A server side JavaScript interpreter.
  • NodeJS SerialPort2 - A Node.JS module for listening to COM ports.
  • NodeJS Socket.IO - A Node.JS module for serving async data to the web using technologies such as WebSockets.
  • NPM - Is a Node.JS package manager already included with the official installer of Node.JS.
  • jQuery - A JavaScript library for easier scripting.
  • Flot - Flot is a pure JavaScript plotting library for jQuery.
  • Apache - Used in this project for serving static content. The WAMP pack is the suggested package for easy installation. The user can also use the WAMP pack for hosting PHP and MySQL. 

For Windows users, SerialPort2 requires the following for a successful build:

  • Python 2.7.3
  • Visual Studio 2010
  • Windows SDK 7.1

The Solution

It is considered that the user already has a working knowledge of an Arduino. For the purpose of this article, we will create a certain scenario for which we will create a solution. A potentiometer is connected to the Arduino board to Analog pin 0 (from now on referred to as A0). We will want to stream the analog signal levels to the web and view it using a web browser such as Google Chrome, Firefox, or Internet Explorer. The signal levels must update in real time as the potentiometer is rotated.

Preparation of the Arduino Board

You can refer to the following schematic in order to setup the potentiometer and your Arduino board.

Programming your Arduino

You can use the following code for you Arduino. The code is sufficiently commented. It is recommended that the reader understand how the code works with respect to the Arduino in order to fully understand the next steps.

const int analogInPin = A0;  // Analog input pin that the potentiometer is attached to

int sensorValue = 0;        // value read from the pot
int prevsensorValue = 0;

void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600); 
}

void loop() {
  // read the analog in value:
  sensorValue = analogRead(analogInPin);
  
  // If the previous value is the same as the new one, the do not send to save
  // communication link between the Arduino and the PC. 
  if (prevsensorValue != sensorValue) {
    // print the results to the serial monitor:
    Serial.print("A"); // Print the letter A to signal the beginning of an Input
    Serial.print(sensorValue); // Send the sensor Value (this is an integer)
    Serial.print("B"); // Print the letter B to signal the end of an Input
    prevsensorValue = sensorValue; // Change the previous sensor value
  }
  // wait 100 milliseconds before the next loop
  // for the analog-to-digital converter to settle
  // after the last reading. If you are sending too fast
  // there is also a tendency to flood the communication line.
  delay(100);                     
}

Preparing Node.JS

You can download the official installer of Node.JS from its official website. The recommended version is Node.JS v0.7.8. Also, in order to successfully build SerialPort2 on Windows, you are required to install Python 2.7.3 and Microsoft Visual Studio 2010 with the Microsoft Windows SDK 7.1. The NPM module which is already a part of the Node.JS v0.7.8 will take care of the build process. However, to make things easier, you may need to add the python.exe directory path to the PATH environment variable.

In order to install the required Node.JS modules using your command prompt, go to your working directory. The following command will download, build, and install the necessary Node.JS modules.

npm install serialport2 socket.io

You should have an output that will appear similar to this.

Preparing the Server Side

Create a file called server.js on the working directory.

The following lines of code prepares the necessary connections for Node.JS and the port. Data received is the global variable:

var SerialPort  = require('serialport2').SerialPort;
var portName = 'COM3';
...

Then the following code opens the serial port connection:

...
var sp = new SerialPort(); // instantiate the serial port.
sp.open(portName, { // portName is instatiated to be COM3, replace as necessary
   baudRate: 9600, // this is synced to what was set for the Arduino Code
   dataBits: 8, // this is the default for Arduino serial communication
   parity: 'none', // this is the default for Arduino serial communication
   stopBits: 1, // this is the default for Arduino serial communication
   flowControl: false // this is the default for Arduino serial communication
});
...

The following code is triggered only when the serial port is receiving messages from the specified port.

...
var cleanData = ''; // this stores the clean data
var readData = '';  // this stores the buffer
sp.on('data', function (data) { // call back when data is received
    readData += data.toString(); // append data to buffer
    // if the letters 'A' and 'B' are found on the buffer then isolate what's in the middle
    // as clean data. Then clear the buffer. 
    if (readData.indexOf('B') >= 0 && readData.indexOf('A') >= 0) {
        cleanData = readData.substring(readData.indexOf('A') + 1, readData.indexOf('B'));
        readData = '';
        /*
            More code here later...
        */
    }
});
...

We are now ready to send the clean data to the web. In order to do this, we must first setup the Socket.IO module. On the top part of the file, insert the instantiation of the Socket.IO module.

var SerialPort  = require('serialport2').SerialPort;
var portName = 'COM3';
var io = require('socket.io').listen(8000); // server listens for socket.io communication at port 8000
io.set('log level', 1); // disables debugging. this is optional. you may remove it if desired.
...

The next step is to turn on Socket.IO.

io.sockets.on('connection', function (socket) {
    // If socket.io receives message from the client browser then 
    // this call back will be executed.
    socket.on('message', function (msg) {
        console.log(msg);
    });
    // If a web browser disconnects from Socket.IO then this callback is called.
    socket.on('disconnect', function () {
        console.log('disconnected');
    });
});

The last step is to allow the server side Socket.IO to emit a message to all listening clients if there is new sensor data. In order to do this, insert the following line to sp.on('data').

...
io.sockets.emit('message', cleanData);
...

After updating the code, sp.on('data') will look like this:

...
var cleanData = ''; // this stores the clean data
var readData = '';  // this stores the buffer
sp.on('data', function (data) { // call back when data is received
    readData += data.toString(); // append data to buffer
    // if the letters 'A' and 'B' are found on the buffer then isolate what's in the middle
    // as clean data. Then clear the buffer. 
    if (readData.indexOf('B') >= 0 && readData.indexOf('A') >= 0) {
        cleanData = readData.substring(readData.indexOf('A') + 1, readData.indexOf('B'));
        readData = '';
        io.sockets.emit('message', cleanData);
    }
});
...

Your entire server side source code server.js will look like the following:

var SerialPort  = require('serialport2').SerialPort;
var portName = 'COM3';

var io = require('socket.io').listen(8000); // server listens for socket.io communication at port 8000
io.set('log level', 1); // disables debugging. this is optional. you may remove it if desired.

var sp = new SerialPort(); // instantiate the serial port.
sp.open(portName, { // portName is instatiated to be COM3, replace as necessary
   baudRate: 9600, // this is synced to what was set for the Arduino Code
   dataBits: 8, // this is the default for Arduino serial communication
   parity: 'none', // this is the default for Arduino serial communication
   stopBits: 1, // this is the default for Arduino serial communication
   flowControl: false // this is the default for Arduino serial communication
});

io.sockets.on('connection', function (socket) {
    // If socket.io receives message from the client browser then 
    // this call back will be executed.
    socket.on('message', function (msg) {
        console.log(msg);
    });
    // If a web browser disconnects from Socket.IO then this callback is called.
    socket.on('disconnect', function () {
        console.log('disconnected');
    });
});

var cleanData = ''; // this stores the clean data
var readData = '';  // this stores the buffer
sp.on('data', function (data) { // call back when data is received
    readData += data.toString(); // append data to buffer
    // if the letters 'A' and 'B' are found on the buffer then isolate what's in the middle
    // as clean data. Then clear the buffer. 
    if (readData.indexOf('B') >= 0 && readData.indexOf('A') >= 0) {
        cleanData = readData.substring(readData.indexOf('A') + 1, readData.indexOf('B'));
        readData = '';
        io.sockets.emit('message', cleanData);
    }
});

Preparing the Client Side

This is how we will want the client side to look like:

The progress bar is powered by jQuery. The graph output is powered by Flot. The value, progress bar, and graph updates in real time as shown in this video.

You must have the jQuery library, and an appropriate jQuery UI library on your working directory to make this work. Also, the Flot library is required to make the graph work.

Refer to the source code section for the exact coding of the index.html. 

Final Step

Connect your Arduino to your PC using the USB and determine the correct port which it was assigned to. You can usually easily do this by using the Arduino programmer software and checking the available ports. For Windows, it is usually higher than COM Port 1.

Setup the Apache config to point to your working directory and have it serve the index.html for the clients.

Using the command prompt pointed at your working directory, you can run server.js by issuing the following command:

node server.js 

You can then rotate your potentiometer and see the potentiometer value, bar graph, and the line graph respond to changes in real time.

Recent Updates  

NodeJS SerialPort2 is think now is merged with the original SerialPort project. You may check the projects here and the message by the author of those great modules here

Points of Interest 

Of course if you want an easier solution, you can buy the Ethernet Shield or the ZigBee shield for an even more sophisticated implementation.

History 

  • Aug 19, 2012 01:03 AM PHT - Edited links and added some more information. 
  • May 22, 2012 7:02 AM PHT - Submitted for posting. 

posted on 2013-12-24 17:28  荣锋亮  阅读(670)  评论(0编辑  收藏  举报

导航