開發與維運

HaaS輕應用(JavaScript)OTA 遠程升級組件

來源 | HaaS技術社區

1、功能簡介

OTA升級是很多嵌入式產品必備的一個功能。HaaS 輕應用提供了完備的OTA解決方案。本案例就是一個升級JavaScript腳本的端雲一體化例子,用戶可以通過JavaScript腳本實現應用腳本的版本上報,下載,完整性檢驗和腳本加載;具體流程如下圖所示:

image.png

1.1、設備聯網

在做腳本升級前確保設備是連網上線的,連網需要加入IOT組件,如果是wifi設備,需要加入netmgr組件進行配網,所以如上代碼中,引入了iot組件和netmgr組件

import * as netmgr from 'netmgr';
import * as iot from 'iot';

還需要添加設備的三元組信息:

var productKey = ' ';      /* your productKey */
var deviceName = ' ';    /* your deviceName */ 
var deviceSecret = ' ';   /* your deviceSecret */

通過調用如下代碼:

var device = iot.device({
        productKey: productKey,
        deviceName: deviceName,
        deviceSecret: deviceSecret
});

實現設備的上線;

1.2、版本上報

當設備上線後,需要將腳本的版本號報上雲端,所以需要事先定義好腳本的版本,如示例代碼定義的版本為:

var default_ver = '2.0.0';

由於阿里雲IoT物聯平臺OTA是多模塊升級方式,所以還需要定義一個模塊名稱,如果當前的腳本為設備的主業務,模塊名稱必須為"default",如示例代碼:

var module_name = 'default';

版本號和模塊名定義完成後,配合設備名和產品密鑰,調用如下代碼可實現版本號上報雲端:

ota.report({
                device_handle: iotDeviceHandle,
                product_key: productKey,
                device_name: deviceName,
                module_name: module_name,
                version: default_ver
        });

ota.report接口用來將腳本版本號上報雲端,入參有5個,第一個為IOT 設備handlem,設備成功連網後,會返回整個對象,第二參數為產品的密鑰,第三個參數為設備名稱,第四個參數為要上報版本模塊的名稱;

完成以上調用後,在阿里雲物聯網平臺會看到如下信息:

image.png

上圖中的default模塊版本即為腳本中填入的版本號,system模塊的版本為當前運行JS的OS系統版本;

1.3、腳本上傳雲端

首先需要做個高版本的js腳本,將步驟2中的JS版本號改成 var default_ver = '3.0.0';,然後創建一個app.json文件,文件內容如下:

{
    "version": "3.0.0",
    "io": {},
    "debugLevel": "DEBUG"
}

此文件主要是JS配套的配置,如設備端的io配置以及JS的版本號(與JS腳本中的版本號要相同);將app.js和app.json放到一個文件夾中,用JS工具打包成app.bin;JS工具用法請參考"命令行工具的pack命令使用";
打包完成後請參考下圖完成固件上傳到雲端:

image.png

1.4、雲端觸發升級

JS腳本上傳完成後,雲端觸發升級,如下圖:

image.png

1.5、獲取升級文件信息

當雲端觸發升級後,設備端會收到雲端的發送的腳本信息,具體包括:文件大小、url、模塊名稱、hash type(md5或sha256)、hash值;對應上面的代碼為:

