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

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
/**
 * Call the protocolToRawData function to convert Alink data to data that can be recognized by a device when IoT Platform sends data to the device.
 * $jsonObj: an input parameter. The value is a JSON object that indicates an association array.
 * $rawData: an output parameter. The value is an array of integers within a value range of [0,255] and cannot be left empty.
 */
function protocolToRawData($jsonObj)
{
    $rawData = array();
    return $rawData;
}

/**
 * Call the rawDataToProtocol function to convert custom data of a device to Alink data when the device reports data to IoT Platform.
 * $rawData: an input parameter. The value is an array of integers.
 * $jsonObj: an 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 left empty.
 */
function rawDataToProtocol($rawData)
{
    $jsonObj = array();
    return $jsonObj;
}

/**
 * Call the transformPayload function to convert the data that is sent by a device to a custom topic to JSON data when the device reports data to IoT Platform.
 * $topic: an input parameter that specifies the topic to which the device sends messages. The value is a string.
 * $rawData: an input parameter. The value is an array of integers.
 * $jsonObj: an 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 left 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 is used to parse the data that is reported by devices. The input 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 the data that is sent by IoT Platform and returns the result in an array. The array must be a regular PHP array. Each element in the array must be an integer within a value range of [0,255].
  • The input of the transformPayload 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, an exception is thrown and subsequent code is not run. To ensure code robustness, you must capture and process exceptions.

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:

<? 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;
}