node-serialport icon indicating copy to clipboard operation
node-serialport copied to clipboard

List symlinks or by ID-path

Open biohazardxxx opened this issue 7 years ago • 22 comments

  • Debian Jessie on Raspberry PI2 Hi,

since with every reboot of raspbian (belive it is the same with other UNIX systems) the USB port assignments are jepardized if several serial devices are attached. Like /dev/ttyUSB0 can be /dev/ttyUSB1 at next boot. It would be good to have the possilbity to list devices by device id path for example: /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A50285BI-if00-port0 or also list symlinks. Then a static link can be created via /etc/udev/rules.d

This is what I have:

pi@rpi:~ $ ls -l /dev/ttyUSB1 crw-rw---- 1 root dialout 188, 1 Feb 6 10:47 /dev/ttyUSB1 pi@rpi:~ $ ls -l /dev/ttyRflink lrwxrwxrwx 1 root root 7 Feb 6 10:44 /dev/ttyRflink -> ttyUSB1

But /dev/ttyRflink does not get listed by serialport.js

biohazardxxx avatar Feb 13 '18 09:02 biohazardxxx

What you might want to do in this case is run udevadm info /dev/ttyUSB0 (either in a console or via process.exec), and look for the DEVLINKS file.

IvanSanchez avatar Feb 26 '18 12:02 IvanSanchez

But using this node as a dependency in an application, it makes more sence to also list virtual/linked devices via node-serialport IMHO.

biohazardxxx avatar Feb 26 '18 13:02 biohazardxxx

We sort of support the lowest common denominator when it comes to port listing. Since we have a few subsystems for serialports (not every kind of adaptor will show under /dev/serial/by-id/ afaict) I think we'd have to support different modes or different list functions.

reconbot avatar Feb 28 '18 04:02 reconbot

AFAIK the symlinks in linux are created by udev, and it might in fact not be safe to assume that a linux installation has udev installed.

IvanSanchez avatar Feb 28 '18 08:02 IvanSanchez

@reconbot please consider #1777 ... I still would really like to have this feature !!

Apollon77 avatar Jan 24 '19 07:01 Apollon77

What does symlinks provide? Why do you need them? I'm hesitant to add this since it's linux only.

reconbot avatar May 02 '19 01:05 reconbot

The problem on Linux (do not know about windows) is that’s so soon as you have multiple usb devices on your host the can change order on next boot. So /dev/ttyUSB0 can be one device now and an other one after next boot.

With this your scripts break because connecting to wrong device. So ttyUSB0 is pointing to an „initialized device“ and not to a USB port where it is connected“.

But Linux provide symlinks like „/dev/serial/by-id/...“ or /dev/serial/by-name/... or options to define your own Namings via udev rules to get names that do not change.

This is the main benefit.

Apollon77 avatar May 02 '19 04:05 Apollon77

That's awesome. I think an option for list when on linux to choose how we return the results is a good way to handle this. Maybe call it source?

const ports = await list({ source: 'udevById` })

And then path is the udev ID path instead of the ttyUSB0 etc

reconbot avatar May 02 '19 14:05 reconbot

Cool idea. Or always try if udev is available and add all. Because code reality maybe would be to get with udev and if empty get as till now. So would simplify for the dev ;-)

Apollon77 avatar May 02 '19 15:05 Apollon77

I'm prepping for a major release so breaking changes are welcome. Sounds like by-id is the most useful?

reconbot avatar May 02 '19 15:05 reconbot

In my eyes yes (by-id)

Apollon77 avatar May 02 '19 18:05 Apollon77

Or if you really want to go "breaking" then return a array ob objects as result with meta infos like [{path='/dev/ttyUSB0', source: 'port'}, {path='/dev/serial/by-id/whatever', source: 'udev'} ]

Apollon77 avatar May 03 '19 10:05 Apollon77

I think it's reasonable to believe you're going to get a single object per device, but I'm for options. Can you give me the output of udevadm info -e with one or more devices from your machine? I don't have a ton of test hardware available.

reconbot avatar May 08 '19 22:05 reconbot

Sure will post tomorrow

Apollon77 avatar May 08 '19 22:05 Apollon77

Here you go :-)

