整理日期:2026-09-29;最近修订:2026-09-30。本文只记录报文证据、协议描述和待验证项。功能目标见 requirements.md,整体设计见 technical-design.md。协议描述可能过时;发生冲突时以真实报文为准。
2026-10-12 补充:逐字段结构和本轮用户确认见 协议详细描述。用户已明确
377/378不能依靠snno关联;服务端实现的379/380可使用snno关联,具体赋值规则仍待补充。下文保留原样本事实和当时的观察,不将新约定改写为旧抓包行为。2026-10-14 补充:业务层字段已由 FaultFilter_MQTT协议文档 定义。下文中与之冲突的旧描述已更正并标注;实报样本事实不变,且与该文档一致。
2026-10-16 补充:新增 2026-10-14 样本,包含文件上传消息
607~610和可解析的hexData。用户确认下载地址规律,并决定本工具只监听平台发起的上传。
| 标记 | 含义 |
|---|---|
| 实报 | 用户提供的 CloudLog_2026-09-29_063029.csv 中的 8 条真实通讯记录(附件未纳入仓库);以及 CloudLog_2026-10-14_104644.csv 中的 24 条记录 |
| 已验证代码 | 用户确认 service/repositories/mqtt/fwh_mqtt/fwh_mqtt_fault_record.go 已实现的部分协议结构可信 |
| FaultFilter 文档 | 设备侧故障录波服务的业务协议文档;定义 dataArea 内的业务字段,不覆盖 377~380 外层 |
| 描述 | 用户提供的旧协议说明;与 FaultFilter 文档冲突的部分已作废,其余未被实报或已验证代码覆盖的细节仍待验证 |
本工具只发送 377,其余消息(378、379、380、607~610)全部监听;380、607、610 由 FWH 平台发出(设计决策,2026-10-16,见 technical-design.md)。2026-09-29 日志只覆盖 cmd=0 和 cmd=2、设备类型 aGate、成功结果。cmd=1、cmd=3、pe 设备类型及失败结果没有实报样本。
实报中的四类消息均有 cmdType、equipNo、type、timeStamp、snno、len、crc、dataArea 字段。样本的 equipNo 均为 10060010A01X26310190,type=0。现有发送代码将 len 设为序列化后 dataArea 的字节长度,并计算其 CRC32 IEEE 大写十六进制值;接收报文是否始终采用同一计算方式,尚未单独验证。
cmdType |
方向 | 作用 | dataArea |
|---|---|---|---|
377 |
服务端 → 设备 | 故障录波操作指令 | cmd、data |
378 |
设备 → 服务端 | 对 377 的应答 |
cmd、result |
379 |
设备 → 服务端 | 故障录波信息上传请求 | cmd、result、按命令出现的 list / filename |
380 |
服务端 → 设备 | 对 379 的应答 |
cmd、result |
378 是对指令的应答,业务数据或文件处理结果出现在后续 379。不能只凭 378.result=0 判定录波数据已经取得。CSV 没有 MQTT topic;当前客户端代码发送到 fwh/s2c/mng/{sn},等待 fwh/c2s/mng/{sn} 的应答,但 379/380 的实际 topic 仍需确认。
379.dataArea 的 result/list/filename 与 FaultFilter 文档回复中 data 对象的内容一致,只是没有 data 包裹,推断 379 承载的就是 FaultFilter 回复。
377:服务端请求dataArea 的形状为 { "cmd": <整数>, "data": { "list": [...] } }。list 和每项的 info 均为数组。以下字段按每个 list[] / info[] 项列出。
cmd |
作用 | list[].type |
list[].info[] |
证据 |
|---|---|---|---|---|
0 |
获取实时数据;code=3 即故障录波总目录 |
实报为 aGate |
sn 字符串;codeList 整数数组(1~3;4/5 只能经 cmd=2 获取) |
aGate、codeList=[3] 为实报;code 字典来自 FaultFilter 文档 |
1 |
设置参数 | 已验证代码发送 pe 或 aGate |
sn 字符串;paraList 为 {id: 功能码, setVal: 十六进制字符串} 数组 |
已验证代码;本次无实报 |
2 |
获取记录 | 实报为 aGate |
sn 字符串;index 整数数组,元素为目录中的记录序号 |
aGate、index=[9] 为实报;旧描述的范围 1~16 未获 FaultFilter 文档支持,以目录为准 |
3 |
查询参数 | — | sn 字符串;idList 功能码数组 |
仅 FaultFilter 文档,无实报 |
4 / 90 / 99 |
退出/连通性测试 | — | data 为 {} |
仅 FaultFilter 文档,无实报 |
旧描述将部分 type 或 sn 写为 string[],而真实报文及已验证代码对应的是单个字符串字段。旧描述列出的 agate、mppt、apbox 不在 FaultFilter 文档中;业务层设备类型只有 pe 和 aGate。
378:设备对 377 的应答dataArea 包含 cmd 和整数 result。描述称 result=0 为成功,result=-1 为失败。实报覆盖 cmd=0 和 cmd=2 的 result=0;失败值及其后续行为待验证。FaultFilter 文档不定义 378。
379:设备上传dataArea.result 为总结果字符串:"ok" 全部子项成功,"error" 存在子项失败;命令无法进入处理时为错误说明(如 busy、pe sn not find)。实报中的 cmd=0 和 cmd=2 均为 "ok"。dataArea.list 是数组,每项包含 type 和 info[]。
cmd |
dataArea 中的业务字段 |
证据 |
|---|---|---|
0 |
list[].type;info[].sn;info[].hexList[],每项含 code 整数、resultOne 字符串、hexData 十六进制字符串 |
实报覆盖:type="aGate"、code=3、resultOne="ok",且有 hexData。hexData 为子设备原始字节,code=3 的结构为 1 字节条数 + N × 14 字节目录项(FaultFilter 文档 5.1.1) |
1 |
list[].type、info[].sn、info[].setResultList[{id, resultOne}] |
FaultFilter 文档。旧描述的 resultList[{id, result}](result 为 string[])有误;resultOne 为字符串 |
2 |
filename 字符串;list[].type;info[].sn;info[].indexInfo[],每项含 index 整数及 resultOne 字符串 |
实报覆盖:filename="2026-09-29_14_18_29",type="aGate",index 为 4 和 5,resultOne 均为 "ok"。index 是数据类型码(4=故障数据,5=波形数据),不是记录序号 |
3 |
list[].type、info[].sn、info[].idInfo[{id, idData, resultOne}] |
仅 FaultFilter 文档 |
旧描述称 379 的设备类型可为 aPower,FaultFilter 文档未定义该值,实报仅见 aGate。旧描述将 cmd=2 的 sn、resultOne 写为数组,实报中二者都是字符串。cmd=2 的 379 只显示文件名和逐项结果,没有录波文件字节或下载地址:文件保存在设备本地 /home/root/ExportFile/faultFilterRecode/<filename>/<sn>/index_<记录序号>/,随后由平台经 607~610 触发上传,见 2026-10-14 样本。
380:服务端对 379 的应答dataArea 包含 cmd 和整数 result。描述称 result=0 成功、result=-1 失败。实报覆盖 cmd=0 和 cmd=2 的 result=0;cmd=1 及失败值待验证。FaultFilter 文档不定义 380。
CSV 倒序展示;下表按 logTime 正序排列。logTime 比同一行的 time 晚 8 小时,与本地时间和 UTC 的差值一致。
| 本地时间 | 消息 | 关键字段 |
|---|---|---|
| 14:17:35 | 377 |
cmd=0,aGate,codeList=[3],snno=7529 |
| 14:17:35 | 378 |
cmd=0,result=0,snno=13 |
| 14:17:38 | 379 |
cmd=0,result="ok",hexList 中 code=3、resultOne="ok"、hexData,snno=14 |
| 14:17:46 | 380 |
cmd=0,result=0,snno=7536 |
| 14:17:47 | 377 |
cmd=2,aGate,index=[9],snno=7539 |
| 14:17:47 | 378 |
cmd=2,result=0,snno=22 |
| 14:18:31 | 379 |
cmd=2,result="ok",filename="2026-09-29_14_18_29",indexInfo 为 4/ok、5/ok,snno=26 |
| 14:18:33 | 380 |
cmd=2,result=0,snno=7559 |
请求 cmd=0 后约 3 秒出现 379;请求 cmd=2 后约 44 秒出现 379。这些是单次样本的观察值,不是超时规则。请求、应答和上传的 snno 不相同;尚不能用它直接关联消息。
该样本没有记录 607~610;当时是否发生上传无法从该日志判断。
来源:CloudLog_2026-10-14_104644.csv,测试服,网关 AFCI_TEST_0713,aGate,外层 equipNo 与 info[].sn 相同。包含两轮完全相同的操作(05:36 和 05:45),每轮依次为 cmd=0, codeList=[3] 和 cmd=2, index=[7]。日志未标明 377 的发送方。
第二轮时间线(logTime,UTC):
| 时间 | 消息 | 关键字段 |
|---|---|---|
| 05:45:25 | 377 |
cmd=0,codeList=[3],snno=6008 |
| 05:45:25 | 378 |
cmd=0,result=0 |
| 05:45:28 | 379 |
cmd=0,result="ok",hexList 中 code=3、resultOne="ok",hexData 见下 |
| 05:45:36 | 380 |
cmd=0,result=0 |
| 05:45:38 | 377 |
cmd=2,index=[7] |
| 05:45:38 | 378 |
cmd=2,result=0 |
| 05:46:21 | 379 |
cmd=2,result="ok",filename="2026-10-14_05_46_20",indexInfo 为 4/ok、5/ok |
| 05:46:21 | 607 |
faultRecordID=5226,fileName="2026-10-14_05_46_20",url="http://test.franklinwh.com/hes-upload/v1/file/upload",logTime="2026-10-14" |
| 05:46:21 | 608 |
{"result":0,"filename":"2026-10-14_05_46_20","result":5226}(result 键重复) |
| 05:46:22 | 380 |
cmd=2,result=0 |
| 05:46:33 | 609 |
result=0,fileName="2026-10-14_05_46_20.tar.bz2" |
| 05:46:33 | 610 |
result=1 |
第一轮(05:36~05:37)顺序与字段结构相同,faultRecordID=5224、filename="2026-10-14_05_37_32",607→609 约 11 秒。
观察:
607 在 379(cmd=2) 同一秒发出,早于 380,带平台召唤记录 ID,推断平台收到 379 后自动发起上传。用户确认本工具只监听这一过程(2026-10-16)。https://test.franklinwh.com/hes-upload/v1/file/download/logger/AFCI_TEST_0713/2026-10-14_05_46_20.tar.bz2,即 logger/<equipNo>/<609.fileName>;生产服替换域名。610.result=1,而 378/380 成功为 0,不同消息的成功值不一致。cmd=0 的 hexData 完全相同。code=3 目录解析(211 字节 = 1 + 15 × 14,结构与 FaultFilter 文档 5.1.1 一致):
| 序号 | 发生时间 | 参数列表版本 | 触发源 |
|---|---|---|---|
| 1 | 2024-01-01 00:00:34 | 00000001 |
0x1002 |
| 2 | 2026-07-14 02:53:35 | 00000001 |
0x1001 |
| 3 | 2026-08-12 02:03:05 | 00000001 |
0x1001 |
| 4 | 2026-08-13 21:40:40 | 00000001 |
0x1001 |
| 5 | 2026-08-14 03:24:16 | 00000001 |
0x1001 |
| 6 | 2026-08-16 03:58:05 | 00000001 |
0x1001 |
| 7 | 2026-08-18 03:03:08 | 00000001 |
0x1001 |
| 8 | 2025-11-24 01:11:46 | 00000001 |
0x1001 |
| 9 | 2025-11-26 21:44:06 | 00000001 |
0x1001 |
| 10 | 2023-05-04 22:01:03 | 00000001 |
0x1002 |
| 11 | 2023-05-04 22:02:33 | 00000001 |
0x1002 |
| 12 | 2023-05-04 22:03:40 | 00000001 |
0x1002 |
| 13 | 2023-05-04 22:04:46 | 00000001 |
0x1002 |
| 14 | 2023-05-04 22:28:14 | 00000001 |
0x1002 |
| 15 | 2026-06-29 15:07:35 | 00000001 |
0x1001 |
目录不按时间排序,像是循环覆盖存储;第 1 条时间疑似设备未校时。
来源:2026-10-14_05_46_20.tar.bz2,即上表 609.fileName 对应的文件,按 logger/<equipNo>/<fileName> 规律下载。用户确认下载不需要 token(2026-10-16)。
.tar.bz2,实际是 gzip 压缩的 tar(文件头 1f 8b),用 bzip2 解压会失败。解压时应按文件头判断格式,不能信任扩展名。目录结构与 FaultFilter 文档 5.2.1 一致,但没有 faultFilterRecode 根目录:
2026-10-14_05_46_20/AFCI_TEST_0713/index_7/failuredata 1024 字符(512 字节)
2026-10-14_05_46_20/AFCI_TEST_0713/index_7/waveformdata 98304 字符(49152 字节)
文件内容为大写十六进制 ASCII 文本,无换行,与文档一致。<sn> 为 info[].sn(本例与网关 SN 相同)。
failuredata(按 FaultFilter 5.2.2 解析)| 字段 | 值 | 说明 |
|---|---|---|
| 单一故障信息数据长度 | 0x0200 = 512 |
等于整个文件的字节数(含本字段和末尾填充),不是有效数据长度 |
| 基本信息 | CAN 协议版本 1;存储格式版本 1;参数列表版本 00000001;最大采样频率 4500;采样频率 4500;采样点总数 1536;故障前 1024;故障后 512 |
与 code=2 结构一致 |
| 位置索引 | 7 | 与请求 index=[7] 一致 |
| 故障发生时间 | 2026-08-18 03:03:08 | 与目录第 7 条一致 |
| 事件触发源 | 0x1001 并网发生状态切换故障 |
与目录一致 |
| DCDC 版本 | EMS_SL:V10R80B21D00,NUL 填充 |
aGate 中为从 DSP 版本 |
| INV/FPGA 版本 | 字节 01 02 03 … 40 |
aGate 中为填充,填充方式不限定(用户确认,2026-10-16);解析时跳过 |
| 快照通道 | 总数 6,已用 6:0x10=2049、0x11=0、0x12=0、0x13=4096、0x05=1、0x04=0 |
|
| 采样通道 | 总数 16,已用 16:0x10 0x11 0x12 0x13 0x3016 0x3017 0x3013 0x3014 0x3010 0x3011 0x3022 0x3023 0x01 0x03 0x03 0x01 |
最后 4 项与可配采样通道的类型码相同,见下 |
| 可配快照通道 | 总数 0 | |
| 可配采样通道 | 总数 4,已配 4:Uint16@0x00014990、float32@0x00001510、float32@0x00001512、Uint16@0x0001476E |
|
| 结构结束位置 | 第 308 字节 | 剩余 204 字节全部为 0xFF 填充 |
waveformdata(按 FaultFilter 5.2.3 解析)failuredata 的“采样通道总数”(16),点数 m = 基本信息的“采样点总数”(1536)。0x01/0x03),不是 F14 参数代码。0x3016/0x3017/0x3013/0x3014)是幅值约 ±2200 的正弦波,按 Uint16 解释会在过零处跳变。文档写的是 Uint16。0x10)在第 1024 点从 0x0000 变为 0x0801,正好等于故障前采样点数。快照 0x10=2049(0x801)等于故障后的值,快照 0x13=4096 等于第 3 通道故障前的值 0x1000。| 通道 | 含义代码 | 特征 |
|---|---|---|
| 0~3 | 0x10~0x13 |
状态/故障字,只有少数几个离散值 |
| 4~7 | 0x3016 0x3017 0x3013 0x3014 |
50 Hz 正弦,±2200 左右 |
| 8~11 | 0x3010 0x3011 0x3022 0x3023 |
小幅值噪声(-36~31) |
| 12 | 可配 Uint16 0x14990 |
3 个离散值(0x3020、0x3900、0x1900) |
| 13~14 | 可配 float32 0x1510/0x1512 |
-248~249 |
| 15 | 可配 Uint16 0x1476E |
4 或 5 |
各通道的物理量和换算系数需要 F14《参数代码表》,目前只能展示原始值。
cmd=2 请求 index=[9],随后上传的 indexInfo 却是索引 4、5。4(故障数据)和 5(波形数据),两者对应同一请求。cmd=0 的 hexData 代表什么。code=3 结构。code=1/2 仍无样本。cmd=2 的录波文件从设备传到服务端的通道。607~610 触发的 HTTP 上传,下载地址规律已确认。下载不需要 token,压缩包结构已确认(见 2026-10-14 录波文件解析)。仍待确认:平台对本工具直连发送的 377 是否同样自动上传。failuredata 长度字段含义;采样值有无符号;float32 可配通道如何存成 16 位。(aGate 的 INV/FPGA 版本字段已确认为填充,解析时跳过。)见 2026-10-14 录波文件解析。379 上传和 380 应答的实际 topic、应答时限、重发机制及消息关联规则。cmd=1/cmd=3 的 379 实报,以及各命令的失败报文在外层的表现。结构本身已由 FaultFilter 文档定义(setResultList/idInfo)。pe 设备的实际寻址(网关 SN 与子设备 SN 不同时的报文);批量记录序号时多组 4/5 的顺序。| 优先级 | 实测场景 | 必须保留的证据 | 要解决的问题 |
|---|---|---|---|
| 1 | pe 子设备、单个 code 的完整 cmd=0 查询 |
操作时间、网关 SN、子设备类型/SN、双向 topic、377~380 原始报文和设备界面中的对应记录 |
按 FaultFilter 文档解析 hexData 验证;网关与子设备 SN 关系 |
| 1 | 本工具直连发送 377(cmd=2),测试服和生产服各一次 |
全部双向报文(含 607~610)、topic、按规律下载的 tar.bz2 |
平台是否自动上传;s2c 能否订阅;下载认证与压缩包结构 |
| 1 | cmd=3 读取一项已知功能码(如 id=5 采样频率) |
请求/返回报文、功能码和当前值 | cmd=3 经外层转发的实际表现 |
| 2 | cmd=1 设置一项参数并用 cmd=3 复读确认 |
377~380 全链路、设置前后值、单项结果 |
378 与 379 各自的成功语义,setResultList 实际结构 |
| 2 | 设备忙、SN 不存在、参数设置失败及超时 | 完整错误报文、重发次数与间隔 | busy 等错误字符串在外层的表现、378 失败值、超时和重试规则 |
新增样本时,先保留原始报文、topic、时间和触发操作,再将“待验证”条目逐项升级为已确认事实。当前代码入口和实现边界见 implementation-status.md。