This topic provides the script template and a sample script for parsing Thing Specification Language (TSL) data in JavaScript.

Script template

You can write a data parsing script in JavaScript based on the following script template.

Note This template applies only to products whose Data Format is Custom.
/**
 * Converts Alink data to a data format that can be recognized by devices before data is sent to devices from IoT Platform.
 * Input: A jsonObj object. It cannot be empty.
 * Output: A rawData byte[] array. It cannot be empty.
 *
 */
function protocolToRawData(jsonObj) {
    return rawdata;
}

/**
 * Converts custom data from devices to Alink protocol data. This function is called when devices report data to IoT Platform.
 * Input: A rawData byte [] array. It cannot be empty.
 * Output: A jsonObj dictionary. It cannot be empty.
 */
function rawDataToProtocol(rawData) {
    return jsonObj;
}
			

Additional considerations

  • Do not use global variables. Otherwise, the execution results may be inconsistent.
  • In the script, data is processed by using the two's complement operation. The complement for values in the range of [-128,127] is [0,255]. For example, the complement of-1 is 255 in decimal.
  • The input of the rawDataToProtocol function is an integer array. Use 0xFF for the bitwise AND operation to obtain the complement.
  • The protocolToRawData function parses the data sent by IoT Platform and returns the result in an array. The array elements are integers ranging from 0 to 255.

Example

The following script is based on the properties and protocol defined in Example for parsing TSL data.

var COMMAND_REPORT = 0x00 // Property data reported by devices.
var COMMAND_SET = 0x01 // Property setting command data from the cloud.
var COMMAND_REPORT_REPLY = 0x02  // Response data for devices reporting properties.
var COMMAND_SET_REPLY = 0x03  // Response data for setting device properties.
var Command_unkown = 0xff  // Unknown commands.
var ALINK_PROP_REPORT_METHOD = 'thing.event.property.post' // The topic for devices to upload property data to the cloud.
var ALINK_PROP_SET_METHOD = 'thing.service.property.set'  // The topic for IoT Platform to send a property control command to devices.
var ALINK_PROP_SET_REPLY_METHOD = 'thing.service.property.set'  // The topic for devices to report the property setting results to IoT Platform.
var SELF_DEFINE_TOPIC_UPDATE_FLAG = '/user/update'  // Custom topic: /user/update.
var SELF_DEFINE_TOPIC_ERROR_FLAG = '/user/update/error' // Custom topic: /user/update/error.
/*
Sample data:
The device reports property data.
Input parameters:
    0x000000000100320100000000
Output result:
    {"method":"thing.event.property.post","id":"1","params":{"prop_float":0,"prop_int16":50,"prop_bool":1},"version":"1.0"}

The device responds after setting properties.
Input parameters:
    0x0300223344c8
Output result:
    {"code":"200","data":{},"id":"2241348","version":"1.0"}
*/
function rawDataToProtocol(bytes) {
    var uint8Array = new Uint8Array(bytes.length);
    for (var i = 0; i < bytes.length; i++) {
        uint8Array[i] = bytes[i] & 0xff;
    }
    var dataView = new DataView(uint8Array.buffer, 0);
    var jsonMap = new Object();
    var fHead = uint8Array[0]; // The command prefix.
    if (fHead == COMMAND_REPORT) {
        jsonMap['method'] = ALINK_PROP_REPORT_METHOD; // The topic for reporting properties in the ALink JSON.
        jsonMap['version'] = '1.0'; // The fixed protocol version in the ALink JSON.
        jsonMap['id'] = ''+ dataView.getInt32(1); // The request ID in the ALink JSON.
        var params = {};
        params['prop_int16'] = dataView.getInt16(5); // The value of the prop_int16 property.
        params['prop_bool'] = uint8Array[7]; // The value of the prop_bool property.
        params['prop_float'] = dataView.getFloat32(8); // The value of the prop_float property.
        jsonMap['params'] = params; // The params field in the ALink JSON.
    } else if(fHead == COMMAND_SET_REPLY) {
        jsonMap['version'] = '1.0'; // The fixed protocol version in the ALink JSON.
        jsonMap['id'] = ''+ dataView.getInt32(1); // The request ID in the ALink JSON.
        jsonMap['code'] = ''+ dataView.getUint8(5);
        jsonMap['data'] = {};
    }

    return jsonMap;
}
/*
Sample data:
IoT Platform pushes a command for setting properties to the device.
Input parameters:
    {"method":"thing.service.property.set","id":"12345","version":"1.0","params":{"prop_float":123.452, "prop_int16":333, "prop_bool":1}}
Output result:
    0x0100003039014d0142f6e76d

IoT Platform responds after the device reports properties.
Input data:
    {"method":"thing.event.property.post","id":"12345","version":"1.0","code":200,"data":{}}
Output result:
    0x0200003039c8
*/
function protocolToRawData(json) {
    var method = json['method'];
    var id = json['id'];
    var version = json['version'];
    var payloadArray = [];
    if (method == ALINK_PROP_SET_METHOD) // Sets properties
    {
        var params = json['params'];
        var prop_float = params['prop_float'];
        var prop_int16 = params['prop_int16'];
        var prop_bool = params['prop_bool'];
        // Raw data is concatenated based on the custom protocol format.
        payloadArray = payloadArray.concat(buffer_uint8(COMMAND_SET)); // The command field.
        payloadArray = payloadArray.concat(buffer_int32(parseInt(id))); // The id in the ALink JSON.
        payloadArray = payloadArray.concat(buffer_int16(prop_int16)); // The value of the prop_int16 property.
        payloadArray = payloadArray.concat(buffer_uint8(prop_bool)); // The value of the prop_bool property.
        payloadArray = payloadArray.concat(buffer_float32(prop_float)); // The value of the prop_float property.
    } else if (method == ALINK_PROP_REPORT_METHOD) {// The response of the reported data.
        var code = json['code'];
        payloadArray = payloadArray.concat(buffer_uint8(COMMAND_SET)); // The command field.
        payloadArray = payloadArray.concat(buffer_int32(parseInt(id))); // The id in the ALink JSON.
        payloadArray = payloadArray.concat(buffer_uint8(code));
    } Else {// Unknown commands. Some commands are not processed.
        var code = json['code'];
        payloadArray = payloadArray.concat(buffer_uint8(COMMAND_UNKOWN)); // The command field.
        payloadArray = payloadArray.concat(buffer_int32(parseInt(id))); // The id in the ALink JSON.
        payloadArray = payloadArray.concat(buffer_uint8(code));
    }
    return payloadArray;
}

