Listado de puertos com disponibles con Python

81

Estoy buscando un método simple para enumerar todos los puertos com disponibles en una PC.

Encontré este método pero es específico de Windows: ¿ Lista de puertos serie (COM) en Windows?

Estoy usando Python 3 con pySerial en una PC con Windows 7.

Encontré en la API pySerial ( http://pyserial.sourceforge.net/pyserial_api.html ) una función serial.tools.list_ports.comports()que enumera los puertos com (exactamente lo que quiero).

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

Pero parece que no funciona. Cuando mi puerta de enlace USB a COM está conectada a la PC (veo el COM5 en el Administrador de dispositivos), este puerto COM no está incluido en la lista devuelta por list_ports.comports(). En cambio, solo obtengo COM4 que parece estar conectado a un módem (no lo veo en la sección COM y LPT del Administrador de dispositivos).

¿Sabes por qué no funciona? ¿Tiene otra solución que no sea específica del sistema?

condenar
fuente
19
Nuevos lectores: tenga en cuenta que han pasado más de cinco años desde que se hizo esta pregunta, y el error en la comports()función de pySerial que se describió en esta pregunta (sin información precisa sobre cómo reproducirlo) probablemente se haya solucionado. Empiece por intentarlo import serial.tools.list_ports; print([comport.device for comport in serial.tools.list_ports.comports()]). Solo si eso no funciona para usted, alguna de las siguientes respuestas es relevante para usted.
Mark Amery
También para los nuevos lectores: aparentemente debido a cambios en pySerial, el código descrito por el OP (y algunas de las respuestas) ya no produce una lista de nombres de puertos COM, ya sean completos o incompletos. En su lugar, genera una lista de referencias de ListPortInfoobjetos a objetos. Para obtener los nombres u otra información, debe utilizar los atributos de estos objetos al crear la lista. Ver: pythonhosted.org/pyserial/…
JDM

Respuestas:

150

Este es el código que utilizo.

Probado con éxito en Windows 8.1 x64, Windows 10 x64, Mac OS X 10.9.x / 10.10.x / 10.11.xy Ubuntu 14.04 / 14.10 / 15.04 / 15.10 con Python 2 y 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
fuente
Podría agregar a esto algo de detección de la versión del sistema y terminarlo. No tengo conocimiento de que "todos los sistemas" sean iguales en el sentido de que los puertos se adquieren de manera diferente según su sistema operativo. Simplemente detectaría la versión del sistema operativo, luego, en base a eso, tendría un interruptor disponible para los diversos casos.
jml
1
También tuve que agregar except OSError: passal probar en OSX.
nvahalik
3
¿Qué pasaría si un puerto ya está abierto? Devolvería un error, ¿verdad? Pero el puerto aún estaría disponible. Me pregunto cómo hacer una desconexión del puerto COM viable en Windows con Python.
Manny42
@ Manny42 No entiendo lo que está tratando de lograr, pero si un puerto ya está abierto, seguramente no está disponible para otros programas y no estaría en la lista de la serial_ports()función (y no generaría una excepción). ¿Por qué no utiliza la close()función proporcionada por pyserial para desconectar un puerto COM?
Thomas
@Thomas: ¿hay alguna manera de obtener una descripción del puerto también? Tengo la necesidad de elegir el puerto de mi elección según la descripción
24

Puedes usar:

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

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

Vea más información aquí: https://pyserial.readthedocs.org/en/latest/tools.html#module-serial.tools.list_ports

moylop260
fuente
Esto funciona muy bien en OSX 10.11.5 con python 2.7.11 y parece ser mucho más rápido que la solución de Thomas. En OSX 10.11.5 con python 3.4.4 devuelve una matriz vacía, por lo que definitivamente faltan algunos puertos com.
Doizuc
Funciona muy bien con Windows7 y Python 2.7. Muy útilmente, devuelve una tupla como esta: ('COM114', 'USB Serial Port (COM114)', 'FTDIBUS\\VID_0403+PID_6001+7&2A8DEF85&0&2\\0000')que le permite filtrar por proveedor USB PID / VID, que es exactamente lo que buscaba.
Richard Aplin
Acabo de probarlo en una placa Linux (Debian, kernel 3.4), resultados igualmente buenos, esta vez incluido el número de serie del dispositivo USB ('/dev/ttyACM1', 'ttyACM1', 'USB VID:PID=0483:5752 SNR=8D7B179D5354'). Gran solución. ¡Gracias!
Richard Aplin
Hay una respuesta muy similar aquí: stackoverflow.com/questions/24214643/…
Gladclef
1
-1; el OP ya mencionó serial.tools.list_ports.comports()y explicó que no funcionó correctamente en la plataforma del solicitante. No está agregando información que no esté en la pregunta.
Mark Amery
15

Básicamente mencioné esto en la documentación pyserial 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))

Resultado:

COM1: Puerto de comunicaciones (COM1) [ACPI \ PNP0501 \ 1]

COM7: Puerto USB MediaTek (COM7) [USB VID: PID = 0E8D: 0003 SER = 6 UBICACIÓN = 1-2.1]

Ozgur Oz
fuente
11

Un posible refinamiento a la excelente respuesta de Thomas es hacer que Linux y posiblemente OSX también intenten abrir puertos y devolver solo aquellos que podrían abrirse. Esto se debe a que Linux, al menos, enumera una gran cantidad de puertos como archivos en / dev / que no están conectados a nada. Si está ejecutando en una terminal, / dev / tty es la terminal en la que está trabajando y abrir y cerrar puede estropear su línea de comando, por lo que el glob está diseñado para no hacer eso. Código:

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

Esta modificación al código de Thomas se ha probado solo en Ubuntu 14.04.

Ngerf
fuente
8

refinamiento en la respuesta de 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))

Aquí se enumeran los puertos que existen en el hardware, incluidos los que están en uso. Existe mucha más información en la lista, según la documentación de las herramientas pyserial

grambo
fuente
3
-1 por al menos un par de razones: es una mala práctica anular los nombres de incorporados como list, y su construcción de cuatro instrucciones de connectedpodría escribirse de manera significativamente más sucinta como connected = [port.device for port in serial.tools.list_ports.comports()].
Mark Amery
5
para el tipo que ha pasado la mitad de su carrera en C incrustado, yo no soy de los que hacen todo el estilo aquí. Ciertamente puede hacerlo todo en una sola línea. He corregido el paso en falso de la 'lista', no estoy seguro de cómo me perdí algo tan evidente como eso. Salud.
grambo
3
@Mark Amery. ¿De verdad crees que las frases sencillas son una buena idea para un sitio de preguntas y respuestas?
cstrutton
@cstrutton No entiendo tu pregunta.
Mark Amery
2
@Mark Avery. Las frases sencillas oscurecen los conceptos clave de los usuarios novatos. Por ejemplo, si usa una lista de comprensión para demostrar un concepto simple, un principiante podría perderse en la lista de comprensión y perder el concepto básico. Si una lista de comprensión es la mejor manera de hacerlo, muestre primero la versión de mano larga y luego cómo acortarla. Enseñas tu punto y refuerzas la composición de la lista al mismo tiempo.
cstrutton
6

solución de una línea con el paquete pySerial.

python -m serial.tools.list_ports
Estoy aprendiendo...
fuente
Esta es la respuesta más fácil en lo que a mí respecta.
Dan Hoover
1

Por favor, pruebe este código:

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

En primer lugar, debe importar el paquete para la comunicación del puerto serie, por lo que:

import serial

luego crea la lista de todos los puertos serie disponibles actualmente:

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

y luego, recorriendo toda la lista, puede, por ejemplo, imprimir nombres de puertos:

for port in ports :
    print(port.device)

Este es solo un ejemplo de cómo obtener la lista de puertos e imprimir sus nombres, pero hay otras opciones que puede hacer con estos datos. Intente imprimir diferentes variantes después

Puerto.

Alexander Lyapin
fuente
Creo que debe importar serial.tools.list_ports, o al menos eso es lo que necesitaba hacer en mi versión de serial en Python 3.7 con PySerial 3.4
Tom Myddeltyn
0

Hay varias opciones disponibles:

Llame a QueryDosDevice con un lpDeviceName NULL para enumerar todos los dispositivos DOS. Luego use CreateFile y GetCommConfig con el nombre de cada dispositivo para averiguar si es un puerto serie.

Llame a SetupDiGetClassDevs con un ClassGuid de GUID_DEVINTERFACE_COMPORT.

WMI también está disponible para programas C / C ++ .

Hay un poco de conversación en el grupo de noticias de Win32 y una CodeProject, er, proyecto .

Matriz de cadera
fuente
3
-1; esta era una pregunta de Python que pedía una solución independiente de la plataforma, y ​​ha respondido con una respuesta que es específica de Windows y no da ninguna indicación de cómo hacer nada de esto en Python en particular. Esta podría ser una gran respuesta a una pregunta ligeramente diferente, pero está fuera de lugar aquí.
Mark Amery
0

prueba este código

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

vuelve

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

si no quiere el nombre del puerto, por ejemplo, COM1

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

vuelve

COM1
COM5

como en mi caso py 3.7 64bits

Ayoub Boulehfa
fuente
0

Funciona solo en 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
fuente