This topic describes how to integrate an IoT Platform Link SDK into a Message Queuing Telemetry Transport (MQTT)-based module and complete the related configurations. In this topic, the sample code is written based on Link SDK v3.0.1.

Scenarios

Link SDKs of IoT Platform are used to connect devices to IoT Platform, verify devices, and enable data communication. When you integrate a Link SDK into a communication module, you can obtain the following benefits:

  • A device manufacturer can run the AT commands of a module on a device to connect the device to IoT Platform without the need to focus on how the microcontroller unit (MCU) of the device establishes a connection to IoT Platform. The workloads of the MCU remain unchanged.
  • The Alibaba Cloud Partner Network page displays certified module models, buy links, and development guides. If you are a device manufacturer or service provider, you can use certified communication modules to connect your devices to IoT Platform.

The following figure shows the process of connecting a device that contains a communication module into which a Link SDK is integrated to IoT Platform.

The following section describes the process of configuring a device as a device manufacturer.

  • Purchase a communication module into which a Link SDK is integrated.
  • Run AT commands on the MCU to connect the device to IoT Platform, and send data to or receive data from IoT Platform.
  • Deploy a cloud service in the IoT Platform to manage the device.

Module providers must perform the following steps on a module:

  • Integrate a Link SDK into the module as expected.
  • Provide the AT commands that the MCU can run to connect the device to IoT Platform.

Usage notes

The following section describes how to integrate a Link SDK into an MQTT-based module. This helps module providers understand the process of integrating a Link SDK. To reduce the complexity, the following section describes how to integrate the device signature module of a Link SDK into the module of a device. This way, you can use the module to connect the device to IoT Platform.

If you are a module provider, we recommend that you integrate more features of a Link SDK, such as Thing Specification Language (TSL) model-related features, over-the-air (OTA)-related features, and device shadow-related features. This way, a device manufacturer can use more features when a device is connected to IoT Platform.

If you use an MQTT-based module, you can call an API operation of a Link SDK that is integrated into the module to generate a client ID, username, and password that are required to connect to an IoT Platform MQTT broker based on the MQTT function module of the module. Then, a module provider can use the data to establish a connection to the IoT Platform MQTT broker, subscribe to an MQTT topic, and send data to the topic.

Create a Basic Edition product in the IoT Platform

When a module provider debugs sample code, the module provider must create a test product and a test device to check whether a Link SDK works as expected. To create a device, perform the following steps:

  1. Log on to the IoT Platform console. If you log on to the console as a module provider, you must create an Alibaba Cloud account. You can create an Alibaba Cloud account free of charge.
  2. Create a test device. On the device details page, you can obtain the DeviceName and DeviceSecret of the device.

The following section describes the process of integrating a Link SDK.

Process of integrating a Link SDK

When a module provider integrates a Link SDK into a module, the process includes multiple stages, as shown in the following figure.

Configure a Link SDK and extract the code

A Link SDK provides a large number of features. To prevent excessive RAM memory and flash memory from being consumed by a Link SDK, you can use a tool provided by the Link SDK to configure and extract only the required function modules.

Configure the Link SDK

The following section describes how to configure the required features as a module provider.

Run a configuration command

  • Linux

Go to the root directory of the Link SDK and run the following command:

make menuconfig
            
  • Windows

Go to the root directory of the Link SDK and run the config.bat file:

config.bat
            

Use one of the preceding methods to start the configuration tool of the Link SDK. The following figure shows the GUI of the tool.

  • If an asterisk (*) appears before an option, the related feature is enabled. Otherwise, the feature is disabled.
  • The tool displays the features that you can configure. If no options are selected, the features that you cannot configure in the Link SDK still take effect.
  • On the GUI, press the Space key to select or clear an option and press the Up Arrow or Down Arrow key on the keypad to switch between different options.
  • If you want to obtain the information about an option, press an arrow key to move the cursor to the option and press the H key. In this case, the information that indicates the purpose of the option and the system actions that are performed after you enable or disable the option is displayed.

