跳到主要内容

空中升级 (OTA) 更新

通过 OTA 升级,无需物理接触设备,也可远程更新节点的固件。

概述

在 RainMaker 中,OTA 更新可以:

  • 检查可用的固件更新。
  • 发起节点 OTA 更新。
  • 监控 OTA 更新任务的状态。

检查 OTA 更新

使用 checkOTAUpdate 方法,检查该节点是否有可用的空中升级(OTA)更新。

try {
const otaResponse = await node.checkOTAUpdate();
console.log("OTA update availability:", otaResponse);

if (otaResponse.otaAvailable) {
console.log("Update available:", otaResponse.fwVersion);
console.log("OTA Job ID:", otaResponse.otaJobId);
console.log("File size:", otaResponse.fileSize);
}
} catch (error) {
console.error("Error checking OTA update:", error);
}

ESPOTAUpdateResponse 接口

checkOTAUpdate 方法返回一个 ESPOTAUpdateResponse 对象,包含 OTA 更新可用性及其详细信息。

属性类型必填说明
otaAvailable布尔值指示设备是否有可用的 OTA 更新。
status字符串OTA 更新的状态。
description字符串OTA 更新的描述。
fwVersion字符串可用于更新的固件版本。
otaJobId字符串可用于发起更新的 OTA 任务 ID。
fileSize数字固件文件的大小(以字节为单位)。
url字符串用于下载固件的 URL。
fileMD5字符串用于校验的固件文件的 MD5 哈希值。
streamId字符串OTA 更新的流 ID。
metadataRecord<string, any>与 OTA 更新相关的附加元数据。

示例:检查 OTA 更新并使用返回结果

try {
const otaResponse = await node.checkOTAUpdate();

if (otaResponse.otaAvailable) {
console.log("OTA Update Available!");
console.log("Firmware Version:", otaResponse.fwVersion);
console.log("Description:", otaResponse.description);
console.log("File Size:", otaResponse.fileSize, "bytes");
console.log("Status:", otaResponse.status);
console.log("OTA Job ID:", otaResponse.otaJobId);

// 使用 otaJobId 发起更新
if (otaResponse.otaJobId) {
// 可以使用此任务 ID 调用 pushOTAUpdate
console.log("Ready to update with job ID:", otaResponse.otaJobId);
}

// 可选字段
if (otaResponse.url) {
console.log("Firmware URL:", otaResponse.url);
}

if (otaResponse.fileMD5) {
console.log("File MD5:", otaResponse.fileMD5);
}

if (otaResponse.metadata) {
console.log("Metadata:", otaResponse.metadata);
}
} else {
console.log("No OTA update available. Current status:", otaResponse.status);
}
} catch (error) {
console.error("Error checking OTA update:", error);
}

示例:在继续操作之前校验 OTA 更新

try {
const otaResponse = await node.checkOTAUpdate();

if (otaResponse.otaAvailable) {
// 验证是否包含所有必需信息
if (!otaResponse.otaJobId) {
console.error("OTA Job ID is missing");
return;
}

// 如有需要,检查文件大小
if (otaResponse.fileSize > 0) {
console.log(`Update size: ${(otaResponse.fileSize / 1024 / 1024).toFixed(2)} MB`);
}

// 如果可用,验证 MD5
if (otaResponse.fileMD5) {
console.log("File verification hash:", otaResponse.fileMD5);
}

// 使用任务 ID 继续执行更新
console.log("Proceeding with OTA update...");
// 将 otaResponse.otaJobId 用于 pushOTAUpdate
}
} catch (error) {
console.error("Error checking OTA update:", error);
}

推送 OTA 更新

使用 pushOTAUpdate 方法,并指定 OTA 任务 ID,发起节点 OTA 更新。该 OTA 任务 ID 来自 checkOTAUpdate 的返回结果。

try {
// 首先,检查可用的 OTA 更新
const otaResponse = await node.checkOTAUpdate();

if (otaResponse.otaAvailable && otaResponse.otaJobId) {
// 使用来自 checkOTAUpdate 响应的 otaJobId
const response = await node.pushOTAUpdate(otaResponse.otaJobId);
console.log("OTA update initiated:", response);
} else {
console.log("No OTA update available or job ID missing");
}
} catch (error) {
console.error("Error initiating OTA update:", error);
}

示例:完整的 OTA 更新流程

