Planen und Übertragen von Aufträgen (Java)

Verwenden Sie Azure IoT Hub zum Planen und Nachverfolgen von Aufträgen, die Millionen von Geräte aktualisieren. Verwenden Sie Aufträge zum:

  • Aktualisieren gewünschter Eigenschaften
  • Aktualisieren von Tags
  • Aufrufen direkter Methoden

Ein Auftrag umschließt eine dieser Aktionen und verfolgt die Ausführung für eine Gruppe von Geräten nach. Mit einer Gerätezwillingsabfrage definieren Sie die Gruppe der Geräte, für die der Auftrag ausgeführt wird. Eine Back-End-App kann z.B. einen Auftrag verwenden, um eine direkte Methode auf 10.000 Geräten aufzurufen, die die Geräte neu startet. Sie geben die Gruppe von Geräten mit einer Gerätezwillingsabfrage ein und planen die Ausführung des Auftrags zu einem späteren Zeitpunkt. Der Auftrag verfolgt den Fortschritt nach, während jedes der Geräte die direkte Methode zum Neustart empfängt und ausführt.

Weitere Informationen zu diesen Funktionen finden Sie unter:

Hinweis

Die in diesem Artikel beschriebenen Features stehen nur im Standard-Tarif von IoT Hub zur Verfügung. Weitere Informationen zu den IoT Hub-Tarifen „Basic“ und „Standard/Free“ finden Sie unter Wählen des richtigen IoT Hub-Tarifs für Ihre Lösung.

In diesem Artikel wird gezeigt, wie Sie zwei Java-Apps erstellen:

  • Eine Geräte-App, simulated-device, die eine direkte Methode namens lockDoor implementiert, die von der Back-End-App aufgerufen werden kann.

  • Eine Back-End-App, schedule-jobs, die zwei Aufträge erstellt. Ein Auftrag ruft die direkte Methode lockDoor auf, und ein anderer Auftrag sendet die gewünschten Eigenschaftenupdates an mehrere Geräte.

Hinweis

Weitere Informationen zu den SDK-Tools zum Erstellen von Geräten und Back-End-Apps finden Sie unter Azure IoT SDKs.

Voraussetzungen

  • Ein IoT Hub in Ihrem Azure-Abonnement. Wenn Sie noch keinen Hub haben, können Sie die Schritte unter Erstellen eines IoT-Hubs ausführen.

  • Ein in Ihrem IoT-Hub registriertes Gerät. Wenn Sie nicht über ein Gerät in Ihrem IoT-Hub verfügen, führen Sie die Schritte unter Registrieren eines Geräts aus.

  • Java SE Development Kit 8 Wählen Sie unter Langfristiger Support unbedingt Java 8 aus, um zu den Downloads für JDK 8 zu gelangen.

  • Maven 3

  • Stellen Sie sicher, dass der Port 8883 in Ihrer Firewall geöffnet ist. Das Beispielgerät in diesem Artikel verwendet das MQTT-Protokoll, das über Port 8883 kommuniziert. In einigen Netzwerkumgebungen von Unternehmen oder Bildungseinrichtungen ist dieser Port unter Umständen blockiert. Weitere Informationen und Problemumgehungen finden Sie unter Herstellen einer Verbindung mit IoT Hub (MQTT).

Hinweis

Der Einfachheit halber wird in diesem Artikel keine Wiederholungsrichtlinie implementiert. Im Produktionscode sollten Sie Wiederholungsrichtlinien implementieren (z.B. exponentielles Backoff), wie es im Artikel Behandeln vorübergehender Fehler vorgeschlagen wird.

Abrufen der IoT-Hub-Verbindungszeichenfolge

In diesem Artikel erstellen Sie einen Back-End-Dienst, der einen Auftrag zum Aufrufen einer direkten Methode auf einem Gerät sowie einen Auftrag zum Aktualisieren des Gerätezwillings plant und den Fortschritt der beiden Aufträge überwacht. Für diese Vorgänge benötigt Ihr Dienst die Berechtigungen Lesevorgänge in Registrierung und Schreibvorgänge in Registrierung. Standardmäßig wird jeder IoT-Hub mit einer SAS-Richtlinie namens registryReadWrite erstellt, die diese Berechtigungen erteilt.

Führen Sie zum Abrufen der IoT-Hub-Verbindungszeichenfolge für die Richtlinie registryReadWrite die folgenden Schritte aus:

  1. Wählen Sie im Azure-Portal die Option Ressourcengruppen aus. Wählen Sie die Ressourcengruppe aus, in der sich der Hub befindet, und wählen Sie dann in der Liste der Ressourcen Ihren Hub aus.

  2. Wählen Sie im linken Bereich Ihres Hubs SAS-Richtlinien aus.

  3. Wählen Sie in der Liste der Richtlinien die Richtlinie registryRead Write aus.

  4. Kopieren Sie die primäre Verbindungszeichenfolge und speichern Sie den Wert.

    Screenshot: Abrufen der Verbindungszeichenfolge

