蓝牙mesh实战
- 基础协议:蓝牙技术联盟(Bluetooth SIG)在2017年发布的蓝牙Mesh协议。
蓝牙mesh系统分层架构
蓝牙mesh系统分层架构如图2.1所示,可以看到蓝牙mesh是基于蓝牙BLE核心规范(Bluetooth Low Energy Core Specification)实现的一种网络协议。
- 承载层(Bearer Layer)把BLE的数据抽象供上层使用,定义了广播承载和GATT承载。
- 网络层(Network Layer)负责基于地址的消息传输,实现中继和代理特性以及对信息进行加密解密和认证行为。
- 底层传输层
- 负责将数据分段和重组。
- 负责对访问层数据包进行分包,最多可以分为16包,每个包为12字节。
- 上层传输层
- 访问层(Access Layer)
- 负责定义应用如何使用上层传输层,定义应用数据格式,定义上层传输层的应用数据加密和解密方式(通过AppKey或DeviceKey进行加解密)。
- 访问层所有消息都是由模型(model)实例来发送的,发送的消息内容包含目标地址,源地址,跳数TTL.
- 基础模型层
- 基础模型层定义了基础模型,包含:Configuration server model 和Configuration client model、Health server model和Health client model
- 所有被配网节点都必须包含Configuration server model,Provisioner必须包含Configuration client model.这两个model包含的常用opcode是subscription add/delete(即订阅组添加,删除)等。并且这两个model的access layer加密都使用device key,所以一般来说,只有provisioner 节点才能发送configuration 的set/get命令。(因为只有provisioner知道节点的DeviceKey)
- 模型层
- model定义了一个节点支持的功能,每一个model都定义了自己的opcode,以及status
- provisioner在配网的时候,会通过get composition data获取节点所支持的model ID,然后,provisioner就知道节点具体支持什么功能。只有这个节点支持了对应的model id,才会给节点发送该model定义的opcode.
订阅组与发布组
设置订阅组
- mesh协议中订阅组是给元素订阅组,而不是给节点订阅组。
- 标准mesh设置订阅组,设置发布地址都使用config model,对access layer加密的时候,如果opcode对应的model是config model,则使用device key,否则使用app key.
- 订阅了开关服务器模型,可以接收处理网关下发的开关状态设置,只有订阅了开关客户端模型,才可以接收处理其它节点或元素上报的开关状态消息。
- 同理,如果要让调光设备处理目的地址是组地址的场景命令,需要让调光设备订阅场景服务器模型的组地址。
设置发布组
- Publish: Publish就是Element主动发送status的过程,可以通过Config Model Publication Set命令配置Publish address,以及设置周期publish参数。
- 一个element的model只可以设置一个发布地址。
- 设置的发布地址可以是:未分配地址(0x00)、单播地址、Label UUID、组播地址,不能是虚拟地址。
当设置的发布地址是未分配地址时,当model状态发生改变后,不往发布地址发布消息。
标准场景
- 场景保存时,以element为单位保存,会保存当前状态到场景号指定的场景,保存内容包含element所有的model状态。
- 场景保存支持保存自定义vendor model功能消息,内容自定义。
- 场景保存时,回调vendor model的回调函数,获取vendor model定义功能点的状态。
telink SDK中保存场景&执行场景的API函数
//保存场景
//cb_par->model_idx指出元素号
//函数内会执行回调函数p_nl_get_vendor_scene_data获取自定义vendor model功能状态,然后进行保存。
u8 mesh_cmd_sig_scene_set_ll(u16 scene_id, mesh_cb_fun_par_t *cb_par)
//执行场景
//函数内会执行p_nl_scene_server_state_recalled回调函数获取vendor model场景内容,然后进行执行。
int mesh_cmd_sig_scene_recall(u8 *par, int par_len, mesh_cb_fun_par_t *cb_par)
- 场景执行的消息格式:包含场景号,渐变时间,延时时间
- 场景状态消息:场景执行消息的应答,也是场景状态获取的应答。
当前场景:
- 场景保存成功,或者场景执行成功,当前场景就是对应的场景号
- 当前场景如果被执行场景删除命令删除,当前场景变为0
- 执行某个场景后,如果元素的状态发生改变,当前场景变为0
目标场景:
- 如果不是场景转换过程,目标场景为0
- 场景转换过程中,目标场景被删除,目标场景变为0
- 场景转换过程中,收到场景保存的命令,目标场景应该是要保存的场景号
- 场景寄存器状态是场景保存,场景删除,场景寄存器状态获取的应答消息,场景寄存器状态代表节点中某个元素支持的16个场景的场景号
蓝牙mesh广播
蓝牙mesh广播实际上是以低功耗蓝牙(BLE)广播为基础的,所用的数据包格式
也是基于低功耗蓝牙广播的数据包格式,通过AD Type字段与其他广播进行区分。
低功耗蓝牙广播的数据格式由多个AD Structure组成,每个AD Structure包含一
个Length字段、一个AD Type字段,以及一个AD Data字段,如下表所示.
Length字段 | AD Type字段 | AD Data字段 |
1字节 | n字节 | Length-n字节 |
- 在蓝牙mesh 协议中使用了3种AD Type字段:Mesh Beacon(0x2B)、Mesh Message(0x2A)和PB-ADB(0x29).对应作用如下。
- Mesh Beacon:用于对蓝牙mesh节点或未配网节点进行周期性的广播,比如未配网设备通过周期性发送Unprobisioned Device Beacon,让自己可以被Provisioner发现,从而有机会加入蓝牙mesh网络。
- Mesh Message:在正常的蓝牙mesh节点间传输网络层数据包,其中包含TTL字段。
- PB-ADV: 在Provision过程中,在广播信道上传输Generic Provision PDU
蓝牙mesh配网
蓝牙mesh配网协议
配网协议栈层次架构如下图所示:
主要分成三层。
- 承载层(Bearer): 用于基本的数据交互,承载所有需要发送的报文。
- 传输层(Transport): 用于定义传输层PDU.
- 配网协议层(Provisioning Protocol): 用于定义具体的PDU.
配网协议栈层次架构
承载层
承载层是用来在配网设备之间传输配网PUD的,蓝牙mesh规范定义了两种不同的承载层:
PB-ADV和PB-GATT,其中PB-ADV基于蓝牙BLE广播,而PB-GATT基于BLE连接。
根据承载层的不同,在传输层,又相应地分成了两种配网PDU:通用配网PDU和代理PDU。
其中通用配网PDU是在PB-ADV传输的,代理PDU是在PB-GATT上传输的。整个配网协议的机制
是基于会话的。
- 百度音响与天猫精灵配网都是基于PB-ADV
- 通过手机APP配网是基于PB-GATT
传输层
PB-ADV的PDU数据格式如表所示。
字段 | 长度(字节) | 备注 |
Link ID | 4 | 当前承载层建立的连接ID |
Transaction Number | 1 | 每个PDU的唯一标识符 |
Generic Provisioning PDU | 1~24 | 通用配网PDU |
Transaction Number主要作用有两个:当同一个配网PDU需要被拆分为多个
PB-ADV时,将共用一个Transaction Number;当同一个PDU被重传时,则使用相
同的Transaction Number.
配网协议
PDU是用来在配网器与未配网设备之间进行通信的基本单元,数据格式如表所示:
字段 | 长度(bit) | 备注 |
Padding | 2 | 0b00,其它值禁止 |
Type | 6 | 配网PDU的类型值 |
Parameters | 可变 | 消息参数 |
蓝牙mesh规范目前定义了10种配网PDU:
- Provisioning Invite
- Provisioning Capabilities
- Provisioning Start
- Provisioning Public Key
- Provisioning Input Complete
- Provisioning Confimation
- Provisioning Random
- Provisioning Data
- Provisioning Complete
- Provisioning Failed