try {
// 步骤 1: 检查可用的 OTA 更新
const otaResponse = await node.checkOTAUpdate();

if (!otaResponse.otaAvailable) {
console.log("No OTA update available. Status:", otaResponse.status);
return;
}

console.log("OTA Update Available!");
console.log("Firmware Version:", otaResponse.fwVersion);
console.log("File Size:", otaResponse.fileSize, "bytes");

// 步骤 2: 使用任务 ID 启动 OTA 更新
if (otaResponse.otaJobId) {
const pushResponse = await node.pushOTAUpdate(otaResponse.otaJobId);
console.log("OTA update initiated:", pushResponse);

// 步骤 3: 监控更新状态
const status = await node.getOTAUpdateStatus(otaResponse.otaJobId);
console.log("OTA update status:", status);
}
} catch (error) {
console.error("Error in OTA update flow:", error);
}

获取 OTA 更新状态

使用 getOTAUpdateStatus 方法,查询此前为节点发起的 OTA 更新的状态。使用从 checkOTAUpdatepushOTAUpdate 获取的 OTA 任务 ID。

try {
// 从 checkOTAUpdate 响应中获取 OTA 任务 ID
const otaResponse = await node.checkOTAUpdate();

if (otaResponse.otaJobId) {
const statusResponse = await node.getOTAUpdateStatus(otaResponse.otaJobId);
console.log("OTA update status:", statusResponse.status);
console.log("Node ID:", statusResponse.nodeId);
console.log("Timestamp:", new Date(statusResponse.timestamp));
console.log("Additional Info:", statusResponse.additionalInfo);
}
} catch (error) {
console.error("Error fetching OTA update status:", error);
}

ESPOTAUpdateStatusResponse 接口

getOTAUpdateStatus 方法返回一个 ESPOTAUpdateStatusResponse 对象,包含当前 OTA 更新的状态。

属性类型必填说明
status字符串当前 OTA 更新的状态(例如 “in_progress”、“completed”、“failed”)。
nodeId字符串正在查询的该节点的 ID。
timestampnumber状态最近一次更新的时间戳(毫秒级 Unix 时间戳)。
additionalInfo字符串关于 OTA 更新状态的附加信息。

示例:监控 OTA 更新进度

async function monitorOTAUpdate(node, otaJobId) {
try {
const maxAttempts = 30; // 状态检查的最大尝试次数
let attempts = 0;

while (attempts < maxAttempts) {
const statusResponse = await node.getOTAUpdateStatus(otaJobId);
const status = statusResponse.status;

console.log(`OTA Update Status (Attempt ${attempts + 1}):`, status);
console.log("Node ID:", statusResponse.nodeId);
console.log("Last Updated:", new Date(statusResponse.timestamp).toLocaleString());

if (statusResponse.additionalInfo) {
console.log("Additional Info:", statusResponse.additionalInfo);
}

// 检查更新是否完成或失败
if (status === "completed" || status === "failed") {
console.log("OTA update finished with status:", status);
return statusResponse;
}

// 等待下一次检查(例如 5 秒)
await new Promise(resolve => setTimeout(resolve, 5000));
attempts++;
}

console.log("Status check timeout");
return null;
} catch (error) {
console.error("Error monitoring OTA update:", error);
throw error;
}
}

// 使用示例
try {
const otaResponse = await node.checkOTAUpdate();
if (otaResponse.otaAvailable && otaResponse.otaJobId) {
await node.pushOTAUpdate(otaResponse.otaJobId);
const finalStatus = await monitorOTAUpdate(node, otaResponse.otaJobId);

if (finalStatus) {
console.log("Final Status:", finalStatus.status);
console.log("Completed at:", new Date(finalStatus.timestamp).toLocaleString());
}
}
} catch (error) {
console.error("Error in OTA update process:", error);
}

示例:处理不同的 OTA 状态值

try {
const otaResponse = await node.checkOTAUpdate();

if (otaResponse.otaAvailable && otaResponse.otaJobId) {
await node.pushOTAUpdate(otaResponse.otaJobId);

const statusResponse = await node.getOTAUpdateStatus(otaResponse.otaJobId);

switch (statusResponse.status) {
case "in_progress":
console.log("OTA update is in progress...");
console.log("Additional Info:", statusResponse.additionalInfo);
break;
case "completed":
console.log("OTA update completed successfully!");
console.log("Completed at:", new Date(statusResponse.timestamp).toLocaleString());
break;
case "failed":
console.error("OTA update failed!");
console.error("Error details:", statusResponse.additionalInfo);
break;
case "pending":
console.log("OTA update is pending...");
break;
default:
console.log("Unknown status:", statusResponse.status);
}
}
} catch (error) {
console.error("Error in OTA update process:", error);
}

OTA 更新流程

下图时序图展示了 SDK、App 与节点之间完整的 OTA 更新流程:

On this page