This article describes how to call the API operations of Link SDK for C to remotely configure a device. In this example, the ./demos/cota_basic_demo.c sample code file is used.

Background information

  • For more information about remote configuration, see Overview.
  • You must establish an MQTT connection. For more information, see Overview.

Step 1: Initialize a client

  1. Add header files.
    ...
    ……
    #include "aiot_ota_api.h"
    ……
  2. Add the underlying dependency and configure the log output feature.
        aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile);
        aiot_state_set_logcb(demo_state_logcb);
  3. Call the aiot_ota_init operation to create an OTA client instance and initialize the default parameters.
        ota_handle = aiot_ota_init();
        if (NULL == ota_handle) {
            printf("aiot_ota_init failed\r\n");
            aiot_mqtt_deinit(&mqtt_handle);
            return -2;
        }

Step 2: Configure required features

Call the aiot_ota_setopt operation to configure the following items.

  1. Associate with an MQTT connection handle.
    Notice Before you set remote configuration-specific parameters, make sure that device authentication information is specified. For more information, see Example.
    • Sample code
          aiot_ota_setopt(ota_handle, AIOT_OTAOPT_MQTT_HANDLE, mqtt_handle);
    • Parameters:
      Parameter Example Description
      AIOT_OTAOPT_MQTT_HANDLE mqtt_handle You must establish an MQTT connection. This parameter is used to associate with the MQTT connection handle.
  2. Specify a callback to process remote configuration commands.
    • Sample code
          aiot_ota_setopt(ota_handle, AIOT_OTAOPT_RECV_HANDLER, demo_ota_recv_handler);
    • Parameters:
      Parameter Example Description
      AIOT_OTAOPT_MQTT_HANDLE demo_ota_recv_handler This callback is called when the device receives a remote configuration command from IoT Platform.

Step 3: Request configuration information

If the device is offline when a remote configuration command is sent from IoT Platform, you can request the remote configuration command after the device goes online.

Note If no device job is created in IoT Platform, the following response is returned after you call the operation: revice task get detail reply, task_id:[$next],status:[9].
  1. Call the aiot_mqtt_pub operation to obtain remote configuration information from IoT Platform.
    • Sample code
          {
              char *topic_string = "/sys/a18wP******/LightSwitch/thing/config/get";
              char *payload_string = "{\"id\":\"123\",\"params\":{\"configScope\":\"product\",\"getType\":\"file\"}}";
      
              res = aiot_mqtt_pub(mqtt_handle, topic_string, (uint8_t *)payload_string, strlen(payload_string), 0);
              if (res < STATE_SUCCESS) {
                  printf("aiot_mqtt_pub failed: -0x%04X\r\n", -res);
                  /* Release resources of the MQTT instance if the MQTT connection fails to be established. */
                  goto exit;
              }
          }
    • Parameters:
      Parameter Example Description
      topic_string /sys/a18wP******5/LightSwitch/thing/config/get The topic that is used to obtain the remote configuration information.

      For more information about topics, see What is a topic?.

      • a18wP****** indicates the ProductKey of the device.
      • LightSwitch indicates the DeviceName of the device.

      For more information, see Obtain device authentication information.

      payload_string {\"id\":\"123\",\"params\":{\"configScope\":\"product\",\"getType\":\"file\"}} The content of the request message.

      The message content is in the JSON format. The content is the value of the params parameter in the Alink data. For more information, see Devices request configuration information from IoT Platform.

  2. After IoT Platform receives the request, IoT Platform returns the configuration information to the device.
    Note The maximum size of the remote configuration information is 64 KB.
    In the IoT Platform console, enable the remote configuration feature and edit configuration information. For more information, see Remote configuration.
  3. Call the aiot_mqtt_recv operation to receive the remote configuration information.
    • If the g_dl_handle pointer is null, the client sends requests to obtain MQTT messages at regular intervals.
    • If the g_dl_handle pointer is non-null, the aiot_download_recv function is called.
    while (1) {
            aiot_mqtt_process(mqtt_handle);
            res = aiot_mqtt_recv(mqtt_handle);
    
            if (res == STATE_SYS_DEPEND_NWK_CLOSED) {
                sleep(1);
            }
            if (NULL != g_dl_handle) {
                /* Before the remote configuration information is received, set the timeout period of receiving MQTT messages to 100 ms to reduce the interval between two remote configuration downloads. */
                int32_t ret = aiot_download_recv(g_dl_handle);
                timeout_ms = 100;
    
                if (STATE_DOWNLOAD_FINISHED == ret) {
                    aiot_download_deinit(&g_dl_handle);
                    /* After the remote configuration information is received, set the timeout period of receiving MQTT messages to 5,000 ms, which is the default value. */
                    timeout_ms = 5000;
                }
                aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_RECV_TIMEOUT_MS, (void *)&timeout_ms);
            }
        }
  4. After the device receives the configuration information, the demo_ota_recv_handler callback is called.
    When you specify the processing logic of the callback, take note of the following items:
    • IoT Platform sends the configuration information by using the /sys/ ${ProductKey} /${DeviceName} /thing/config/push topic.
    • Link SDK automatically parses the configuration information. aiot_ota_recv_t indicates the data format. Link SDK automatically parses the received
    • AIOT_OTARECV_COTA indicates the message type .
    • A callback is used to initiate an HTTPS request and download the remote configuration file. For more information about how to write a callback, see Step 5: Download the remote configuration file.

Step 4: Receive the remote configuration information

If the device is online, the device can receive the remote configuration information that is sent from IoT Platform. Then, the demo_ota_recv_handler callback is called.

For more information, see Specify callback logic.

Step 5: Download the remote configuration file