You can select the following options based on your business scenario:

  • If the development environment supports stdint.h, select PLATFORM_HAS_STDINT.
  • If the development environment supports malloc/free, select PLATFORM_HAS_DYNMEM.
  • If an operating system runs in your environment, select PLATFORM_HAS_OS.

Do not select other options. After you complete the configuration, move the cursor to Exit and press the Enter key to exit the tool, and then save the configuration as prompted.

Extract the code of the Link SDK

The following section describes how to extract the code of the Link SDK.

Run an extract command

  • Linux

Go to the root directory of the Link SDK and run the following command:

sh ./extract.sh
            
  • Windows

Go to the root directory of the Link SDK and run the extract.bat file:

extract.bat
            
Use one of the preceding methods to start the code extraction tool of the Link SDK. The tool helps you extract the required code files and copy the files to the output directory, as shown in the following figure.

Import the files of the Link SDK to your project

You can copy the eng directory in the output directory to your project directory, and then import code files to your project.

The code files are stored in the eng/dev_sign, eng/infra, and eng/wrappers directories. When you compile the project, you must specify the preceding paths in a header file.

Implement hardware abstraction layer (HAL) functions

None.

Integrate the Link SDK with the existing MQTT function module

Generate an MQTT client ID, username, and password.

When you connect an MQTT client to an MQTT broker, you must specify the client ID, username, and password. You can call the IOT_Sign_MQTT() function of the Link SDK to generate the information.

int32_t IOT_Sign_MQTT(iotx_mqtt_region_types_t region, iotx_dev_meta_info_t *meta, iotx_sign_mqtt_t *signout)
            

If you want to use the function, you must specify the dev_sign_internal.h header file in the sample code.

#include "dev_sign_internal.h"
            

Input parameters

  • region

The IoT Platform endpoint to which you want to connect. The valid values of the parameter are defined in the eng/infra/infra_defs.h file.

typedef enum {
    IOTX_CLOUD_REGION_SHANGHAI,   /* Shanghai */
    IOTX_CLOUD_REGION_SINGAPORE,  /* Singapore */
    IOTX_CLOUD_REGION_JAPAN,      /* Japan */
    IOTX_CLOUD_REGION_USA_WEST,   /* America */
    IOTX_CLOUD_REGION_GERMANY,    /* Germany */
    IOTX_CLOUD_REGION_CUSTOM,     /* Custom setting */
    IOTX_CLOUD_DOMAIN_MAX         /* Maximum number of domain */
} iotx_mqtt_region_types_t;
            
  • If the module is available for purchase in the Chinese mainland, set the parameter to IOTX_CLOUD_REGION_SHANGHAI.

  • meta

The identity information about the device. The following code shows the data structure of the parameter:

typedef struct {
    char product_key[IOTX_PRODUCT_KEY_LEN + 1];
    char product_secret[IOTX_PRODUCT_SECRET_LEN + 1];
    char device_name[IOTX_DEVICE_NAME_LEN + 1];
    char device_secret[IOTX_DEVICE_SECRET_LEN + 1];
} iotx_dev_meta_info_t;
            

After a product is created in the IoT Platform console, the values of the preceding variables are requested by a device manufacturer for each device. In actual product development scenarios, an MCU transmits the values of the variables to a module by running AT commands.

Output parameters

  • signout

The parameter contains a client ID, username, and password that are required when you connect a client to an MQTT broker. The following code shows the data structure of the parameter:

typedef struct {
    char hostname[DEV_SIGN_HOSTNAME_MAXLEN];
    uint16_t port;
    char clientid[DEV_SIGN_CLIENT_ID_MAXLEN];
    char username[DEV_SIGN_USERNAME_MAXLEN];
    char password[DEV_SIGN_PASSWORD_MAXLEN];
} iotx_sign_mqtt_t;
            

