40

我们如何在 Python 中查询连接的 USB 设备信息?我想获取 UID 设备名称(例如:SonyEricsson W660)、设备路径(例如:/dev/ttyACM0)

还有什么是上述信息中的最佳参数,可在再次连接时用于识别设备?(UID?)

我正在开发 Ubuntu 11.04。

ATM 我有这个代码(使用 pyUSB)

busses = usb.busses()
for bus in busses:
  devices = bus.devices
  for dev in devices:
    print repr(dev)
    print "Device:", dev.filename
    print "  idVendor: %d (0x%04x)" % (dev.idVendor, dev.idVendor)
    print "  idProduct: %d (0x%04x)" % (dev.idProduct, dev.idProduct)
    print "Manufacturer:", dev.iManufacturer
    print "Serial:", dev.iSerialNumber
    print "Product:", dev.iProduct

问题是我没有得到想要的输出,将粘贴一个示例:

<usb.legacy.Device object at 0x1653990>
Device: 
  idVendor: 4046 (0x0fce)
  idProduct: 53411 (0xd0a3)
Manufacturer: 1
Serial: 3
Product: 2

首先我没有得到文件名,这对我来说最重要。我假设它是 /dev/ttyACM0 等部分。其次,我猜每个 USB 设备都有一些 UID,或者我应该同时使用 Vendor 或 Product id?

编辑:显然我有一些设置问题,我想我使用了错误的 USB 库。(使用 libusb0.1)ATM。这就是为什么我让 Device (dev.filename) 字符串为空。如果有人可以请告诉他在什么操作系统上使用什么USB库和什么版本的PyUSB,我认为它会解决我的问题。

4

6 回答 6

71

我可以想到这样的快速代码。

由于所有 USB 端口都可以通过 /dev/bus/usb/<bus>/<device> 访问

对于生成的 ID,即使您拔下设备并重新连接它[可能是其他端口]。它会是一样的。

import re
import subprocess
device_re = re.compile("Bus\s+(?P<bus>\d+)\s+Device\s+(?P<device>\d+).+ID\s(?P<id>\w+:\w+)\s(?P<tag>.+)$", re.I)
df = subprocess.check_output("lsusb")
devices = []
for i in df.split('\n'):
    if i:
        info = device_re.match(i)
        if info:
            dinfo = info.groupdict()
            dinfo['device'] = '/dev/bus/usb/%s/%s' % (dinfo.pop('bus'), dinfo.pop('device'))
            devices.append(dinfo)
print devices

这里的示例输出将是:

[
{'device': '/dev/bus/usb/001/009', 'tag': 'Apple, Inc. Optical USB Mouse [Mitsumi]', 'id': '05ac:0304'},
{'device': '/dev/bus/usb/001/001', 'tag': 'Linux Foundation 2.0 root hub', 'id': '1d6b:0002'},
{'device': '/dev/bus/usb/001/002', 'tag': 'Intel Corp. Integrated Rate Matching Hub', 'id': '8087:0020'},
{'device': '/dev/bus/usb/001/004', 'tag': 'Microdia ', 'id': '0c45:641d'}
]

针对 Python 3 更新的代码

import re
import subprocess
device_re = re.compile(b"Bus\s+(?P<bus>\d+)\s+Device\s+(?P<device>\d+).+ID\s(?P<id>\w+:\w+)\s(?P<tag>.+)$", re.I)
df = subprocess.check_output("lsusb")
devices = []
for i in df.split(b'\n'):
    if i:
        info = device_re.match(i)
        if info:
            dinfo = info.groupdict()
            dinfo['device'] = '/dev/bus/usb/%s/%s' % (dinfo.pop('bus'), dinfo.pop('device'))
            devices.append(dinfo)
            
print(devices)
于 2011-11-25T06:50:51.337 回答
42

如果您在 Windows 上工作,则可以使用pywin32(旧链接:请参阅下面的更新)。

我在这里找到了一个例子:

import win32com.client

wmi = win32com.client.GetObject ("winmgmts:")
for usb in wmi.InstancesOf ("Win32_USBHub"):
    print usb.DeviceID

2020 年 4 月更新:

218 及更高版本的“pywin32”发布版本可以github 上找到。当前版本 227。

于 2011-11-13T09:14:21.310 回答
5

对于旧版 USB 回归和 libusb-1.0 的系统,此方法将用于检索各种实际字符串。我以供应商和产品为例。它可能会导致一些 I/O,因为它实际上是从设备读取信息(至少是第一次,无论如何)。某些设备不提供此信息,因此在这种情况下假设它们会抛出异常;没关系,所以我们通过了。

import usb.core
import usb.backend.libusb1

busses = usb.busses()
for bus in busses:
    devices = bus.devices
    for dev in devices:
        if dev != None:
            try:
                xdev = usb.core.find(idVendor=dev.idVendor, idProduct=dev.idProduct)
                if xdev._manufacturer is None:
                    xdev._manufacturer = usb.util.get_string(xdev, xdev.iManufacturer)
                if xdev._product is None:
                    xdev._product = usb.util.get_string(xdev, xdev.iProduct)
                stx = '%6d %6d: '+str(xdev._manufacturer).strip()+' = '+str(xdev._product).strip()
                print stx % (dev.idVendor,dev.idProduct)
            except:
                pass
于 2014-11-03T23:35:00.670 回答
4

对于 linux,我编写了一个名为 find_port.py 的脚本,您可以在这里找到: https ://github.com/dhylands/usb-ser-mon/blob/master/usb_ser_mon/find_port.py

它使用 pyudev 枚举所有 tty 设备,并且可以匹配各种属性。

使用 --list 选项显示所有已知的 USB 串行端口及其属性。您可以按 VID、PID、序列号或供应商名称进行过滤。使用 --help 查看过滤选项。

find_port.py 打印 /dev/ttyXXX 名称而不是 /dev/usb/... 名称。

于 2015-05-27T14:52:10.177 回答
0

例如,当我运行您的代码时,我会得到以下输出。

<usb.Device object at 0xef38c0>
Device: 001
  idVendor: 7531 (0x1d6b)
  idProduct: 1 (0x0001)
Manufacturer: 3
Serial: 1
Product: 2

值得注意的是a)我有usb.Device对象而你有usb.legacy.Device对象,b)我有设备文件名。

每个usb.Bus都有一个dirname字段,每个usb.Device都有文件名。如您所见,文件名类似于001,目录名也是如此。您可以结合这些来获取总线文件。对于dirname=001and filname=001,它应该类似于 /dev/bus/usb/001/001。

您应该首先弄清楚这种“usb.legacy”情况是什么。我正在运行最新版本,我什至没有legacy子模块。

最后,您应该使用idVendoridProduct字段在插入设备时唯一标识设备。

于 2011-11-18T13:17:19.620 回答
-1

如果您只需要设备的名称,这里是我在 bash 中编写的一个小技巧。要在 python 中运行它,您需要以下代码段。只需将 $1 和 $2 替换为总线编号和设备编号,例如 001 或 002。

import os
os.system("lsusb | grep \"Bus $1 Device $2\" | sed 's/\// /' | awk '{for(i=7;i<=NF;++i)print $i}'")

或者,您可以将其保存为 bash 脚本并从那里运行它。只需将其保存为 bash 脚本,如 foo.sh 即可使其可执行。

#!/bin/bash
myvar=$(lsusb | grep "Bus $1 Device $2" | sed 's/\// /' | awk '{for(i=7;i<=NF;++i)print $i}')
echo $myvar

然后在python脚本中调用它

import os
os.system('foo.sh')
于 2011-11-14T09:11:04.183 回答