上报升级进度
首先我们使用一个类来封装上报升级进度的操作:
//IotHub_Device/sdk/ota_progress.jsconst ObjectId = require('bson').ObjectID;class OTAProgress {constructor({productName, deviceName, mqttClient, version, type}) {this.productName = productNamethis.deviceName = deviceNamethis.mqttClient = mqttClientthis.version = versionthis.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.jshandleCommand({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 = 0var performUpgrade = function () {console.log(`download:${percent}`)progress.download(percent)if(percent < 100){percent += 20setTimeout(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 = 0var 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.progressconsole.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.jsdevice is onlinegoing to upgrade firmware: http://test.com/firmware/1.1.pkg, version=1.1download:0download:20download:40download:60download:80download:100upgrade 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 升级功能,在接下来的几节课中,我们会讨论如何设计和实现一个新的功能: 设备影子。
