当前位置: 首页 > news >正文

低功耗蓝牙BLE与小程序通讯

1.低功耗蓝牙BLE介绍

低功耗蓝牙(Bluetooth Low Energy, BLE,也称 Bluetooth LE 或旧商标 Bluetooth Smart)是蓝牙技术联盟(Bluetooth SIG)专为物联网和低功耗设备设计的一种短距离无线通信技术
。它自蓝牙4.0规范(2010年)开始引入,以其极低的功耗、快速的连接和广泛的兼容性,成为可穿戴设备、智能家居、医疗健康等领域的理想选择

BLE 的核心优势在于其低功耗设计,这主要通过以下几种方式实现

  • 无线电间歇工作:BLE 设备大部分时间处于休眠状态,仅在需要发送或接收数据时才短暂唤醒无线电,从而极大降低能耗。
  • 更短的连接时间:BLE 使用更少的射频通道(仅3个广播通道)进行设备发现和连接,减少了扫描和建立连接所需的时间和能量。
  • 更小的数据包:BLE 传输的数据包更小,编码和解码所需的计算开销更少,降低了功耗。
  • 利用电池恢复效应:BLE 的数据传输采用周期性短脉冲形式,之后留有空闲时间,这种脉冲式放电有助于电池恢复,延长其使用寿命。
  • 非对称设计:在连接中,功耗和计算能力要求较高的中央设备(如手机)承担更多工作,而资源受限的外围设备(如传感器)则尽可能简单工作以节省电量。

此外,BLE 还具有快速连接(最快3毫秒即可完成连接)、成本低兼容性强(被主流操作系统和物联网平台广泛支持)以及支持广播模式(设备无需配对即可向周围广播数据,非常适合信标、室内定位等场景)等特点

2.低功耗蓝牙GAT

低功耗蓝牙(BLE)中的 GAP(Generic Access Profile,通用访问配置文件)是蓝牙协议栈中非常关键的一层。它主要负责定义蓝牙设备如何被发现、如何建立连接以及如何进行安全交互,可以看作是蓝牙设备的“交通规则”和“自我介绍手册”。

2.1 GAP 的核心功能

GAP 主要规范了以下几个方面的行为:
• 设备发现:规定了设备如何通过广播和扫描来彼此发现。
• 连接管理:定义了设备如何建立连接、管理连接参数(如连接间隔、从设备延迟、连接超时)以及终止连接。
• 安全机制:制定了设备如何进行配对和绑定,以确保通信安全。
• 角色定义:为 BLE 设备定义了四种不同的通信角色。

2.2 GAP 的设备角色

BLE GAP 为设备定义了四种核心角色,这体现了其非对称设计以优化功耗和成本的思路:

角色 职责 典型设备 关键特点
外围设备 (Peripheral) 对外发送广播数据包,并等待被中心设备连接 智能手环、心率传感器、智能门锁 通常资源受限,电池供电,可连接
中央设备 (Central) 主动扫描周围的广播数据包,并选择性地发起连接 手机、平板电脑、PC 通常资源丰富,作为数据消费者和控制者,可连接多个外设
广播者 (Broadcaster) 只发送广播数据包,不接受也不响应连接请求 iBeacon、Eddystone 等信标设备 不可连接,单向数据传输
观察者 (Observer) 只扫描和接收广播数据包,不发起任何连接 商场导航APP、数据采集器、蓝牙嗅探器 不可连接,单向数据接收

一个物理设备可以同时支持多个角色,例如,一部手机可以同时作为中央设备(连接智能手环)和外围设备(被智能手表连接)。

2.3 GAP 的工作流程:广播、扫描与连接

2.3.1. 广播 (Advertising)

这是外围设备或广播者向外宣告自身存在的主要方式。它们会周期性地在特定的信道上发送广播数据包。
• 广播数据 (Advertising Data):必需包含,最大 31 字节。通常包含设备名称、支持的服务UUID、发射功率、制造商特定数据等。
• 扫描响应数据 (Scan Response):可选,最大也是 31 字节。当中央设备发起主动扫描时,外围设备可以用此包回复更多信息(如完整的设备名)。
• 广播间隔 (Advertising Interval):两次广播事件之间的时间。间隔短则被发现快,但功耗高;间隔长则省电,但可能被发现慢。

