node-serialport
node-serialport copied to clipboard
List symlinks or by ID-path
- 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
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.
But using this node as a dependency in an application, it makes more sence to also list virtual/linked devices via node-serialport IMHO.
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.
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.
@reconbot please consider #1777 ... I still would really like to have this feature !!
What does symlinks provide? Why do you need them? I'm hesitant to add this since it's linux only.
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.
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
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 ;-)
I'm prepping for a major release so breaking changes are welcome. Sounds like by-id
is the most useful?
In my eyes yes (by-id)
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'} ]
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.
Sure will post tomorrow
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?
A local Proxmox host I assume? I’ll start with these.
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.
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.
Looks good, looking forward for it :-) I hope that all USB port cases also have a "by-id" ...
PS: It may break some UIs showing the values of the port list because now the strings are way longer :-)
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(' ')
}
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.