TSL model programming

Updated at:

A Thing Specification Language (TSL) model is a data model that you define for a product in Alibaba Cloud IoT Platform. The model describes product features using properties, services, and events. When you develop a device, you must program its features according to the TSL model.

Get the Link SDK

For more information about how to download different versions of the Link SDK, see Obtain SDKs. This topic uses Link SDK v3.2.0 as an example to describe how to program device properties, services, and events.

Important
  • In a Linux environment, you must modify the default device authentication information in the wrappers/os/ubuntu/HAL_OS_linux.c file. This lets you use the identity information of the device that you created in the IoT Platform console.
  • The src/dev_model/examples folder contains a TSL model description file named model_for_example.json. You must replace the `ProductKey` value in the file with the ProductKey of your product. Then, you can import the TSL model file to the product definition in IoT Platform. This lets you quickly test TSL model-based programming using the sample code.

Device properties

  • Report properties
    You can call the IOT_Linkkit_Report() function to report properties. When you report properties, you must marshal them into the JSON format defined by IoT Platform. The user_post_property function in the sample code shows how to use IOT_Linkkit_Report to report properties. For more information about how to report anomalies, see ./src/dev_model/examples/linkkit_example_solo.c.
    Note
    • property_payload = "{\"Counter\":1}" marshals the property into a JSON object.
    • To request an acknowledgement from IoT Platform for a property or event report, set the IOTX_IOCTL_RECV_EVENT_REPLY option using IOT_Ioctl.
    void user_post_property(void)
    {
        static int cnt = 0;
        int res = 0;
    
        char property_payload[30] = {0};
        HAL_Snprintf(property_payload, sizeof(property_payload), "{\"Counter\": %d}", cnt++);
    
        res = IOT_Linkkit_Report(EXAMPLE_MASTER_DEVID, ITM_MSG_POST_PROPERTY,
                                (unsigned char *)property_payload, strlen(property_payload));
    
        EXAMPLE_TRACE("Post Property Message ID: %d", res);
    }
  • Set properties
    The sample code in the user_property_set_event_handler callback function retrieves the property values set by IoT Platform. The function then sends the received data back to IoT Platform without modification to update the device property values in IoT Platform. You must process the received property values in this function.
    Note This callback function is registered for the ITE_PROPERTY_SET event using IOT_RegisterCallback during the sample initialization.
    static int user_property_set_event_handler(const int devid, const char *request, const int request_len)
    {
        int res = 0;
        user_example_ctx_t *user_example_ctx = user_example_get_ctx();
        EXAMPLE_TRACE("Property Set Received, Devid: %d, Request: %s", devid, request);
    
        res = IOT_Linkkit_Report(user_example_ctx->master_devid, ITM_MSG_POST_PROPERTY,
                                (unsigned char *)request, request_len);
        EXAMPLE_TRACE("Post Property Message ID: %d", res);
    
        return 0;
    }

Device services

In the sample program, the following callback function is triggered when the device receives a service invocation request for a synchronous or asynchronous service:

Note
  • You must dynamically allocate memory to store the service acknowledgement data and return the data to the SDK through the `response` parameter. The SDK releases the memory that `response` points to after it sends the acknowledgement data.
  • If the service has no output parameters, *response must point to the memory that stores the JSON object {}. *response cannot be a null pointer.
static int user_service_request_event_handler(const int devid, const char *serviceid, const int serviceid_len,
                                            const char *request, const int request_len,
                                            char **response, int *response_len){    int add_result = 0;
    cJSON *root = NULL, *item_number_a = NULL, *item_number_b = NULL;
    const char *response_fmt = "{\"Result\": %d}";

    EXAMPLE_TRACE("Service Request Received, Service ID: %.*s, Payload: %s", serviceid_len, serviceid, request);

    /* Parse Root */
    root = cJSON_Parse(request);
    if (root == NULL || !cJSON_IsObject(root)) {
        EXAMPLE_TRACE("JSON Parse Error");
        return -1;
    }

    if (strlen("Operation_Service") == serviceid_len && memcmp("Operation_Service", serviceid, serviceid_len) == 0) {
        /* Parse NumberA */
        item_number_a = cJSON_GetObjectItem(root, "NumberA");
        if (item_number_a == NULL || !cJSON_IsNumber(item_number_a)) {
            cJSON_Delete(root);
            return -1;
        }
        EXAMPLE_TRACE("NumberA = %d", item_number_a->valueint);

        /* Parse NumberB */
        item_number_b = cJSON_GetObjectItem(root, "NumberB");
        if (item_number_b == NULL || !cJSON_IsNumber(item_number_b)) {
            cJSON_Delete(root);
            return -1;
        }
        EXAMPLE_TRACE("NumberB = %d", item_number_b->valueint);

        add_result = item_number_a->valueint + item_number_b->valueint;

        /* Service acknowledgement data. The data length is passed to the SDK through the response and response_len parameters. */
        *response_len = strlen(response_fmt) + 10 + 1;
        *response = (char *)HAL_Malloc(*response_len);
        if (*response == NULL) {
            EXAMPLE_TRACE("Memory Not Enough");
            return -1;
        }
        memset(*response, 0, *response_len);
        HAL_Snprintf(*response, *response_len, response_fmt, add_result);
        *response_len = strlen(*response);
    }

    cJSON_Delete(root);
    return 0;
}

Device events

This example reports events using the IOT_Linkkit_TriggerEvent API and also demonstrates how to use the IOT_Linkkit_Report API. For more information about reporting abnormal events, see the ./src/dev_model/examples/linkkit_example_solo.c file.

