Agendar e difundir trabalhos (Java)
Use o Hub IoT do Azure para agendar e controlar os trabalhos que atualizam milhões de dispositivos. Use trabalhos para:
- Atualizar as propriedades desejadas
- Marcas de atualização
- Chamar métodos diretos
Um trabalho encapsula uma dessas ações e controla a execução em um conjunto de dispositivos. Uma consulta dispositivo gêmeo define o conjunto de dispositivos para os quais o trabalho é executado. Por exemplo, um aplicativo de back-end pode usar um trabalho para invocar um método direto em 10.000 dispositivos que reinicie os dispositivos. Você especifica o conjunto de dispositivos com uma consulta de dispositivo gêmeo e agenda o trabalho para execução futura. O trabalho controla o andamento conforme cada um dos dispositivos recebe e executa o método direto de reinicialização.
Para saber mais sobre cada uma dessas capacidades, consulte:
Dispositivo gêmeo e propriedades: Introdução aos dispositivos gêmeos e Entender e usar os dispositivos gêmeos no Hub IoT
Métodos direitos: Guia do desenvolvedor no Hub IoT – métodos diretos
Observação
Os recursos descritos neste artigo estão disponíveis apenas na camada padrão do Hub IoT. Para obter mais informações sobre as camadas básica e padrão/gratuita do Hub IoT, confira Escolher a camada certa do Hub IoT para sua solução.
Este artigo mostra como criar dois aplicativos Java:
Um aplicativo de dispositivo, simulated-device, que implementa um método direto chamado lockDoor, que pode ser chamado pelo aplicativo de back-end.
Um aplicativo de back-end, schedule-jobs, que cria dois trabalhos. Um trabalho chama o método direto lockDoor e outro envia atualizações de propriedade desejadas para vários dispositivos.
Observação
Consulte os SDKs da IoT do Azure para obter mais informações sobre as ferramentas do SDK disponíveis para compilar aplicativos de dispositivo e back-end.
Pré-requisitos
Um Hub IoT na assinatura do Azure. Caso você ainda não tenha um hub, poderá seguir as etapas em Criar um hub IoT.
Um dispositivo registrado em seu hub IoT. Se você não tiver um dispositivo em seu hub IoT, siga as etapas em Registrar um dispositivo.
Java SE Development Kit 8. Certifique-se de selecionar Java 8 em Suporte de longo prazo para obter downloads do JDK 8.
Verifique se a porta 8883 está aberta no firewall. O exemplo de dispositivo deste artigo usa o protocolo MQTT, que se comunica pela porta 8883. Essa porta poderá ser bloqueada em alguns ambientes de rede corporativos e educacionais. Para obter mais informações e maneiras de resolver esse problema, confira Como se conectar ao Hub IoT (MQTT).
Observação
Para simplificar, este artigo não implementa nenhuma política de repetição. No código de produção, implemente políticas de repetição (como uma retirada exponencial), conforme sugerido no artigo Tratamento de falhas transitórias.
Obter a cadeia de conexão do Hub IoT
Neste artigo, você cria um serviço de back-end que agenda um trabalho para invocar um método direto em um dispositivo, agenda um trabalho para atualizar o dispositivo gêmeo e monitora o progresso de cada trabalho. Para executar essas operações, o seu serviço precisa das permissões leitura de registro e gravação de registro. Por padrão, todo hub IoT é criado com uma política de acesso compartilhado chamada registryReadWrite que concede essas permissões.
Para obter a cadeia de conexão do Hub IoT para a política registryReadWrite, siga estas etapas:
No portal do Azure, selecione Grupos de recursos. Selecione o grupo de recursos em que o Hub está localizado e, em seguida, selecione o seu hub na lista de recursos.
No painel do lado esquerdo do hub, selecione Políticas de acesso compartilhado.
Na lista de políticas, selecione a política registryReadWrite.
Copie a Cadeia de conexão primária e salve o valor.
Para obter mais informações sobre permissões e políticas de acesso compartilhado do Hub IoT, consulte Controle de acesso e permissões.
Importante
Este artigo inclui etapas para se conectar a um serviço usando uma assinatura de acesso compartilhado. Esse método de autenticação é conveniente para teste e avaliação, mas a autenticação em um serviço com o Microsoft Entra ID ou identidades gerenciadas é uma abordagem mais segura. Para saber mais, consulte Melhores Práticas de Segurança > Segurança da Nuvem.
Criar o aplicativo do serviço
Nesta seção, você cria um aplicativo de console Java que usa trabalhos para:
Chamar o método direto lockDoor em vários dispositivos.
Enviar as propriedades desejadas para vários dispositivos.
Para criar o aplicativo:
No computador de desenvolvimento, crie uma pasta vazia chamada iot-java-schedule-jobs.
Na pasta iot-java-schedule-jobs, crie um projeto Maven chamado schedule-jobs usando o comando a seguir no prompt de comando. Observe que este é um comando único e longo:
mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=schedule-jobs -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
No prompt de comando, navegue até a pasta schedule-jobs.
Usando um editor de texto, abra o arquivo pom.xml na pasta schedule-jobs e adicione a dependência a seguir ao nó dependências. Essa dependência permite que você use o pacote iot-service-client em seu aplicativo para se comunicar com seu hub IoT:
<dependency> <groupId>com.microsoft.azure.sdk.iot</groupId> <artifactId>iot-service-client</artifactId> <version>1.17.1</version> <type>jar</type> </dependency>
Observação
Você pode verificar a versão mais recente do iot-service-client usando a pesquisa do Maven.
Adicione o seguinte nó buid após o nó dependencies. Esta configuração instrui o Maven a usar Java 1.8 para compilar o aplicativo:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.3</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build>
Salve e feche o arquivo pom.xml.
Usando um editor de texto, abra o arquivo schedule-jobs\src\main\java\com\mycompany\app\App.java.
Adicione as seguintes instruções import ao arquivo:
import com.microsoft.azure.sdk.iot.service.devicetwin.DeviceTwinDevice; import com.microsoft.azure.sdk.iot.service.devicetwin.Pair; import com.microsoft.azure.sdk.iot.service.devicetwin.Query; import com.microsoft.azure.sdk.iot.service.devicetwin.SqlQuery; import com.microsoft.azure.sdk.iot.service.jobs.JobClient; import com.microsoft.azure.sdk.iot.service.jobs.JobResult; import com.microsoft.azure.sdk.iot.service.jobs.JobStatus; import java.util.Date; import java.time.Instant; import java.util.HashSet; import java.util.Set; import java.util.UUID;
Adicione as seguintes variáveis no nível da classe à classe App . Substitua
{youriothubconnectionstring}
pela cadeia de conexão do seu hub IoT, que você copiou anteriormente em Obter a cadeia de conexão do hub IoT:public static final String iotHubConnectionString = "{youriothubconnectionstring}"; public static final String deviceId = "myDeviceId"; // How long the job is permitted to run without // completing its work on the set of devices private static final long maxExecutionTimeInSeconds = 30;
Adicione o método a seguir à classe Aplicativo para agendar um trabalho para atualizar as propriedades Prédio e Andar desejadas no dispositivo gêmeo:
private static JobResult scheduleJobSetDesiredProperties(JobClient jobClient, String jobId) { DeviceTwinDevice twin = new DeviceTwinDevice(deviceId); Set<Pair> desiredProperties = new HashSet<Pair>(); desiredProperties.add(new Pair("Building", 43)); desiredProperties.add(new Pair("Floor", 3)); twin.setDesiredProperties(desiredProperties); // Optimistic concurrency control twin.setETag("*"); // Schedule the update twin job to run now // against a single device System.out.println("Schedule job " + jobId + " for device " + deviceId); try { JobResult jobResult = jobClient.scheduleUpdateTwin(jobId, "deviceId='" + deviceId + "'", twin, new Date(), maxExecutionTimeInSeconds); return jobResult; } catch (Exception e) { System.out.println("Exception scheduling desired properties job: " + jobId); System.out.println(e.getMessage()); return null; } }
Para agendar um trabalho para chamar o método lockDoor, adicione o método a seguir à classe Aplicativo:
private static JobResult scheduleJobCallDirectMethod(JobClient jobClient, String jobId) { // Schedule a job now to call the lockDoor direct method // against a single device. Response and connection // timeouts are set to 5 seconds. System.out.println("Schedule job " + jobId + " for device " + deviceId); try { JobResult jobResult = jobClient.scheduleDeviceMethod(jobId, "deviceId='" + deviceId + "'", "lockDoor", 5L, 5L, null, new Date(), maxExecutionTimeInSeconds); return jobResult; } catch (Exception e) { System.out.println("Exception scheduling direct method job: " + jobId); System.out.println(e.getMessage()); return null; } };
Para monitorar um trabalho, adicione o seguinte método à classe Aplicativo:
private static void monitorJob(JobClient jobClient, String jobId) { try { JobResult jobResult = jobClient.getJob(jobId); if(jobResult == null) { System.out.println("No JobResult for: " + jobId); return; } // Check the job result until it's completed while(jobResult.getJobStatus() != JobStatus.completed) { Thread.sleep(100); jobResult = jobClient.getJob(jobId); System.out.println("Status " + jobResult.getJobStatus() + " for job " + jobId); } System.out.println("Final status " + jobResult.getJobStatus() + " for job " + jobId); } catch (Exception e) { System.out.println("Exception monitoring job: " + jobId); System.out.println(e.getMessage()); return; } }
Para consultar detalhes dos trabalhos que você executou, adicione o seguinte método:
private static void queryDeviceJobs(JobClient jobClient, String start) throws Exception { System.out.println("\nQuery device jobs since " + start); // Create a jobs query using the time the jobs started Query deviceJobQuery = jobClient .queryDeviceJob(SqlQuery.createSqlQuery("*", SqlQuery.FromType.JOBS, "devices.jobs.startTimeUtc > '" + start + "'", null).getQuery()); // Iterate over the list of jobs and print the details while (jobClient.hasNextJob(deviceJobQuery)) { System.out.println(jobClient.getNextJob(deviceJobQuery)); } }
Atualize a assinatura do método principal para incluir a seguinte cláusula
throws
:public static void main( String[] args ) throws Exception
Para executar e monitorar dois trabalhos sequencialmente, substitua o código no método main pelo seguinte código:
// Record the start time String start = Instant.now().toString(); // Create JobClient JobClient jobClient = JobClient.createFromConnectionString(iotHubConnectionString); System.out.println("JobClient created with success"); // Schedule twin job desired properties // Maximum concurrent jobs is 1 for Free and S1 tiers String desiredPropertiesJobId = "DPCMD" + UUID.randomUUID(); scheduleJobSetDesiredProperties(jobClient, desiredPropertiesJobId); monitorJob(jobClient, desiredPropertiesJobId); // Schedule twin job direct method String directMethodJobId = "DMCMD" + UUID.randomUUID(); scheduleJobCallDirectMethod(jobClient, directMethodJobId); monitorJob(jobClient, directMethodJobId); // Run a query to show the job detail queryDeviceJobs(jobClient, start); System.out.println("Shutting down schedule-jobs app");
Salve e feche o arquivo schedule-jobs\src\main\java\com\mycompany\app\App.java
Compile o aplicativo schedule-jobs e corrija eventuais erros. No prompt de comando, navegue até a pasta schedule-jobs e execute o seguinte comando:
mvn clean package -DskipTests
Criar um aplicativo de dispositivo
Nesta seção, você deve criar um aplicativo de console de Java que manipule as propriedades desejadas enviadas do Hub IoT e implemente a chamada de método direto.
Importante
Este artigo inclui etapas para conectar um dispositivo usando uma assinatura de acesso compartilhado, também chamada de autenticação de chave simétrica. Esse método de autenticação é conveniente para teste e avaliação, mas a autenticação em um dispositivo que usa certificados X.509 é uma abordagem mais segura. Para saber mais, consulte Melhores práticas de segurança> em Conexão de segurança.
Na pasta iot-java-schedule-jobs, crie um projeto Maven denominado simulated-device usando o comando a seguir no prompt de comando. Observe que este é um comando único e longo:
mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=simulated-device -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
No prompt de comando, navegue até a pasta simulated-device.
Usando um editor de texto, abra o arquivo pom.xml na pasta simulated-device e adicione as seguintes dependências ao nó dependências. Essa dependência permite que você use o pacote iot-device-client em seu aplicativo para se comunicar com seu hub IoT:
<dependency> <groupId>com.microsoft.azure.sdk.iot</groupId> <artifactId>iot-device-client</artifactId> <version>1.17.5</version> </dependency>
Observação
Você pode verificar a versão mais recente do iot-device-client usando a pesquisa do Maven.
Adicione a dependência a seguir ao nó dependências. Essa dependência configura um NOP para a fachada de log do Apache SLF4J, que é usada pelo SDK do cliente do dispositivo para implementar o registro em log. Essa configuração é opcional, mas, se você omiti-la, poderá ver um aviso no console ao executar o aplicativo. Para obter mais informações sobre o registro em log no SDK de cliente do dispositivo, consulte Registro em log no arquivo Leiame Exemplos do SDK do dispositivo IoT do Azure para Java.
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-nop</artifactId> <version>1.7.28</version> </dependency>
Adicione o seguinte nó buid após o nó dependencies. Esta configuração instrui o Maven a usar Java 1.8 para compilar o aplicativo:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.3</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build>
Salve e feche o arquivo pom.xml.
Usando um editor de texto, abra o arquivo simulated-device\src\main\java\com\mycompany\app\App.java.
Adicione as seguintes instruções import ao arquivo:
import com.microsoft.azure.sdk.iot.device.*; import com.microsoft.azure.sdk.iot.device.DeviceTwin.*; import java.io.IOException; import java.net.URISyntaxException; import java.util.Scanner;
Adicione as seguintes variáveis no nível da classe à classe App . Substitua
{yourdeviceconnectionstring}
pela cadeia de conexão de dispositivo que você viu quando registrou um dispositivo no Hub IoT:private static String connString = "{yourdeviceconnectionstring}"; private static IotHubClientProtocol protocol = IotHubClientProtocol.MQTT; private static final int METHOD_SUCCESS = 200; private static final int METHOD_NOT_DEFINED = 404;
Este aplicativo de exemplo usa a variável protocol quando cria uma instância de um objeto DeviceClient.
Para imprimir notificações do dispositivo gêmeo para o console, adicione a seguinte classe aninhada à classe App:
// Handler for device twin operation notifications from IoT Hub protected static class DeviceTwinStatusCallBack implements IotHubEventCallback { public void execute(IotHubStatusCode status, Object context) { System.out.println("IoT Hub responded to device twin operation with status " + status.name()); } }
Para imprimir notificações do método direto para o console, adicione a seguinte classe aninhada à classe App:
// Handler for direct method notifications from IoT Hub protected static class DirectMethodStatusCallback implements IotHubEventCallback { public void execute(IotHubStatusCode status, Object context) { System.out.println("IoT Hub responded to direct method operation with status " + status.name()); } }
Para manipular chamadas de método direto do Hub IoT, adicione a seguinte classe aninhada à classe App:
// Handler for direct method calls from IoT Hub protected static class DirectMethodCallback implements DeviceMethodCallback { @Override public DeviceMethodData call(String methodName, Object methodData, Object context) { DeviceMethodData deviceMethodData; switch (methodName) { case "lockDoor": { System.out.println("Executing direct method: " + methodName); deviceMethodData = new DeviceMethodData(METHOD_SUCCESS, "Executed direct method " + methodName); break; } default: { deviceMethodData = new DeviceMethodData(METHOD_NOT_DEFINED, "Not defined direct method " + methodName); } } // Notify IoT Hub of result return deviceMethodData; } }
Atualize a assinatura do método principal para incluir a seguinte cláusula
throws
:public static void main( String[] args ) throws IOException, URISyntaxException
Substitua o código no método main pelo seguinte código para:
- Criar um cliente de dispositivo para se comunicar com o Hub IoT.
- Criar um objeto Dispositivo para armazenar as propriedades do dispositivo gêmeo.
// Create a device client DeviceClient client = new DeviceClient(connString, protocol); // An object to manage device twin desired and reported properties Device dataCollector = new Device() { @Override public void PropertyCall(String propertyKey, Object propertyValue, Object context) { System.out.println("Received desired property change: " + propertyKey + " " + propertyValue); } };
Para iniciar os serviços de cliente do dispositivo, adicione o seguinte código ao método main:
try { // Open the DeviceClient // Start the device twin services // Subscribe to direct method calls client.open(); client.startDeviceTwin(new DeviceTwinStatusCallBack(), null, dataCollector, null); client.subscribeToDeviceMethod(new DirectMethodCallback(), null, new DirectMethodStatusCallback(), null); } catch (Exception e) { System.out.println("Exception, shutting down \n" + " Cause: " + e.getCause() + " \n" + e.getMessage()); dataCollector.clean(); client.closeNow(); System.out.println("Shutting down..."); }
Para aguardar o usuário pressionar a tecla Enter antes de desligar, adicione o seguinte código ao final do método main:
// Close the app System.out.println("Press any key to exit..."); Scanner scanner = new Scanner(System.in); scanner.nextLine(); dataCollector.clean(); client.closeNow(); scanner.close();
Salve e feche o arquivo simulated-device\src\main\java\com\mycompany\app\App.java.
Compile o aplicativo simulated-device e corrija os erros. No prompt de comando, navegue até a pasta simulated-device e execute o seguinte comando:
mvn clean package -DskipTests
Executar os aplicativos
Agora você está pronto para executar os aplicativos de console.
Em um prompt de comando na pasta simulated-device, execute o seguinte comando para iniciar o aplicativo de dispositivo escutando alterações de propriedades desejadas e chamadas de método direto:
mvn exec:java -Dexec.mainClass="com.mycompany.app.App"
Em um prompt de comando na pasta
schedule-jobs
, execute o comando a seguir para executar o aplicativo de serviço schedule-jobs para executar dois trabalhos. O primeiro define os valores de propriedade desejados, o segundo chama o método direto:mvn exec:java -Dexec.mainClass="com.mycompany.app.App"
O aplicativo de dispositivo manipula a alteração da propriedade desejada e a chamada de método direto:
Próximas etapas
Neste artigo, você agendou trabalhos para executar um método direto e atualizar as propriedades do dispositivo gêmeo.
Para continuar explorando os padrões de Hub IoT e de gerenciamento de dispositivo, atualize uma imagem no tutorial Atualização de dispositivo para o Hub IoT do Azure usando a imagem de referência do Raspberry Pi 3 B +.