广播 100ms 间隔高速率
import bluetooth, struct
#汉字一个3B,注意 最大8个汉字 100ms 广播高速率
def ble_name(dev_name):
if len(dev_name)>26:
return False
ble = bluetooth.BLE()
ble.active(False)
ble.active(True)
adv_data = struct.pack('BBB', 0x02, 0x01, 0x06)
name_bytes = dev_name.encode()
adv_data += struct.pack('B', 1 + len(name_bytes)) + b'\x09' + name_bytes
ble.gap_advertise(None)
ble.gap_advertise(100000, adv_data)
print("广播启动,名称:", dev_name," 长度:",len(dev_name))
return True
扫描 1s 定时版
from micropython import const
import bluetooth
import time
# 常量定义
_IRQ_SCAN_RESULT = const(5)
AD_TYPE_NAME_COMPLETE = const(0x09)
AD_TYPE_NAME_SHORT = const(0x08)
ble = bluetooth.BLE()
device_set = set()
def _parse_name(adv_data):
i = 0
while i < len(adv_data):
ad_len = adv_data[i]
if ad_len == 0:
break
ad_type = adv_data[i+1]
payload = adv_data[i+2:i+1+ad_len]
if ad_type in (AD_TYPE_NAME_COMPLETE, AD_TYPE_NAME_SHORT):
try:
return payload.decode("utf-8").strip()
except:
return "Unreadable"
i += ad_len + 1
return "NoName"
def _scan_callback(event, data):
global device_set
if event == _IRQ_SCAN_RESULT:
_, _, _, _, adv_data = data
name = _parse_name(bytes(adv_data))
device_set.add(name)
def scan_ble_devices():
"""
阻塞扫描1秒,返回周围蓝牙设备名称列表(去重)
return: list[str]
"""
global device_set
device_set.clear()
# 初始化蓝牙与回调
ble.active(True)
ble.irq(_scan_callback)
# 扫描时长1000ms,高速抓包参数
ble.gap_scan(1000, 30000, 28000, 1)
# 阻塞等待最多1秒
t_start = time.ticks_ms()
while time.ticks_diff(time.ticks_ms(), t_start) < 1000:
pass
# 停止扫描、关闭蓝牙
ble.gap_scan(None)
ble.active(False)
# 转列表返回
return list(device_set)
# 调用示例
if __name__ == "__main__":
names = scan_ble_devices()
print("扫描到蓝牙设备:")
for n in names:
print("-", n)
#返回
#names = scan_ble_devices()
后台版本
开启服务 start_background_full_scan()然后返回扫描的设备列表 scan_ble_devices()
from micropython import const
import bluetooth
import time
# BLE常量
_IRQ_SCAN_RESULT = const(5)
AD_TYPE_NAME_COMPLETE = const(0x09)
AD_TYPE_NAME_SHORT = const(0x08)
ble = bluetooth.BLE()
# 存储结构 {设备名称: 最后收到广播时间戳}
dev_cache = dict()
SCAN_RUNNING = False
# 设备超时时间:1500ms未收到广播判定离开
DEV_TIMEOUT = 1500
def _parse_name(adv_data):
"""解析广播包中的蓝牙设备名称"""
idx = 0
data_len = len(adv_data)
while idx < data_len:
ad_len = adv_data[idx]
if ad_len == 0:
break
ad_type = adv_data[idx + 1]
payload = adv_data[idx + 2 : idx + 1 + ad_len]
if ad_type in (AD_TYPE_NAME_COMPLETE, AD_TYPE_NAME_SHORT):
try:
return payload.decode("utf-8").strip()
except Exception:
return "Unreadable_Device"
idx += ad_len + 1
return "No_Name"
def ble_irq_callback(event, data):
global dev_cache
if event == _IRQ_SCAN_RESULT:
_, _, _, _, adv_data = data
dev_name = _parse_name(bytes(adv_data))
now = time.ticks_ms()
# 更新该设备最后活跃时间
dev_cache[dev_name] = now
def start_background_full_scan():
"""启动后台永久高速扫描,匹配100ms间隔信标"""
global SCAN_RUNNING
if SCAN_RUNNING:
return
ble.active(True)
ble.irq(ble_irq_callback)
# gap_scan(永久扫描0, 扫描周期100000us=100ms, 监听窗口90000us=90ms, 主动扫描1)
ble.gap_scan(0, 100000, 90000, 1)
SCAN_RUNNING = True
print("后台BLE扫描已启动 | 适配100ms间隔蓝牙信标")
def scan_ble_devices():
"""
对外调用接口:瞬间返回当前在场蓝牙设备名称列表
自动清理超时消失的设备,无阻塞
return: list[str]
"""
global dev_cache
if not SCAN_RUNNING:
return []
now = time.ticks_ms()
# 过滤超时设备
valid_devs = []
for name, last_tick in dev_cache.items():
if time.ticks_diff(now, last_tick) < DEV_TIMEOUT:
valid_devs.append(name)
return valid_devs
def stop_ble_scan():
"""停止扫描、关闭蓝牙,程序结束时调用"""
global SCAN_RUNNING
if not SCAN_RUNNING:
return
ble.gap_scan(None)
ble.active(False)
SCAN_RUNNING = False
dev_cache.clear()
print("BLE扫描已关闭")
------------------- 测试示例 -------------------
if __name__ == "__main__":
# 程序启动只执行一次,开启后台扫描
start_background_full_scan()
# 循环读取设备列表,随便高频调用无压力
while True:
dev_list = scan_ble_devices()
print("==== 在场蓝牙设备 ====")
if len(dev_list) == 0:
print("无设备")
else:
for name in dev_list:
print("-", name)
# time.sleep_ms(500)