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:
Gerätezwilling und Eigenschaften: Erste Schritte mit Gerätezwillingen (Vorschau) und Verstehen und Verwenden von Gerätezwillingen in IoT Hub
Direkte Methoden:IoT Hub-Entwicklerleitfaden – direkte Methoden
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.
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:
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.
Wählen Sie im linken Bereich Ihres Hubs SAS-Richtlinien aus.
Wählen Sie in der Liste der Richtlinien die Richtlinie registryRead Write aus.
Kopieren Sie die primäre Verbindungszeichenfolge und speichern Sie den Wert.
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:
Erstellen Sie auf dem Entwicklungscomputer einen leeren Ordner mit dem Nameniot-java-schedule-jobs.
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
Navigieren Sie an der Eingabeaufforderung zum Ordner schedule-jobs.
Ö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.
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>
Speichern und schließen Sie die Datei pom.xml.
Öffnen Sie die Datei schedule-jobs\src\main\java\com\mycompany\app\App.java in einem Text-Editor.
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;
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;
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; } }
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; } };
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; } }
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)); } }
Aktualisieren Sie die Signatur der main-Methode und schließen Sie die folgende
throws
-Klausel ein:public static void main( String[] args ) throws Exception
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");
Speichern und schließen Sie die Datei schedule-jobs\src\main\java\com\mycompany\app\App.java.
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.
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
Navigieren Sie an der Eingabeaufforderung zum Ordner simulated-device.
Ö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.
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>
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>
Speichern und schließen Sie die Datei pom.xml.
Öffnen Sie die Datei simulated-device\src\main\java\com\mycompany\app\App.java mit einem Text-Editor.
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;
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.
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()); } }
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()); } }
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; } }
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
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); } };
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..."); }
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();
Speichern und schließen Sie die Datei simulated-device\src\main\java\com\mycompany\app\App.java.
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.
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"
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"
Die Geräte-App führt die Änderung der gewünschten Eigenschaften und den Aufruf der direkten Methode durch:
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.