Skip to content

固件与 OTA 服务

固件管理、存储代理和 OTA 升级任务调度的后端模块设计。整体架构见 11.OTA升级架构,MQTT Topic 见 06.MQTT通信协议 3.3 节。


1. 模块定位

两个子模块,归属于 NestJS 后端:

模块职责对应数据库表
FirmwareModule固件上传、版本管理、OSS 存储代理firmwares
OtaModule升级任务创建、调度、进度追踪、结果记录ota_tasks

2. FirmwareModule:固件管理

2.1 固件上传流程

FirmwareService.upload(file, productId, version, changelog) 流程:

  1. Web 后台通过 POST /api/v1/firmware/upload 提交 .bin 文件
  2. 校验文件格式(见 2.2 节)
  3. 计算文件 MD5 和大小
  4. 通过 StorageService 上传到阿里云 OSS,存储路径 firmware/{productKey}/{version}/{filename}.bin
  5. 写入 firmwares 表(productId、version、url、size、md5、changelog)
  6. 返回固件版本信息给前端

2.2 文件校验规则

校验项规则错误码
扩展名必须是 .binA0301
魔数文件头第一个字节为 0xE9(ESP32 固件标识)A0301
版本号同产品下 version 唯一,重复拒绝A0302
文件大小最大 4MB(ESP32 典型 OTA 分区大小)A0001

2.3 StorageService 抽象

定义统一的文件存储接口,适配 OSS 和 MinIO:

方法说明
upload(file, path)上传文件,返回文件 URL
getSignedUrl(path, ttl)生成预签名下载链接(设备端用,默认 24h TTL)
delete(path)删除固件文件

使用 ali-oss SDK,Bucket 名称和 AccessKey 通过环境变量注入。

2.4 目录结构

src/modules/firmware/
├── firmware.module.ts
├── firmware.service.ts      # 上传、校验、版本查询
├── firmware.controller.ts   # REST API
└── storage/                 # 存储抽象层
    ├── storage.interface.ts
    └── oss.storage.ts

3. OtaModule:升级任务

3.1 任务创建与下发

OtaService.createTask(firmwareId, deviceIds) 流程:

  1. 查询 Firmware 记录,确认固件存在且 URL 有效
  2. 查询目标设备列表,过滤离线设备(标记为 pending,待上线后补发)
  3. 为每台设备创建 OtaTask 记录(status=pending
  4. 通过 MqttService.publish() 逐批下发通知,每批 100 台,间隔 30 秒
  5. 下发后将任务状态更新为 notified
  6. 返回任务 ID 和总设备数给 Web 后台

3.2 进度追踪

OtaService.updateProgress(deviceId, progress, desc) 流程:

  1. 查找该设备当前进行中的 OtaTask(status=notifieddownloading
  2. 更新 progress 字段
  3. 根据 desc 转换状态:
desc 值status 变更说明
downloading保持为 downloading更新进度百分比
flashinginstalling下载完成,正在写入分区
donesuccess写入完成,记录 completedAt
verify_failedfailed(或自动重试)校验失败,检查重试次数
  1. 通过 WebSocket 推送最新进度到 Web 后台(见 10.WebSocket实时通信

3.3 离线设备补发机制

设备首次属性上报时检查 pending OTA 任务:

  1. OtaService 查询该设备是否有 pendingnotified 状态的 OtaTask
  2. 有则通过 MQTT 立即补发升级通知
  3. 补发前重新生成预签名 URL(确保下载链接未过期)

3.4 重试策略

场景策略
MD5 校验失败自动重新创建任务,最多重试 2 次
每次重试重新生成预签名 URL(旧 URL 可能已过期)
2 次重试仍失败标记 failed,WebSocket 通知运维

3.5 批量升级并发控制

参数说明
单次任务最大设备数500 台防止 MQTT 消息风暴
分批间隔30 秒逐批下发,给 OSS 带宽缓冲
预签名 URL TTL24 小时确保离线设备上线后能下载

3.6 目录结构

src/modules/ota/
├── ota.module.ts
├── ota.service.ts           # 任务创建、调度、进度追踪
├── ota.controller.ts        # REST API
└── ota.gateway.ts           # WebSocket 进度推送

4. 与 MQTT 路由的集成

OtaModule 注册到 MQTT 路由系统(04.MQTT服务设计 第 2.3 节),通过 ota.handler.ts 处理 OTA 相关 Topic:

MQTT TopicHandler调用
sys/+/+/thing/ota/progressota.handler.tsOtaService.updateProgress()

FirmwareModule 不直接参与 MQTT 通信,仅通过 REST API 供 Web 后台调用。OTA 通知下发通过 MqttService.publish() 完成。


5. 预签名 URL 生成

设备通过预签名 URL 下载固件,避免直接暴露 OSS Bucket:

机制说明
下载 URL 有效期24 小时,超时后 OSS 拒绝访问
离线设备补发上线时检测到未完成的 OtaTask,重新生成 URL 后补发
API 封装使用 ali-oss SDK 的 signatureUrl() 方法生成预签名 URL

设备端只需发送 HTTP GET 请求到预签名 URL 即可下载,无需携带额外认证信息。