Arduino and node.js

As part of my Open Source Factory Production monitoring, I setup an Arduino to collect analog data and send it to a node.js server. The Arduino sketch takes advantage of the DNS lookup ability in the Ethernet.h library and the DHCP IP address assignment. My goal for this sketch was to make it as easy as possible to use an Arduino for data collection. The sketch takes care of assigning an IP address that is compatible with the network. It then uses DNS lookup to find the IP address of my server. If the network is not configured for DNS lookup it defaults to a known IP address. In my limited testing I have taken the arduino to 3 separate offices and the Arduino was able to log data to the remote server without any configuration.

Arduino

My code is an adaptation from this post by Franci Kapel http://frenki.net/2012/10/remote-logging-with-arduino-and-node-js/. I took that code a step further and automate the IP address configuration and the server IP address lookup. Copy the following code to a new Arduino sketch, edit the IP addresses and server name, then download it to an Arduino Uno with Ethernet Shield.

#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <Dns.h>

IPAddress receiverIP(74, 125, 140, 99); // backup IP of udp packets receiver. used if dns lookup fails. set this to your node.js server IP
unsigned int receiverPort = 8080;      // port for Arduino communication to node.js server
byte mac[] = {  0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 }; //mac address
EthernetUDP Udp;
byte serialNum[] = {  0x99, 0xAA, 0xBB, 0xCC }; // a unique identifier for each arduino on the network
int sensorPin = A0; //define sensor pin
int sensorValue;

void setup() {
// Open serial communications and wait for port to open:
  Serial.begin(9600);
  // start the Ethernet connection:
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    for(;;)
      ;
  }
  // print your local IP address:
  Serial.print("My IP address: ");
  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    // print the value of each byte of the IP address:
    Serial.print(Ethernet.localIP()[thisByte], DEC);
    Serial.print(".");
  }
  Serial.println();
  Udp.begin(receiverPort);
  // lookup the IP of the logging site
  DNSClient dns;
  IPAddress remote_addr;
  int ret = 0;
  Serial.print("DNS IP is ");
  dns.begin(Ethernet.dnsServerIP());
  ret = dns.getHostByName("www.google.com",remote_addr); // set this to the DNS name of your server.
  Serial.println(remote_addr);
  Serial.print("Log IP is ");
  if (ret == 1) {
    receiverIP = remote_addr; // dns lookup was successful
  }
  Serial.println(receiverIP);
}

void loop() {
  sensorValue = analogRead(sensorPin);//read sensor value from 0 to 1023
  byte valueInBytes[8] = {lowByte(sensorValue), highByte(sensorValue), serialNum[0], serialNum[1], serialNum[2], serialNum[3]}; //convert it to byte array
  Udp.beginPacket(receiverIP, receiverPort); //start udp packet
  Udp.write(valueInBytes, 8); // write sensor data and serial number to udp packet
  Udp.endPacket(); // end packet

  delay(10000);
}

node.js

My node.js server is an Ubuntu instance hosted by Amazon. I installed node.js as I outlined here. Then I adapted the node.js code by Franci Kapel http://frenki.net/2012/10/remote-logging-with-arduino-and-node-js/. To easily access the data from Drupal later on, I put the data into MySQL instead of a file. Also, I record the Unix Timestamp and incoming IP address. When the node.js script is run it waits for incoming UDP packets on port 8080 and then parses them and puts them in the database. I created a new table and user in MySQL for the node.js server. The table has the columns: ID, value, serialNum, date, datetime, and IP. Date is the MySQL CURRENT_TIMESTAMP and datetime is the UNIX TIMESTAMP. (The timestamps are different.) Having the Unix Timestamp makes my front end graphing scripts run much faster.

After installing node.js add the mysql library with the command npm install mysql@2.0.0-alpha3.

var dgram = require("dgram");
var server = dgram.createSocket("udp4");

var crlf = new Buffer(2);
crlf[0] = 0xD; //CR - Carriage return character
crlf[1] = 0xA; //LF - Line feed character

var mysql      = require('mysql');
var connection = mysql.createConnection({
  host     : 'localhost',
  user     : 'user',
  password : 'password',
});

server.on("message", function (msg, rinfo) { //every time new data arrives do this:
  var MYtime = new Date().getTime();
  var MYquery = 'INSERT INTO `arduino`.`arTable` (`id`, `value`, `serialNum`, `date`, `datetime`, `IP`) VALUES (NULL, "' + msg.readUInt16BE(1) + msg.readUInt16BE(0) +  '", "' + msg.readUInt16BE(2) + msg.readUInt16BE(3) + msg.readUInt16BE(4) + '", CURRENT_TIMESTAMP, "'+ MYtime + '", "'+ rinfo.address + ":" + rinfo.port + '");';
  //console.log(MYquery); // you can comment this line out
  connection.query(MYquery, function(err, rows) {
  });
});

server.on("listening", function () {
  var address = server.address();
  console.log("server listening " + address.address + ":" + address.port);
});

server.bind(8080); //listen to udp traffic on port 8080

Read More