Auflistung der verfügbaren Com-Ports mit Python

81

Ich suche nach einer einfachen Methode, um alle verfügbaren COM-Ports auf einem PC aufzulisten.

Ich habe diese Methode gefunden, aber sie ist Windows-spezifisch: Auflisten von seriellen (COM) Ports unter Windows?

Ich verwende Python 3 mit pySerial auf einem Windows 7-PC.

Ich habe in der pySerial-API ( http://pyserial.sourceforge.net/pyserial_api.html ) eine Funktion gefunden serial.tools.list_ports.comports(), die COM-Ports auflistet (genau das, was ich will).

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

Aber es scheint, dass es nicht funktioniert. Wenn mein USB-zu-COM-Gateway mit dem PC verbunden ist (ich sehe den COM5 im Geräte-Manager), ist dieser COM-Anschluss nicht in der von zurückgegebenen Liste enthalten list_ports.comports(). Stattdessen bekomme ich nur COM4, ​​das an ein Modem angeschlossen zu sein scheint (ich sehe es nicht im COM & LPT-Bereich des Geräte-Managers)!

Weißt du warum es nicht funktioniert? Haben Sie eine andere Lösung, die nicht systemspezifisch ist?

Untergang
quelle
19
Neue Leser: Beachten Sie, dass diese Frage vor über fünf Jahren gestellt wurde und der comports()in dieser Frage beschriebene Fehler in der Funktion von pySerial (ohne genaue Informationen zur Reproduktion) wahrscheinlich behoben wurde. Versuchen Sie es zunächst import serial.tools.list_ports; print([comport.device for comport in serial.tools.list_ports.comports()]). Nur wenn dies für Sie nicht funktioniert, sind die folgenden Antworten für Sie relevant.
Mark Amery
Auch für neue Leser: Anscheinend aufgrund von Änderungen in pySerial erzeugt der vom OP beschriebene Code (und einige der Antworten) keine Liste von COM-Port-Namen mehr, ob vollständig oder unvollständig. Stattdessen wird eine Liste von Objektreferenzen auf ListPortInfoObjekte generiert . Um die Namen oder andere Informationen zu erhalten, müssen Sie beim Erstellen der Liste die Attribute dieser Objekte verwenden. Siehe: pythonhosted.org/pyserial/…
JDM

Antworten:

150

Dies ist der Code, den ich benutze.

Erfolgreich getestet unter Windows 8.1 x64, Windows 10 x64, Mac OS X 10.9.x / 10.10.x / 10.11.x und Ubuntu 14.04 / 14.10 / 15.04 / 15.10 mit Python 2 und 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())
Thomas
quelle
Ich könnte dazu eine Systemversionserkennung hinzufügen und es einen Tag nennen. Mir ist nicht bekannt, dass "alle Systeme" gleich sind, da die Ports je nach Betriebssystem unterschiedlich erfasst werden. Ich würde einfach die Betriebssystemversion erkennen und darauf basierend einen Schalter für die verschiedenen Fälle zur Verfügung haben.
jml
1
Ich musste auch except OSError: passbeim Testen unter OSX hinzufügen .
Nvahalik
3
Was würde passieren, wenn ein Port bereits geöffnet ist? Es würde einen Fehler zurückgeben, oder? Der Port wäre aber noch verfügbar. Ich frage mich nur, wie ich unter Windows mit Python eine funktionsfähige COM-Port-Dekonnektion herstellen kann.
Manny42
@ Manny42 Ich verstehe nicht, was Sie erreichen wollen, aber wenn ein Port bereits geöffnet ist, ist er sicherlich nicht für andere Programme verfügbar und würde von der serial_ports()Funktion nicht aufgelistet (und würde keine Ausnahme auslösen). Warum verwenden Sie nicht close()die von pyserial bereitgestellte Funktion, um einen COM-Port zu trennen?
Thomas
@ Thomas - gibt es eine Möglichkeit, auch eine Beschreibung des Ports zu erhalten? Ich muss den Port meiner Wahl basierend auf der Beschreibung
24

Sie können verwenden:

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

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

Weitere Informationen finden Sie hier: https://pyserial.readthedocs.org/en/latest/tools.html#module-serial.tools.list_ports

moylop260
quelle
Dies funktioniert unter OSX 10.11.5 mit Python 2.7.11 hervorragend und scheint viel schneller zu sein als die Lösung von Thomas. Unter OSX 10.11.5 mit Python 3.4.4 wird ein leeres Array zurückgegeben, sodass definitiv einige COM-Ports fehlen.
Doizuc
Funktioniert hervorragend mit Windows7 und Python 2.7. Sehr nützlich, es gibt ein Tupel wie das folgende zurück: Damit ('COM114', 'USB Serial Port (COM114)', 'FTDIBUS\\VID_0403+PID_6001+7&2A8DEF85&0&2\\0000')können Sie nach Vendor USB PID / VID filtern, was genau das ist, wonach ich gesucht habe.
Richard Aplin
Gerade auf einem Linux-Board (Debian, 3.4 Kernel) getestet, gleich gute Ergebnisse, diesmal inklusive der Seriennummer des USB-Geräts ('/dev/ttyACM1', 'ttyACM1', 'USB VID:PID=0483:5752 SNR=8D7B179D5354')Tolle Lösung. Danke!
Richard Aplin
Es gibt eine sehr ähnliche Antwort hier: stackoverflow.com/questions/24214643/…
Gladclef
1
-1; Das OP erwähnte serial.tools.list_ports.comports()und erklärte bereits , dass es auf der Plattform des Fragestellers nicht richtig funktionierte. Sie fügen keine Informationen hinzu, die nicht in Frage kamen.
Mark Amery
11

