Serial to JSON in Node.js and Arduino

Node.js is great for making web services, and node-serialport makes it very easy to connect to serial devices on your computer. In my last post, I showed how to connect an Arduino microcontroller application to a web page using Node.  This post expands on that, introducing how to use JavaScript Object Notation (JSON) from Arduino all the way through to your HTML page.

The beauty of node is that it’s JavaScript, so you get to use everything Javacript gives you, including its wonderful lightweight data format, JSON, or JavaScript Object Notation. JSON describes data objects using arrays of key-value pairs separated by colons. If you want to add more properties to an object, just add another array element. the value of an element can be a JSON object itself. When you’ve got an application that uses JavaScript on the server side and on the client side, it makes sense to use JSON to describe your data all the way through, so you can just pass it around without a lot of conversion.

Arduino doesn’t speak JSON natively. There are a couple JSON parser libraries out there for Arduino, but I haven’t seen one that I like yet. All of the ones I’ve seen expect more pointer knowledge from the user than I’d like.  So for this example you’ll assemble your own JSON string using Arduino’s String class, and letting node.js turn it into a JSON object.

To make this happen you’ll need:

This post assumes you understand:

  • How to use Arduino, including how to send serial data
  • How to write a web page, and what a server is
  • A little about JavaScript
  • A little about the command line
  • Beginning experience with node.js.  For my brief intro, see this post.

The example works like this:

  • Arduino reads accelerometer
  • Arduino sends JSON string of X,Y, and Z values to node.js
  • node.js listens for clients
  • If node.js gets a client, it reads serial string and generates a serialEvent, sending along the JSON object read from the Arduino
  • Web client (also written in JavaScript) opens a websocket to node.js
  • Web client listens for serialEvents, extracts object, uses it to set properties of a paragraph tag in the HTML document.
First, get the project from my GitHub repository. If you’re familiar with git, just clone the whole NetworkExamples repository. If you’re not familiar with git, then download the .zip file and copy the serialToJSON directory to your user directory or desktop or wherever you like to work.

The Arduino Sketch

You can find this sketch in the ADXL326 directory of the project.

The accelerometer used for this project is an ADXL326 breakout board from Adafruit.  It’s conveniently arranged so that you can plug it directly into pins A0 through A5 of an Arduino Uno, leaving the Test pin of the accelerometer hanging loose.  The pins line up as follows:

  • Vin – A0
  • 3Vo – A1
  • Zout – A2
  • Yout – A3
  • XOut – A4
  • Gnd – A5
The accelerometer consumes very little amperage, so it can run off the output of an I/O pin easily. To make it work, set the pinMode of pins A0 and A5 to OUTPUT and take them HIGH and LOW respectively, like so:
  // initialize power and ground pins for accelerometer:
  pinMode(A0, OUTPUT);
  pinMode(A5, OUTPUT);
  digitalWrite(A0, HIGH);
  digitalWrite(A5, LOW);

Reading the accelerometer on the Arduino is pretty standard, but the formatting of the serial output is special.  The X, Y, and Z pins of the accelerometer outpu an analog voltage that varies with the acceleration on that axis. You read them using analogRead().  To format the data as a JSON string, though, it should look like this:

{"x":"379","y":"364","z":"389"}

One easy way to format it is to assemble the values and the text around it as a String:

 // form a JSON-formatted string:
    String jsonString = "{\"x\":\"";
    jsonString += x;
    jsonString +="\",\"y\":\"";
    jsonString += y;
    jsonString +="\",\"z\":\"";
    jsonString += z;
    jsonString +="\"}";

    // print it:
    Serial.println(jsonString);

In order to get the quotation marks in the string (which are needed for proper JSON formatting),  you need to escape them with a backslash like so: \”

There’s a handshaking setup between node.js and the Arduino so that the Arduino sends data only when there’s a web client connected to node.js. Arduino starts sending when it sees the letter c come in the serial port, and stops when it sees the letter x:

 // read for incoming messages. c = send, x = don't send:
  char inChar = Serial.read();
  switch (inChar) {
  case 'c':    // connection open
    sending = true;
    break;
  case 'x':    // connection closed
    sending = false;
    break;
  }

  if (sending) {
     // read sensors and send serial data here
  }

That’s it on the Arduino side. You can test the code by opening the Serial Monitor and sending a c, then watching the data, then sending an x. You should see something like the string shown above.

 The node.js Server Script

