Skip to content

OTA 升级

一、什么是 OTA 升级

OTA 是指设备在远程状态下完成软件、固件或模块升级,不需要人工到现场刷机。

在本平台中,OTA 不只是"发一个升级指令"这么简单,而是完整覆盖以下过程:

  • 升级包管理
  • 升级任务创建
  • 设备接收升级通知
  • 设备下载和安装升级包
  • 上报升级进度和结果
  • 平台统计成功、失败、超时和回滚情况

二、推荐的 OTA 工作方式

本平台推荐的标准 OTA 模式是:

  1. 平台向设备发送升级通知
  2. 设备拿到升级包地址
  3. 设备自行下载升级包
  4. 设备校验、安装、重启
  5. 设备上报进度、结果和新版本

推荐方式

建议设备通过 HTTPHTTPS 或对象存储地址下载升级包。

也就是说,平台默认更适合做"升级控制面",而不是直接通过消息链路去传整个大文件。

这套方式适合 MQTTTCPUDP 以及其他自定义协议设备。协议不同,只会影响"指令怎么发、上报怎么解",不会改变 OTA 的核心业务逻辑。


三、平台侧与设备侧职责

平台侧负责

  • 管理升级包
  • 创建升级任务
  • 控制灰度、分批、定时和回滚策略
  • 向设备发送升级通知
  • 记录设备升级明细
  • 判断成功、失败和超时

设备侧负责

  • 接收升级通知
  • 获取并校验升级包完整性
  • 执行安装、必要时自动重启
  • 上报进度、最终结果和最新版本号

注意

如果设备本身不具备"下载、校验、安装、重启、结果上报"这些能力,平台只能创建任务和发送通知,不能替设备完成真正的升级。


四、使用前准备

开始使用 OTA 前,建议先确认:

  1. 产品和设备都已经创建完成
  2. 设备已经能正常接入平台
  3. 已经准备好升级包文件
  4. 设备端已经实现升级流程
  5. 已经明确升级失败后的恢复方案

建议优先整理好以下升级包信息:升级包名称、产品、版本号、升级类型、模块、文件大小、校验值、发布说明、标签。


五、标准 OTA 任务流程

第一步:上传升级包

在升级包管理中上传升级包,并完善版本、校验值和发布说明。

第二步:创建升级任务

创建任务时,一般需要确定:选择哪个升级包、升级哪些设备、是否立即/定时执行、是否灰度/分批推送、是否失败自动回滚、超时时间和重试次数。

第三步:平台发送升级通知

任务开始后,平台会把标准 OTA 内容下发到协议层,由协议层再转换成设备真正能识别的报文。

第四步:设备执行升级

设备收到通知后,开始下载、校验、安装和重启。

第五步:设备回传进度和结果

设备在升级过程中持续上报当前进度、当前状态、当前版本、目标版本,以及最终成功或失败结果。

第六步:平台汇总结果

在任务中心里,平台会统计总设备数、成功数、失败数、超时数、取消数和跳过数。


六、平台下发给设备的标准 OTA 内容

这部分是设备研发和协议研发最关心的内容。

平台在下发 OTA 时,会先形成一份统一的 OTA 标准内容,然后由具体协议去编码成 MQTTTCPUDP 或厂商私有报文。

下发升级通知示例

下面是协议编解码层通常能拿到的标准 OTA 内容示例:

json
{
  "messageType": "FUNCTIONS",
  "function": "otaUpgrade",
  "data": {
    "action": "start",
    "taskId": "1024",
    "taskNo": "OTA202603220001",
    "taskDeviceId": "50001",
    "packageId": "2",
    "packageName": "主程序升级包 1.0.2",
    "packageType": "FIRMWARE",
    "customType": "default",
    "module": "APPLICATION",
    "currentVersion": "1.0.1",
    "targetVersion": "1.0.2",
    "downloadUrl": "https://example.com/ota/firmware-1.0.2.bin",
    "fileName": "firmware-1.0.2.bin",
    "fileSize": 1048576,
    "checksum": "8d1c7f8ef8d6a0ce4f13f6c9c2aef001",
    "checksumAlgorithm": "MD5",
    "signatureUrl": "https://example.com/ota/firmware-1.0.2.sign",
    "forceUpgrade": false,
    "releaseNotes": "修复已知问题并优化稳定性",
    "strategy": {
      "maxRetryCount": 3,
      "timeoutSeconds": 1800,
      "batchSize": 100,
      "batchIntervalSeconds": 0,
      "requireVersionCheck": true,
      "autoDispatch": true
    }
  }
}

