./demos/cota_basic_demo.c協助您實現裝置的遠程配置功能。
背景資訊
步驟一:初始化
添加標頭檔。
…… …… #include "aiot_ota_api.h" ……
配置底層依賴和日誌輸出。
aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile); aiot_state_set_logcb(demo_state_logcb);
調用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,配置以下功能。
- 關聯MQTT串連的控制代碼。重要 在設定遠程配置參數前,請確保已配置裝置認證資訊等相關參數。具體操作,請參見MQTT配置串連參數。
aiot_ota_setopt(ota_handle, AIOT_OTAOPT_MQTT_HANDLE, mqtt_handle);
配置項 樣本 說明 AIOT_OTAOPT_MQTT_HANDLE mqtt_handle 遠程配置功能的請求基於MQTT串連,通過該配置項,關聯MQTT串連控制代碼。
- 設定遠程配置的指令訊息的回調。
aiot_ota_setopt(ota_handle, AIOT_OTAOPT_RECV_HANDLER, demo_ota_recv_handler);
配置項 樣本 說明 AIOT_OTAOPT_MQTT_HANDLE demo_ota_recv_handler 當裝置收到來自物聯網平台的遠程配置指令時,調用該回呼函數。
步驟三:裝置主動請求配置訊息
如果物聯網平台下發遠程配置指令時,裝置不線上,但裝置上線後,可主動請求擷取遠程配置的指令訊息。
說明 如果物聯網平台未建立裝置任務,調用介面後,返回
revice task get detail reply, task_id:[$next],status:[9]
。- 調用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的值。詳細說明,請參見裝置主動請求配置資訊。
- 物聯網平台接收請求後,向裝置返回配置資訊。
- 調用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); } }
- 如果
- 裝置接收配置指令的訊息後,觸發回呼函數
demo_ota_recv_handler
。您可以參考以下內容,編寫回呼函數的處理邏輯:- 物聯網平台通過Topic
/sys/${ProductKey}/${DeviceName}/thing/config/push
,向裝置下發遠程配置指令。 - Link SDK解析物聯網平台指令,解析後的資料結構類型為aiot_ota_recv_t,Link SDK自動解析收到的配置訊息。
- 遠程配置的訊息類型為AIOT_OTARECV_COTA。
通過回呼函數,發起HTTPS協議的請求,下載遠程設定檔。回呼函數的編寫邏輯,請參見步驟五:下載遠程設定檔。
- 物聯網平台通過Topic
步驟四:裝置接收物聯網平台推送的遠程配置資訊
如果裝置線上,物聯網平台下發遠程配置指令後,裝置隨即接收遠程配置指令,觸發回呼函數。
具體操作,請參見編寫回呼函數的處理邏輯。
步驟五:下載遠程設定檔
重要 接收配置指令後,裝置不會自動下載設定檔,您需調用Link SDK提供的API啟動下載。
- 初始化下載器。調用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);
- 配置下載參數。調用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; } }
- 發起下載請求後,接收應答報文,觸發回呼函數
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; } …… …… }
- 調用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); }
- 下載結束後,通過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);