如何实现由设备和手机应用主动检查 OTA 升级的功能?
本文说明 ESP RainMaker 中用户确认 OTA 的工作流程与实现。与管理面板中的 "User Approval" 选项不同,该方案让节点自行决定是立即应用升级,还是等待用户明确确认,从而对升级过程提供更好的控制和安全性。
组件
节点端
- OTA 服务(
esp.service.ota),包含两个参数:Operation(esp.param.ota_operation):用于接收指令Info(esp.param.ota_info):用于共享升级信息
客户端应用
- 监控
Info参数以获知可用升级 - 提供用户确认升级的界面
- 通过
Operation参数发送指令
工作流程
- 发起升级检查 — 可通过
CONFIG_ESP_RMAKER_OTA_AUTOFETCH自动触发,也可通过check操作指令手动触发。 - 发现可用升级 — 节点用升级详情更新
Info参数,并等待用户确认。上报状态为delayed,描述为Waiting for Approval。 - 确认升级 — 用户在应用中查看升级信息。用户确认后,应用发送
start指令,并缓存任务 ID,以便后续通过nodes/ota_statusREST API 查询。 - 升级过程 — 节点下载固件、校验、应用升级,成功后重启。
- 升级监控 — 节点作为常规 OTA 流程的一部分上报升级状态。用户可使用节点 ID 和任务 ID,通过
nodes/ota_statusREST API 进行监控。
JSON 结构
节点配置 JSON
{
"node_id": "<node-id>",
"config_version": "2020-03-20",
"devices": [],
"services": [
{
"name": "OTA",
"type": "esp.service.ota",
"params": [
{
"name": "Operation",
"type": "esp.param.ota_operation",
"data_type": "string",
"properties": ["write"],
"valid_strs": ["check", "start"]
},
{
"name": "Info",
"type": "esp.param.ota_info",
"data_type": "object",
"properties": ["read"]
}
]
}
]
}
节点参数 JSON
初始状态
{
"OTA": {
"Operation": "",
"Info": "{}"
}
}
发现可用升级时
{
"OTA": {
"Operation": "",
"Info": {
"job_id": "job_12345",
"fw_version": "2.0.0"
}
}
}
参数更新消息
从应用到节点(Operation)
{ "OTA": { "Operation": "check" } }
或
{ "OTA": { "Operation": "start" } }
从节点到应用(Info)
{
"OTA": {
"Info": {
"job_id": "job_12345",
"fw_version": "2.0.0"
}
}
}
实现示例
节点端实现
/* 创建 OTA 服务 */
esp_rmaker_device_t *ota_service = esp_rmaker_service_create("OTA", "esp.service.ota", NULL);
/* 添加带 write 属性和合法取值的 "Operation" 字符串参数 */
esp_rmaker_param_t *operation_param = esp_rmaker_param_create("Operation",
"esp.param.ota_operation",
esp_rmaker_str(""),
PROP_FLAG_WRITE);
const char *valid_strs[] = {"check", "start"};
esp_rmaker_param_add_valid_str_list(operation_param, valid_strs, 2);
esp_rmaker_device_add_param(ota_service, operation_param);
/* 添加只读的 "Info" 对象参数 */
esp_rmaker_param_t *info_param = esp_rmaker_param_create("Info",
"esp.param.ota_info",
esp_rmaker_obj("{}"),
PROP_FLAG_READ);
esp_rmaker_device_add_param(ota_service, info_param);
/* 为 OTA 服务注册写入回调 */
esp_rmaker_device_add_cb(ota_service, ota_service_write_cb, NULL);
/* 将 OTA 服务添加到节点 */
esp_rmaker_node_add_device(node, ota_service);
/* 注册自定义 OTA 回调 */
esp_rmaker_ota_config_t ota_config = {
.ota_cb = custom_ota_callback,
};
esp_rmaker_ota_enable(&ota_config, OTA_USING_TOPICS);
写入回调实现
static esp_err_t ota_service_write_cb(const esp_rmaker_device_t *device,
const esp_rmaker_param_t *param,
const esp_rmaker_param_val_t val,
void *priv_data,
esp_rmaker_write_ctx_t *ctx)
{
if (strcmp(esp_rmaker_param_get_name(param), "Operation") == 0) {
if (strcmp(val.val.s, "start") == 0) {
ota_approved = true;
ESP_LOGI(TAG, "OTA approved.");
esp_rmaker_ota_fetch_with_delay(1);
} else if (strcmp(val.val.s, "check") == 0) {
ESP_LOGI(TAG, "Checking for OTA updates.");
esp_rmaker_ota_fetch_with_delay(1);
}
}
return ESP_OK;
}

