Script template
Script template has a simple high-level structure that can be extended to map a specific device make and model for use within IMPACT IoT.
This code is a template to begin the development of a new codec script. For more information, see Creating Payload mapping script.
The following script provides a good template for understanding and creating codec scripts.
Codec script template:
var utils = Java.type('com.nokia.transformation.script.model.TransformUtil');
function LoraPulseCodec() //This example is for a LORA device, this is only an example and can be named as needed.
///////////////////////////////
// Encoder function, this is the downlink message handling
this.encode = function (impactRequest) {
// 1. get the request details from input
var request = getImpactRequestAsJson(impactRequest);
// 2. handle the request, to decide what type of request, it can be READ or WRITE
// EXECUTE, OBSERVE or DELETE operations triggered from either an API or using the Console
var resBuffer; // typeof resBuffer is Int8Array
var unack = true; // true means this request has no response/ack from the device
switch (request.type) {
case "READ":
// IMPACT IoT sends a downlink message to a device triggered from an API or via the Console, which reads the information of a specific resource, which then responds either right away for synchronous or with a notification for asynchronous.
unack = false; // device will response for READ, hence setting unack = false
// handle read request and set resBuffer
break;
case "WRITE":
// IMPACT IoT sends a write JSON request to the devices. When the write request is sent, the device responds with the success message.
// handle write request and set resBuffer
break;
case "EXECUTE":
//If a device has an executable resource, then the IMPACT IoT may send an execute command JSON using the POST method to /devices.
//This is also triggered from an API or via the Console.
//If any one of the Devices fails to perform the execute operation, then the entire operation is considered a failure, and appropriate status codes can be sent.
// handle execute request and set resBuffer
break;
case "OBSERVE":
// When a resource on a device needs to be monitored, IMPACT IoT sends a JSON object for the Adapter to start monitoring the resource.
// This is due to IMPACT IoT establishing a subscription request, either from API or using Monitoring.
// The content is sent as POST /devices from IMPACT IoT to the adapter.
case "DELETE":
// IMPACT IoT sends a delete resource request, which allows the client application to delete a specific resource of a given endpoint device or gateway.
default:
// throw error if a request type is not supported
throw new Error(`request type ${request.type} not supported by the lora pulse device`);
}
return utils.createBinaryResponse(resBuffer, _map, unack);
}
///////////////////////////////
// Decoder Function
this.decode = function (decodeCtx) {
var bytes = decodeCtx.getUplinkMessage();
var resources = [];
// decode the input and extract all resource information available
// return as json
return formImpactResponseFromJson(decodeCtx, resources, (result == success));
}
}
var codec = new LoraPulseCodec();
(codec);
For more information on the Lora pulse codec script, see the section lora_cyble_b64_codec.js script and lora_pulse_hex_codec.js script.
The util functions for the codec can be defined as
below:
var utils = Java.type('com.nokia.transformation.script.model.TransformUtil');
// utility functions
//
function getImpactRequestAsJson(impactRequest) {
var request = {};
request.type = utils.getRequestType(impactRequest);
request.url = impactRequest.getResource();//The resource path name or URI is extracted
if (!request.type || !request.url) {
throw new Error(`request type and resource URL are required in the input`);
}
var resourceItems = request.url.split("/");
request.resource = resourceItems[resourceItems.length - 1];
if (impactRequest.getValue) {
request.resourceValue = impactRequest.getValue();
}
console.log("input to encoder", request);
return request;
}
function formImpactResponseFromJson(decodeCtx, resources, success=true) {
if(decodeCtx.getRequest() != null) {
var corrId = decodeCtx.getRequest().getCorrelatorId();
var resp = {responseCode: success? 0: 1, requestStatus: 0, response: [], correlatorId: corrId};
var resourceObj = {"device/0/endPointClientName":client.getEndpoint()};
resources.forEach(resource => {
resourceObj[resource.name] = resource.value;
});
resp.response.push(resourceObj);
console.log('sending response ' + JSON.stringify(resp));
return utils.createJsonResponse(JSON.stringify(resp));
} else {
var resp = {details: {"device/0/endPointClientName": client.getEndpoint()}};
resources.forEach(resource => {
resp.details[resource.name] = resource.value;
});
console.log('sending notification ' + JSON.stringify(resp));
return utils.createJsonResponse(JSON.stringify(resp));
}
}
function buf2hex(buffer) { // buffer is an ArrayBuffer
return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
}
// Conversion from string to character binary is commonly needed and this feature does this
// simple function
function bytes2String(bytes, offset=0) {
if (offset < 0) { offset=0; }
var result = "";
for (var i = offset; i < bytes.length; i++) {
result += String.fromCharCode(bytes[i]);
}
return result;
}
// Conversion from string to character binary is commonly needed and this feature does this
// simple function
function string2Bytes(str, offset=0) {
if (offset < 0) { offset=0; }
var bytes;
const strLen = str? str.length : 0;
bytes = new Array(strLen + offset);
for (var i = 0; i < strLen; i++) {
bytes[offset+i] = str.charCodeAt(i);
}
return bytes;
}
// Simple function to determine if a bit is set in a particular byte.
function isBitSet(byte, bitNum) {
return ((byte >> bitNum) & 0xFF) == 0x01;
}
For more information on the Lora common utility codec scripts, see the section codec_util.js script.