Python hidapi, why can't read my keyboard via usb? - python

I am trying to read the data input from my keyboard in python hidapi, and print it to the console.
(This is the keyboard I am currently using, but I would like to read the USB with a python code too)
I can't get it to work.
At data = device.read(64)
line I always getting a read error.
I was trying different alternatives with the help of chatGPT, start visual studio code as administrator, plug out-in the keyboard, but nothing helps.
Here is my code:
import hid
# Enumerate all connected HID devices
devices = hid.enumerate(0, 0)
for device in devices:
print("Device:", device)
# Open a specific HID device
device = hid.device()
device.open(3690, 704)
# Read data from the device
data = device.read(64)
# Print the data
print("Data:", data)
# Close the device
device.close()
Here are the datas of my keyboard:
Device: {'path': b'\\?\HID#VID_0E6A&PID_02C0&MI_01&Col05#7&28db5c83&0&0004#{4d1e55b2-f16f-11cf-88cb-001111000030}\KBD', 'vendor_id': 3690, 'product_id': 704, 'serial_number': '', 'release_number':
22529, 'manufacturer_string': 'dakai', 'product_string': 'PS/2+USB Keyboard', 'usage_page': 1, 'usage': 6, 'interface_number': 1}
Here is the failure message:
Thanks for your help!

Related

How to use Python win32print to change Printer trays

I am using Windows 10 and MS PCL6 Class Driver on a SHARP MX-M654N printer. I can successfully print a PDF file to the printer but I need to print every third page of the PDF to a different tray (different paper color).
The following code returns pywintypes.error: (5, 'OpenPrinter', 'Access is denied.') I have also tried ADMINISTER in place of PRINTER_ALL_ACCESS with the same result.
# PRINTER_DEFAULTS = {"DesiredAccess":win32print.PRINTER_ALL_ACCESS}
# pHandle = win32print.OpenPrinter(printer_name, PRINTER_DEFAULTS)
I have also tried the following without using the above but command is ignored
# win32print.SetJob(ph, hJob, 0, None, tray1_name)

How to print the barcode using Epson

I want to print a barcode using epson printer in python i didn't get any error but i got the output is another format not in barcode can any one please help me
from escpos import printer
Epson = printer.Usb(0x154f,0x154f,0,0x81,0x02)
Epson.barcode('1324354657687', 'EAN13', 64, 2, '', '')
Epson.cut()

Is there a way for the python package psutil to detect unmounted devices on Debian/Ubuntu and OSX

