This article provides a script template and a sample script in PHP to parse Thing Specification Language (TSL) data.

Script template

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

Note This template applies only to products whose Data Format parameter is set to Custom.
<?php
/**
 * Convert Alink data to data that can be recognized by a device when IoT Platform sends downstream data. 
 * $jsonObj: the input parameter. The value is a JSON object that indicates an association array. 
 * $rawData: the output parameter. The value is an array of integers within a value range of [0,255]. Array elements cannot be empty. 
 */
function protocolToRawData($jsonObj)
{
    $rawData = array();
    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 an array of integers. 
 * $jsonObj: the output parameter. The value is a JSON object that indicates an association array. The value of each key must be a string. However, the string cannot consist of only digits such as 10. Key values cannot be empty. 
 */
function rawDataToProtocol($rawData)
{
    $jsonObj = array();
    return $jsonObj;
}

/**
 * Convert the data that is sent by a device to a custom topic to JSON data when the device submits data to IoT Platform. 
 * $topic: the input parameter that specifies the topic to which the device sends messages. The value is a string. 
 * $rawData: the input parameter. The value is an array of integers. 
 * $jsonObj: the output parameter. The value is a JSON object that indicates an association array. The value of each key must be a string. However, the string cannot consist of only digits such as 10. Key values cannot be empty. 
 */
function transformPayload($topic, $rawData)
{
    $jsonObj = array();
    return $jsonObj;
}

Notes for script writing

  • Do not use global variables or static variables. Otherwise, results may be inconsistent.
  • The script is used to process data by using the two's complement operation. The complement range for 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 returned result is an association array. Each key value must contain non-array characters. For example, if a key value is 10, the PHP array retrieves the integer 10.
  • The protocolToRawData function parses downstream data sent by IoT Platform and returns an array. The array must be a common PHP array. Each element in the array must be an integer within a value range of [0,255].
  • The transformPayload function parses data that is sent to custom topics. The input parameter of the function is an integer array. Use 0xFF for the bitwise AND operation to obtain the complement. The returned result is an association array. Each key value must contain non-array characters. For example, if a key value is 10, the PHP array retrieves the integer 10.
  • The PHP runtime environment is significantly strict with exception handling. If an error occurs, the subsequent logic is not implemented. To ensure code robustness, you must capture and process errors.

Sample script

The following sample script is written based on the properties and protocol that are defined in the Example for parsing TSL data article:

For more information about the data types supported by TSL models, see Supported data types.

<? php
/*
Sample data
Submit device data
Input parameters:
    0x0000000001003201
Output result:
    {"method":"thing.event.property.post","id":"1","params":{"prop_int16":50,"prop_bool":1},"version":"1.0"}

Response after property configurations
Input parameters:
    0x0300223344c8
Output result:
    {"code":"200","id":"2241348","version":"1.0"}
*/
function rawDataToProtocol($bytes)
{
    $data = [];
    $length = count($bytes);
    for ($i = 0; $i < $length; $i++) {
        $data[$i] = $bytes[$i] & 0xff;
    }

    $jsonMap = [];
    $fHead = $data[0]; //The command field.
    if ($fHead == 0x00) {
        $jsonMap['method'] = 'thing.event.property.post '; //The topic that is used to submit properties. Data format: ALink JSON.
        jsonMap['version'] = '1.0'; //The version of the protocol. This field is fixed. Data format: ALink JSON.
        $jsonMap['id'] = '' . getInt32($data, 1); //The ID of the request. Data format: ALink JSON.
        $params = [];
        $params['prop_int16'] = getInt16($data, 5); //The value of the prop_int16 property of the product.
        params['prop_bool'] = $data[7]; //The value of the prop_bool property of the product.
        jsonMap['params'] = params; //The params field. Data format: ALink JSON.
    } else if ($fHead == 0x03) {
        jsonMap['version'] = '1.0'; //The version of the protocol. This field is fixed. Data format: ALink JSON.
        $jsonMap['id'] = '' . getInt32($data, 1); //The ID of the request. Data format: ALink JSON.
        $jsonMap['code'] = getInt8($data, 5);
    }

    return $jsonMap;
}

/*
Sample data
Configure properties
Input parameters:
    {"method":"thing.service.property.set","id":"12345","version":"1.0","params":{"prop_int16":333, "prop_bool":1}}
Output result:
    0x013039014d01

Response after data submission
Input data:
    {"method":"thing.event.property.post","id":"12345","version":"1.0","code":200,"data":{}}
Output result:
    0x023039c8
*/
function protocolToRawData($json)
{
    $method = $json['method'];
    $id = $json['id'];
    $version = $json['version'];
    $payloadArray = [];
    if ($method == 'thing.service.property.set ') //Configure properties.
    {
        $params = $json['params'];
        $prop_int16 = $params['prop_int16'];
        $prop_bool = $params['prop_bool'];
        //Raw data is concatenated based on the custom protocol format.
        $payloadArray = concat($payloadArray, hexStringToByteArray(toHex(0x01)));//The command field.
        $payloadArray = concat($payloadArray, hexStringToByteArray(toHex(intval($id)))); //The ID of the request. Data format: ALink JSON.
        $payloadArray = concat($payloadArray, hexStringToByteArray(toHex($prop_int16))); //The value of the prop_int16 property.
        $payloadArray = concat($payloadArray, hexStringToByteArray(toHex($prop_bool))); //The value of the prop_bool property.
    } else if ($method == 'thing.event.property.post ') { //The response after data submission.
        $code = $json['code'];
        $payloadArray = concat($payloadArray, hexStringToByteArray(toHex(0x02))); //The command field.
        $payloadArray = concat($payloadArray, hexStringToByteArray(toHex(intval($id)))); //The ID of the request. Data format: ALink JSON.
        $payloadArray = concat($payloadArray, hexStringToByteArray(toHex($code)));
    } Else {//Unknown commands. Certain commands are not processed.
        $code = $json['code'];
        $payloadArray = concat($payloadArray, hexStringToByteArray(toHex(0xff))); //The command field.
        $payloadArray = concat($payloadArray, hexStringToByteArray(toHex(intval($id)))); //The ID of the request. Data format: ALink JSON.
        $payloadArray = concat($payloadArray, hexStringToByteArray(toHex($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)
{
    $data = array();
    $length = count($bytes);
    for ($i = 0; $i < $length; $i++) {
        $data[$i] = $bytes[$i] & 0xff;
    }

    $jsonMap = array();

    if (strpos($topic, '/user/update/error') ! == false) {
        $jsonMap['topic'] = $topic;
        $jsonMap['errorCode'] = getInt8($data, 0);
    } else if (strpos($topic, '/user/update') ! == false) {
        $jsonMap['topic'] = $topic;
        $jsonMap['prop_int16'] = getInt16($data, 5);
        $jsonMap['prop_bool'] = $data[7];
    }

    return $jsonMap;
}

function getInt32($bytes, $index)
{
    $array = array($bytes[$index], $bytes[$index + 1], $bytes[$index + 2], $bytes[$index + 3]);

    return hexdec(byteArrayToHexString($array));
}

function getInt16($bytes, $index)
{
    $array = array($bytes[$index], $bytes[$index + 1]);

    return hexdec(byteArrayToHexString($array));
}

function getInt8($bytes, $index)
{
    $array = array($bytes[$index]);
    return hexdec(byteArrayToHexString($array));
}

function byteArrayToHexString($data)
{
    $hexStr = '';
    for ($i = 0; $i < count($data); $i++) {
        $hexValue = dechex($data[$i]);

        $tempHexStr = strval($hexValue);

        if (strlen($tempHexStr) === 1) {
            $hexStr = $hexStr . '0' . $tempHexStr;
        } else {
            $hexStr = $hexStr . $tempHexStr;
        }
    }

    return $hexStr;
}

function hexStringToByteArray($hex)
{
    $result = array();
    $index = 0;
    for ($i = 0; $i < strlen($hex) - 1; $i += 2) {
        $result[$index++] = hexdec($hex[$i] . $hex[$i + 1]);
    }
    return $result;
}


function concat($array, $data)
{
    return array_merge($array, $data);
}

function toHex($data)
{
    $var = dechex($data);
    $length = strlen($var);
    if ($length % 2 == 1) {
        $var = '0' . $var;
    }
    return $var;
}