蓝牙通信接口

蓝牙通信接口

概述

本文主要包含包含了蓝牙功能的前端设备的广播,扫描应答,GATT 服务等蓝牙通信接口

BeacoNice 广播包

蓝牙应用程序使用主动扫描模式下,当设备收到扫描请求包之后会立即回复一个扫描应答包

蓝牙设备通过扫描应答包来传输设备名称,设备类型,固件版本号,电池电量等基本信息.

扫描应答包中必须包含制造商数据内容,并通过其 Company ID,Department ID 和 Product ID 属性的值来判断是否是 BeacoNice 蓝牙设备.

扫描应答包数据结构

No. Name Size Sample Note
1 AD Size 1 0x0E 这个 AD 的大小,14 个字节
5 AD Type 1 0xFF AD_TYPE_MANUFACTURER_SPECIFIC_DATA
3 Company ID 2 0x0D06 TDK Corporation: 0x060D
4 Department ID 1 0x11 部门 ID,总是为 0x11
5 Product ID 1 0x02 产品类型 ID,0x02: Sensor & DTU
6 Firmware Version 2 0x0A0B 固件版本,0x0A0B = v10.11
7 Battery Level 1 0x0B 电池电量,0x00-0x64,0xFF 表示没有电池
8 Device ID 6 - 设备 ID,如: 0x0080980287d6,即蓝牙 MAC 地址
9 AD Size 1 0x02 这个 AD 的长度,2 个字节
10 AD Type 1 0x0A ADV_TYPE_TX_POWER_LEVEL
11 Tx Power Value 1 0xC0 无线发射功率,0xEC = -20dBm
12 AD Size 1 0x0A 设备名结构体长度 (最长 11 个字节)
13 AD type 1 0x09 ADV_TYPE_COMPLETE_LOCAL_NAME
14 Name Data 10 - 设备名称,如: BN5001ABCD

AD

蓝牙广播包 PDU 主要由一到多个 AD 组成,每个 AD 的结构如下:

扫描应答包主要包含了如下 3 个 AD:

它们的具体描述如下:

无线发射功率 AD

这个 AD (ADV_TYPE_TX_POWER_LEVEL) 包含了设备的无线发射功率.

使用一个字节有符号整数来表示无线发射功率,单位为 dBm.

可以表示的范围为 -20 dBm ~ 100 dBm,除此外的值不被蓝牙规范接受.

这个 AD 是可选的.

设备名称 AD

这个 AD (ADV_TYPE_COMPLETE_LOCAL_NAME) 包含了设备的名称.

内容为 UTF-8 字符串,可以在应用程序或配置工具里显示,方便用户识别.

当没有指定设备名时,将使用默认的设备名,默认设备名生成规则为:

这个 AD 是必需的.

制造商数据 AD

这个 AD (AD_TYPE_MANUFACTURER_SPECIFIC_DATA) 包含了和设备制造商有关的信息.

BeacoNice 使用制造商数据来传递 Beacon 的一些基本属性.

产品类型 ID:

BeacoNice 使用一个字节来表示产品类型,下面是具体的值分别代表的产品类型:

Product ID Product Name Description
0x00 Reserve 保留将来使用
0x01 Battery Beacon 普通 Beacon
0x02 Sensor 传感器和数据采集器
0x07 Thermometer 蓝牙基础体温计
0x03 Solar Beacon 光能 Beacon
0x04-0x06 Asset Tag 资产定位标签
0x08-0xFF Reserve 保留将来使用

固件版本:

BeacoNice 使用两个字节无符号整数来表示固件版本

电池电量:

BeacoNice 使用一个字节无符号整数来表示电池电量百分比

信标 ID:

BeacoNice 使用六个字节来表示信标的 ID (即蓝牙 MAC 地址)

因为在 iOS 等设备中不允许读取蓝牙设备的 MAC 地址,所以这个字段对 iOS 等应用很有用

这个属性是可选的,如果不包含则制造商数据 AD 长度为 8.

Sensor 广播包数据包结构

Sensor 广播用来对外发送设备内置的传感器测量得到的数据

主要组成内容如下:

因为不同的设备包含的传感器不一样,所以不同于其他广播包,这个广播的具体内容和长度是可变的

可以同时包含多个传感器测量值,但是最大不要超过 22 个字节 (整个广播包不要超过 31 个字节)

数据包格式如下:

No. Name Size Sample Note
1 AD Size 1 0x02 这个结构体的长度,2 个字节
2 AD Type 1 0x01 AD_TYPE_FLAGS
3 Flags Value 1 0x06 Flags value
4 AD Size 1 0x0E 这个结构体的长度,最多 27 个字节
5 AD Type 1 0xFF AD_TYPE_MANUFACTURER_SPECIFIC_DATA
6 Company ID 2 0x0D06 TDK Corporation: 0x060D
7 Department ID 1 0x11 部门 ID,总是为 0x11
8 Product ID 1 0x02 产品类型 ID,0x02: Sensor
9 Sensor Data N - 传感器数据内容,最多 22 个字节

