Liệt kê các cổng com có ​​sẵn bằng Python


81

Tôi đang tìm kiếm một phương pháp đơn giản để liệt kê tất cả các cổng com hiện có trên PC.

Tôi đã tìm thấy phương pháp này nhưng nó dành riêng cho Windows: Liệt kê các cổng nối tiếp (COM) trên Windows?

Tôi đang sử dụng Python 3 với pySerial trên PC chạy Windows 7.

Tôi đã tìm thấy trong API pySerial ( http://pyserial.sourceforge.net/pyserial_api.html ) một hàm serial.tools.list_ports.comports()liệt kê các cổng com (chính xác những gì tôi muốn).

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

Nhưng có vẻ như nó không hoạt động. Khi cổng kết nối USB tới COM của tôi được kết nối với PC (tôi thấy COM5 trong Trình quản lý thiết bị), cổng COM này không có trong danh sách được trả về list_ports.comports(). Thay vào đó, tôi chỉ nhận được COM4 dường như được kết nối với modem (tôi không thấy nó trong phần COM & LPT của Trình quản lý thiết bị)!

Bạn có biết tại sao nó không hoạt động? Bạn có một giải pháp khác không dành riêng cho hệ thống không?


19
Người đọc mới: lưu ý rằng đã hơn năm năm kể từ khi câu hỏi này được đặt ra và lỗi trong comports()chức năng của pySerial được mô tả trong câu hỏi này (không có thông tin chính xác về cách tạo lại nó) có thể đã được sửa. Bắt đầu bằng cách thử import serial.tools.list_ports; print([comport.device for comport in serial.tools.list_ports.comports()]). Chỉ khi điều đó không hiệu quả với bạn thì bất kỳ câu trả lời nào dưới đây mới phù hợp với bạn.
Mark Amery

Cũng đối với độc giả mới: dường như do những thay đổi trong pySerial, đoạn mã được OP mô tả (và một số câu trả lời) không còn tạo ra danh sách tên cổng COM, cho dù đầy đủ hay không đầy đủ. Thay vào đó, nó tạo ra một danh sách các tham chiếu đối tượng đến ListPortInfocác đối tượng. Để lấy tên hoặc thông tin khác, bạn phải sử dụng các thuộc tính của các đối tượng này khi xây dựng danh sách. Xem: pythonhosted.org/pyserial/…
JDM

Câu trả lời:


150

Đây là mã tôi sử dụng.

Đã thử nghiệm thành công trên Windows 8.1 x64, Windows 10 x64, Mac OS X 10.9.x / 10.10.x / 10.11.x và Ubuntu 14.04 / 14.10 / 15.04 / 15.10 với cả Python 2 và 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())

Tôi có thể thêm vào điều này một số phát hiện phiên bản hệ thống và gọi nó là một ngày. Tôi không biết "tất cả các hệ thống" đều bình đẳng trong đó các cổng được mua khác nhau tùy thuộc vào hệ điều hành của bạn. Tôi chỉ đơn giản là phát hiện phiên bản hệ điều hành, sau đó dựa trên đó có một công tắc có sẵn cho các trường hợp khác nhau.
jml

1
Tôi cũng phải thêm except OSError: passkhi thử nghiệm trên OSX.
nvahalik

3
Điều gì sẽ xảy ra nếu một cổng đã được mở? Nó sẽ trả về một lỗi phải không? Nhưng cổng sẽ vẫn có sẵn. Tôi chỉ tự hỏi làm cách nào để thực hiện giải mã kết nối cổng COM khả thi trên các cửa sổ bằng python.
Manny42

@ Manny42 Tôi không hiểu bạn đang cố gắng hoàn thành điều gì, nhưng nếu một cổng đã được mở thì chắc chắn nó không có sẵn cho các chương trình khác và sẽ không được liệt kê bởi serial_ports()hàm (và sẽ không đưa ra ngoại lệ). Tại sao bạn không sử dụng close()chức năng do pyserial cung cấp để ngắt kết nối cổng COM?
Thomas

@Thomas - là có một cách để có được một số mô tả về là tốt cổng tôi có nhu cầu để chọn cổng của sự lựa chọn của tôi dựa trên mô tả

24

Bạn có thể dùng:

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

Lọc theo cổng biết: python -c "import serial.tools.list_ports;print [port for port in serial.tools.list_ports.comports() if port[2] != 'n/a']"

Xem thêm thông tin tại đây: https://pyserial.readthedocs.org/en/latest/tools.html#module-serial.tools.list_ports


Điều này hoạt động tốt trên OSX 10.11.5 với python 2.7.11 và dường như nhanh hơn nhiều so với giải pháp từ Thomas. Trên OSX 10.11.5 với python 3.4.4, nó trả về một mảng trống, vì vậy chắc chắn nó thiếu một số cổng com.
doizuc

Hoạt động tốt với Windows7 và Python 2.7. Rất hữu ích, nó trả về một bộ giá trị như thế này: ('COM114', 'USB Serial Port (COM114)', 'FTDIBUS\\VID_0403+PID_6001+7&2A8DEF85&0&2\\0000')Cho phép bạn lọc theo PID / VID USB của Nhà cung cấp, chính xác là những gì tôi đang theo đuổi.
Richard Aplin

Vừa thử nghiệm trên bo mạch Linux (Debian, nhân 3.4), kết quả tốt như nhau, lần này bao gồm cả số sê-ri thiết bị USB ('/dev/ttyACM1', 'ttyACM1', 'USB VID:PID=0483:5752 SNR=8D7B179D5354')Giải pháp tuyệt vời. Cám ơn!
Richard Aplin

