Planowanie i emisja zadań (Java)
Usługa Azure IoT Hub umożliwia planowanie i śledzenie zadań, które aktualizują miliony urządzeń. Użyj zadań, aby:
- Aktualizowanie żądanych właściwości
- Aktualizowanie tagów
- Wywoływanie metod bezpośrednich
Zadanie opakowuje jedną z tych akcji i śledzi wykonywanie względem zestawu urządzeń. Zapytanie bliźniaczej reprezentacji urządzenia definiuje zestaw urządzeń wykonywanych przez zadanie. Na przykład aplikacja zaplecza może użyć zadania do wywołania metody bezpośredniej na 10 000 urządzeniach, które ponownie uruchamiają urządzenia. Należy określić zestaw urządzeń z zapytaniem bliźniaczej reprezentacji urządzenia i zaplanować uruchomienie zadania w przyszłości. Zadanie śledzi postęp, gdy każdy z urządzeń odbiera i wykonuje metodę bezpośrednią ponownego rozruchu.
Aby dowiedzieć się więcej o każdej z tych możliwości, zobacz:
Bliźniacze reprezentacje urządzenia i właściwości: Wprowadzenie do bliźniaczych reprezentacji urządzeń oraz Omówienie bliźniaczych reprezentacji urządzeń i korzystanie z nich w usłudze IoT Hub
Metody bezpośrednie: Przewodnik dewelopera usługi IoT Hub — metody bezpośrednie
Uwaga
Funkcje opisane w tym artykule są dostępne tylko w warstwie Standardowa usługi IoT Hub. Aby uzyskać więcej informacji na temat warstw podstawowej i standardowej/bezpłatnej usługi IoT Hub, zobacz Wybieranie odpowiedniej warstwy usługi IoT Hub dla rozwiązania.
W tym artykule pokazano, jak utworzyć dwie aplikacje Java:
Aplikacja urządzenia, symulowane urządzenie, która implementuje metodę bezpośrednią o nazwie lockDoor, którą można wywołać przez aplikację zaplecza.
Aplikacja zaplecza, schedule-jobs, która tworzy dwa zadania. Jedno zadanie wywołuje metodę bezpośrednią lockDoor , a inne zadanie wysyła żądane aktualizacje właściwości do wielu urządzeń.
Uwaga
Zobacz Zestawy SDK usługi Azure IoT, aby uzyskać więcej informacji na temat narzędzi zestawu SDK dostępnych do kompilowania aplikacji urządzeń i zaplecza.
Wymagania wstępne
Centrum IoT w ramach subskrypcji platformy Azure. Jeśli nie masz jeszcze centrum, możesz wykonać kroki opisane w temacie Tworzenie centrum IoT Hub.
Urządzenie zarejestrowane w centrum IoT Hub. Jeśli nie masz urządzenia w centrum IoT Hub, wykonaj kroki opisane w temacie Rejestrowanie urządzenia.
Java SE Development Kit 8. Upewnij się, że wybrano środowisko Java 8 w obszarze Obsługa długoterminowa , aby pobrać plik JDK 8.
Upewnij się, że port 8883 jest otwarty w zaporze. Przykład urządzenia w tym artykule używa protokołu MQTT, który komunikuje się za pośrednictwem portu 8883. Ten port może zostać zablokowany w niektórych środowiskach sieci firmowych i edukacyjnych. Aby uzyskać więcej informacji i sposobów obejścia tego problemu, zobacz Nawiązywanie połączenia z usługą IoT Hub (MQTT).
Uwaga
Aby zachować prostotę, ten artykuł nie implementuje zasad ponawiania. W kodzie produkcyjnym należy zaimplementować zasady ponawiania prób (takie jak wycofywanie wykładnicze), zgodnie z sugestią w artykule Obsługa przejściowych błędów.
Pobieranie parametry połączenia usługi IoT Hub
W tym artykule tworzysz usługę zaplecza, która planuje wywołanie metody bezpośredniej na urządzeniu, planuje zadanie aktualizacji bliźniaczej reprezentacji urządzenia i monitoruje postęp każdego zadania. Aby wykonać te operacje, usługa wymaga uprawnień do odczytu rejestru i zapisu rejestru. Domyślnie każde centrum IoT jest tworzone przy użyciu zasad dostępu współdzielonego o nazwie registryReadWrite , które przyznaje te uprawnienia.
Aby uzyskać parametry połączenia usługi IoT Hub dla zasad registryReadWrite, wykonaj następujące kroki:
W witrynie Azure Portal wybierz pozycję Grupy zasobów. Wybierz grupę zasobów, w której znajduje się centrum, a następnie wybierz centrum z listy zasobów.
W okienku po lewej stronie centrum wybierz pozycję Zasady dostępu współdzielonego.
Z listy zasad wybierz zasady registryReadWrite .
Skopiuj parametry połączenia podstawową i zapisz wartość.
Aby uzyskać więcej informacji na temat zasad dostępu współdzielonego i uprawnień usługi IoT Hub, zobacz Kontrola dostępu i uprawnienia.
Ważne
Ten artykuł zawiera kroki nawiązywania połączenia z usługą przy użyciu sygnatury dostępu współdzielonego. Ta metoda uwierzytelniania jest wygodna do testowania i oceny, ale uwierzytelnianie w usłudze przy użyciu identyfikatora Entra firmy Microsoft lub tożsamości zarządzanych jest bardziej bezpieczne. Aby dowiedzieć się więcej, zobacz Security best practices Cloud security (Najlepsze rozwiązania > dotyczące zabezpieczeń w chmurze).
Tworzenie aplikacji usługi
W tej sekcji utworzysz aplikację konsolową Java, która używa zadań do wykonywania:
Wywołaj metodę bezpośrednią lockDoor na wielu urządzeniach.
Wysyłanie żądanych właściwości do wielu urządzeń.
Aby utworzyć aplikację:
Na maszynie deweloperów utwórz pusty folder o nazwie iot-java-schedule-jobs.
W folderze iot-java-schedule-jobs utwórz projekt Maven o nazwie schedule-jobs przy użyciu następującego polecenia w wierszu polecenia. Zwróć uwagę, że jest to jedno długie polecenie:
mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=schedule-jobs -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
W wierszu polecenia przejdź do folderu schedule-jobs .
Za pomocą edytora tekstów otwórz plik pom.xml w folderze schedule-jobs i dodaj następującą zależność do węzła zależności . Ta zależność umożliwia używanie pakietu iot-service-client w aplikacji do komunikowania się z centrum IoT:
<dependency> <groupId>com.microsoft.azure.sdk.iot</groupId> <artifactId>iot-service-client</artifactId> <version>1.17.1</version> <type>jar</type> </dependency>
Uwaga
Możesz sprawdzić dostępność najnowszej wersji pakietu iot-service-client za pomocą funkcji wyszukiwania narzędzia Maven.
Dodaj następujący węzeł kompilacji po węźle zależności . Ta konfiguracja nakazuje narzędziu Maven użycie środowiska Java 1.8 do skompilowania aplikacji:
<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>
Zapisz i zamknij plik pom.xml.
Za pomocą edytora tekstów otwórz plik schedule-jobs\src\main\java\com\mycompany\app\App.java .
Dodaj do pliku następujące instrukcje importowania:
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;
Dodaj następujące zmienne na poziomie klasy do klasy App. Zastąp
{youriothubconnectionstring}
element parametry połączenia centrum IoT Hub skopiowanym wcześniej w sekcji Pobieranie centrum IoT Hub parametry połączenia: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;
Dodaj następującą metodę do klasy App , aby zaplanować zadanie aktualizacji żądanych właściwości budynku i piętra w bliźniaczej reprezentacji urządzenia:
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; } }
Aby zaplanować zadanie wywołania metody lockDoor , dodaj następującą metodę do klasy App :
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; } };
Aby monitorować zadanie, dodaj następującą metodę do klasy App :
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; } }
Aby wykonać zapytanie o szczegóły uruchomionych zadań, dodaj następującą metodę:
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)); } }
Zaktualizuj sygnaturę metody głównej, aby uwzględnić następującą
throws
klauzulę:public static void main( String[] args ) throws Exception
Aby uruchomić i monitorować dwa zadania sekwencyjnie, zastąp kod w metodzie main następującym kodem:
// 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");
Zapisz i zamknij plik schedule-jobs\src\main\java\com\mycompany\app\App.java
Skompiluj aplikację schedule-jobs i popraw wszelkie błędy. W wierszu polecenia przejdź do folderu schedule-jobs i uruchom następujące polecenie:
mvn clean package -DskipTests
Tworzenie aplikacji urządzenia
W tej sekcji utworzysz aplikację konsolową Java, która obsługuje żądane właściwości wysyłane z usługi IoT Hub i implementuje wywołanie metody bezpośredniej.
Ważne
Ten artykuł zawiera kroki łączenia urządzenia przy użyciu sygnatury dostępu współdzielonego, nazywanej również uwierzytelnianiem klucza symetrycznego. Ta metoda uwierzytelniania jest wygodna do testowania i oceny, ale uwierzytelnianie urządzenia przy użyciu certyfikatów X.509 jest bardziej bezpieczne. Aby dowiedzieć się więcej, zobacz Zabezpieczenia najlepszych rozwiązań > zabezpieczeń Zabezpieczenia zabezpieczeń Zabezpieczenia zabezpieczeń.
W folderze iot-java-schedule-jobs utwórz projekt Maven o nazwie simulated-device przy użyciu następującego polecenia w wierszu polecenia. Zwróć uwagę, że jest to jedno długie polecenie:
mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=simulated-device -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
W wierszu polecenia przejdź do folderu simulated-device .
Za pomocą edytora tekstów otwórz plik pom.xml w folderze simulated-device i dodaj następujące zależności do węzła zależności . Ta zależność umożliwia używanie pakietu iot-device-client w aplikacji do komunikowania się z centrum IoT:
<dependency> <groupId>com.microsoft.azure.sdk.iot</groupId> <artifactId>iot-device-client</artifactId> <version>1.17.5</version> </dependency>
Uwaga
Możesz sprawdzić dostępność najnowszej wersji pakietu iot-device-client za pomocą funkcji wyszukiwania narzędzia Maven.
Dodaj następującą zależność do węzła zależności . Ta zależność konfiguruje NOP dla fasady rejestrowania Apache SLF4J , która jest używana przez zestaw SDK klienta urządzenia do implementowania rejestrowania. Ta konfiguracja jest opcjonalna, ale jeśli ją pominięto, po uruchomieniu aplikacji może zostać wyświetlone ostrzeżenie w konsoli programu . Aby uzyskać więcej informacji na temat rejestrowania w zestawie SDK klienta urządzenia, zobacz Rejestrowaniew przykładach dla zestawu SDK urządzenia Azure IoT dla pliku readme języka Java .
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-nop</artifactId> <version>1.7.28</version> </dependency>
Dodaj następujący węzeł kompilacji po węźle zależności . Ta konfiguracja nakazuje narzędziu Maven użycie środowiska Java 1.8 do skompilowania aplikacji:
<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>
Zapisz i zamknij plik pom.xml.
Za pomocą edytora tekstów otwórz plik simulated-device\src\main\java\com\mycompany\app\App.java .
Dodaj do pliku następujące instrukcje importowania:
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;
Dodaj następujące zmienne na poziomie klasy do klasy App. Zastąp
{yourdeviceconnectionstring}
element urządzeniem parametry połączenia, które zostało wyświetlone podczas rejestrowania urządzenia w usłudze IoT Hub: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;
Ta przykładowa aplikacja używa zmiennej protocol podczas tworzenia wystąpienia obiektu DeviceClient.
Aby wydrukować powiadomienia bliźniaczej reprezentacji urządzenia w konsoli, dodaj następującą klasę zagnieżdżonych do klasy 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()); } }
Aby wydrukować powiadomienia metody bezpośredniej w konsoli, dodaj następującą klasę zagnieżdżonych do klasy 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()); } }
Aby obsługiwać wywołania metod bezpośrednich z usługi IoT Hub, dodaj następującą klasę zagnieżdżonych do klasy 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; } }
Zaktualizuj sygnaturę metody głównej, aby uwzględnić następującą
throws
klauzulę:public static void main( String[] args ) throws IOException, URISyntaxException
Zastąp kod w metodzie main następującym kodem:
- Utwórz klienta urządzenia do komunikowania się z usługą IoT Hub.
- Utwórz obiekt Device do przechowywania właściwości bliźniaczej reprezentacji urządzenia.
// 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); } };
Aby uruchomić usługi klienckie urządzeń, dodaj następujący kod do metody 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..."); }
Aby poczekać na naciśnięcie Enter przed zamknięciem, dodaj następujący kod na końcu metody 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();
Zapisz i zamknij plik simulated-device\src\main\java\com\mycompany\app\App.java .
Skompiluj aplikację symulowanego urządzenia i popraw wszelkie błędy. W wierszu polecenia przejdź do folderu simulated-device i uruchom następujące polecenie:
mvn clean package -DskipTests
Uruchamianie aplikacji
Teraz możesz uruchomić aplikacje konsolowe.
W wierszu polecenia w folderze simulated-device uruchom następujące polecenie, aby uruchomić aplikację urządzenia nasłuchując żądaną zmianę właściwości i wywołania metod bezpośrednich:
mvn exec:java -Dexec.mainClass="com.mycompany.app.App"
W wierszu polecenia w folderze
schedule-jobs
uruchom następujące polecenie, aby uruchomić aplikację usługi schedule-jobs , aby uruchomić dwa zadania. Pierwszy ustawia żądane wartości właściwości, a drugi wywołuje metodę bezpośrednią:mvn exec:java -Dexec.mainClass="com.mycompany.app.App"
Aplikacja urządzenia obsługuje zmianę żądanej właściwości i wywołanie metody bezpośredniej:
Następne kroki
W tym artykule zaplanowano zadania uruchamiania metody bezpośredniej i aktualizowania właściwości bliźniaczej reprezentacji urządzenia.
Aby kontynuować eksplorowanie wzorców zarządzania usługą IoT Hub i urządzeniami, zaktualizuj obraz w samouczku Dotyczącym aktualizacji urządzenia dla usługi Azure IoT Hub przy użyciu obrazu referencyjnego urządzenia Raspberry Pi 3 B+ .