2025-12-01 22:26:31 +08:00
|
|
|
|
# 区域主控 MicroPython OTA 升级方案
|
|
|
|
|
|
|
|
|
|
|
|
## 1. 概述
|
|
|
|
|
|
|
|
|
|
|
|
### 1.1. 目标
|
|
|
|
|
|
|
|
|
|
|
|
实现区域主控 (ESP32-S3-N16R8, MicroPython 固件) 的安全、可靠的远程固件升级 (OTA)。
|
|
|
|
|
|
|
|
|
|
|
|
### 1.2. 核心思想
|
|
|
|
|
|
|
2025-12-02 13:27:20 +08:00
|
|
|
|
* **AB 分区模式**: 区域主控采用 AB 分区模式,允许在设备运行时更新非活动分区,升级失败时可回滚到上一个已知的工作版本。
|
|
|
|
|
|
* **平台主导**: 升级过程由平台完全控制,包括固件准备、文件分发和升级指令下发。
|
|
|
|
|
|
* **LoRa 传输层自动分片**: 充分利用 LoRa 传输层自动分片和重组的能力,简化应用层协议设计。
|
|
|
|
|
|
* **逐文件校验**: 设备在接收每个文件后立即进行 MD5 校验,确保文件完整性,并处理重试。
|
|
|
|
|
|
* **清单文件**: 使用清单文件管理所有待更新文件的元数据和校验信息。
|
|
|
|
|
|
* **设备自驱动**: 设备主动请求清单文件和固件文件,并在所有文件校验成功后自行激活新固件并重启。
|
|
|
|
|
|
* **平台记录升级任务**: 平台将记录 OTA 升级任务的创建、进度和最终状态。
|
|
|
|
|
|
* **配置文件独立管理**: OTA 升级过程将不涉及配置文件的更新,配置文件由平台提供独立的远程修改功能。
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
|
|
|
|
|
### 1.3. 涉及组件
|
|
|
|
|
|
|
2025-12-02 13:27:20 +08:00
|
|
|
|
* **平台**: 负责固件包管理、清单文件生成、数字签名(未来)、文件分发、指令下发、状态接收和**升级任务记录**。
|
|
|
|
|
|
* **LoRa 传输层**: 负责应用层数据的分片、传输和重组。
|
|
|
|
|
|
* **区域主控 (ESP32-S3-N16R8)**: 负责接收文件、存储到非活动分区、文件校验、分区切换、新固件启动验证和状态上报。
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
|
|
|
|
|
## 2. 固件包结构与准备
|
|
|
|
|
|
|
|
|
|
|
|
### 2.1. 原始固件包 (由开发者提供给平台)
|
|
|
|
|
|
|
2025-12-02 13:27:20 +08:00
|
|
|
|
* 一个标准的压缩包(例如 `.zip`),其中包含所有 MicroPython `.py` 文件、资源文件等。
|
|
|
|
|
|
* 压缩包内的文件结构应与期望在设备上部署的路径结构一致。
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
|
|
|
|
|
### 2.2. 平台处理流程
|
|
|
|
|
|
|
2025-12-02 13:27:20 +08:00
|
|
|
|
1. **接收**: 平台接收开发者上传的 MicroPython 项目压缩包。
|
|
|
|
|
|
2. **解压**: 平台将该压缩包解压到内部的一个临时目录。
|
|
|
|
|
|
3. **分析与生成清单**: 平台遍历解压后的所有文件,为每个文件计算:
|
|
|
|
|
|
* 在设备上的目标路径 (`path`)
|
|
|
|
|
|
* MD5 校验和 (`md5`)
|
|
|
|
|
|
* 文件大小 (`size`)
|
|
|
|
|
|
* **排除配置文件**: 平台会识别配置文件(例如通过文件名约定,如 `/config/` 目录下的所有文件),并**排除**
|
|
|
|
|
|
这些文件,不将其包含在清单文件中,也不通过 OTA 传输。
|
|
|
|
|
|
4. **生成清单文件**: 平台根据上述信息,生成一个 JSON 格式的清单文件。
|
2025-12-02 17:16:48 +08:00
|
|
|
|
5. **数字签名 (未来扩展)**: 平台使用其私钥对**清单文件**的内容进行数字签名,并将签名添加到清单文件中。
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
|
|
|
|
|
### 2.3. 清单文件 (Manifest File) 结构
|
|
|
|
|
|
|
|
|
|
|
|
清单文件是一个 JSON 对象,包含新固件的元数据和所有文件的详细信息。
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
2025-12-02 13:27:20 +08:00
|
|
|
|
"version": "1.0.1",
|
|
|
|
|
|
// 新固件版本号
|
|
|
|
|
|
"signature": "...",
|
|
|
|
|
|
// 清单文件内容的数字签名 (未来扩展)
|
|
|
|
|
|
"files": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"path": "/manifest.json",
|
2025-12-02 17:16:48 +08:00
|
|
|
|
// 清单文件本身也作为文件列表的一部分
|
2025-12-02 13:27:20 +08:00
|
|
|
|
"md5": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6",
|
|
|
|
|
|
"size": 1024
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"path": "/main.py",
|
|
|
|
|
|
"md5": "b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6a1",
|
|
|
|
|
|
"size": 10240
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"path": "/lib/sensor.py",
|
|
|
|
|
|
"md5": "c3d4e5f6a7b8c9d0e1f2a3b4c5d6a1b2",
|
|
|
|
|
|
"size": 5120
|
|
|
|
|
|
}
|
|
|
|
|
|
// ... 更多文件 (不包含配置文件)
|
|
|
|
|
|
]
|
2025-12-01 22:26:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 3. 通信协议定义 (Protobuf Messages)
|
|
|
|
|
|
|
|
|
|
|
|
以下是 OTA 过程中平台与区域主控之间通信所需的 Protobuf 消息定义。
|
|
|
|
|
|
|
|
|
|
|
|
```protobuf
|
|
|
|
|
|
// OTA 升级指令和状态消息
|
|
|
|
|
|
|
|
|
|
|
|
// PrepareUpdateReq: 平台发送给设备,通知设备准备开始 OTA 升级
|
|
|
|
|
|
message PrepareUpdateReq {
|
2025-12-02 13:27:20 +08:00
|
|
|
|
string version = 1; // 新固件版本号
|
2025-12-03 16:23:33 +08:00
|
|
|
|
uint32 task_id = 2; // 升级任务唯一ID
|
2025-12-02 13:27:20 +08:00
|
|
|
|
string manifest_md5 = 3; // 清单文件的 MD5 校验和,用于设备初步校验清单文件完整性
|
2025-12-01 22:26:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// RequestFile: 设备向平台请求特定文件 (包括清单文件和固件文件)
|
|
|
|
|
|
message RequestFile {
|
2025-12-03 16:23:33 +08:00
|
|
|
|
uint32 task_id = 1; // 升级任务ID
|
2025-12-02 17:16:48 +08:00
|
|
|
|
string filepath = 2; // 请求的文件路径 (例如 "/manifest.json" 或 "/main.py")
|
2025-12-01 22:26:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// FileResponse: 平台响应设备请求,发送单个文件的完整内容
|
|
|
|
|
|
// LoRa 传输层会自动处理分片和重组,因此应用层可以直接发送完整的单个文件内容
|
|
|
|
|
|
message FileResponse {
|
2025-12-03 16:23:33 +08:00
|
|
|
|
uint32 task_id = 1; // 升级任务ID
|
2025-12-02 17:16:48 +08:00
|
|
|
|
string filepath = 2; // 设备上的目标路径 (例如 "/manifest.json" 或 "/main.py")
|
|
|
|
|
|
bytes content = 3; // 文件的完整内容
|
2025-12-01 22:26:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// UpdateStatusReport: 设备向平台报告升级状态
|
|
|
|
|
|
message UpdateStatusReport {
|
2025-12-03 16:23:33 +08:00
|
|
|
|
uint32 task_id = 1; // 升级任务ID
|
2025-12-03 14:06:56 +08:00
|
|
|
|
string current_version = 2; // 操作完成后的当前版本
|
2025-12-02 13:27:20 +08:00
|
|
|
|
enum Status {
|
2025-12-02 17:16:48 +08:00
|
|
|
|
STATUS_UNKNOWN = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// --- 设备主动上报的状态 ---
|
|
|
|
|
|
SUCCESS = 1; // 升级成功,新固件已运行 (由设备在自检成功后主动上报)
|
|
|
|
|
|
SUCCESS_ALREADY_UP_TO_DATE = 2; // 版本已是最新,未执行升级 (由设备在版本检查后主动上报)
|
|
|
|
|
|
FAILED_PRE_CHECK = 3; // 升级前检查失败 (例如拒绝降级、准备分区失败等,由设备主动上报)
|
|
|
|
|
|
FAILED_DOWNLOAD = 4; // 文件下载或校验失败 (由设备在下载过程中主动上报)
|
|
|
|
|
|
|
|
|
|
|
|
// --- 平台推断的状态 (数据库记录用) ---
|
|
|
|
|
|
FAILED_TIMEOUT = 5; // 平台在超时后仍未收到SUCCESS报告,将任务标记为此状态
|
2025-12-02 13:27:20 +08:00
|
|
|
|
}
|
2025-12-03 14:06:56 +08:00
|
|
|
|
Status status = 3; // 升级的最终状态
|
|
|
|
|
|
string error_message = 4; // 人类可读的详细错误信息
|
|
|
|
|
|
string failed_file = 5; // 失败时关联的文件路径 (可选)
|
2025-12-01 22:26:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 4. 平台侧操作流程
|
|
|
|
|
|
|
|
|
|
|
|
### 4.1. 准备升级任务
|
|
|
|
|
|
|
2025-12-02 13:27:20 +08:00
|
|
|
|
1. 接收开发者提供的 MicroPython 项目压缩包。
|
|
|
|
|
|
2. 解压压缩包。
|
|
|
|
|
|
3. 遍历解压后的文件,计算每个文件的 MD5、大小,并确定目标路径。
|
2025-12-02 17:16:48 +08:00
|
|
|
|
4. **排除配置文件**: 平台会识别配置文件(例如通过文件名约定,如 `/config/` 目录下的所有文件),并**排除**这些文件。
|
|
|
|
|
|
5. 生成清单文件 (Manifest File)。**注意:清单文件本身也应作为 OTA 的一部分,其元数据应包含在清单文件自身的 `files`
|
|
|
|
|
|
列表中。Manifest文件生成后将被放在解压后的文件夹的根目录下, 方便后续主控设备获取**
|
2025-12-02 13:27:20 +08:00
|
|
|
|
6. (未来扩展)对清单文件进行数字签名。
|
|
|
|
|
|
7. 将清单文件和所有固件文件存储在平台内部,等待分发。
|
|
|
|
|
|
8. **记录 OTA 升级任务**: 在数据库中创建一条新的 OTA 升级任务记录(模型名为 `OTATask`,位于 `internal/infra/models/ota.go`
|
|
|
|
|
|
),包含任务 ID、目标设备、新固件版本、状态(例如“待开始”)。
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
|
|
|
|
|
### 4.2. 发送“准备更新”指令
|
|
|
|
|
|
|
2025-12-02 17:16:48 +08:00
|
|
|
|
1. 平台向目标区域主控发送 `PrepareUpdateReq` 消息。
|
|
|
|
|
|
2. **更新任务记录**: 平台发送指令后,更新 OTA 任务记录的状态为“进行中”。
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
2025-12-02 17:16:48 +08:00
|
|
|
|
### 4.3. 响应设备文件请求
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
2025-12-02 13:27:20 +08:00
|
|
|
|
1. 平台接收区域主控发送的 `RequestFile` 消息。
|
2025-12-02 17:16:48 +08:00
|
|
|
|
2. 平台根据 `task_id` 和 `filepath` 在内部存储中找到对应的文件内容。
|
|
|
|
|
|
3. 平台构建 `FileResponse` 消息,将文件的完整内容和路径放入其中。
|
|
|
|
|
|
4. 平台通过 LoRa 传输层发送 `FileResponse` 消息。
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
|
|
|
|
|
### 4.4. 处理设备状态上报
|
|
|
|
|
|
|
2025-12-02 13:27:20 +08:00
|
|
|
|
1. 平台接收区域主控发送的 `UpdateStatusReport` 消息。
|
2025-12-02 17:16:48 +08:00
|
|
|
|
2. 根据报告的 `status` (`SUCCESS` 或 `FAILED`),更新 OTA 任务记录的最终状态,并记录 `error_code` 和 `error_message`。
|
|
|
|
|
|
3. 如果状态为 `SUCCESS`,平台应更新该设备在系统中的固件版本记录。
|
|
|
|
|
|
4. **总超时管理**: 平台为每个 OTA 任务设置一个总的超时时间(例如 2 小时)。如果在总超时时间内未能收到设备的最终状态报告,平台应自动将该任务标记为
|
|
|
|
|
|
`FAILED`,`error_code` 设为 `ERR_TIMEOUT`。
|
|
|
|
|
|
5. **处理重复报告**: 平台在收到最终状态报告后,即使后续再次收到相同的报告,也只需更新一次任务记录,无需重复处理。
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
|
|
|
|
|
## 5. 区域主控侧操作流程 (MicroPython)
|
|
|
|
|
|
|
2025-12-02 17:16:48 +08:00
|
|
|
|
### 5.1. 接收“准备更新”指令与版本检查
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
2025-12-02 13:27:20 +08:00
|
|
|
|
1. 区域主控接收 `PrepareUpdateReq` 消息。
|
2025-12-02 17:16:48 +08:00
|
|
|
|
2. **版本检查**: 设备将 `PrepareUpdateReq` 中的 `version` 与自身当前运行的固件版本进行比较。
|
|
|
|
|
|
* **降级场景**: 如果 `新版本 < 当前版本`,设备立即中止升级,并向平台发送 `UpdateStatusReport` (status: `FAILED`,
|
|
|
|
|
|
error_code: `ERR_VERSION_ROLLBACK`, error_message: "拒绝版本回滚,目标版本低于当前版本")。
|
|
|
|
|
|
* **同版本场景**: 如果 `新版本 == 当前版本`,设备立即中止升级,并向平台发送 `UpdateStatusReport` (status: `SUCCESS`,
|
|
|
|
|
|
error_code: `SUCCESS_ALREADY_UP_TO_DATE`, error_message: "版本已是最新,无需升级")。
|
|
|
|
|
|
* **正常升级场景**: 如果 `新版本 > 当前版本`,继续执行下一步。
|
|
|
|
|
|
3. **清空非活动分区**: 使用 MicroPython 的文件系统操作(例如 `os.remove()` 和 `os.rmdir()`),递归删除非活动 OTA 分区(例如
|
|
|
|
|
|
`/ota_b`)下的所有文件和目录。
|
|
|
|
|
|
* **错误处理**: 如果清空分区失败,设备应立即中止,并向平台发送 `UpdateStatusReport` (status: `FAILED`, error_code:
|
|
|
|
|
|
`ERR_PREPARE`, error_message: "清空非活动分区失败: [具体错误]").
|
|
|
|
|
|
4. 设备准备就绪后,将直接开始请求清单文件。
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
|
|
|
|
|
### 5.2. 请求并验证清单文件
|
|
|
|
|
|
|
2025-12-02 17:16:48 +08:00
|
|
|
|
1. 设备完成准备后,向平台发送 `RequestFile` 消息,请求清单文件 (`filepath: "/manifest.json"`)。
|
|
|
|
|
|
2. 设备接收平台响应的 `FileResponse` 消息,并将其写入非活动分区(例如 `/ota_b/manifest.json`)。
|
|
|
|
|
|
3. **MD5 校验**: 计算写入的清单文件的 MD5,并与 `PrepareUpdateReq` 消息中提供的 `manifest_md5` 进行比对。
|
|
|
|
|
|
4. **解析 JSON**: 解析清单文件内容。
|
|
|
|
|
|
5. **数字签名验证 (未来扩展)**: 使用预置的平台公钥,验证清单文件的数字签名。
|
|
|
|
|
|
6. 如果上述任何步骤失败,设备应向平台发送 `UpdateStatusReport` (status: `FAILED`, error_code: `ERR_MANIFEST_VERIFY`,
|
|
|
|
|
|
error_message: "[具体失败原因]"), 然后中止升级。
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
|
|
|
|
|
### 5.3. 请求与存储固件文件 (逐文件校验)
|
|
|
|
|
|
|
2025-12-02 13:27:20 +08:00
|
|
|
|
1. 设备成功接收并验证清单文件后,根据清单文件中的文件列表,**逐个文件**地向平台发送 `RequestFile` 消息。
|
|
|
|
|
|
2. 对于每个请求的文件:
|
2025-12-02 17:16:48 +08:00
|
|
|
|
* **请求、接收与写入**: 设备请求文件,接收响应,并根据 `filepath` 将内容写入到非活动 OTA 分区。需要确保目标目录存在,如果不存在则创建。
|
|
|
|
|
|
* **MD5 校验**: 在文件写入完成后,计算该文件的 MD5 校验和,并与清单文件中记录的 MD5 进行比对。
|
|
|
|
|
|
* **错误处理与重试**:
|
|
|
|
|
|
* 如果文件下载超时、写入失败或 MD5 校验失败,设备将进行重试(例如最多 3 次)。
|
|
|
|
|
|
* 如果达到最大重试次数仍失败,设备应立即中止整个 OTA 任务,并向平台发送 `UpdateStatusReport` (status: `FAILED`,
|
|
|
|
|
|
error_code: `ERR_DOWNLOAD` 或 `ERR_VERIFY`, error_message: "[具体失败原因]", failed_file: "[失败的文件路径]")。
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
|
|
|
|
|
### 5.4. 自激活与重启
|
|
|
|
|
|
|
2025-12-02 13:27:20 +08:00
|
|
|
|
1. **所有文件接收并校验成功后**,设备将自行执行以下操作:
|
2025-12-02 17:16:48 +08:00
|
|
|
|
* **配置 OTA 分区**: 使用 MicroPython 提供的 ESP-IDF OTA API,设置下一个启动分区为刚刚写入新固件的非活动分区。
|
2025-12-02 13:27:20 +08:00
|
|
|
|
* **自触发重启**: 在成功配置 OTA 分区后,区域主控自行触发重启。
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
|
|
|
|
|
### 5.5. 新版本启动与验证
|
|
|
|
|
|
|
2025-12-02 13:27:20 +08:00
|
|
|
|
1. 设备重启后,启动加载器会从新的 OTA 分区加载 MicroPython 固件。
|
2025-12-02 17:16:48 +08:00
|
|
|
|
2. **自检**: 新固件启动后,应执行必要的自检(如 LoRa 初始化、网络连接等)。
|
|
|
|
|
|
3. **标记有效**: 只有当所有自检项都成功通过后,新固件才必须调用相应的 API(例如 `esp.ota_mark_app_valid_cancel_rollback()`
|
|
|
|
|
|
)来标记自身为有效。
|
|
|
|
|
|
4. **看门狗与回滚**:
|
|
|
|
|
|
* 如果新固件在一定次数的尝试后仍未标记自身为有效,启动加载器会自动回滚到上一个有效固件。
|
|
|
|
|
|
* 在 MicroPython 应用层,如果自检失败,**绝不能**标记自身为有效,并应等待底层机制自动触发回滚。
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
|
|
|
|
|
### 5.6. 报告最终状态
|
|
|
|
|
|
|
2025-12-02 17:16:48 +08:00
|
|
|
|
1. **成功场景**: 新固件自检成功并标记有效后,向平台发送 `UpdateStatusReport` (status: `SUCCESS`, current_version:
|
|
|
|
|
|
新版本号)。
|
|
|
|
|
|
2. **回滚场景**: 设备回滚到旧版本后,向平台发送 `UpdateStatusReport` (status: `FAILED`, error_code: `ERR_ROLLED_BACK`,
|
|
|
|
|
|
error_message: "新固件启动失败,已自动回滚", current_version: 旧版本号)。
|
|
|
|
|
|
3. **重复发送**: 为了提高在单向 LoRa 通信中的可靠性,设备在发送最终状态报告时,应在短时间内重复发送多次(例如 3-5 次)。
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
|
|
|
|
|
## 6. 关键技术点与注意事项
|
|
|
|
|
|
|
|
|
|
|
|
### 6.1. LoRa 传输层
|
|
|
|
|
|
|
2025-12-02 17:16:48 +08:00
|
|
|
|
* 确保 `internal/infra/transport/lora/lora_mesh_uart_passthrough_transport.go` 能稳定处理大尺寸 Protobuf 消息的分片和重组。
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
2025-12-02 13:02:27 +08:00
|
|
|
|
### 6.2. 平台侧的请求处理
|
|
|
|
|
|
|
2025-12-02 17:16:48 +08:00
|
|
|
|
* `internal/app/listener/lora_listener.go` 在接收 `RequestFile` 消息时,需要高效处理,避免阻塞监听器。
|
2025-12-02 13:02:27 +08:00
|
|
|
|
|
|
|
|
|
|
### 6.3. 文件系统操作 (MicroPython)
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
2025-12-02 17:16:48 +08:00
|
|
|
|
* 确保文件系统操作(创建目录、写入文件、删除文件)的正确性和鲁棒性,并对错误进行捕获和报告。
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
2025-12-02 13:02:27 +08:00
|
|
|
|
### 6.4. MD5 校验 (MicroPython)
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
2025-12-02 17:16:48 +08:00
|
|
|
|
* MicroPython 的 `hashlib` 模块提供 MD5 算法。确保计算的效率和准确性。
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
2025-12-02 13:02:27 +08:00
|
|
|
|
### 6.5. OTA 分区管理 (MicroPython)
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
2025-12-02 17:16:48 +08:00
|
|
|
|
* 熟悉 ESP-IDF 的 OTA 机制在 MicroPython 中的绑定和使用方法。正确调用 API 来设置启动分区和标记应用有效。
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
2025-12-02 13:02:27 +08:00
|
|
|
|
### 6.6. 回滚机制
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
2025-12-02 17:16:48 +08:00
|
|
|
|
* 完全依赖 ESP-IDF 提供的 OTA 回滚机制。新固件必须在启动后标记自身为有效,否则会自动回滚。
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
2025-12-02 13:02:27 +08:00
|
|
|
|
### 6.7. 错误处理与重试
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
2025-12-02 17:16:48 +08:00
|
|
|
|
* **设备侧**: 实现文件级别的下载和校验重试。对于无法恢复的错误,立即上报 `FAILED` 状态并中止任务。
|
|
|
|
|
|
* **平台侧**: 实现任务级别的总超时管理。这是处理设备意外断电、失联等情况的关键机制。设备重启后无需保留升级状态,简化了设备端逻辑。
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
2025-12-02 17:16:48 +08:00
|
|
|
|
### 6.8. 安全性
|
2025-12-01 22:26:31 +08:00
|
|
|
|
|
2025-12-02 17:16:48 +08:00
|
|
|
|
* **数字签名**: 强烈建议尽快实现清单文件的数字签名。**没有数字签名,OTA 过程将面临严重的安全风险(如中间人攻击)**
|
|
|
|
|
|
,攻击者可能下发恶意固件。平台的公钥需要被硬编码到设备固件中,作为信任的根基。
|
2025-12-02 13:27:20 +08:00
|
|
|
|
* **LoRaWAN 安全**: 确保 LoRaWAN 的网络层和应用层密钥管理得当, 防止未经授权的设备加入网络或窃听数据。
|
2025-12-02 13:02:27 +08:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-02 13:27:20 +08:00
|
|
|
|
## 7. 固件 OTA 升级流程描述
|
|
|
|
|
|
|
2025-12-02 17:16:48 +08:00
|
|
|
|
### 阶段一:任务准备与下发
|
2025-12-02 13:27:20 +08:00
|
|
|
|
|
2025-12-02 17:16:48 +08:00
|
|
|
|
1. **上传与准备 (Developer -> Platform)**: 开发者上传固件包,平台解压、计算MD5、生成清单文件、创建升级任务。
|
|
|
|
|
|
2. **下发更新通知 (Platform -> Device)**: 平台向设备发送 `PrepareUpdateReq`。
|
2025-12-02 13:27:20 +08:00
|
|
|
|
|
2025-12-02 17:16:48 +08:00
|
|
|
|
### 阶段二:设备版本检查与准备
|
2025-12-02 13:27:20 +08:00
|
|
|
|
|
2025-12-02 17:16:48 +08:00
|
|
|
|
1. **版本检查 (Device)**:
|
|
|
|
|
|
* **失败分支 (降级/同版本)**: 设备拒绝升级,上报 `FAILED` (ERR_VERSION_ROLLBACK) 或 `SUCCESS` (
|
|
|
|
|
|
SUCCESS_ALREADY_UP_TO_DATE),流程结束。
|
|
|
|
|
|
* **成功分支**: 版本检查通过,设备继续。
|
2025-12-02 13:27:20 +08:00
|
|
|
|
2. **设备准备 (Device)**:
|
2025-12-02 17:16:48 +08:00
|
|
|
|
* 设备清空非活动分区。
|
|
|
|
|
|
* **失败分支**: 上报 `FAILED` (ERR_PREPARE),流程结束。
|
|
|
|
|
|
* **成功分支**: 设备发送 `RequestFile` 请求清单文件。
|
|
|
|
|
|
|
|
|
|
|
|
### 阶段三:文件循环下载和校验
|
|
|
|
|
|
|
|
|
|
|
|
1. **清单文件传输与校验 (Platform <-> Device)**:
|
|
|
|
|
|
* 平台发送清单文件,设备接收并校验。
|
|
|
|
|
|
* **失败分支**: 上报 `FAILED` (ERR_MANIFEST_VERIFY),流程结束。
|
|
|
|
|
|
2. **固件文件循环 (Device <-> Platform)**:
|
|
|
|
|
|
* 设备逐个请求、下载、校验清单中的所有文件。
|
|
|
|
|
|
* **失败分支 (重试耗尽)**: 上报 `FAILED` (ERR_DOWNLOAD / ERR_VERIFY),流程结束。
|
|
|
|
|
|
|
|
|
|
|
|
### 阶段四:激活与最终状态
|
|
|
|
|
|
|
|
|
|
|
|
1. **激活重启 (Device)**: 所有文件成功下载后,设备配置启动分区并重启。
|
2025-12-02 13:27:20 +08:00
|
|
|
|
2. **新固件自检 (Device)**:
|
2025-12-02 17:16:48 +08:00
|
|
|
|
* **成功分支**:
|
|
|
|
|
|
* 设备标记自身为有效。
|
|
|
|
|
|
* 设备上报 `SUCCESS`。
|
|
|
|
|
|
* 平台更新任务状态为 `SUCCESS`。
|
|
|
|
|
|
* **失败分支 (自检失败/未标记)**:
|
|
|
|
|
|
* 设备等待底层机制自动回滚。
|
|
|
|
|
|
* 设备回滚后,上报 `FAILED` (ERR_ROLLED_BACK)。
|
|
|
|
|
|
* 平台更新任务状态为 `FAILED`。
|
|
|
|
|
|
3. **总超时检查 (Platform)**: 如果在规定时间内未收到任何最终报告,平台将任务标记为 `FAILED` (ERR_TIMEOUT)。
|