Compartilhar via


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:

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.

  • Maven 3

  • 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:

  1. 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.

  2. No painel do lado esquerdo do hub, selecione Políticas de acesso compartilhado.

  3. Na lista de políticas, selecione a política registryReadWrite.

  4. Copie a Cadeia de conexão primária e salve o valor.

    Captura de tela que mostra como recuperar a cadeia de conexão

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:

  1. No computador de desenvolvimento, crie uma pasta vazia chamada iot-java-schedule-jobs.

  2. 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
    
  3. No prompt de comando, navegue até a pasta schedule-jobs.

  4. 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.

  5. 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>
    
  6. Salve e feche o arquivo pom.xml.

  7. Usando um editor de texto, abra o arquivo schedule-jobs\src\main\java\com\mycompany\app\App.java.

  8. 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;
    
  9. 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;
    
  10. 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;
      }
    }
    
  11. 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;
      }
    };
    
  12. 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;
      }
    }
    
  13. 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));
      }
    }
    
  14. Atualize a assinatura do método principal para incluir a seguinte cláusula throws:

    public static void main( String[] args ) throws Exception
    
  15. 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");
    
  16. Salve e feche o arquivo schedule-jobs\src\main\java\com\mycompany\app\App.java

  17. 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.

  1. 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
    
  2. No prompt de comando, navegue até a pasta simulated-device.

  3. 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.

  4. 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>
    
  5. 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>
    
  6. Salve e feche o arquivo pom.xml.

  7. Usando um editor de texto, abra o arquivo simulated-device\src\main\java\com\mycompany\app\App.java.

  8. 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;
    
  9. 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.

  10. 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());
      }
    }
    
  11. 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());
      }
    }
    
  12. 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;
      }
    }
    
  13. Atualize a assinatura do método principal para incluir a seguinte cláusula throws:

    public static void main( String[] args ) throws IOException, URISyntaxException
    
  14. 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);
      }
    };
    
  15. 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...");
    }
    
  16. 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();
    
  17. Salve e feche o arquivo simulated-device\src\main\java\com\mycompany\app\App.java.

  18. 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.

  1. 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"
    

    O cliente do dispositivo é iniciado

  2. 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 serviço de aplicativo de Hub IoT Java cria dois trabalhos

  3. O aplicativo de dispositivo manipula a alteração da propriedade desejada e a chamada de método direto:

    O dispositivo cliente responde às alterações

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 +.