應用腳本建置器

模擬一個物聯網裝置

Schema 的資料來源來自於物聯網裝置發送,或是資料經過處理之後的結果。在這個教學中,我們藉由利用腳本建置器與排程功能來模擬一台智慧電表定時回報總用電量的功能。

  • 建立一個 Electro Schema。排程會定期執行 Script,將 timestamp 數值除以 999999999 之餘數,視作裝置用電總量,寫入 Schema AttributeTotalValue 屬性內。
    • 排程時間:每小時 00 分
    • Script 行為:
      • 執行時間為 12:00,則產生 11:00 ~ 12:00 之間的裝置用電總量。
      • 11:01 時的用電總量,記錄於 11:01,以此類推。
      • 設 timestamp 為變數 S,電表顯示最大值 999999999 為變數 M,每分鐘等於 60000(毫秒)為變數 T,
        則依序產生 11:01, 11:02 ... 12:00 時間之對應數值為:
        (S-60T)%M, (S-59T)%M, ... (S-2T)%M, (S-1T)%M
      • 共寫入 60 筆 entry 於 Electro Schema 內。

Electro Schema

{
    "schemaname":"Electro",
    "key_schema":[{"name":"StartTime","type":"DT"},{"name":"EndDeviceMAC","type":"S","length":32},
                  {"name":"GatewayID","type":"S","length":64},{"name":"UserID","type":"S","length":256},
                  {"name":"ClusterID","type":"S","length":64},{"name":"AttributeID","type":"S","length":64}
                 ],
    "attributes":[{"name":"EndTime","type":"DT"},{"name":"EndDeviceType","type":"S","length":32},
                  {"name":"AttributeValue","type":"D"},{"name":"AttributeTotalValue","type":"L"}
                 ]
}
          

Electro Data Example

{
   "StartTime": "2018-12-01 00:00:00",
   "EndTime": "2018-12-01 00:00:00",
   "AttributeTotalValue": 12345,
   "EndDeviceMac": "mac_A",
   "GatewayID": "gateway_A",
   "UserID": "user_A",
   "ClusterID": "65452",
   "AttributeID": "attribute_A",
   "EndDeviceType": "type_A",
   "AttributeValue": 0
 }

Electro Script

function main(){
    var sid = '{SID}';
    var progkey = '{Progkey}';
    var service = '{Service}';

    var datetime = new Date(Omni.getDatetime('UTC'));
    datetime.setHours(datetime.getHours() - 1);
    datetime.setMinutes(0);
    datetime.setSeconds(0);

    var entries = new Array();
    /* add 60 data to Electro */
    for(var i = 0; i < 60 ; i++){
        entries.push(getEntries(datetime));
        datetime.setMinutes(datetime.getMinutes() + 1);
    }

    /* Request Object of PutEntries */
    var putReq = {
    	sid: sid,
    	progKey: progkey,
    	service: service,
    	body: JSON.stringify(buildPutEntries(entries))
    };
    Omni.putEntries(putReq);
}

var getEntries = function(time){
    var timestamp = time.getTime();
    var M = 999999999;
    var value = timestamp % M;
    return {
			    StartTime: dateFormat(time),
			    EndTime: dateFormat(time),
			    AttributeTotalValue: value,
			    EndDeviceMAC: 'mac_A',
			    GatewayID: 'gateway_A',
			    UserID: 'user_A',
			    ClusterID: '65452',
			    AttributeID: 'attribute_A',
			    EndDeviceType: 'type_A',
			    AttrivuteValue: '0'
			};
}

var buildPutEntries = function(entries){
	return {schemaname: "Electro",
			entries:entries};
};

var dateFormat = function(time){
    return time.getFullYear() + '-' + (time.getMonth() + 1) + '-' + time.getDate() + ' ' + timeChcck(time.getHours())  + ':' + timeChcck(time.getMinutes()) + ':' + timeChcck(time.getSeconds());
};

var timeChcck = function(value){
    if(value < 10)
        return '0' + value;
    return value;
};


