Este artigo descreve como chamar as operações de API do Link SDK for C para implementar device jobs. Este exemplo utiliza o arquivo de código de amostra ./demos/task_posix_demo.c.
Informações básicas
Para obter mais informações sobre device jobs, consulte Visão geral.
usa conexões MQTT. Para exemplos de código relacionados, consulte Conexão MQTT.
Etapa 1: Inicialização
-
Adicione os arquivos de cabeçalho.
... ... #include "aiot_task_api.h" -
Configure as dependências subjacentes e a saída de log.
aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile); aiot_state_set_logcb(demo_state_logcb); -
Chame a operação aiot_task_init() para criar uma instância cliente
taske inicializar os parâmetros padrão.task_handle = aiot_task_init(); if (task_handle == NULL) { demo_mqtt_stop(&mqtt_handle); printf("aiot_task_init failed\n"); return -1; }
Etapa 2: Configurar recursos
Chame a operação aiot_task_setopt() para configurar os seguintes itens:
-
Associe um handle de conexão MQTT.
ImportanteAntes de definir parâmetros específicos de device job, configure parâmetros como credenciais do dispositivo. Para obter mais informações, consulte Configurar parâmetros de conexão para MQTT.
-
Código de amostra:
aiot_task_setopt(task_handle, AIOT_TASKOPT_MQTT_HANDLE, mqtt_handle); -
Parâmetros:
Parâmetro
Exemplo
Descrição
AIOT_TASKOPT_MQTT_HANDLE
mqtt_handle
As solicitações TSL utilizam esta conexão.
-
-
Configure um callback de mensagem.
-
Código de amostra
aiot_task_setopt(task_handle, AIOT_TASKOPT_RECV_HANDLER, demo_task_recv_handler); -
Parâmetros:
Parâmetro
Exemplo
Descrição
AIOT_TASKOPT_RECV_HANDLER
demo_task_recv_handler
O sistema chama esta função ao receber uma mensagem específica de device job.
-
Etapa 3: Receber uma notificação de job downstream
Se o IoT Platform enviar uma notificação de job enquanto o dispositivo estiver online, execute as etapas a seguir para processar a notificação:
Faça login no IoT Platform console e crie um device job.
-
Após a criação do device job, o IoT Platform envia uma notificação ao dispositivo. Quando o dispositivo recebe essa notificação, o sistema aciona o callback
demo_task_recv_handler.Ao definir a lógica do callback, observe os seguintes itens:
aiot_task_recv_t é um parâmetro de entrada do callback e indica o formato dos dados.
AIOT_TASKRECV_NOTIFY indica o tipo de mensagem.
-
A tabela a seguir descreve um exemplo de notificação e o formato de dados Alink correspondente.
Exemplo
Formato de dados Alink
Descrição
{ "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" } } } }O conteúdo da mensagem está no formato JSON e corresponde ao valor do parâmetro params nos dados Alink.
O dispositivo executa as tarefas do job e envia os status correspondentes ao IoT Platform. Para obter mais informações sobre como atualizar tarefas, consulte Etapa 5: Atualizar os status das tarefas do job.
-
Este exemplo não fornece a lógica para executar as tarefas. Especifique a lógica de processamento conforme as necessidades do seu negócio.
void demo_task_recv_handler(void *handle, const aiot_task_recv_t *packet, void *userdata) { switch (packet->type) { case 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.If no job records exist in the handle, save the job that is sent by IoT Platform to the default_task_desc field in the handle. */ if (NULL == g_local_task_desc) { demo_copy_task_to_local_task(&g_local_task_desc, in_desc); /* Start the job. In this example, the job information is printed. You can specify the logic based on your business needs. */ 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 { /* Set the type of the downloading thread to detach. After the firmware is obtained, the downloading thread automatically exits. */ pthread_detach(g_task_thread); } /* Change the job status.TODO: The following code is for reference only. After the job is completed, you must set the status to AIOT_TASK_STATUS_SUCCEEDED. */ g_local_task_desc->status = AIOT_TASK_STATUS_IN_PROGRESS; aiot_task_update(handle, g_local_task_desc); demo_free_local_task(&g_local_task_desc); break; } /* 2.If the job status is set to the final status by IoT Platform, the local job is cleared. */ if (in_desc->status == AIOT_TASK_STATUS_CANCELLED || in_desc->status == AIOT_TASK_STATUS_REMOVED || in_desc->status == AIOT_TASK_STATUS_TIMED_OUT) { /* TODO: Clear the local job and stop the thread. */ /* If the job is the default job recorded in the handle, clear the memory of the job. Otherwise, you must maintain the memory of the job. */ if (NULL != g_local_task_desc && 0 == strcmp(in_desc->task_id, g_local_task_desc->task_id)) { /* Release the memory of the local job. */ demo_free_local_task(&g_local_task_desc); } break; } /* 3.If a local job already exists, IoT Platform updates the description of the job. You must check the updated description. */ 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: Update the description of the local job. You can suspend the current job based on your business needs. * / break; } } /* 4.In other cases, the received job is determined as a new job. If a job is running and a new job is received, you can create a list in the main() function. */ /* Pass in the list as the userdata parameter and record all jobs in this list for maintenance. */ break; } …… ... }
Etapa 4: Solicitar um device job
Após colocar o dispositivo online, solicite um device job.
-
Chame a operação aiot_task_get_task_detail para enviar uma solicitação ao IoT Platform. Se você definir o parâmetro como NULL, será possível obter as informações sobre o primeiro job ainda não executado.
NotaCaso o IoT Platform envie múltiplos device jobs para o dispositivo, chame a operação aiot_task_get_task_list para consultar os device jobs antes de receber as notificações. Em seguida, consulte as informações de cada device job individualmente.
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; } Ao receber a solicitação, o IoT Platform retorna as informações do device job criado para o dispositivo.
-
Quando o dispositivo recebe a notificação do job, o sistema aciona o callback
demo_task_recv_handler.Ao definir a lógica do callback, observe os seguintes itens:
aiot_task_recv_t é um parâmetro de entrada do callback e indica o formato dos dados.
AIOT_TASKRECV_GET_DETAIL_REPLY indica o tipo de mensagem.
-
A tabela a seguir descreve um exemplo de notificação e o formato de dados Alink correspondente.
Exemplo
Formato de dados Alink
Descrição
{ "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" } } } }O conteúdo da mensagem está no formato JSON e corresponde ao valor do parâmetro params nos dados Alink.
O dispositivo executa as tarefas do job e envia os status correspondentes ao IoT Platform. Para obter mais informações sobre como atualizar tarefas, consulte Etapa 5: Atualizar os status das tarefas do job.
-
Este exemplo não fornece a lógica para executar as tarefas. Especifique a lógica de processamento conforme as necessidades do seu negócio.
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.document_file_url, in_reply->task.sign_method, in_reply->task.sign); task_desc_t task; memset(&task, 0, sizeof(task)); memcpy(&task, &(in_reply->task), sizeof(task)); /* TODO: Implement the job by starting a thread. */ /* Change the job status. TODO: The following code is for reference only. You can specify the logic based on your business needs. After the task is completed, set the status to AIOT_TASK_STATUS_SUCCEEDED. */ task.status = AIOT_TASK_STATUS_IN_PROGRESS; task.progress = 88; aiot_task_update(handle, &task); } } break; } …… ... }
Etapa 5: Atualizar os status das tarefas do job
Depois que o dispositivo obtém as informações do job e executa suas tarefas, ele deve enviar os status das tarefas para o IoT Platform.
-
Chame a operação aiot_task_update para enviar os status das tarefas ao IoT Platform.
Ao enviar os status das tarefas, observe os seguintes itens:
task_desc_t indica o formato dos dados.
aiot_task_update indica a operação de API.
-
O exemplo a seguir mostra uma mensagem no formato Alink.
NotaO conteúdo da mensagem está no formato JSON e corresponde ao valor do parâmetro params nos dados Alink.
{ "id": "123", "version": "1.0", "params": { "taskId": "i5Ks***F010101", "status": "IN_PROGRESS", "statusDetails": { "key": "value" }, "progress": 50 } }O conteúdo da mensagem está no formato JSON e corresponde ao valor do parâmetro params nos dados Alink. O conteúdo da mensagem está no formato JSON e corresponde ao valor do parâmetro params nos dados Alink. Nota: O conteúdo da mensagem está no formato JSON e corresponde ao valor do parâmetro params nos dados Alink. O conteúdo da mensagem está no formato JSON e corresponde ao valor do parâmetro params nos dados Alink.
-
Neste exemplo, o sistema envia o status AIOT_TASK_STATUS_IN_PROGRESS. Em cenários reais de negócios, obtenha os status das tarefas e envie-os adequadamente.
-
Código de amostra para a Etapa 3
g_local_task_desc->status = AIOT_TASK_STATUS_IN_PROGRESS; aiot_task_update(handle, g_local_task_desc); demo_free_local_task(&g_local_task_desc); -
Código de amostra para a Etapa 4
task.status = AIOT_TASK_STATUS_IN_PROGRESS; task.progress = 88; aiot_task_update(handle, &task);
-
-
Após o envio dos status das tarefas, o IoT Platform retorna uma mensagem de resposta. Nesse momento, o sistema aciona o callback
demo_task_recv_handler.Ao definir a lógica do callback, observe os seguintes itens:
aiot_task_recv_t é um parâmetro de entrada do callback e indica o formato dos dados.
AIOT_TASKRECV_UPDATE_REPLY indica o tipo de mensagem.
-
Este exemplo não fornece a lógica para executar as tarefas. Especifique a lógica de processamento conforme as necessidades do seu negócio.
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 task's status_details value must be json format\r\n"); } /* TODO */ break; } …… ... }
Etapa 6: Sair do programa
Chame a operação aiot_task_deinit() para destruir a instância cliente task e liberar recursos.
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;
}
Etapa 7: Encerrar a conexão
O protocolo MQTT é geralmente utilizado em dispositivos que exigem conexão persistente. Por isso, o programa normalmente não chega a este ponto.
No programa de amostra, a thread principal configura parâmetros e estabelece a conexão. Após o estabelecimento da conexão, a thread principal pode entrar em hibernação.
Chame aiot_mqtt_disconnect para enviar uma mensagem de desconexão ao IoT Platform e encerrar a conexão de rede.
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;
}
Próximos passos
-
Após configurar o arquivo de código de amostra, compile-o para gerar um arquivo executável. Neste exemplo, o sistema gera o arquivo executável ./output/task_posix_demo.
Para obter mais informações, consulte Compilar e executar.
Para obter mais informações sobre os resultados da execução, consulte Logs de operação.