我用python中的Bluez(5.49版)编写了一个程序.目标是发送广告包(IBeacon),并使用嗅探器将其解包并保存主要、次要和RSSI(如果UUID是正确的).主要值和次要值是用于发送数据的广告频道.

首先,我使用两个模块Sena Parani-UD100.一个人发送信息,另一个人接收信息.接收器工作得非常好,我用手机上的一个应用程序测试了它,该应用程序可以发送广告包裹,它可以让它们非常迅速地完成我预期的接收包裹的操作.

所以当我用另一个模块发送信息时,问题来了,它每秒只发送一次广告包(实际上,大约1.3-1.4秒),我不知道问题出在哪里,为什么要花那么多时间.

以下是我的代码:


import sys
import argparse
import os
import signal
import time
import struct
import bluetooth._bluetooth as bluez
import blescan
import random
import re

# Configurable parameters
intervalm = 1000
intervalM = 1000
tx = -55

# HCI BLE CORE COMMANDS
LE_META_EVENT = 0x3e
LE_PUBLIC_ADDRESS=0x00
LE_RANDOM_ADDRESS=0x01
LE_SET_SCAN_PARAMETERS_CP_SIZE=7
OGF_LE_CTL=0x08
OCF_LE_SET_SCAN_PARAMETERS=0x000B
OCF_LE_SET_SCAN_ENABLE=0x000C
OCF_LE_CREATE_CONN=0x000D
OCF_LE_SET_ADVERTISING_PARAMETERS=0x0006
OCF_LE_SET_ADVERTISING_DATA=0x0008
OCF_LE_SET_ADVERTISE_ENABLE=0x000A
OCF_LE_SET_RANDOM_MAC=0x0005

LE_ROLE_MASTER = 0x00
LE_ROLE_SLAVE = 0x01

# these are actually subevents of LE_META_EVENT
EVT_LE_CONN_COMPLETE=0x01
EVT_LE_ADVERTISING_REPORT=0x02
EVT_LE_CONN_UPDATE_COMPLETE=0x03
EVT_LE_READ_REMOTE_USED_FEATURES_COMPLETE=0x04

# Advertisment event types
ADV_IND=0x00
ADV_DIRECT_IND=0x01
ADV_SCAN_IND=0x02
ADV_NONCONN_IND=0x03
ADV_SCAN_RSP=0x04


def randomMAC():
    return [ 0x1A, 0x3A, 0x3e,
        random.randint(0x00, 0x7f),
        random.randint(0x00, 0xff),
    random.randint(0x00, 0xff)]


def macCanal():
    return [0x11,0x11,0x11,0x11,0x11,0x11]


def printpacket(pkt):
    for c in pkt:
        sys.stdout.write("%02x " % struct.unpack("B",c)[0])


def hci_le_set_advertising_parameters(sock, interval_min, interval_max, canal):

    min1 = interval_min/0.625
    max1 = interval_max/0.625

    if canal == 37:
        advertising_channel_map = 0x01  # 0b00000001
    elif canal == 38:
        advertising_channel_map = 0x02  # 0b00000010
    elif canal == 39:
        advertising_channel_map = 0x04  # 0b00000100
    else:
        advertising_channel_map = 0x07  # Other channels

    cmd_pkt = struct.pack("<HHBBBBBB", int(min1), int(max1), ADV_NONCONN_IND, 0x00, 0x00, 0x00, advertising_channel_map, 0x00)
    bluez.hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_ADVERTISING_PARAMETERS, cmd_pkt)


def hci_le_set_advertising_data(sock, minor, major, txpower):

    min = minor
    print("Minor:", min)
    maj = major
    print("major: ", maj)

    tx = txpower
    print("tx power: ", tx)
    #uu = uuid.uuid4().hex
    uu="11111111111111111111111111111002"
    print ("UUID: ", uu)
    uui = re.findall('.{1,2}', uu) 
    txp = struct.pack(">h", int(tx))
    txup = struct.unpack("<h", txp)
    cmd_pkt = struct.pack(">BBBBBBBBBBBBBBBBBBBBBBBBBBHHh", 0x1E, 0x02, 0x01, 0x1A, 0x1A, 0xFF, 0x4C, 0x00, 0x02, 0x15, int(uui[0], 16), int(uui[1], 16), int(uui[2], 16), int(uui[3], 16), int(uui[4], 16), int(uui[5], 16), int(uui[6], 16), int(uui[7], 16), int(uui[8], 16), int(uui[9], 16), int(uui[10], 16), int(uui[11], 16), int(uui[12], 16), int(uui[13], 16), int(uui[14], 16), int(uui[15], 16), int(min), int(maj), int(txup[0]))
    bluez.hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_ADVERTISING_DATA, cmd_pkt)


def hci_enable_le_advertise(sock):
    hci_toggle_le_advertise(sock, 0x01)

def hci_disable_le_advertise(sock):
    hci_toggle_le_advertise(sock, 0x00)

def hci_toggle_le_advertise(sock, enable):
    cmd_pkt = struct.pack("<B", enable)
    bluez.hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_ADVERTISE_ENABLE, cmd_pkt)