ota.on('new', function(res) {
                console.log('length is ' + res.length);
                console.log('module_name is ' + res.module_name);
                console.log('version is ' + res.version);
                console.log('url is ' + res.url);
                console.log('hash is ' + res.hash);
                console.log('hash_type is ' + res.hash_type);

1.6、下載升級文件

通過步驟5設備端已拿到雲端即將下發文件的版本號、url、模塊名等,用戶可根據需求決定是否下載此文件,比如版本比對,發現版本號較當前版本小,可以選擇不下載,還可以通過模塊名稱判斷下載的是什麼文件,如模塊名稱為default,則下載的是JS腳本,用戶可根據自己需要自己定義; 如用設備需要下載此文件,則通過download方法可實現下載,如示例代碼:

ota.download({
                        url: info.url,
                        store_path: info.store_path
                }, function(res) {

下載接口,需要填入的參數有2個,第一參數為文件的URL,第二參數為文件的存儲路徑,包括存儲的文件名稱,如示例代碼定義的:

var info = {
        url: '',
        store_path: '/data/jsamp/pack.bin',

1.7、校驗升級文件

當文件下載完成後,需要驗證文件下載的是否完整,需要調用verify驗證,如上面示例代碼:

ota.verify({
                                        length: info.length,
                                        hash_type: info.hashType,
                                        hash: info.hash,
                                        store_path: info.store_path
                                }, function(res) {

ota.verify入參有4個,分別為,下載文件的長度、雲端下發的hash type(md5或sha256)、對應的hash值以及存儲已下載文件的路徑,這些參數已通過步驟5全部獲取,直接填入即可;

1.8、加載升級文件

當步驟7校驗成功後,即可實現腳本文件的加載,此時調用upgrade即可實現腳本的重新加載,如上面的示例代碼:

ota.upgrade({
                                                        length: info.length,
                                                        store_path: info.store_path,
                                                        install_path: info.install_path
                                                }, function(res)

ota.upgrade有3個入參,第一個為下載文件的長度,第二入參為已下載文件的路徑,第三個參數為要安裝的路徑,如示例代碼定義的安裝路徑:

install_path: '/data/jsamp/',

如果升級成功,腳本會重新加載,上報版本號,雲端狀態如下圖所示:

image.png

2、OTA接口介紹

open(Object option)

屬性

類型

必填

描述

iot

Text

傳入IOT組件的device handle

report(Object option)

屬性

類型

必填

描述

device_handle

Number

傳入IOT組件的device handle指針

product_key

String

設備的產品密鑰

device_name

String

設備名稱

module_name

String

模塊名稱

version

String

模塊的版本號

dowload(Object option, Function callback)

屬性

類型

必填

描述

url

String

下載文件的URL

store_path

String

存儲下載文件的路徑包括文件名稱

callback

Function

下載完後的回調函數

verify(Object option, Function callback)

屬性

類型

必填

描述

length

String

下載文件的長度

hash_type

String

是md5還是sha256

store_path

String

存儲下載文件的路徑

callback

Functiom

校驗結果的回調函數

upgrade(Object option, Function callback)

屬性

類型

必填

描述

length

String

下載文件的長度

store_path

String

存儲下載文件的路徑

install_path

String

安裝腳本的路徑

callback

Function

升級成功的回調函數

3、參考代碼

 
import * as netmgr from 'netmgr';
import * as iot from 'iot';
import * as appota from 'appota'
 
//此腳本包含了wifi連網功能,僅適合haas100、haaseduk1
 
var productKey = '';      /* your productKey */
var deviceName = '';      /* your deviceName */
var deviceSecret = '';  /* your deviceSecret */
var device;
var module_name = 'default';
var default_ver = '2.0.0';
 
var ota;
var status;
/* download info */
var info = {
        url: '',
        store_path: '/data/jsamp/pack.bin',
        install_path: '/data/jsamp/',
        length: 0,
        hashType: '',
        hash: ''
}
 
function createDevice() {
    device = iot.device({
        productKey: productKey,
        deviceName: deviceName,
        deviceSecret: deviceSecret,
        region: 'cn-shanghai',
    });
 
device.on('connect', function () {
    console.log('(re)connected');
    var iotDeviceHandle = device.getDeviceHandle();
    console.log('get device handle module');
        ota = appota.open(iotDeviceHandle);
        console.log('report default module ver');
        ota.report({
                device_handle: iotDeviceHandle,
                product_key: productKey,
                device_name: deviceName,
                module_name: module_name,
                version: default_ver
        });
        ota.on('new', function(res) {
                console.log('length is ' + res.length);
                console.log('module_name is ' + res.module_name);
                console.log('version is ' + res.version);
                console.log('url is ' + res.url);
                console.log('hash is ' + res.hash);
                console.log('hash_type is ' + res.hash_type);
 
                info.url = res.url;
                info.length = res.length;
                info.module_name = res.module_name;
                info.version = res.version;
                info.hash = res.hash;
                info.hashType = res.hash_type;
 
                ota.download({
                        url: info.url,
                        store_path: info.store_path
                }, function(res) {
                        if (res >= 0) {
                                console.log('download success');
                                console.log('verify start');
                                console.log(info.hashType);
                                ota.verify({
                                        length: info.length,
                                        hash_type: info.hashType,
                                        hash: info.hash,
                                        store_path: info.store_path
                                }, function(res) {
                                        if (res >= 0) {
                                                console.log('verify success');
                                                console.log('upgrade start');
                                                ota.upgrade({
                                                        length: info.length,
                                                        store_path: info.store_path,
                                                        install_path: info.install_path
                                                }, function(res) {
                                                        if (res >= 0) {
                                                                console.log('upgrade success')
                                                        } else {
                                                                console.log('upgrade failed')
                                                        }
                                                })
                                        } else {
                                                console.log('verify failed');
                                        }
                                })
                        } else {
                                console.log('download failed');
                        }
                });
        });
});
}
 
var network = netmgr.openNetMgrClient({
    name: '/dev/wifi0'
});
 
var status;
status = network.getState();
console.log('status is ' + status);
network.connect({
  ssid: '',             //請替換為自己的熱點ssid
  password: ''          //請替換為自己熱點的密碼
});
 
network.on('error', function () {
    console.log('error ...');
});
 
network.on('connect', function () {
    createDevice();
});

Leave a Reply

Your email address will not be published. Required fields are marked *