上报升级进度
首先我们使用一个类来封装上报升级进度的操作:
//IotHub_Device/sdk/ota_progress.js
const ObjectId = require('bson').ObjectID;
class OTAProgress {
constructor({productName, deviceName, mqttClient, version, type}) {
this.productName = productName
this.deviceName = deviceName
this.mqttClient = mqttClient
this.version = version
this.type = type
}
sendProgress(progress) {
var meta = {
version: this.version,
type: this.type
}
var topic = `update_ota_status/${this.productName}/${this.deviceName}/${new ObjectId().toHexString()}`
this.mqttClient.publish(topic, JSON.stringify({...meta, ...progress}), {qos: 1})
}
download(percent, desc = "download") {
this.sendProgress({progress: percent, desc: desc})
}
downloadError(desc = "download error"){
this.download(-1, desc)
}
checkMD5Error(desc = "check md5 error"){
this.sendProgress({progress: -2, desc: desc})
}
installError(desc = "install error"){
this.sendProgress({progress: -3, desc: desc})
}
error(desc = "error"){
this.sendProgress({progress: -4, desc: desc})
}
}
这个类封装了上报升级进度的各个节点的操作,设备应用代码只需要在相应的节点调用对应的方法就是了。比如下载升级包时调用 progress.download(17)
,安装失败时调用 progress.installError()
响应OTA指令
在收到$ota_upgrade
指令以后,DeviceSDK 代码需要把指令数据传递给设备应用代码:
//IotHub_Device/sdk/iot_device.js
handleCommand({commandName, requestID, encoding, payload, expiresAt, commandType = "cmd"}) {
...
if (commandName.startsWith("$")) {
payload = JSON.parse(data.toString())
if (commandName == "$set_ntp") {
this.handleNTP(payload)
} else if (commandName == "$set_tags") {
this.setTags(payload)
}else if(commandName == "$ota_upgrade"){
var progress = new OTAProgress({
productName: this.productName,
deviceName: this.deviceName,
mqttClient: this.client,
version: payload.version,
type: payload.type
})
this.emit("ota_upgrade", payload, progress)
}
}
...
}
}
DeviceSDK 除了把 OTA 升级相关的数据通过”ota_upgrade”事件传递给设备应用代码,还传递了一个 OTAProgress 对象,设备应用代码可以调用这个对象方法正确上报升级进度。
代码联调
设备端的功能就全部实现了,接下来我们写一端代码来测试 OTA 升级功能。
首先实现一个设备端来模拟 OTA 升级,它收到 OTA 升级指令以后,会每隔 2 秒更新一次下载进度,当下载进度达到 100% 时,会再等待 3 秒之后上报更新后的软件版本,我们用这样的方式来模拟一次成功的 OTA 升级流程:
//IotHub_Device/samples/ota_upgrade.js
...
const currentVersion = "1.0"
device.on("online", function () {
console.log("device is online")
})
device.on("ota_upgrade", function (ota, progress) {
console.log(going to upgrade ${ota.type}: ${ota.url}, version=${ota.version})
var percent = 0
var performUpgrade = function () {
console.log(`download:${percent}`)
progress.download(percent)
if(percent < 100){
percent += 20
setTimeout(performUpgrade, 2000)
}else{
setTimeout(function () {
device.updateStatus({firmware_ver: ota.version})
}, 3000)
}
}
performUpgrade()
})
device.connect()
device.updateStatus({firmware_ver: currentVersion})
然后模拟业务系统,向设备发送 OTA 指令以后,每隔 1 秒钟查询一次设备的升级进度,进度达到 100 以后就检查设备的软件版本,如果设备的软件版本和预期一致,就说明设备已经升级成功了:
//IotHub_Server/samples/perform_ota.js
...
var otaData = {
type: "firmware",
url: "http://test.com/firmware/1.1.pkg",
version: "1.1",
size: 1000,
md5: "abcd"
}
var progress = 0
var checkUpgradeProgress = function () {
if (progress < 100) {
request.get(`http://127.0.0.1:3000/ota/${process.env.TARGET_PRODUCT_NAME}/${process.env.TARGET_DEVICE_NAME}`, function (err, res, body) {
if (!err && res.statusCode == 200) {
var info = JSON.parse(body);
if(info.version == otaData.version) {
progress = info.progress
console.log(`current progress:${progress}%`);
}
setTimeout(checkUpgradeProgress, 1000)
}
})
} else {
request.get(`http://127.0.0.1:3000/devices/${process.env.TARGET_PRODUCT_NAME}/${process.env.TARGET_DEVICE_NAME}`, function (err, res, body) {
if (!err && res.statusCode == 200) {
var info = JSON.parse(body);
console.log(`current version:${info.device_status.firmware_ver}`);
if (info.device_status.firmware_ver == otaData.version) {
console.log(`upgrade completed`);
} else {
setTimeout(checkUpgradeProgress, 1000)
}
}
})
}
}
console.log("perform upgrade")
request.post(`http://127.0.0.1:3000/ota/${process.env.TARGET_PRODUCT_NAME}/${process.env.TARGET_DEVICE_NAME}`, {
form: otaData
}, function (error, response) {
if (error) {
console.log(error)
} else {
console.log('statusCode:', response && response.statusCode);
checkUpgradeProgress()
}
})
先运行 IotHub\_Device/samples/ota\_upgrade.js
,然后运行 IotHub\_Server/samples/perform_ota.js
,观察下输出:
## IotHub_Device/samples/ota_upgrade.js
device is online
going to upgrade firmware: http://test.com/firmware/1.1.pkg, version=1.1
download:0
download:20
download:40
download:60
download:80
download:100
upgrade completed
## IotHub_Server/samples/perform_ota.js
perform upgrade
statusCode: 200
current progress:0%
current progress:0%
current progress:20%
current progress:20%
current progress:40%
current progress:60%
current progress:60%
current progress:80%
current progress:80%
current progress:100%
current version:1.0
current version:1.0
current version:1.1
upgrade completed
这说明 OTA 升级功能在正确工作了。
这一节,我们完成了 IotHub 设备的 OTA 升级功能,在接下来的几节课中,我们会讨论如何设计和实现一个新的功能: 设备影子。