2.3.2 扫描 (Scanning)

这是中央设备或观察者的行为,目的是监听和接收广播数据。
• 被动扫描 (Passive Scanning):只监听广播包,不发送任何请求。功耗较低,但获取的信息量仅限于广播包内的31字节。
• 主动扫描 (Active Scanning):在接收到广播包后,会发送扫描请求,以期获取外围设备回复的扫描响应数据。功耗相对较高,但可以获取最多62字节的信息(广播包+扫描响应)。

2.3.3 连接建立 (Connection Establishment)

当中央设备扫描到想要连接的外围设备广播包后,会向其发送连接请求。双方协商一致后,便会建立一条独占的无线链路。之后,它们会按照约定的连接参数进行周期性的通信。
• 连接间隔 (Connection Interval):两次连接事件之间的时间。间隔短,延迟低,数据吞吐率高,但功耗高;间隔长,则更省电,但延迟增加。
• 从设备延迟 (Slave Latency):允许从设备(外围设备)跳过一定次数的连接事件,而无需唤醒监听,用于节能。
• 监督超时 (Supervision Timeout):连接超时时间。在此时间内若无有效通信,则认为连接丢失并断开。

🔒 GAP 的安全机制
GAP 定义了设备如何通过配对交换密钥,以及通过绑定保存长期密钥以便后续快速安全连接。BLE 的安全模式主要分为:
• LE Legacy Pairing: 旧式配对方法。
• LE Secure Connections: 更安全的配对方式,提供更强的加密和防中间人攻击保护。

⚙️ GAP 与 GATT 的关系
• GAP 负责 “如何连接”:解决设备如何被发现、谁连谁、怎么连上、连多快、安不安全等问题。它管的是“握手”和“ introductions”。
• GATT 负责 “连接后做什么”:在连接建立之后,定义数据交换的结构和内容(通过服务、特征值等)。它管的是“对话的内容”。

2.4 代码示例

以下是小程序代码示例,展示了从初始化到连接的完整 GAP 相关操作

