Handle data sent back over serial by Arduino I have a machine that is being controlled by an Arduino.  If I send the machine the command '9' it will send back JSON with some sensor temperatures in the format {"temperatures":{"bean_temp":110.75,"env_temp":98.15}}.

I am exposing a function called getTemperatures() that I currently call from elsewhere every 1000ms. The serialport library provides a listener for all the data that gets sent back over the wire from the machine (machine.on('data', handleData)). There are other types of data that will get sent back from the machine, such as {"action":"handle_pulled"}. I am filtering the data that comes back over the serial and then assigning temperatures responses to a temperatures variable that I continuously overwrite. I then give a 999 ms delay before calling back that variable.

This works, but seems fragile (and not elegant).

var serialport = require('serialport');

var ports = require('./ports'),
    port = ports.arduino;

var machine = new serialport(port, {
  baudRate: 9600,
  parser: serialport.parsers.readline("\n")
});

machine.on('data', handleData);

var temperatures = {};

machine.getTemperatures = function(callback) {
    sendCommand('9');
    setTimeout(function(){
      callback(temperatures);
    }, 999)
}

function sendCommand(data) {
  machine.write(data);
}

function handleData(dataString){
  data = JSON.parse(dataString);

  if ('temperatures' in data) {
    temperatures = data;
  } 
} 

module.exports.getTemperatures = getTemperatures;
Nobody wants an explicit setTimeout in their async code; you want data as soon as possible.

So I'd wrap the Arduino interface in an object that is an EventEmitter. Have that object listen to any and all incoming data, and dispatch it as temperature events, leverPulled events, and whatever else, based on content.

For extra points, make the Arduino object's data detection extensible, so it can, by itself, be dumb. It might just parse any given line as JSON, and then look through its registered data detection/classification methods, to see what kind of packet it got. Then it'll dispatch an event with that name to whomever listens.

So something like:

// in arduino.js or whatever you want to call it
var serialport = require('serialport'),
    ports = require('./ports'),
    port = ports.arduino;

var machine = new serialport(port, {
  baudRate: 9600,
  parser: serialport.parsers.readline("\n")
});

var wrapper = new require('events'); // i.e. new EventEmitter

var classifiers = {};

machine.on('data', function (string) {
  try {
    var json = JSON.parse(string);
    for (var type in classifiers) {
      if (!classifiers.hasOwnProperty(type)) continue;

      // classifiers are just function that return true
      // if they recognize the json they're given
      if (classifiers[type](json)) {
        wrapper.emit(type, json);
        break;
      }
    }
  } catch (e) {
    wrapper.emit('error', e); // might want to be more elaborate
  }
});

wrapper.addClassifier = function (type, callback) {
  // might want throw an error if the type already exists
  classifiers[type] = callback;
};

wrapper.send = function (string) {
  machine.send(string);
};

module.exports = wrapper;


Usage would be something like:

var arduino = require('./arduino');

// give the arduino wrapper a way to recognize temperature packets
arduino.addClassifier('temperature', function (json) {
  return ('temperature' in json);
});

module.exports.getTemperature = function (callback) {
  // listen for the next incoming temperature reading
  // and send it straight to the callback
  arduino.once('temperature', callback);

  arduino.send('9');
};


And if you want to check for errors, then you can add a timeout - if the temperature event hasn't fired in, say 500ms from sending the '9' command, something's probably wrong (and you'll want to remove the listener). You'll also want to give getTemperature a callback with the Node-typical err, data parameters, so you can send an error back:

module.exports.getTemperature = function (callback) {
  var timeout = null;

  var listener = function (json) {
    clearTimeout(timeout);
    callback(null, json);
  };

  arduino.once('temperature', listener);

  arduino.send('9');

  setTimeout(function () {
    // if we're here, we didn't hear back from the arduino in time
    arduino.removeListener('temperature', listener);
    callback(new Error('Timed out'), null);
  }, 500);
};