Listing available com ports with Python

PythonPyserial

Python Problem Overview


I am searching for a simple method to list all available com port on a PC.

I have found this method but it is Windows-specific: https://stackoverflow.com/questions/1205383/listing-serial-com-ports-on-windows

I am using Python 3 with pySerial on a Windows 7 PC.

I have found in the pySerial API (http://pyserial.sourceforge.net/pyserial_api.html) a function serial.tools.list_ports.comports() that lists com ports (exactly what I want).

import serial.tools.list_ports
print(list(serial.tools.list_ports.comports()))

But it seems that it doesn't work. When my USB to COM gateway is connected to the PC (I see the COM5 in the Device Manager), this COM port isn't included in the list returned by list_ports.comports(). Instead I only get COM4 which seems to be connected to a modem (I don't see it in the COM&LPT section of Device Manager)!

Do you know why it doesn't work? Have you got another solution which is not system specific?

Python Solutions


Solution 1 - Python

This is the code I use.

Successfully tested on Windows 8.1 x64, Windows 10 x64, Mac OS X 10.9.x / 10.10.x / 10.11.x and Ubuntu 14.04 / 14.10 / 15.04 / 15.10 with both Python 2 and Python 3.

import sys
import glob
import serial


def serial_ports():
    """ Lists serial port names

        :raises EnvironmentError:
            On unsupported or unknown platforms
        :returns:
            A list of the serial ports available on the system
    """
    if sys.platform.startswith('win'):
        ports = ['COM%s' % (i + 1) for i in range(256)]
    elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'):
        # this excludes your current terminal "/dev/tty"
        ports = glob.glob('/dev/tty[A-Za-z]*')
    elif sys.platform.startswith('darwin'):
        ports = glob.glob('/dev/tty.*')
    else:
        raise EnvironmentError('Unsupported platform')

    result = []
    for port in ports:
        try:
            s = serial.Serial(port)
            s.close()
            result.append(port)
        except (OSError, serial.SerialException):
            pass
    return result


if __name__ == '__main__':
    print(serial_ports())

Solution 2 - Python

Basically mentioned this in pyserial documentation https://pyserial.readthedocs.io/en/latest/tools.html#module-serial.tools.list_ports

import serial.tools.list_ports
ports = serial.tools.list_ports.comports()

for port, desc, hwid in sorted(ports):
        print("{}: {} [{}]".format(port, desc, hwid))

Result :

COM1: Communications Port (COM1) [ACPI\PNP0501\1]

COM7: MediaTek USB Port (COM7) [USB VID:PID=0E8D:0003 SER=6 LOCATION=1-2.1]

Solution 3 - Python

You can use:

python -c "import serial.tools.list_ports;print serial.tools.list_ports.comports()"

Filter by know port: python -c "import serial.tools.list_ports;print [port for port in serial.tools.list_ports.comports() if port[2] != 'n/a']"

See more info here: https://pyserial.readthedocs.org/en/latest/tools.html#module-serial.tools.list_ports

Solution 4 - Python

A possible refinement to Thomas's excellent answer is to have Linux and possibly OSX also try to open ports and return only those which could be opened. This is because Linux, at least, lists a boatload of ports as files in /dev/ which aren't connected to anything. If you're running in a terminal, /dev/tty is the terminal in which you're working and opening and closing it can goof up your command line, so the glob is designed to not do that. Code:

	# ... Windows code unchanged ...

    elif sys.platform.startswith ('linux'):
	    temp_list = glob.glob ('/dev/tty[A-Za-z]*')

	result = []
	for a_port in temp_list:

		try:
			s = serial.Serial(a_port)
			s.close()
			result.append(a_port)
		except serial.SerialException:
			pass

	return result

This modification to Thomas's code has been tested on Ubuntu 14.04 only.

Solution 5 - Python

one line solution with pySerial package.

python -m serial.tools.list_ports

Solution 6 - Python

refinement on https://stackoverflow.com/users/3753497/moylop260">moylop260</a>'s answer:

import serial.tools.list_ports
comlist = serial.tools.list_ports.comports()
connected = []
for element in comlist:
	connected.append(element.device)
print("Connected COM ports: " + str(connected))

This lists the ports that exist in hardware, including ones that are in use. A whole lot more information exists in the list, per https://pythonhosted.org/pyserial/tools.html">the pyserial tools documentation

Solution 7 - Python

Probably late, but might help someone in need.

import serial.tools.list_ports


class COMPorts:

    def __init__(self, data: list):
        self.data = data

    @classmethod
    def get_com_ports(cls):
        data = []
        ports = list(serial.tools.list_ports.comports())

        for port_ in ports:
            obj = Object(data=dict({"device": port_.device, "description": port_.description.split("(")[0].strip()}))
            data.append(obj)

        return cls(data=data)

    @staticmethod
    def get_description_by_device(device: str):
        for port_ in COMPorts.get_com_ports().data:
            if port_.device == device:
                return port_.description

    @staticmethod
    def get_device_by_description(description: str):
        for port_ in COMPorts.get_com_ports().data:
            if port_.description == description:
                return port_.device


class Object:
    def __init__(self, data: dict):
        self.data = data
        self.device = data.get("device")
        self.description = data.get("description")


if __name__ == "__main__":
    for port in COMPorts.get_com_ports().data:
        print(port.device)
        print(port.description)

    print(COMPorts.get_device_by_description(description="Arduino Leonardo"))
    print(COMPorts.get_description_by_device(device="COM3"))

Solution 8 - Python

Please, try this code:

import serial
ports = serial.tools.list_ports.comports(include_links=False)
for port in ports :
    print(port.device)

first of all, you need to import package for serial port communication, so:

import serial

then you create the list of all the serial ports currently available:

ports = serial.tools.list_ports.comports(include_links=False)

and then, walking along whole list, you can for example print port names:

for port in ports :
    print(port.device)

This is just an example how to get the list of ports and print their names, but there some other options you can do with this data. Just try print different variants after

> port.

Solution 9 - Python

try this code

import serial.tools.list_ports
for i in serial.tools.list_ports.comports():
    print(i) 

it returns

COM1 - Port de communication (COM1)
COM5 - USB-SERIAL CH340 (COM5)

if you just wont the name of the port for exemple COM1

import serial.tools.list_ports
for i in serial.tools.list_ports.comports():
    print(str(i).split(" ")[0])

it returns

COM1
COM5

as in my case py 3.7 64bits

Solution 10 - Python

Several options are available:

Call QueryDosDevice with a NULL lpDeviceName to list all DOS devices. Then use CreateFile and GetCommConfig with each device name in turn to figure out whether it's a serial port.

Call SetupDiGetClassDevs with a ClassGuid of GUID_DEVINTERFACE_COMPORT.

WMI is also available to C/C++ programs.

There's some conversation on the win32 newsgroup and a CodeProject, er, project.

Solution 11 - Python

Works only on Windows:

import winreg
import itertools

def serial_ports() -> list:
    path = 'HARDWARE\\DEVICEMAP\\SERIALCOMM'
    key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, path)

    ports = []
    for i in itertools.count():
        try:
            ports.append(winreg.EnumValue(key, i)[1])
        except EnvironmentError:
            break

    return ports

if __name__ == "__main__":
    ports = serial_ports()

Solution 12 - Python

something simple but I use it a lot.

import serial.tools.list_ports as ports

com_ports = list(ports.comports()) # create a list of com ['COM1','COM2'] 
    for i in com_ports:            
        print(i.device) # returns 'COMx'        

Solution 13 - Python

One thing to note, codes like this:

for i in serial.tools.list_ports.comports():
print(i) 

Return the following:

COM7 - Standard Serial over Bluetooth link (COM7) COM1 - Communications Port (COM1) COM8 - Standard Serial over Bluetooth link (COM8) COM4 - USB-SERIAL CH340 (COM4)

If you want the ports listed in order, and only the ones available to you, try:(credit to tfeldmann)

   def serial_ports():
    """ Lists serial port names

        :raises EnvironmentError:
            On unsupported or unknown platforms
        :returns:
            A list of the serial ports available on the system
    """
    if sys.platform.startswith('win'):
        ports = ['COM%s' % (i + 1) for i in range(256)]
    elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'):
        # this excludes your current terminal "/dev/tty"
        ports = glob.glob('/dev/tty[A-Za-z]*')
    elif sys.platform.startswith('darwin'):
        ports = glob.glob('/dev/tty.*')
    else:
        raise EnvironmentError('Unsupported platform')

    result = []
    for port in ports:
        try:
            s = serial.Serial(port)
            s.close()
            result.append(port)
        except (OSError, serial.SerialException):
            pass
    return result

This returns the following:

['COM1', 'COM4', 'COM8']

So unlike the first example, where the result was ['COM7', 'COM1', 'COM8', 'COM4'], this time I get all of the com ports in order, and only the ones available. Very handy if you need them in order, and tested to see if they're available.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiondoomView Question on Stackoverflow
Solution 1 - PythontfeldmannView Answer on Stackoverflow
Solution 2 - PythonOzgur OzView Answer on Stackoverflow
Solution 3 - Pythonmoylop260View Answer on Stackoverflow
Solution 4 - PythonNgerfView Answer on Stackoverflow
Solution 5 - PythonI am Learning...View Answer on Stackoverflow
Solution 6 - PythongramboView Answer on Stackoverflow
Solution 7 - PythonMalcolm WhoView Answer on Stackoverflow
Solution 8 - PythonAlexander LyapinView Answer on Stackoverflow
Solution 9 - PythonAyoub BoulehfaView Answer on Stackoverflow
Solution 10 - PythonHip Hip ArrayView Answer on Stackoverflow
Solution 11 - PythonOndřej VacekView Answer on Stackoverflow
Solution 12 - PythonAlberto StolowichView Answer on Stackoverflow
Solution 13 - PythonMichael WoodcockView Answer on Stackoverflow