// 初始化蓝牙模块
wx.openBluetoothAdapter({success: (res) => {console.log('蓝牙适配器初始化成功');// 开始搜索设备wx.startBluetoothDevicesDiscovery({services: ['FEE7'], // 根据目标设备的主服务UUID过滤[5](@ref)allowDuplicatesKey: false,success: (res) => {console.log('开始搜索设备成功');},fail: (err) => {console.error('开始搜索设备失败', err);}});// 监听发现新设备wx.onBluetoothDeviceFound((res) => {res.devices.forEach(device => {if (device.name && device.name === 'YourTargetDeviceName') {console.log('找到目标设备', device);wx.stopBluetoothDevicesDiscovery(); // 停止扫描const deviceId = device.deviceId;// 连接目标设备wx.createBLEConnection({deviceId: deviceId,success: (res) => {console.log('设备连接成功');// 连接成功后可进行GATT操作,如发现服务、读写特征值等},fail: (err) => {console.error('设备连接失败', err);}});}});});},fail: (err) => {console.error('初始化蓝牙适配器失败', err);}
});

3. BLE的特征

低功耗蓝牙(BLE)中的 GATT(Generic Attribute Profile,通用属性配置文件)是蓝牙协议栈中至关重要的一层,它定义了蓝牙设备在建立连接后如何进行数据通信。GATT 基于 ATT (Attribute Protocol,属性协议),采用一种结构化的数据组织方式,使得设备间的数据交换变得清晰和标准化

3.1 服务

服务用于实现设备的某种特定功能,是一些相关联数据的集合。

  • 每个服务都有一个唯一的UUID(通用唯一识别码)来标识其类型
  • 标准服务:由蓝牙技术联盟(SIG)预定义,UUID 为 16位(如 0x180F代表电池服务,0x180A代表设备信息服务)。
  • 自定义服务:开发者为自己特定应用定义的服务,UUID 为 128位

一个设备可以包含多个服务。例如,一个健康手环可能同时包含电池服务(0x180F)和心率服务(0x180D)。

3.2 特征 (Characteristic)

特征是服务中的具体数据值,是客户端与服务器进行数据交互的实际对象。一个特征包含三个基本部分:

1.​​声明 (Declaration)​​:一条类型为 0x2803(Characteristic Declaration)的属性,其​​值​​包含了该特征的​​属性 (Properties)​​、​​值句柄 (Value Handle)​​ 和​​特征 UUID​​。

2.​​值 (Value)​​:一条类型为​​特征 UUID​​ 的属性,存放​​实际的数据​​(如温度值、开关状态等)。

3.​​描述符 (Descriptor)​​(可选):提供特征的额外信息或配置选项。最常用的是​​客户端特征配置描述符 (CCCD, UUID: 0x2902)​​,用于启用或禁用通知 (Notify) 和指示 (Indicate)。

3.2.1 特征属性 (Properties)

特征属性定义了客户端可以对特征进行哪些操作,主要包括:

  • Read:读取特征值。
  • Write:写入特征值(需要响应)。
  • Write without response:无响应写入(更快速,但不可靠)。
  • Notify:服务器主动向客户端发送值(无需确认)。
  • Indicate:服务器主动向客户端发送值(需要客户端确认)。
  • Broadcast:通过广播发送特征值。

3.2.2 角色关系

在 GATT 交互中,设备扮演两种角色:
GATT 服务器 (Server):存储属性表(包含服务、特征和数据),并响应客户端的请求。通常是​​外围设备​​(如传感器、手环)。
GATT 客户端 (Client):向服务器发起请求,读取或写入数据。通常是​​中央设备​​(如手机、电脑)。

3.2.3 核心操作流程

GATT 通信通常遵循以下步骤:

  1. 设备发现与连接​​(通过 GAP 完成):中央设备扫描并连接外围设备。
  2. 服务与特征发现​​:连接成功后,客户端(主设备)发现服务器(从设备)支持的所有服务和特征。
  3. 数据交互​​:客户端根据特征的属性,对服务器进行读取、写入、启用通知等操作。
  4. 连接维护与断开​​:可能涉及连接参数更新,最终由一方或超时导致连接断开

3.2.4 小程序代码示例

// 获取蓝牙设备所有服务
wx.getBLEDeviceServices({deviceId: deviceId, // 目标设备IDsuccess: (res) => {console.log('设备服务列表:', res.services);// 假设我们目标服务的UUID是 '0000FFE0-0000-1000-8000-00805F9B34FB'const targetService = res.services.find(s => s.uuid === '0000FFE0-0000-1000-8000-00805F9B34FB');if (targetService) {// 获取指定服务下的所有特征this.getDeviceCharacteristics(deviceId, targetService.uuid);}}
});// 获取特定服务的所有特征
getDeviceCharacteristics(deviceId, serviceId) {wx.getBLEDeviceCharacteristics({deviceId: deviceId,serviceId: serviceId,success: (res) => {console.log('特征列表:', res.characteristics);// 遍历特征,根据其属性决定如何操作res.characteristics.forEach(char => {if (char.properties.read) {// 如果特征可读,则读取一次this.readCharacteristic(deviceId, serviceId, char.uuid);}if (char.properties.notify || char.properties.indicate) {// 如果特征支持通知或指示,则启用监听this.enableNotify(deviceId, serviceId, char.uuid);}// 对于支持写的特征,可以保留其UUID,后续用于发送数据});}});
}// 向设备发送数据(ArrayBuffer类型)
sendDataToDevice(deviceId, serviceId, characteristicId, dataArray) {// 将数组(如[0x01, 0x02, 0x03])转换为ArrayBufferconst buffer = new ArrayBuffer(dataArray.length);const dataView = new DataView(buffer);for (let i = 0; i < dataArray.length; i++) {dataView.setUint8(i, dataArray[i]);}wx.writeBLECharacteristicValue({deviceId: deviceId,serviceId: serviceId,characteristicId: characteristicId,value: buffer, // 必须是 ArrayBuffer 类型success: (res) => {console.log('写入数据成功', res);},fail: (err) => {console.error('写入数据失败', err);}});
}

启用通知Notify

enableNotify(deviceId, serviceId, characteristicId) {wx.notifyBLECharacteristicValueChange({deviceId,serviceId,characteristicId,state: true, // 启用 notifysuccess: (res) => {console.log('已启用通知', res);},fail: (err) => {console.error('启用通知失败', err);}});
}// 记得在页面或组件卸载时取消通知
disableNotify(deviceId, serviceId, characteristicId) {wx.notifyBLECharacteristicValueChange({deviceId,serviceId,characteristicId,state: false // 禁用 notify});
}

4. 蓝牙MTU

BLE 中的 ​​MTU​​(Maximum Transmission Unit,最大传输单元)是指在一次数据包传输中能够承载的最大数据量,它直接影响蓝牙通信的效率和吞吐能力。默认情况下,BLE 的 MTU 为 ​​23 字节​​,其中约 20 字节可用于有效载荷(实际应用数据),其余部分用于协议头等开销。若传输的数据超过 MTU 限制,则需进行分包,这会增加延迟和通信开销。通过协商更大的 MTU(如 247 字节),可以显著减少传输次数,提高数据交换效率。

在 ​​Android 和 iOS 系统​​中,MTU 的处理和支持存在一些差异。Android 设备允许开发者通过 API(如 BluetoothGatt.requestMtu())主动请求更大的 MTU 值。实际支持的最大值因设备和系统版本而异,现代 Android 设备通常可支持 128 字节或更高(甚至可达 517 字节)。需要注意的是,Android 系统从 5.1(API 21)开始才支持 MTU 修改。

iOS 系统则更自动化一些,其在建立连接时会自动发起 MTU 交换过程。运行 iOS 10 及以上系统的设备通常会请求 ​​185 字节​​ 的 MTU。iOS 对 MTU 的手动控制接口相对较少,更多依赖于系统自身的协商机制。

MTU 的大小直接影响传输延迟、通信开销和整体吞吐率。较大的 MTU 允许单次传输更多有效数据,特别有利于需要高频或大数据量交换的应用场景(如固件升级、持续传感器数据流等),从而降低功耗并提升响应速度。

微信小程序提供一下接口控制MTU:

// 假设已连接设备,并获取到 deviceId
wx.setBLEMTU({deviceId: deviceId, // 目标蓝牙设备 IDmtu: 100,           // 期望设置的 MTU 值,建议在 23 到 512 之间[1](@ref)success: (res) => {console.log('MTU 设置成功', res.mtu); // res.mtu 为实际协商后的MTU值},fail: (err) => {console.error('MTU 设置失败:', err);// 处理设置失败的情况,例如采用分包策略}
});
http://www.agseo.cn/news/358/

相关文章:

  • 同事突然关心有没有对象?这可能是职场发展的隐形陷阱
  • TTS微软Azure
  • 12.6 类的封装
  • 深度解码你自己看着办:职场新人必须掌握的潜台词破解术
  • 6 个替代 Jira 的开源项目管理工具推荐
  • 记录一个Windows上的键盘鼠标模拟库和沟子库--Input
  • 惊世骇俗:《易经》六十四卦与数学公理完整映射表
  • 解决docker: Error response from daemon: Get “https://registry-1.docker.io/v2/“:连接超时问题
  • 27届春招备战一轮复习--第三期(推荐)
  • 数据集和数据系统_AI成为工作中很好用的协同成员了
  • IDM超详细图文安装激活教程,一次安装免费使用 Internet Download Manager
  • 标题
  • 12.5 多态与多态性
  • 集训日记
  • 数字孪生技术如何破解产线效率瓶颈? - 智慧园区
  • 三期集训 日记?
  • 需求爆炸?领歌3步科学精简法,让团队重获掌控力!
  • 从想法到代码:AI编程时代,我们如何高质量“喂养”AI?
  • 12.4 菱形继承问题(了解)
  • 25年CSP前ds做题记录
  • 极域电子学生机无法连接教师机
  • Python Flask框架入门_2.API增加授权验证
  • 12.2 类的派生
  • CSP-S模拟18
  • 在服务器后台运行python服务
  • HCIP回顾—2 OSPF工作过程及状态机制
  • python基础——函数小进阶
  • 你的开发服务器在说谎-热重载与热重启的关键区别
  • 在疼痛中,在喧嚣 失聪与惶惑中
  • AT_agc018_b [AGC018B] Sports Festival