I am writing a python script that uses the psutil package to detect when a USB device is plugged into a computer. However, I would like to also detect if the device is plugged in but not mounted.
I was reading the documentation and assumed that something like current_state = psutil.disk_partitions(all=True) would do something like this however on further inspection it doesn't seem to.
Is there another way to get psutil to detect unmounted devices? Failing that is there a system agnostic way/package to detect if a device is plugged in but is not mounted?
Listing unmounted block devices is OS-dependent: The mechanism for doing so is not common between MacOS and Linux, and presently, the psutil library does not implement an abstraction layer over those differentes.
Listing All Block Devices On Linux
The following iterator will yield a list of block devices on Linux, excluding those which have partitions (for which you presumably only want to check whether the partitions themselves are mounted), such that the result can be compared against the list of devices attached to mount points:
import glob
def linux_block_devices():
for blockdev_stat in glob.glob('/sys/block/*/stat'):
blockdev_dir = blockdev_stat.rsplit('/', 1)[0]
found_parts = False
for part_stat in glob.glob(blockdev_dir + '/*/stat'):
yield blockdev_stat.rsplit('/', 2)[-2]
found_parts = True
if not found_parts:
yield blockdev_dir.rsplit('/', 1)[-1]
Listing All Block Devices On MacOS
On MacOS, I'm unaware of an interface intended for programmatic use exposed to Python -- you might end up parsing command-line output, as the following:
import subprocess, re
def mac_block_devices():
output = subprocess.check_output(['diskutil', 'list'])
return re.findall('^\s+\d+:.*\s(disk\S*)$', output, flags=re.MULTILINE)
...this one is cruder, inasmuch as it doesn't exclude devices that have children; consider that an exercise for the reader.
Combining Either Of The Above With psutil
import os, psutil
all_block_devices = set(
linux_block_devices() if os.path.exists('/sys') else mac_block_devices()
)
used_block_devices = set(
(p.device.replace('/dev/', '') for p in psutil.disk_partitions())
)
unused_block_devices = all_block_devices - used_block_devices
The above will give you a list of unused block devices on either OS -- akin to set(['sdb1', 'sdc1']) on Linux, or set(['disk3', 'disk4s1']) on MacOS.
Note that this is "unused" in the sense of "not used in the mount table". There are several other ways a block device can be used without being present in the mount table (direct raw access by application code; swap partition use; presence in device-mapper or backing for logical-volume mechanisms; etc), and detecting all these would require a great deal of wiring for either OS.
I have recently solved this problem on OSX and potentially on *nix as well (pending further testing) using hidapi. An example of how I used it is included below:
import hid
import pprint
hid_state = hid.enumerate()
pprint.pprint(hid_state)
The output is as follows:
[ {'interface_number': -1,
'manufacturer_string': 'Apple Inc.',
'path': b'IOService:/AppleACPIPlatformExpert/PCI0#0/AppleACPIPCI/XHC1#14/X'
b'HC1#14000000/HS12#14400000/Apple Internal Keyboard / Trackpad#14'
b'400000/Apple Internal Keyboard#0/AppleUSBTCKeyboard#14400000,0',
'product_id': 610,
'product_string': 'Apple Internal Keyboard / Trackpad',
'release_number': 549,
'serial_number': '',
'usage': 6,
'usage_page': 1,
'vendor_id': 1452},
{'interface_number': -1,
'manufacturer_string': 'Apple Inc.',
'path': b'IOService:/AppleACPIPlatformExpert/PCI0#0/AppleACPIPCI/XHC1#14/X'
b'HC1#14000000/HS12#14400000/Apple Internal Keyboard / Trackpad#14'
b'400000/Touchpad#1/AppleUSBMultitouchDriver#14400000,1',
'product_id': 610,
'product_string': 'Apple Internal Keyboard / Trackpad',
'release_number': 549,
'serial_number': '',
'usage': 1,
'usage_page': 65280,
'vendor_id': 1452},
{'interface_number': -1,
'manufacturer_string': 'Apple Inc.',
'path': b'IOService:/AppleACPIPlatformExpert/PCI0#0/AppleACPIPCI/XHC1#14/X'
b'HC1#14000000/HS12#14400000/Apple Internal Keyboard / Trackpad#14'
b'400000/Touchpad#2/AppleUSBTCButtons#14400000,2',
'product_id': 610,
'product_string': 'Apple Internal Keyboard / Trackpad',
'release_number': 549,
'serial_number': '',
'usage': 2,
'usage_page': 1,
'vendor_id': 1452},
{'interface_number': -1,
'manufacturer_string': '',
'path': b'IOService:/AppleACPIPlatformExpert/PCI0#0/AppleACPIPCI/PEG1#1,1/'
b'IOPP/UPSB#0/IOPP/DSB1#3/IOPP/UPS0#0/IOPP/pci-bridge#0/IOPP/pci1b'
b'73,1100#0/AppleUSBXHCIFL1100#00000000/AppleUSB20XHCIPort#0040000'
b'0/USB Keyboard#00400000/IOUSBHostInterface#1/IOUSBHostHIDDevice#'
b'00400000,1',
'product_id': 617,
'product_string': 'USB Keyboard',
'release_number': 4368,
'serial_number': '',
'usage': 1,
'usage_page': 12,
'vendor_id': 1241},
{'interface_number': -1,
'manufacturer_string': '',
'path': b'IOService:/AppleACPIPlatformExpert/PCI0#0/AppleACPIPCI/HDEF#1B/A'
b'ppleHDAController#1B/IOHDACodecDevice#1B,0/IOHDACodecDriver/IOHD'
b'ACodecFunction#1B,0,1/AppleHDACodecGeneric/AppleHDADriver/AppleM'
b'ikeyHIDDriver',
'product_id': 0,
'product_string': 'Apple Mikey HID Driver',
'release_number': 0,
'serial_number': '',
'usage': 1,
'usage_page': 12,
'vendor_id': 0}]
This example has been reduced for brevity, however one problem faced was multiple entries for the same device where only the path is slightly different, an example is shown below:
'path': b'IOService:/AppleACPIPlatformExpert/PCI0#0/AppleACPIPCI/XHC1#14/X'
b'HC1#14000000/HS12#14400000/Apple Internal Keyboard / Trackpad#14'
b'400000/Touchpad#2/AppleUSBTCButtons#14400000,2',
vs.
'path': b'IOService:/AppleACPIPlatformExpert/PCI0#0/AppleACPIPCI/XHC1#14/X'
b'HC1#14000000/HS12#14400000/Apple Internal Keyboard / Trackpad#14'
b'400000/Apple Internal Keyboard#0/AppleUSBTCKeyboard#14400000,0',
I was able to remove these duplicates (as many only ended with a different ",number") by sorting the list of dicts using the path value minus the last characters, like as follows:
list({str(v['path'][:-2]): v for v in r}.values())
As I have mentioned I still need to do testing on *nix, however, I can say it has done a good job of picking up HID devices such as mice and keyboards on OSX, I will need to determine if it is able to pick up malicious HID devices such as USB Rubber Duckies but signs look good.