Eine mögliche Verfeinerung von Thomas 'hervorragender Antwort besteht darin, dass Linux und möglicherweise OSX auch versuchen, Ports zu öffnen und nur diejenigen zurückzugeben, die geöffnet werden könnten. Dies liegt daran, dass Linux zumindest eine Schiffsladung von Ports als Dateien in / dev / auflistet, die mit nichts verbunden sind. Wenn Sie in einem Terminal ausgeführt werden, ist / dev / tty das Terminal, in dem Sie arbeiten, und das Öffnen und Schließen kann Ihre Befehlszeile beschädigen. Daher ist der Glob so konzipiert, dass er dies nicht tut. 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

Diese Änderung an Thomas 'Code wurde nur unter Ubuntu 14.04 getestet.

Ngerf
quelle
8

Verfeinerung der Antwort von 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))

Hier werden die in der Hardware vorhandenen Ports aufgelistet, einschließlich der verwendeten. In der Liste sind in der Dokumentation zu den Pyserial-Tools viel mehr Informationen enthalten

Grambo
quelle
3
-1 aus mindestens ein paar Gründen: Es ist eine schlechte Praxis, die Namen von Builtins wie zu überschreiben list, und Ihre Konstruktion mit vier Anweisungen von connectedkönnte deutlich prägnanter geschrieben werden als connected = [port.device for port in serial.tools.list_ports.comports()].
Mark Amery
5
Für den Kerl, der eine halbe Karriere in Embedded C verbracht hat, bin ich nicht einer für die einzelne Linie, die hier alles stilvoll macht. Sie können sicherlich alles in einer Zeile erledigen. Ich habe die 'Liste' Fauxpas korrigiert und bin mir nicht sicher, wie ich so etwas Grelles verpasst habe. Prost.
Grambo
3
@ Mark Amery. Denken Sie wirklich, dass Einzeiler eine gute Idee für eine Frage- und Antwortseite sind?
Cstrutton
@cstrutton Ich verstehe deine Frage nicht.
Mark Amery
2
@ Mark Avery. Einzeiler verschleiern Schlüsselkonzepte von unerfahrenen Benutzern. Wenn Sie beispielsweise ein Listenverständnis verwenden, um ein einfaches Konzept zu demonstrieren, kann ein Anfänger im Listenverständnis verloren gehen und das Basiskonzept verfehlen. Wenn ein Listenverständnis der beste Weg ist, zeigen Sie zuerst die Langhandversion und dann, wie Sie sie kürzen können. Sie lehren Ihren Standpunkt und verstärken gleichzeitig die Liste comp.
Cstrutton
6

Einzeilige Lösung mit pySerial-Paket.

python -m serial.tools.list_ports
Ich lerne...
quelle
Dies ist für mich die einfachste Antwort.
Dan Hoover
1

Bitte versuchen Sie diesen Code:

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

Zunächst müssen Sie das Paket für die Kommunikation über die serielle Schnittstelle importieren.

import serial

Anschließend erstellen Sie eine Liste aller derzeit verfügbaren seriellen Schnittstellen:

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

Wenn Sie dann die gesamte Liste durchgehen, können Sie beispielsweise Portnamen drucken:

for port in ports :
    print(port.device)

Dies ist nur ein Beispiel, wie Sie die Liste der Ports abrufen und deren Namen drucken können. Es gibt jedoch einige andere Optionen, die Sie mit diesen Daten ausführen können. Versuchen Sie einfach, verschiedene Varianten danach zu drucken

Hafen.

Alexander Lyapin
quelle
Ich denke, Sie müssen serial.tools.list_ports importieren, oder zumindest war es das, was ich auf meiner Version von serial unter Python 3.7 mit PySerial 3.4
Tom Myddeltyn
0

Es stehen mehrere Optionen zur Verfügung:

Rufen Sie QueryDosDevice mit einem NULL-lpDeviceName auf, um alle DOS-Geräte aufzulisten. Verwenden Sie dann CreateFile und GetCommConfig mit jedem Gerätenamen, um herauszufinden, ob es sich um eine serielle Schnittstelle handelt.

Rufen Sie SetupDiGetClassDevs auf mit einer ClassGuid von GUID_DEVINTERFACE_COMPORT auf.

WMI ist auch für C / C ++ - Programme verfügbar .

Es gibt einige Gespräche in der Win32-Newsgroup und in einem CodeProject- Projekt .

Hip Hip Array
quelle
3
-1; Dies war eine Python-Frage, in der nach einer plattformunabhängigen Lösung gefragt wurde. Sie haben mit einer Windows-spezifischen Antwort geantwortet, die keinen Hinweis darauf gibt, wie dies in Python insbesondere zu tun ist. Dies könnte eine gute Antwort auf eine etwas andere Frage sein, ist aber hier fehl am Platz.
Mark Amery
0

Versuchen Sie diesen Code

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

es kehrt zurück

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

wenn Sie nur den Namen des Ports nicht kennen, zum Beispiel COM1

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

es kehrt zurück

COM1
COM5

wie in meinem Fall py 3.7 64bits

Ayoub Boulehfa
quelle
0

Funktioniert nur unter 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()
Ondřej Vacek
quelle