2
votes

I'm using the serialport2 library for node.js to receive serial data from an arduino. This works like a charm but every now and then the pc running node, decides to deactivate the usb ports due to EMI. Allthough the ports get activated again right away, Serialport drops the connection. Node.js remains running but never recovers the serial connection to the arduino.

Using the 'closed' event of Serialport I want node to reconnect to the serial port, after a short delay. This works fine, so far:

var SerialPort  = require('serialport2').SerialPort;
var arduinoPort = '/dev/arduino';

// setting up the serial connection
var arduinoSerial = new SerialPort();

var connectArd = function() {
  arduinoSerial.open(arduinoPort, {
    baudRate: 9600,
    dataBits: 8,
    parity: 'none',
    stopBits: 1,
    flowControl: false
  });
}

connectArd();

// do something with incoming data
arduinoSerial.on('data', function (data) {
  .
  .
  .
});

// check for connection errors or drops and reconnect
var reconnectArd = function () {
  console.log('INITIATING RECONNECT');
  setTimeout(function(){
    console.log('RECONNECTING TO ARDUINO');
    connectArd();
  }, 2000);
};

arduinoSerial.on('close', function(){
  console.log('ARDUINO PORT CLOSED');
  reconnectArd();
});

arduinoSerial.on('error', function (err) {
  console.error("error", err);
  reconnectArd();
});

As soon as there is an EMI or the USB cable gets disconnected the 'close' listener of 'arduinoSerial' kicks in, waits for about 2 seconds and reconnects to the arduino. The connection is recovered and node receives data from the arduino again.

But... this only works once!? When there is a second disconnect, node stops receiving data but for some reason, this time the 'close' event doesn't get triggered. I have to restart the node application in order to reconnect to the arduino again.

I'm fairly new to javascript, so this could very well be a rookie mistake. What am I doing wrong? Could someone please point me in the right direction?

(I know I should rather start looking for the source of the interference but this kind of an auto-reconnect-function will come in handy for usability/handling reasons of the device, as well.)

thanks

5
Silly question possible, but have you verified that the application runs and can react on events in general?JanD
Yeah, I checked... events in general are fine.mrv

5 Answers

3
votes

It's still insane to me that these old posts come up on my Google searches, but I figured I better post an answer here for other time travelers.

The problem with the accepted answer is you're likely going to exceed the maximum event listeners set by Node since you're redefining them every time. What you can do simply, using newest versions of Node SerialPort 7.x.x, call the open() method. Here's some sample code that I've tested and confirmed. I doubt this.connected is necessary as there is likely a access method on SerialPort but I was just using it for troubleshooting. I'm using this class as a super as well so there's some other logic in there for handling different kinds of parsers so you can ignore that as well.

  connect() {
    return new Promise((resolve) => {
      this.serialPort = new SerialPort(this.port, { baudRate: this.baudRate, autoOpen: false });
      this.parser = this.serialPort.pipe(this.parser);

      this.serialPort.on('open', () => {
        this.connected = true;
      });
      this.serialPort.on('close', () => {
        this.connected = false;
        setTimeout(this.reconnect.bind(this), 5000);
      });
      this.serialPort.on('error', () => {
        setTimeout(this.reconnect.bind(this), 5000);
      });

      this.serialPort.open();

      resolve(this.parser);
    });
  }

  reconnect() {
    if (!this.connected) { this.serialPort.open(); }
  }
2
votes

Thanks for your answers. I could figure it out.

var SerialPort  = require('serialport2').SerialPort;
var arduinoPort = '/dev/arduino';

// setting up the serial connection

var connectArd = function() {
  var arduinoSerial = new SerialPort();
  arduinoSerial.open(arduinoPort, {
    baudRate: 9600,
    dataBits: 8,
    parity: 'none',
    stopBits: 1,
    flowControl: false
  });

  // do something with incoming data
  arduinoSerial.on('data', function (data) {
  .
  .
  .
  });

  arduinoSerial.on('close', function(){
    console.log('ARDUINO PORT CLOSED');
    reconnectArd();
  });

  arduinoSerial.on('error', function (err) {
    console.error("error", err);
    reconnectArd();
  });

}

connectArd();

// check for connection errors or drops and reconnect
var reconnectArd = function () {
  console.log('INITIATING RECONNECT');
  setTimeout(function(){
    console.log('RECONNECTING TO ARDUINO');
    connectArd();
  }, 2000);
};

I think the breakthrough was to call var arduinoSerial = new SerialPort(); on every reconnect. I guess this (re)attatches the listeners, so they don't get lost in the arduinoSerial.on('close') event.

0
votes
  • Shouldn't you register the .on function before opening the connection?

  • There seems to be a module for this babysitter

0
votes

you should not use serialport2 because it has been deprecated for over year. You should use node serial port instead, it works the same way and may solve your problem.

-1
votes

In serialport close event, you should call arduinoSerial.resume() method according to serialport.io.

  arduinoSerial.on('close', function(){
    console.log('ARDUINO PORT CLOSED');
    arduinoSerial.resume();
    reconnectArd();
  });