デバイスジョブを実装し。、。/demos/task_posix_demo.cサンプルコードファイルを使用します。
背景情報
ステップ1: クライアントの初期化
ヘッダーファイルの追加
を含む... ... # 「aiot_task_api.h」
基になる依存関係を追加し、ログ出力機能を設定します。
aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile); aiot_state_set_logcb(demo_state_logcb);
aiot_task_init() 操作を呼び出して、
タスク
を作成します。task_handle = aiot_task_init(); if (task_handle == NULL) { demo_mqtt_stop(&mqtt_handle); printf("aiot_task_init failed\n"); return -1; }
ステップ2: 機能の設定
aiot_task_setopt() 操作を呼び出して、次の項目を設定します。
MQTT接続ハンドルに関連付けます。
重要デバイスジョブ固有のパラメーターを設定する前に、デバイス認証情報が指定されていることを確認してください。 詳細については、「例」をご参照ください。
aiot_task_setopt(task_handle、AIOT_TASKOPT_MQTT_HANDLE、mqtt_handle);
パラメーター
例
説明
AIOT_TASKOPT_MQTT_HANDLE
mqtt_handle
MQTT接続を確立する必要があります。 このパラメータは、MQTT接続ハンドルに関連付けるために使用されます。
メッセージコールバックの設定
aiot_task_setopt(task_handle、AIOT_TASKOPT_RECV_HANDLER、demo_task_recv_handler);
パラメーター
例
説明
AIOT_TASKOPT_RECV_HANDLER
demo_task_recv_handler
デバイスジョブ固有のメッセージが受信されると、この関数が呼び出される。
ステップ3: ダウンストリームジョブ通知の受信
デバイスがオンラインのときにIoT Platformがジョブ通知を送信する場合、次の手順を実行して通知を処理します。
IoT Platformコンソールにログインし、デバイスジョブを作成します。
デバイスジョブを作成すると、IoT Platformはデバイスに通知を送信します。 デバイスが通知を受信すると、
demo_task_recv_handler
コールバックが呼び出されます。コールバックの処理ロジックを指定する場合は、次の項目に注意してください。
aiot_task_recv_tはコールバックの入力パラメーターです。 このパラメーターは、データ形式を示します。
AIOT_TASKRECV_NOTIFYはメッセージタイプを示します。
次の表に、通知例と通知のAlinkデータ形式を示します。
例
Alinkデータ形式
説明
{ "task": { "taskId": "i5Ks6 *** pF010101" 、 "status": "SENT" 、 "jobDocument": { }, "jobFile": { "signMethod": "Md5" 、 "sign": "wssxff56dhdsd ***" 、 "fileUrl": "https:// iotx-*** .aliyuncs.com/***.zip" } } }
{ "id": "7542940" 、 "version": "1.0"、 "params": { "task": { "taskId": "i5Ks6 *** pF010101" 、 "status": "SENT" 、 "jobDocument": { }, "jobFile":{ "signMethod":"Md5" 、 "sign":"wssxff56dhdsd ***" 、 "fileUrl": "https:// iotx-*** .aliyuncs.com/***.zip" } } } }
メッセージの内容はJSON形式です。 コンテンツは、Alinkデータのparamsパラメーターの値です。
デバイスはジョブの下にタスクを実装し、タスクのステータスをIoT Platformに送信します。 タスクを更新する方法の詳細については、「手順5: ジョブのタスクのステータスを更新する」をご参照ください。
この例では、タスクを実装するロジックは提供されていません。 ビジネスニーズに基づいて処理ロジックを指定する必要があります。
void demo_task_recv_handler(void * handle, const aiot_task_recv_t * packet, void * userdata) { switch (packet->type) { ケースAIOT_TASKRECV_NOTIFY: { const task_desc_t * in_desc = &(packet->data.notify); printf("revice task notify, task_id:[% s],status:[% d],job_document[% s],document_file_url:[% s],\ sign_method:[% s],sign[% s]\r\n ", in_desc->task_id、in_desc->status、in_desc->job_document、 in_desc->document_file_url、in_desc->sign_method、in_desc->sign); /* 1. ハンドルにジョブレコードが存在しない場合、IoT Platformによって送信されたジョブをハンドルのdefault_task_descフィールドに保存します。 */ if (NULL == g_local_task_desc) { demo_copy_task_to_local_task(&g_local_task_desc、in_desc); /* ジョブを開始します。 この例では、ジョブ情報が印刷される。 ビジネスニーズに基づいてロジックを指定できます。 */ int res = pthread_create(&g_task_thread, NULL, demo_task_thread, g_local_task_desc); if (res != 0) { printf("pthread_create demo_task_thread failed: % d\r\n", res); } else { /* デタッチするダウンロードスレッドのタイプを設定します。 ファームウェアが取得されると、ダウンロードスレッドは自動的に終了します。 */ pthread_detach(g_task_thread); } /* ジョブのステータスを変更します。TODO: 次のコードは参照用です。 ジョブが完了したら、ステータスをAIOT_TASK_STATUS_SUCCEEDEDに設定する必要があります。 */ g_local_task_desc->status = AIOT_TASK_STATUS_IN_PROGRESS; aiot_task_update (ハンドル、g_local_task_desc); demo_free_local_task(&g_local_task_desc); break; } /* 2. IoT Platformによってジョブステータスが最終ステータスに設定されている場合、ローカルジョブはクリアされます。 */ if (in_desc->status == AIOT_TASK_STATUS_CANCELLED | | in_desc->status ==AIOT_TASK_STATUS_REMOED | | in_desc->status == AIOT_TASK_STATUS_TIMED_OUT) { /* TODO: ローカルジョブをクリアし、スレッドを停止します。 */ /* ジョブがハンドルに記録されているデフォルトのジョブの場合は、ジョブのメモリをクリアします。 それ以外の場合は、ジョブのメモリを維持する必要があります。 */ if (NULL != g_local_task_desc&0 == strcmp(in_desc->task_id, g_local_task_desc->task_id)) { /* ローカルジョブのメモリを解放します。 */ demo_free_local_task(&g_local_task_desc); } break; } /* 3.ローカルジョブがすでに存在する場合、IoT Platformはジョブの説明を更新します。 更新された説明を確認する必要があります。 */ if (in_desc->status == AIOT_TASK_STATUS_IN_PROGRESS) { if (NULL != g_local_task_desc&0 == strcmp(in_desc->task_id, g_local_task_desc->task_id)) { /* TODO: ローカルジョブの説明を更新します。 ビジネスニーズに基づいて、現在のジョブを一時停止できます。 * / break; } } /* 4. その他の場合は、受信したジョブを新規ジョブと判定する。 ジョブが実行中で、新しいジョブを受信した場合は、main() 関数でリストを作成できます。 */ /* リストをuserdataパラメータとして渡し、このリストのすべてのジョブをメンテナンス用に記録します。 */ break; } …… ... }
ステップ4: デバイスジョブを要求する
デバイスがオンラインになったら、デバイスジョブをリクエストできます。
aiot_task_get_task_detail操作を呼び出して、IoT Platformにリクエストを送信します。 パラメーターをNULLに設定すると、パラメーターに関する情報を取得できます。 第一 実装されていないジョブ。
説明IoT Platformが複数のデバイスジョブをデバイスにプッシュする場合、ジョブ通知を受信する前にaiot_task_get_task_list操作を呼び出してデバイスジョブを照会できます。 次に、各デバイスジョブに関する情報を照会できます。
res = aiot_task_get_task_detail(task_handle、NULL); if (res < STATE_SUCCESS) { aiot_task_deinit(&task_handle); demo_mqtt_stop(&mqtt_handle); return -1; }
IoT Platformがリクエストを受信すると、IoT Platformは作成したデバイスジョブ情報をデバイスに返します。
デバイスがジョブ通知を受信すると、
demo_task_recv_handler
コールバックが呼び出されます。コールバックの処理ロジックを指定する場合は、次の項目に注意してください。
aiot_task_recv_tはコールバックの入力パラメーターです。 このパラメーターは、データ形式を示します。
AIOT_TASKRECV_GET_DETAIL_REPLYはメッセージタイプを示します。
次の表に、通知例と通知のAlinkデータ形式を示します。
例
Alinkデータ形式
説明
{ "taskId": "i5Ks *** F010101" 、 "status": "IN_PROGRESS" 、 "jobDocument": { }, "jobFile":{ "signMethod":"Md5" 、 "sign":"wssxff56dhdsd ***" 、 "fileUrl": "https:// iotx-*** .aliyuncs.com/***.zip" } }
{ "id": "1234" 、 "code": 200, "data": { "taskId": "$next" 、 "task":{ "taskId": "i5Ks *** F010101" 、 "status": "IN_PROGRESS" 、 "jobDocument": { }, "jobFile":{ "signMethod":"Md5" 、 "sign":"wssxff56dhdsd ***" 、 "fileUrl": "https:// iotx-*** .aliyuncs.com/***.zip" } } } }
メッセージの内容はJSON形式です。 コンテンツは、Alinkデータのparamsパラメーターの値です。
デバイスはジョブの下にタスクを実装し、タスクのステータスをIoT Platformに送信します。 タスクを更新する方法の詳細については、「手順5: ジョブのタスクのステータスを更新する」をご参照ください。
この例では、タスクを実装するロジックは提供されていません。 ビジネスニーズに基づいて処理ロジックを指定する必要があります。
void demo_task_recv_handler(void * handle, const aiot_task_recv_t * packet, void * userdata) { switch (packet->type) { ... ... case AIOT_TASKRECV_GET_DETAIL_REPLY: { const task_get_detail_reply_t * in_reply = &(packet->data.get_detail_reply); printf("revice task get detail, code:[% d]\r\n", in_reply->code); if (200 == in_reply->code) { printf("revice task get detail reply, task_id:[% s],status:[% d]\r\n", in_reply->task.task_id, in_reply->task.status); if (in_reply->task.status != AIOT_TASK_STATUS_NOT_FOUND) { printf("job_document[% s],document_file_url:[% s], sign_method:[% s], sign[% s]\r\n", in_reply->task.job_document, in_reply->task.doc ument_file_url, in_reply->task.sign_method, in_reply->task.sign); task_desc_tタスク; memset(&task, 0, sizeof(task)); memcpy(&task, &(in_reply->task), sizeof(task)); /* TODO: スレッドを起動してジョブを実装します。 */ /* ジョブのステータスを変更します。 TODO: 次のコードは参考用です。 ビジネスニーズに基づいてロジックを指定できます。 タスクが完了したら、ステータスをAIOT_TASK_STATUS_SUCCEEDEDに設定します。 */ task.status = AIOT_TASK_STATUS_IN_PROGRESS; task.progress = 88; aiot_task_update (ハンドル、タスク); } } break; } …… ... }
ステップ5: ジョブ配下のタスクのステータスを更新する
デバイスがジョブ情報を取得し、ジョブの下にタスクを実装した後、デバイスはタスクステータスをIoT Platformに送信する必要があります。
aiot_task_update操作を呼び出して、タスクステータスをIoT Platformに送信します。
タスクのステータスを送信するときは、次の項目に注意してください。
task_desc_tはデータ形式を示します。
aiot_task_updateはAPI操作を示します。
Alink形式のメッセージの例を次に示します。
説明メッセージの内容はJSON形式です。 コンテンツは、Alinkデータのparamsパラメーターの値です。
{ "id": "123", "version": "1.0"、 "params": { "taskId": "i5Ks *** F010101" 、 "status": "IN_PROGRESS" 、 "statusDetails": { "キー": "値" }, "progress": 50 } }
メッセージの内容はJSON形式です。 コンテンツは、Alinkデータのparamsパラメーターの値です。メッセージの内容はJSON形式です。 内容は、Alinkデータのparamsパラメーターの値です。注メッセージの内容はJSON形式です。 コンテンツは、Alinkデータのparamsパラメーターの値です。 メッセージの内容はJSON形式です。 コンテンツは、Alinkデータのparamsパラメーターの値です。
この例では、AIOT_TASK_STATUS_IN_PROGRESSステータスが送信されています。 実際のビジネスシナリオでタスクのステータスを取得し、ステータスを送信する必要があります。
ステップ3のサンプルコード
g_local_task_desc->status = AIOT_TASK_STATUS_IN_PROGRESS; aiot_task_update (ハンドル、g_local_task_desc); demo_free_local_task(&g_local_task_desc);
ステップ4のサンプルコード
task.status = AIOT_TASK_STATUS_IN_PROGRESS; task.progress = 88; aiot_task_update (ハンドル、タスク);
タスクステータスが送信されると、IoT Platformは応答メッセージを返します。 この場合、
demo_task_recv_handler
コールバックが呼び出されます。コールバックの処理ロジックを指定する場合は、次の項目に注意してください。
aiot_task_recv_tはコールバックの入力パラメーターです。 このパラメーターは、データ形式を示します。
AIOT_TASKRECV_UPDATE_REPLYはメッセージタイプを示します。
この例では、タスクを実装するロジックは提供されていません。 ビジネスニーズに基づいて処理ロジックを指定する必要があります。
void demo_task_recv_handler(void * handle, const aiot_task_recv_t * packet, void * userdata) { switch (packet->type) { ... ... case AIOT_TASKRECV_UPDATE_REPLY: { const task_update_reply_t * update_reply = &(packet->data.update_reply); printf("revice task update reply, code:[% d]\r\n", update_reply->code); if (200 == update_reply->code) { printf("revice task update reply, task_id:[% s]\r\n", update_reply->task_id); } if (71012 == update_reply->code) { printf("aiot_task_updateタスクのstatus_details値はjson format\r\n" でなければなりません); } /* TODO * / break; } …… ... }
ステップ6: プログラムを終了する
aiot_task_deinit() 操作を呼び出して、タスク
を破棄します。
res = aiot_task_deinit(&task_handle);
if (res < STATE_SUCCESS) {
demo_mqtt_stop(&mqtt_handle);
printf("aiot_task_deinit failed: -0x % 04X\n" 、-res);
return -1;
}
ステップ7: 接続を終了する
MQTT接続は、永続的に接続されたままのデバイスに適用されます。 IoT Platformからデバイスを手動で切断できます。
この例では、メインスレッドを使用してパラメータを設定し、接続を確立します。 接続が確立されたら、メインスレッドを一時停止できます。
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;
}