The hostname variable specifies the endpoint of an Alibaba Cloud MQTT broker. The port variable specifies the port number of the Alibaba Cloud MQTT broker.

Return value

If the call is successful, the function returns 0. If the call fails, the function returns -1.

Example

The following code in the eng\examples\dev_sign_example.c file shows how to call the IOT_Sign_MQTT() function:

#define EXAMPLE_PRODUCT_KEY     "a1X2bEnP82z"
#define EXAMPLE_PRODUCT_SECRET  "7jluWm1zql7bt8qK"
#define EXAMPLE_DEVICE_NAME     "example1"
#define EXAMPLE_DEVICE_SECRET   "ga7XA6KdlEeiPXQPpRbAjOZXwG8ydgSe"

/* Implenment this HAL or using "printf" of your own system if you want to print something in example*/
void HAL_Printf(const char *fmt, ...);

int main(int argc, char *argv[])
{
    iotx_mqtt_region_types_t region = IOTX_CLOUD_REGION_SHANGHAI;
    iotx_dev_meta_info_t meta;
    iotx_sign_mqtt_t sign_mqtt;

    memset(&meta,0,sizeof(iotx_dev_meta_info_t));
    memcpy(meta.product_key,EXAMPLE_PRODUCT_KEY,strlen(EXAMPLE_PRODUCT_KEY));
    memcpy(meta.product_secret,EXAMPLE_PRODUCT_SECRET,strlen(EXAMPLE_PRODUCT_SECRET));
    memcpy(meta.device_name,EXAMPLE_DEVICE_NAME,strlen(EXAMPLE_DEVICE_NAME));
    memcpy(meta.device_secret,EXAMPLE_DEVICE_SECRET,strlen(EXAMPLE_DEVICE_SECRET));

    if (IOT_Sign_MQTT(region,&meta,&sign_mqtt) < 0) {
        return -1;
    }
    ...
}

            

In this example, specific values are specified for the product_key, product_secret, device_name, and device_secret parameters. In actual scenarios, the values must be transmitted by an MCU to a module.

When a module provider debugs a Link SDK, the module provider must create a test product and a test device in the IoT Platform console and obtain the values of the product_key, product_secret, device_name, and device_secret parameters. The values are generated by IoT Platform for the device.

Upload a module provider ID and module model

If a module provider wants to verify a module in IoT Platform, the module provider must submit the module provider ID and the model of the module. This way, IoT Platform can obtain the number of devices that are connected to IoT Platform by module provider ID or module model.

Before you integrate a Link SDK, contact Alibaba Cloud to obtain a module provider ID and module model by sending an email with the subject "Module or chip model application" to linkcertification@list.alibaba-inc.com. If you are not a module provider, you do not need to apply for a module provider ID.

After a module is connected to IoT Platform, copy the following code to your environment and run the function in the code to submit the information. The pid parameter specifies the ID of a module provider and the mid parameter specifies the ID of a module model.

#define PID_STRING_LEN_MAX          32  /* The maximum length of the value of the pid parameter. The value is a string. */
#define MID_STRING_LEN_MAX          32  /* The maximum length of the value of the mid parameter. The value is a string. */


