边缘侧 OTA 固件升级方案知识分享

张嘉龙 4 阅读

1. 业务背景与需求

业务场景

储能电站边缘侧,对接 BMS、PCS 等设备,云端下发固件,边缘侧完成固件下载、校验、分片下发设备、设备烧录、状态回传、失败回滚。

核心需求

  • 云端下发升级任务,边缘 Qt 网关接收 OTA 任务

  • 固件包下载:断点续传、MD5/SHA256 完整性校验

  • 多设备管理:支持批量升级、单设备升级、升级排队

  • 设备层:BMS/PCS 按通信协议(Modbus / 自定义串口协议 / CAN)分片写入固件

  • 状态机管控:空闲→下载中→待升级→升级中→成功 / 失败

  • 断电保护:升级中途断电,可恢复任务,不损坏设备固件

  • 进度实时上报云端,错误码、日志留存本地 SQLite

  • 禁止随意重启业务程序,升级失败支持设备回滚旧固件

  • 互斥保护:同一台设备同一时间只能有一个升级任务

2. 整体系统架构

角色分工

  1. 云端:管理固件库,创建升级任务,下发任务给边缘,接收边缘上报状态。

  2. Qt 边缘应用:任务代理。下载固件、校验、调度、分片转发固件给设备,中转设备状态回传给云端。不直接写设备 Flash。

  3. BMS/PCS:真正执行固件烧录、Flash 擦写、断电保护、固件回滚逻辑。

3. OTA 完整业务流程

4. 边缘侧 Qt 模块职责拆分

模块

Qt 相关类

职责

MQTT 消息交互

QMqttClient

接收云端 OTA 任务,上报进度、状态、错误码

HTTP 固件下载

QNetworkAccessManager

下载固件,断点续传,文件哈希校验

OTA 任务调度

QObject + QStateMachine

任务队列、升级状态机、任务互斥、串行 / 并行调度

持久化存储

QSqlite

保存升级任务、历史记录、升级日志,重启后恢复未完成任务

设备通信层

QSerialPort / QtCAN / ModbusQt

和 BMS、PCS 通信,下发升级指令、分片固件,读取设备状态

文件工具模块

QFile, QFileInfo

固件读写,临时文件管理,文件完整性校验

日志模块

QLoggingCategory

本地日志输出,记录升级全链路事件

5. 固件包规范设计

OTA 任务 MQTT payload 关键字段

{
  "taskId": "ota_20260819_001",
  "targetDevices": ["pcs_001", "bms_002"],
  "targetType": "PCS",
  "firmwareUrl": "http://xxx/fw/pcs_v1.2.3.bin",
  "firmwareVersion": "V1.2.3",
  "fileSize": 262144,
  "sha256": "xxxxxxxxxxxxxxxxxxxxxx",
  "timeoutSec": 600,
  "rollbackEnable": true,
  "runMode": "serial"
}

固件文件约束

  1. 原始固件:.bin,设备原生固件,边缘不解包固件,原样分片转发。

  2. 本地缓存路径:/opt/ota/cache/,按 taskId 命名固件文件。

  3. 校验算法:优先 SHA256,备选 MD5。

  4. 临时文件后缀 .tmp,下载完成校验通过才重命名为正式 bin 文件。

  5. 磁盘空间预检查:下载前判断剩余空间 > 文件大小 * 1.5,空间不足直接失败。

6. Qt 关键技术实现要点

6.1 文件下载 QNetworkAccessManager

  • 使用 QNetworkRequest,支持断点续传:设置 Range HTTP 头。

  • readyRead() 分片写入本地 tmp 文件,不要全部读进内存(固件可能几百 KB~ 数 MB)。

  • finished() 信号判断 http 返回码;下载完成后读取全部文件计算 SHA256 和云端对比。

  • 超时处理:设置请求超时;下载超时标记任务失败。

6.2 SHA256 文件哈希计算

使用 QCryptographicHash,流式读取文件,分块计算哈希,防止大文件占满内存。

6.3 SQLite 持久化任务

OTA 任务表核心字段

字段

说明

taskId

任务唯一 ID

deviceId

目标设备 ID

targetType

BMS/PCS

firmwareVersion

目标版本

localFilePath

本地固件路径

taskStatus

0 空闲,1 下载中,2 待升级,3 升级中,4 成功,5 失败

progress

0‑100 进度

errorCode

错误码

createTime / updateTime

时间戳

6.4 任务队列与互斥

  • 每个设备 ID 维护升级锁:同一设备不能同时跑两个 OTA 任务。

6.5 MQTT 上报设计

上报消息固定携带:taskId、deviceId、progress、status、errorCode、msg。

升级过程中定时上报进度,状态变更必须立即上报;防止云端状态不同步。

7. 升级状态机设计

使用 Qt QStateMachine 管理 OTA 单设备升级任务。

任意状态收到失败信号 → 进入 Failed 状态,记录错误码,上报云端,释放设备锁。

8. 可靠性与异常防护设计

  1. 磁盘保护

    • 下载前校验磁盘剩余空间;

    • 失败任务自动清理 .tmp 缓存文件;避免磁盘占满。

  2. 断电恢复

    • 全部任务状态落 SQLite;程序重启恢复未完成任务;

    • 下载中断:支持断点续传继续下载;

    • 分片传输中断:边缘重新发起进入升级模式,从分片序号继续传输。

  3. 超时防护

    • 每个阶段设置超时计时器:下载超时、设备应答超时、分片 ACK 超时、设备烧录总超时;超时直接判定任务失败。

  4. 设备 A/B 双分区依赖(硬件侧)

    Qt 边缘侧无法保证设备不死机,BMS/PCS 必须实现固件 A/B 双分区备份:

    • A 分区运行,B 分区接收新固件;校验完成再切换启动分区;

    • 新固件启动失败自动回滚到老 A 分区。

  5. 版本校验

    • 升级完成回读设备实际版本号,和目标版本对比,版本不一致判定升级失败。

  6. 总线防风暴

    CAN/Modbus 升级阶段降低总线其他业务报文频率,防止固件分片报文被业务报文挤丢。

9. BMS/PCS 设备底层交互说明

  1. 进入升级模式指令:边缘下发指令,设备停止业务逻辑,准备接收固件分片。

  2. 固件分片帧:每帧携带:分片序号、分片数据、校验和 CRC16;设备返回 ACK + 当前分片序号。

  3. 分片重传机制:边缘发送分片,如果超时没有 ACK,最多重传 N 次;重传失败直接升级失败。

  4. 全部分片下发完毕指令:通知设备:固件全部接收完成,请校验并烧录 Flash。

  5. 设备主动上报进度 或者边缘轮询寄存器获取升级进度、状态。

  6. 设备重启:设备自行重启,边缘等待设备重新上线,读取版本确认。