/*
  Sample data
  Custom topic for reporting data: /user/update
  Input parameters: 
     topic: /{productKey}/{deviceName}/user/update
     bytes: 0x000000000100320100000000
  Output parameters:
  {
     "prop_float": 0,
     "prop_int16": 50,
     "prop_bool": 1,
     "topic": "/{productKey}/{deviceName}/user/update"
   }
 */
function transformPayload(topic, bytes) {
    var uint8Array = new Uint8Array(bytes.length);
    for (int i = 0; i < edges.length; i++) {
        uint8Array[i] = bytes[i] & 0xff;
    }
    var dataView = new DataView(uint8Array.buffer, 0);
    var jsonMap = {};

    if(topic.includes(SELF_DEFINE_TOPIC_ERROR_FLAG)) {
        jsonMap['topic'] = topic;
        jsonMap['errorCode'] = dataView.getInt8(0)
    } else if (topic.includes(SELF_DEFINE_TOPIC_UPDATE_FLAG)) {
        jsonMap['topic'] = topic;
        jsonMap['prop_int16'] = dataView.getInt16(5);
        jsonMap['prop_bool'] = uint8Array[7];
        jsonMap['prop_float'] = dataView.getFloat32(8);
    }

    return jsonMap;
}

// The following are some helper functions.
function buffer_uint8(value) {
    var uint8Array = new Uint8Array(1);
    var dv = new DataView(uint8Array.buffer, 0);
    dv.setUint8(0, value);
    return [].slice.call(uint8Array);
}
function buffer_int16(value) {
    var uint8Array = new Uint8Array(2);
    var dv = new DataView(uint8Array.buffer, 0);
    dv.setInt16(0, value);
    return [].slice.call(uint8Array);
}
function buffer_int32(value) {
    var uint8Array = new Uint8Array(4);
    var dv = new DataView(uint8Array.buffer, 0);
    dv.setInt32(0, value);
    return [].slice.call(uint8Array);
}
function buffer_float32(value) {
    var uint8Array = new Uint8Array(4);
    var dv = new DataView(uint8Array.buffer, 0);
    dv.setFloat32(0, value);
    return [].slice.call(uint8Array);
}