int example_report_pid_mid(void *pclient, const char *product_key, const char *device_name, const char *pid, const char *mid)
{
    int res = 0;
    iotx_mqtt_topic_info_t topic_msg;

    const char topic_frag1[] = "/sys/";
    const char topic_frag2[] = "/thing/deviceinfo/update";
    char topic[sizeof(topic_frag1) + sizeof(topic_frag2) + IOTX_PRODUCT_KEY_LEN + IOTX_DEVICE_NAME_LEN] = {0};

    const char payload_frag1[] = "{\"id\":\"0\",\"version\":\"1.0\",\"params\":[{\"attrKey\":\"SYS_MODULE_ID\",\"attrValue\":\"";
    const char payload_frag2[] = "\",\"domain\":\"SYSTEM\"},{\"attrKey\":\"SYS_PARTNER_ID\",\"attrValue\":\"";
    const char payload_frag3[] = "\",\"domain\":\"SYSTEM\"}],\"method\": \"thing.deviceinfo.update\"}";
    char payload[sizeof(payload_frag1) + sizeof(payload_frag2) + sizeof(payload_frag3) + PID_STRING_LEN_MAX + MID_STRING_LEN_MAX] = {0};

    if (strlen(pid) > PID_STRING_LEN_MAX || strlen(mid) > MID_STRING_LEN_MAX) {
        return -1;
    }

    /* Combine strings to create an MQTT topic. */
    memcpy(topic, topic_frag1, strlen(topic_frag1));
    memcpy(topic + strlen(topic), product_key, strlen(product_key));
    memcpy(topic + strlen(topic), "/", 1);
    memcpy(topic + strlen(topic), device_name, strlen(device_name));
    memcpy(topic + strlen(topic), topic_frag2, strlen(topic_frag2));

    /* Combine strings to create the payload of the MQTT topic. The payload includes the values of the pid and mid parameters */
    memcpy(payload, payload_frag1, strlen(payload_frag1));
    memcpy(payload + strlen(payload), mid, strlen(mid));
    memcpy(payload + strlen(payload), payload_frag2, strlen(payload_frag2));
    memcpy(payload + strlen(payload), pid, strlen(pid));
    memcpy(payload + strlen(payload), payload_frag3, strlen(payload_frag3));

    topic_msg.qos = IOTX_MQTT_QOS0;
    topic_msg.retain = 0;
    topic_msg.dup = 0;
    topic_msg.payload = (void *)payload;
    topic_msg.payload_len = strlen(payload);

    /* Call the MQTT IOT_MQTT_Publish function to send a message that include the values of the pid and mid parameters. 
       Modify the MQTT IOT_MQTT_Publish function based on your business scenario.*/
    res = IOT_MQTT_Publish(pclient, topic, &topic_msg);
    if (res < 0) {
        return -1;
    }

    return 0;
}

            

Debugging

Connect the module to IoT Platform

A module provider must write code that can be used to connect the module to IoT Platform. The MQTT function module of the module provides a function that is used to connect to an MQTT broker. Specify the endpoint, port number, client ID, username, and password that are returned after you all the IOT_Sign_MQTT() function of the Link SDK for the function.

The following sample code integrates the Link SDK and an open source MQTT library named mosquitto.

        // Call the IOT_Sign_MQTT() function to obtain the username, password, and client ID.
        IOT_Sign_MQTT(region,&meta,&sign_mqtt);

        mosquitto_lib_init();

        // Specify the client ID and configure the cleansession parameter.
        mosq = mosquitto_new(sign_mqtt.clientid,0/*dont clean session*/,NULL);
        if(mosq==NULL){
                printf("Error:Failed creating mosquitto client\n\r");
                return(-1);
        }
        // Specify the username and password that are required to connect to an MQTT broker.
        if(0 != mosquitto_username_pw_set(mosq, sign_mqtt.username, sign_mqtt.password)){
                printf("Error:Failed setting username or password\n\r");
                return(-1);
        }

        ...
        // Specify the endpoint and port number to establish a connection to the MQTT broker.
        if(mosquitto_connect(mosq, sign_mqtt.hostname, sign_mqtt.port, kaInterval)){
                printf("Error: Failed connecting cloud.\n\r");
                sleep(1);
                return -1;
        }
            

When you establish an MQTT connection, you must specify a keepalive interval. We recommend that you specify an interval of 60 seconds. A module provider can implement an AT command that can be called by an MCU to specify the interval. IoT Platform supports a keepalive interval that ranges from 30 to 1,200 seconds.

If an MQTT connection is not closed between a module and IoT Platform after the module is connected to IoT Platform, the module remains in the Online state. You can find a test device and view the status of the device in the IoT Platform. The following figure shows a device that is in the Online state.