Notice After the device receives the remote configuration information, the device does not automatically download the configuration file. You must call the API operation provided by Link SDK to download the file.
  1. Initialize the downloader.
    Call the aiot_download_init operation to create a download client instance and initialize the default parameters.
                uint32_t res = 0;
                uint16_t port = 443;
                uint32_t max_buffer_len = 2048;
                aiot_sysdep_network_cred_t cred;
                void *dl_handle = aiot_download_init();
    
                if (NULL == dl_handle || NULL == ota_msg->task_desc) {
                    return;
                }
    
                printf("configId: %s, configSize: %u Bytes\r\n", ota_msg->task_desc->version,
                       ota_msg->task_desc->size_total);
    
                memset(&cred, 0, sizeof(aiot_sysdep_network_cred_t));
                cred.option = AIOT_SYSDEP_NETWORK_CRED_SVRCERT_CA;
                cred.max_tls_fragment = 16384;
                cred.x509_server_cert = ali_ca_cert;
                cred.x509_server_cert_len = strlen(ali_ca_cert);
  2. Set the parameters.
    Call the aiot_download_setopt operation to set the parameters that are related to the download task.
                /* Set the TLS protocol for downloading. */
                if ((STATE_SUCCESS != aiot_download_setopt(dl_handle, AIOT_DLOPT_NETWORK_CRED, (void *)(&cred))) ||
                    /* Set the port number of the server to be accessed. */
                    (STATE_SUCCESS != aiot_download_setopt(dl_handle, AIOT_DLOPT_NETWORK_PORT, (void *)(&port))) ||
                    /* Set the task information. You can obtain the information from the task_desc field in the ota_msg input parameter. The information includes the download URL, and the size and version of the remote configuration file. */
                    (STATE_SUCCESS != aiot_download_setopt(dl_handle, AIOT_DLOPT_TASK_DESC, (void *)(ota_msg->task_desc))) ||
                    /* Set the callback that is called when the downloaded content is received. */
                    (STATE_SUCCESS != aiot_download_setopt(dl_handle, AIOT_DLOPT_RECV_HANDLER, (void *)(demo_download_recv_handler))) ||
                    /* Set the maximum buffer length for a single download. Users are notified if the limit is reached. */
                    (STATE_SUCCESS != aiot_download_setopt(dl_handle, AIOT_DLOPT_BODY_BUFFER_MAX_LEN, (void *)(&max_buffer_len))) ||
                    /* Send an HTTP GET request to the HTTP server. */
                    (STATE_SUCCESS != aiot_download_send_request(dl_handle))) {
                    if (res != STATE_SUCCESS) {
                        aiot_download_deinit(&dl_handle);
                        break;
                    }
                }
  3. After you initiate a download request, IoT Platform returns a response message. Then, the demo_download_recv_handler callback is called to download the remote configuration file.
    When you specify the processing logic of the callback, take note of the following items:
    • aiot_download_recv_t is an input parameter of the callback. This parameter indicates the data format.
    • AIOT_DLRECV_HTTPBODY indicates the message type (packet->type).
    • In this example, the information is printed. You can download the configuration file to a specified location based on your business needs.
    void demo_download_recv_handler(void *handle, const aiot_download_recv_t *packet, void *userdata)
    {
        /* You can set packet->type only to AIOT_DLRECV_HTTPBODY. */
        if (!packet || AIOT_DLRECV_HTTPBODY != packet->type) {
            return;
        }
        int32_t percent = packet->data.percent;
        uint8_t *src_buffer = packet->data.buffer;
        uint32_t src_buffer_len = packet->data.len;
    
        /* A negative value of percent indicates that an exception occurs during data receiving or the digest authentication fails. */
        if (percent < 0) {
            /* An exception occurs during data receiving or the digest authentication fails. */
            printf("exception happend, percent is %d\r\n", percent);
            return;
        }
    ……
    ...
    }
  4. Call the aiot_download_report_progress operation to submit the download progress.
    void demo_download_recv_handler(void *handle, const aiot_download_recv_t *packet, void *userdata)
    {
        /* You can set packet->type only to AIOT_DLRECV_HTTPBODY. */
        if (!packet || AIOT_DLRECV_HTTPBODY != packet->type) {
            return;
    ...
    ...
        aiot_download_report_progress(handle, percent);
        printf("config len is %d, config content is %.*s\r\n", src_buffer_len, src_buffer_len, (char *)src_buffer);
    }
  5. After you download the file, call the aiot_download_deinit operation to clear the handle (g_dl_handle).
    while (1) {
            aiot_mqtt_process(mqtt_handle);
            res = aiot_mqtt_recv(mqtt_handle);
    
            if (res == STATE_SYS_DEPEND_NWK_CLOSED) {
                sleep(1);
            }
            if (NULL != g_dl_handle) {
                /* Before the remote configuration information is received, set the timeout period of receiving MQTT messages to 100 ms to reduce the interval between two remote configuration downloads. */
                int32_t ret = aiot_download_recv(g_dl_handle);
                timeout_ms = 100;
    
                if (STATE_DOWNLOAD_FINISHED == ret) {
                    aiot_download_deinit(&g_dl_handle);
                    /* After the remote configuration information is received, set the timeout period of receiving MQTT messages to 5,000 ms, which is the default value. */
                    timeout_ms = 5000;
                }
                aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_RECV_TIMEOUT_MS, (void *)&timeout_ms);
            }
        }

Step 6: Exit the program

Call the aiot_ota_deinit operation to destroy the OTA client instance and release resources.

    aiot_ota_deinit(&ota_handle);

What to do next

  • After you configure the sample code file, compile the file to generate an executable file In this example, the ./output//cota-basic-demo executable file is generated.

    For more information, see Compilation and running.

  • For more information about running results, see View logs.