To use node.js, you need to be familiar with the  command line interface on your computer.  Open a new terminal window and change directories to the serialToJSON project directory you downloaded. If you list the files, you should see something like the following:

  • ADXL326 – a directory containing the Arduino sketch
  • SerialToJSON.js – the node.js server script
  • README.md – the readme file
  • index.html – the index page to be served to the web client
  • package.json – the package description for the project.

The node.js server script relies on several node packages:

There’s a package.json file included in the  gitHub repository for this project, so once you’ve downloaded this project from gitHub, you can install all the packages by typing:

npm install

 This command will download and install all the necessary packages for this project from the net.  It’ll create a new directory for them in the project directory called node_modules. For more on this, see the npm guide to making packages.

Once you’ve got the packages installed, it’s time to launch the server.  You’ll need to know the name of your serial port.  It’lll be the same name you used to choose your serial port in Arduino. For example, on my mac, it’s /dev/tty.usb241331. On my PC, it’s COM4. To launch the server, type

node SerialToJSON.js portname

For example, for me it’s

node SerialToJSON.js /dev/tty.usbmodem241331

You’ll get a message like this:

info - socket.io started
opening serial port: /dev/tty.usbmodem241331
Listening for new clients on port 8080

Now you can open a connection to the server in a browser. Open a browser and enter this address:

http://localhost:8080

The server will deliver index.html to your browser and start listening to the serial port.  The index page will listen for serial events from the server, and update the DIV with the new data.  Voila! You’re serving serial data to a web page. You should see the accelerometer values in your browser window, and if you shake the accelerometer you’ll see the values jump around in the window.

To stop the server, hold down the control key then type C on the command line.

There are three main parts to the server script. The top part is where you set up all the initial variables and start listening on the serial port and on TCP port 8080 for web clients. The second part is where you listen for HTTP GET requests from the client. The only thing you’ll do here is to serve the index.html file, like so:

// respond to web GET requests with the index.html page:
app.get('/', function (request, response) {
  response.sendfile(__dirname + '/index.html');
});

The third and most complex part is the section that responds to a websocket connection event. This occurs when a client connects, so the first thing you want to do is keep track of whether you’re connected or not, and send a message to the Arduino to start sending data, like so:

// if the client connects:
if (!connected) {
	// clear out any old data from the serial bufffer:
	myPort.flush();
	// send a byte to the serial port to ask for data:
	myPort.write('c');
        console.log('user connected');
    	connected = true;
}

You’ll also listen for two other events: a websocket disconnect event, where you’ll send a serial message to the Arduino to disconnect, like so:

 // if the client disconnects:
socket.on('disconnect', function () {
	myPort.write('x');
        console.log('user disconnected');
    	connected = false;
  });

The other event to listen for is a new serial data event.  When this happens, you’ll convert the JSON string that came in serially to a JSON object, and send it to the client via the websocket:

        
// listen for new serial data:  
myPort.on('data', function (data) {
	// Convert the string into a JSON object:
	var serialData = JSON.parse(data);
	// for debugging, you should see this in the terminal window:
	console.log(data);
	// send a serial event to the web client with the data:
	socket.emit('serialEvent', serialData);
});

That’s it for the server script. The rest is handled by the web client page.

The Web Client page

Printing the serial data to the web page is done using JavaScript and CSS.  When the page loads, it makes a websocket connection back to the server, then waits for serialEvents.

There’s a paragraph tag in the body of the HTML page.  When the client gets a new serialEvent, it uses the JSON object it gets from the server to set the CSS properties of the paragraph tag, like so:

 // when you get a serialdata event, do this:
socket.on('serialEvent', function (data) {
	// you're going to move the div in the HTML:
	var element = document.getElementById('textDisplay');
	element.style.position = "absolute";
        // set the left edge of the text	
	element.style.left = data.x+ "px";
        // set the top edge of the text	
	element.style.top = data.y+ "px";	
        // set the size of the text
	element.style.fontSize = data.z + "%";	
        // set the text itself	
	element.innerHTML = data.x + "," + data.y + ","+ data.z;
});

Notice how easy it is to pull the data out of the message thanks to JSON. You just refer to
That’s it! When the page loads, the client starts the JavaScript, which starts the websocket, and the rest is history.

Using a combination of websockets and JSON like this, you can pass any data from a serially connected device to a web page via node. Enjoy!

This entry was posted in arduino/wiring, code, javascript, node.js. Bookmark the permalink.