Check whether a device can send data to IoT Platform as expected

After a module is connected to IoT Platform, the device can send a message to the /${productKey}/${deviceName}/get topic to check whether data can be sent to IoT Platform as expected.

By default, a device has the Subscribe permission on the /${productKey}/${deviceName}/get topic. To prevent messages from being dropped after the messages are sent to IoT Platform, we recommend that you change the permission on the topic to Subscribe and Publish. This way, the sample program can run as expected without failures.

Sample code:

    int res = 0;
    iotx_mqtt_topic_info_t topic_msg;
    const char *fmt = "/%s/%s/get";
    char *topic = NULL;
    int topic_len = 0;
    char *payload = "hello,world";

    topic_len = strlen(fmt) + strlen(product_key) + strlen(device_name) + 1;
    topic = HAL_Malloc(topic_len);
    if (topic == NULL) {
        HAL_Printf("memory not enough\n");
        return -1;
    }
    memset(topic, 0, topic_len);
    // Generate a topic.
    HAL_Snprintf(topic, topic_len, fmt, product_key, device_name);

        // Generate a message.
    memset(&topic_msg, 0x0, sizeof(iotx_mqtt_topic_info_t));
    topic_msg.qos = IOTX_MQTT_QOS0;
    topic_msg.retain = 0;
    topic_msg.dup = 0;
    topic_msg.payload = (void *)payload;
    topic_msg.payload_len = strlen(payload);

        // Send the message to the topic. Replace the following function with the MQTT publish function that is specific to your module.
    res = IOT_MQTT_Publish(handle, topic, &topic_msg);
            

In the IoT Platform console, check whether the data is received on the Device Log tab of the device.

  • The tab displays the time when a message was received from the device and the name of the topic from which the message was received. The content is not displayed.
  • IoT Platform does not support quality of service (QoS) 2 messages.

Check whether a device has subscribed to a topic

A module provider can subscribe to the data of the /{productKey}/${deviceName}/get topic for a device. After the device submits data to IoT Platform, IoT Platform sends the data to the device. This way, the module provider can check whether the device has subscribed to the topic. Sample code:

    int res = 0;
    const char *fmt = "/%s/%s/get";
    char *topic = NULL;
    int topic_len = 0;

    topic_len = strlen(fmt) + strlen(product_key) + strlen(device_name) + 1;
    topic = HAL_Malloc(topic_len);
    if (topic == NULL) {
        HAL_Printf("memory not enough\n");
        return -1;
    }
    // Construct a topic
    memset(topic, 0, topic_len);
    snprintf(topic, topic_len, fmt, product_key, device_name);

    /* Subscribe to the topic and specify a function to process messages. 
      Replace the following function with the MQTT subscribe function that is specific to your module. */
    res = IOT_MQTT_Subscribe(handle, topic, IOTX_MQTT_QOS0, example_message_arrive, NULL);
            

In the IoT Platform console, a module provide can check whether data is sent to a device.

  • The Device Log tab displays the time when IoT Platform sent a message to a device. The tab does not display the content of the message.
  • A module provider must check whether the received data is the same as the submitted data on a module. This ensures that data can be received as expected.

Implement AT commands

A module provider must provide AT commands that can be called by an MCU. If you use an MQTT-based module, API operations that can be called to configure MQTT connections, establish connections, close connection, subscribe to messages, and publish messages must be provided. After a module provider integrates a Link SDK, the module provider can implement more AT commands that are specific to Alibaba Cloud or modify existing AT commands.

The following table describes the recommended AT commands.

CommandDescription
Specify identity information for a deviceSpecify a ProductKey, ProductSecret, DeviceName, and DeviceSecret for a device.
Specify IoT Platform endpointsIoT Platform is available in multiple regions, such as the Chinese mainland, US, and Japan. You can specify the information about an IoT Platform endpoint to which you want to connect an MCU.

You can continue to use other existing AT commands of a module provider.