0

I wrote some Python code that drives a barcode scanner on the Pi 3 Model B.

It works fine when I execute "python3 barcode.py" from the terminal, but when I put this:

python3 barcode.py&

into /etc/rc.local it doesn't work.

The program does run - it beeps when it starts, and I hear the beep.

I think the problem is that the scanner acts like a keyboard - any barcode that's scanned comes out as if you'd typed it. The Python program reads the code like this:

upc_code = input("Enter UPC: ")

And so I suspect the Python program isn't seeing the output from the barcode scanner when it's started from /etc/rc.local. It's meant to run this on boot (the Pi will be running headless once I get this working).

One thing that indicates to me that the barcode data isn't getting to Python is that the barcode scanner still outputs to the terminal interactively.

How do I fix that? How to "route" the barcode data to the Python program started from /etc/rc.local, while still allowing the real USB keyboard to work normally? From what little I know of Linux, it's something to do with TTY devices...but that's all I know.

  • 1
    The problem is that you put an unlisted file - (which could contain anything) into /etc/rc.local which is an obsolete SysV init file - Raspbian uses systemd, and has for 4 years. – Milliways Apr 7 '18 at 3:23
  • Seems it is more a problem with output then input. Maybe your program does not know where to write the output? Have you tried to write the output into a file e.g. /tmp/debug.out? I also suggest to forget /etc/rc.local. It's only emulated by systemd.and never needed. You should make a clean service direct started by systemd. Then you have the possibility to setup the needed environment for your program. – Ingo Apr 7 '18 at 9:39
  • you are asking the wrong question .... your problem has nothing to do with a scanner .... it is about getting input from multiple keyboards .... google python multiple keyboards .... one hit is this one .... stackoverflow.com/questions/10209252/… – jsotola Apr 7 '18 at 19:02
1

I figured it out. It seems there is no simple way to read 'cooked' keyboard input from a particular HID device (in Linux, anyway - I suspect this all would be different in Windows).

However it's not too hard to read the particular keyboard at the low-level event handler, using the Python evdev package.

My barcode scanner turned out to be at /dev/input/event0.

Since I'm on Python3, I had to install evdev (it's not pre-installed on the Pi) per this:

https://stackoverflow.com/questions/10763440/how-to-install-python3-version-of-package-via-pip-on-ubuntu

Then, this is the code, very slightly modified from:

https://stackoverflow.com/questions/19732978/how-can-i-get-a-string-from-hid-device-in-python-with-evdev

#thanks to https://stackoverflow.com/questions/19732978/how-can-i-get-a-string-from-hid-device-in-python-with-evdev

from evdev import InputDevice, categorize, ecodes  

scancodes = {
    # Scancode: ASCIICode
    0: None, 1: u'ESC', 2: u'1', 3: u'2', 4: u'3', 5: u'4', 6: u'5', 7: u'6', 8: u'7', 9: u'8',
    10: u'9', 11: u'0', 12: u'-', 13: u'=', 14: u'BKSP', 15: u'TAB', 16: u'q', 17: u'w', 18: u'e', 19: u'r',
    20: u't', 21: u'y', 22: u'u', 23: u'i', 24: u'o', 25: u'p', 26: u'[', 27: u']', 28: u'CRLF', 29: u'LCTRL',
    30: u'a', 31: u's', 32: u'd', 33: u'f', 34: u'g', 35: u'h', 36: u'j', 37: u'k', 38: u'l', 39: u';',
    40: u'"', 41: u'`', 42: u'LSHFT', 43: u'\\', 44: u'z', 45: u'x', 46: u'c', 47: u'v', 48: u'b', 49: u'n',
    50: u'm', 51: u',', 52: u'.', 53: u'/', 54: u'RSHFT', 56: u'LALT', 57: u' ', 100: u'RALT'
}

capscodes = {
    0: None, 1: u'ESC', 2: u'!', 3: u'@', 4: u'#', 5: u'$', 6: u'%', 7: u'^', 8: u'&', 9: u'*',
    10: u'(', 11: u')', 12: u'_', 13: u'+', 14: u'BKSP', 15: u'TAB', 16: u'Q', 17: u'W', 18: u'E', 19: u'R',
    20: u'T', 21: u'Y', 22: u'U', 23: u'I', 24: u'O', 25: u'P', 26: u'{', 27: u'}', 28: u'CRLF', 29: u'LCTRL',
    30: u'A', 31: u'S', 32: u'D', 33: u'F', 34: u'G', 35: u'H', 36: u'J', 37: u'K', 38: u'L', 39: u':',
    40: u'\'', 41: u'~', 42: u'LSHFT', 43: u'|', 44: u'Z', 45: u'X', 46: u'C', 47: u'V', 48: u'B', 49: u'N',
    50: u'M', 51: u'<', 52: u'>', 53: u'?', 54: u'RSHFT', 56: u'LALT',  57: u' ', 100: u'RALT'
}

def readBarcode(devicePath):

    dev = InputDevice(devicePath)
    dev.grab() # grab provides exclusive access to the device

    x = ''
    caps = False

    for event in dev.read_loop():
        if event.type == ecodes.EV_KEY:
            data = categorize(event)  # Save the event temporarily to introspect it
            if data.scancode == 42:
                if data.keystate == 1:
                    caps = True
                if data.keystate == 0:
                    caps = False

            if data.keystate == 1:  # Down events only
                if caps:
                    key_lookup = u'{}'.format(capscodes.get(data.scancode)) or u'UNKNOWN:[{}]'.format(data.scancode)  # Lookup or return UNKNOWN:XX
                else:
                    key_lookup = u'{}'.format(scancodes.get(data.scancode)) or u'UNKNOWN:[{}]'.format(data.scancode)  # Lookup or return UNKNOWN:XX


                if (data.scancode != 42) and (data.scancode != 28):
                    x += key_lookup

                if(data.scancode == 28):
                    return(x)

Just do s = readBarcode("/dev/input/event0") and it returns the string from the scanner.

  • Your solution is fine, apart from one thing. The barcode scan is still going to the keyboard driver and thus, rendered as keypresses into the application which has the keyboard focus. You had to disable this particular device for X11 with xinput (or other, similar measures). – Janka Apr 7 '18 at 22:27
  • @Janka Thanks. Can you suggest how to disable the device? (FWIW, I haven't seen this problem - as I recall the input stopped going to stdin after the grab() call. But I'm not in front of the thing now and can't test.) – nerdfever.com Apr 9 '18 at 15:59
  • Ah, I forgot the EVIOCGRAB it issues. – Janka Apr 9 '18 at 16:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.