全部產品
Search
文件中心

:使用樣本

更新時間:Jun 30, 2024

./demos/cota_basic_demo.c協助您實現裝置的遠程配置功能。

背景資訊

  • 遠程配置功能的更多資訊,請參見概述
  • 遠程配置功能基於MQTT接入,開發過程中涉及MQTT接入的代碼說明,請參見MQTT接入

步驟一:初始化

  1. 添加標頭檔。

    ……
    ……
    #include "aiot_ota_api.h"
    ……
  2. 配置底層依賴和日誌輸出。

        aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile);
        aiot_state_set_logcb(demo_state_logcb);
  3. 調用aiot_ota_init,建立OTA

        ota_handle = aiot_ota_init();
        if (NULL == ota_handle) {
            printf("aiot_ota_init failed\r\n");
            aiot_mqtt_deinit(&mqtt_handle);
            return -2;
        }

步驟二:配置功能

調用aiot_ota_setopt,配置以下功能。

  1. 關聯MQTT串連的控制代碼。
    重要 在設定遠程配置參數前,請確保已配置裝置認證資訊等相關參數。具體操作,請參見MQTT配置串連參數
    •     aiot_ota_setopt(ota_handle, AIOT_OTAOPT_MQTT_HANDLE, mqtt_handle);
    • 配置項樣本說明
      AIOT_OTAOPT_MQTT_HANDLEmqtt_handle遠程配置功能的請求基於MQTT串連,通過該配置項,關聯MQTT串連控制代碼。

  2. 設定遠程配置的指令訊息的回調。
    •     aiot_ota_setopt(ota_handle, AIOT_OTAOPT_RECV_HANDLER, demo_ota_recv_handler);
    • 配置項樣本說明
      AIOT_OTAOPT_MQTT_HANDLEdemo_ota_recv_handler當裝置收到來自物聯網平台的遠程配置指令時,調用該回呼函數。

步驟三:裝置主動請求配置訊息

如果物聯網平台下發遠程配置指令時,裝置不線上,但裝置上線後,可主動請求擷取遠程配置的指令訊息。

說明 如果物聯網平台未建立裝置任務,調用介面後,返回revice task get detail reply, task_id:[$next],status:[9]
  1. 調用aiot_mqtt_pub,向物聯網平台發送請求,以擷取遠程配置資訊。
    •     {
              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);
                  /* 嘗試建立串連失敗, 銷毀MQTT執行個體, 回收資源 */
                  goto exit;
              }
          }
    • 參數樣本值說明
      topic_string/sys/a18wP******5/LightSwitch/thing/config/get請求擷取遠程配置資訊的Topic。

      關於Topic的更多資訊,請參見什麼是Topic

      範例程式碼中:

      • a18wP******為裝置的ProductKey。

      • LightSwitch為裝置的DeviceName。

      更多資訊,請參見擷取裝置認證資訊

      payload_string{\"id\":\"123\",\"params\":{\"configScope\":\"product\",\"getType\":\"file\"}}請求訊息的內容。

      請求訊息的內容為JSON格式,是Alink格式資料中params的值。詳細說明,請參見裝置主動請求配置資訊

  2. 物聯網平台接收請求後,向裝置返回配置資訊。
    說明 遠程配置內容大小的上限是64 KB。
    您需在物聯網平台控制台,開啟遠程配置,編輯配置資訊。具體操作,請參見編輯設定檔
  3. 調用aiot_mqtt_recv,接收遠程配置指令訊息。
    • 如果g_dl_handle指標會為空白, 則只從網路上輪詢MQTT報文。
    • 如果g_dl_handle指標為非空, 則調用aiot_download_recv函數。
    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) {
                /* 完成遠程配置的接收前, 將mqtt的收包逾時調整到100毫秒, 以減少兩次遠程配置的下載間隔*/
                int32_t ret = aiot_download_recv(g_dl_handle);
                timeout_ms = 100;
    
                if (STATE_DOWNLOAD_FINISHED == ret) {
                    aiot_download_deinit(&g_dl_handle);
                    /* 完成遠程配置的接收後, 將mqtt的收包逾時調整回到預設值5000毫秒 */
                    timeout_ms = 5000;
                }
                aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_RECV_TIMEOUT_MS, (void *)&timeout_ms);
            }
        }
  4. 裝置接收配置指令的訊息後,觸發回呼函數demo_ota_recv_handler
    您可以參考以下內容,編寫回呼函數的處理邏輯:
    • 物聯網平台通過Topic /sys/${ProductKey}/${DeviceName}/thing/config/push,向裝置下發遠程配置指令。
    • Link SDK解析物聯網平台指令,解析後的資料結構類型為aiot_ota_recv_t,Link SDK自動解析收到的配置訊息。
    • 遠程配置的訊息類型為AIOT_OTARECV_COTA
    • 通過回呼函數,發起HTTPS協議的請求,下載遠程設定檔。回呼函數的編寫邏輯,請參見步驟五:下載遠程設定檔

