如何在Linux下识别产生输入事件的蓝牙输入外设来源?
如何识别Linux上蓝牙输入设备的事件来源
问题背景
我正在为Kachaka家庭机器人开发呼叫按钮网关,用树莓派作为蓝牙中心设备,搭配多个售价1美元的Smartphone Shutter Remote Controller(蓝牙快门遥控器,本质是单按键蓝牙键盘,仅发送VolumeUp按键事件)。按下不同房间的遥控器后,需要让机器人前往对应位置,但目前无法区分事件来自哪个设备——重连后/dev/input/eventX的设备号不固定,且遥控器无法升级固件发送唯一标识,需要通过MAC地址等稳定信息识别事件来源。

解决方案:通过evdev的phys属性获取蓝牙设备MAC
Linux下的evdev设备提供了phys属性,对于蓝牙输入设备,该属性会包含外设的MAC地址,格式通常为bluetooth:XX:XX:XX:XX:XX:XX,这是不受设备号变化影响的稳定标识。
1. 遍历并筛选蓝牙输入设备
先收集所有蓝牙类型的键盘设备,记录它们的MAC地址与对应的evdev设备对象:
import evdev from evdev import ecodes # 存储蓝牙设备的MAC与对应的InputDevice对象 bluetooth_devices = [] # 遍历系统所有输入设备 for dev_path in evdev.list_devices(): dev = evdev.InputDevice(dev_path) # 筛选蓝牙设备且具备按键输入能力 if dev.phys.startswith('bluetooth:') and ecodes.EV_KEY in dev.capabilities(): # 提取MAC地址(从phys字段拆分) device_mac = dev.phys.split(':')[1] bluetooth_devices.append( (device_mac, dev) ) print(f"已识别蓝牙设备: {device_mac} | 设备名: {dev.name}")
2. 监听多设备事件并识别来源
用select同时监听所有蓝牙设备的事件,触发时通过设备对象关联到对应的MAC地址,再根据MAC映射到具体房间执行指令:
from select import select # 提前定义MAC与房间的映射关系 room_mapping = { "AA:BB:CC:DD:EE:FF": "客厅", "11:22:33:44:55:66": "卧室", "99:88:77:66:55:44": "厨房" } while True: # 等待事件触发 readable_devs, _, _ = select([dev for (mac, dev) in bluetooth_devices], [], []) for dev in readable_devs: # 找到当前设备对应的MAC current_mac = next(mac for mac, d in bluetooth_devices if d == dev) # 读取并处理事件 for event in dev.read(): if ( event.type == ecodes.EV_KEY and event.code == ecodes.KEY_VOLUMEUP and event.value == 1 # 仅处理按键按下事件 ): target_room = room_mapping.get(current_mac, "未知房间") print(f"收到来自{target_room}的呼叫请求") # 调用Kachaka机器人API,发送前往对应房间的指令 # send_kachaka_command(target_room)
3. 获取蓝牙设备MAC的方法
如果不知道遥控器的MAC地址,可以通过以下方式获取:
- 配对设备后,在终端执行
bluetoothctl devices命令,查看已配对设备的MAC列表。 - 运行上述代码后,按下对应遥控器,终端会输出该设备的MAC地址,直接记录即可。
4. 可靠性说明
蓝牙设备的phys属性由系统根据蓝牙连接生成,只要外设的MAC地址不变,该属性就不会改变,完全不受重连后/dev/input设备号变化的影响,能稳定识别事件来源。
内容的提问来源于stack exchange,提问作者okapies
相关产品推荐
相关产品推荐

