本文将介绍如何在 python 程序中使用 hcitool 工具对周围低功耗蓝牙设备(BLE)进行扫描。
设备及系统软件需求
设备依赖:
树莓派3B及更新版本设备
其他带有蓝牙功能的开发板(需确认软件支持)
配备蓝牙功能的x86主机或已安装蓝牙适配器
系统及软件依赖:
树莓派OS:Raspbian、Ubuntu Core
X86主机:Ubuntu、或其他Linux发行版 (Window及MacOS无原生支持Gatttool及Hcitool,因此不适应,若需要相应功能,可参考pybluez库)
软件:bluetooth、rpi-bluetooth (树莓派)
参考资料
参考开源库 penlin/pygatt ,以其中 /pygatt/backends/gatttool/gatttool.py
中 scan 方法为例,作相应修改完成。
前置知识
首先需要了解 hcitool 工具的使用。对于该工具的详细功能和参数的使用方法,可以使用:
hcitool --help
在开始使用 hcitool 工具之前,需要先进行一些配置。默认情况下, hcitool 工具需要有 root 权限,但是我们在使用中或者python程序中调用,都希望不需要使用 root 权限或者使用 sudo 来提权,我们可以通过以下配置来实现不需要 root 权限而对工具进行调用:
sudo setcap 'cap_net_raw,cap_net_admin+eip' `which hcitool`
完成配置后,我们就可以开始来了解 hcitool这个工具。以下介绍几个最主要常用的功能。首先是获取当前蓝牙设备的信息:
hcitool dev
>
Devices:
hci0 00:1A:7D:DA:**:**
如果蓝牙设备正常,可以看到返回当前蓝牙的 Mac 地址,如果蓝牙设备不能正常使用,则不会有返回信息,我们可以通过手动关闭蓝牙来实验以下。
sudo hciconifg hci0 down
hcitool dev
>
Devices:
sudo hciconfig hci0 up
hcitool dev
>
Devices:
hci0 00:1A:7D:DA:**:**
这里还有一个技巧,如果使用蓝牙扫描是出现 Set scan parameters failed: Input/output errer
的错误信息,可以使用上述的方法,手动重启蓝牙,即可解决问题。
接下来是对周围的低功耗蓝牙设备进行搜索:
hcitool lescan
>
LE Scan ...
20:91:**:B9:0B:** (unknown)
20:91:48:**:0B:EE UPots
20:91:48:B9:**:89 (unknown)
20:91:**:B9:08:89 UPots
20:91:48:**:0B:C2 (unknown)
20:91:48:B9:**:C2 UPots
20:91:48:**:0B:EE (unknown)
执行命令后,可以看到会不断打印出周围蓝牙设备的名称和 MAC 地址。
到这里为止,我们就完成对 hcitool 工具的基本了解了,下面将进入 python 编程部分。
使用 Python 调用 hcitool 工具完成 BLE 扫描
我们在刚才是试验中,已经了解到,当使用 hcitool 时,该工具不会自动停止,而是会不断打印搜索结果。这里我们需要使用 pexpect
的 timeout
来控制运行一定时间后就自动停止。
import pexpect
# 这里的 timeout 设置为 3 ,即 3 秒后就会停止
scan = pexpect.spawn('hcitoon lescan, timeout=3)
在运行后,正常情况下的输出结果应该和上面类似,以 LE Scan … 开头,下面接着就是搜索出来的设备和 MAC 地址,我们可以通过用 expect
来获取结果。这里有个技巧,因为我们的 hcitool 会不断打印到时间停止,所以我们可以通过 expect
捕获随便一个不存在的字符,这样程序就会直接进入 pexpect.TIMEOUT
,我们再通过 before
就能拿到所有的打印结果,接而进一步对结果处理即可。
scan.expect('foooooo') # 设置捕获一个不存在的字符串即可
scan.before
>
b'LE Scan ...\r\n20:91:48:**:0B:C2 (unknown)\r\n
20:91:48:**:08:89 (unknown)\r\n
20:91:48:**: