Simple Way to Query Connected Usb Devices Info in Python

Simple way to query connected USB devices info in Python?

I can think of a quick code like this.

Since all USB ports can be accessed via /dev/bus/usb/< bus >/< device >

For the ID generated, even if you unplug the device and reattach it [ could be some other port ]. It will be the same.

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

Sample output here will be:

[
{'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'}
]

Code Updated for 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)

PyUSB: SCPI communication with OWON Oscilloscope

I guess there was no chance to answer this question unless somebody already went through the very same problems.
I'm sorry for all of you (@Alex P., @Turbo J, @igrinis, @2xB) who took your time to make suggestions to help.

My findings: (I hope they will be useful to others):

  1. Everything seems to be OK with PyUSB.
  2. the vendor has provided outdated and wrong documentation. I hope very much that they will soon update the documentation on their homepage.
  3. Sending the command :SDSLSCPI# is not necessary to enter SCPI-mode (but actually leads to a crash/restart)
  4. For example: :CHAN1:SCAL 10v is wrong, it has to be :CH1:SCALe 10v (commands apparenty can't be abbreviated, although mentioned in the documentation that :CH1:SCAL 10v should also work.)
  5. the essential command to get data :DATA:WAVE:SCREen:CH1? was missing in the manual.

The way it is working for me (so far):

The following would have been the minimal code I expected from the vendor/manufacturer. But instead I wasted a lot of time debugging their documentation.
However, still some strange things are going on, e.g. it seems you get data only if you ask for the header beforehand. But, well, this is not the topic of the original question.

Code:

### read data from a Peaktech 1337 Oscilloscope (OWON)
import usb.core
import usb.util

dev = usb.core.find(idVendor=0x5345, idProduct=0x1234)

if dev is None:
raise ValueError('Device not found')
else:
print(dev)
dev.set_configuration()

def send(cmd):
# address taken from results of print(dev): ENDPOINT 0x3: Bulk OUT
dev.write(3,cmd)
# address taken from results of print(dev): ENDPOINT 0x81: Bulk IN
result = (dev.read(0x81,100000,1000))
return result

def get_id():
return send('*IDN?').tobytes().decode('utf-8')

def get_data(ch):
# first 4 bytes indicate the number of data bytes following
rawdata = send(':DATA:WAVE:SCREen:CH{}?'.format(ch))
data = []
for idx in range(4,len(rawdata),2):
# take 2 bytes and convert them to signed integer using "little-endian"
point = int().from_bytes([rawdata[idx], rawdata[idx+1]],'little',signed=True)
data.append(point/4096) # data as 12 bit
return data

def get_header():
# first 4 bytes indicate the number of data bytes following
header = send(':DATA:WAVE:SCREen:HEAD?')
header = header[4:].tobytes().decode('utf-8')
return header

def save_data(ffname,data):
f = open(ffname,'w')
f.write('\n'.join(map(str, data)))
f.close()

print(get_id())
header = get_header()
data = get_data(1)
save_data('Osci.dat',data)
### end of code

Result: (using gnuplot)

Sample Image

Identifying serial/usb device python

No matter how you configure your device, at some point you're probably going to have to ask the user where the port is, or poll all serial devices for a known response. (Polling has it's pitfalls though, so read on!). Unlike USB devices, there is no vendor/device ID that is made known to the OS when you attach a plain-old serial device.

First you need to find the serial ports. Here's a question that might help: What is the cross-platform method of enumerating serial ports in Python (including virtual ports)?.

Once you have a list of serial ports, you could ask the user whether they know which one to use. If they do, problem solved!

If they don't, you could offer to poll ALL serial devices with some data that you know will yield a certain response from your device. Keep in mind though that if the user has other serial devices attached, your string of "hello" bytes might actually be the self-destruct sequence for some other device! Hence, you should warn the user that polling may interfere with other devices, and always prompt them before you do so.

Without knowing more about your code (eg. what comms framework, if any, you're using; are you doing this in the console or are you using a GUI toolkit, etc), it's impossible to say what the best way to code this might be. In the simplest case, you could just loop over all of your serial devices, send the greeting and check for a response. (You could also do this in parallel: loop once for the greeting, and loop again to check what's in the buffer. If you're going to get more fancy than that, use a proper library.)


Side note: You might be able to get around this if you have a built-in converter that you can set the vendor/device ID for, but the converter will still be automatically detected by any modern OS and enumerated as a serial port; you won't get to talk to it directly as a USB device. It could be possible to figure out which port goes with which ID, but I've never tried to do that. But this approach is useless if you're not the one who gets to pick the converter (eg. if it's a user-supplied cable).



Related Topics



Leave a reply



Submit