Weitere Informationen zu SAS-Richtlinien und Berechtigungen für IoT-Hubs finden Sie unter Access Control und Berechtigungen.

Erstellen der Dienst-App

In diesem Abschnitt erstellen Sie eine Java-Konsolen-App, die Aufträge für folgende Zwecke nutzt:

  • Aufrufen der direkten lockDoor-Methode auf mehreren Geräten

  • Senden von gewünschten Eigenschaften an mehrere Geräte

Gehen Sie wie folgt vor, um die App zu erstellen:

  1. Erstellen Sie auf dem Entwicklungscomputer einen leeren Ordner mit dem Nameniot-java-schedule-jobs.

  2. Erstellen Sie im Ordner iot-java-schedule-jobs ein Maven-Projekt mit dem Namen schedule-jobs, indem Sie an der Eingabeaufforderung den folgenden Befehl ausführen. Beachten Sie, dass es sich hierbei um einen einzelnen langen Befehl handelt:

    mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=schedule-jobs -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
    
  3. Navigieren Sie an der Eingabeaufforderung zum Ordner schedule-jobs.

  4. Öffnen Sie mit einem Text-Editor die Datei pom.xml im Ordner schedule-jobs, und fügen Sie dem Knoten dependencies die folgende Abhängigkeit hinzu. Mit dieser Abhängigkeit können Sie das Paket iot-service-client in Ihrer App zum Kommunizieren mit Ihrem IoT Hub verwenden:

    <dependency>
      <groupId>com.microsoft.azure.sdk.iot</groupId>
      <artifactId>iot-service-client</artifactId>
      <version>1.17.1</version>
      <type>jar</type>
    </dependency>
    

    Hinweis

    Sie finden die aktuelle Version von iot-service-client mithilfe der Maven-Suche.

  5. Fügen Sie den Knoten build hinter dem Knoten dependencies hinzu. Diese Konfiguration weist Maven an, Java 1.8 zu verwenden, um die App zu erstellen:

    <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. Speichern und schließen Sie die Datei pom.xml.

  7. Öffnen Sie die Datei schedule-jobs\src\main\java\com\mycompany\app\App.java in einem Text-Editor.

  8. Fügen Sie der Datei die folgenden import -Anweisungen hinzu:

    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. Fügen Sie die folgenden Variablen auf Klassenebene der App -Klasse die folgende Variable auf Klassenebene hinzu. Ersetzen Sie {youriothubconnectionstring} durch Ihre IoT-Hub-Verbindungszeichenfolge, die Sie zuvor unter Abrufen der IoT-Hub-Verbindungszeichenfolge kopiert haben:

    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. Fügen Sie der App-Klasse die folgende Methode hinzu, um einen Auftrag zum Aktualisieren der gewünschten Eigenschaften Building und Floor im Gerätezwilling zu planen:

    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. Fügen Sie der App-Klasse die folgende Methode hinzu, um einen Auftrag zum Aufrufen der lockDoor-Methode zu planen:

    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. Fügen Sie der App-Klasse die folgende Methode hinzu, um einen Auftrag zu überwachen:

    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. Fügen Sie die folgende Methode hinzu, um die Details zu den ausgeführten Aufträgen abzufragen:

    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. Aktualisieren Sie die Signatur der main-Methode und schließen Sie die folgende throws-Klausel ein:

    public static void main( String[] args ) throws Exception
    
  15. Ersetzen Sie den Code in der main-Methode durch den folgenden Code, um zwei Aufträge sequenziell auszuführen und zu überwachen:

    // 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. Speichern und schließen Sie die Datei schedule-jobs\src\main\java\com\mycompany\app\App.java.

  17. Erstellen Sie die App schedule-jobs, und beheben Sie etwaige Fehler. Navigieren Sie an der Eingabeaufforderung zum Ordner schedule-jobs, und führen Sie den folgenden Befehl aus:

    mvn clean package -DskipTests
    

Erstellen einer Geräte-App