编解码脚本要注意

当前平台在执行 DEV_FUNCTION 编码时,传给协议层 encode() 的就是上面这段函数 JSON 本身,而不是整个 UnifiedDownlinkCommand

也就是说,你在 magic/js/java/spring 编码器里通常直接处理的是 messageTypefunctiondata,而不是再去取一层 function.data

设备建议识别哪些字段

平台下发的 OTA 内容会尽量完整,但并不是要求所有设备一次性把所有字段都"硬编码支持"。更合理的做法是按设备能力分层实现:

分类字段说明
必需字段actiontargetVersiondownloadUrl设备启动升级流程的最核心内容,建议所有 OTA 设备都支持
条件必需modulepackageTypefileSizechecksumchecksumAlgorithm存在多模块升级、多包类型或需要自行做完整性校验时必须支持;如固件包自带签名/厂商校验流程,可作为辅助信息而非强制依赖
推荐字段taskIdtaskDeviceIdstrategy.maxRetryCountstrategy.timeoutSeconds不是"能不能升级"的前提,但会明显提升任务追踪、超时判定和问题排查能力

推荐做法

设备尽量回传 taskDeviceId。如果实在不能回,也建议回 taskId。如果这两个都没有,平台只能根据设备、模块、目标版本等信息做兜底匹配,准确性会下降。

平台推荐"字段尽量完整",但真正的最低要求仍然是:设备能拿到升级地址,完成下载、校验、安装,并且能把进度和结果回传上来。


七、设备上报给平台的标准 OTA 消息

设备上报时,推荐统一成三类消息:

  • 版本确认使用 messageType = PROPERTIES
  • 升级进度使用 messageType = EVENT, event = otaProgress
  • 升级结果使用 messageType = EVENT, event = otaResult
  • OTA 扩展字段直接放在 data 节点中,不再额外包一层 ota

1. 设备上报当前版本

适合设备日常上报版本信息,或者升级完成重启后再次确认版本。

json
{
  "messageType": "PROPERTIES",
  "data": {
    "reportType": "FIRMWARE_INFO",
    "taskId": "1024",
    "taskDeviceId": "50001",
    "packageType": "FIRMWARE",
    "module": "APPLICATION",
    "currentVersion": "1.0.2",
    "targetVersion": "1.0.2"
  },
  "properties": {
    "firmwareVersion": "1.0.2"
  }
}

2. 设备上报升级进度

升级中建议定期上报进度,例如 10%30%60%90%

json
{
  "messageType": "EVENT",
  "event": "otaProgress",
  "data": {
    "reportType": "UPGRADE_PROGRESS",
    "taskId": "1024",
    "taskDeviceId": "50001",
    "packageType": "FIRMWARE",
    "module": "APPLICATION",
    "currentVersion": "1.0.1",
    "targetVersion": "1.0.2",
    "upgradeStatus": "DOWNLOADING",
    "progress": 45,
    "statusDetail": "已下载 45%"
  }
}

3. 设备上报升级成功

升级完成后,建议显式上报成功结果。

json
{
  "messageType": "EVENT",
  "event": "otaResult",
  "data": {
    "reportType": "UPGRADE_RESULT",
    "taskId": "1024",
    "taskDeviceId": "50001",
    "packageType": "FIRMWARE",
    "module": "APPLICATION",
    "currentVersion": "1.0.2",
    "targetVersion": "1.0.2",
    "upgradeStatus": "SUCCESS",
    "progress": 100,
    "statusDetail": "升级完成并重启成功"
  }
}

4. 设备上报升级失败

失败时建议把失败原因一起带回来。

