模块: Bluetooth
约 6485 字大约 22 分钟
2026-03-18
构建固件和导入到JS
额外组件
该功能需要安装 beshell-bt 组件才能使用。
安装方法:
- 编辑项目根目录下的
idf_component.yml文件,添加依赖:
dependencies:
become-cool/beshell-bt: '>=1.0.10'- 或在 ESP-IDF 环境的命令行中执行:
idf.py add-dependency "become-cool/beshell-bt>=1.0.10"在 C++ 里加入以下代码, 然后重新编译构建固件:
// 为了控制固件的尺寸,BeShell 的 module 是按需引入的。
beshell.use<be::bt::BT>() ;在JS中导入 bt module:
import * as bt from 'bt'import bt简介
bt 模块提供了完整的 BLE(低功耗蓝牙)功能,支持 Central(主机)和 Peripheral(从机)两种模式。
导出对象
bt 模块预创建了以下对象:
peripheral - 类 Peripheral 实例,用于 BLE 从机模式
此外,bt 模块还导出了以下简写形式,与完整名称等价:
bt.centbt.periphbt.pher
使用示例:
import * as bt from 'bt'
// 以下写法等价
bt.central.init()
bt.cent.init()
bt.peripheral.addService({...})
bt.periph.addService({...})
bt.pher.addService({...})Central 模式(主机)
Central 模式用于连接并操作其他 BLE 设备(Peripheral):
import * as bt from 'bt'
// 初始化并扫描设备
bt.central.init()
bt.startScan()
bt.on('scan-res', async (device) => {
if (device.addr === 'AA:BB:CC:DD:EE:FF') {
bt.stopScan()
// 连接设备
const peer = await bt.central.connect(device.addr, 5000)
await peer.search()
// 读写特征
const data = await peer['2a37'].read()
await peer['2a37'].write(new Uint8Array([0x01]))
}
})Peripheral 模式(从机)
Peripheral 模式用于创建 BLE 服务,供其他设备(Central)连接:
import * as bt from 'bt'
// 初始化并创建服务
bt.peripheral.init()
const service = bt.peripheral.addService({
uuid: '180d',
primary: true,
chars: [
{ uuid: '2a37', props: ['read', 'notify'] }
]
})
// 设置特征值并发送通知
service.chars['2a37'].setValue('hello')
service.chars['2a37'].notify('data updated')
// 开始广播
bt.startAdv()模块函数
函数 setPower
原型: setPower (level:number, type:number=0)
设置 BLE 发射功率
示例:
import * as bt from 'bt'
// 设置默认发射功率为 6dBm
bt.setPower(6)
// 设置指定类型的发射功率
bt.setPower(6, 0) // 设置默认功率类型参数:
level
类型number
参数说明功率等级,取值范围 -24 ~ 21 (dBm)
type
类型number
默认值0
参数说明功率类型,0 表示默认类型
异常:
- 功率等级无效
- 功率类型无效
返回值:
类型number
说明错误码,0 表示成功
函数 power
原型: power ()
获取 BLE 当前发射功率
示例:
import * as bt from 'bt'
const power = bt.power()
console.log('当前功率:', power, 'dBm')返回值:
类型number
说明当前发射功率等级 (dBm)
函数 setRandomMac
原型: setRandomMac (mac:string)
设置 BLE 随机 MAC 地址
设置设备的随机地址(底层调用 esp_ble_gap_set_rand_addr),配合 startAdv 的 own_addr_type = 1(BLE_ADDR_TYPE_RANDOM)即可用该地址进行广播。
地址首字节(最高两位)决定地址类型:
- 最高两位为 11(首字节 0xC0~0xFF):静态随机地址 (Static Random Address)
- 最高两位为 00(首字节 0x00~0x3F):不可解析私有地址 (NRPA) 其余情况(如 0xAA)为无效随机地址,会被蓝牙协议栈拒绝。
示例:
import * as bt from 'bt'
// 设置静态随机地址(首字节 0xC0,最高两位为 11)
bt.setRandomMac('C0:AA:BB:CC:DD:EE')
// 以随机地址类型开始广播
bt.startAdv({ own_addr_type: 1 }) // 1 = BLE_ADDR_TYPE_RANDOM参数:
mac
类型string
参数说明MAC 地址字符串,格式为 "xx:xx:xx:xx:xx:xx"
异常:
- MAC 地址格式无效
- 设置 MAC 地址失败
返回值:
类型undefined
函数 parseAdv central侧
原型: parseAdv (raw:ArrayBuffer)
解析广播数据(Central 角色)
作为 Central 将扫描到的原始广播数据解析为对象格式,方便读取设备名称、UUID 等信息。 支持的字段包括:flag、name、shortName、complete16、more16、complete128、 more128、txPower、service16、service128、msd 等。
示例:
import * as bt from 'bt'
bt.on('scan-res', (device) => {
const adv = bt.parseAdv(device.adv_raw)
// 获取设备名称
if (adv.name) {
const name = new TextDecoder().decode(adv.name)
console.log('设备名称:', name)
}
// 获取 16-bit UUID
if (adv.complete16) {
const uuid = '0x' + Array.from(adv.complete16).map(b => b.toString(16).padStart(2, '0')).join('')
console.log('UUID:', uuid)
}
// 获取制造商数据
if (adv.msd) {
console.log('制造商数据:', adv.msd)
}
})参数:
raw
类型ArrayBuffer
参数说明原始广播数据
返回值:
类型object
说明解析后的广播数据对象,包含 name、flag、complete16 等字段
函数 waitScanning central侧
原型: waitScanning (ms:number=10000)
等待扫描完成(Central 角色)
作为 Central 等待扫描完成,返回一个 Promise,当扫描完成时 resolve。 如果当前没有在扫描,立即 resolve。扫描可能因调用 stopScan() 或达到设定的扫描持续时间而完成。
示例:
import * as bt from 'bt'
bt.startScan()
// 等待最多 10 秒扫描完成
await bt.waitScanning(10000)
console.log('扫描完成')
// 无限等待扫描完成
await bt.waitScanning()参数:
ms
类型number
默认值10000
参数说明超时时间(毫秒),0 表示无限等待
返回值:
类型Promise<undefined>
说明扫描完成时 resolve,超时时 reject
函数 setMTU
原型: setMTU (mtu:number)
设置本地 MTU 大小
设置 BLE 协议栈的本地 MTU (Maximum Transmission Unit) 大小。 默认值为 23 字节,最大可设置为 517 字节。
示例:
import * as bt from 'bt'
// 设置 MTU 为 185 字节
bt.setMTU(185)参数:
mtu
类型number
参数说明MTU 大小,范围 23 ~ 517
异常:
- MTU 大小无效
- 设置 MTU 失败
返回值:
类型undefined
函数 getMTU
原型: getMTU ()
获取当前 MTU 大小
获取当前设置的本地 MTU 大小。
示例:
import * as bt from 'bt'
const mtu = bt.getMTU()
console.log('当前 MTU:', mtu)返回值:
类型number
说明当前 MTU 大小
函数 setScanParam central侧
原型: setScanParam (options:object)
设置 BLE 扫描参数(Central 角色)
在 Central 模式下开始扫描前配置扫描参数,包括扫描类型、间隔、窗口等。
示例:
import * as bt from 'bt'
bt.setScanParam({
scan_type: 0, // 0: 被动扫描, 1: 主动扫描
own_addr_type: 0, // 0: 公共地址, 1: 随机地址
scan_filter_policy: 0, // 0: 接受所有, 1: 只接受白名单
scan_interval: 0x50, // 扫描间隔 (0x0004 ~ 0x4000)
scan_window: 0x40, // 扫描窗口 (0x0004 ~ 0x4000)
scan_duplicate: 0 // 0: 不重复, 1: 重复
})参数:
options
类型object (详见下方类型定义)
参数说明扫描参数对象
options 类型定义:
{ scan_type?: number, // 扫描类型:0 被动扫描,1 主动扫描,默认 0 own_addr_type?: number, // 自身地址类型:0 公共地址,1 随机地址,默认 0 scan_filter_policy?: number, // 扫描过滤策略,默认 0 scan_interval?: number, // 扫描间隔,默认 0x50 scan_window?: number, // 扫描窗口,默认 0x40 scan_duplicate?: number // 重复扫描策略,默认 0 }
异常:
- 设置扫描参数失败
- BLE 4.2 不支持
返回值:
类型undefined
函数 startScan central侧
原型: startScan (duration:number=4294967295)
开始扫描 BLE 设备(Central 角色)
作为 Central 开始扫描周围的 BLE 设备,扫描结果通过 'scan-res' 事件返回。
示例:
import * as bt from 'bt'
// 监听扫描结果
bt.on('scan-res', (device) => {
console.log('发现设备:', device.addr, 'RSSI:', device.rssi)
})
// 开始扫描,持续 10 秒
bt.startScan(10)
// 无限扫描
bt.startScan()参数:
duration
类型number
默认值4294967295
参数说明扫描持续时间(秒),默认为无限
异常:
- 开始扫描失败
- BLE 4.2 不支持
返回值:
类型undefined
函数 stopScan central侧
原型: stopScan ()
停止扫描 BLE 设备(Central 角色)
作为 Central 停止扫描周围的 BLE 设备。
示例:
import * as bt from 'bt'
bt.stopScan()异常:
- BLE 4.2 不支持
返回值:
类型boolean
说明是否成功停止
函数 isScanning central侧
原型: isScanning ()
检查是否正在扫描(Central 角色)
检查 Central 是否正在扫描 BLE 设备。
示例:
import * as bt from 'bt'
if (bt.isScanning()) {
console.log('正在扫描中...')
}返回值:
类型boolean
说明是否正在扫描
函数 connect central侧
原型: connect (addr:string)
连接到 BLE 设备(Central 角色)
作为 Central 连接到指定的 BLE 设备。
示例:
import * as bt from 'bt'
// 连接到指定 MAC 地址的设备
bt.connect('AA:BB:CC:DD:EE:FF')
// 使用 JS 侧封装的 Promise API
const peer = await bt.central.connect('AA:BB:CC:DD:EE:FF', 5000)参数:
addr
类型string
参数说明目标设备的 MAC 地址,格式为 "xx:xx:xx:xx:xx:xx"
异常:
- 未初始化 Central 模式
- MAC 地址格式无效
- 连接失败
返回值:
类型undefined
函数 disconnect central侧
原型: disconnect (conn_id:number)
断开与 BLE 设备的连接(Central 角色)
作为 Central 断开与指定 BLE 设备的连接。
示例:
import * as bt from 'bt'
// 断开指定连接 ID 的设备
bt.disconnect(connId)参数:
conn_id
类型number
参数说明连接 ID
异常:
- 未初始化 Central 模式
- 断开连接失败
返回值:
类型undefined
函数 requestMTU central侧
原型: requestMTU (conn_id:number)
请求更新 MTU (Maximum Transmission Unit)(Central 角色)
作为 Central 向连接的设备请求更新 MTU 大小。
示例:
import * as bt from 'bt'
bt.requestMTU(connId)
// 等待 MTU 更新完成
bt.once('cfg-mtu', (status, connId, mtu) => {
console.log('MTU 更新为:', mtu)
})参数:
conn_id
类型number
参数说明连接 ID
异常:
- 未初始化 Central 模式
返回值:
类型undefined
函数 search central侧
原型: search (conn_id:number)
搜索 BLE 设备的服务和特征(Central 角色)
作为 Central 在已连接的设备上搜索所有 GATT 服务和特征。 搜索结果通过 'search-res' 和 'search-cmpl' 事件返回。
示例:
import * as bt from 'bt'
bt.on('search-res', (connId, service) => {
console.log('发现服务:', service.uuid)
console.log('特征列表:', service.chars)
})
bt.on('search-cmpl', (status, connId) => {
console.log('搜索完成')
})
bt.search(connId)参数:
conn_id
类型number
参数说明连接 ID
异常:
- 未初始化 Central 模式
返回值:
类型undefined
函数 read central侧
原型: read (conn_id:number, handle:number)
读取特征值(Central 角色)
作为 Central 从已连接设备的指定特征读取数据。 读取结果通过 'read-char' 事件返回。
示例:
import * as bt from 'bt'
bt.on('read-char', (status, handle, data) => {
if (status === 0) {
console.log('读取成功:', data)
}
})
bt.read(connId, charHandle)参数:
conn_id
类型number
参数说明连接 ID
handle
类型number
参数说明特征句柄
异常:
- 未初始化 Central 模式
- 读取失败
返回值:
类型undefined
函数 write central侧
原型: write (conn_id:number, handle:number, data:ArrayBuffer, rsp:boolean=false)
写入特征值(Central 角色)
作为 Central 向已连接设备的指定特征写入数据。 写入结果通过 'write-char' 事件返回。
示例:
import * as bt from 'bt'
bt.on('write-char', (status, handle, offset) => {
if (status === 0) {
console.log('写入成功')
}
})
// 写入数据(不需要响应)
bt.write(connId, handle, new Uint8Array([0x01, 0x02]))
// 写入数据(需要响应)
bt.write(connId, handle, new Uint8Array([0x01, 0x02]), true)参数:
conn_id
类型number
参数说明连接 ID
handle
类型number
参数说明特征句柄
data
类型ArrayBuffer
参数说明要写入的数据
rsp
类型boolean
默认值false
参数说明是否需要响应
异常:
- 未初始化 Central 模式
- 数据格式无效
- 写入失败
返回值:
类型undefined
函数 subscribe central侧
原型: subscribe (conn_id:number, handle:number, type:number=1)
订阅特征值通知(Central 角色)
作为 Central 订阅指定特征的通知或指示。订阅成功后,设备会主动推送数据变化。 订阅结果通过 'write-desc' 事件返回。
示例:
import * as bt from 'bt'
bt.on('write-desc', (status, handle, offset) => {
if (status === 0) {
console.log('订阅成功')
}
})
// 订阅通知 (type=1)
bt.subscribe(connId, cccdHandle, 1)
// 订阅指示 (type=2)
bt.subscribe(connId, cccdHandle, 2)参数:
conn_id
类型number
参数说明连接 ID
handle
类型number
参数说明CCCD (Client Characteristic Configuration Descriptor) 句柄
type
类型number
默认值1
参数说明订阅类型:1 通知 (Notification),2 指示 (Indication)
异常:
- 未初始化 Central 模式
- 订阅类型无效
- 订阅失败
返回值:
类型undefined
函数 setAdvName peripheral侧
原型: setAdvName (name:string)
设置广播设备名称(Peripheral 角色)
作为 Peripheral 设置 BLE 设备在广播时显示的名称。
示例:
import * as bt from 'bt'
bt.peripheral.init()
bt.setAdvName('MyBLEDevice')
bt.startAdv()参数:
name
类型string
参数说明设备名称
异常:
- 未初始化 Peripheral 模式
- 设置名称失败
返回值:
类型undefined
函数 setAdvData peripheral侧
原型: setAdvData (data:ArrayBuffer)
设置原始广播数据(Peripheral 角色)
作为 Peripheral 设置 BLE 广播的原始数据包内容。
示例:
import * as bt from 'bt'
// 设置自定义广播数据
const advData = new Uint8Array([
0x02, 0x01, 0x06, // 广播标志
0x03, 0x03, 0xAA, 0xFE // 16-bit UUID
])
bt.setAdvData(advData.buffer)参数:
data
类型ArrayBuffer
参数说明原始广播数据
异常:
- 未初始化 Peripheral 模式
- 设置广播数据失败
返回值:
类型undefined
函数 startAdv peripheral侧
原型: startAdv (options:object)
开始 BLE 广播(Peripheral 角色)
作为 Peripheral 开始发送 BLE 广播包,让其他设备可以发现并连接。
BLE 设备地址类型说明(对应 own_addr_type):
- 公共地址 (Public Address):由 IEEE 注册机构分配的 48 位地址,全球唯一,类似以太网 MAC 地址。 前 24 位为厂商唯一标识符(OUI,由 IEEE 分配),后 24 位由厂商自行分配。地址固定不变, 优点是稳定且全球唯一,缺点是身份可被追踪,且 OUI 需向 IEEE 付费申请。
- 随机地址 (Random Address):无需向 IEEE 申请,由设备本地生成,常用于隐私保护。分为: · 静态随机地址 (Static Random Address):上电时随机生成(最高两位为 11),同一设备通常保持不变, 可作为公共地址的替代;在 JS 中可通过 bt.setRandomMac 设置(首字节最高两位须为 11,见下方示例)。 · 私有地址 (Private Address):定期更换以防止被追踪,又分为可解析私有地址(RPA, 通过 IRK 身份解析密钥还原身份)和不可解析私有地址(NRPA,无法还原身份)。
示例:
import * as bt from 'bt'
// 使用默认参数开始广播
bt.startAdv()
// 自定义广播参数
bt.startAdv({
min: 0xA0, // 最小广播间隔
max: 0xB0, // 最大广播间隔
type: 0, // 广播类型
own_addr_type: 0, // 自身地址类型
channel_map: 0x07, // 广播通道映射
adv_filter_policy: 0 // 广播过滤策略
})
// 使用静态随机地址广播(定制 MAC)
bt.setRandomMac('C0:AA:BB:CC:DD:EE') // 首字节最高两位须为 11,如 0xC0
bt.startAdv({ own_addr_type: 1 }) // 1 = BLE_ADDR_TYPE_RANDOM(随机地址)参数:
options
类型object (详见下方类型定义)
参数说明可选的广播参数
options 类型定义:
{ min?: number, // 最小广播间隔,单位 0.625ms,范围 0x20~0x4000,默认 0xA0 (100ms) max?: number, // 最大广播间隔,单位 0.625ms,范围 0x20~0x4000,默认 0xB0 (110ms) type?: number, // 广播类型,默认 0: // 0 ADV_TYPE_IND 可连接、可扫描的不定向广播(常规广播) // 1 ADV_TYPE_DIRECT_IND_HIGH 定向连接广播(高占空比,约 1.28s 超时) // 2 ADV_TYPE_SCAN_IND 可扫描、不可连接广播 // 3 ADV_TYPE_NONCONN_IND 不可连接、不可扫描广播(信标类广播,如 iBeacon) // 4 ADV_TYPE_DIRECT_IND_LOW 定向连接广播(低占空比) own_addr_type?: number, // 自身地址类型,默认 0: // 0 BLE_ADDR_TYPE_PUBLIC 公共设备地址 // 1 BLE_ADDR_TYPE_RANDOM 随机设备地址(需先用 setRandomMac 设置随机地址) // 2 BLE_ADDR_TYPE_RPA_PUBLIC 可解析私有地址(RPA),使用公共身份地址 // 3 BLE_ADDR_TYPE_RPA_RANDOM 可解析私有地址(RPA),使用随机身份地址 channel_map?: number, // 广播通道映射,默认 0x07,可位或组合: // 0x01 ADV_CHNL_37 通道 37 (2402 MHz) // 0x02 ADV_CHNL_38 通道 38 (2426 MHz) // 0x04 ADV_CHNL_39 通道 39 (2480 MHz) // 0x07 ADV_CHNL_ALL 全部三个通道 adv_filter_policy?: number // 广播过滤策略,默认 0: // 0 ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY 接受任何设备的扫描和连接请求 // 1 ADV_FILTER_ALLOW_SCAN_WLST_CON_ANY 仅接受白名单设备的扫描请求,接受任何设备的连接请求 // 2 ADV_FILTER_ALLOW_SCAN_ANY_CON_WLST 接受任何设备的扫描请求,仅接受白名单设备的连接请求 // 3 ADV_FILTER_ALLOW_SCAN_WLST_CON_WLST 仅接受白名单设备的扫描和连接请求 }
异常:
- 未初始化 Peripheral 模式
- 开始广播失败
返回值:
类型undefined
函数 stopAdv peripheral侧
原型: stopAdv ()
停止 BLE 广播(Peripheral 角色)
作为 Peripheral 停止发送 BLE 广播包。
示例:
import * as bt from 'bt'
bt.stopAdv()异常:
- 未初始化 Peripheral 模式
- 停止广播失败
返回值:
类型undefined
函数 addService peripheral侧
原型: addService (uuid:string, num_handles:number)
添加 GATT 服务(Peripheral 角色)
作为 Peripheral 添加一个 GATT 服务。服务创建成功后会自动启动。
示例:
import * as bt from 'bt'
// 添加一个心率服务 (0x180D)
const serviceHandle = bt.addService('180D', 10)
console.log('服务句柄:', serviceHandle)参数:
uuid
类型string
参数说明服务的 UUID(16位、32位或128位)
num_handles
类型number
参数说明服务的句柄数量
异常:
- 未初始化 Peripheral 模式
- UUID 格式无效
- 创建服务失败
- 服务创建超时
返回值:
类型number
说明服务句柄
函数 addChar peripheral侧
原型: addChar (service_handle:number, uuid:string, perm:string|Array)
添加 GATT 特征(Peripheral 角色)
作为 Peripheral 在指定服务中添加一个 GATT 特征。
示例:
import * as bt from 'bt'
// 添加一个可读写的特征
const charHandle = bt.addChar(serviceHandle, '2A37', 'read,write,notify')
// 使用数组指定权限
const charHandle = bt.addChar(serviceHandle, '2A37', ['read', 'write', 'notify'])参数:
service_handle
类型number
参数说明服务句柄
uuid
类型string
参数说明特征的 UUID
perm
类型string, Array
参数说明权限,可以是字符串(如 "read,write")或数组(如 ["read", "write"])
- read: 可读
- write: 可写(需要响应)
- writeNR: 可写(不需要响应)
- notify: 支持通知
- indicate: 支持指示
异常:
- 未初始化 Peripheral 模式
- UUID 格式无效
- 权限参数无效
- 添加特征失败
- 添加特征超时
返回值:
类型number
说明特征句柄
函数 setCharValue peripheral侧
原型: setCharValue (char_handle:number, value:string|ArrayBuffer|number)
设置特征值(Peripheral 角色)
作为 Peripheral 设置指定特征的本地值。当 Central 读取该特征时,会返回此值。
示例:
import * as bt from 'bt'
// 设置字符串值
bt.setCharValue(charHandle, 'hello world')
// 设置二进制数据
bt.setCharValue(charHandle, new Uint8Array([0x01, 0x02, 0x03]).buffer)
// 设置数字值(4字节小端序)
bt.setCharValue(charHandle, 12345)参数:
char_handle
类型number
参数说明特征句柄
value
类型string, ArrayBuffer, number
参数说明要设置的值
异常:
- 未初始化 Peripheral 模式
- 特征句柄无效
- 值类型无效
- 设置值失败
返回值:
类型undefined
函数 sendNotify peripheral侧
原型: sendNotify (char_handle:number, data:string|ArrayBuffer, is_indication:boolean=false, conn_id:number)
发送通知或指示(Peripheral 角色)
作为 Peripheral 向已连接的 Central 设备发送特征值通知或指示。 如果数据长度超过 MTU,会自动分包发送。
示例:
import * as bt from 'bt'
// 发送通知
bt.sendNotify(charHandle, 'data updated')
// 发送指示(需要确认)
bt.sendNotify(charHandle, 'important data', true)
// 发送到指定连接
bt.sendNotify(charHandle, 'data', false, connId)参数:
char_handle
类型number
参数说明特征句柄
data
类型string, ArrayBuffer
参数说明要发送的数据
is_indication
类型boolean
默认值false
参数说明是否为指示(需要确认)
conn_id
类型number
参数说明连接 ID(可选,默认使用最后连接的 ID)
异常:
- 未初始化 Peripheral 模式
- 特征句柄无效
- 没有设备连接
- 数据类型无效
- 发送失败
返回值:
类型undefined
