This topic provides a JavaScript script template and a sample JavaScript script that you can use to parse Thing Specification Language (TSL) data.

Script template

You can write a JavaScript script to parse TSL data based on the following JavaScript script template:

Note This template applies only to products whose Data Format parameter is set to Custom.
/**
 * Convert Alink data to data that can be recognized by a device when IoT Platform sends data to the device.
 * jsonObj: the input parameter. The value is a JSON object that cannot be empty. 
 * rawData: the output parameter. The value is a byte array that cannot be empty. 
 *
 */
function protocolToRawData(jsonObj) {
    return rawdata;
}

/**
 * Convert custom data of a device to Alink data when the device submits data to IoT Platform. 
 * rawData: the input parameter. The value is a byte array that cannot be empty. 
 * jsonObj: the output parameter. The value is a JSON object that cannot be empty. 
 */
function rawDataToProtocol(rawData) {
    return jsonObj;
}
            

Notes for script writing

  • Do not use global variables. Otherwise, results may be inconsistent.
  • The script processes data by using the two's complement operation. The complement range for the values in the range of [-128,127] is [0,255]. For example, the complement of -1 is 255 in decimal.
  • The rawDataToProtocol function parses the data that is submitted by devices. The input parameter of the function is an integer array. Use 0xFF for the bitwise AND operation to obtain the complement.
  • The protocolToRawData function parses the data that is sent by IoT Platform and returns the result in an array. Each element in the array must be an integer within a value range of [0,255].

Sample script

The following sample script is written based on the properties and the protocol that are defined in the Submit a script to parse TSL data topic:

For more information about the data types supported by TSL models, see Supported data types. After a device submits TSL property data or event data, IoT Platform generates a response whose data is in the Alink JSON format. Before IoT Platform sends the response to the device, IoT Platform uses the script to convert the format of the data to a format that can be recognized by the device. For more information about the Alink JSON format, see Device properties, events, and services.

var COMMAND_REPORT = 0x00; // Submit properties. 
var COMMAND_SET = 0x01; // Configure properties. 
var COMMAND_REPORT_REPLY = 0x02; // The data submission result. 
var COMMAND_SET_REPLY = 0x03; // The property setting result. 
var COMMAD_UNKOWN = 0xff;    // Unknown commands. 
var ALINK_PROP_REPORT_METHOD = 'thing.event.property.post'; // The topic that is used by devices to submit property data to IoT Platform. 
var ALINK_PROP_SET_METHOD = 'thing.service.property.set'; // The topic that is used by IoT Platform to send a property setting command to devices. 
var ALINK_PROP_SET_REPLY_METHOD = 'thing.service.property.set'; // The topic that is used by devices to submit the property setting results to IoT Platform. 
var SELF_DEFINE_TOPIC_UPDATE_FLAG = '/user/update'  // Define the following custom topic: /user/update. 
var SELF_DEFINE_TOPIC_ERROR_FLAG = '/user/update/error' // Define the following custom topic: /user/update/error. 
/*
Sample data:
Submit property data
Input:
    0x000000000100320100000000
Output:
    {"method":"thing.event.property.post","id":"1","params":{"prop_float":0,"prop_int16":50,"prop_bool":1},"version":"1.0"}

Result of property setting
Input:
    0x0300223344c8
Output:
    {"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]; // command
    if (fHead == COMMAND_REPORT) {
        jsonMap['method'] = ALINK_PROP_REPORT_METHOD; // The topic that is used to submit properties. Data format: Alink JSON. 
        jsonMap['version'] = '1.0'; // The version of the protocol. This value is fixed. Data format: Alink JSON. 
        jsonMap['id'] = '' + dataView.getInt32(1); // The ID of the request. Data format: Alink JSON. 
        var params = {};
        params['prop_int16'] = dataView.getInt16(5); // The value of the prop_int16 property of the product. 
        params['prop_bool'] = uint8Array[7]; // The value of the prop_bool property of the product. 
        params['prop_float'] = dataView.getFloat32(8); // The value of the prop_float property of the product. 
        jsonMap['params'] = params; // The params field. Data format: Alink JSON. 
    } else if(fHead == COMMAND_SET_REPLY) {
        jsonMap['version'] = '1.0'; // The version of the protocol. This value is fixed. Data format: Alink JSON. 
        jsonMap['id'] = '' + dataView.getInt32(1); // The ID of the request. Data format: Alink JSON. 
        jsonMap['code'] = ''+ dataView.getUint8(5);
        jsonMap['data'] = {};
    }

    return jsonMap;
}
/*
Sample data:
Send downstream commands to configure device properties
Input:
    {"method":"thing.service.property.set","id":"12345","version":"1.0","params":{"prop_float":123.452, "prop_int16":333, "prop_bool":1}}
Output:
    0x0100003039014d0142f6e76d

Result of data submission
Input:
    {"method":"thing.event.property.post","id":"12345","version":"1.0","code":200,"data":{}}
Output:
    0x0200003039c8
*/
function protocolToRawData(json) {
    var method = json['method'];
    var id = json['id'];
    var version = json['version'];
    var payloadArray = [];
    if (method == ALINK_PROP_SET_METHOD) // Configure properties. 
    {
        var params = json['params'];
        var prop_float = params['prop_float'];
        var prop_int16 = params['prop_int16'];
        var prop_bool = params['prop_bool'];
        // Concatenate raw data 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 of the request. Data format: 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. 
        var code = json['code'];
        payloadArray = payloadArray.concat(buffer_uint8(COMMAND_REPORT_REPLY)); // The command field. 
        payloadArray = payloadArray.concat(buffer_int32(parseInt(id))); // The ID of the request. Data format: Alink JSON. 
        payloadArray = payloadArray.concat(buffer_uint8(code));
    } else { // Unknown commands. These 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 of the request. Data format: Alink JSON. 
        payloadArray = payloadArray.concat(buffer_uint8(code));
    }
    return payloadArray;
}

/*
  Sample data
  Use the following custom topic to submit data:
     /user/update. 
  Input:
     topic:/{productKey}/{deviceName}/user/update
     bytes: 0x000000000100320100000000
  Output:
  {
     "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 (var i = 0; i < bytes.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 code describes 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);
}