Node-serialport: serialport works for only the first connection

Created on 4 Mar 2019  路  8Comments  路  Source: serialport/node-serialport

Summary of Problem

_Can establish the first connection with serialport, any subsequent attempt to read or write fails_
(Please answer all 3)

  • What are you trying to do?
    _Issue commands to an Ardunio_

  • What happens?
    _Connections are established fine, subsequent connections return an error that the port is busy_

  • What should have happened?
    _The commands should have been received by the Arduino and the builtin led should have turned on._

Code to Reproduce the Issue

var SerialPort = require('serialport')
const { ipcRenderer } = require('electron')

let selected_port = '/dev/tty/usb0001'


read_serial_port = function() {
  console.log('Reading from serialport')
  const port = new SerialPort(selected_port, { baudRate: 9600, autoOpen: false})
  port.open()
  port.on('data', (data) => {
    console.log(data)
  })
  port.close()
}

led_on = function() {
  const port = new SerialPort(selected_port, { baudRate: 9600, autoOpen: false})
  port.open()
  port.write('on\n')
  // port.close()
}
led_off = function() {
  const port = new SerialPort(selected_port, { baudRate: 9600, autoOpen: false})
  port.open()
  port.write('off\n')
  // port.close()
}

get_ports = function () {
  SerialPort.list((err, ports) => {
    if (err) {
      console.log(err)
      return
    } else {
      ipcRenderer.send('serialPorts', ports)
    }
  })
}

ipcRenderer.on('portSelected', (event, data) => {
  console.log(data.comName)
  selected_port = data.comName
})

get_ports()


// Code

Versions, Operating System and Hardware

  • SerialPort@? _7.1.4_
  • Node.js v? _10.15.1_
  • Windows? Linux? Mac? _Mac(Mojave)_
  • Hardware and chipset? (Prolific/FTDI/Other) _Sparkfun Redboard_
support

Most helpful comment

I鈥檓 not sure I understand what you mean. Shouldn鈥檛 each interaction with serial have an open-interaction-close transaction? What should that look like?

Not necessarily. I believe the most common pattern with serial ports is to open the port once, keep it open as long as your program is communicating with it, then close it when no longer in use.

You CAN use a pattern where you open it for each command, send the command, then close the port, but this will only allow one-direction communication and won't necessarily be easy to implement because I don't believe node-serialport has an easy way to ensure the command is written fully before the port closes.

Having also built an electron+serialport app, I would also recommend considering developing the serialport communication within the renderer process itself then refactor into a separate process later. You may save yourself a few headaches dealing with ipc handlers (at least I did).

All 8 comments

From my reading, your led functions try to open the port each time they're called but never close it. That's not going to work, because the port can only be opened if it's closed. Your read_serial_port function will also not work, because it closes the port as soon as the listener is created.

You need to move declaring and opening the port outside the scope of those function blocks.

I鈥檓 not sure I understand what you mean. Shouldn鈥檛 each interaction with serial have an open-interaction-close transaction? What should that look like?

this function, you open & close immediate. the 'data' callback is unefficient

read_serial_port = function() {
  console.log('Reading from serialport')
  const port = new SerialPort(selected_port, { baudRate: 9600, autoOpen: false})
  port.open()
  port.on('data', (data) => {
    console.log(data)
  })
  port.close()
}

if you call the led_on, the port will open.
but, when you call the led_off, the port is opened already!

led_on = function() {
  const port = new SerialPort(selected_port, { baudRate: 9600, autoOpen: false})
  port.open()
  port.write('on\n')
  // port.close()
}
led_off = function() {
  const port = new SerialPort(selected_port, { baudRate: 9600, autoOpen: false})
  port.open()
  port.write('off\n')
  // port.close()
}

open the port once, and use all the time.
close the port when you no longer need

I think I am starting to get a little traction here:

````js
var SerialPort = require('serialport')
const Readline = require('@serialport/parser-readline')
const { ipcRenderer } = require('electron')

let selected_port = '/dev/tty/usb0001'

led_on = function () {
const parser = port.pipe(new Readline({ delimiter: '\r\n' }))
console.log(port)
port.write('on\n', (err) => {
if (err) { console.log(err) }
console.log('meesage sent')
})
parser.on('data', (data) => {
console.log(data)
})
}

get_ports = function () {
SerialPort.list((err, ports) => {
if (err) {
console.log(err)
return
} else {
ipcRenderer.send('serialPorts', ports)
}
})
}

ipcRenderer.on('portSelected', (event, data) => {
console.log(data.comName)
selected_port = data.comName
return port = new SerialPort(selected_port)
})

get_ports()
````

I鈥檓 not sure I understand what you mean. Shouldn鈥檛 each interaction with serial have an open-interaction-close transaction? What should that look like?

Not necessarily. I believe the most common pattern with serial ports is to open the port once, keep it open as long as your program is communicating with it, then close it when no longer in use.

You CAN use a pattern where you open it for each command, send the command, then close the port, but this will only allow one-direction communication and won't necessarily be easy to implement because I don't believe node-serialport has an easy way to ensure the command is written fully before the port closes.

Having also built an electron+serialport app, I would also recommend considering developing the serialport communication within the renderer process itself then refactor into a separate process later. You may save yourself a few headaches dealing with ipc handlers (at least I did).

What does closing a listener look like?

I am getting a console logs each time I look for data event but the numbers increase by one each time. Then at some point I get a node error that too many listeners are active and that I should set the max listener count.

Hmmm.

What does closing a listener look like?

I am getting a console logs each time I look for data event but the numbers increase by one each time. Then at some point I get a node error that too many listeners are active and that I should set the max listener count.

Hmmm.

You can close listeners manually using the removeEventListener method, but I generally try to avoid needing to. If you're setting new listeners frequently, you might want to try using the .once() listener instead of .on(). If you're using .on(), you should probably only be setting it once and then handling each event.

You might also be running in to a quirk of Electron and automatic reloading. When you make changes and your Electron app reloads, it restarts the renderer process, but does not NOT restart your main process or (IIRC) other child processes. Listeners you create in your main process will be recreated if you start them with an IPC command from renderer.

It's not NECESSARILY something you have to fix as long as you understand what's happening, but it can trigger some other bugs (like showing duplicate responses). In my case, I "fixed" it in hacky way by only initializing some of the listeners when the main process starts the first time, but I eventually avoided it altogether by refactoring so listeners mostly live closer to the events they're looking for.

I've gotten this to work. Thanks for the assistance folks.

Cheers,

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rwaldron picture rwaldron  路  7Comments

HemantJoshi picture HemantJoshi  路  4Comments

Fuzzzzel picture Fuzzzzel  路  6Comments

byarchil picture byarchil  路  3Comments

apiel picture apiel  路  5Comments