pyudev: how to get the device's "friendly" name?

I want to give a /dev/DEVICE path as input and get the device "human friendly" name as output.
I was having success getting the name from ID_MODEL_ENC, like in this snippet:
def dev_name(dev_path):
from pyudev import Context
for device in Context().list_devices(DEVNAME=dev_path):
print device.get('ID_MODEL_ENC').decode('string_escape')
But it doesn't work with a bluetooth device. It seems that ID_MODEL_ENC is not so widely used.
In my application I'll use it only for joysticks, then the device path will be always /dev/input/js*.
Example 1: USB joystick is the js0
$ dev_name.py /dev/input/js0
Twin USB Joystick
Example 2: Bluetooth joystick is the js2
$ dev_name.py /dev/input/js2
Traceback (most recent call last):
File "pyudev_get_js_name.py", line 9, in <module>
dev_name(sys.argv[1])
File "pyudev_get_js_name.py", line 7, in dev_name
print '"'+ device.get('ID_MODEL_ENC').decode('string_escape') +'"'
AttributeError: 'NoneType' object has no attribute 'decode'
It obviously occurs because that device doesn't have the ID_MODEL_ENC attribute.
Just to make sure that the system knows the device's name we can do this directly in the shell prompt:
$ sys_dev_path="$(udevadm info --name=/dev/input/js2 | grep DEVPATH | cut -d= -f2)"
$ cat "/sys$(dirname $sys_dev_path)/name"
8Bitdo NES30 GamePad
I know I can make something similar with python and check the contents of /sys/devices/.../name file, but it looks like a makeshift. Is there a way to make pyudev give me the joystick name?
Note: I know it's pretty simple to get joystick names using pygame, but it's not an option here.
Thanks in advance.
I checked the device object created by pyudev with my controllers, and none of the members of the object held the descriptive name. As far as I could find, it doesn't mention it in the docs either. Anyways, this is how I implemented the name functionality. Like you said, I'm just pulling from the name file.
def get_devices():
context = Context()
##devices = []
#equivalent to "ls /dev/input | grep js"
js_list = [d for d in os.listdir("/dev/input") if d.startswith("js")]
for js in js_list:
js_file = os.path.join("/dev/input", js)
#different syntax to only get one item from Context()
#.sys_path gives only the full system path
js_path = Devices.from_device_file(context, js_file).sys_path
#the name file should exist at this combined path
name_path = os.path.join(js_path, "device", "name")
#read the name from that file
with open(name_path, "r") as buf:
js_name = buf.read().strip()
print("File: {}".format(js_path))
print("Name: {}".format(js_name))
##devices.append(...)
##return devices
If pyudev isn't giving you what you require, try evdev instead.
>>> from evdev import InputDevice,list_devices
>>> devices = [InputDevice(fn) for fn in list_devices()]
>>> for dev in devices:
... print (dev.fn, dev.name)
...
/dev/input/event12 HDA Intel PCH HDMI/DP,pcm=3
/dev/input/event11 HDA Intel PCH Front Headphone
/dev/input/event10 HDA Intel PCH Line Out
/dev/input/event9 HDA Intel PCH Rear Mic
/dev/input/event8 HDA Intel PCH Front Mic
/dev/input/event7 RDing FootSwitch3F1.
/dev/input/event6 USB OPTICAL MOUSE
/dev/input/event5 BTC USB Multimedia Keyboard
/dev/input/event4 BTC USB Multimedia Keyboard
/dev/input/event3 Video Bus
/dev/input/event2 Power Button
/dev/input/event1 Sleep Button
/dev/input/event0 Power Button
http://python-evdev.readthedocs.io/en/latest/
In response to your comment about joysticks only, the simple answer, is not directly but if you can find a capability that all joysticks have but that nothing else has, then that could be used to filter out all non-joystick devices.
I had a similar requirement, in that I needed to identify only foot pedal devices. To achieve that, I created a file containing a list of the USB Vendor and Procuct Id's of all known foot pedals. Armed with that I simply checked the dev.info.vendor and dev.info.product items of each device, to see if I got a match.
To allow for people with unknown devices, if I found no match, I presented all of the devices and asked them to identify their foot pedal (joystick), which I simply appended to the list and appended to the /lib/udev/rules.d/51-footswitch.rules file.
Here is the checking code:
devices = [InputDevice(fn) for fn in list_devices()]
for dev in devices:
vendor = "%x" % dev.info.vendor
vendor = vendor.zfill(4)
product = "%x" % dev.info.product
product = product.zfill(4)
check_pedal_string = vendor+":"+product
event_id = dev.fn
if check_pedal_string in known_devices:
found_hid = event_id
break

