./demos/cota_basic_demo.c のデモでは、デバイスのリモート設定を実装する方法を説明します。
背景情報
ステップ1: クライアントの初期化
ヘッダーファイルの追加
... …… # 「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); リターン-2; }
ステップ 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_RECV_HANDLER demo_ota_recv_handler デバイスが IoT Platform からリモート設定の指示を受信したときに呼び出されます。
ステップ 3:デバイスからの設定メッセージのリクエスト
IoT Platform がリモート設定の指示を送信したときにデバイスがオフラインの場合、デバイスはオンラインになった後にリクエストできます。
説明 IoT Platform でデバイスタスクが作成されていない場合、API 呼び出しは
receive task get detail reply, task_id:[$next],status:[9] を返します。- aiot_mqtt_pub を呼び出して、リモート設定情報を取得するリクエストを IoT Platform に送信します。
{ 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******/LightSwitch/thing/config/get リモート設定情報をリクエストするために使用されるトピックです。 詳細については、「トピック」をご参照ください。
サンプルコードでは:
a1oGs ******はデバイスのProductKeyです。LightSwitchは、デバイスのDeviceNameです。
詳細については、「デバイスの認証情報の取得」をご参照ください。
payload_string {\"id\":\"123\",\"params\":{\"configScope\":\"product\",\"getType\":\"file\"}} リクエストメッセージの内容です。 リクエストメッセージは JSON 形式です。これは Alink 形式データの params の値です。詳細については、「デバイスからの設定情報のリクエスト」をご参照ください。
- IoT Platform がリクエストを受信すると、設定情報をデバイスに返します。
IoT Platform コンソールでリモート設定を有効にして設定を編集できます。詳細については、「設定ファイルの編集」をご参照ください。説明 リモート設定コンテンツの最大サイズは 64 KB です。
- aiot_mqtt_recv を呼び出して、リモート設定の指示メッセージを受信します。
g_dl_handleポインターが null の場合、システムはネットワークから MQTT メッセージのみをポーリングします。g_dl_handleポインターが null でない場合、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 ms に変更して、2 つのリモート設定ダウンロード間の間隔を短縮します。 */ 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 ms に戻します。 */ timeout_ms = 5000; } aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_RECV_TIMEOUT_MS, (void *)&timeout_ms); } } - デバイスが設定の指示メッセージを受信すると、
demo_ota_recv_handlerコールバック関数が呼び出されます。以下の情報を使用して、コールバック関数の処理ロジックを記述してください。- IoT Platform は
/sys/${ProductKey}/${DeviceName}/thing/config/pushトピックを使用してリモート設定の指示をデバイスに送信します。 - Link SDK は IoT Platform からの指示を aiot_ota_recv_t データ構造にパースし、設定メッセージを自動的に解析します。
- リモート設定のメッセージタイプは AIOT_OTARECV_COTA です。
-
コールバック関数内で、HTTPS リクエストを開始してリモート設定ファイルをダウンロードできます。コールバック関数の記述方法については、「ステップ 5:リモート設定ファイルのダウンロード」をご参照ください。
- IoT Platform は
ステップ 4:IoT Platform からプッシュされるリモート設定情報の受信
デバイスがオンラインの場合、IoT Platform からのリモート設定の指示を即座に受信し、コールバック関数を呼び出します。
詳細については、「コールバック関数の処理ロジックの記述」をご参照ください。
ステップ 5:リモート設定ファイルのダウンロード
重要 デバイスは設定の指示を受信した後、自動的に設定ファイルをダウンロードしません。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 メンバーから取得されます。ダウンロード URL、リモート設定のサイズとバージョン番号が含まれます。 */ (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))) || /* 1 回のダウンロードの最大バッファー長を設定します。バッファーがいっぱいになるたびにユーザーに通知されます。 */ (STATE_SUCCESS != aiot_download_setopt(dl_handle, AIOT_DLOPT_BODY_BUFFER_MAX_LEN, (void *)(&max_buffer_len))) || /* HTTP サーバーに HTTP GET リクエストを送信します。 */ (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 が負の数の場合、パケット受信の例外またはダイジェスト検証エラーが発生しました。 */ if (percent < 0) { /* パケット受信の例外またはダイジェスト検証エラーが発生しました。 */ 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ハンドルを null に設定します。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 ms に変更して、2 つのリモート設定ダウンロード間の間隔を短縮します。 */ 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 ms に戻します。 */ timeout_ms = 5000; } aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_RECV_TIMEOUT_MS, (void *)&timeout_ms); } }
ステップ 6:プログラムの終了
aiot_ota_deinit操作を呼び出して、OTAを破棄します。
aiot_ota_deinit(&ota_handle);