node package manager

backchat

node-backchat

Backchat is a chat handler for managing conversations (command/response) with simple serial devices. These might be (for example) devices that support the Hayes AT command set or similar line-oriented text exhange interactions. Backchat isn't suitable for establishing modem links (there's no way to hand off to the data stream) but will work in other cases such as SMS messaging on some GSM modems or for managing a Zigbee Coordinator.

Basic features

  1. Abstracts connection layer to support both local (serial) devices and tcp sockets (uses a URI form to specify the device so the calling interface is the same regardles of network or serial port).

  2. Response buffering (line by line) with an event dispatcher that allows multi-line responses to be collected and dispatched together via EventEmitter.

  3. A rate limiter to prevent flooding the device with multiple asynchronous requests (device access is locked on each write and a 'writeDelay' enforced to enable the rate of command writing to be throttled).

How it works

Say you are writing a script to chat to a device which accepts text commands (e.g. the "AT" command set) and returns responses to your commands with defined prompts. The approach taken with Backchat is that the lines are buffered until it finds a string (coming back from the device) that matches one of those specified in "eventTriggers", then it emits an event with the entire response buffer for proceessing asynchronously by your event handler. The names of the events raised are derived from the commands you send the device, with some basic pre-processing (just to remove any trailing arguments, and lowercase the result). This means that for example, if you routinely issue COMMAND:A, COMMAND:B and COMMAND:C, you could tell Backchat to strip off the ':' character and trailing text, and have it emit a 'command' event which you use to process the buffered results from those commands.

For example, you might issue a command ATCOMMAND:WITH,SOME,ARGS\r, and the device executes your command, issues a number of lines of text in response, and then finishes with an OK or ERROR:CODE response. To use Backchat with this stream you'd configure 'OK' and 'ERROR' as prompts to trigger an event and buffer flush, and specify ':' as a character used to strip trailing arguments. Then when either of 'OK' or 'ERROR' are encountered, the first line of the buffer is processed, and an event 'atcommand' is raised.

Specifying the device URI

Serial Devices

example: serial:///dev/ttyS0?baudrate=57600&databits=8&parity=none&stopbits=1

Note that any parameters supported by the Node.js serialport library can be supplied.

Defaults:

var serialSettings = {
  baudrate: 19200,
  databits: 8,
  parity: 'none',
  stopbits: 1,
  flowcontrol: false,
  parser: ser.parsers.readline("\r\n") // take care of line buffering
};

Network Sockets

example: tcp://hostname:port

Sample Use

The following simple example opens a serial device at /dev/ttyUSB0 at 19200 baud, with a writeDelay of 50 milliseconds. The eventTriggers array specifies strings in the response stream that trigger an event to be emitted (at which point the read buffer is sent). The eventNameStrip array specifies the characters which will be used to strip off trailing characters from the first line of the read buffer to generate the event name.

var Backchat = require('backchat');

var mySerialHandler = new Backchat({
  eventTriggers: [
    { "match": "OK", "exact": true },
    { "match": "ACK", "exact": false },
    { "match": "NACK", "exact": false },
    { "match": "ERROR", "exact": false },
  ],
  eventNameStrip: [':','?','=']
});

mySerialHandler.connect({deviceUrl: 'serial:///dev/ttyUSB0?baudrate=19200', writeDelay: 50 },
  function() {
    mySerialHandler.write('ATI\r');
    mySerialHandler.on('ati', function(stream) {
      // stream is passed in here as an array of lines, the first line
      // being the 'ATI' command, the last being the 'OK' or 'ERROR'
      // that triggered the buffer flush.
      console.log(JSON.stringify(stream));
    });
  }
);