./demos/mota_basic_demo.c ファイルでは、デバイスが MQTT を使用して単一のアップデートファイルを含む OTA アップデートパッケージをダウンロードし、アップデートを実行する方法を説明します。
背景情報
ステップ1: クライアントの初期化
- ヘッダーファイルを追加します。
…… …… #include "aiot_ota_api.h" #include "aiot_mqtt_download_api.h" ……
/* portfiles/aiot_port ディレクトリにあるシステム適応関数群 */ extern aiot_sysdep_portfile_t g_aiot_sysdep_portfile; /* TODO: ログを無効にするには、この関数を空の関数として実装します。 ログを減らすには、コードに基づいてログを出力しないようにします。 * 例:[1578463098.611][LK-0309] pub: /ota/device/upgrade/a13FN******/ota_demo * 上記のログのコードは 0309 (16 進数) です。 コード値の詳細については、core/aiot_state_api.h をご参照ください。 */ /* これはログコールバック関数です。 SDK のログはここから出力されます。 */ int32_t demo_state_logcb(int32_t code, char *message) { printf("%s", message); return 0; }
- aiot_ota_init を呼び出して OTA ハンドルを作成します。
ota_handle = aiot_ota_init(); if (NULL == ota_handle) { goto exit; }
ステップ2: 必要な機能の設定
aiot_ota_setopt操作を呼び出して、次の項目を設定します。
MQTT接続ハンドルに関連付けます。
重要OTA更新固有のパラメーターを設定する前に、デバイス認証情報が指定されていることを確認してください。 詳細については、「例」をご参照ください。
aiot_ota_setopt(ota_handle, AIOT_OTAOPT_MQTT_HANDLE, mqtt_handle);パラメーター
例
説明
AIOT_OTAOPT_MQTT_HANDLE
mqtt_handle
MQTT接続を確立する必要があります。 このパラメータは、MQTT接続ハンドルに関連付けるために使用されます。
- OTA アップデート命令のコールバックを設定します。
aiot_ota_setopt(ota_handle, AIOT_OTAOPT_RECV_HANDLER, user_ota_recv_handler);-
設定項目 例 説明 AIOT_OTAOPT_MQTT_HANDLER
user_ota_recv_handler このコールバック関数は、デバイスがIoT PlatformからOTA更新コマンドを受信したときに呼び出されます。
ステップ3: デバイスのバージョン番号を送信する
デバイスがIoT PlatformとのMQTT接続を確立した後、aiot_ota_report_version操作を呼び出して、デバイスのバージョン番号を送信します。 IoT Platformは、バージョン番号に基づいて更新が必要かどうかを判断します。
この例では、送信されたバージョン番号は1.0.0です。 実際のビジネスシナリオでは、デバイス設定からバージョン番号を取得し、バージョン番号を送信するロジックを指定する必要があります。
OTAアップデートを実行する前に、バージョン番号を少なくとも1回送信する必要があります。
cur_version = "1.0.0";
res = aiot_ota_report_version(ota_handle, cur_version);
if (res < STATE_SUCCESS) {
printf("aiot_ota_report_version failed: -0x % 04X\r\n" 、-res);
}ステップ4: 更新コマンドの受信
IoT Platformに更新パッケージを追加して更新タスクを開始すると、IoT Platformは更新コマンドをデバイスに送信します。
詳細については、「アップデートパッケージの追加」をご参照ください。
- デバイスは aiot_mqtt_recv を呼び出してメッセージを受信します。 メッセージが OTA アップデート命令として識別されると、
user_ota_recv_handlerコールバックが呼び出されて命令が処理されます。 - コールバック関数の処理ロジックを記述します。
次の情報に基づいて、コールバック関数の処理ロジックを記述します:IoT Platformは、
/ota/device/upgrade/${ProductKey}/${DeviceName}トピックを使用して、OTA更新コマンドをデバイスに送信します。${ProductKey} および ${DeviceName} の詳細については、「デバイス検証情報の取得」をご参照ください。
- OTA アップデート命令のタイプは AIOT_OTARECV_FOTA です。
void user_ota_recv_handler(void *ota_handle, aiot_ota_recv_t *ota_msg, void *userdata) { uint32_t request_size = 10 * 1024; switch (ota_msg->type) { case AIOT_OTARECV_FOTA: { if (NULL == ota_msg->task_desc || ota_msg->task_desc->protocol_type != AIOT_OTA_PROTOCOL_MQTT) { break; } …… …… } OTA更新コマンドのAlinkデータ形式の詳細については、「OTA更新パッケージに関する情報をデバイスにプッシュする」をご参照ください。
aiot_ota_recv_tはデータ形式を示します。 Link SDKは、受信したメッセージを自動的に解析します。
- コールバック関数の処理ロジックを記述するには、「ステップ5」をご参照ください。
ステップ5: アップデートパッケージをダウンロードしてOTAアップデートを実行する
デバイスがIoT Platformによってプッシュされた更新コマンドを受信した後、デバイスは更新パッケージを自動的にダウンロードしません。 パッケージをダウンロードするには、Link SDKのAPI操作を呼び出す必要があります。
user_ota_recv_handler がトリガーされた後、ダウンローダーは MQTT ベースのダウンロードリクエストを送信して、IoT Platform からアップデートパッケージを受信し、OTA アップデートを実行します。
- ダウンローダーを初期化します。
aiot_mqtt_download_init を呼び出してdownloadvoid user_ota_recv_handler(void *ota_handle, aiot_ota_recv_t *ota_msg, void *userdata) { …… …… printf("OTA ターゲットファームウェアのバージョン: %s、サイズ: %u バイト\r\n", ota_msg->task_desc->version, ota_msg->task_desc->size_total); void *md_handler = aiot_mqtt_download_init(); …… …… }
- ダウンロードパラメーターを設定します。
aiot_mqtt_download_setopt を呼び出して、ダウンロードタスクのパラメーターを設定します。aiot_mqtt_download_setopt(md_handler, AIOT_MDOPT_TASK_DESC, ota_msg->task_desc); /* ダウンロードパッケージのサイズを設定します。 リソースに制約のあるデバイスでは、この値を調整できます。 */ aiot_mqtt_download_setopt(md_handler, AIOT_DLOPT_DATA_REQUEST_SIZE, &request_size); /* アップデートパッケージをセグメントでダウンロードする場合、またはパッケージのフラグメントのみをダウンロードする場合の各セグメントの開始バイト番号と終了バイト番号。 * ダウンロードの範囲を設定した場合、単一メッセージ内のデータには巡回冗長検査 (CRC) がありますが、SDK はファイル全体の MD5 検証を実行しません。 * デフォルトでは、ファイル全体がダウンロードされます。 単一メッセージ内のデータには CRC があり、SDK はファイル全体の MD5 検証を実行します。 * 次のコードのコメントを解除すると、ダウンロードはファイルの 10 バイト目から始まり、50 キロバイト目の 10 バイト目で終わります。 */ // uint32_t range_start = 10, range_end = 50 * 1024 + 10; // aiot_mqtt_download_setopt(md_handler, AIOT_MDOPT_RANGE_START, &range_start); // aiot_mqtt_download_setopt(md_handler, AIOT_MDOPT_RANGE_END, &range_end); aiot_mqtt_download_setopt(md_handler, AIOT_MDOPT_RECV_HANDLE, user_download_recv_handler); g_dl_handle = md_handler;-
設定項目 例 説明 AIOT_MDOPT_TASK_DESC ota_msg->task_desc ダウンロードタスクを指定します。 AIOT_DLOPT_DATA_REQUEST_SIZE request_size IoT Platform から要求される各データパッケージのサイズ。 AIOT_MDOPT_RANGE_START range_start アップデートパッケージをセグメントでダウンロードする場合、またはパッケージのフラグメントのみをダウンロードする場合の各セグメントの開始バイト番号と終了バイト番号。 これを設定しない場合、ファイル全体が一度にダウンロードされます。
たとえば、2つのセグメントを使用して1,024バイトの更新パッケージをダウンロードする場合は、パラメーターに次の値を指定します。
最初のセグメント:
AIOT_DLOPT_RANGE_START=0、AIOT_DLOPT_RANGE_END=5112番目のセグメント:
AIOT_DLOPT_RANGE_START=512、AIOT_DLOPT_RANGE_END=1023
AIOT_MDOPT_RANGE_END range_end AIOT_MDOPT_RECV_HANDLE user_download_recv_handler OTA アップデートパッケージデータを受信するためのコールバックを指定します。 このコールバックは、デバイスがダウンロードリクエストを開始した後に、IoT Platform がアップデートパッケージの内容を含むメッセージを返したときにトリガーされます。
- aiot_mqtt_download_process を呼び出して、ダウンロードリクエストを IoT Platform に送信します。
while (1) { aiot_mqtt_process(mqtt_handle); aiot_mqtt_recv(mqtt_handle); if(g_dl_handle != NULL) { int32_t res = aiot_mqtt_download_process(g_dl_handle); …… …… } } - IoT Platform がダウンロードリクエストを受信した後、アップデートパッケージをデバイスに返します。 デバイスがパッケージデータを受信すると、
user_download_recv_handlerコールバックがトリガーされます。コールバック関数の処理ロジックを記述して、ダウンロードしたアップデートパッケージデータをローカルファイルに保存します。void user_download_recv_handler(void *handle, const aiot_mqtt_download_recv_t *packet, void *userdata) { uint32_t data_buffer_len = 0; /* 現在、packet->type が AIOT_MDRECV_DATA_RESP の場合のみサポートされています。 */ if (!packet || AIOT_MDRECV_DATA_RESP != packet->type) { return; } /* ファイルをローカルに永続化する操作は、ここに実装する必要があります。 */ FILE *file = fopen("mota_demo.bin", "ab"); fwrite(packet->data.data_resp.data, packet->data.data_resp.data_size, sizeof(int8_t), file); fclose(file); data_buffer_len = packet->data.data_resp.data_size; printf("ダウンロード %03d%% 完了、+%d バイト\r\n", packet->data.data_resp.percent, data_buffer_len); } - アップデートパッケージがダウンロードされた後、aiot_mqtt_download_deinit を呼び出してダウンローダーのリソースを解放します。
while (1) { aiot_mqtt_process(mqtt_handle); aiot_mqtt_recv(mqtt_handle); if(g_dl_handle != NULL) { int32_t res = aiot_mqtt_download_process(g_dl_handle); if(STATE_MQTT_DOWNLOAD_SUCCESS == res) { /* アップデートは成功しました。 ここでデバイスを再起動し、新しいバージョン番号を報告できます。 */ printf("mqtt download ota success \r\n"); aiot_mqtt_download_deinit(&g_dl_handle); break; } else if(STATE_MQTT_DOWNLOAD_FAILED_RECVERROR == res || STATE_MQTT_DOWNLOAD_FAILED_TIMEOUT == res || STATE_MQTT_DOWNLOAD_FAILED_MISMATCH == res) { printf("mqtt download ota failed \r\n"); aiot_mqtt_download_deinit(&g_dl_handle); break; } } }
ステップ6: 更新後にバージョン番号を送信する
バージョン番号の報告方法に関するサンプルコードについては、「ステップ3:現在のデバイスバージョンの報告」をご参照ください。
デバイスの更新後、最新のバージョン番号を送信する必要があります。 それ以外の場合、IoT PlatformはOTA更新タスクが失敗したと判断します。
デバイスは、更新後に再起動する必要があります。 この場合、デバイスの再起動後に最新のバージョン番号を送信してください。
この例では、更新後に最新のバージョン番号を送信するロジックは指定されていません。 ビジネス要件に基づいてロジックを指定する必要があります。
ステップ7:切断
aiot_mqtt_disconnect操作を呼び出して、デバイスをIoT Platformから切断します。
res = aiot_mqtt_disconnect(mqtt_handle);
if (res < STATE_SUCCESS) {
aiot_mqtt_deinit(&mqtt_handle);
printf("aiot_mqtt_disconnect failed: -0x % 04X\n", -res);
return -1;
}
ステップ8: プログラムを終了する
aiot_ota_deinit操作を呼び出して、OTAを破棄します。
aiot_ota_deinit(&ota_handle);