pySerial works in one script but not another

Now getting output, yet it is wrong Post modified to reflect progress.
I have been reading the documentation as well as following links from this site. I was able to find a script that works in reading data from my Arduino serial output.
It is as follows:
import time
import serial
# configure the serial connections (the parameters differs on the device you are connecting to)
ser = serial.Serial(
port='/dev/ttyACM0',
baudrate=115200,
parity=serial.PARITY_ODD,
stopbits=serial.STOPBITS_TWO,
bytesize=serial.SEVENBITS
)
ser.isOpen()
print 'Enter your commands below.\r\nInsert "exit" to leave the application.'
input=1
while 1 :
# get keyboard input
input = raw_input(">> ")
# Python 3 users
# input = input(">> ")
if input == 'exit':
ser.close()
exit()
else:
# send the character to the device
# (note that I happend a \r\n carriage return and line feed to the characters - this is requested by my device)
ser.write(input + '\r\n')
out = ''
# let's wait one second before reading output (let's give device time to answer)
time.sleep(1)
while ser.inWaiting() > 0:
out += ser.read(1)
if out != '':
print ">>" + out
The output window of Python opens and the code is executed. I am able to type 'exit' to exit or 'read' and a ton of lines from the Arduino serial monitor are now populated in the Python output window.
What I would like is to have the output from the Arduino to constantly be populated in the Python output window. (later I will try to plot the data using Matplotlib)
The code I used to attempt to read everything from the Arduinb is as such:
import time
import serial
# configure the serial connections (the parameters differs on the device you are connecting to)
ser = serial.Serial(
port='/dev/ttyACM0',
baudrate=115200,
parity=serial.PARITY_ODD,
stopbits=serial.STOPBITS_TWO,
bytesize=serial.SEVENBITS
)
ser.isOpen()
input=1
while True:
#First things first, lets wait for data prior to reading
time.sleep(1)
if (ser.inWaiting()>0):
myArduinoData = ser.read()
print myArduinoData
However, when I use the above code the Python execution hangs and I get no output from the serial monitor. This was now corrected by the above code and the community help
The new problem is the output only giving a single digit value and not the two to three digit value output to the Arduino serial monitor.
thanks to #jalo I was able to get the values in question by specifying a byte value in my inWaiting and ser.read statements. The change is as follows:
(ser.inWaiting()>4):
ser = ser.read(4)
Thank you.

Categories