OTA更新系统(详细设计)
OTA
包的content.json
键值 | 类型 | 备注 |
---|---|---|
package | 字符串 | 包名称 |
description | 字符串 | 描述 |
updateInfo | 字符串 | 更新描述 |
version | 字符串 | 版本号 |
branch | 字符串 | 分支 |
local | 字符串 | 本地包位置 |
remote | 字符串 | OTA服务器 |
sha256 | 字符串 | 升级包的SHA256校验码 |
AfterUpdate | 字符串 | 更新后指令 |
dependencies | JSON | 依赖 |
一、生产运行侧
重启设备
daemon程序
依赖:flask
、requests
JSON配置文件
由于单个设备的包较少,所以维护一个json文件
daemon整体配置文件(device.json
):
键值 | 类型 | 备注 |
---|---|---|
id | INT | 设备唯一id |
device | 字符串 | 设备名称 |
registry | 字符串 | 设备注册服务地址 |
description | 字符串 | 描述 |
flask | JSON | flask配置项(见下) |
package | 列表 | 列表中每一项是一个json ,为每个包的content.json |
flask配置项:
键值 | 类型 | 备注 |
---|---|---|
host | 字符串 | 设备启动IP |
port | 整数 | 端口号 |
debug | 布尔 | 是否开启debug模式 |
例如:
1 | { |
信息API接口
地址 | 参数 | 返回值 |
---|---|---|
/getInfo |
无 | -“status” -“content”:该设备的 device.json |
操作API接口
地址 | 内容类型 | 参数 | 返回值 |
---|---|---|---|
/startUpdate |
Content-Type: multipart/form-data |
content : content.json (包的content.json ) |
status |
二、OTA服务器
依赖:flask
、pymysql
配置文件
数据库
ota表:
字段 | 类型 | 备注 |
---|---|---|
id | INT | |
name | VARCHAR | 包名 |
version | VARCHAR | 版本号 |
branch | VARCHAR | 分支 |
content | JSON | 包的content.json |
文件管理
文件获取地址:/otafiles/<package>/<branch>/<package>-<branch>-<version>.zip
例如,我需要helloworld
包的major
分支的0.1.0
版本的包
那么访问http://IP:PORT/otafiles/helloworld/major/helloworld-major-0.1.0.zip
即可下载文件
API接口
status正常返回200,404代表无法找到,400代表参数错误或服务器错误
地址 | 参数 | 返回值 |
---|---|---|
/latestVersion |
package= 包名branch= 分支 |
-“status” -“content.json”:该包的 content.json |
/getVersion |
package= 包名(必须)branch= 分支version= 版本号 |
-“status” -“list”:一个列表,存储所有的查询结果 |
上传接口
用PUT的方式上传status正常返回200
为了以防上传丢包导致问题,服务器会重新进行包校验,如果与content.json
不符,服务器不会接受这个文件
如果在上传时发现文件已存在或者数据库中已经有该版本的记录时,不会进行修改,
此时在url的参数里加上’overwrite=1’可以强制进行写入
-
地址 内容类型 参数 返回值 /upload
Content-Type: multipart/form-data
content : content.json
file : 文件status
三、开发侧
依赖:requests
使用:python pack.py
主要流程:
- 输入服务器的URL,并检查其可用性。
- 输入包名和分支名,获取服务器上的最新版本信息。
- 输入要打包的版本号,检查其是否已存在于服务器上。如果已存在,可以选择覆盖或退出。
- 输入要打包的文件夹路径,如果文件夹存在,则开始打包。
- 打包成功后,生成一个包含最新版本信息的
content.json
文件,开发者可以在上传前修改这个content.json
文件。 - 最后,将打包的zip文件和
content.json
文件上传到服务器
四、设备注册服务
数据库
devices表:
字段 | 类型 | 备注 |
---|---|---|
id | INT | |
device | VARCHAR | 设备名 |
address | VARCHAR | 设备地址 |
content | JSON | 设备内包情况 |
status | JSON | 设备状态 |
lastupdate | TIMESTAMP | 最后更新时间 |
设备侧API接口
接受从生产运行侧的注册和注销请求
每30s接受一次心跳包,超过120s未接收到心跳包即注销设备
地址 | 内容类型 | 参数 | 返回值 |
---|---|---|---|
/register |
Content-Type: multipart/form-data |
content : device.json address : 设备管理地址 |
status |
/logout |
Content-Type: multipart/form-data |
id : 设备id | status |
/heartbeat |
Content-Type: multipart/form-data |
id : 设备id | status |
接受从设备上的更新状态
地址 | 内容类型 | 参数 | 返回值 |
---|---|---|---|
/updateInfo |
Content-Type: multipart/form-data |
content : update.json |
status |
update.json
若是正常过程升级:
1 | { |
若是出现错误:
1 | { |
信息API接口
返回场景内的所有设备与包信息
地址 | 参数 | 返回值 | |
---|---|---|---|
/getAllInfo |
无 | -“status” -“devices”:所有设备的包的情况例子如下 |
1 | { |
地址 | 参数 | 返回值 | |
---|---|---|---|
/getDeviceInfo |
id=设备id | -“status” -“id”:设备id -“packages”:设备上所有的包 |
1 | { |
地址 | 参数 | 返回值 | |
---|---|---|---|
/getStatus |
无 | -“status” -“update”:升级状态 |
1 | { |
升级状态分为:
- BeforeUpdate:升级前准备
- Downloading:下载包
- Updating:替换中
- AfterUpdate:升级后准备
- Restore:重建现场
地址 | 参数 | 返回值 | |
---|---|---|---|
/getUpdatelist |
无 | -“status” -“list”:注册服务中的更新队列 |
获取更新队列
1 | { |
获取当前升级任务的日志
地址 | 参数 | 返回值 | |
---|---|---|---|
/getUpdatelog |
无 | 一个字符串,自上次All Update Complete之后的所有日志内容 |
操作API接口
地址 | 内容类型 | 参数 | 返回值 |
---|---|---|---|
/update |
Content-Type: multipart/form-data |
content : update.json |
status |
升级场景内的设备与包,content的内容例子如下
1 | { |
若当前存在非空的升级队列status
返回400
地址 | 内容类型 | 参数 | 返回值 |
---|---|---|---|
/delFromlist |
Content-Type: multipart/form-data |
content : delete.json |
status |
删除更新队列中的某些更新内容,delete.json
的内容例子如下
1 | { |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 四叶草の博客!