In diesem Abschnitt erstellen Sie eine Java-Konsolen-App, mit der die vom IoT Hub gesendeten gewünschten Eigenschaften verarbeitet und der Aufruf der direkten Methode implementiert wird.

  1. Erstellen Sie im Ordner iot-java-schedule-jobs ein Maven-Projekt mit dem Namen simulated-device, indem Sie an der Eingabeaufforderung den folgenden Befehl ausführen. Beachten Sie, dass es sich hierbei um einen einzelnen langen Befehl handelt:

    mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=simulated-device -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
    
  2. Navigieren Sie an der Eingabeaufforderung zum Ordner simulated-device.

  3. Öffnen Sie mit einem Text-Editor die Datei pom.xml im Ordner simulated-device, und fügen Sie dem Knoten dependencies die folgenden Abhängigkeiten hinzu. Mit dieser Abhängigkeit können Sie das Paket iot-device-client in Ihrer App zum Kommunizieren mit Ihrem IoT Hub verwenden:

    <dependency>
      <groupId>com.microsoft.azure.sdk.iot</groupId>
      <artifactId>iot-device-client</artifactId>
      <version>1.17.5</version>
    </dependency>
    

    Hinweis

    Sie finden die aktuelle Version von iot-device-client mithilfe der Maven-Suche.

  4. Fügen Sie dem Knoten dependencies die folgende Abhängigkeit hinzu. Mit dieser Abhängigkeit wird ein NOP für die Apache SLF4J-Protokollierungsfassade konfiguriert, die vom Geräteclient-SDK zum Implementieren der Protokollierung verwendet wird. Diese Konfiguration ist optional, aber wenn Sie sie weglassen, wird in der Konsole beim Ausführen der App ggf. eine Warnung angezeigt. Weitere Informationen zur Protokollierung im Geräteclient-SDK finden Sie unter Logging (Protokollierung) in der Infodatei Samples for the Azure IoT device SDK for Java (Beispiele für das Azure IoT-Geräte-SDK für Java).

    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-nop</artifactId>
      <version>1.7.28</version>
    </dependency>
    
  5. Fügen Sie den Knoten build hinter dem Knoten dependencies hinzu. Diese Konfiguration weist Maven an, Java 1.8 zu verwenden, um die App zu erstellen:

    <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. Speichern und schließen Sie die Datei pom.xml.

  7. Öffnen Sie die Datei simulated-device\src\main\java\com\mycompany\app\App.java mit einem Text-Editor.

  8. Fügen Sie der Datei die folgenden import -Anweisungen hinzu:

    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. Fügen Sie die folgenden Variablen auf Klassenebene der App -Klasse die folgende Variable auf Klassenebene hinzu. Ersetzen Sie {yourdeviceconnectionstring} durch die Geräteverbindungszeichenfolge, die Ihnen beim Registrieren eines Geräts im IoT-Hub angezeigt wurde:

    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;
    

    Diese Beispiel-App verwendet beim Instanziieren eines DeviceClient-Objekts die protocol-Variable.

  10. Fügen Sie der App-Klasse die folgende geschachtelte Klasse hinzu, um Gerätezwillingsbenachrichtigungen auf der Konsole auszugeben:

    // 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. Fügen Sie der App-Klasse die folgende geschachtelte Klasse hinzu, um Benachrichtigungen über direkte Methoden auf der Konsole auszugeben:

    // 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. Fügen Sie der App-Klasse die folgende geschachtelte Klasse hinzu, um Aufrufe von direkten Methoden über den IoT Hub zu verarbeiten:

    // 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. Aktualisieren Sie die Signatur der main-Methode und schließen Sie die folgende throws-Klausel ein:

    public static void main( String[] args ) throws IOException, URISyntaxException
    
  14. Ersetzen Sie den Code in der main-Methode durch den folgenden Code:

    • Erstellen Sie einen Geräteclient zur Kommunikation mit IoT Hub.
    • Erstellen Sie ein Device-Objekt, das die Gerätezwillingseigenschaften speichert.
    // 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. Fügen Sie der main-Methode den folgenden Code hinzu, um die Dienste für den Geräteclient zu starten:

    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. Fügen Sie am Ende der main-Methode den folgenden Code hinzu, wenn vor dem Herunterfahren darauf gewartet werden soll, dass der Benutzer die EINGABETASTE drückt:

    // 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. Speichern und schließen Sie die Datei simulated-device\src\main\java\com\mycompany\app\App.java.

  18. Erstellen Sie die App simulated-device, und korrigieren Sie etwaige Fehler. Navigieren Sie an der Eingabeaufforderung zum Ordner simulated-device, und führen Sie den folgenden Befehl aus:

    mvn clean package -DskipTests
    

Ausführen der Apps

Sie können nun die Konsolen-Apps ausführen.

  1. Führen Sie an einer Eingabeaufforderung im Ordner simulated-device den folgenden Befehl aus, um die Geräte-App zu starten, mit der auf Änderungen von gewünschten Eigenschaften und Aufrufe von direkten Methoden gelauscht wird:

    mvn exec:java -Dexec.mainClass="com.mycompany.app.App"
    

    Geräteclient wird gestartet

  2. Führen Sie an der Eingabeaufforderung im Ordner schedule-jobs den folgenden Befehl aus, um die Dienst-App schedule-jobs für zwei Aufträge auszuführen. Mit dem ersten Auftrag werden die gewünschten Eigenschaftswerte festgelegt, und mit dem zweiten wird die direkte Methode aufgerufen:

    mvn exec:java -Dexec.mainClass="com.mycompany.app.App"
    

    Java-IoT Hub-Dienst-App erstellt zwei Aufträge

  3. Die Geräte-App führt die Änderung der gewünschten Eigenschaften und den Aufruf der direkten Methode durch:

    Geräteclient reagiert auf Änderungen

Nächste Schritte

In diesem Artikel haben Sie Aufträge geplant, um eine direkte Methode auszuführen und die Eigenschaften des Gerätezwillings zu aktualisieren.

Informationen zur weiteren Erkundung von IoT Hub und Geräteverwaltungsmustern, aktualisieren Sie ein Image unter Device Update for Azure IoT Hub unter Verwendung des Raspberry Pi 3 B+-Referenzimages.