步驟四:裝置接收物聯網平台推送的遠程配置資訊

如果裝置線上,物聯網平台下發遠程配置指令後,裝置隨即接收遠程配置指令,觸發回呼函數。

具體操作,請參見編寫回呼函數的處理邏輯

步驟五:下載遠程設定檔

重要 接收配置指令後,裝置不會自動下載設定檔,您需調用Link SDK提供的API啟動下載。
  1. 初始化下載器。
    調用aiot_download_init,建立download
                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. 配置下載參數。
    調用aiot_download_setopt,配置下載任務的相關參數。
                /* 設定下載時為TLS下載 */
                if ((STATE_SUCCESS != aiot_download_setopt(dl_handle, AIOT_DLOPT_NETWORK_CRED, (void *)(&cred))) ||
                    /* 設定下載時訪問的伺服器連接埠號碼 */
                    (STATE_SUCCESS != aiot_download_setopt(dl_handle, AIOT_DLOPT_NETWORK_PORT, (void *)(&port))) ||
                    /* 設定下載的任務資訊, 通過輸入參數 ota_msg 中的 task_desc 成員得到, 內含下載地址, 遠程配置的大小和版本號碼*/
                    (STATE_SUCCESS != aiot_download_setopt(dl_handle, AIOT_DLOPT_TASK_DESC, (void *)(ota_msg->task_desc))) ||
                    /* 設定下載內容到達時, SDK將調用的回呼函數 */
                    (STATE_SUCCESS != aiot_download_setopt(dl_handle, AIOT_DLOPT_RECV_HANDLER, (void *)(demo_download_recv_handler))) ||
                    /* 設定單次下載最大的buffer長度, 每當這個長度的記憶體讀滿了後會通知使用者 */
                    (STATE_SUCCESS != aiot_download_setopt(dl_handle, AIOT_DLOPT_BODY_BUFFER_MAX_LEN, (void *)(&max_buffer_len))) ||
                    /* 發送http的GET請求給http伺服器 */
                    (STATE_SUCCESS != aiot_download_send_request(dl_handle))) {
                    if (res != STATE_SUCCESS) {
                        aiot_download_deinit(&dl_handle);
                        break;
                    }
                }

  3. 發起下載請求後,接收應答報文,觸發回呼函數demo_download_recv_handler,執行下載處理。
    您可以參考以下內容,編寫回呼函數的處理邏輯:
    • 下載訊息的資料結構類型為aiot_download_recv_t,是回到函數的入參。
    • 下載訊息的packet->type類型AIOT_DLRECV_HTTPBODY
    • 範例程式碼僅做列印處理,您需根據業務需要,將設定檔下載至指定位置。
    void demo_download_recv_handler(void *handle, const aiot_download_recv_t *packet, void *userdata)
    {
        /* 目前只支援 packet->type 為 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;
    
        /* 如果 percent 為負數, 說明發生了收包異常或者digest校正錯誤 */
        if (percent < 0) {
            /* 收包異常或者digest校正錯誤 */
            printf("exception happend, percent is %d\r\n", percent);
            return;
        }
    ……
    ……
    }
  4. 調用aiot_download_report_progress,上報下載進度。
    void demo_download_recv_handler(void *handle, const aiot_download_recv_t *packet, void *userdata)
    {
        /* 目前只支援 packet->type 為 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. 下載結束後,通過aiot_download_deinit,把控制代碼置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) {
                /* 完成遠程配置的接收前, 將mqtt的收包逾時調整到100ms, 以減少兩次遠程配置的下載間隔*/
                int32_t ret = aiot_download_recv(g_dl_handle);
                timeout_ms = 100;
    
                if (STATE_DOWNLOAD_FINISHED == ret) {
                    aiot_download_deinit(&g_dl_handle);
                    /* 完成遠程配置的接收後, 將mqtt的收包逾時調整回到預設值5000ms */
                    timeout_ms = 5000;
                }
                aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_RECV_TIMEOUT_MS, (void *)&timeout_ms);
            }
        }

步驟六:退出程式

調用aiot_ota_deinit,銷毀OTA

    aiot_ota_deinit(&ota_handle);

後續步驟