All are Ubuntu 18.04 VMs on Proxmox hosts

io1: ZWave USB stick connected and also Bluetooth (but not shown as serial port) io1.txt

io2: Zigbee USB stick connected and Bluetooth (but not shown as serial port) io2.txt

io3: Two USB-IR-Reading.Heads with same chipset connected. They are also configured with their very special name by a custom UDEV rule io3.txt

Do you need more?

Apollon77 avatar May 09 '19 10:05 Apollon77

A local Proxmox host I assume? I’ll start with these.

reconbot avatar May 09 '19 22:05 reconbot

Im fact the usb devices are connected to the proxmox hosts and made available via usbip to the vms. Bite so for the vms are as local devices.

Apollon77 avatar May 10 '19 04:05 Apollon77

Please take a look at #1871 I decided to only use the by-id path without options. I can't imagine when we'd need the normal path, serialport will always be able to open the port with that path. But we'll have the beta to see if I'm overlooking something.

reconbot avatar May 17 '19 05:05 reconbot

Looks good, looking forward for it :-) I hope that all USB port cases also have a "by-id" ...

Apollon77 avatar May 23 '19 14:05 Apollon77

PS: It may break some UIs showing the values of the port list because now the strings are way longer :-)

Apollon77 avatar May 23 '19 14:05 Apollon77

That's a really cool feature. :+1: Missed this so much in the past because I always add custom symlinks to my serial ports to get a stable device link. But in my opinion it's not enough to only took this "by-id" symlink. With udev you are able to create as many symlink as you want to. Udev comes with a default rule set for serial devices in /lib/udev/rules.d/60-persistent-serial.rules. This automaticly adds the "by-id" and "by-path" symlink. But for me I always add a custom name. This is very important for me because these "by-id" symlinks can be the same for differnt devices. For example, if a plug in two of my China Arduinos:

Click to see Udev example

~ udevadm info /dev/ttyUSB0 P: /devices/pci0000:00/0000:00:14.0/usb3/3-3/3-3:1.0/ttyUSB0/tty/ttyUSB0 N: ttyUSB0 L: 0 S: serial/by-path/pci-0000:00:14.0-usb-0:3:1.0-port0 S: ttyChinaArduino1 S: serial/by-id/usb-1a86_USB2.0-Serial-if00-port0 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb3/3-3/3-3:1.0/ttyUSB0/tty/ttyUSB0 E: DEVNAME=/dev/ttyUSB0 E: MAJOR=188 E: MINOR=0 E: SUBSYSTEM=tty E: USEC_INITIALIZED=21160250070 E: ID_BUS=usb E: ID_VENDOR_ID=1a86 E: ID_MODEL_ID=7523 E: ID_PCI_CLASS_FROM_DATABASE=Serial bus controller E: ID_PCI_SUBCLASS_FROM_DATABASE=USB controller E: ID_PCI_INTERFACE_FROM_DATABASE=XHCI E: ID_VENDOR_FROM_DATABASE=QinHeng Electronics E: ID_MODEL_FROM_DATABASE=CH340 serial converter E: ID_VENDOR=1a86 E: ID_VENDOR_ENC=1a86 E: ID_MODEL=USB2.0-Serial E: ID_MODEL_ENC=USB2.0-Serial E: ID_REVISION=0263 E: ID_SERIAL=1a86_USB2.0-Serial E: ID_TYPE=generic E: ID_USB_INTERFACES=:ff0102: E: ID_USB_INTERFACE_NUM=00 E: ID_USB_DRIVER=ch341 E: ID_USB_CLASS_FROM_DATABASE=Vendor Specific Class E: ID_PATH=pci-0000:00:14.0-usb-0:3:1.0 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_3_1_0 E: ID_MM_CANDIDATE=1 E: DEVLINKS=/dev/serial/by-path/pci-0000:00:14.0-usb-0:3:1.0-port0 /dev/ttyChinaArduino1 /dev/serial/by-id/usb-1a86_USB2.0-Serial-if00-port0 E: TAGS=:systemd: E: CURRENT_TAGS=:systemd:

