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

Script template

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

Note This script template applies only to products whose Data Type parameter is set to Custom.
<?php
/**
 * Convert Alink JSON 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 JSON 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 messages that are 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 messages sent by IoT Platform, and then 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 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.

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

Result of property setting
Input:
    0x0300223344c8
Output:
    {"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 value 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 value 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:
Property setting
Input:
    {"method":"thing.service.property.set","id":"12345","version":"1.0","params":{"prop_int16":333, "prop_bool":1}}
Output:
    0x013039014d01

Result of device data submission:
Input:
    {"method":"thing.event.property.post","id":"12345","version":"1.0","code":200,"data":{}}
Output:
    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'];
        // Concatenate raw data 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. 
        $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. The commands are not run. 
        $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:
  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)
{
    $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;
}