ESP32 蓝牙 HID 主机:手柄重连失败问题排查与解决
背景
IDF版本:v5.5.4
设备:ESP-WROOM-32
在使用 IDF 示例 esp_hid_host 示例, ESP32 作为蓝牙 HID 主机(HID Host)连接游戏手柄(Q34U - XBOX模式)时,遇到一个问题:
ESP32能扫描到BT和BLE,成功连接上手柄后,关闭手柄再次按手柄重连键,能连接且能读取到数据。然而重启ESP32,再次重连会出现连接上,但是不能正常识别为HID设备从而断开连接。
问题现象
-
首次扫描配对:一切正常,手柄可以成功连接,获取报告描述符,接收输入数据。
-
手柄重启: 手柄按下重连键,可以正常重连上 ESP32,接收输入数据。
-
设备复位/重启后:手柄按下重连键,尝试主动重连,和ESP32 虽然建立了 ACL 连接,但无法发现 HID 服务,最终打开失败,链路断开。
日志输出:
I (234608) ESP_HID_GAP: ESP_BT_GAP_ACL_CONN_CMPL_STAT_EVT: 83:55:01:09:a0:c5
I (234608) ESP_HID_GAP: Status: 0
W (234898) ESP_HID_GAP: BT GAP EVENT: ENC_CHG - 21
E (48068) BT_HIDH: OPEN ERROR: ERR_SDP
I (48068) ESP_HIDH_DEMO: ESP_HIDH_OPEN_EVENT
E (48068) ESP_HIDH_DEMO: OPEN failed! status = -1
总之看日志是可以发现ACL已经建立连接了,但是某种错误最终导致 BT_HIDH: OPEN ERROR: ERR_SDP,进而导致 ESP_HIDH_DEMO: OPEN failed!
根因分析
观察现象,问题出现在 ESP32 设备重启之后,似乎重启之后某些信息丢失了,但是查看 NVS,连接过的设备MAC仍然保存在里面。
一番折腾,这个问题在 ESP-IDF 官方 GitHub 上有记录:
Issue #18335 - ESP-IDF Bluetooth Classic Reconnection Failure (HID Devices Not Loaded From Flash)
Thanks for reporting. The issue might be caused by the SDP failure. For now, the Bluedroid doesn't load the saved HID device information. When the peer HID Device initiate the reconnection, the HID Host accepts the incomming connection, but it will initiate SDP connection to obtain the newest information for HID Device. However, the incomming HID report data may fail the SDP procedure which cause the open failure at last. Please try the following patch to see if the issue is still exist. In this patch, I enabled the btc_storage_load_bonded_hid_info.
感谢你的报告。问题可能是SDP失效引起的。目前,Bluedroid不会加载保存的HID设备信息。当对等的HID设备发起重新连接时,HID主机接受接收的连接,但会发起SDP连接以获取HID设备的最新信息。然而,接收的HID报告数据可能未能通过SDP过程,最终导致开放故障。请尝试以下补丁,看看问题是否仍然存在。在这个补丁中,我启用了btc_storage_load_bonded_hid_info。
原因在于 ESP-IDF 蓝牙协议栈的一个已知 bug:
-
系统在复位/重启后,没有从 NVS(非易失性存储)中加载已绑定的 HID 设备信息(报告描述符、属性等)。
-
导致重连时,HID Host 认为这是一个“新设备”,必须通过 SDP 查询获取服务信息。
-
但此时链路处于 Sniff 模式,SDP 查询超时,最终打开失败。
解决方案
Issue #18335 - ESP-IDF Bluetooth Classic Reconnection Failure (HID Devices Not Loaded From Flash)
Issue 中已有补丁修复此问题,enable_load_hid_devices.zip enable_load_hid_devices.zip
此外Issue中的第二个补丁也包含了第一个补丁,且修补了其它内容 hid_host_refactor_and_fix.zip hid_host_refactor_and_fix.zip
手动打补丁步骤(以 PlatformIO 为例)
-
找到 ESP-IDF 框架目录
cd ~/.platformio/packages/framework-espidf -
下载补丁文件(从 Issue #18335 获取)
-
应用补丁
patch -p1 < enable_load_hid_devices.patch成功输出应类似:
┌──-[~/.platformio/packages/framework-espidf] └─$ patch -p1 < enable_load_hid_devices.patch patching file components/bt/host/bluedroid/bta/hh/bta_hh_act.c patching file components/bt/host/bluedroid/btc/profile/std/hid/btc_hh.c patching file components/esp_hid/src/bt_hidh.c patching file examples/bluetooth/esp_hid_host/main/esp_hid_gap.c -
清理并重新编译
pio run -t clean pio run -t build -
烧录测试
补丁核心改动解读
补丁主要做了三件事:
| 文件 | 改动 | 作用 |
|---|---|---|
btc_hh.c |
取消注释 btc_storage_load_bonded_hid_info() |
从 NVS 加载已绑定 HID 设备信息 |
bta_hh_act.c |
设置 dev_info.status = BTA_HH_OK |
正确标记设备状态 |
bt_hidh.c |
重构连接队列管理逻辑 | 修复事件顺序和内存释放问题 |
效果:重连时不再需要执行 SDP 查询,直接使用 NVS 中的缓存信息,避免 Sniff 模式超时问题。
验证结果
补丁应用后,重新编译烧录,重连日志变为:
I (234608) ESP_HID_GAP: ESP_BT_GAP_ACL_CONN_CMPL_STAT_EVT: 83:55:01:09:a0:c5
I (234978) ESP_HIDH_DEMO: ESP_HIDH_OPEN_EVENT
BDA:83:55:01:09:a0:c5, Status: OK, Connected: YES, Handle: 0, Usage: GAMEPAD
Report Map Length: 334
GENERIC INPUT REPORT, ID: 4, Length: 1
GAMEPAD INPUT REPORT, ID: 1, Length: 16
手柄成功重连,SDP 错误消失,报告描述符正常获取。
经验总结(Ai总结)
-
ERR_SDP不一定是对端设备问题:Sniff 模式可能导致 SDP 超时,尤其是在重连场景。 -
ESP-IDF 蓝牙 HID Host 重连机制有缺陷:需要加载 NVS 中的绑定信息才能正常工作。
-
平台差异:原生 ESP-IDF 环境可直接使用
git apply,PlatformIO 需要手动打补丁或使用自动化脚本。 -
调试技巧:开启详细日志(
esp_log_level_set("*", ESP_LOG_VERBOSE))有助于定位问题。

浙公网安备 33010602011771号