'Serialport npm List of available COM ports

I'm having a problem with a part of my program and i think I know what the problem is I can't find way to fix it, hence need your help.

I think the problem is not with the serialport.list function but more with the way I am using it.

This is my code:

    var getPortsList= ()=>{
    var portsList = [];
    SerialPort.list((err, ports)=>{
      ports.forEach((ports)=>{
        portsList.push(ports.comName);
        //console.log(portsList);
      });
    });

    return portsList;

  };

So I wraped the list function in my own function and I am calling it when I need to check what ports are available. The problem I'm having is that I always get an empty array returned. If I console.log from inside the forEach i am definitely getting the COM port names and if I console.log from inside the list function after the forEach loop I'm getting the array and is not empty. I can only assume this is some issue relating to the concorrent nature of javascript, but I'm not quite sure how to solve this problem. I can see this is an important concept that will come up all the time and I would like to understand it a bit better. Any info on ways to handle this kind of issue or suitable links would be apreciated. Thank you. Best Regards Luis



Solution 1:[1]

I hope below solution will work for you.

var getPortsList = (callback) => {
  var portsList = [];

  SerialPort.list((err, ports) => {
    ports.forEach((port) => {
      portsList.push(port.comName);
    });

    callback(null, portsList);
  });
};

The reason this does work is because the SerialPort.list method is asynchronous. This leaves your portsList empty because your SerialPort.list hasn't had a chance to complete and fill it yet. Adding in a completion callback gives it the time to run and provide you with a filled array of ports.

Solution 2:[2]

For Windows 10, serialPort's list method prints all available Com ports with info.

const serialPort = require('serialport');

serialPort.list().then(function(ports){
  ports.forEach(function(port){
    console.log("Port: ", port);
  })
});

On terminal:

Port:  { comName: 'COM1',
  manufacturer: '(Standard port types)',
  serialNumber: undefined,
  pnpId: 'ACPI\\PNP0501\\0',
  locationId: undefined,
  vendorId: undefined,
  productId: undefined }
Port:  { comName: 'COM4',
  manufacturer: 'HHD Software Ltd.',
  serialNumber: undefined,
  pnpId: 'ROOT\\PORTS\\0000',
  locationId: undefined,
  vendorId: undefined,
  productId: undefined }
Port:  { comName: 'COM5',
  manufacturer: 'HHD Software Ltd.',
  serialNumber: undefined,
  pnpId: 'ROOT\\PORTS\\0001',
  locationId: undefined,
  vendorId: undefined,
  productId: undefined }

Solution 3:[3]

For windows 7 node serialPort 8, inside electron, using ZTE usb gsm modem.

    // We are using electron and i am using electronService to check if we are inside electron
 if(this._electronService.isElectronApp) {

    // getting serialPort inside electron   
    const serialPort = window['require']('serialport');

    // the serialPort will return promise so we are using then 
    serialPort.list().then(function (data) {
        console.log(data);  
    });

}

Although it doesn't list ZTE USB modem but it lists other ports. I am using little trick to get usb modem port no (I know its not correct way for getting usb modem port)

if(data[0] != undefined){
    let portNameToDecrease = data[0].path;
    let portNoToDecrease = portNameToDecrease.charAt(3);
    portNoToDecrease  = portNoToDecrease - 1 ;
    portNoToDecrease = "COM"+portNoToDecrease;
    data.push({path: portNoToDecrease});
    //Now the data contain the required port
}

Solution 4:[4]

For those who are wondering why the solution marked as an answer isn't working, SerialPort.List is deprecated from SerialPort and moved to SerialPort/List as command tools

Source : https://serialport.io/docs/guide-cli (SerialPort Official Docs)

Installation of SerialPort/List:

npm install @serialport/list

if the installation fails run with sudo

And the method to get List of ports:

const bindings = require('@serialport/bindings')

var listOfPorts=[];

//called automatically by bindings.list()
function list(ports) {
  listOfPorts=ports;
  // now listOfPorts will be the port Objects
  console.log(listOfPorts);
}

bindings.list().then(list, err => {
  process.exit(1)
})

I couldn't find much documentation for serialPort/list with nodejs so i took some of the code out of the source code. BTW I'm a newbie. so don't come at me if I made silly mistakes with the code I pulled out.

I took the Source Code from here: https://github.com/serialport/node-serialport/blob/master/packages/list/lib/index.js

Solution 5:[5]

To further the response by janithcooray, updated to use async/await, this worked for me.

const bindings = require("@serialport/bindings");

/**
 * Get a list of available serial ports. 
 * @param {boolean} verbose - Log results if true. 
 * @returns {{status: string, data: array|object}} - 'ok' or 'fail' with details to handle elsewhere. 
 */
const listPorts = async (verbose) => {
  let result;
  try {
    const portList = await bindings.list();
    if (verbose) console.table(portList); // Print out the array if desired.
    result = { status: "ok", data: portList };
  } catch (err) {
    if (verbose) console.log(err); // To see what the error is, if desired.
    result = { status: "fail", data: err };
  }
  return result;
};

// Run the command.
const { portStatus, portList } = listPorts(true);
// If portStatus is 'ok' then portsList is ready to use. 

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Mark L.
Solution 2 supercat
Solution 3 Muhammad Habib
Solution 4 janithcooray
Solution 5