ble - 低功耗蓝牙
作者:王世豪
一、概述
1.1 模式解释
外围设备模式(peripheral), 设备会被扫描到, 并且可以被连接;
中心设备模式(central), 设备会扫描其他设备, 并且可以连接其他设备;
广播者模式(ibeacon), 设备会周期性的广播 beacon 信息, 可以被扫描到, 但一般不会被连接;
观察者模式(scan), 设备会扫描其他设备, 但不会连接其他设备。
1.2 蓝牙中的重要概念
1、GATT(通用属性配置文件)
定义 BLE 设备如何组织和传输数据,以 “服务(Service)” 和 “特征(Characteristic)” 为单位。
示例:心率监测设备的 GATT 服务包含 “心率特征”,手机通过读取该特征获取心率数据。
2、服务和特征
服务是特征的容器,通过逻辑分组简化复杂功能的管理;
特征是数据交互的最小单元,通过属性定义实现灵活的读写与推送机制;
两者结合构成 GATT 协议的核心框架,支撑蓝牙设备间的标准化数据交互(如智能穿戴、医疗设备、物联网传感器)。
3、特征的关键属性(Properties)
特征通过"属性"定义数据的操作方式。从 GATT 通信角色看:
服务端(通常为外围设备):存储特征值的数据提供方
客户端(通常为中心设备):操作特征值的数据消费方
常见属性包括:
1)可读(Read):允许客户端读取服务端的特征值(如手机读取手环的电量)。
2)可写(Write):允许客户端向服务端写入特征值(如手机设置设备的参数)。
3)通知(Notify):服务端主动向客户端推送特征值更新(如手环向手机推送心率数据)。
4、UUID
UUID 是蓝牙 GATT 协议的 “数字身份证”,通过标准化的唯一标识机制,实现了跨厂商设备的功能互认(标准 UUID)与厂商个性化功能的扩展(自定义 UUID)
注: 一个蓝牙设备可以包含多个服务(Service),每个服务由一个 UUID 唯一标识。 每个服务可以包含多个特征(Characteristic),每个特征也由一个 UUID 唯一标识。 特征是最小的数据单元,我们通过读写特征来与设备交互。
1.3 四种模式的基本流程
1.3.1 外围设备模式(peripheral)的基本流程(概要描述)
1、初始化蓝牙框架
bluetooth_device = bluetooth.init()
2、创建 BLE 对象
local ble_device = bluetooth_device:ble(ble_callback)
3、创建 GATT 描述
local att_db = {xxx}
4、创建广播信息
ble_device:adv_create(adv_data)
5、开始广播
ble_device:adv_start()
6、等待连接
7、在回调函数中处理连接事件, 如接收数据, 发送数据等
1.3.2 中心设备模式(central)的基本流程(概要描述)
1、初始化蓝牙框架
bluetooth_device = bluetooth.init()
2、创建 BLE 对象
local ble_device = bluetooth_device:ble(ble_callback)
3、扫描目标 BLE 设备
ble_device:scan_start()
4、建立与目标设备的连接
ble_device:connect(mac, add_type)
5、处理各类 BLE 事件(连接、断开连接、扫描报告、GATT 操作完成等)
1.3.3 广播者模式(ibeacon)的基本流程(概要描述)
1、初始化蓝牙底层框架
bluetooth_device = bluetooth.init()
2、创建 BLE 对象
local ble_device = bluetooth_device:ble(ble_callback)
3、配置 ibeacon 广播数据包
包含厂商特定数据格式,ibeacon 类型标识符,设置UUID、Major、Minor等关键参数
4、启动 BLE 广播功能
ble_device:adv_start()
1.3.4 观察者模式(scan)的基本流程(概要描述)
1、初始化蓝牙框架
bluetooth_device = bluetooth.init()
2、创建 BLE 对象
local ble_device = bluetooth_device:ble(ble_callback)
3、开始扫描
ble_device:scan_start()
4、在回调函数中处理扫描事件, 如接收设备信息等
5、按需停止扫描
ble_device:scan_stop()
1.4 应用场景
1.4.1 外围设备 + 中心设备(连接模式)
设计框图:
1.4.2 广播者 + 观察者(无连接模式)
设计框图:
二、核心示例
-
核心示例是指:使用本库文件提供的核心 API,开发的基础业务逻辑的演示代码;
-
核心示例的作用是:帮助开发者快速理解如何使用本库,所以核心示例的逻辑都比较简单;
-
更加完整和详细的 demo,请参考 LuatOS 仓库 中各个产品目录下的 demo/ble;
2.1 中心设备模式(central)的核心示例
-- 重启BLE扫描的函数
local function restart_ble_scan(device)
device:scan_start()
end
-- 蓝牙事件回调函数
local function ble_callback(ble_device, ble_event, ble_param)
if ble_event == ble.EVENT_CONN then
log.info("ble", "connect 成功")
elseif ble_event == ble.EVENT_DISCONN then
log.info("ble", "disconnect", ble_param.reason)
sys.timerStart(restart_ble_scan, 1000, ble_device)
elseif ble_event == ble.EVENT_WRITE then
log.info("ble", "write", ble_param.handle,ble_param.uuid_service:toHex(),ble_param.uuid_characteristic:toHex())
log.info("ble", "data", ble_param.data:toHex())
elseif ble_event == ble.EVENT_READ_VALUE then
log.info("ble", "read", ble_param.handle,ble_param.uuid_service:toHex(),ble_param.uuid_characteristic:toHex(),ble_param.data:toHex())
elseif ble_event == ble.EVENT_SCAN_REPORT then
print("ble scan report",ble_param.addr_type,ble_param.rssi,ble_param.adv_addr:toHex(),ble_param.data:toHex())
-- 注意, 这里是连接到另外一个设备, 设备名称带LuatOS字样
if ble_param.addr_type == 0 and ble_param.data:find("LuatOS") then
log.info("ble", "停止扫描, 连接设备", ble_param.adv_addr:toHex(), ble_param.addr_type)
ble_device:scan_stop()
scan_count = 0
ble_device:connect(ble_param.adv_addr,ble_param.addr_type)
end
scan_count = scan_count + 1
if scan_count > 100 then
log.info("ble", "扫描次数超过100次, 停止扫描, 5秒后重新开始")
scan_count = 0
ble_device:scan_stop()
sys.timerStart(function() ble_device:scan_start() end, 5000)
end
elseif ble_event == ble.EVENT_GATT_ITEM then
-- 读取GATT完成, 打印出来
log.info("ble", "gatt item", ble_param[1]:toHex(), #ble_param)
elseif ble_event == ble.EVENT_GATT_DONE then
log.info("ble", "gatt done", ble_param.service_num)
local wt = {uuid_service = string.fromHex("FA00"), uuid_characteristic = string.fromHex("EA01")}
ble_device:notify_enable(wt, true) -- 开启通知
-- 主动写入数据, 但不带通知, 带通知是 write_notify
local wt = {uuid_service = string.fromHex("FA00"), uuid_characteristic = string.fromHex("EA02")}
ble_device:write_value(wt,string.fromHex("1234"))
-- 主动读取数据
local wt = {uuid_service = string.fromHex("FA00"), uuid_characteristic = string.fromHex("EA03")}
ble_device:read_value(wt)
elseif ble_event == ble.EVENT_SCAN_STOP then
log.info("ble", "scan stop")
end
end
local function ble_central_task_func()
log.info("开始初始化蓝牙核心")
bluetooth_device = bluetooth.init()
log.info("初始化BLE功能")
ble_device = bluetooth_device:ble(ble_callback)
ble_device:scan_create({})
ble_device:scan_start()
end
-- 启动蓝牙初始化任务
sys.taskInit(ble_central_task_func)
2.2 外围设备模式(peripheral)的核心示例
-- 重新开始广播
local function restart_ble_adv(device)
device:adv_start()
end
local att_db = { -- Service
string.fromHex("FA00"), -- Service UUID
-- Characteristic
{ -- Characteristic 1
string.fromHex("EA01"), -- Characteristic UUID Value
ble.NOTIFY | ble.READ | ble.WRITE -- Properties
}, { -- Characteristic 2
string.fromHex("EA02"), ble.WRITE
}, { -- Characteristic 3
string.fromHex("EA03"), ble.READ
}, { -- Characteristic 4
string.fromHex("EA04"), ble.IND | ble.READ
}
}
local function ble_callback(ble_device, ble_event, ble_param)
if ble_event== ble.EVENT_CONN then
ble_stat = true
elseif ble_event== ble.EVENT_DISCONN then
log.info("ble", "disconnect")
ble_stat = false
-- 1秒后重新开始广播
sys.timerStart(restart_ble_adv, 1000, ble_device)
elseif ble_event== ble.EVENT_WRITE then
-- 收到写请求
log.info("ble", "接收到写请求", ble_param.uuid_service:toHex(), ble_param.uuid_characteristic:toHex(), ble_param.data:toHex())
end
end
local function ble_peripheral_task_func()
log.info("开始初始化蓝牙核心")
bluetooth_device = bluetooth.init()
log.info("初始化BLE功能")
ble_device = bluetooth_device:ble(ble_callback)
log.info('开始创建GATT')
ret = ble_device:gatt_create(att_db)
log.info("创建的GATT", ret)
log.info("开始设置广播内容")
ble_device:adv_create({
addr_mode = ble.PUBLIC,
channel_map = ble.CHNLS_ALL,
intv_min = 120,
intv_max = 120,
adv_data = {
{ble.FLAGS, string.char(0x06)},
{ble.COMPLETE_LOCAL_NAME, "LuatOS123"},
{ble.SERVICE_DATA, string.fromHex("FE01")},
{ble.MANUFACTURER_SPECIFIC_DATA, string.fromHex("05F0")}
}
})
log.info("开始广播")
ble_device:adv_start()
-- 放入预设值, 注意是有READ属性的特性才能读取
-- 手机APP设置MTU到256
local wt = {
uuid_service = string.fromHex("FA00"),
uuid_characteristic = string.fromHex("EA01"),
}
ble_device:write_value(wt, "12345678901234567890")
end
-- 启动蓝牙初始化任务
sys.taskInit(ble_peripheral_task_func)
2.3 广播者模式(ibeacon)的核心示例
function ble_ibeacon_task_func()
log.info("开始初始化蓝牙核心")
bluetooth_device = bluetooth.init()
log.info("初始化BLE功能")
ble_device = bluetooth_device:ble(ble_callback)
log.info("开始设置广播内容")
local adv_data1 = string.char(0x4C, 0x00, -- Manufacturer ID(2字节)
0x02, 0x15, -- ibeacon数据类型(2字节)
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, -- UUID(16字节)
0x00, 0x01, -- Major(2字节)
0x00, 0x02, -- Minor(2字节)
0xC0) -- Signal Power(1字节)
ble_device:adv_create({
addr_mode = ble.PUBLIC, -- 广播地址模式, 目前仅支持ble.PUBLIC
channel_map = ble.CHNLS_ALL, -- 广播的通道, 可选值: ble.CHNLS_37, ble.CHNLS_38, ble.CHNLS_39, ble.CHNLS_ALL
intv_min = 120, -- 广播间隔最小值, 单位为0.625ms, 最小值为20, 最大值为10240
intv_max = 120, -- 广播间隔最大值, 单位为0.625ms, 最小值为20, 最大值为10240
adv_data = { -- 支持表格形式, 也支持字符串形式(255字节以内)
{ble.FLAGS, string.char(0x06)},
{ble.COMPLETE_LOCAL_NAME, "1"},
{ble.MANUFACTURER_SPECIFIC_DATA, adv_data1}
}
})
log.info("开始广播")
ble_device:adv_start()
end
sys.taskInit(ble_ibeacon_task_func)
2.4 观察者模式(scan)的核心示例
local function ble_callback(ble_device, ble_event, ble_param)
if ble_event == ble.EVENT_SCAN_INIT then
log.info("ble", "scan init")
elseif ble_event == ble.EVENT_SCAN_REPORT then
log.info("ble", "scan report", ble_param.rssi, ble_param.adv_addr:toHex(), ble_param.data:toHex())
-- 解析广播数据, 日志很多, 按需使用
-- local adv_data = ble_device:adv_decode(ble_param.data)
-- if adv_data then
-- for k, v in pairs(adv_data) do
-- log.info("ble", "adv data", v.len, v.tp, v.data:toHex())
-- end
-- end
-- if ble_param.data:byte(1) == 0x1A then
-- log.info("ble", "ibeacon数据", ble_param.rssi, ble_param.adv_addr:toHex(), ble_param.data:toHex())
-- end
elseif ble_event == ble.EVENT_SCAN_STOP then
log.info("ble", "scan stop")
end
end
function ble_scan_task_func()
log.info("开始初始化蓝牙核心")
bluetooth_device = bluetooth.init()
log.info("初始化BLE功能")
ble_device = bluetooth_device:ble(ble_callback)
-- 扫描模式
ble_device:scan_create() -- 使用默认参数, addr_mode=0, scan_interval=100, scan_window=100
-- ble_device:scan_create(0, 10, 10) -- 使用自定义参数
log.info("开始扫描")
ble_device:scan_start()
end
sys.taskInit(ble_scan_task_func)
三、常量详解
核心库常量,顾名思义是由合宙LuatOS内核固件中定义的、不可重新赋值或修改的固定值,在脚本代码中不需要声明,可直接调用;
3.1 地址模式常量
3.1.1 ble.PUBLIC
常量含义:公共地址模式;
数据类型:number;
常量取值: 0;
注意事项:公共地址模式下,使用设备出厂时分配的MAC地址;
示例代码:-- 设置广播地址模式为公共地址
ble_device:adv_create({
addr_mode = ble.PUBLIC
})
3.2 特征属性常量
3.2.1 ble.READ
常量含义:特征可读属性;
数据类型:number;
常量取值:0x08;
注意事项:表示该特征支持读取操作;
示例代码:-- 创建一个可读特征
local att_db = { -- Service
string.fromHex("FA00"), -- Service UUID, 服务的UUID, 可以是16位、32位或128位
{
string.fromHex("EA01"), -- Characteristic UUID, 特征UUID,可以是16位、32位或128位
ble.READ -- 特征可读属性
}
}
ble_device:gatt_create(att_db)
3.2.2 ble.WRITE
常量含义:特征可写属性;
数据类型:number;
常量取值:0x10;
注意事项:表示该特征支持写入操作;
示例代码:-- 创建一个可写特征
local att_db = { -- Service
string.fromHex("FA00"), -- Service UUID, 服务的UUID, 可以是16位、32位或128位
{
string.fromHex("EA01"), -- Characteristic UUID, 特征UUID,可以是16位、32位或128位
ble.WRITE -- 特征可写属性
}
}
ble_device:gatt_create(att_db)
3.2.3 ble.NOTIFY
常量含义:特征通知属性;
数据类型:number;
常量取值:0x40;
注意事项:表示该特征支持通知功能,无需接收方确认;
示例代码:-- 创建一个支持通知的特征
local att_db = { -- Service
string.fromHex("FA00"), -- Service UUID, 服务的UUID, 可以是16位、32位或128位
{
string.fromHex("EA01"), -- Characteristic UUID, 特征UUID,可以是16位、32位或128位
ble.NOTIFY -- 特征通知属性
}
}
ble_device:gatt_create(att_db)
3.2.4 ble.IND
常量含义:特征指示属性;
数据类型:number;
常量取值:0x20;
注意事项:表示该特征支持指示功能,需要接收方确认;
示例代码:-- 创建一个支持指示的特征
local att_db = { -- Service
string.fromHex("FA00"), -- Service UUID, 服务的UUID, 可以是16位、32位或128位
{
string.fromHex("EA01"), -- Characteristic UUID, 特征UUID,可以是16位、32位或128位
ble.IND -- 特征指示属性
}
}
ble_device:gatt_create(att_db)
3.2.5 ble.WRITE_CMD
常量含义:特征写入无响应属性;
数据类型:number;
常量取值:0x80;
注意事项:表示该特征支持无需响应的写入操作;
示例代码:-- 创建一个支持无响应写入的特征
local att_db = { -- Service
string.fromHex("FA00"), -- Service UUID
{
string.fromHex("EA02"), -- Characteristic UUID, 特征UUID,可以是16位、32位或128位
ble.WRITE_CMD -- 特征写入无响应属性
}
}
ble_device:gatt_create(att_db)
3.3 事件类型常量
3.3.1 ble.EVENT_CONN
常量含义:连接成功事件;
数据类型:number;
常量取值:12;
注意事项:当BLE设备成功建立连接时触发;
示例代码:-- 在回调函数中处理连接成功事件
function ble_callback(ble_device, ble_event, ble_param)
if ble_event == ble.EVENT_CONN then
log.info("ble", "connect 成功", ble_param.addr:toHex())
end
end
3.3.2 ble.EVENT_DISCONN
常量含义:断开连接事件;
数据类型:number;
常量取值:13;
注意事项:当BLE设备连接断开时触发;
示例代码:-- 在回调函数中处理断开连接事件
function ble_callback(ble_device, ble_event, ble_param)
if ble_event == ble.EVENT_DISCONN then
log.info("ble", "disconnect", ble_param.reason)
end
end
3.3.3 ble.EVENT_WRITE
常量含义:收到写请求事件;
数据类型:number;
常量取值:15;
注意事项:当中心设备向外围设备的特征写入数据时(包括开启通知或指示功能),在外围设备端触发此事件;
示例代码:-- 在外围设备的回调函数中处理写请求_
-- 示例场景:手机APP设置手环闹钟_
-- 中心设备(手机)向外围设备(手环)的闹钟特征写入数据:"08:30"_
-- 外围设备触发此事件,解析数据并设置闹钟_
function ble_callback(ble_device, ble_event, ble_param)
if ble_event == ble.EVENT_WRITE then
log.info("ble", "接收到写请求", ble_param.data:toHex())
end
end
3.3.4 ble.EVENT_READ_VALUE
常量含义:读取操作完成事件;
数据类型:number;
常量取值:17;
注意事项:当中心设备主动读取外围设备的特征值完成时,在中心设备端触发此事件;
示例代码:-- 在中心设备的回调函数中处理读取完成事件_
-- 示例场景:读取手环电量_
-- 中心设备(手机)读取外围设备(手环)的电量特征(0x2A19)_
-- 读取完成后,手机触发此事件,获取电量百分比并显示_
function ble_callback(ble_device, ble_event, ble_param)
if ble_event == ble.EVENT_READ_VALUE then
log.info("ble", "读取操作完成", ble_param.data:toHex())
end
end
3.3.5 ble.EVENT_SCAN_REPORT
常量含义:扫描报告事件;
数据类型:number;
常量取值:11;
注意事项:当中心设备扫描到其他BLE设备的广播时触发;
示例代码:-- 在中心设备的回调函数中处理扫描报告事件
-- 示例场景:设备发现与连接_
-- 中心设备(手机)扫描周围的外围设备_
-- 每发现一个设备就触发此事件,可以显示设备列表供用户选择连接_
function ble_callback(ble_device, ble_event, ble_param)
if ble_evt == ble.EVENT_SCAN_REPORT then
log.info("ble", "scan report", ble_param.rssi, ble_param.adv_addr:toHex())
end
end
3.3.6 ble.EVENT_GATT_ITEM
常量含义:收到GATT项事件;
数据类型:number;
常量取值:18;
注意事项:当中心设备发现外围设备的GATT服务或特征时触发;
示例代码:-- 在中心设备的回调函数中处理GATT项事件,一般调试使用
function ble_callback(ble_device, ble_event, ble_param)
if ble_event == ble.EVENT_GATT_ITEM then
log.info("ble", "gatt item", ble_param[1]:toHex(), #ble_param)
end
end
3.3.7 ble.EVENT_GATT_DONE
常量含义:GATT操作完成事件;
数据类型:number;
常量取值:14;
注意事项:当中心设备完成外围设备的GATT服务发现后触发;
示例代码:-- 在中心设备的回调函数中处理GATT完成事件
-- 示例场景:设备就绪通知_
-- 中心设备(手机)完成对外围设备(手环)的GATT发现_
-- 触发此事件表示可以开始正常的数据交互(读取、写入、订阅)_
function ble_callback(ble_device, ble_event, ble_param)
if ble_event == ble.EVENT_GATT_DONE then
log.info("ble", "gatt done", ble_param.service_num)
end
end
3.3.8 ble.EVENT_SCAN_STOP
常量含义:扫描停止事件;
数据类型:number;
常量取值:9;
注意事项:当中心设备停止扫描BLE外围设备时触发;
示例代码:-- 在中心设备的回调函数中处理扫描停止事件
function ble_callback(ble_device, ble_event, ble_param)
if ble_event == ble.EVENT_SCAN_STOP then
log.info("ble", "scan stop")
end
end
3.4 广播相关常量
3.4.1 ble.COMPLETE_LOCAL_NAME
常量含义:完整本地名称;
数据类型:number;
常量取值:0x09:
注意事项:用于在广播数据中设置设备的完整名称;
示例代码:-- 在广播数据中设置设备名称
ble_device:adv_create({
adv_data = {
{ble.COMPLETE_LOCAL_NAME, "LuatOS"}
}
})
3.4.2 ble.CHNLS_ALL
常量含义:使用所有广播通道;
数据类型:number;
常量取值:0x07;
注意事项:表示使用蓝牙LE的所有三个广播通道(37, 38, 39);
示例代码:-- 设置使用所有广播通道
ble_device:adv_create({
channel_map = ble.CHNLS_ALL
})
3.4.3 ble.CHNL_37
常量含义:使用广播通道37;
数据类型:number;
常量取值:0x01;
注意事项:表示仅使用蓝牙LE的广播通道37;
示例代码:-- 设置仅使用广播通道37
ble_device:adv_create({
channel_map = ble.CHNL_37
})
3.4.4 ble.CHNL_38
常量含义:使用广播通道38;
数据类型:number;
常量取值:0x02;
注意事项:表示仅使用蓝牙LE的广播通道38;
示例代码:-- 设置仅使用广播通道38
ble_device:adv_create({
channel_map = ble.CHNL_38
})
3.4.5 ble.CHNL_39
常量含义:使用广播通道39;
数据类型:number;
常量取值:0x04;
注意事项:表示仅使用蓝牙LE的广播通道39;
示例代码:-- 设置仅使用广播通道39
ble_device:adv_create({
channel_map = ble.CHNL_39
})
3.4.6 ble.FLAGS
常量含义:广播标志位;
数据类型:number;
常量取值:0x01:
注意事项:用于在广播数据中设置设备的广播标志位;
示例代码:-- 在广播数据中设置广播标志位
ble_device:adv_create({
adv_data = {
{ble.FLAGS, string.char(0x06)}
}
})
3.4.7 ble.SERVICE_DATA
常量含义:服务数据;
数据类型:number;
常量取值:0x16;
注意事项:用于在广播数据中设置设备的服务数据;
示例代码:-- 在广播数据中设置服务数据
ble_device:adv_create({
adv_data = {
{ble.SERVICE_DATA, string.fromHex("FE01")}
}
})
3.4.8 ble.MANUFACTURER_SPECIFIC_DATA
常量含义:制造商特定数据;
数据类型:number;
常量取值:0xFF;
注意事项:用于在广播数据中设置设备的制造商特定数据;
示例代码:-- 在广播数据中设置制造商特定数据
ble_device:adv_create({
adv_data = {
{ble.MANUFACTURER_SPECIFIC_DATA, string.fromHex("05F0")}
}
})
四、函数详解
4.1 bluetooth.init()
功能
初始化蓝牙框架
注意事项
必须在使用蓝牙功能之前调用;
仅需要调用一次,若创建失败, 会返回nil, 请检查内存是否足够。
参数
无
返回值
local bluetooth_device = bluetooth.init()
bluetooth_device
含义说明:蓝牙对象;
数据类型:userdata/nil;
取值范围:创建成功返回userdata对象,失败返回nil;
注意事项:有返回nil的情况,需做好对应逻辑处理;
返回示例:成功返回:BLUETOOTH*: 0C7FD730
失败返回:nil
local bluetooth_device = bluetooth.init()
log.info("bluetooth_device", bluetooth_device)
示例
-- 初始化蓝牙
bluetooth_device = bluetooth.init()
if not bluetooth_device then
log.error("bluetooth", "init failed")
return
end
4.2 bluetooth_device:ble(ble_callback)
功能
创建一个BLE对象, 用于操作BLE设备
注意事项
必须在bluetooth.init()初始化成功后调用
参数
ble_callback
含义说明:BLE事件回调函数, 用于处理BLE设备的事件, 如连接、断开、接收数据等;
详细说明请参考本api中的示例部分。
数据类型:function;
取值范围:无;
是否必选:是;
注意事项:不同事件类型的param参数结构不同,需根据evt值进行相应处理;
参数示例:-- 创建回调函数处理BLE事件
function ble_callback(ble_device, ble_event, ble_param)
-- ble_device: BLE设备对象
-- ble_event: 事件类型(如ble.EVENT_CONN、ble.EVENT_DISCONN等)
-- ble_param: 事件相关参数,结构根据事件类型不同而变化
-- 具体事件类型及参数说明详见后续示例代码
end
返回值 local ble_device = bluetooth_device:ble(ble_callback)
ble_device
含义说明:BLE对象;
数据类型:userdata/nil;
取值范围:创建成功返回userdata对象,失败返回nil;
注意事项:后续所有BLE操作都依赖此对象,注意对象的生命周期管理;
有返回nil的情况,需做好对应逻辑处理。
返回示例:成功返回:BLE*: 0C7FCFA8
失败返回:nil
local ble_device = bluetooth_device:ble(ble_callback)
log.info("ble_device", ble_device )
示例
-- ble_callback 是自定义函数, 用于处理BLE事件
-- BLE事件回调函数, 回调时的参数如下:
function ble_callback(ble_device, ble_event, ble_param)
-- ble_device 是BLE设备对象, 可以通过dev:adv_create()等方法进行操作
-- ble_event 是BLE事件类型, 可以是以下几种:
-- ble.EVENT_CONN: 连接成功
-- ble_param是事件参数(table)包含以下字段:
-- ble_param.addr: 对端设备的地址(string), 6字节的二进制数据, 代表BLE设备的MAC地址
-- ble.EVENT_DISCONN: 断开连接
-- ble_param是事件参数(table), 包含以下字段:
-- ble_param.reason: 断开连接的原因(number)
-- ble.EVENT_WRITE: 收到写请求
-- ble_param是事件参数(table), 包含以下字段:
-- ble_param.uuid_service: 服务的UUID(string)
-- ble_param.uuid_characteristic: 特征的UUID_(string)
-- ble_param.uuid_descriptor: 描述符的UUID_(string), 可选, 不一定存在
-- ble_param.data: 写入的数据
-- ble.EVENT_READ_VALUE: 读取操作完成
-- ble_param是事件参数_(table), 包含以下字段:
-- ble_param.uuid_service: 服务的UUID(string)
-- ble_param.uuid_characteristic: 特征的UUID(string)
-- ble_param.uuid_descriptor: 描述符的UUID(string), 可选, 不一定存在
-- ble_param.data: 读取到的数据
-- ble.EVENT_SCAN_REPORT: 扫描到设备
-- ble_param是事件参数(table), 包含以下字段:
-- ble_param.rssi: 信号强度(number)
-- ble_param.adv_addr: 广播地址(string), 6字节的二进制数据
-- ble_param.data: 广播数据(string), 二进制数据
-- ble.EVENT_GATT_ITEM: 收到GATT项
-- ble_param是事件参数(table),为一个嵌套表结构,具体如下:
-- ble_param[1]: 服务的UUID(string), 二进制数据
-- ble_param[2...]: 特征值信息(table),每个都是一个子表
-- ble_param[索引][1]: 特征值的UUID(string), 二进制数据
-- ble_param[索引][2]: 特征值的属性(number), 表示读写权限等
-- ble.EVENT_GATT_DONE: GATT操作完成
-- ble_param是事件参数(table), 包含以下字段:
-- ble_param.service_num: 服务数量(number)
-- ble.EVENT_SCAN_STOP: 扫描停止
-- ble_param为nil
if ble_event == ble.EVENT_CONN then
log.info("ble", "connect 成功", ble_param, ble_paramand ble_param.addr and ble_param.addr:toHex() or "unknow")
ble_stat = true
elseif ble_event == ble.EVENT_DISCONN then
log.info("ble", "disconnect")
ble_stat = false
-- 1秒后重新开始广播
sys.timerStart(function() dev:adv_start() end, 1000)
elseif ble_event == ble.EVENT_SCAN_REPORT then
log.info("ble", "scan report", ble_param.rssi, param.adv_addr:toHex(), param.data:toHex())
elseif ble_event == ble.EVENT_WRITE then
log.info("ble", "接收到写请求", ble_param.uuid_service:toHex(), ble_param.uuid_characteristic:toHex(), ble_param.data:toHex())
elseif ble_event == ble.EVENT_READ_VALUE then
log.info("ble", "读取操作完成", ble_param.uuid_service:toHex(), ble_param.uuid_characteristic:toHex(), ble_param.data:toHex())
elseif ble_event == ble.EVENT_SCAN_STOP then
log.info("ble", "scan stop")
elseif ble_event == ble.EVENT_GATT_ITEM then
log.info("ble", "gatt item", ble_param[1]:toHex(), #ble_param)
elseif ble_event == ble.EVENT_GATT_DONE then
log.info("ble", "gatt done", ble_param.service_num)
end
end
-- 初始化蓝牙并创建BLE对象
bluetooth_device = bluetooth.init()
ble_device = bluetooth_device:ble(ble_callback)
4.3 ble_device:scan_create(addr_mode,scan_interval,scan_window)
功能
创建一个 BLE 扫描
注意事项
无
参数
addr_mode
含义说明:要扫描的广播地址模式
数据类型:number;
取值范围:可选值: 当前仅支持ble.PUBLIC
是否必选:否;
注意事项:默认值为ble.PUBLIC
参数示例:ble.PUBLIC
scan_interval
含义说明:扫描间隔
表示两次扫描事件之间的间隔时间;
数据类型:number;
取值范围:单位为0.625ms, 最小值为20, 最大值为10240
是否必选:否;
注意事项:默认值为100
参数示例:100
scan_window
含义说明:扫描窗口
是指 BLE 设备在扫描过程中,打开接收器去监听广播设备的时间段;
这个时间段是设备实际进行扫描操作的时间,也称为扫描事件的持续时间;
数据类型:number;
取值范围:单位为0.625ms, 最小值为20, 最大值为10240
是否必选:否;
注意事项:默认值为100,它的值必须小于或等于扫描间隔;
参数示例:100
返回值
local result = ble_device:scan_create(addr_mode,scan_interval,scan_window)
result
含义说明:是否创建成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示创建成功,false表示创建失败;
返回示例:成功返回:true
失败返回:false
local result = ble_device:scan_create(ble.PUBLIC, 100, 100)
log.info("result", result)
示例
-- 创建BLE扫描
ble_device:scan_create(ble.PUBLIC, 100, 100)
4.4 ble_device:scan_start()
功能
开始 BLE 扫描
注意事项
扫描会一直进行, 直到调用 ble.scan_stop()停止扫描;
扫描到结果会触发 ble.EVENT_SCAN_REPORT 事件,执行通过 bluetooth_device:ble(ble_callback)创建 BLE 对象时注册的回调函数;
扫描到同一个设备不会去重, 扫描到数据就会执行回调。
参数
无
返回值
local result = ble_device:scan_start()
result
含义说明:是否开始扫描成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示开始扫描成功,false表示开始扫描失败;
返回示例:成功返回:true
失败返回:false
local result = ble_device:scan_start()
log.info("result", result)
示例
-- 开始BLE扫描
ble_device:scan_start()
4.5 ble_device:scan_stop()
功能
停止 BLE 扫描
注意事项
扫描会一直进行, 直到调用 ble.scan_stop()停止扫描。
参数
无
返回值
local result = ble_device:scan_stop()
result
含义说明:是否停止扫描成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示停止扫描成功,false表示停止扫描失败;
返回示例:成功返回:true
失败返回:false
local result = ble_device:scan_stop()
log.info("result", result)
示例
-- 停止BLE扫描
ble_device:scan_stop()
4.6 ble_device:connect(mac, addr_type)
功能
发起 BLE 连接请求
注意事项
无
参数
mac
含义说明:目标蓝牙设备的MAC地址;
数据类型:string;
取值范围:有效的12个十六进制字符组成的蓝牙MAC地址字符串(如"AABBCCDDEEFF")
是否必选:是;
注意事项:MAC地址需要先使用string.fromHex()函数将十六进制字符串转换为二进制格式;
参数示例:-- MAC地址转换示例
local mac_hex = "AABBCCDDEEFF" -- 12位十六进制字符串
-- 转换为二进制格式:
local mac_bin = string.fromHex(mac_hex)
addr_type
含义说明:目标蓝牙设备的地址类型;
数据类型:number;
取值范围:可选值: 当前仅支持ble.PUBLIC;
是否必选:是;
注意事项:无;
参数示例:ble.PUBLIC
返回值
local result = ble_device:connect(mac, addr_type)
result
含义说明:是否成功发起连接请求;
真正的连接结果通过异步事件ble.EVENT_CONN通知到bluetooth_device:ble(ble_callback)中设置的回调函数ble_callback:
数据类型:boolean;
取值范围:true/false;
注意事项:true表示连接请求已成功发起,不代表连接已建立;
false表示发起连接请求失败;
返回示例:成功返回:true
失败返回:false
local result = ble_device:connect(mac, addr_type)
log.info("result", result)
示例
-- BLE连接
ble_device:connect(string.fromHex("C8478C4E027D"),0)
4.7 ble_device:disconnect()
功能
发起 BLE 断开连接请求
注意事项
无
参数
无
返回值
local result = ble_device:disconnect()
result
含义说明:是否成功发起断开连接请求;
真正的连接结果通过异步事件ble.EVENT_DISCONN通知到bluetooth_device:ble(ble_callback)中设置的回调函数ble_callback;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示断开连接请求已成功发起,不代表连接已被断开;
false表示发起断开连接请求失败;
返回示例:成功返回:true
失败返回:false
local result = ble_device:disconnect()
log.info("result", result)
示例
-- BLE断开连接
ble_device:disconnect()
4.8 ble_device:gatt_create(opts)
功能
创建一个 BLE GATT 服务
注意事项
确保 UUID 格式正确,且特征属性使用正确的权限常量;
特征属性必须是 ble.NOTIFY | ble.READ | ble.WRITE | ble.IND 的一种或多种组合;
参数
opts
含义说明:GATT服务的描述信息,包含服务UUID和其下所有特征的定义;
表的第一个元素:服务的UUID(通过string.fromHex转换的16位、32位或128位UUID)
表的后续元素:特征定义表(每个特征为一个子表),子表结构为:
第一个元素:特征的UUID(通过string.fromHex转换)
第二个元素:特征的属性(权限常量的组合,如ble.NOTIFY | ble.READ | ble.WRITE | ble.IND)
数据类型:table;
取值范围:符合上述结构的table对象;
是否必选:是;
注意事项:确保UUID格式正确,且特征属性使用正确的权限常量;
返回值
local result = ble_device:gatt_create(opts)
result
含义说明:是否创建GATT服务成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示创建GATT服务成功,false表示创建GATT服务失败;
返回示例:成功返回:true
失败返回:false
local result = ble_device:gatt_create(opts)
log.info("result", result)
示例
local att_db = { -- Service
string.fromHex("FA00"), -- Service UUID, 服务的UUID, 可以是16位、32位或128位
-- Characteristic
{ -- Characteristic 1
string.fromHex("EA01"), -- Characteristic UUID Value, 特征的UUID值, 可以是16位、32位或128位
ble.NOTIFY | ble.READ | ble.WRITE -- Properties, 对应蓝牙特征的属性, 参考权限常量
}, { -- Characteristic 2
string.fromHex("EA02"), ble.WRITE
}, { -- Characteristic 3
string.fromHex("EA03"), ble.READ
}, { -- Characteristic 4
string.fromHex("EA04"), ble.IND | ble.READ
}
}
ble_device:gatt_create(att_db)
4.9 ble_device:adv_create(opts)
功能
创建一个 BLE 广播
注意事项
无
参数
opts
含义说明:BLE广播配置参数表,包含广播的各种属性配置
addr_mode: 广播地址模式(可选值:ble.PUBLIC)
-- addr_mode可选值说明:
-- ble.PUBLIC - 公共地址(设备出厂时分配的固定MAC地址)
channel_map: 广播通道配置(可选值:ble.CHNL_37, ble.CHNL_38, ble.CHNL_39, ble.CHNLS_ALL)
-- channel_map可选值说明:
-- ble.CHNL_37 - 广播通道37
-- ble.CHNL_38 - 广播通道38
-- ble.CHNL_39 - 广播通道39
-- ble.CHNLS_ALL - 广播通道37、38、39
intv_min: 广播间隔最小值(单位:0.625ms,取值范围:20-10240)
intv_max: 广播间隔最大值(单位:0.625ms,取值范围:20-10240)
adv_data: 广播数据内容(支持表格形式和字符串形式,字符串形式不超过255字节)
数据类型:table;
取值范围:符合上述结构的table对象;
是否必选:是;
注意事项:注意参数根据实际情况填写
返回值
local result = ble:adv_create(opts)
result
含义说明:是否创建广播成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示创建广播成功,false表示创建广播失败;
返回示例:成功返回:true
失败返回:false
local result = ble:adv_create(opts)
log.info("result", result)
示例
-- 创建广播信息
ble_device:adv_create({
addr_mode = ble.PUBLIC, -- 广播地址模式, 可选值: ble.PUBLIC
channel_map = ble.CHNLS_ALL, -- 广播的通道, 可选值: ble.CHNL_37, ble.CHNL_38, ble.CHNL_39, ble.CHNLS_ALL
intv_min = 120, -- 广播间隔最小值, 单位为0.625ms, 最小值为20, 最大值为10240
intv_max = 120, -- 广播间隔最大值, 单位为0.625ms, 最小值为20, 最大值为10240
adv_data = { -- 支持表格形式, 也支持字符串形式(255字节以内)
{ble.FLAGS, string.char(0x06)},
{ble.COMPLETE_LOCAL_NAME, "LuatOS123"}, -- 广播的设备名
{ble.SERVICE_DATA, string.fromHex("FE01")}, -- 广播的服务数据
{ble.MANUFACTURER_SPECIFIC_DATA, string.fromHex("05F0")}
}
})
4.10 ble_device:adv_start()
功能
开始广播
注意事项
对于外围设备模式, 如果被断开了连接, 则需要重新开始广播, 才能被重新搜索到
参数
无
返回值
local result = ble_device:adv_start()
result
含义说明:是否开始广播成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示开始广播成功,false表示开始广播失败;
返回示例:成功返回:true
失败返回:false
local result = ble_device:adv_start()
log.info("result", result)
示例
-- 开始广播
ble_device:adv_start()
4.11 ble_device:adv_stop()
功能
主动停止广播
注意事项
无
参数
无
返回值
local result = ble_device:adv_stop()
result
含义说明:是否停止广播成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示停止广播成功,false表示停止广播失败;
返回示例:成功返回:true
失败返回:false
local result = ble_device:adv_stop()
log.info("result", result)
示例
-- 停止广播
ble_device:adv_stop()
4.12 ble_device:write_notify(opts,value)
功能
写入带通知的特征值
注意事项
外围设备使用,主动向中心设备发送通知数据
参数
opts
含义说明:写入特征值的配置参数表,包含服务UUID和特征值的UUID
uuid_service: 服务的UUID,用于标识要写入的特征值所属的服务
uuid_characteristic: 特征的UUID值,用于标识要写入的特征值
数据类型:table;
取值范围:符合上述结构的table对象;
是否必选:是;
注意事项:注意参数根据实际情况填写
value
含义说明:写入的特征值内容
数据类型:string;
取值范围:无特别限制
是否必选:是;
注意事项:注意参数根据实际情况填写
返回值
local result = ble_device:write_notify(opts,value)
result
含义说明:是否写入成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示写入成功,false表示写入失败;
返回示例:成功返回:true
失败返回:false
local result = ble_device:write_notify(opts,value)
log.info("result", result)
示例
-- 写入带通知的特征值
ble_device:write_notify({
uuid_service = "FA00", -- 服务的UUID, 可以是16位、32位或128位
uuid_characteristic = "EA01", -- 特征的UUID值, 可以是16位、32位或128位
}, "Hello BLE") -- 要写入的值
4.13 ble_device:write_indicate(opts,value)
功能
写入带指示的特征值
注意事项
外围设备使用,主动向中心设备发送指示数据
参数
opts
含义说明:写入特征值的配置参数表,包含服务UUID和特征值的UUID
uuid_service: 服务的UUID,用于标识要写入的特征值所属的服务
uuid_characteristic: 特征的UUID值,用于标识要写入的特征值
数据类型:table;
取值范围:符合上述结构的table对象;
是否必选:是;
注意事项:注意参数根据实际情况填写
value
含义说明:写入的特征值内容
数据类型:string;
取值范围:无特别限制
是否必选:是;
注意事项:注意参数根据实际情况填写
返回值
local result = ble:write_indicate(opts,value)
result
含义说明:是否写入成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示写入成功,false表示写入失败;
返回示例:成功返回:true
失败返回:false
local result = ble:write_indicate(opts,value)
log.info("result", result)
示例
-- 写入带指示的特征值
ble_device:write_indicate({
uuid_service = "FA00", -- 服务的UUID, 可以是16位、32位或128位
uuid_characteristic = "EA01", -- 特征的UUID值, 可以是16位、32位或128位
}, "Hello BLE") -- 要写入的值
4.14 ble_device:write_value(opts,value)
功能
写入特征值
注意事项
无
参数
opts
含义说明:写入特征值的配置参数表,包含服务UUID和特征值的UUID
uuid_service: 服务的UUID,用于标识要写入的特征值所属的服务
uuid_characteristic: 特征的UUID值,用于标识要写入的特征值
数据类型:table;
取值范围:符合上述结构的table对象;
是否必选:是;
注意事项:注意参数根据实际情况填写
value
含义说明:写入的特征值内容
数据类型:string;
取值范围:无特别限制
是否必选:是;
注意事项:注意参数根据实际情况填写
返回值
local result = ble_device:write_value(opts,value)
result
含义说明:是否写入成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示写入成功,false表示写入失败;
返回示例:成功返回:true
失败返回:false
local result = ble_device:write_value(opts,value)
log.info("result", result)
示例
-- 写入特征值,填充预设值,被动读取
ble_device:write_value({
uuid_service = "FA00", -- 服务的UUID, 可以是16位、32位或128位
uuid_characteristic = "EA01", -- 特征的UUID值, 可以是16位、32位或128位
}, "Hello BLE") -- 要写入的值
4.15 ble_device:read_value(opts)
功能
读取特征值
注意事项
无
参数
opts
含义说明:读取特征值的配置参数表,包含服务UUID和特征值的UUID;
uuid_service: 服务的UUID,用于标识要读取的特征值所属的服务;
uuid_characteristic: 特征的UUID值,用于标识要读取的特征值;
数据类型:table;
取值范围:符合上述结构的table对象;
是否必选:是;
注意事项:注意参数根据实际情况填写;
返回值
local result = ble_device:read_value(opts)
result
含义说明:是否读取成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示读取成功,false表示读取失败;
通过回调中的 EVENT_READ_VALUE 事件返回读取的value值;
返回示例:成功返回:true
失败返回:false
local result = ble_device:read_value(opts)
log.info("result", result)
示例
-- 读取特征值,通过回调中的 EVENT_READ_VALUE 事件返回读取的value值
ble_device:read_value({
uuid_service = "FA00", -- 服务的UUID, 可以是16位、32位或128位
uuid_characteristic = "EA01", -- 特征的UUID值, 可以是16位、32位或128位
})
4.16 ble_device:notify_enable(opts,enable)
功能
开关通知监听
注意事项
中心设备使用,配置是否接收外围设备发送的通知消息
参数
opts
含义说明:通知监听的配置参数表,包含服务UUID和特征值的UUID;
uuid_service: 服务的UUID,用于标识要通知监听的特征值所属的服务;
uuid_characteristic: 特征的UUID值,用于标识要通知监听的特征值;
数据类型:table;
取值范围:符合上述结构的table对象;
是否必选:是;
注意事项:注意参数根据实际情况填写;
enable
含义说明:通知监听的状态;;
数据类型:boolean;
取值范围:true/false;
是否必选:是;
注意事项:true表示开启通知监听,false表示关闭通知监听;
返回值
local result = ble_devie:notify_enable(opts,enable)
result
含义说明:是否开启通知监听成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示开启通知监听成功,false表示开启通知监听失败;
返回示例:成功返回:true
失败返回:false
local result = ble_devie:notify_enable(opts,enable)
log.info("result", result)
示例
ble_device:notify_enable({
uuid_service = "FA00", -- 服务的UUID, 可以是16位、32位或128位
uuid_characteristic = "EA01", -- 特征的UUID值, 可以是16位、32位或128位
}, true) -- 开/关
4.17 ble_device:indicate_enable(opts,enable)
功能
开关指示监听
注意事项
中心设备使用,配置是否接收外围设备发送的指示消息
参数
opts
含义说明:指示监听的配置参数表,包含服务UUID和特征值的UUID;
uuid_service: 服务的UUID,用于标识要指示监听的特征值所属的服务;
uuid_characteristic: 特征的UUID值,用于标识要指示监听的特征值;
数据类型:table;
取值范围:符合上述结构的table对象;
是否必选:是;
注意事项:注意参数根据实际情况填写;
enable
含义说明:指示监听的状态;
数据类型:boolean;
取值范围:true/false;
是否必选:是;
注意事项:true表示开启指示监听,false表示关闭指示监听;
返回值
local result = ble_device:indicate_enable(opts,enable)
result
含义说明:是否开启指示监听成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示开启指示监听成功,false表示开启指示监听失败;
返回示例:成功返回:true
失败返回:false
local result = ble_device:indicate_enable(opts,enable)
log.info("result", result)
示例
ble_device:indicate_enable({
uuid_service = "FA00", -- 服务的UUID, 可以是16位、32位或128位
uuid_characteristic = "EA01", -- 特征的UUID值, 可以是16位、32位或128位
}, true) -- 开/关
4.18 ble_device:adv_decode(data)
功能
解码广播数据
注意事项
广播数据通常来自于 ble.EVENT_SCAN_REPORT 事件的 ble_param.data
参数
data
含义说明:原始广播数据;
数据类型:string;
取值范围:广播数据的字符串表示;
是否必选:是;
注意事项:注意参数根据实际情况填写;
返回值
local adv_data = ble_device:adv_decode(data)
adv_data
含义说明:广播数据的解码结果,为table类型,表结构如下:
索引型表(索引从1开始);
每个索引对应一个子表,代表一个广告数据单元(AD Structure);
每个子表包含以下三个字段:
len :整数类型,表示数据长度
tp :整数类型,表示广播数据类型(AD Type)
data :字符串类型(二进制数据),表示广播数据内容
数据类型:table/nil;
取值范围:解码成功返回table对象,失败返回nil。
注意事项:返回的数据需要自行解析提取
返回示例:成功返回:table: 0C7F6570
失败返回:nil
local result = ble_device:adv_decode(data)
log.info("result", result)
示例
-- 解码广播数据
local adv_data = ble_device:adv_decode(ble_param.data)
-- 解析广播数据
if adv_data then
for k, v in pairs(adv_data) do
log.info("ble", "adv data", v.len, v.tp, v.data:toHex())
end
end
4.19 ble.mac()
功能
获取蓝牙 MAC
注意事项
无
参数
无
返回值
local mac = ble.mac
mac
含义说明:蓝牙MAC地址;
数据类型:string/nil;
取值范围:成功返回string,失败返回nil;
注意事项:成功返回6字节的二进制字符串,需要通过toHex()方法转换为可读的12个连续十六进制字符(如"AABBCCDDEEFF");
返回示例:成功返回:如果mac地址为"AABBCCDDEEFF",则返回6个字节长度的string数据;
第1个字节的ascii值为0xAA,后续5个字节的ascii值依次为0xBB, 0xCC, 0xDD, 0xEE, 0xFF
失败返回:nil
local mac = ble.mac()
log.info("原始二进制字符串", mac)
local mac_hex = mac:toHex()
log.info("转换成十六进制字符", mac_hex) -- 输出如:"AABBCCDDEEFF"
示例
-- 本函数于2025.8.29新增
local mac = ble.mac()
log.info("ble mac", mac and mac:toHex())
五、产品支持说明
适用于 Air8000,Air8000A,Air8000W,Air8000XB,Air8000U,Air8000WU,Air8000N,Air8000WN,以及 Air6101/Air8101 系列 此类支持蓝牙功能的产品。