Aggregate 行為

  • 建立一個 ElectroHour Schema。排程會每小時檢查 Electro 內裝置用電總量,再減去前 1 小時裝置用電總量,得到 1 小時之間的用電量,寫入 Schema 內。
    • 排程時間:每小時 15 分
    • Script 行為:
      • 執行時間為 12:15,則計算 11:00~12:00之間的裝置用電總量,資料佚失查詢時間為 K 分鐘。
      • 資料佚失查詢時間的意義為,當整點之用電總量不存在時,往區間內(夾擊)搜尋的分鐘數。
      • 僅取得 Electro.ClusterID 的值為 65452 的entry 來進行計算。
      • Script 行為:
        • 設 11:00 ~ 12:00 之間的用電量為 R,取 Electro 當日 12:00 為結束總用電量為 M,當日 11:00 為初始總用電量為 N,則R = M - N
        • 假設 11:00 初始總用電量不存在資料,資料佚失查詢時間為 10 分鐘,則取 11:00~11:10 之間最接近 11:00 且有資料的總用電量作為初始總用電量 N
        • 假設 12:00 結束總用電量不存在資料,資料佚失查詢時間為 10 分鐘,則取 11:50~12:00 之間最接近 12:00 且有資料的的總用電量作為結束總用電量 M
        • 若 M 或 N 任一項依上述方式無法取得,則 R 視為 null
        • 將 11:00~12:00 用電量以時間 11:00:00 填入 ElectroHour 資料表內


ElectroHour Schema

{
    "schemaname":"ElectroHour"
    "key_schema":[
                    {"name":"Time","type":"DT"},{"name":"EndDeviceMAC","type":"S","length":32},
                    {"name":"GatewayID","type":"S","length":64},{"name":"ClusterID","type":"S","length":64},
                    {"name":"AttributeID","type":"S","length":64}
                 ],
    "attributes":[
                    {"name":"AttributeValue_MAX","type":"D"},{"name":"AttributeValue_MIN","type":"D"},
                    {"name":"AttributeValue_AVG","type":"D"},{"name":"AttributeValue_COUNT","type":"UL"},
                    {"name":"AttributeValue_STDDEV_POP","type":"D"},{"name":"LastModified","type":"DT"}
                 ]
}
          

ElectroHour Data Example

{
   "Time": "2018-12-01 00:00:00",
   "LastModified": "2018-12-01 00:00:00",
   "AttributeValue_AVG": 4,
   "EndDeviceMac": "mac_A",
   "GatewayID": "gateway_A",
   "ClusterID": "65452",
   "AttributeID": "attribute_A",
   "AttributeValue_MAX": null,
   "AttributeValue_MIN": null,
   "AttributeValue_COUNT": 1,
   "AttributeValue_STDDEV_POP": null
 }

ElectroHour Script

function main(){
    var sid = '{SID}';
    var progkey = '{Progkey}';
    var service = '{Service}';
    var K = 10 * 60000; // 10 minutes

    var start = new Date(Omni.getDatetime('UTC'));
    start.setHours(start.getHours() - 1);
    start.setMinutes(0);
    start.setSeconds(0);

    var end = new Date(Omni.getDatetime('UTC'));
    end.setMinutes(0);
    end.setSeconds(0);

   /* Request Object of Query */
	var queryReq = {
		sid: sid,
		progKey: progkey,
		service: service,
		body: JSON.stringify(buildQueryBody(start, end))
	};

	var rs = Omni.queryEntries(queryReq);
    var entries = rs.entries;
	if(entries){
    	var first = entries[0];
    	var last = entries[entries.length - 1];

    	var firstTime = new Date(first['StartTime']);
    	var lastTime = new Date(last['StartTime']);

    	if((firstTime - start.getTime() <= K ) && (end.getTime() - lastTime <= K)){
    	    var electroValue = last['AttributeTotalValue'] - first['AttributeTotalValue'];

    	    /* Request Object of PutEntries */
        	var putReq = {
        		sid: sid,
        		progKey: progkey,
        		service: service,
        		body: JSON.stringify(buildPutEntries(start, electroValue))
        	};

        	Omni.putEntries(putReq);
    	}
	}

}

var buildQueryBody = function(initail, finish){
	return {schemaname:"Electro",
			keyconditions:[["ClusterID","=","65452"],["StartTime","BETWEEN",[dateFormat(initail),dateFormat(finish)]]]};
};

var buildPutEntries = function(time, value){
    var modified = dateFormat(new Date(Omni.getDatetime('UTC')));
	return {schemaname: "ElectroHour",
			entries: [{
			           Time: dateFormat(time),
			           LastModified: modified,
			           AttributeValue_AVG: value,
			           EndDeviceMAC:'mac_A',
			           GatewayID: 'gateway_A',
			           ClusterID: '65452',
			           AttributeID: 'attribute_A',
			           AttributeValue_MAX: 0,
			           AttributeValue_MIN: 0,
			           AttributeValue_COUNT: 1,
			           AttributeValue_STDDEV_POP: 0
			        }]
	       };
};

var dateFormat = function(time){
    return time.getFullYear() + '-' + (time.getMonth() + 1) + '-' + time.getDate() + ' ' + timeChcck(time.getHours())  + ':' + timeChcck(time.getMinutes()) + ':' + timeChcck(time.getSeconds());
};

var timeChcck = function(value){
    if(value < 10)
        return '0' + value;
    return value;
};