You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派Pico W基于aioble的BLE连接立即失败问题求助

树莓派Pico W BLE HID键盘连接失败问题

我尝试用树莓派Pico W制作一款带按键的小型蓝牙键盘,但尚未实现按键功能就卡在了BLE连接环节——设备可被BLE调试APP搜索到,但尝试连接时蓝牙会立即断开。

我使用aioble模块(简写为ble)定义了三类服务:设备信息服务(DIS)、电池电量服务(BAS)和HID服务(仅HID服务被设置为广播)。曾尝试执行await connection.exchange_mtu()进行MTU交换,但问题反而恶化。

相关代码如下:

import struct
from bluetooth import UUID
import asyncio

_ADV_INTERVAL_MS = 250_000

dis_service = ble.Service(UUID(0x180A))
dis_model_char = ble.Characteristic(dis_service, UUID(0x2A24), read = True)
dis_serial_char = ble.Characteristic(dis_service, UUID(0x2A25), read = True)
dis_firm_char = ble.Characteristic(dis_service, UUID(0x2A26), read = True)
dis_hard_char = ble.Characteristic(dis_service, UUID(0x2A27), read = True)
dis_soft_char = ble.Characteristic(dis_service, UUID(0x2A28), read = True)
dis_manu_char = ble.Characteristic(dis_service, UUID(0x2A29), read = True)
dis_pnp_char = ble.Characteristic(dis_service, UUID(0x2A50), read = True)

bas_service = ble.Service(UUID(0x180F))
bas_levl_char = ble.Characteristic(bas_service, UUID(0x2A19), notify = True)

hid_service = ble.Service(UUID(0x1812))
hid_info_char = ble.Characteristic(hid_service, UUID(0x2A4A), read = True)
hid_irmap_char = ble.Characteristic(hid_service, UUID(0x2A4B), read = True)
hid_control_char = ble.Characteristic(hid_service, UUID(0x2A4C), write = True)
hid_report_char = ble.Characteristic(hid_service, UUID(0x2A4D), notify = True, read = True)
hid_protocol_char = ble.Characteristic(hid_service, UUID(0x2A4E), write = True)
hid_report_desc = ble.Descriptor(hid_report_char, UUID(0x2908), read = True)

ble.register_services(dis_service, bas_service, hid_service)
print("Services registered")

HID_INPUT_REPORT = bytes([    # Report Description: describes what we communicate
    0x05, 0x01,                    # USAGE_PAGE (Generic Desktop)
    0x09, 0x06,                    # USAGE (Keyboard)
    0xa1, 0x01,                    # COLLECTION (Application)
    0x85, 0x01,                    #     REPORT_ID (1)
    0x75, 0x01,                    #     Report Size (1)
    0x95, 0x08,                    #     Report Count (8)
    0x05, 0x07,                    #     Usage Page (Key Codes)
    0x19, 0xE0,                    #     Usage Minimum (224)
    0x29, 0xE7,                    #     Usage Maximum (231)
    0x15, 0x00,                    #     Logical Minimum (0)
    0x25, 0x01,                    #     Logical Maximum (1)
    0x81, 0x02,                    #     Input (Data, Variable, Absolute); Modifier byte
    0x95, 0x01,                    #     Report Count (1)
    0x75, 0x08,                    #     Report Size (8)
    0x81, 0x01,                    #     Input (Constant); Reserved byte
    0x95, 0x05,                    #     Report Count (5)
    0x75, 0x01,                    #     Report Size (1)
    0x05, 0x08,                    #     Usage Page (LEDs)
    0x19, 0x01,                    #     Usage Minimum (1)
    0x29, 0x05,                    #     Usage Maximum (5)
    0x91, 0x02,                    #     Output (Data, Variable, Absolute); LED report
    0x95, 0x01,                    #     Report Count (1)
    0x75, 0x03,                    #     Report Size (3)
    0x91, 0x01,                    #     Output (Constant); LED report padding
    0x95, 0x06,                    #     Report Count (6)
    0x75, 0x08,                    #     Report Size (8)
    0x15, 0x00,                    #     Logical Minimum (0)
    0x25, 0x65,                    #     Logical Maximum (101)
    0x05, 0x07,                    #     Usage Page (Key Codes)
    0x19, 0x00,                    #     Usage Minimum (0)
    0x29, 0x65,                    #     Usage Maximum (101)
    0x81, 0x00,                    #     Input (Data, Array); Key array (6 bytes)
    0xc0                           # END_COLLECTION
])

def pack_str(in_str):
    return struct.pack(str(len(in_str))+"s", in_str.encode('UTF-8'))

pnp_manufacturer_source = 0x01 # Bluetooth uuid list
pnp_manufacturer_uuid = 0xaf73 # 0xFEB2 for Microsoft, 0xFE61 for Logitech, 0xFD65 for Razer
pnp_product_id = 0x01 # ID 1
pnp_product_version = 0x0123 # Version 1.2.3

battery_level = 100

appearance = 961
name = "Pi Pico Keyboard"

dis_model_char.write(pack_str("1"))
dis_serial_char.write(pack_str("1"))
dis_firm_char.write(pack_str("1"))
dis_hard_char.write(pack_str("1"))
dis_soft_char.write(pack_str("1"))
dis_manu_char.write(pack_str("Homebrew"))
dis_pnp_char.write(struct.pack("<BHHH", pnp_manufacturer_source, pnp_manufacturer_uuid, pnp_product_id, pnp_product_version))

bas_levl_char.write(struct.pack("<B", battery_level))

hid_info_char.write(b"\x01\x01\x00\x02")
hid_irmap_char.write(HID_INPUT_REPORT)
hid_report_desc.write(struct.pack("<BB", 1, 1))
#hid_report_desc.write(struct.pack("<BB", 1, 2))
hid_protocol_char.write(b"\x01")

print("Characteristics written")

async def advertise():
    while True:
        print("Advertising")
        async with await ble.advertise(
            _ADV_INTERVAL_MS,
            name=name,
            services=[UUID(0x1812)],
            appearance=appearance,
        ) as connection:
            print("Connection from", connection.device)
            await connection.disconnected(timeout_ms=None)

# Run both tasks.
async def main():
    t1 = asyncio.create_task(advertise())
    await asyncio.gather(t1)

asyncio.run(main())

内容的提问来源于stack exchange,提问作者Tyrannicodin16

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 02:14:58