注意 Sensor Data 总共不能超过 22 个字节.

Sensor Data 的格式如下:

No. Name Size Sample Note
1 Data Type 1 - 传感器的类型
2 Data Value N - 测量的值,长度由类型决定
N - - - 更多传感器数据

例如下面是一个包含了温湿和大气压传感器的设备的广播内容:

No. Name Size Sample Note
1 AD Size 1 0x02 这个结构体的长度,2 个字节
2 AD Type 1 0x01 AD_TYPE_FLAGS
3 Flags Value 1 0x06 Flags value
4 AD Size 1 0x0E 这个结构体的长度,最多 27 个字节
5 AD Type 1 0xFF AD_TYPE_MANUFACTURER_SPECIFIC_DATA
6 Company ID 2 0x0D06 TDK Corporation: 0x060D
7 Department ID 1 0x11 部门 ID,总是为 0x11
8 Product ID 1 0x02 产品类型 ID,0x02: Sensor
9 Data Type 1 0x01 温度
10 Data Value 2 0x1980 0x1980 = 0x19 + 0x80 / 0x100 = 25 + 128 / 256 = 25.5 度
11 Data Type 1 0x03 湿度
12 Data Value 1 0x50 0x50 = 80 = 80%
13 Data Type 1 0x04 压力
14 Data Value 3 0x018A16 0x018a16 = 100886 = 1008.86Hpa

常用传感器类型

Name ID Size Sample Note
Beacon ID 0x00 6 0x112233AABBCC 设备的 MAC 地址
Battery 0x01 2 0x6000 电池电压,1 mV/bit,Big Endian
Temperature 0x02 2 0x1980 摄氏温度,第一字节: 整数位,第二字节: 小数位。 0x1980 = 0x19 + 0x80 / 256 = 25 + 128 / 256 = 25.5 度
Humidity 0x03 1 0x50 相对湿度,0x00-0x64,如 0x50 = 80 = 80%
Atmosphere 0x04 3 0x018A16 大气压,0~167 * 1000Hpa,0x018a16 = 100886 = 1008.86Hpa,Big Endian
Alarm 0x05 1 0x01 告警状态, 1 表示告警, 0 表示正常
Open 0x06 1 0x01 打开/关闭状态, 1 表示打开,0 表示关闭
ch2o 0x10 2 0x1000 无符号整数,单位为 ug/m3
co 0x11 2 0x1000 无符号整数,单位为 ug/m3
co2 0x12 2 0x1000 无符号整数,单位为 ug/m3
h2s 0x13 2 0x1000 无符号整数,单位为 ug/m3
nh3 0x14 2 0x1000 无符号整数,单位为 ug/m3
no2 0x15 2 0x1000 无符号整数,单位为 ug/m3
o3 0x16 2 0x1000 无符号整数,单位为 ug/m3
so2 0x17 2 0x1000 无符号整数,单位为 ug/m3
pm10 0x20 2 0x1000 无符号整数,单位为 ug/m3
pm25 0x21 2 0x1000 无符号整数,单位为 ug/m3
- 0x22-0xFE - - 保留将来使用
Sensor Type 0xFF 1 0x01 传感器类型

上面只列出了已知的产品包含的传感器类型,将来可以继续扩展,暂时最多可以定义 255 种传感器类型.

传感器类型

ID 类型
0x00 无指定类型传感器
0x01 温度传感器
0x02 气象站
0x03 气体传感器
0x04 烟雾报警器
0x05 门窗传感器
0x06 水浸传感器

通用访问 (GAP) 服务

TYPE NOTE
Name Generic Access
Service UUID 0x1800

设备名

TYPE NOTE
Characteristic UUID 0x2A00
Name Device Name
Properties READ
Value 表示设备的名称,UTF-8 字符串

常见产品名称:

外观

TYPE NOTE
Characteristic UUID 0x2A01
Name Appearance
Properties READ
Value 外观特性,16 位的值,默认为 0x0000

这个特征值为枚举类型,在编号分配文件中定义. 用来列举设备的外观样式,如颜色等.

外围设备首选连接参数

TYPE NOTE
Characteristic UUID 0x2A04
Name Slave Preferred Connection Parameters
Properties READ
Value -

具体请参考 GAP 服务相关规范.

通用属性 (GATT) 服务

TYPE NOTE
Name Generic Attribute
Service UUID 0x1801

服务改变

TYPE NOTE
Characteristic UUID 0x2A05
Name Service Changed
Properties INDICATE

一旦服务端的 GATT 属性分布有变(增加了或者移除了一些信息),服务就可以通过这个特征值的 indication 来通知应用程序.

具体请参考 GATT 服务相关规范.

设备信息服务

所有产品都必须实现这个服务,用来提供关于这个设备的基本信息.

TYPE NOTE
Name Device Information
Service UUID 0x180A

制造商名称字符串

TYPE NOTE
Characteristic UUID 0x2A29
Name Manufacturer Name String
Properties READ
Value 总是为 TDK Corporation

