Appearance
蓝牙配置协议
帧格式
数据八位一个字节。下面的数字表示一个字节char.
完整帧的格式 [header(3)][type(1)][ctrl(1)][seq(1)][len(1)][data(len)][crc(2)]
分片帧的格式 [header(3)][type(1)][ctrl(1)][seq(1)][len(1)][data_total(2)][data(len)][crc(2)]
header
帧固定头 [0xBC, 0x59, 0x51];
type
帧类型定义 (低2位表示类型,高6位表示子类型) 所以一个帧类型是
Main Type
| 类型名称 | 类型值 | 类型说明 |
|---|---|---|
| 控制帧 | 0x00 | 用于发送控制指令 |
| 数据帧 | 0x01 | 用于发送数据指令 |
| 应答帧 | 0x02 | 用于应答指令 |
Sub Type
控制帧的Sub Type
| 类型名称 | 类型值 | 类型说明 | 回复帧类型 |
|---|---|---|---|
| 设置 Wi‑Fi | 0x05 | 用于设置WI-FI指令 | 应答帧 0x02 |
| 设置 MQTT | 0x06 | 用于设置MQTT指令 | 应答帧 0x02 |
| 获取版本信息 | 0x07 | 用于获取设备版本信息指令 | 数据帧 0x03 |
| 重启设备 | 0x08 | 用于重启设备指令 | 应答帧 0x02 |
| 设置串口参数 | 0x0A | 用于设置串口指令 | 应答帧 0x02 |
| 设置低功耗模式参数 | 0x0E | 用于设置低功耗参数指令 | 应答帧 0x02 |
| 获取低功耗模式参数 | 0x0F | 用于设置获取低功耗参数指令 | 数据帧 0x03 |
| 清除WI-FI与MQTT配置 | 0x10 | 用于清除WI-FI与MQTT配置指令 | 应答帧 0x02 |
| 获取WI-FI参数和状态 | 0x11 | 获取WI-FI状态 | 数据帧 0x03 |
| 获取MQTT参数和状态 | 0x12 | 用于清除WI-FI与MQTT配置指令 | 数据帧 0x03 |
| 获取UART参数 | 0x13 | 用于清除WI-FI与MQTT配置指令 | 数据帧 0x03 |
数据帧的Sub Type
| 类型名称 | 类型值 | 类型说明 |
|---|---|---|
| 设备版本信息 | 0x10 | 版本信息 |
| 低功耗设置 | 0x13 | 低功耗设置的数据 |
| WI-FI状态数据 | 0x14 | WI-FI状态数据 |
| MQTT状态数据 | 0x15 | MQTT状态数据 |
| UART设置数据 | 0x16 | UART设置数据 |
应答帧 Sub Type
与控制帧一致。
Payload 只带有一个值 0/1
分别表示 失败 / 成功
ctrl
帧控制字段定义
| 是否还有数据分片 | 是否为 ACK 帧 | 数据方向 | 是否包含校验位 | 是否加密 |
|---|---|---|---|---|
| 0x10 | 0x08 | 0x04 | 0x02 | 0x01 |
0x01 是否加密 (0: 不加密;1: 加密)
0x02:是否包含校验位(CRC等)
0x04:数据方向(0: 手机->设备;1: 设备->手机)
0x08:是否为 ACK 帧 (废除)
0x10:是否还有后续数据分片(1 表示还有分片)
使用的时候进行或运算即可
seq
分片序号
len
当前帧传输数据的长度
data_total
分片的时候有效,当表示数据总的长度
data
传输的数据内容
crc
CRC16 校验 校验为止从帧头开始一直到data。
Data格式 (TLV)
TLV(Type-Length-Value)是一种高效的数据编码格式,通过“类型-长度-值”三元组实现灵活的数据传输,特别适合物联网、网络协议等场景。
核心结构
Type(类型):固定长度字段(1字节),标识数据类型。
Length(长度):动态变长编码(1字节),声明Value的字节数。
Value(值):实际数据内容,长度由Length指定。WIFI设置
0x01: SSID (str), //SSID
0x02: Password (str) //密码
MQTT设置:
0x00 is_ssl //是否开启SSL (预留,默认为不开启)
0x01 server //服务器地址
0x02 port //服务器端口号
0x03 username //用户名
0x04 password //密码
0x05 topic //自定义topic
0x06 server_ca_pem //证书(预留)
0x07 client_cert_pem //证书(预留)
0x08 client_key_pem //证书(预留)
0x09 mqtt_proto //MQTT 协议版本 默认 311 ,值 311,31,5
NOTE
SSL 当前版本未实现。啥时候实现待定。主要没有合适的测试环境
串口设置命令
0x01 baud, //波特率
0x02 data_bits, //数据位
0x03 stop_bits, //停止位
0x04 parity, //奇偶校验
0x05 flow_control //流量控制
状态采集指令
// Wi‑Fi 相关字段
const int TLV_WIFI_STATE = 0x01; // u8
const int TLV_WIFI_SSID = 0x02; // str
const int TLV_WIFI_IP = 0x03; // str
const int TLV_TYPE_WIFI_DISCONNECT_REASON = 0x0E //u8
// MQTT 相关字段
const int TLV_MQTT_STATE = 0x04; // u8
const int TLV_MQTT_URI = 0x05; // str (server address or URI)
const int TLV_MQTT_SUB_TOPIC = 0x06; // str
const int TLV_MQTT_PUB_TOPIC = 0x07; // str
// 串口(UART)相关字段
const int TLV_UART_BAUD = 0x08; // u32 BE
const int TLV_UART_DATA_BITS = 0x09; // u8
const int TLV_UART_STOP_BITS = 0x0A; // u8 (encoded: 0,1,1.5,2 as 0..3)
const int TLV_UART_PARITY = 0x0B; // u8 (0 none,1 odd,2 even)
const int TLV_UART_FLOW = 0x0C; // u8 (0 none,1 hw,2 sw)
OTA_URL 设置命令 (预留)
0x01: OTA URL (string). len==0 表示清除 OTA_URL。
低功耗设置命令
0x01: deep_sleep_enable (u8) 0/1
0x02: deep_sleep_wake_sec (u32 BE)
0x03: awake_keep_sec (u32 BE)
WIFI 断网原因对照表
const Map<int, String> m = <int, String>{
1: 'UNSPECIFIED',
2: 'AUTH_EXPIRE',
3: 'AUTH_LEAVE',
4: 'DISASSOC_DUE_TO_INACTIVITY',
5: 'ASSOC_TOOMANY',
6: 'CLASS2_FRAME_FROM_NONAUTH_STA',
7: 'CLASS3_FRAME_FROM_NONASSOC_STA',
8: 'ASSOC_LEAVE',
9: 'ASSOC_NOT_AUTHED',
10: 'DISASSOC_PWRCAP_BAD',
11: 'DISASSOC_SUPCHAN_BAD',
12: 'BSS_TRANSITION_DISASSOC',
13: 'IE_INVALID',
14: 'MIC_FAILURE',
15: '4WAY_HANDSHAKE_TIMEOUT',
16: 'GROUP_KEY_UPDATE_TIMEOUT',
17: 'IE_IN_4WAY_DIFFERS',
18: 'GROUP_CIPHER_INVALID',
19: 'PAIRWISE_CIPHER_INVALID',
20: 'AKMP_INVALID',
21: 'UNSUPP_RSN_IE_VERSION',
22: 'INVALID_RSN_IE_CAP',
23: '802_1X_AUTH_FAILED',
24: 'CIPHER_SUITE_REJECTED',
25: 'TDLS_PEER_UNREACHABLE',
26: 'TDLS_UNSPECIFIED',
27: 'SSP_REQUESTED_DISASSOC',
28: 'NO_SSP_ROAMING_AGREEMENT',
29: 'BAD_CIPHER_OR_AKM',
30: 'NOT_AUTHORIZED_THIS_LOCATION',
31: 'SERVICE_CHANGE_PERCLUDES_TS',
32: 'UNSPECIFIED_QOS',
33: 'NOT_ENOUGH_BANDWIDTH',
34: 'MISSING_ACKS',
35: 'EXCEEDED_TXOP',
36: 'STA_LEAVING',
37: 'END_BA',
38: 'UNKNOWN_BA',
39: 'TIMEOUT',
46: 'PEER_INITIATED',
47: 'AP_INITIATED',
48: 'INVALID_FT_ACTION_FRAME_COUNT',
49: 'INVALID_PMKID',
50: 'INVALID_MDE',
51: 'INVALID_FTE',
67: 'TRANSMISSION_LINK_ESTABLISH_FAILED',
68: 'ALTERATIVE_CHANNEL_OCCUPIED',
200: 'BEACON_TIMEOUT',
201: 'NO_AP_FOUND',
202: 'AUTH_FAIL',
203: 'ASSOC_FAIL',
204: 'HANDSHAKE_TIMEOUT',
205: 'CONNECTION_FAIL',
206: 'AP_TSF_RESET',
207: 'ROAMING',
208: 'ASSOC_COMEBACK_TIME_TOO_LONG',
209: 'SA_QUERY_TIMEOUT',
210: 'NO_AP_FOUND_W_COMPATIBLE_SECURITY',
211: 'NO_AP_FOUND_IN_AUTHMODE_THRESHOLD',
212: 'NO_AP_FOUND_IN_RSSI_THRESHOLD',
};长度限制
参数
| 参数 | 最大长度(char) |
|---|---|
| WI-FI SSID | 32 |
| WI-FI Password | 64 |
| MQTT 自定义topic | 16 |
| MQTT sub/pub 订阅和发布的主题 | 128 |
透传
透传为最大 1024 char.
分帧说明
由于蓝牙MTU设置为23,所以Data过长的时候是需要分帧的。解析前需要把分帧合并成单帧再进行解析
指令例子
WI-FI状态查询
发送:[0xBC, 0x59, 0x51, 0x44, 0x02, 0x00, 0x00, 0x1C, 0xC9]
接收:[0xBC, 0x59, 0x51, 0x51, 0x06, 0x00, 0x1E, 0x01, 0x01, 0x04, 0x0E, 0x01, 0x00, 0x02, 0x07, 0x37, 0x31, 0x32, 0x30, 0x31, 0x2D, 0x32, 0x03, 0x0D, 0x31, 0x39, 0x32, 0x2E, 0x31, 0x36, 0x38, 0x2E, 0x39, 0x2E, 0x31, 0x30, 0x38, 0x35, 0x1B]
请求帧字段解析
请求帧:[0xBC, 0x59, 0x51, 0x44, 0x02, 0x00, 0x00, 0x1C, 0xC9]
| 字段 | 字节 | 值 | 说明 |
|---|---|---|---|
| header | 3 | BC 59 51 | 固定帧头 |
| type | 1 | 44 | type & 0x03 = 0 → 控制帧;type >> 2 = 0x11 → SubType=0x11(获取 WI-FI 参数和状态) |
| ctrl | 1 | 02 | 包含 CRC(0x02) |
| seq | 1 | 00 | 序号(示例为 0) |
| len | 1 | 00 | 数据长度为 0(本指令无 payload) |
| crc | 2 | 1C C9 | CRC16(从 header 到 data 末尾) |
响应帧字段解析
响应帧:[0xBC, 0x59, 0x51, 0x51, 0x06, 0x00, 0x1E, ... , 0x35, 0x1B]
| 字段 | 字节 | 值 | 说明 |
|---|---|---|---|
| header | 3 | BC 59 51 | 固定帧头 |
| type | 1 | 51 | type & 0x03 = 1 → 数据帧;type >> 2 = 0x14 → SubType=0x14(WI-FI 状态数据) |
| ctrl | 1 | 06 | 0x04 设备→手机 + 0x02 包含 CRC |
| seq | 1 | 00 | 序号(示例为 0) |
| len | 1 | 1E | 数据长度 0x1E = 30 字节 |
| data | len | 见下 | TLV 数据 |
| crc | 2 | 35 1B | CRC16(从 header 到 data 末尾) |
响应 data(TLV)解析
响应 data 共 30 字节,按 TLV(Type-Length-Value)解析如下:
01 01 04
- Type=
0x01(TLV_WIFI_STATE) - Length=
0x01 - Value=
0x04→WIFI_STATE_GOT_IP(已联网并获取 IP)
0E 01 00
- Type=
0x0E(TLV_TYPE_WIFI_DISCONNECT_REASON) - Length=
0x01 - Value=
0x00(示例值为 0;如断网可对照上面的断网原因表)
02 07 37 31 32 30 31 2D 32
- Type=
0x02(TLV_WIFI_SSID) - Length=
0x07 - Value=
37 31 32 30 31 2D 32→ ASCII 字符串71201-2
03 0D 31 39 32 2E 31 36 38 2E 39 2E 31 30 38
- Type=
0x03(TLV_WIFI_IP) - Length=
0x0D - Value=
31 39 32 2E 31 36 38 2E 39 2E 31 30 38→ ASCII 字符串192.168.9.108
MQTT状态查询
发送(十六进制):[0xBC, 0x59, 0x51, 0x48, 0x02, 0x00, 0x00, 0x53, 0xFB]
接收(十六进制):[0xBC, 0x59, 0x51, 0x55, 0x06, 0x00, 0x62, ... , 0x87, 0xD6]
请求帧字段解析
请求帧:[0xBC, 0x59, 0x51, 0x48, 0x02, 0x00, 0x00, 0x53, 0xFB]
| 字段 | 字节 | 值 | 说明 |
|---|---|---|---|
| header | 3 | BC 59 51 | 固定帧头 |
| type | 1 | 48 | type & 0x03 = 0 → 控制帧;type >> 2 = 0x12 → SubType=0x12(获取 MQTT 参数和状态) |
| ctrl | 1 | 02 | 包含 CRC(0x02) |
| seq | 1 | 00 | 序号(示例为 0) |
| len | 1 | 00 | 数据长度为 0(本指令无 payload) |
| crc | 2 | 53 FB | CRC16(从 header 到 data 末尾) |
响应帧字段解析
响应帧(完整十进制数组):
text
[0xBC, 0x59, 0x51, 0x55, 0x06, 0x00, 0x62, 0x04, 0x01, 0x02, 0x05, 0x17, 0x6D, 0x71, 0x74, 0x74, 0x3A, 0x2F, 0x2F, 0x31, 0x30, 0x31, 0x2E, 0x34, 0x32, 0x2E, 0x34, 0x2E, 0x35, 0x31, 0x3A, 0x31, 0x38, 0x38, 0x33, 0x06, 0x21, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x2F, 0x65, 0x73, 0x70, 0x2F, 0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x2F, 0x73, 0x75, 0x62, 0x2F, 0x36, 0x43, 0x43, 0x38, 0x34, 0x30, 0x42, 0x42, 0x42, 0x38, 0x30, 0x45, 0x07, 0x21, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x2F, 0x65, 0x73, 0x70, 0x2F, 0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x2F, 0x70, 0x75, 0x62, 0x2F, 0x36, 0x43, 0x43, 0x38, 0x34, 0x30, 0x42, 0x42, 0x42, 0x38, 0x30, 0x45, 0x87, 0xD6]| 字段 | 字节 | 值 | 说明 |
|---|---|---|---|
| header | 3 | BC 59 51 | 固定帧头 |
| type | 1 | 55 | type & 0x03 = 1 → 数据帧;type >> 2 = 0x15 → SubType=0x15(MQTT 状态数据) |
| ctrl | 1 | 06 | 0x04 设备→手机 + 0x02 包含 CRC |
| seq | 1 | 00 | 序号(示例为 0) |
| len | 1 | 62 | 数据长度 0x62 = 98 字节 |
| data | len | 见下 | TLV 数据 |
| crc | 2 | 87 D6 | CRC16(从 header 到 data 末尾) |
响应 data(TLV)解析
响应 data 共 98 字节,按 TLV(Type-Length-Value)解析如下:
04 01 02
- Type=
0x04(TLV_MQTT_STATE) - Length=
0x01 - Value=
0x02→MQTT_STATE_CONNECTED(已连接)
05 17 6D 71 74 74 3A 2F 2F 31 30 31 2E 34 32 2E 34 2E 35 31 3A 31 38 38 33
- Type=
0x05(TLV_MQTT_URI) - Length=
0x17(23 字节) - Value → ASCII 字符串
mqtt://101.42.4.51:1883
06 21 ...
- Type=
0x06(TLV_MQTT_SUB_TOPIC) - Length=
0x21(33 字节) - Value → ASCII 字符串
trans/esp/client/sub/6CC840BBB80E
07 21 ...
- Type=
0x07(TLV_MQTT_PUB_TOPIC) - Length=
0x21(33 字节) - Value → ASCII 字符串
trans/esp/client/pub/6CC840BBB80E
UART参数查询
发送(十六进制):[0xBC, 0x59, 0x51, 0x4C, 0x02, 0x00, 0x00, 0x99, 0x0A]
接收(十六进制):[0xBC, 0x59, 0x51, 0x59, 0x06, 0x00, 0x12, 0x08, 0x04, 0x00, 0x00, 0x25, 0x80, 0x09, 0x01, 0x08, 0x0A, 0x01, 0x01, 0x0B, 0x01, 0x00, 0x0C, 0x01, 0x00, 0x97, 0x56]
请求帧字段解析
请求帧:[0xBC, 0x59, 0x51, 0x4C, 0x02, 0x00, 0x00, 0x99, 0x0A]
| 字段 | 字节 | 值 | 说明 |
|---|---|---|---|
| header | 3 | BC 59 51 | 固定帧头 |
| type | 1 | 4C | type & 0x03 = 0 → 控制帧;type >> 2 = 0x13 → SubType=0x13(获取 UART 参数) |
| ctrl | 1 | 02 | 包含 CRC(0x02) |
| seq | 1 | 00 | 序号(示例为 0) |
| len | 1 | 00 | 数据长度为 0(本指令无 payload) |
| crc | 2 | 99 0A | CRC16(从 header 到 data 末尾) |
响应帧字段解析
响应帧:[0xBC, 0x59, 0x51, 0x59, 0x06, 0x00, 0x12, ... , 0x97, 0x56]
| 字段 | 字节 | 值 | 说明 |
|---|---|---|---|
| header | 3 | BC 59 51 | 固定帧头 |
| type | 1 | 59 | type & 0x03 = 1 → 数据帧;type >> 2 = 0x16 → SubType=0x16(UART 设置数据) |
| ctrl | 1 | 06 | 0x04 设备→手机 + 0x02 包含 CRC |
| seq | 1 | 00 | 序号(示例为 0) |
| len | 1 | 12 | 数据长度 0x12 = 18 字节 |
| data | len | 见下 | TLV 数据 |
| crc | 2 | 97 56 | CRC16(从 header 到 data 末尾) |
响应 data(TLV)解析
响应 data 共 18 字节,按 TLV(Type-Length-Value)解析如下:
08 04 00 00 25 80
- Type=
0x08(TLV_UART_BAUD) - Length=
0x04 - Value=
00 00 25 80(u32 BE)→ 9600
09 01 08
- Type=
0x09(TLV_UART_DATA_BITS) - Length=
0x01 - Value=
0x08→ 数据位 8
0A 01 01
- Type=
0x0A(TLV_UART_STOP_BITS) - Length=
0x01 - Value=
0x01→ 停止位编码 1(对应 1 stop bit)
0B 01 00
- Type=
0x0B(TLV_UART_PARITY) - Length=
0x01 - Value=
0x00→ parity none
0C 01 00
- Type=
0x0C(TLV_UART_FLOW) - Length=
0x01 - Value=
0x00→ flow control none
版本信息查询
发送(十六进制):[0xBC, 0x59, 0x51, 0x1C, 0x02, 0x00, 0x00, 0xEC, 0x31]
接收(十六进制):[0xBC, 0x59, 0x51, 0x41, 0x06, 0x00, 0x05, 0x31, 0x2E, 0x35, 0x2E, 0x31, 0xEA, 0x67]
请求帧字段解析
请求帧:[0xBC, 0x59, 0x51, 0x1C, 0x02, 0x00, 0x00, 0xEC, 0x31]
| 字段 | 字节 | 值 | 说明 |
|---|---|---|---|
| header | 3 | BC 59 51 | 固定帧头 |
| type | 1 | 1C | type & 0x03 = 0 → 控制帧;type >> 2 = 0x07 → SubType=0x07(获取版本信息) |
| ctrl | 1 | 02 | 包含 CRC(0x02) |
| seq | 1 | 00 | 序号(示例为 0) |
| len | 1 | 00 | 数据长度为 0(本指令无 payload) |
| crc | 2 | EC 31 | CRC16(从 header 到 data 末尾) |
响应帧字段解析
响应帧:[0xBC, 0x59, 0x51, 0x41, 0x06, 0x00, 0x05, ... , 0xEA, 0x67]
| 字段 | 字节 | 值 | 说明 |
|---|---|---|---|
| header | 3 | BC 59 51 | 固定帧头 |
| type | 1 | 41 | type & 0x03 = 1 → 数据帧;type >> 2 = 0x10 → SubType=0x10(设备版本信息) |
| ctrl | 1 | 06 | 0x04 设备→手机 + 0x02 包含 CRC |
| seq | 1 | 00 | 序号(示例为 0) |
| len | 1 | 05 | 数据长度 5 字节 |
| data | len | 31 2E 35 2E 31 | ASCII 字符串 1.5.1 |
| crc | 2 | EA 67 | CRC16(从 header 到 data 末尾) |
设置 Wi‑Fi(分帧示例)
提醒:分片帧需要先按
data_total合并成完整 data,再按 TLV 解析。
发送三个分帧:
[0xBC, 0x59, 0x51, 0x14, 0x12, 0x00, 0x09, 0x00, 0x13, 0x01, 0x07, 0x37, 0x31, 0x32, 0x30, 0x31, 0x2D, 0x32, 0x7C, 0x40][0xBC, 0x59, 0x51, 0x14, 0x12, 0x00, 0x09, 0x00, 0x13, 0x02, 0x08, 0x31, 0x71, 0x32, 0x65, 0x33, 0x65, 0x34, 0x00, 0x4E][0xBC, 0x59, 0x51, 0x14, 0x02, 0x00, 0x01, 0x00, 0x13, 0x72, 0x0E, 0x18]
接收:[0xBC, 0x59, 0x51, 0x16, 0x06, 0x00, 0x01, 0x00, 0xB2, 0xCC]
分片请求帧字段解析(以第 1 帧为例)
第 1 帧:[0xBC, 0x59, 0x51, 0x14, 0x12, 0x00, 0x09, 0x00, 0x13, ... , 0x7C, 0x40]
| 字段 | 字节 | 值 | 说明 |
|---|---|---|---|
| header | 3 | BC 59 51 | 固定帧头 |
| type | 1 | 14 | type & 0x03 = 0 → 控制帧;type >> 2 = 0x05 → SubType=0x05(设置 Wi‑Fi) |
| ctrl | 1 | 12 | 0x10 表示还有后续分片 + 0x02 表示包含 CRC |
| seq | 1 | 00 | 分片序号(本示例中均为 0;实现若使用递增序号,应按 seq 排序再合并) |
| len | 1 | 09 | 当前分片 data 长度(不含 data_total 与 crc) |
| data_total | 2 | 00 13 | 完整 data 总长度 0x0013 = 19 字节 |
| data | len | 见下 | 分片数据 |
| crc | 2 | 7C 40 | CRC16(从 header 到本分片 data 末尾) |
合帧(把 3 个分片的 data 拼接)
三个分片的 data(len) 依次为:
- 分片 1:
01 07 37 31 32 30 31 2D 32 - 分片 2:
02 08 31 71 32 65 33 65 34 - 分片 3:
72
合并后的完整 data(19 字节)为:
01 07 37 31 32 30 31 2D 32 02 08 31 71 32 65 33 65 34 72
合并后 data(TLV)解析
按“WIFI设置”TLV 约定:0x01=SSID、0x02=Password。
01 07 37 31 32 30 31 2D 32
- Type=
0x01(SSID) - Length=
0x07 - Value → ASCII:
71201-2
02 08 31 71 32 65 33 65 34 72
- Type=
0x02(Password) - Length=
0x08 - Value → ASCII:
1q2e3e4r
响应帧(ACK)解析
理论上:
接收:[0xBC, 0x59, 0x51, 0x16, 0x06, 0x00, 0x01, 0x00, 0xB2, 0xCC]
type=0x16→type & 0x03 = 2(应答帧),type >> 2 = 0x05(对应设置 Wi‑Fi 的 ACK)len=0x01,payload=0x00- 按文档约定:
0=失败,1=成功→ 本次设置结果为失败 实际上已经重启。没有回复帧。 后期补上吧。
- 按文档约定:
设置 MQTT(分帧示例)
说明:与“设置 Wi‑Fi(分帧示例)”一致,先按
data_total合并完整 data,再按 MQTT 的 TLV 定义解析。
发送分帧(仅十六进制):
[0xBC, 0x59, 0x51, 0x18, 0x12, 0x00, 0x09, 0x00, 0x3F, 0x00, 0x01, 0x00, 0x01, 0x0B, 0x31, 0x30, 0x31, 0x2E, 0x6A, 0xDC][0xBC, 0x59, 0x51, 0x18, 0x12, 0x00, 0x09, 0x00, 0x3F, 0x34, 0x32, 0x2E, 0x34, 0x2E, 0x35, 0x31, 0x02, 0x02, 0xDF, 0x61][0xBC, 0x59, 0x51, 0x18, 0x12, 0x00, 0x09, 0x00, 0x3F, 0x07, 0x5B, 0x03, 0x0D, 0x65, 0x73, 0x70, 0x5F, 0x6D, 0x4A, 0xA1][0xBC, 0x59, 0x51, 0x18, 0x12, 0x00, 0x09, 0x00, 0x3F, 0x71, 0x74, 0x74, 0x5F, 0x75, 0x73, 0x65, 0x72, 0x04, 0x5E, 0x55][0xBC, 0x59, 0x51, 0x18, 0x12, 0x00, 0x09, 0x00, 0x3F, 0x11, 0x65, 0x73, 0x70, 0x5F, 0x6D, 0x71, 0x74, 0x74, 0x89, 0x2D][0xBC, 0x59, 0x51, 0x18, 0x12, 0x00, 0x09, 0x00, 0x3F, 0x5F, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6F, 0x72, 0x64, 0x59, 0x97][0xBC, 0x59, 0x51, 0x18, 0x02, 0x00, 0x09, 0x00, 0x3F, 0x05, 0x03, 0x65, 0x73, 0x70, 0x09, 0x02, 0x01, 0x37, 0x25, 0x3B]
接收(ACK):[0xBC, 0x59, 0x51, 0x1A, 0x06, 0x00, 0x01, 0x00, 0x39, 0xE7]
分片请求帧字段解析(以第 1 帧为例)
第 1 帧:[0xBC, 0x59, 0x51, 0x18, 0x12, 0x00, 0x09, 0x00, 0x3F, ...]
type=0x18→ 控制帧,type >> 2 = 0x06(设置 MQTT)ctrl=0x12→ 有后续分片(0x10)+ 含 CRC(0x02)len=0x09data_total=0x003F→ 完整 data 总长度 63 字节
合帧(把 7 个分片的 data 拼接)
合并后的完整 data(63 字节)为:
00 01 00 01 0B 31 30 31 2E 34 32 2E 34 2E 35 31 02 02 07 5B 03 0D 65 73 70 5F 6D 71 74 74 5F 75 73 65 72 04 11 65 73 70 5F 6D 71 74 74 5F 70 61 73 73 77 6F 72 64 05 03 65 73 70 09 02 01 37
合并后 data(TLV)解析
按“MQTT设置”TLV 约定:
0x00 is_ssl0x01 server0x02 port0x03 username0x04 password0x05 topic0x09 mqtt_proto
00 01 00
- Type=
0x00(is_ssl) - Length=
0x01 - Value=
0x00→ 关闭 SSL
01 0B 31 30 31 2E 34 32 2E 34 2E 35 31
- Type=
0x01(server) - Length=
0x0B - Value → ASCII:
101.42.4.51
02 02 07 5B
- Type=
0x02(port) - Length=
0x02 - Value=
07 5B(u16 BE)→ 1883
03 0D 65 73 70 5F 6D 71 74 74 5F 75 73 65 72
- Type=
0x03(username) - Length=
0x0D - Value → ASCII:
esp_mqtt_user
04 11 65 73 70 5F 6D 71 74 74 5F 70 61 73 73 77 6F 72 64
- Type=
0x04(password) - Length=
0x11 - Value → ASCII:
esp_mqtt_password
05 03 65 73 70
- Type=
0x05(topic) - Length=
0x03 - Value → ASCII:
esp
09 02 01 37
- Type=
0x09(mqtt_proto) - Length=
0x02 - Value=
01 37(u16 BE)→ 311(即 MQTT 3.1.1)
响应帧(ACK)解析
接收:[0xBC, 0x59, 0x51, 0x1A, 0x06, 0x00, 0x01, 0x00, 0x39, 0xE7]
type=0x1A→type & 0x03 = 2(应答帧),type >> 2 = 0x06(对应设置 MQTT 的 ACK)len=0x01,payload=0x00- 按文档约定:
0=失败,1=成功→ 本次设置结果为失败
- 按文档约定:
设置 UART(分帧示例)
发送分帧(仅十六进制):
[0xBC, 0x59, 0x51, 0x28, 0x12, 0x00, 0x09, 0x00, 0x12, 0x01, 0x04, 0x00, 0x00, 0x25, 0x80, 0x02, 0x01, 0x08, 0x44, 0xC4][0xBC, 0x59, 0x51, 0x28, 0x02, 0x00, 0x09, 0x00, 0x12, 0x03, 0x01, 0x01, 0x04, 0x01, 0x00, 0x05, 0x01, 0x00, 0xEA, 0x38]
接收(ACK):[0xBC, 0x59, 0x51, 0x2A, 0x06, 0x00, 0x01, 0x00, 0x35, 0x09]
分片请求帧字段解析(以第 1 帧为例)
第 1 帧:[0xBC, 0x59, 0x51, 0x28, 0x12, 0x00, 0x09, 0x00, 0x12, ...]
type=0x28→ 控制帧,type >> 2 = 0x0A(设置串口参数)ctrl=0x12→ 有后续分片(0x10)+ 含 CRC(0x02)len=0x09data_total=0x0012→ 完整 data 总长度 18 字节
合帧(把 2 个分片的 data 拼接)
两个分片的 data(len) 依次为:
- 分片 1:
01 04 00 00 25 80 02 01 08 - 分片 2:
03 01 01 04 01 00 05 01 00
合并后的完整 data(18 字节)为:
01 04 00 00 25 80 02 01 08 03 01 01 04 01 00 05 01 00
合并后 data(TLV)解析
按“串口设置命令”TLV 约定:
0x01 baud0x02 data_bits0x03 stop_bits0x04 parity0x05 flow_control
01 04 00 00 25 80
- Type=
0x01(baud) - Length=
0x04 - Value=
00 00 25 80(u32 BE)→ 9600
02 01 08
- Type=
0x02(data_bits) - Length=
0x01 - Value=
0x08→ 8
03 01 01
- Type=
0x03(stop_bits) - Length=
0x01 - Value=
0x01→ 1 stop bit
04 01 00
- Type=
0x04(parity) - Length=
0x01 - Value=
0x00→ none
05 01 00
- Type=
0x05(flow_control) - Length=
0x01 - Value=
0x00→ none
响应帧(ACK)解析
接收:[0xBC, 0x59, 0x51, 0x2A, 0x06, 0x00, 0x01, 0x00, 0x35, 0x09]
type=0x2A→type & 0x03 = 2(应答帧),type >> 2 = 0x0A(对应设置串口参数的 ACK)len=0x01,payload=0x00- 按文档约定:
0=失败,1=成功→ 本次设置结果为失败
- 按文档约定:
重启设备
发送(十六进制):[0xBC, 0x59, 0x51, 0x20, 0x02, 0x00, 0x00, 0x8F, 0xEA]
请求帧字段解析
请求帧:[0xBC, 0x59, 0x51, 0x20, 0x02, 0x00, 0x00, 0x8F, 0xEA]
| 字段 | 字节 | 值 | 说明 |
|---|---|---|---|
| header | 3 | BC 59 51 | 固定帧头 |
| type | 1 | 20 | type & 0x03 = 0 → 控制帧;type >> 2 = 0x08 → SubType=0x08(重启设备) |
| ctrl | 1 | 02 | 包含 CRC(0x02) |
| seq | 1 | 00 | 序号(示例为 0) |
| len | 1 | 00 | 数据长度为 0(本指令无 payload) |
| crc | 2 | 8F EA | CRC16(从 header 到 data 末尾) |
响应帧(ACK)解析(理论)
说明:重启指令可能会在设备重启前来不及返回 ACK;以下为按协议约定的 ACK 帧格式。
理论 ACK:[0xBC, 0x59, 0x51, 0x22, 0x06, 0x00, 0x01, <result>, <crc1>, <crc2>]
type=0x22→type & 0x03 = 2(应答帧),type >> 2 = 0x08(对应重启设备的 ACK)len=0x01,payload=<result><result>=0x00:失败<result>=0x01:成功
设置 Low Power(分帧示例)
发送分帧(十六进制):
[0xBC, 0x59, 0x51, 0x38, 0x12, 0x00, 0x09, 0x00, 0x0F, 0x01, 0x01, 0x01, 0x02, 0x04, 0x00, 0x00, 0x17, 0x70, 0x2A, 0x8B][0xBC, 0x59, 0x51, 0x38, 0x02, 0x00, 0x06, 0x00, 0x0F, 0x03, 0x04, 0x00, 0x01, 0x5F, 0x90, 0xDE, 0x99]
接收(ACK):[0xBC, 0x59, 0x51, 0x3A, 0x06, 0x00, 0x01, 0x00, 0x31, 0x53]
分片请求帧字段解析(以第 1 帧为例)
第 1 帧:[0xBC, 0x59, 0x51, 0x38, 0x12, 0x00, 0x09, 0x00, 0x0F, ...]
type=0x38→ 控制帧,type >> 2 = 0x0E(设置低功耗模式参数)ctrl=0x12→ 有后续分片(0x10)+ 含 CRC(0x02)len=0x09data_total=0x000F→ 完整 data 总长度 15 字节
合帧(把 2 个分片的 data 拼接)
两个分片的 data(len) 依次为:
- 分片 1:
01 01 01 02 04 00 00 17 70 - 分片 2:
03 04 00 01 5F 90
合并后的完整 data(15 字节)为:
01 01 01 02 04 00 00 17 70 03 04 00 01 5F 90
合并后 data(TLV)解析
按“低功耗设置命令”TLV 约定:
0x01 deep_sleep_enable (u8)0x02 deep_sleep_wake_sec (u32 BE)0x03 awake_keep_sec (u32 BE)
01 01 01
deep_sleep_enable=1
02 04 00 00 17 70
deep_sleep_wake_sec=0x00001770→ 6000 秒(约 100 分钟)
03 04 00 01 5F 90
awake_keep_sec=0x00015F90→ 90000 秒(25 小时)
响应帧(ACK)解析
接收:[0xBC, 0x59, 0x51, 0x3A, 0x06, 0x00, 0x01, 0x00, 0x31, 0x53]
type=0x3A→type & 0x03 = 2(应答帧),type >> 2 = 0x0E(对应设置低功耗模式参数的 ACK)len=0x01,payload=0x00- 按文档约定:
0=失败,1=成功→ 本次设置结果为失败
- 按文档约定:
查询 Low Power(获取低功耗模式参数)
发送(十六进制):[0xBC, 0x59, 0x51, 0x3C, 0x02, 0x00, 0x00, 0xDB, 0x7F]
接收(十六进制):[0xBC, 0x59, 0x51, 0x4D, 0x06, 0x00, 0x0F, 0x01, 0x01, 0x01, 0x02, 0x04, 0x00, 0x00, 0x17, 0x70, 0x03, 0x04, 0x00, 0x01, 0x5F, 0x90, 0x8D, 0x5A]
请求帧字段解析
请求帧:[0xBC, 0x59, 0x51, 0x3C, 0x02, 0x00, 0x00, 0xDB, 0x7F]
| 字段 | 字节 | 值 | 说明 |
|---|---|---|---|
| header | 3 | BC 59 51 | 固定帧头 |
| type | 1 | 3C | type & 0x03 = 0 → 控制帧;type >> 2 = 0x0F → SubType=0x0F(获取低功耗模式参数) |
| ctrl | 1 | 02 | 包含 CRC(0x02) |
| seq | 1 | 00 | 序号(示例为 0) |
| len | 1 | 00 | 数据长度为 0(本指令无 payload) |
| crc | 2 | DB 7F | CRC16(从 header 到 data 末尾) |
响应帧字段解析
响应帧:[0xBC, 0x59, 0x51, 0x4D, 0x06, 0x00, 0x0F, ... , 0x8D, 0x5A]
| 字段 | 字节 | 值 | 说明 |
|---|---|---|---|
| header | 3 | BC 59 51 | 固定帧头 |
| type | 1 | 4D | type & 0x03 = 1 → 数据帧;type >> 2 = 0x13 → SubType=0x13(低功耗设置数据) |
| ctrl | 1 | 06 | 0x04 设备→手机 + 0x02 包含 CRC |
| seq | 1 | 00 | 序号(示例为 0) |
| len | 1 | 0F | 数据长度 0x0F = 15 字节 |
| data | len | 见下 | TLV 数据 |
| crc | 2 | 8D 5A | CRC16(从 header 到 data 末尾) |
响应 data(TLV)解析
响应 data 共 15 字节,按“低功耗设置命令”TLV 约定解析如下:
01 01 01
deep_sleep_enable=1
02 04 00 00 17 70
deep_sleep_wake_sec=0x00001770→ 6000 秒(约 100 分钟)
03 04 00 01 5F 90
awake_keep_sec=0x00015F90→ 90000 秒(25 小时)
清除网络配置(清除WI-FI与MQTT配置)
发送(十六进制):[0xBC, 0x59, 0x51, 0x40, 0x02, 0x00, 0x00, 0xD6, 0x38]
接收(十六进制):[0xBC, 0x59, 0x51, 0x42, 0x06, 0x00, 0x01, 0x00, 0x2E, 0xF8]
请求帧字段解析
请求帧:[0xBC, 0x59, 0x51, 0x40, 0x02, 0x00, 0x00, 0xD6, 0x38]
| 字段 | 字节 | 值 | 说明 |
|---|---|---|---|
| header | 3 | BC 59 51 | 固定帧头 |
| type | 1 | 40 | type & 0x03 = 0 → 控制帧;type >> 2 = 0x10 → SubType=0x10(清除WI-FI与MQTT配置) |
| ctrl | 1 | 02 | 包含 CRC(0x02) |
| seq | 1 | 00 | 序号(示例为 0) |
| len | 1 | 00 | 数据长度为 0(本指令无 payload) |
| crc | 2 | D6 38 | CRC16(从 header 到 data 末尾) |
响应帧(ACK)解析
响应帧:[0xBC, 0x59, 0x51, 0x42, 0x06, 0x00, 0x01, 0x00, 0x2E, 0xF8]
| 字段 | 字节 | 值 | 说明 |
|---|---|---|---|
| header | 3 | BC 59 51 | 固定帧头 |
| type | 1 | 42 | type & 0x03 = 2 → 应答帧;type >> 2 = 0x10 → SubType=0x10(清除WI-FI与MQTT配置的 ACK) |
| ctrl | 1 | 06 | 0x04 设备→手机 + 0x02 包含 CRC |
| seq | 1 | 00 | 序号(示例为 0) |
| len | 1 | 01 | 数据长度 1 字节 |
| payload | 1 | 00 | 结果 0=失败,1=成功(本例为 0,失败) |
| crc | 2 | 2E F8 | CRC16(从 header 到 data 末尾) |
说明:本例返回 0,表示清除失败。实际使用时 0x01 表示成功。
例子
提供了Flutter 的例子,代码风格人人有别。不喜勿喷。
gitee地址:https://gitee.com/buddycoder/u2mdemo