~ udevadm info /dev/ttyUSB1 P: /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.5/2-1.5:1.0/ttyUSB1/tty/ttyUSB1 N: ttyUSB1 L: 0 S: serial/by-id/usb-1a86_USB2.0-Serial-if00-port0 S: ttyChinaArduino2 S: serial/by-path/pci-0000:00:1d.0-usb-0:1.5:1.0-port0 E: DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.5/2-1.5:1.0/ttyUSB1/tty/ttyUSB1 E: DEVNAME=/dev/ttyUSB1 E: MAJOR=188 E: MINOR=1 E: SUBSYSTEM=tty E: USEC_INITIALIZED=24912404225 E: ID_BUS=usb E: ID_VENDOR_ID=1a86 E: ID_MODEL_ID=7523 E: ID_PCI_CLASS_FROM_DATABASE=Serial bus controller E: ID_PCI_SUBCLASS_FROM_DATABASE=USB controller E: ID_PCI_INTERFACE_FROM_DATABASE=EHCI E: ID_VENDOR_FROM_DATABASE=QinHeng Electronics E: ID_MODEL_FROM_DATABASE=CH340 serial converter E: ID_VENDOR=1a86 E: ID_VENDOR_ENC=1a86 E: ID_MODEL=USB2.0-Serial E: ID_MODEL_ENC=USB2.0-Serial E: ID_REVISION=0254 E: ID_SERIAL=1a86_USB2.0-Serial E: ID_TYPE=generic E: ID_USB_INTERFACES=:ff0102: E: ID_USB_INTERFACE_NUM=00 E: ID_USB_DRIVER=ch341 E: ID_USB_CLASS_FROM_DATABASE=Vendor Specific Class E: ID_PATH=pci-0000:00:1d.0-usb-0:1.5:1.0 E: ID_PATH_TAG=pci-0000_00_1d_0-usb-0_1_5_1_0 E: ID_MM_CANDIDATE=1 E: DEVLINKS=/dev/serial/by-id/usb-1a86_USB2.0-Serial-if00-port0 /dev/ttyChinaArduino2 /dev/serial/by-path/pci-0000:00:1d.0-usb-0:1.5:1.0-port0 E: TAGS=:systemd: E: CURRENT_TAGS=:systemd:

Here you see two things. At first both have the same ID and second I've added an individual symlink: ttyChinaArduino1 and ttyChinaArduino2. And thats very important for me to distinguish between the two.

So long story short: I would prefer to add all those symlinks to an array. So for my setting it would look like this:

[{
  "comName": "/dev/ttyUSB0",
  "manufacturer": "1a86",
  "serialNumber": "1a86_USB2.0-Serial",
  "vendorId": "0x1a86",
  "productId": "0x7523",
  "symlinks": [
    "/dev/serial/by-id/usb-1a86_USB2.0-Serial-if00-port0",
    "/dev/serial/by-path/pci-0000:00:14.0-usb-0:3:1.0-port0",
    "/dev/ttyChinaArduino1"
  ]
},
{
  "comName": "/dev/ttyUSB1",
  "manufacturer": "1a86",
  "serialNumber": "1a86_USB2.0-Serial",
  "vendorId": "0x1a86",
  "productId": "0x7523",
  "symlinks": [
    "/dev/ttyChinaArduino2",
    "/dev/serial/by-path/pci-0000:00:1d.0-usb-0:1.5:1.0-port0",
    "/dev/serial/by-id/usb-1a86_USB2.0-Serial-if00-port0"
  ]
}]

And that's very easy in code, too:

  let symlinks;
  if (udevInfo.devlinks) {
    symlinks = udevInfo.devlinks.split(' ')
  }

coolchip avatar Dec 17 '21 14:12 coolchip

Annex: The duplicated Id is the result of a non-existent serial number on most China devices. This does not normally happen with devices from well-known manufacturers. But these China devices are very often used in the DIY universe (Arduino clones or ESPs with attached USB). https://arduino.stackexchange.com/a/31958

But regardless of that, it's still nice to be able to find the serial port based on the symlink given.

coolchip avatar Dec 17 '21 17:12 coolchip