def hci_set_random_mac(sock, canal):
    mac = macCanal() #BREAKPOINT#################
    if canal == 37:
        print(canal)
        cmd_pkt = struct.pack("<BBBBBB", 55, mac[4], mac[3], mac[2], mac[1], mac[0])
        bluez.hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_RANDOM_MAC, cmd_pkt)
    elif canal == 38:
        print(canal)
        cmd_pkt = struct.pack("<BBBBBB", 56, mac[4], mac[3], mac[2], mac[1], mac[0])
        bluez.hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_RANDOM_MAC, cmd_pkt)
    elif canal == 39:
        print(canal)
        cmd_pkt = struct.pack("<BBBBBB", 57, mac[4], mac[3], mac[2], mac[1], mac[0])
        bluez.hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_RANDOM_MAC, cmd_pkt)
    else:
        print("Tres canales")
        cmd_pkt = struct.pack("<BBBBBB", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0])
        bluez.hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_RANDOM_MAC, cmd_pkt)

########################################################################################################################


def showAdapters():
    os.system("sudo hcitool dev")


def signal_handler(signal, frame):
    print("You pressed Ctrl+C")
    blescan.hci_disable_le_advertise(sock)
    sys.exit(0)


signal.signal(signal.SIGINT, signal_handler)
parser = argparse.ArgumentParser()
parser.add_argument("-i","--id", type=int, help="device id")
parser.add_argument("-d", "--devices", action="store_true", help="Show devices")
parser.add_argument("-t","--tx", type=int, help="Tx power")
parser.add_argument("-u","--intervalm", type=int, help="Interval min")
parser.add_argument("-U","--intervalM", type=int, help="Interval max")
parser.add_argument("-s","--sleep", type=int, help="Sleep time")
args = parser.parse_args()


if args.sleep == None:
    sleep = 1
else:
    sleep = args.sleep

if args.intervalm == None:
    intervalm = intervalm
else:
    intervalm = args.intervalm

if args.intervalM == None:
        intervalM = intervalM
else:
        intervalM = args.intervalM

if intervalM < intervalm:
    print("Max interval is smaller than min interval.")
    sys.exit(2)

if args.tx == None:
        tx = tx
else:
        tx = args.tx

if args.id == None:
    args.id = 1

if args.devices:
    showAdapters()
    sys.exit(2)


try:
    sock = bluez.hci_open_dev(args.id)
    print("ble thread started")
except:
    print("error accessing bluetooth device")
    sys.exit(1)


channel = 37  # First advertisement channel
while True:
    blescan.hci_set_random_mac(sock, channel)
    blescan.hci_le_set_advertising_parameters(sock, int(intervalm), int(intervalM), channel)
    blescan.hci_le_set_advertising_data(sock, channel, channel, int(tx))
    blescan.hci_enable_le_advertise(sock)
    time.sleep(1)
    if channel == 39:
        channel = 37
        blescan.hci_disable_le_advertise(sock)
    else:
        channel = channel + 1
        blescan.hci_disable_le_advertise(sock)

请注意,当我在启用广告后将程序置于Hibernate 状态时,在这段时间内必须发送许多包,但它只发送一个.

在BLE中,我try 每秒发送多个包裹,这是BLE中常见的广告流程,但它每秒只发送一个,所以我试图优化代码,并try 修改包裹和接收器中的过滤器,认为问题出在接收器中,但这些都不起作用.经过多次商议,我最终得出结论,问题出在emits 器上,对我来说,代码是正确的.还有人机界面命令的功能,所以我不知道问题出在哪里.

推荐答案

问题可能出在emits 机这一端.您可以使用Bluez HCI命令来try 增加广告费率,如我的答案here所示(使用hcitool命令的shell 脚本,对不起,但是您应该能够将其应用于Python).

sudo hcitool -i hci0 cmd 0x08 0x0006 A0 00 A0 00 03 00 00 00 00 00 00 00 00 07 00

[The]hcitool命令(0x08 0x0006)是"le set Advertising" 参数.前两个字节A00是"最小间隔".这个 后两个字节A00是"最大间隔".在本例中,它 将广告间隔时间设置为100ms.它的粒度 设置为0.625ms,因此将间隔设置为01 00会设置 广告每隔0.625毫秒一次.将其设置为A00将设置 广告每隔0xA0*0.625毫秒=100毫秒.

不同的BLE平台支持不同的广告费率(1赫兹、10赫兹或更高),因此有可能在硬件方面受到限制.要在排除接收器任何问题的同时测试这一点,最简单的方法是使用移动应用程序来测量接收率.我会推荐我的Android版BeaconScope应用程序,它提供了这些统计数据.(也有iOS版本,但iOS无法测量iBeacon的数据包接收率,因为API将检测限制为每秒一次.)

Python-3.x相关问答推荐

是否可以使用参数对Flask重定向?

数据类对象列表的字典获取方法-在数据类列表中查找具有特定变量值的数据类

无法使用Python发送带有参数和标头的POST请求

将列表转换为 pandas 数据框,其中列表包含字典

Django 模型类方法使用错误的 `self`

Django - ValueError:无法将字符串转换为浮点数:''

提高时间复杂度的一些建议

以不规则频率识别数据框日期时间列上缺失的日期,并用关联值填充它们

将两列合并为一列,将它们制成字典 - pandas - groupby

使用 pandas 进行多类分类的总体准确度

Pandas 值列中列表中元素的计数

每个数据行中每个数据帧值的总和

Tkinter IntVar 返回 PY_VAR0 而不是值

二进制文件的 Python 3 和 base64 编码

使用自定义比较删除重复项

Python中调用者函数的访问变量

混合全局/参数和名为top的函数的奇怪python行为

导入父目录进行简要测试

matplotlib - 模块sip没有属性setapi

如何避免使用我的 python 包构建 C 库?