void user_post_event(void){
    int res = 0;
    char *event_id = "HardwareError";
    char *event_payload = "{\"ErrorCode\": 0}";

    res = IOT_Linkkit_TriggerEvent(EXAMPLE_MASTER_DEVID, event_id, strlen(event_id),
                                event_payload, strlen(event_payload));
    EXAMPLE_TRACE("Post Event Message ID: %d", res);
}

Format and examples of reported messages

When you report properties, the property IDs and values are placed in the payload of IOT_Linkkit_Report() in JSON format. The following examples show the format for different data types and for multiple properties:

/* Integer data */
char *payload = "{\"Brightness\":50}";

/* Report floating-point data */
char *payload = "{\"Temperature\":11.11}";

/* Report enumeration data */
char *payload = "{\"WorkMode\":2}";

/* Report Boolean data. In a TSL model definition, a Boolean type is an integer with a value of 0 or 1. This is different from the integer type in JSON format. */
char  *payload = "{\"LightSwitch\":1}";

/* Report string data */
char *payload = "{\"Description\":\"Amazing Example\"}";

/* Report time data. In a TSL model definition, the time type is a string. */
char *payload = "{\"Timestamp\":\"1252512000\"}";

/* Report a complex property type. In a TSL model definition, a complex property type is a JSON object. */
char *payload = "{\"RGBColor\":{\"Red\":11,\"Green\":22,\"Blue\":33}}";

/* Report multiple properties. To report all properties of the preceding data types, place them in a single JSON object. */
char *payload = "{\"Brightness\":50,\"Temperature\":11.11,\"WorkMode\":2,\"LightSwitch\":1,\"Description\":\"Amazing Example\",\"Timestamp\":\"1252512000\",\"RGBColor:{\"Red\":11,\"Green\":22,\"Blue\":33}\"}";

/* After the property payload is ready, use the following interface to report it. */
IOT_Linkkit_Report(devid, ITM_MSG_POST_PROPERTY, payload, strlen(payload));           

The main difference between reporting an event and reporting a property is that for an event, the event ID must be specified in the eventid parameter of the IOT_Linkkit_TriggerEvent() function. The event content, which consists of the output parameters defined in the TSL model, is reported in the same format as properties. The following examples show how to report events:

/* The event ID is Error. Its output parameter ID is ErrorCode, and the data type is enumeration. */
char *eventid = "Error";
char *payload = "{\"ErrorCode\":0}";

/* The event ID is HeartbeatNotification. It has two output parameters. The first is the Boolean parameter ParkingState, and the second is the floating-point parameter VoltageValue. */
char *eventid = "HeartbeatNotification";
char *payload = "{\"ParkingState\":1,\"VoltageValue\":3.0}";

/* After the event payload is ready, use the following interface to report it. */
IOT_Linkkit_TriggerEvent(devid, event_id, strlen(event_id), payload, strlen(payload));

/* As shown in the preceding examples, when an event has multiple output parameters, the payload format is the same as that for reporting multiple properties. */

Send and receive data over MQTT topics

Although the TSL model programming APIs do not expose the pClient parameter that the IOT_MQTT_XXX() MQTT programming interfaces require, you can still send and receive data over MQTT topics when you use the TSL model programming APIs. The following sections describe the interfaces and provide examples of how to send and receive MQTT data.
  • MQTT data sending and receiving interfaces:
    Note For the following interfaces, you can set the first parameter to 0. This indicates that the default MQTT channel is used to send and receive data.
    • IOT_MQTT_Construct
    • IOT_MQTT_Destroy
    • IOT_MQTT_Yield
    • IOT_MQTT_CheckStateNormal
    • IOT_MQTT_Subscribe
    • IOT_MQTT_Unsubscribe
    • IOT_MQTT_Publish
    • IOT_MQTT_Subscribe_Sync
    • IOT_MQTT_Publish_Simple
  • Examples:
    • Subscribe to a topic

      To subscribe to a topic in a code segment that uses TSL model programming APIs, use the following interface:

      IOT_MQTT_Subscribe(0, topic_request, IOTX_MQTT_QOS0, topic_callback, topic_context);
    • Report data

      To publish data to a topic (report data) in a code segment that uses TSL model programming APIs, use the following interface:

      IOT_MQTT_Publish_Simple(0, topic, IOTX_MQTT_QOS0, payload, payload_len);

List of APIs related to TSL model features

Function nameDescription
IOT_Linkkit_OpenCreates local resources. Call this interface to get a session handle before you interact with network messages.
IOT_Linkkit_ConnectFor a master device or gateway, this establishes communication between the device and IoT Platform. For a sub-device, this registers the sub-device with IoT Platform and adds the master-sub-device topology relationship.
Note If the sub-device is already registered, this directly adds the master-sub-device topology relationship.
IOT_Linkkit_YieldIf the SDK has a dedicated thread, this function dispatches received network messages to your callback function. Otherwise, this function yields the CPU to the SDK to let it receive network messages and dispatch them to your callback function.
IOT_Linkkit_CloseIf the session handle in the input parameter is for a master device or gateway, this closes the network connection and releases all resources occupied by the SDK for that session.
IOT_Linkkit_TriggerEventSends event messages, error codes, anomaly alerts, and more to IoT Platform.
IOT_Linkkit_ReportSends upstream messages that do not have business data sent down to IoT Platform. These include messages for property values, device tags, binary pass-through data, and sub-device management.
IOT_Linkkit_QuerySends query messages to IoT Platform for which business data is sent down. These include messages for OTA status queries, OTA firmware downloads, sub-device topology queries, and NTP time queries.
IOT_RegisterCallbackRegisters event callback functions with the SDK. Examples include when the connection to IoT Platform succeeds or fails, when a property setting or service request arrives, or when a sub-device management message is acknowledged.
IOT_IoctlSets and gets various runtime parameters for the SDK, and gets runtime status information. The actual parameters can be of any data type.