蓝牙通信接口
蓝牙通信接口
概述
本文主要包含包含了蓝牙功能的前端设备的广播,扫描应答,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 的结构如下:
AD Size
,1 个字节,这个 AD 的长度,不包括AD Size
本身AD Type
,1 个字节,这个 AD 的类型AD Data
,0 到多个字节,这个 AD 的内容
扫描应答包主要包含了如下 3 个 AD:
- 无线发射功率 AD
- 设备名称 AD
- 制造商数据 AD
它们的具体描述如下:
无线发射功率 AD
这个 AD (ADV_TYPE_TX_POWER_LEVEL
) 包含了设备的无线发射功率.
使用一个字节有符号整数来表示无线发射功率,单位为 dBm.
可以表示的范围为 -20 dBm ~ 100 dBm,除此外的值不被蓝牙规范接受.
这个 AD 是可选的.
设备名称 AD
这个 AD (ADV_TYPE_COMPLETE_LOCAL_NAME
) 包含了设备的名称.
内容为 UTF-8 字符串,可以在应用程序或配置工具里显示,方便用户识别.
当没有指定设备名时,将使用默认的设备名,默认设备名生成规则为:
型号名
+MAC
地址最后两个字节的 16 进制字符串.- 总体长度不能超过 10 个字节
- 例如
BN1004ABCD
这个 AD 是必需的.
制造商数据 AD
这个 AD (AD_TYPE_MANUFACTURER_SPECIFIC_DATA
) 包含了和设备制造商有关的信息.
BeacoNice 使用制造商数据来传递 Beacon 的一些基本属性.
- Company ID - 厂商 ID,2 个字节,由 SIG 分配,TDK 为
0x060D
- Frame Type - 数据帧类型,1 个字节,由公司分配
- Product ID - 产品类型 ID,1 个字节,由公司分配
- Firmware Version - 固件版本,2 个字节,高字节为主版本号,低字节为次版本号
- Battery Level - 1 个字节,电池剩余电量百分比
- Beacon ID - 可选,设备 ID,6 个字节,即设备的蓝牙 MAC 地址
产品类型 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 使用两个字节无符号整数来表示固件版本
- 高字节: 主版本号,0 ~ 255
- 底字节: 次版本号,0 ~ 255
电池电量:
BeacoNice 使用一个字节无符号整数来表示电池电量百分比
- 0x00~0x64 表示 0% ~ 100% 的电量
- 0xFF 表示没有电池
信标 ID:
BeacoNice 使用六个字节来表示信标的 ID (即蓝牙 MAC 地址)
因为在 iOS 等设备中不允许读取蓝牙设备的 MAC 地址,所以这个字段对 iOS 等应用很有用
这个属性是可选的,如果不包含则制造商数据 AD 长度为 8.
Sensor 广播包数据包结构
Sensor 广播用来对外发送设备内置的传感器测量得到的数据
主要组成内容如下:
- Beacon ID
- 传感器类型
- 传感器测量值
因为不同的设备包含的传感器不一样,所以不同于其他广播包,这个广播的具体内容和长度是可变的
可以同时包含多个传感器测量值,但是最大不要超过 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 字符串 |
常见产品名称:
- BN2001:
Asset Tag
- BN2002:
Asset Tag
- BN1002:
Beacon
- BN1003:
Solar Beacon
- BN1004:
Solar Beacon
- BN1005:
Temperature Sensor
- BL1001:
ESL
- BN5001:
Motor Sensor
- BN5003:
Temperature Sensor
- BN5005:
Alarm Detector
- DT01:
DTU
外观
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
描述:
返回一个如下编码的数组:
version_byte
: 8-bit 版本号, 当前版本号为0x00
.product_byte
: 8-bit 产品号, 当前版本号为0x00
.data
数据内容,具体内容和设备版本相关supported_radio_tx_power
: 一个可变长度的数组,表示支持的无线发射功率值. 注意必须按从低到高排列.
返回值:
Read Not Permitted
: 当试图读锁定状态的 Beacon 时.Write Not Permitted
: 当任何时间试图写入时.
锁定状态
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]
}
描述:
读取这个属性时,将读取到一个表示当前锁定状态的字节:
- 0x00:
LOCKED
锁定状态 - 0x01:
UNLOCKED
解锁状态 - 0x02:
UNLOCKED AND AUTOMATIC RELOCK DISABLED
写一个字节来锁定,或者写 17 个字节来切换到一个新的锁定状态:
0x00: 切换到锁定状态,但是不会改变当前密钥 0x00 + key[16]: 切换到锁定状态,但是会改变当前密钥. 0x02: disable the automatic relocking capability of the interface
长度: 1 byte or 17 bytes
- 建立连接后,5 秒内不解锁将断开连接,防止耗电
- BEACON 硬件和手机 APP 默认相同的密钥
返回值:
Write Not Permitted
: 当试图写入一个非法的 Key 来解锁
解锁
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.
- 读: 返回一个 128 位的
challenge token
,这个码是一次性的,不能重复使用. - 写: Beacon 接收一个 128 位的加密值,它能通过这个值来验证应用程序是否知道正确的解锁码.
应用程序首先通过这个 Characteristic 读取到一个 16 个字节的随机码,然后使用 AES-128-ECB.encrypt (key=beacon_lock_code[16],text=challenge[16])
算法生成一个 16 字节的解锁码.
应用程序将生成的解锁码写到这个 Characteristic,Beacon 将使用同样的算法计算出相应的结果并和这个解锁码比较.
如果两个值是相同的,Beacon 就会被解锁,并设置 Lock state
为 0x01
.
返回值:
Read Not Permitted
: 当试图在未锁定状态下读取.Write Not Permitted
: 当试图在未锁定状态下写入.
恢复出厂设置
TYPE | NOTE |
---|---|
Name | (Advanced) Factory reset |
Characteristic UUID | a3c8750b-8ed3-4bdf-8a39-a01bebede295 |
Lock Requirement | 必须在解锁后才能写. 且锁定状态必须为 0x01. |
属性:
uint8_t reset_boolean
(write)
描述:
当写入一个 0x0B
的值后,Beacon 必须恢复到出厂状态. 但是不会恢复解锁码,它还是保留当前的值. 其他用户配置的数据,比如广播的数据内容等都会被清除.
写入其他的值都不会有任何处理.
返回值:
Write Not Permitted
: 当试图在锁定状态时或者锁定状态不是0x01
时写入.
批量读写配置参数
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]
...
}
描述:
批量读写配置参数
返回值:
Read Not Permitted
: 当试图在锁定状态下读取.Write Not Permitted
: 当试图在锁定状态下写入.Invalid Attribute Length
: 当试图写入一个非法长度的数据.
GATT 错误码
Code | Description | Notes |
---|---|---|
0x02 | Read Not Permitted | 当在 Beacon 处于锁定状态时访问一个需要认证的特征值 |
0x03 | Write Not Permitted | 当特征值为只读 |
0x0d | Invalid Attribute Length | 当参数超出范围,或者数据长度不同于预期 |
附录
密码锁策略
- 设备默认设置为公共密钥,APP 默认内置这个公共密钥
- 在客户下单时,为客户创建账号,并为客户生成客户密钥,并保存在数据库
- 将客户密钥写入将出售给客户的 设备中
- 客户收到 设备 时,下载配置 APP 并登录自己的账号,同时会下载自己的密钥
- 客户通过自己的密钥可以配置自己购买的 设备,但其他人都无法修改
- 设备同时内置一个超级管理密钥,以便设备密钥遗忘或维修使用
- 当客户密钥密码验证不通过时,会验证是否是超级管理密钥,如果都不通过才返回验证失败
- 使用超级管理密钥解锁后就可以重新设置新的客户密钥等