树莓派python扫描蓝牙

仅为防止原文丢失,如果侵犯到原作者的权益,请联系本人删除。

原文地址:https://blog.csdn.net/weixin_42211601/article/details/107469141,以下为原文内容

环境

树莓派3b+
python3.7
蓝牙设备

pybluez库

github链接:https://github.com/pybluez/pybluez

  • 安装库
sudo pip3 install pybluez
  • 简单扫描
import bluetooth
nearby_devices = bluetooth.discover_devices(lookup_names=True)
print("Found {} devices.".format(len(nearby_devices)))
for addr, name in nearby_devices:
    print("  {} - {}".format(addr, name))

能够正常运行,但只能扫描到手机。我用的是蓝牙卡片,手机扫描到的是在其他设备栏里,查找资料发现是属于低功耗蓝牙设备ibeacon。下面还有另一个官方示例,提示是扫描低功耗的,尝试一下。

  • 低功耗扫描
from bluetooth.ble import DiscoveryService
service = DiscoveryService()
devices = service.discover(2)
for address, name in devices.items():
    print("name: {}, address: {}".format(name, address))

运行后提示缺少gattlib库,由于该库依赖其他环境,找了半天解决方案还是有问题,于是放弃了,暂时只能做到扫描手机设备。

bluepy库

github链接:https://github.com/IanHarvey/bluepy
找到了另外一个蓝牙扫描库,能扫出低功耗的蓝牙设备。

  • 安装库
sudo pip3 install bluepy
  • 示例代码
from bluepy.btle import Scanner, DefaultDelegate
class ScanDelegate(DefaultDelegate):
    def __init__(self):
        DefaultDelegate.__init__(self)
    def handleDiscovery(self, dev, isNewDev, isNewData):
        if isNewDev:
            print("Discovered device", dev.addr)
        elif isNewData:
            print("Received new data from", dev.addr)
scanner = Scanner().withDelegate(ScanDelegate())
devices = scanner.scan(10.0)
print(len(devices))
for dev in devices:
    print("---------------")
    print("Device %s (%s), RSSI=%d dB" % (dev.addr, dev.addrType, dev.rssi))
    for (adtype, desc, value) in dev.getScanData():
        print("  %s = %s" % (desc, value))

其中scanner.scan(10.0)代表扫描时间

  • 扫描结果
---------------
Device ac:23:3f:58:4e:ca (public), RSSI=-61 dB
  Flags = 06
  Manufacturer = 4c000215fda50693a4e24fb1afcfc6eb0764782527114cb9c5
  Tx Power = ec
  Complete 16b Services = 0000fda5-0000-1000-8000-00805f9b34fb
  16b Service Data = a5fd6427114cb9ac233f584eca
  Complete Local Name = axon_33
---------------
Device ac:23:3f:58:4f:fd (public), RSSI=-86 dB
  Flags = 06
  Manufacturer = 4c000215fda50693a4e24fb1afcfc6eb0764782527114cb9c5
  Tx Power = ec
  Complete 16b Services = 0000fda5-0000-1000-8000-00805f9b34fb
  16b Service Data = a5fd6427114cb9ac233f584ffd
  Complete Local Name = axon_71

目前需求需要让设备持续扫描一段时间,将所有的蓝牙信息上报,为防止扫描遗漏,故需扫描时间延长到几十秒以上。

但发现若扫描时间过长,会报bluepy.btle.BTLEDisconnectError: Device disconnected错误。原因是某个蓝牙设备的断开而使程序发生错误了,于是想到开启额外线程循环扫描,每次扫描时间设为5秒,代码如下:

  • 循环扫描
from bluepy.btle import Scanner, DefaultDelegate
from multiprocessing import Process, Event
class ScanDelegate(DefaultDelegate):
    def __init__(self):
        DefaultDelegate.__init__(self)
    def handleDiscovery(self, dev, isNewDev, isNewData):
        if isNewDev:
            print("Discovered device", dev.addr)
        elif isNewData:
            print("Received new data from", dev.addr)
class BLEScanner:
    def __init__(self):
        self.scanner = Scanner().withDelegate(ScanDelegate())
        self.stop_event = Event()
    def start(self):
        self.stop_event.clear()
        self.process = Process(target=self.scan, args = ())
        self.process.start()
        return self
    def scan(self):
        while True:
            if self.stop_event.is_set():
                return
            self.devices = self.scanner.scan(5, passive=True)
    def stop(self):
        self.stop_event.set()
BLEScanner().start()


后续只要将mac地址扔到set集合中,收集一段时间后上报就行了。