Lista dostępnych portów COM w Pythonie


86

Szukam prostej metody, aby wyświetlić listę wszystkich dostępnych portów COM na komputerze.

Znalazłem tę metodę, ale jest ona specyficzna dla systemu Windows: listy portów szeregowych (COM) w systemie Windows?

Używam Pythona 3 z pySerial na komputerze z systemem Windows 7.

Znalazłem w pySerial API ( http://pyserial.sourceforge.net/pyserial_api.html ) funkcję, serial.tools.list_ports.comports()która wyświetla listę portów com (dokładnie to, czego chcę).

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

Ale wydaje się, że to nie działa. Kiedy moja bramka USB-COM jest podłączona do komputera (widzę COM5 w Menedżerze urządzeń), ten port COM nie znajduje się na liście zwróconej przez list_ports.comports(). Zamiast tego dostaję tylko COM4, ​​który wydaje się być podłączony do modemu (nie widzę go w sekcji COM i LPT Menedżera urządzeń)!

Czy wiesz, dlaczego to nie działa? Czy masz inne rozwiązanie, które nie jest specyficzne dla systemu?


21
Nowi czytelnicy: zauważcie, comports()że minęło ponad pięć lat od zadania tego pytania, a błąd w funkcji pySerial, który został opisany w tym pytaniu (bez dokładnych informacji o tym, jak go odtworzyć) został prawdopodobnie naprawiony. Zacznij od spróbowania import serial.tools.list_ports; print([comport.device for comport in serial.tools.list_ports.comports()]). Tylko jeśli to nie zadziała, każda z poniższych odpowiedzi będzie dla Ciebie odpowiednia.
Mark Amery,

Również dla nowych czytelników: najwyraźniej z powodu zmian w pySerial kod opisany przez OP (i niektóre odpowiedzi) nie tworzy już listy nazw portów COM, kompletnych lub niekompletnych. Zamiast tego generuje listę odniesień do ListPortInfoobiektów. Aby uzyskać nazwy lub inne informacje, musisz użyć atrybutów tych obiektów podczas tworzenia listy. Zobacz: pythonhosted.org/pyserial/…
JDM

Odpowiedzi:


155

To jest kod, którego używam.

Pomyślnie przetestowano na Windows 8.1 x64, Windows 10 x64, Mac OS X 10.9.x / 10.10.x / 10.11.x i Ubuntu 14.04 / 14.10 / 15.04 / 15.10 zarówno z Pythonem 2, jak i Pythonem 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())

Mogę dodać do tego wykrywanie wersji systemu i nazwać to dniem. Nie jestem świadomy tego, że „wszystkie systemy” są równe, ponieważ porty są pozyskiwane w różny sposób w zależności od systemu operacyjnego. Po prostu wykryłbym wersję systemu operacyjnego, a następnie na podstawie tego miałbym dostępny przełącznik dla różnych przypadków.
jml

1
Musiałem też dodać except OSError: passpodczas testów na OSX.
nvahalik

4
Co by się stało, gdyby port był już otwarty? Zwróciłby błąd, prawda? Ale port byłby nadal dostępny. Zastanawiam się tylko, jak zrobić realne rozłączenie portu COM w systemie Windows z Pythonem.
Manny42

@ Manny42 Nie rozumiem, co próbujesz osiągnąć, ale jeśli port jest już otwarty, z pewnością nie jest dostępny dla innych programów i nie zostałby wymieniony przez serial_ports()funkcję (i nie zgłosiłby wyjątku). Dlaczego nie używasz close()funkcji dostarczonej przez pyserial do odłączania portu COM?
tfeldmann

@Thomas - czy jest sposób na uzyskanie opisu portu? Muszę wybrać port, który wybrałem na podstawie opisu

25

Możesz użyć:

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

Filtruj według znanego portu: python -c "import serial.tools.list_ports;print [port for port in serial.tools.list_ports.comports() if port[2] != 'n/a']"

Zobacz więcej informacji tutaj: https://pyserial.readthedocs.org/en/latest/tools.html#module-serial.tools.list_ports


Działa to świetnie na OSX 10.11.5 z Pythonem 2.7.11 i wydaje się być dużo szybsze niż rozwiązanie Thomasa. Na OSX 10.11.5 z pythonem 3.4.4 zwraca pustą tablicę, więc zdecydowanie brakuje niektórych portów com.
doizuc

Działa świetnie z Windows7 i Pythonem 2.7. Bardzo przydatne, zwraca krotkę taką jak ta: ('COM114', 'USB Serial Port (COM114)', 'FTDIBUS\\VID_0403+PID_6001+7&2A8DEF85&0&2\\0000')która pozwala filtrować według PID / VID USB dostawcy, co jest dokładnie tym, o co mi chodziło.
Richard Aplin

Właśnie przetestowany na płycie Linux (Debian, jądro 3.4), równie dobre wyniki, tym razem z numerem seryjnym urządzenia USB. ('/dev/ttyACM1', 'ttyACM1', 'USB VID:PID=0483:5752 SNR=8D7B179D5354')Świetne rozwiązanie. Dzięki!
Richard Aplin

Tutaj jest bardzo podobna odpowiedź: stackoverflow.com/questions/24214643/…
Gladclef

2
-1; OP już wspomniał serial.tools.list_ports.comports()i wyjaśnił, że nie działa poprawnie na platformie pytającego. Nie dodajesz żadnych informacji, których nie było w pytaniu.
Mark Amery,


11

Możliwe udoskonalenie doskonałej odpowiedzi Thomasa polega na tym, że Linux i prawdopodobnie OSX również próbują otwierać porty i zwracać tylko te, które można otworzyć. Dzieje się tak, ponieważ Linux przynajmniej wyświetla listę portów jako pliki w / dev /, które nie są do niczego podłączone. Jeśli korzystasz z terminala, / dev / tty jest terminalem, na którym pracujesz, a otwieranie i zamykanie może spowodować błąd w linii poleceń, więc glob został zaprojektowany tak, aby tego nie robić. Kod:

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

Ta modyfikacja kodu Thomasa została przetestowana tylko w systemie Ubuntu 14.04.


8

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

Zawiera listę portów, które istnieją w sprzęcie, w tym te, które są używane. O wiele więcej informacji znajduje się na liście, zgodnie z dokumentacją narzędzi


3
-1 z co najmniej kilku powodów: zła praktyka jest nadpisywanie nazw wbudowanych, takich jak list, a twoja cztero-wyrażeniowa konstrukcja connectedmoże być napisana znacznie bardziej zwięźle jako connected = [port.device for port in serial.tools.list_ports.comports()].
Mark Amery,

5
dla faceta, który spędził pół kariery w embedded C, nie jestem osobą, która chce zrobić wszystko tutaj w stylu. Z pewnością możesz to wszystko zrobić w jednej linii. Poprawiłem faux pas z „listy”, nie jestem pewien, dlaczego przegapiłem coś takiego. Twoje zdrowie.
grambo

3
@Mark Amery. Czy naprawdę uważasz, że jednolinijkowe teksty to dobry pomysł na witrynę z pytaniami i odpowiedziami?
cstrutton

@cstrutton Nie rozumiem twojego pytania.
Mark Amery,

2
@Mark Avery. Jednoliniowe treści przesłaniają kluczowe pojęcia początkującym użytkownikom. Na przykład, jeśli użyjesz rozumienia listowego, aby zademonstrować prostą koncepcję, nowicjusz może zgubić się w zrozumieniu listy i przegapić koncepcję podstawową. Jeśli najlepszym sposobem na zrobienie tego jest zrozumienie listy, pokaż najpierw długą wersję, a następnie, jak ją skrócić. Uczysz swojego punktu widzenia i jednocześnie wzmacniasz listę comp.
cstrutton

7

rozwiązanie jednoprzewodowe z pakietem pySerial.

python -m serial.tools.list_ports

Jeśli o mnie chodzi, to najłatwiejsza odpowiedź.
Dan Hoover

2

Spróbuj tego kodu:

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

przede wszystkim należy zaimportować pakiet do komunikacji przez port szeregowy, więc:

import serial

następnie tworzysz listę wszystkich aktualnie dostępnych portów szeregowych:

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

a następnie, przechodząc przez całą listę, możesz na przykład wydrukować nazwy portów:

for port in ports :
    print(port.device)

To jest tylko przykład, jak pobrać listę portów i wydrukować ich nazwy, ale jest kilka innych opcji, które możesz zrobić z tymi danymi. Po prostu spróbuj wydrukować różne warianty później

Port.


Myślę, że musisz zaimportować serial.tools.list_ports, a przynajmniej to właśnie musiałem zrobić w mojej wersji serialu w Pythonie 3.7 z PySerial 3.4
Tom Myddeltyn

0

Dostępnych jest kilka opcji:

Wywołaj QueryDosDevice z NULL lpDeviceName, aby wyświetlić listę wszystkich urządzeń DOS. Następnie użyj CreateFile i GetCommConfig dla każdej nazwy urządzenia, aby dowiedzieć się, czy jest to port szeregowy.

Wywołaj SetupDiGetClassDevs z ClassGuid o wartości GUID_DEVINTERFACE_COMPORT.

Usługa WMI jest również dostępna dla programów C / C ++ .

Trwa rozmowa na grupie dyskusyjnej win32 i projekcie CodeProject .


3
-1; to było pytanie w Pythonie z pytaniem o rozwiązanie niezależne od platformy, a Ty odpowiedziałeś odpowiedzią, która jest specyficzna dla systemu Windows i nie daje żadnej wskazówki, jak to zrobić w szczególności w Pythonie. To może być świetna odpowiedź na nieco inne pytanie, ale nie na miejscu.
Mark Amery,

0

wypróbuj ten kod

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

wraca

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

jeśli po prostu nie chcesz nazwy portu na przykład COM1

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

wraca

COM1
COM5

jak w moim przypadku py 3.7 64bits


0

Działa tylko w systemie 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()
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.