Issue
I want to use multiple Bluetooth input devices on a Linux as /dev/input
and write a program to handle their input event, but I need to vary its behavior depending on the source peripheral. How do we identify which peripheral originates the received input event?
Background:
I'm working on a personal project to develop a call button for a home robot without using its official smartphone app. The robot will come for you if you push the button arranged in every room.
I make use of Smartphone Shutter Remote Controller (BT Shutter), a $1 Bluetooth peripheral to tap a shutter button on your smartphone from a distance. It is actually a one-button Bluetooth keyboard that can only send a VolumeUp
keyboard event to the paired central device. I think it is ideal to implement my use case regarding cost and battery life.
I plan to develop a gateway server in Python on a Linux device like Rasberry Pi that acts as a Bluetooth central and sends a control command to the robot via its API in response to receiving keyboard events from the BT Shutters, like the following:
import evdev
device = evdev.InputDevice('/dev/input/event1')
for event in device.read_loop():
if (
event.type == evdev.ecodes.EV_KEY
and event.code == evdev.ecodes.KEY_VOLUMEUP
and event.value == 1: # KEYDOWN
):
# Move the robot to the defined location in the house.
...
However, the server cannot distinguish the events from different rooms because BT Shutter is just a single-function keyboard and cannot upgrade its firmware to make it send a unique identifier. It would be helpful if it could retrieve the MAC address or something of the input device to identify the source of the events. Note that the device name /event?
is not reliable because evdev does not ensure its consistency between re-connection.
Solution
Each /dev/input/event*
provides a UNIQ
identifier in response to the EVIOCGUNIQ
ioctl request. In the case of Bluetooth, UNIQ represents a MAC address to identify the underlying peripheral uniquely. evdev also exposes PRODUCT
via EVIOCGID
request.
We can easily get the value in Python by using python-evdev, that provides a convenient wrapper function of ioctl:
>>> import evdev
>>> dev = evdev.InputDevice('/dev/input/event1')
>>> dev.name
'BT Shutter Keyboard'
>>> dev.info
DeviceInfo(bustype=5, vendor=9354, product=33382, version=1)
>>> dev.phys # Controller MAC address
'xx:xx:xx:xx:xx:xx'
>>> dev.uniq # Device MAC address
'xx:xx:xx:xx:xx:xx'
udevadm
also provides the event device path that includes the path to the underlying input device on sysfs:
$ udevadm info /dev/input/event1
P: /devices/virtual/misc/uhid/XXXX:XXXX:XXXX.XXXX/input/input1/event1
N: input/event1
L: 0
E: DEVPATH=/devices/virtual/misc/uhid/XXXX:XXXX:XXXX.XXXX/input/input1/event1
E: DEVNAME=/dev/input/event1
...
$ udevadm info /sys/devices/virtual/misc/uhid/XXXX:XXXX:XXXX.XXXX/input/input1
PRODUCT=5/248a/8266/1
NAME="BT Shutter Keyboard"
PHYS="xx:xx:xx:xx:xx:xx"
UNIQ="xx:xx:xx:xx:xx:xx"
...
Answered By - okapies Answer Checked By - Senaida (WPSolving Volunteer)