使用Python列出可用的com端口


81

我正在寻找一种列出PC上所有可用com端口的简单方法。

我找到了这种方法,但是它是Windows特定的:在Windows上列出串行(COM)端口?

我在Windows 7 PC上使用带有pySerial的Python 3。

我在pySerial API(http://pyserial.sourceforge.net/pyserial_api.html)中找到了serial.tools.list_ports.comports()列出com端口(正是我想要的功能)的函数。

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

但似乎不起作用。当我的USB到COM网关连接到PC时(我在设备管理器中看到了COM5),该COM端口未包含在所返回的列表中list_ports.comports()。相反,我只能得到似乎已连接到调制解调器的COM4(我在“设备管理器”的“ COM&LPT”部分中没有看到它)!

您知道为什么它不起作用吗?您有不是系统特定的另一种解决方案吗?


19
新读者:请注意,距提出此问题已有五年多了,此问题中comports()描述的pySerial函数中的错误(没有有关如何重现该错误的精确信息)可能已得到修复。从尝试开始import serial.tools.list_ports; print([comport.device for comport in serial.tools.list_ports.comports()])。以下仅是与您相关的任何答案,除非这对您不起作用。
Mark Amery

对新读者来说:显然是由于pySerial的更改,由OP描述的代码(以及一些答案)不再产生完整或不完整的COM端口名称列表。相反,它将生成对对象的对象引用列表ListPortInfo。要获取名称或其他信息,必须在构建列表时使用这些对象的属性。请参阅: pythonhosted.org/pyserial/...
JDM

Answers:


150

这是我使用的代码。

使用Python 2和Python 3在Windows 8.1 x64,Windows 10 x64,Mac OS X 10.9.x / 10.10.x / 10.11.x和Ubuntu 14.04 / 14.10 / 15.04 / 15.10上成功测试。

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())

我可能会添加一些系统版本检测,并称之为一天。我不知道“所有系统”是相同的,因为根据您的操作系统,获取端口的方式有所不同。我只需要检测操作系统版本,然后基于该版本在各种情况下都可以使用。
jml

1
except OSError: pass在OSX上测试时,我还必须添加。
nvahalik 2014年

3
如果已经打开端口会发生什么?它会返回错误吧?但是该端口仍然可用。我只是想知道如何使用python在Windows上实现可行的COM端口断开连接。
Manny42

@ Manny42我不明白您要完成的工作,但是如果端口已经打开,则肯定对其他程序不可用,并且该serial_ports()功能也不会列出该端口(并且不会引发异常)。为什么不使用close()pyserial提供的功能来断开COM端口?
托马斯

@Thomas-是否有办法获得端口的描述?我需要根据描述选择我选择的端口

24

您可以使用:

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

按已知端口过滤: python -c "import serial.tools.list_ports;print [port for port in serial.tools.list_ports.comports() if port[2] != 'n/a']"

在此处查看更多信息:https : //pyserial.readthedocs.org/en/latest/tools.html#module-serial.tools.list_ports


这在使用python 2.7.11的OSX 10.11.5上效果很好,并且似乎比Thomas的解决方案要快得多。在使用python 3.4.4的OSX 10.11.5上,它返回一个空数组,因此肯定缺少一些com端口。
doizuc

与Windows7和Python 2.7完美兼容。它非常有用,它返回一个如下的元组:('COM114', 'USB Serial Port (COM114)', 'FTDIBUS\\VID_0403+PID_6001+7&2A8DEF85&0&2\\0000')它允许您按供应商USB PID / VID进行过滤,这正是我所追求的。
理查德·阿普林

刚刚在Linux板(Debian,3.4内核)上进行了测试,结果同样不错,这次包括了USB设备序列号('/dev/ttyACM1', 'ttyACM1', 'USB VID:PID=0483:5752 SNR=8D7B179D5354')。谢谢!
理查德·阿普林

这里有一个非常类似的答案:stackoverflow.com/questions/24214643/…–
Gladclef

1
-1; OP已经提到serial.tools.list_ports.comports()并解释说,它在asker的平台上无法正常工作。您没有添加没有问题的信息。
Mark Amery


11

对Thomas出色答案的一种可能的改进是让Linux和OSX也尝试打开端口并仅返回那些可以打开的端口。这是因为,至少Linux在/ dev /中将一堆端口列出为未连接任何文件的文件。如果您在终端中运行,则/ dev / tty是您要在其中运行的终端,打开和关闭该终端可以破坏命令行,因此glob旨在不这样做。码:

    # ... 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

仅在Ubuntu 14.04上测试了对Thomas代码的修改。


8

完善moylop260的答案:

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))

这列出了硬件中存在的端口,包括正在使用的端口。根据pyserial工具文档,列表中还有更多信息


3
-1至少有两个原因:覆盖诸如此类的内建名称是不正确的做法list,并且您的四语句构造connected可能更简洁地写为connected = [port.device for port in serial.tools.list_ports.comports()]
Mark Amery

5
对于在嵌入式C上花了1/2职业生涯的人来说,我不是一个人都可以在这里完成所有样式的工作。您当然可以在一行上完成所有操作。我已经更正了“列表”伪造的舞步,不确定我是如何错过类似这样的耀眼事物的。干杯。
grambo

3
@马克·阿默里(Mark Amery)。您真的认为单行代码是问答网站的好主意吗?
cstrutton

@cstrutton我不明白你的问题。
Mark Amery

2
@马克·艾弗里(Mark Avery)。单行代码模糊了新手用户的关键概念。例如,如果您使用列表理解来演示一个简单的概念,那么新手可能会迷失在列表理解中而错过基本概念。如果列表理解是最好的方法,请先显示长手版本,然后再将其缩短。您可以教导自己的观点并同时增强列表组合。
cstrutton


1

请尝试以下代码:

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

首先,您需要导入软件包以进行串行端口通信,因此:

import serial

然后创建当前可用的所有串行端口的列表:

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

然后遍历整个列表,例如可以打印端口名称:

for port in ports :
    print(port.device)

这只是一个如何获取端口列表并打印其名称的示例,但是您可以使用此数据进行其他一些选择。在之后尝试打印不同的变体

港口。


我认为您需要导入serial.tools.list_ports,或者至少这是我在使用PySerial 3.4的Python 3.7上的串行版本上需要执行的操作
Tom Myddeltyn

0

有几个选项:

用NULL lpDeviceName调用QueryDosDevice以列出所有DOS设备。然后依次对每个设备名称使用CreateFile和GetCommConfig来确定它是否是串行端口。

呼叫SetupDiGetClassDevs与GUID_DEVINTERFACE_COMPORT的ClassGuid。

WMI也可用于C / C ++程序

Win32新闻组和CodeProject er项目上有一些对话。


3
-1; 这是一个Python问题,要求平台无关的解决方案,并且您的回答是Windows特定的,并且没有给出如何在Python中进行任何特定操作的指示。对于一个稍有不同的问题,这可能是一个很好的答案,但是在这里不合适。
Mark Amery

0

试试这个代码

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

它返回

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

如果您只是不使用示例COM1的端口名称

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

它返回

COM1
COM5

例如我的py 3.7 64bits


0

仅适用于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()
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.