Có một câu trả lời rất giống nhau ở đây: stackoverflow.com/questions/24214643/…
Gladclef,

1
-1; OP đã đề cập serial.tools.list_ports.comports()và giải thích rằng nó không hoạt động chính xác trên nền tảng của người hỏi. Bạn không thêm thông tin nào không có trong câu hỏi.
Mark Amery

15

Về cơ bản đã đề cập đến vấn đề này trong tài liệu hướng dẫn 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))

Kết quả :

COM1: Cổng giao tiếp (COM1) [ACPI \ PNP0501 \ 1]

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


11

Một cải tiến khả thi cho câu trả lời xuất sắc của Thomas là có Linux và có thể cả OSX cũng cố gắng mở các cổng và chỉ trả lại những cổng có thể mở được. Điều này là do Linux, ít nhất, liệt kê một lượng cảng dưới dạng tệp trong / dev / không được kết nối với bất kỳ thứ gì. Nếu bạn đang chạy trong một thiết bị đầu cuối, / dev / tty là thiết bị đầu cuối mà bạn đang làm việc và việc mở và đóng nó có thể làm hỏng dòng lệnh của bạn, do đó, hình cầu được thiết kế để không làm điều đó. Mã:

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

Sửa đổi này đối với mã của Thomas chỉ được thử nghiệm trên Ubuntu 14.04.


8

sàng lọc về câu trả lời của 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))

Phần này liệt kê các cổng tồn tại trong phần cứng, bao gồm cả những cổng đang được sử dụng. Có rất nhiều thông tin khác tồn tại trong danh sách, theo tài liệu về công cụ pyserial


3
-1 vì ít nhất một vài lý do: việc ghi đè tên của các nội trang như thế này là không tốt listvà cấu trúc bốn câu lệnh của bạn connectedcó thể được viết ngắn gọn hơn đáng kể connected = [port.device for port in serial.tools.list_ports.comports()].
Mark Amery

5
đối với anh chàng đã dành 1/2 sự nghiệp trong lĩnh vực nhúng C, tôi không phải là người thích làm mọi thứ theo phong cách ở đây. Bạn chắc chắn có thể làm tất cả trên một dòng. Tôi đã sửa lại mật khẩu giả 'danh sách', không biết làm thế nào mà tôi lại bỏ lỡ thứ gì đó chói lọi như vậy. Chúc mừng.
grambo

3
@Mark Amery. Bạn có thực sự nghĩ rằng một lớp lót là một ý tưởng tốt cho một trang web hỏi đáp không?
cstrutton

@cstrutton Tôi không hiểu câu hỏi của bạn.
Mark Amery,

2
@Mark Avery. Một lớp lót che khuất các khái niệm chính đối với người dùng mới làm quen. Ví dụ, nếu bạn sử dụng khả năng hiểu danh sách để chứng minh một khái niệm đơn giản, một người mới làm quen có thể bị lạc trong việc hiểu danh sách và bỏ lỡ khái niệm cơ sở. Nếu hiểu danh sách là cách tốt nhất để làm điều đó, hãy hiển thị phiên bản dài tay trước, sau đó là cách rút ngắn nó. Bạn dạy quan điểm của mình và củng cố danh sách cùng một lúc.
cstrutton

6

giải pháp một dòng với gói pySerial.

python -m serial.tools.list_ports

Đây là câu trả lời dễ dàng nhất theo như tôi liên quan.
Dan Hoover

1

Vui lòng thử mã này:

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

trước hết, bạn cần nhập gói để giao tiếp cổng nối tiếp, vì vậy:

import serial

sau đó bạn tạo danh sách tất cả các cổng nối tiếp hiện có:

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

và sau đó, đi dọc toàn bộ danh sách, bạn có thể in ví dụ như tên cổng:

for port in ports :
    print(port.device)

Đây chỉ là một ví dụ về cách lấy danh sách các cổng và in tên của chúng, nhưng có một số tùy chọn khác mà bạn có thể thực hiện với dữ liệu này. Chỉ cần thử in các biến thể khác nhau sau

Hải cảng.


Tôi nghĩ rằng bạn cần phải làm serial.tools.list_ports nhập khẩu, hoặc ít nhất đó là những gì tôi cần phải làm trên phiên bản của tôi về sê-ri trên Python 3.7 với PySerial 3.4
Tom Myddeltyn

0

Một số tùy chọn có sẵn:

Gọi QueryDosDevice với NULL lpDeviceName để liệt kê tất cả các thiết bị DOS. Sau đó sử dụng CreateFile và GetCommConfig lần lượt với từng tên thiết bị để tìm xem đó có phải là cổng nối tiếp hay không.

Gọi SetupDiGetClassDevs với ClassGuid là GUID_DEVINTERFACE_COMPORT.

WMI cũng có sẵn cho các chương trình C / C ++ .

Có một số cuộc trò chuyện trên nhóm tin win32 và một dự án CodeProject .


3
-1; đây là một câu hỏi Python yêu cầu một giải pháp bất khả tri nền tảng và bạn đã trả lời bằng một câu trả lời dành riêng cho Windows và không đưa ra dấu hiệu về cách thực hiện bất kỳ điều này trong Python nói riêng. Đây có thể là một câu trả lời tuyệt vời cho một câu hỏi hơi khác, nhưng không đúng ở đây.
Mark Amery

0

thử mã này

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

nó trở lại

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

nếu bạn chỉ không đặt tên cổng cho COM1, ví dụ

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

nó trở lại

COM1
COM5

như trong trường hợp của tôi py 3,7 64bits


0

Chỉ hoạt động trên 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()
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.