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’可以强制进行写入
- 
地址 内容类型 参数 返回值 /uploadContent-Type: multipart/form-datacontent : 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.jsonaddress : 设备管理地址 | 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 许可协议。转载请注明来自 四叶草の博客!