json
{
  "messageType": "EVENT",
  "event": "otaResult",
  "data": {
    "reportType": "UPGRADE_RESULT",
    "taskId": "1024",
    "taskDeviceId": "50001",
    "packageType": "FIRMWARE",
    "module": "APPLICATION",
    "currentVersion": "1.0.1",
    "targetVersion": "1.0.2",
    "upgradeStatus": "FAILED",
    "progress": 65,
    "errorCode": "VERIFY_FAILED",
    "errorMessage": "校验失败"
  }
}

八、TCP 私有报文怎么做 OTA

如果设备不是直接收发 JSON,也完全可以做 OTA。思路很简单:

  1. 平台先生成上面的标准 OTA 内容
  2. 你的 encode 把标准内容翻译成设备私有帧
  3. 设备上报时,你的 decode 再把私有帧翻译回标准 OTA 消息

下行可以是 HEX,上行也可以是 HEX,但进入平台统一处理前,最好被转换成标准 OTA 语义。

例如,设备上报的原始 TCP 帧里即使只有状态码、进度、版本号、错误码,只要在协议脚本里把它们映射成 reportTypeupgradeStatusprogresscurrentVersiontargetVersionerrorCodeerrorMessage,平台就能继续识别。


九、平台如何判断升级成功、失败和超时

判断升级成功

平台一般通过以下方式判断升级成功:

  • 设备明确上报 SUCCESS
  • 设备进度达到 100
  • 设备升级后再次上报的新版本已经等于目标版本

最稳妥的方式是同时满足两件事:设备上报升级结果为成功,且设备重启后再次上报当前版本号。

判定失败的常见场景

  • 下载失败、校验失败、存储空间不足
  • 安装失败、重启失败
  • 设备主动返回失败状态

判定超时的常见场景

平台下发升级任务后,如果设备长时间没有继续反馈,平台应判定为超时。例如:下发后一直没有任何回应、上报到 30% 后长时间不再更新、下载中断后一直没有后续状态。

建议

超时时间建议按设备能力和文件大小设置,一般可以从 30 分钟 起步。


十、灰度、分批、定时、回滚

灰度发布

建议先选择少量代表性设备试升级,例如不同地区、不同网络环境、不同硬件批次。

分批发布

不建议第一次就全量升级,推荐先发 5%~10% 观察结果,再逐步扩大范围,最后再全量发布。

定时发布

适合夜间、低峰期或指定运维窗口执行升级,减少业务影响。

失败回滚

建议提前准备稳定版本作为回滚包。当失败率达到阈值后,可以停止继续放量,并对已经升级成功但需要回退的设备执行回滚。


十一、为什么推荐 URL 下载而不是消息分片传包

原因主要有这些:

  • 升级包通常比较大
  • 消息链路更适合控制指令
  • 分片传输要处理丢包、重传、排序、续传和整包校验
  • 大规模同时升级时,对 Broker 和设备压力都更大

所以本平台默认推荐消息下发升级通知,设备通过 URL 拉取升级包。如果设备无法访问 URL,再考虑私有分片传包方案。


十二、日常使用建议

  • 升级包命名尽量规范,发布说明写清楚变更内容
  • 先灰度,再逐步放量
  • 对核心设备启用回滚策略
  • 尽量让设备回传 taskDeviceId
  • 升级完成后再上报一次版本信息
  • 对失败和超时设备保留人工复核和重试空间

十三、常见问题

设备只上报进度,不上报结果,可以吗?

可以作为过程信息,但不建议长期只报进度。最好补充最终结果和最终版本。

设备不回 taskDeviceId 可以吗?

可以,但不推荐。最好至少回 taskId。如果两个都不回,平台只能根据设备、模块、目标版本等信息做关联。

平台下发成功了,为什么不代表升级成功?

因为"下发成功"只代表设备收到了升级通知,不代表设备已经下载、校验、安装并重启成功。

升级结果上报成功后,还要不要再报版本?

建议报。结果上报是"过程结束",版本上报是"最终状态确认",两者一起会更稳。


总结

如果你要把 OTA 做得稳定可用,建议记住这三点:

  1. 平台负责任务和流程控制
  2. 设备负责真正的升级执行
  3. 协议层负责把私有报文转换成统一 OTA 语义

只要把"下发通知、进度上报、结果上报、版本确认"这四个环节打通,OTA 就可以真正落地,而不是停留在"只能发指令"的阶段。