树莓派Zero W蓝牙扫描代码异常求助:C无结果Python报错
树莓派Zero W蓝牙扫描程序故障排查
问题描述
- 采用网上的C示例代码编写BLE扫描程序,无编译/运行报错,但始终无法发现设备,
num_rsp变量持续为0 - 执行
hcitool lescan可正常列出周边BLE设备,证明蓝牙硬件及驱动功能正常 - 使用Python Bleak库编写扫描脚本时,触发
org.bluez.Error.InProgress错误,提示操作已在进行中 - 已将bluez更新至最新版本,
bluetoothctl和hcitool等工具可正常工作,但自行编写的代码均无法正常完成扫描
Bleak报错代码及错误信息
Python代码:
import sys import platform import logging import binascii import asyncio from bleak import BleakScanner async def main(): async with BleakScanner() as scanner: devices = await scanner.discover() for d in devices: print(d) asyncio.run(main())
错误日志:
Traceback (most recent call last): File "/home/pi/stryd.py", line 16, in <module> asyncio.run(main()) File "/usr/lib/python3.9/asyncio/runners.py", line 44, in run return loop.run_until_complete(main) File "/usr/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete return future.result() File "/home/pi/stryd.py", line 11, in main devices = await scanner.discover() File "/usr/local/lib/python3.9/dist-packages/bleak/__init__.py", line 216, in discover async with cls(**kwargs) as scanner: File "/usr/local/lib/python3.9/dist-packages/bleak/__init__.py", line 126, in __aenter__ await self._backend.start() File "/usr/local/lib/python3.9/dist-packages/bleak/backends/bluezdbus/scanner.py", line 191, in start self._stop = await manager.active_scan( File "/usr/local/lib/python3.9/dist-packages/bleak/backends/bluezdbus/manager.py", line 368, in active_scan assert_reply(reply) File "/usr/local/lib/python3.9/dist-packages/bleak/backends/bluezdbus/utils.py", line 20, in assert_reply raise BleakDBusError(reply.error_name, reply.body) bleak.exc.BleakDBusError: [org.bluez.Error.InProgress] Operation already in progress
原始C示例代码
#include <stdio.h> #include <errno.h> #include <stdlib.h> #include <unistd.h> #include <curses.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <bluetooth/bluetooth.h> #include <bluetooth/hci.h> #include <bluetooth/hci_lib.h> #define HCI_STATE_NONE 0 #define HCI_STATE_OPEN 2 #define HCI_STATE_SCANNING 3 #define HCI_STATE_FILTERING 4 #define EIR_FLAGS 0X01 #define EIR_NAME_SHORT 0x08 #define EIR_NAME_COMPLETE 0x09 #define EIR_MANUFACTURE_SPECIFIC 0xFF struct hci_state { int device_id; int device_handle; struct hci_filter original_filter; int state; int has_error; char error_message[1024]; } hci_state; int main(int argc, char **argv) { struct hci_state dev_id; inquiry_info *ii = NULL; int max_rsp, num_rsp; int sock, len, flags; int i; char addr[19] = { 0 }; char name[248] = { 0 }; dev_id.device_id = hci_get_route(NULL); if((dev_id.device_handle = hci_open_dev(dev_id.device_id)) < 0){ dev_id.has_error = TRUE; snprintf(dev_id.error_message, sizeof(dev_id.error_message), "Could not open device: %s", strerror(errno)); } // Set fd non-blocking int on = 1; if(ioctl(dev_id.device_handle, FIONBIO, (char *)&on) < 0){ dev_id.has_error = TRUE; snprintf(dev_id.error_message, sizeof(dev_id.error_message), "Could set device to non-blocking: %s", strerror(errno)); } dev_id.state = HCI_STATE_OPEN; if (hci_le_set_scan_parameters(dev_id.device_handle, 0x01, htobs(0x0010), htobs(0x0010), 0x00, 0x00, 1000) < 0){ dev_id.has_error = 1; snprintf(dev_id.error_message, sizeof(dev_id.error_message), "Failed to set scan parameters: %s", strerror(errno)); } if (hci_le_set_scan_enable(dev_id.device_handle, 0x01, 1, 1000) < 0){ dev_id.has_error = 1; snprintf(dev_id.error_message, sizeof(dev_id.error_message), "Failed to enable scan: %s", strerror(errno)); } sock = dev_id.device_handle; len = 8; max_rsp = 255; flags = IREQ_CACHE_FLUSH; ii = (inquiry_info*)malloc(max_rsp * sizeof(inquiry_info)); num_rsp = hci_inquiry(dev_id.device_id, len, max_rsp, NULL, &ii, flags); if( num_rsp < 0 ) perror("hci_inquiry"); for (i = 0; i < num_rsp; i++) { ba2str(&(ii+i)->bdaddr, addr); memset(name, 0, sizeof(name)); if (hci_read_remote_name(sock, &(ii+i)->bdaddr, sizeof(name), name, 0) < 0) strcpy(name, "[unknown]"); printf("%s %s\n", addr, name); } free( ii ); close( sock ); return 0; }
解决方案
1. Bleak库报错修复
原因:系统中已有蓝牙扫描进程在运行(比如bluetoothctl扫描未停止、hcitool lescan后台进程未结束),导致BlueZ拒绝新的扫描请求。
修复步骤:
- 先停止所有正在运行的蓝牙扫描进程:
sudo bluetoothctl scan off killall hcitool - 或修改Python代码,明确指定扫描超时时间,简化扫描逻辑:
import asyncio from bleak import BleakScanner async def main(): # 指定扫描超时为5秒 devices = await BleakScanner.discover(timeout=5) for d in devices: print(d) asyncio.run(main())
2. C代码扫描BLE设备修复
原因:原始代码混用了经典蓝牙(BR/EDR)扫描API (hci_inquiry) 和 BLE扫描配置,hci_inquiry仅能扫描经典蓝牙设备,无法获取BLE广告包,因此num_rsp始终为0。
修正后的C代码:
#include <stdio.h> #include <errno.h> #include <stdlib.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <bluetooth/bluetooth.h> #include <bluetooth/hci.h> #include <bluetooth/hci_lib.h> #define SCAN_DURATION 5 // 扫描时长(秒) // 解析BLE广告数据中的设备名称 void parse_eir_data(uint8_t *eir, char *name, size_t name_len) { uint8_t *ptr = eir; while (*ptr) { uint8_t len = *ptr++; uint8_t type = *ptr++; if (type == 0x09 || type == 0x08) { // 完整名称/短名称 snprintf(name, name_len, "%.*s", len - 1, ptr); break; } ptr += len - 1; } } int main() { int dev_id = hci_get_route(NULL); int sock = hci_open_dev(dev_id); if (sock < 0) { perror("hci_open_dev"); exit(EXIT_FAILURE); } // 设置BLE扫描参数:主动扫描,间隔10ms,窗口10ms le_set_scan_parameters_cp scan_params = { .type = 0x01, // 主动扫描 .interval = htobs(0x0010), .window = htobs(0x0010), .own_bdaddr_type = 0x00, .filter_policy = 0x00 }; if (hci_le_set_scan_parameters(sock, &scan_params, 1000) < 0) { perror("hci_le_set_scan_parameters"); close(sock); exit(EXIT_FAILURE); } // 开启BLE扫描 if (hci_le_set_scan_enable(sock, 0x01, 1, 1000) < 0) { perror("hci_le_set_scan_enable"); close(sock); exit(EXIT_FAILURE); } // 设置HCI过滤,只接收BLE广告事件 struct hci_filter flt; hci_filter_clear(&flt); hci_filter_set_ptype(HCI_EVENT_PKT, &flt); hci_filter_set_event(EVT_LE_META_EVENT, &flt); if (setsockopt(sock, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) { perror("setsockopt HCI_FILTER"); close(sock); exit(EXIT_FAILURE); } printf("扫描BLE设备中,持续%d秒...\n", SCAN_DURATION); fd_set read_set; struct timeval timeout; timeout.tv_sec = SCAN_DURATION; timeout.tv_usec = 0; while (1) { FD_ZERO(&read_set); FD_SET(sock, &read_set); int ret = select(sock + 1, &read_set, NULL, NULL, &timeout); if (ret == 0) { // 超时结束扫描 break; } else if (ret < 0) { perror("select"); break; } if (FD_ISSET(sock, &read_set)) { uint8_t buf[HCI_MAX_EVENT_SIZE]; int len = read(sock, buf, sizeof(buf)); if (len < 0) { perror("read"); continue; } // 解析BLE广告事件 evt_le_meta_event *meta = (evt_le_meta_event *)(buf + 2); if (meta->subevent != EVT_LE_ADVERTISING_REPORT) { continue; } le_advertising_info *info = (le_advertising_info *)(meta->data + 1); char addr[19] = {0}; char name[256] = "[unknown]"; ba2str(&info->bdaddr, addr); parse_eir_data(info->data, name, sizeof(name)); printf("设备地址: %s 名称: %s RSSI: %d\n", addr, name, info->data[info->length]); } } // 关闭扫描 hci_le_set_scan_enable(sock, 0x00, 1, 1000); close(sock); return 0; }
编译命令:
gcc ble_scan.c -o ble_scan -lbluetooth
说明:
- 改用
hci_le_set_scan_parameters和hci_le_set_scan_enable配置BLE扫描 - 通过
select监听HCI套接字,读取BLE广告事件(EVT_LE_META_EVENT) - 解析广告数据中的设备名称和RSSI信息
- 扫描结束后主动关闭BLE扫描
内容的提问来源于stack exchange,提问作者Charlie Mason
相关产品推荐
相关产品推荐

