Pregunta

I want to use pySerial's serial.tools.list_ports.comports() to list available COM ports.

Reading the documentation:

The function returns an iterable that yields tuples of three strings:

  • port name as it can be passed to serial.Serial or serial.serial_for_url()
  • description in human readable form
  • sort of hardware ID. E.g. may contain VID:PID of USB-serial adapters.

I'm particulary interested in the third string to search for a specific USB-serial adapter with a VID:PID pair. I would like it (ideally) to work in Windows XP and later, Mac OS X, and Linux. I've tried with pySerial 2.7 in Ubuntu 13.10 and Windows 7 and works like a charm, but the docs also say:

Also note that the reported strings are different across platforms and operating systems, even for the same device.

Note: Support is limited to a number of operating systems. On some systems description and hardware ID will not be available.

Do you have any real-world experience with respect these ambiguities? More detailed info? Any non-working example? Variations on the hardware ID strings across systems?

Thanks a lot!

¿Fue útil?

Solución 2

It's been some time since my original question, but current versions of pyserial (3.0+, I believe) have solved this in a neat way. No more clever parsing.

serial.tools.list_ports.comports(...) now returns a list containing ListPortInfo objects.

ListPortInfo objects contain vid and pid attributes (integer) as well as other useful USB-related attributes (see docs) which "are all None if it is not an USB device (or the platform does not support extended info)" and this seems to be supported on the main 3 platforms ("Under Linux, OSX and Windows, extended information will be available for USB devices").

So you can do something like the following:

for port in serial.tools.list_ports.comports():
    if port.vid is not None and port.pid is not None:
        # It's a USB port on a platform that supports the extended info
        # Do something with it.
        print("Port={},VID={:#06x},PID={:#06x}".format(port.device, port.vid, port.pid))

Otros consejos

I guess if you want a counter-example of it working not as expected, here's what I get:

>>> serial.tools.list_ports.comports()
[('/dev/tty.Bluetooth-Incoming-Port', '/dev/tty.Bluetooth-Incoming-Port', '/dev/tty.Bluetooth-Incoming-Port'), ('/dev/tty.Bluetooth-Modem', '/dev/tty.Bluetooth-Modem', '/dev/tty.Bluetooth-Modem'), ('/dev/tty.usbserial-A1024XBO', '/dev/tty.usbserial-A1024XBO', '/dev/tty.usbserial-A1024XBO')]

where a FTDI USB-Serial adapter is plugged in. Which is expectable, because here's the comports() function:

def comports():
    """scan for available ports. return a list of device names."""
    devices = glob.glob('/dev/tty.*')
    return [(d, d, d) for d in devices]

which is the same for cygwin, BSD, NetBSD, IRIX, HP-UX, Solaris/SunOS, AIX…

How come that result can happen? Well, because my pyserial is version 2.6, which is only six months old :-)

After upgrading to latest version (2.7) from pypi, here's what I get:

>>> serial.tools.list_ports.comports()
[['/dev/cu.Bluetooth-Incoming-Port', 'n/a', 'n/a'], ['/dev/cu.Bluetooth-Modem', 'n/a', 'n/a'], ['/dev/cu.usbserial-A1024XBO', 'FT232R USB UART', 'USB VID:PID=403:6001 SNR=A1024XBO']]

so basically, add a version check to the latest version of pyserial in your setup.py, or you may get problems. Though support is still not added for other unix flavors. It looks like the VID:PID string is handled directly by parsing OS specific stuff to make that string generic enough. So basically I guess you can safely get it with something like : vid, pid = sp[2].split(' ')[1].split('=')[-1].split(':') (which is quite stupid, why parse values to build a string that has to be parsed again afterwards?!, I mean they do szHardwareID_str = 'USB VID:PID=%s:%s SNR=%s' % (m.group(1), m.group(2), m.group(4)) we couldn't be happier with just a tuple!)

And finally, pyserial looks inconsistent with its documentation, as it says: On some systems description and hardware ID will not be available (None)., whereas it does really return 'n/a'. I guess that will be fixed in pyserial 2.8 :-)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top