型号编码字符串

TYPE NOTE
Characteristic UUID 0x2A24
Name Model Number String
Properties READ
Value BN5001

固件版本字符串

TYPE NOTE
Characteristic UUID 0x2A26
Name Firmware Revision String
Properties READ
Value 3.2,分别表示主,次版本号

硬件版本字符串

TYPE NOTE
Characteristic UUID 0x2A27
Name Hardware Revision String
Properties READ
Value 1.0,分别表示主,次版本号

电池服务

只有带电池的产品可选实现这个服务.

TYPE NOTE
Name Battery Service
Service UUID 0x180F

电池电量

TYPE NOTE
Characteristic UUID 0x2A19
Name Battery Level
Properties READ
Value 0 到 100,表示 0% 到 100% 的电量

虚拟串口服务

只有蓝牙传感器可选实现这个服务.

TYPE NOTE
Name UART Service
Service UUID 6E400001-B5A3-F393-E0A9-E50E-24DCCA9E

接收端

TYPE NOTE
Characteristic UUID 0x0002
Name RX
Lock Requirement 当为解锁状态时可写
Properties READ,NOTIFY

发送端

TYPE NOTE
Characteristic UUID 0x0003
Name TX
Lock Requirement 当为解锁状态时可读
Properties WRITE

配置服务

TYPE NOTE
Name Configuration Service
Service UUID A3C87600-8ED3-4BDF-8A39-A01BEBEDE295

在没有明确说明的情况下,写入和读取的数据都是用 big-endian 的字节数组来定义的。

设备能力

TYPE NOTE
Characteristic UUID a3c87501-8ed3-4bdf-8a39-a01bebede295
Name Capabilities
Lock Requirement 当为解锁状态时可读,永远不可写
Properties READ

属性:

// byte array (read)

{
    version_byte,
    product_byte,
    data[N],
    supported_radio_tx_power[0] ... supported_radio_tx_power[N-1]
}

长度: >= 7 bytes

描述:

返回一个如下编码的数组:

返回值:

锁定状态

TYPE NOTE
Characteristic UUID a3c87506-8ed3-4bdf-8a39-a01bebede295
Name Lock State
Lock Requirement 总是可读,必须在解锁状态下才可以读写

属性:

uint8_t lock_state (read)

byte_array (write) {
    lock_byte,
    encrypted_key[0] ... encrypted_key[15]
}

描述:

读取这个属性时,将读取到一个表示当前锁定状态的字节:

写一个字节来锁定,或者写 17 个字节来切换到一个新的锁定状态:

0x00: 切换到锁定状态,但是不会改变当前密钥 0x00 + key[16]: 切换到锁定状态,但是会改变当前密钥. 0x02: disable the automatic relocking capability of the interface

长度: 1 byte or 17 bytes

返回值:

解锁

TYPE NOTE
Name Unlock
Characteristic UUID a3c87507-8ed3-4bdf-8a39-a01bebede295
Lock Requirement 必须在锁定的状态下才可以读写

属性:

byte_array (read) {
    challenge[0] ... challenge[15]
}

byte_array (write) {
    unlock_token[0] ... unlock_token[15]
}

长度: 16 bytes

描述:

用来解锁 Beacon.

应用程序首先通过这个 Characteristic 读取到一个 16 个字节的随机码,然后使用 AES-128-ECB.encrypt (key=beacon_lock_code[16],text=challenge[16]) 算法生成一个 16 字节的解锁码.

应用程序将生成的解锁码写到这个 Characteristic,Beacon 将使用同样的算法计算出相应的结果并和这个解锁码比较.

如果两个值是相同的,Beacon 就会被解锁,并设置 Lock state0x01.

返回值:

恢复出厂设置

TYPE NOTE
Name (Advanced) Factory reset
Characteristic UUID a3c8750b-8ed3-4bdf-8a39-a01bebede295
Lock Requirement 必须在解锁后才能写. 且锁定状态必须为 0x01.

属性:

uint8_t reset_boolean (write)

描述:

当写入一个 0x0B 的值后,Beacon 必须恢复到出厂状态. 但是不会恢复解锁码,它还是保留当前的值. 其他用户配置的数据,比如广播的数据内容等都会被清除.

写入其他的值都不会有任何处理.

返回值:

批量读写配置参数

TYPE NOTE
Name (Advanced) BeacoNice Configuration
Characteristic UUID a3c87680-8ed3-4bdf-8a39-a01bebede295
Lock Requirement 必须在解锁状态下读写.

属性:

byte array (read/write) {
    size,
    type,
    data[0]...data[N],
    size,
    type,
    data[0]...data[N]
    ...
}

描述:

批量读写配置参数

返回值:

GATT 错误码

Code Description Notes
0x02 Read Not Permitted 当在 Beacon 处于锁定状态时访问一个需要认证的特征值
0x03 Write Not Permitted 当特征值为只读
0x0d Invalid Attribute Length 当参数超出范围,或者数据长度不同于预期

附录

密码锁策略