0
votes

I'm working on a project that will read a QR code. I purchased a small USB barcode QR code scanner and I connected it to my system and I can scan a QR code and it will send it to my application I'm writing, but I have to know the /dev/ device/port name because each time it is disconnected and reconnected it can change which /dev/ device/port name it is assigned.

I have tried using pyusb, but all it returns is device info. I do not see any details as to which /dev/ it is represented as.

using PySerial:

import serial
from serial.tools import list_ports

for port in serial.tools.list_ports.comports():
    if port.vid is not None and port.pid is not None:
        # It's a USB port on a platform that supports the extended info
        # Do something with it.
        print("Port={},VID={:#06x},PID={:#06x}".format(port.device, port.vid, port.pid))

but this does not see the barcode reader connected to /dev/ttys002, which is strange since PyUSB can see it. In fact, it only sees two other devices (bluetooth incoming port and my wireless airpods), but it doesn't print those because port.vid and port.pid is 'none' for both.

using PyUSB:

import usb
import usb.backend.libusb1 as libusb1
import libusb1 as libusb

# find our device
dev = usb.core.find(idVendor=0xad93, idProduct=0x4002, backend=libusb1.get_backend())

print (dev)

output:

DEVICE ID ad93:4002 on Bus 020 Address 038 =================
 bLength                :   0x12 (18 bytes)
 bDescriptorType        :    0x1 Device
 bcdUSB                 :  0x110 USB 1.1
 bDeviceClass           :    0x0 Specified at interface
 bDeviceSubClass        :    0x0
 bDeviceProtocol        :    0x0
 bMaxPacketSize0        :   0x40 (64 bytes)
 idVendor               : 0xad93
 idProduct              : 0x4002
 bcdDevice              :  0x100 Device 1.0
 iManufacturer          :    0x1 YK
 iProduct               :    0x2 YK-2D PRODUCT HID KBW
 iSerialNumber          :    0x3 APP-000000000
 bNumConfigurations     :    0x1
  CONFIGURATION 1: 200 mA ==================================
   bLength              :    0x9 (9 bytes)
   bDescriptorType      :    0x2 Configuration
   wTotalLength         :   0x22 (34 bytes)
   bNumInterfaces       :    0x1
   bConfigurationValue  :    0x1
   iConfiguration       :    0x0 
   bmAttributes         :   0x80 Bus Powered
   bMaxPower            :   0x64 (200 mA)
    INTERFACE 0: Human Interface Device ====================
     bLength            :    0x9 (9 bytes)
     bDescriptorType    :    0x4 Interface
     bInterfaceNumber   :    0x0
     bAlternateSetting  :    0x0
     bNumEndpoints      :    0x1
     bInterfaceClass    :    0x3 Human Interface Device
     bInterfaceSubClass :    0x1
     bInterfaceProtocol :    0x1
     iInterface         :    0x0 
      ENDPOINT 0x81: Interrupt IN ==========================
       bLength          :    0x7 (7 bytes)
       bDescriptorType  :    0x5 Endpoint
       bEndpointAddress :   0x81 IN
       bmAttributes     :    0x3 Interrupt
       wMaxPacketSize   :    0x8 (8 bytes)
       bInterval        :    0x1

All I want to do is pass the vendor ID and device ID to a function and have it return the /dev/tty port it is connected to so I can set up a thread to read/capture a QR code when one is scanned.

I've been trying to solve this for two days now and I don't have much hair left to pull out!

Oh, and I am using Mac OS Mojave 10.14.6 with Python 3.7.4.

EDIT:

I am able to read the QR code using this code.

f=open("/dev/ttys002")
print (f.read())

Second UPDATE: I found out the barcode scanner is representing itself as an HID device (keyboard). I look into the pyhid and libusb/hdiapi and I am able to get that to find the device, but I do not know how to read it in python. Here's the code I'm using:

import hid

# get list of HID devices connected to this computer
h=hid.enumerate()
print ("HID info=", h,"\n")

# get path of first item
item=0
path=h[item]['path']
vid=h[item]['vendor_id']
pid=h[item]['product_id']

print ("Path=%s Vid=%s Pid=%s" % (path, vid, pid) + "/n")

# open the device
try:

    # using path works on raw, not non-raw
    #    d=hid.Device(path=path)
    #    print "Opened device=", path

    d=hid.Device(vid=vid, pid=pid)
    print ("Opened device=", vid, pid, "\n")

    # -- TBD
    #r=d.get_feature_report(1, 1024)
    #print "Report=", r

    # loop rading the keyboard....
    done=0
    while(done==0):
        r=d.read(10)
        for c in r:
            x=ord(c)
            print ("read=",x,"\n")

except Exception as e:
    print ("Exception, e=", e)

print ("Done!")

I'm also adding the macos and hid tags to this if I can so maybe someone else who can help will see this.

1
I think your reader is presenting itself as a keyboard. This is fairly common for readers. If so, then it will be in /dev/input. To find it you might be able to use subprocess and lsusb or dmesg. It's not clear to me if knowing the device helps much. I think you have to figure out how to listen for keypresses. Check out this answer to get started. Good luck.bfris
please see my editSouthernYankee65

1 Answers

0
votes

If your device is /dev/ttys002, maybe it will show up in PySerial

import serial.tools.list_ports

for LPI in serial.tools.list_ports.comports():
    print()
    print('device: %s' % LPI.device)
    print('name: %s' % LPI.name)
    print('description: %s' % LPI.description)
    print('hwid: %s' % LPI.hwid)
    print('vid: %s' % LPI.vid)
    print('pid: %s' % LPI.pid)
    print('serial_number: %s' % LPI.serial_number)
    print('location: %s' % LPI.location)
    print('manufacturer: %s' % LPI.manufacturer)
    print('product: %s' % LPI.product)
    print('interface: %s' % LPI.interface)