python - 检测蓝牙遥控器上的按钮(HID over GATT)
问题描述
我有一个蓝牙 LE 遥控器,我想将它与我的 Raspberry Pi Zero 配对。
]
我能够成功地将遥控器与 Android 手机配对,然后它就像键盘一样工作,我能够将键盘上的数字输入空白笔记,甚至可以改变手机的音量。
似乎raspbian不支持 GATT 上的 HID,这意味着我需要使用 python 实现/模仿 GATT 上的最小 HID 行为。(如果有更直接的方法可以做到这一点,请纠正我。)
树莓派
我可以使用以下命令在 Linux 终端中发现遥控器lescan
:
sudo hcitool lescan
...
AA:BB:CC:DD:EE:FF FancyRemoteXY
现在在 GATTTool 中,我可以与遥控器配对。然而,几秒钟后,当遥控器继续闪烁白色 LED 时,遥控器与我的 Pi 断开连接。Android手机不会发生这种情况。因此,远程和主机之间必须进行某种握手,以保持连接。
# Press 1 & 3 to unpair the remote from existing devices
gatttool -I -b AA:BB:CC:DD:EE:FF
connect
# Press the OK button on the remote
Python GATT 库
我现在可以读取特性,并且过去我也已经处理过 BLE 和读/写特性来控制灯泡。
目前尚不清楚如何以“GATT-ian”方式检测遥控器的按键事件。我确实尝试为我在遥控器中找到的所有特征启用通知,但从未调用过回调。
我确实查看了 GATT 规范上的蓝牙 HID,但没有找到有关如何获得有关按键事件通知的线索。
总结一下。我的问题如下:
- 如何在不丢失连接的情况下成功连接遥控器
- 如何使用 GATT 检测遥控器上的按下按钮
附录:Bluetooth Explorer GATT 属性
使用iOS 应用程序,我能够列出以下 GATT 服务和特征。
使用这个应用程序,我还能够连接到遥控器,但我也像使用 Raspberry Pi 一样断开连接。
解决方案
感谢@ukBaz ,我现在可以在我的树莓派零上访问蓝牙 LE 遥控器,他指出了如何通过 GATT 访问 HID(Linux 中的短HoG:
使用遥控器配对bluetoothctl
这必须只发生一次。
首先,我同时按住 1 和 3 以清除遥控器上的任何当前配对。这是特定于我的远程模型的,但很高兴知道在连接之前重置设备可能是必要的。
sudo bluetoothctl
power on
agent on
# you might need to do `scan on` / `scan off` until you see the remote
pair AA:BB:CC:DD:EE:FF
# click ok on the remote or otherwise confirm the pairing
trust AA:BB:CC:DD:EE:FF
connect AA:BB:CC:DD:EE:FF # Pairing might perform a connect, but it does not hurt
info # info shows you if you're connected and or paired with the remote
现在重启树莓派
自动连接
在bluetoothctl
提示中显示您是否已连接到设备。60 秒后,连接断开。我认为这是一个问题,遥控器现在不会向 PI 发送命令,但重要的是要注意,一旦建立配对,遥控器似乎会自动连接到我的 Raspberry Pi。
Linux 中的 HoG 和/dev/input
我首先认为我需要连接到 GATT 协议栈并检测那些 GATT 消息和事件,以便检测遥控器的按钮事件。这是可能的,但由于 Raspberry Pi 上的 BlueZ 支持 HID over GATT,即蓝牙低功耗鼠标、操纵杆、键盘、游戏控制器或遥控器。这意味着 Pi 上的内核创建了一个位于/dev/input/
. 因此,一旦我配对并连接了我的 BLE Remote,两个新条目确实出现在/dev/input
:/dev/input/event1
和/dev/input/event0
.
我做了一个cat /dev/input/event1
,一旦我按下遥控器上的一个键,我就看到一些字节垃圾飞过终端。所以我可以验证遥控器是否正在向 Pi 发送事件。
使用读取事件evdev
更新:evdev 有一个模块,可让您快速输出所选设备的事件:
python3 -m evdev.evtest
@ukBaz指出我可以使用 pip3 包evdev来访问我的设备。通过运行以下 python 代码,我能够检测到遥控器上的按钮
安装evdev
并运行 python3 控制台:
pip3 install evdev
python3
运行python脚本
import evdev
device = evdev.InputDevice('/dev/input/event1')
print(device)
# device /dev/input/event1, name "Swisscom RC", phys "AA:BB:CC:DD:EE:FF"
for event in device.read_loop():
if event.type == evdev.ecodes.EV_KEY:
print(evdev.categorize(event))
这将输出以下内容:
key event at 1550575506.080840, 2 (KEY_1), down
key event at 1550575506.230643, 2 (KEY_1), up
key event at 1550575506.410622, 3 (KEY_2), down
key event at 1550575506.560618, 3 (KEY_2), up
key event at 1550575506.730621, 4 (KEY_3), down
key event at 1550575506.880608, 4 (KEY_3), up
key event at 1550575507.080630, 5 (KEY_4), down
key event at 1550575507.230630, 5 (KEY_4), up
key event at 1550575507.430884, 6 (KEY_5), down
key event at 1550575507.580611, 6 (KEY_5), up
key event at 1550575507.770633, 7 (KEY_6), down
key event at 1550575507.930623, 7 (KEY_6), up
key event at 1550575514.040805, 104 (KEY_PAGEUP), down
key event at 1550575514.295156, 104 (KEY_PAGEUP), hold
key event at 1550575514.345174, 104 (KEY_PAGEUP), hold
key event at 1550575514.395158, 104 (KEY_PAGEUP), hold
key event at 1550575514.445154, 104 (KEY_PAGEUP), hold
key event at 1550575514.495155, 104 (KEY_PAGEUP), hold
key event at 1550575514.545187, 104 (KEY_PAGEUP), hold
key event at 1550575514.595153, 104 (KEY_PAGEUP), hold
key event at 1550575514.645155, 104 (KEY_PAGEUP), hold
key event at 1550575514.695154, 104 (KEY_PAGEUP), hold
key event at 1550575514.745153, 104 (KEY_PAGEUP), hold
key event at 1550575514.795154, 104 (KEY_PAGEUP), hold
key event at 1550575514.840643, 104 (KEY_PAGEUP), up
key event at 1550575517.290737, 116 (KEY_POWER), down
key event at 1550575517.440740, 116 (KEY_POWER), up
key event at 1550575520.110901, 158 (KEY_BACK), down
key event at 1550575520.230905, 158 (KEY_BACK), up
key event at 1550575658.372344, 113 (['KEY_MIN_INTERESTING', 'KEY_MUTE']), down
key event at 1550575658.375718, 113 (['KEY_MIN_INTERESTING', 'KEY_MUTE']), up
key event at 1550575520.530643, 164 (KEY_PLAYPAUSE), down
key event at 1550575520.680666, 164 (KEY_PLAYPAUSE), up
key event at 1550575520.880818, 167 (KEY_RECORD), down
key event at 1550575521.020807, 167 (KEY_RECORD), up
事件对象有一个值 0,1,2,它是向下并保持的,一个类似的代码104
可以解析为相应的代码KEY_PAGEUP
,在我的遥控器上是更改程序键。
请注意,静音键有某种双重分配,您可能需要以不同方式处理。
问题 #1 - 更新 Bluez
bluez 包确实支持 HID over GATT,并且在此过程中进行了一些修复。在某些时候,您必须将--experimental
标志添加到ExecStart
bluez 服务的末尾/etc/systemd/system/dbus-org.bluez.service
。但是,GATT 上的 HID 在某些时候被添加到默认值中。
我确实将 bluez 更新到了最新版本,即bluez-5.50
. 我是从源头做的,这不是太难,在这里描述
bluetoothctl -v
5.43
sudo apt-get install libdbus-1-dev libglib2.0-dev libudev-dev libical-dev libreadline-dev -y
wget www.kernel.org/pub/linux/bluetooth/bluez-5.50.tar.xz
tar xvf bluez-5.50.tar.xz
cd cd bluez-5.50/
./configure --prefix=/usr --mandir=/usr/share/man --sysconfdir=/etc --localstatedir=/var --enable-experimental
make -j4
sudo make install
sudo reboot
bluetoothctl -v
# bluetoothctl: 5.50
问题 #2 - 运行rpi-update
只是为了确保我确实使用rpi-update
. 与所有这些陷阱一样,我不知道它们是否是必需的,但如果有疑问,更新系统通常是一个好习惯。
推荐阅读
- python-3.x - 如何访问孩子的xml文本?
- python - converting audio file and return it
- python - MultipleObjectsReturned at /checkout/ get() returned more than one Order -- it returned 2
- php - 读取csv文件并写入数据库
- python - Python: add a class to another classes bases
- mysql - update row if already exist or else insert new record in table using mysql
- angular - 如何使用 take 运算符取消订阅?
- git - How to install all roles without skipping any using ansible-galaxy?
- bash - 循环浏览目录的所有文件时如何仅打印文件名
- python - 当任务的开始日期大于执行日期时,气流无法完成 dag 运行