python扫描蓝牙
in 树莓派 with 0 comment 78 views

python扫描蓝牙

in 树莓派 with 0 comment 78 views

环境

树莓派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错误。原因是某个蓝牙设备的断开而使程序发生错误了,于是想到开启额外线程循环扫描,每次扫描时间设为10秒,代码如下:

#!/usr/bin/python3

import threading
import time
from bluepy.btle import Scanner, DefaultDelegate
import requests
import json

macSet = set()

class ScanDelegate(DefaultDelegate):
    def __init__(self):
        DefaultDelegate.__init__(self)

    def handleDiscovery(self, dev, isNewDev, isNewData):
        macSet.add(dev.addr)


class ScanBluetooth(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        
    def run(self):        
        scanner = Scanner().withDelegate(ScanDelegate())
        while True:
            try:
                devices = scanner.scan(10.0)
            except BaseException:
                pass

class Poster(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
    
    def run(self):
        global macSet
        while True:
            try:
                time.sleep(60)
                macAddressList = list(macSet)
                macSet = set()
                
                url = "http://192.168.0.210:8988/gate/scanData"
                data = {"gate":"SouthGate","macAddressList":macAddressList}
                headers = {"Content-Type":"application/json"}
                
                res = requests.post(url = url,data = json.dumps(data),headers = headers)
                print(res)
            except BaseException:
                pass


# 创建新线程
scanBluetooth = ScanBluetooth()
poster = Poster()

# 开启新线程
scanBluetooth.start()
poster.start()
scanBluetooth.join()
poster.join()
print ("退出主线程")

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

Responses