I am trying to find a way to iterate over all USB devices on a Raspberry Pi, and print out Vendor ID, Product ID, manufacturer name, and device node; via posts like:
- Simple way to query connected USB devices info in Python?
- Detect the state of a switch connected to USB with python
- Get USB device address through python
... I understood I could use PyUSB - but I'm having lots of trouble, similar to:
... which that post does not answer.
So here is my test case - I have this on the Raspberry Pi Raspbian Stretch:
pi@raspberry:~ $ apt-show-versions -r libusb
libusb-0.1-4:armhf/stretch 2:0.1.12-30 uptodate
libusb-1.0-0:armhf/stretch 2:1.0.21-1 uptodate
libusbmuxd4:armhf/stretch 1.0.10-3 uptodate
I installed PyUSB with:
sudo pip3 install pyusb
As an example, I've connected an Arduino UNO to the Raspberry Pi; tail -f /var/log/syslog
prints this upon USB connection:
...
Jun 23 09:35:01 raspberry kernel: [71431.582554] usb 1-1.2: new full-speed USB device number 7 using dwc_otg
Jun 23 09:35:01 raspberry kernel: [71431.726403] usb 1-1.2: New USB device found, idVendor=2341, idProduct=0043, bcdDevice= 0.01
Jun 23 09:35:01 raspberry kernel: [71431.726420] usb 1-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=220
Jun 23 09:35:01 raspberry kernel: [71431.726431] usb 1-1.2: Manufacturer: Arduino (www.arduino.cc)
Jun 23 09:35:01 raspberry kernel: [71431.726440] usb 1-1.2: SerialNumber: 64131383231351C03272
Jun 23 09:35:01 raspberry mtp-probe: checking bus 1, device 7: "/sys/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2"
Jun 23 09:35:01 raspberry mtp-probe: bus: 1, device: 7 was not an MTP device
Jun 23 09:35:01 raspberry kernel: [71431.778630] cdc_acm 1-1.2:1.0: ttyACM0: USB ACM device
Jun 23 09:35:01 raspberry kernel: [71431.779553] usbcore: registered new interface driver cdc_acm
Jun 23 09:35:01 raspberry kernel: [71431.779562] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters
...
So, I know that Vendor ID is 0x2341 (apparently, hex), Product ID is 0x0043 (apparently, hex), manufacturer name is Arduino (www.arduino.cc)
, and device node/file is /dev/ttyACM0
; and I simply want to print this out for all USB devices that are connected to the system via PyUSB.
Now, there is a bit of confusion online, since apparently, you can iterate over USB devices in PyUSB in two ways: the old "legacy" way, and the "new" way/API. So, I made a test script which tries them both, which I call test-usb.py
:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import usb.core
import usb.util
print("This is 'old' PyUSB style iteration - uses legacy:")
busses = usb.busses() # SO:8110310
for bus in busses:
print(type(bus)) # <class 'usb.legacy.Bus'>
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 = "USB VID: 0x{:04X} PID: 0x{:04X} Mfr name '{}' Product '{}'".format(dev.idVendor, dev.idProduct, str(xdev._manufacturer).strip(), str(xdev._product).strip(), dev.filename)
print( stx )
try:
print("xdev.filename: '{}'".format(xdev.filename))
except Exception as e:
print("xdev.filename exception: {}".format(e))
try:
print("dev.filename: '{}'".format(dev.filename))
except Exception as e:
print("dev.filename exception: {}".format(e))
except Exception as e:
print("Exception: {}".format(e))
print()
def print_internals(dev): # SO: 18224189
for attrib in dir(dev):
if not attrib.startswith('_') and not attrib == 'configurations':
try:
x=getattr(dev, attrib)
print( " ", attrib, x)
except Exception as e:
print("Exception for attrib '{}': {}".format(attrib, e))
try:
for config in dev.configurations:
for attrib in dir(config):
if not attrib.startswith('_'):
try:
x=getattr(config, attrib)
print( " ", attrib, x)
except Exception as e:
print("Exception for attrib '{}': {}".format(attrib, e))
except Exception as e:
print("Exception config in dev.configurations: {}".format(e))
print("This is 'new' PyUSB style iteration - does not use legacy:")
for xdev in usb.core.find(find_all=True): # SO:9577601
print(type(xdev)) # <class 'usb.core.Device'>
try:
if xdev._manufacturer is None:
xdev._manufacturer = usb.util.get_string(xdev, xdev.iManufacturer)
except Exception as e:
print("Exception: {}".format(e))
try:
if xdev._product is None:
xdev._product = usb.util.get_string(xdev, xdev.iProduct)
except Exception as e:
print("Exception: {}".format(e))
stx = "USB VID: 0x{:04X} PID: 0x{:04X} Mfr name '{}' Product '{}'".format(xdev.idVendor, xdev.idProduct, str(xdev._manufacturer).strip(), str(xdev._product).strip())
print( stx )
try:
print("xdev.filename: '{}'".format(xdev.filename))
except Exception as e:
print("xdev.filename exception: {}".format(e))
print_internals(xdev)
The above script outputs:
pi@raspberry:~ $ python3 test-usb.py
This is 'old' PyUSB style iteration - uses legacy:
<class 'usb.legacy.Bus'>
Exception: The device has no langid
USB VID: 0x0424 PID: 0x7800 Mfr name 'None' Product 'None'
xdev.filename exception: 'Device' object has no attribute 'filename'
dev.filename: ''
USB VID: 0x0424 PID: 0x2514 Mfr name 'None' Product 'None'
xdev.filename exception: 'Device' object has no attribute 'filename'
dev.filename: ''
USB VID: 0x0424 PID: 0x2514 Mfr name 'None' Product 'None'
xdev.filename exception: 'Device' object has no attribute 'filename'
dev.filename: ''
Exception: The device has no langid
This is 'new' PyUSB style iteration - does not use legacy:
<class 'usb.core.Device'>
Exception: The device has no langid
Exception: The device has no langid
USB VID: 0x2341 PID: 0x0043 Mfr name 'None' Product 'None'
xdev.filename exception: 'Device' object has no attribute 'filename'
address 7
attach_kernel_driver <bound method Device.attach_kernel_driver of <DEVICE ID 2341:0043 on Bus 001 Address 007>>
bDescriptorType 1
bDeviceClass 2
bDeviceProtocol 0
bDeviceSubClass 0
bLength 18
bMaxPacketSize0 8
bNumConfigurations 1
backend <usb.backend.libusb1._LibUSB object at 0x7680f510>
bcdDevice 1
bcdUSB 272
bus 1
clear_halt <bound method Device.clear_halt of <DEVICE ID 2341:0043 on Bus 001 Address 007>>
ctrl_transfer <bound method Device.ctrl_transfer of <DEVICE ID 2341:0043 on Bus 001 Address 007>>
default_timeout 1000
detach_kernel_driver <bound method Device.detach_kernel_driver of <DEVICE ID 2341:0043 on Bus 001 Address 007>>
finalize <bound method AutoFinalizedObject.finalize of <DEVICE ID 2341:0043 on Bus 001 Address 007>>
get_active_configuration <bound method Device.get_active_configuration of <DEVICE ID 2341:0043 on Bus 001 Address 007>>
iManufacturer 1
iProduct 2
iSerialNumber 220
idProduct 67
idVendor 9025
is_kernel_driver_active <bound method Device.is_kernel_driver_active of <DEVICE ID 2341:0043 on Bus 001 Address 007>>
langids ()
Exception for attrib 'manufacturer': The device has no langid
port_number 2
port_numbers (1, 2)
Exception for attrib 'product': The device has no langid
read <bound method Device.read of <DEVICE ID 2341:0043 on Bus 001 Address 007>>
reset <bound method Device.reset of <DEVICE ID 2341:0043 on Bus 001 Address 007>>
Exception for attrib 'serial_number': The device has no langid
set_configuration <bound method Device.set_configuration of <DEVICE ID 2341:0043 on Bus 001 Address 007>>
set_interface_altsetting <bound method Device.set_interface_altsetting of <DEVICE ID 2341:0043 on Bus 001 Address 007>>
speed 2
write <bound method Device.write of <DEVICE ID 2341:0043 on Bus 001 Address 007>>
Exception config in dev.configurations: 'method' object is not iterable
<class 'usb.core.Device'>
USB VID: 0x0424 PID: 0x7800 Mfr name 'None' Product 'None'
xdev.filename exception: 'Device' object has no attribute 'filename'
address 4
attach_kernel_driver <bound method Device.attach_kernel_driver of <DEVICE ID 0424:7800 on Bus 001 Address 004>>
bDescriptorType 1
bDeviceClass 255
bDeviceProtocol 255
bDeviceSubClass 0
bLength 18
bMaxPacketSize0 64
bNumConfigurations 1
backend <usb.backend.libusb1._LibUSB object at 0x7680f510>
bcdDevice 768
bcdUSB 528
bus 1
clear_halt <bound method Device.clear_halt of <DEVICE ID 0424:7800 on Bus 001 Address 004>>
ctrl_transfer <bound method Device.ctrl_transfer of <DEVICE ID 0424:7800 on Bus 001 Address 004>>
default_timeout 1000
detach_kernel_driver <bound method Device.detach_kernel_driver of <DEVICE ID 0424:7800 on Bus 001 Address 004>>
finalize <bound method AutoFinalizedObject.finalize of <DEVICE ID 0424:7800 on Bus 001 Address 004>>
get_active_configuration <bound method Device.get_active_configuration of <DEVICE ID 0424:7800 on Bus 001 Address 004>>
iManufacturer 0
iProduct 0
iSerialNumber 0
idProduct 30720
idVendor 1060
is_kernel_driver_active <bound method Device.is_kernel_driver_active of <DEVICE ID 0424:7800 on Bus 001 Address 004>>
langids ()
manufacturer None
port_number 1
port_numbers (1, 1, 1)
product None
read <bound method Device.read of <DEVICE ID 0424:7800 on Bus 001 Address 004>>
reset <bound method Device.reset of <DEVICE ID 0424:7800 on Bus 001 Address 004>>
serial_number None
set_configuration <bound method Device.set_configuration of <DEVICE ID 0424:7800 on Bus 001 Address 004>>
set_interface_altsetting <bound method Device.set_interface_altsetting of <DEVICE ID 0424:7800 on Bus 001 Address 004>>
speed 3
write <bound method Device.write of <DEVICE ID 0424:7800 on Bus 001 Address 004>>
Exception config in dev.configurations: 'method' object is not iterable
<class 'usb.core.Device'>
USB VID: 0x0424 PID: 0x2514 Mfr name 'None' Product 'None'
xdev.filename exception: 'Device' object has no attribute 'filename'
address 3
attach_kernel_driver <bound method Device.attach_kernel_driver of <DEVICE ID 0424:2514 on Bus 001 Address 003>>
bDescriptorType 1
bDeviceClass 9
bDeviceProtocol 2
bDeviceSubClass 0
bLength 18
bMaxPacketSize0 64
bNumConfigurations 1
backend <usb.backend.libusb1._LibUSB object at 0x7680f510>
bcdDevice 2995
bcdUSB 512
bus 1
clear_halt <bound method Device.clear_halt of <DEVICE ID 0424:2514 on Bus 001 Address 003>>
ctrl_transfer <bound method Device.ctrl_transfer of <DEVICE ID 0424:2514 on Bus 001 Address 003>>
default_timeout 1000
detach_kernel_driver <bound method Device.detach_kernel_driver of <DEVICE ID 0424:2514 on Bus 001 Address 003>>
finalize <bound method AutoFinalizedObject.finalize of <DEVICE ID 0424:2514 on Bus 001 Address 003>>
get_active_configuration <bound method Device.get_active_configuration of <DEVICE ID 0424:2514 on Bus 001 Address 003>>
iManufacturer 0
iProduct 0
iSerialNumber 0
idProduct 9492
idVendor 1060
is_kernel_driver_active <bound method Device.is_kernel_driver_active of <DEVICE ID 0424:2514 on Bus 001 Address 003>>
langids ()
manufacturer None
port_number 1
port_numbers (1, 1)
product None
read <bound method Device.read of <DEVICE ID 0424:2514 on Bus 001 Address 003>>
reset <bound method Device.reset of <DEVICE ID 0424:2514 on Bus 001 Address 003>>
serial_number None
set_configuration <bound method Device.set_configuration of <DEVICE ID 0424:2514 on Bus 001 Address 003>>
set_interface_altsetting <bound method Device.set_interface_altsetting of <DEVICE ID 0424:2514 on Bus 001 Address 003>>
speed 3
write <bound method Device.write of <DEVICE ID 0424:2514 on Bus 001 Address 003>>
Exception config in dev.configurations: 'method' object is not iterable
<class 'usb.core.Device'>
USB VID: 0x0424 PID: 0x2514 Mfr name 'None' Product 'None'
xdev.filename exception: 'Device' object has no attribute 'filename'
address 2
attach_kernel_driver <bound method Device.attach_kernel_driver of <DEVICE ID 0424:2514 on Bus 001 Address 002>>
bDescriptorType 1
bDeviceClass 9
bDeviceProtocol 2
bDeviceSubClass 0
bLength 18
bMaxPacketSize0 64
bNumConfigurations 1
backend <usb.backend.libusb1._LibUSB object at 0x7680f510>
bcdDevice 2995
bcdUSB 512
bus 1
clear_halt <bound method Device.clear_halt of <DEVICE ID 0424:2514 on Bus 001 Address 002>>
ctrl_transfer <bound method Device.ctrl_transfer of <DEVICE ID 0424:2514 on Bus 001 Address 002>>
default_timeout 1000
detach_kernel_driver <bound method Device.detach_kernel_driver of <DEVICE ID 0424:2514 on Bus 001 Address 002>>
finalize <bound method AutoFinalizedObject.finalize of <DEVICE ID 0424:2514 on Bus 001 Address 002>>
get_active_configuration <bound method Device.get_active_configuration of <DEVICE ID 0424:2514 on Bus 001 Address 002>>
iManufacturer 0
iProduct 0
iSerialNumber 0
idProduct 9492
idVendor 1060
is_kernel_driver_active <bound method Device.is_kernel_driver_active of <DEVICE ID 0424:2514 on Bus 001 Address 002>>
langids ()
manufacturer None
port_number 1
port_numbers (1,)
product None
read <bound method Device.read of <DEVICE ID 0424:2514 on Bus 001 Address 002>>
reset <bound method Device.reset of <DEVICE ID 0424:2514 on Bus 001 Address 002>>
serial_number None
set_configuration <bound method Device.set_configuration of <DEVICE ID 0424:2514 on Bus 001 Address 002>>
set_interface_altsetting <bound method Device.set_interface_altsetting of <DEVICE ID 0424:2514 on Bus 001 Address 002>>
speed 3
write <bound method Device.write of <DEVICE ID 0424:2514 on Bus 001 Address 002>>
Exception config in dev.configurations: 'method' object is not iterable
<class 'usb.core.Device'>
Exception: The device has no langid
Exception: The device has no langid
USB VID: 0x1D6B PID: 0x0002 Mfr name 'None' Product 'None'
xdev.filename exception: 'Device' object has no attribute 'filename'
address 1
attach_kernel_driver <bound method Device.attach_kernel_driver of <DEVICE ID 1d6b:0002 on Bus 001 Address 001>>
bDescriptorType 1
bDeviceClass 9
bDeviceProtocol 1
bDeviceSubClass 0
bLength 18
bMaxPacketSize0 64
bNumConfigurations 1
backend <usb.backend.libusb1._LibUSB object at 0x7680f510>
bcdDevice 1049
bcdUSB 512
bus 1
clear_halt <bound method Device.clear_halt of <DEVICE ID 1d6b:0002 on Bus 001 Address 001>>
ctrl_transfer <bound method Device.ctrl_transfer of <DEVICE ID 1d6b:0002 on Bus 001 Address 001>>
default_timeout 1000
detach_kernel_driver <bound method Device.detach_kernel_driver of <DEVICE ID 1d6b:0002 on Bus 001 Address 001>>
finalize <bound method AutoFinalizedObject.finalize of <DEVICE ID 1d6b:0002 on Bus 001 Address 001>>
get_active_configuration <bound method Device.get_active_configuration of <DEVICE ID 1d6b:0002 on Bus 001 Address 001>>
iManufacturer 3
iProduct 2
iSerialNumber 1
idProduct 2
idVendor 7531
is_kernel_driver_active <bound method Device.is_kernel_driver_active of <DEVICE ID 1d6b:0002 on Bus 001 Address 001>>
langids ()
Exception for attrib 'manufacturer': The device has no langid
port_number 0
port_numbers None
Exception for attrib 'product': The device has no langid
read <bound method Device.read of <DEVICE ID 1d6b:0002 on Bus 001 Address 001>>
reset <bound method Device.reset of <DEVICE ID 1d6b:0002 on Bus 001 Address 001>>
Exception for attrib 'serial_number': The device has no langid
set_configuration <bound method Device.set_configuration of <DEVICE ID 1d6b:0002 on Bus 001 Address 001>>
set_interface_altsetting <bound method Device.set_interface_altsetting of <DEVICE ID 1d6b:0002 on Bus 001 Address 001>>
speed 3
write <bound method Device.write of <DEVICE ID 1d6b:0002 on Bus 001 Address 001>>
Exception config in dev.configurations: 'method' object is not iterable
So, the only thing I could get to, is USB VID: 0x2341 PID: 0x0043; the exception The device has no langid
prevents retrieval of manufacturer and product name (and there are a ton of other exceptions, too)
And no one knows where the device node/path is: apparently, there used to be a dev.filename
in the "legacy" mode, which maybe at a certain point in the past, maybe did contain the device node/file /dev/ttyACM0
- but now seemingly does not anymore, as it is empty; and I couldn't find a mention of where that information resides in the "new" API (if it's there).
So - how can I iterate over all USB devices in Python 3 in Linux, and print out Vendor ID, Product ID, manufacturer name, and device node filename? If this is not possible with PyUSB - what other options do I have in terms of Python libraries (I'd like to avoid parsing /var/log/syslog
or /dev/bus
manually)?