Share via


デバイス管理の開始 (Java)

バックエンド アプリでは、Azure IoT Hub プリミティブ (デバイス ツインダイレクト メソッドなど) を使用して、デバイス上のデバイス管理アクションをリモートで開始および監視できます。 この記事では、バックエンド アプリとデバイス アプリをどのように連携させると、IoT Hub を使用してデバイスの再起動をリモートで開始して監視できるかについて示します。

Note

この記事で説明されている機能は、Standard レベルの IoT Hub でのみ使用できます。 Basic および Standard または Free レベルの IoT Hub の詳細については、ソリューションに適した IoT Hub のレベルの選択に関するページを参照してください。

ダイレクト メソッドを使用して、クラウド内のバックエンド アプリケーションからデバイス管理操作 (再起動、出荷時の設定に戻す、ファームウェアの更新など) を開始します。 デバイスは次の操作を担当します。

  • IoT Hub から送信されたメソッド要求の処理。

  • デバイスでの対応するデバイス固有の操作の開始。

  • "報告されるプロパティ" を介した IoT Hub への状態更新の提供。

クラウドでバックエンド アプリを使用してデバイス ツインのクエリを実行することで、デバイス管理操作の進行状況を報告できます。

この記事では、次のものを作成する方法について説明します。

  • simulated-device: デバイスを再起動し、最後の再起動時刻を報告するダイレクト メソッドを含むシミュレートされたデバイス アプリ。 ダイレクト メソッドは、クラウドから呼び出されます。

  • trigger-reboot: シミュレートされたデバイス アプリのダイレクト メソッドを IoT Hub から呼び出す Java アプリ。 応答と更新されて報告されたプロパティを表示します。

注意

デバイス上で動作するアプリケーションの作成とソリューションのバックエンドで動作するアプリケーションの開発に利用できる各種 SDK については、「Azure IoT SDK」をご覧ください。

前提条件

  • IoT Hub。 CLI または Azure portal を使って作成します。

  • 登録済みのデバイス。 Azure portal に登録してください。

  • Java SE Development Kit 8。 JDK 8 のダウンロードを利用するには、「長期サポート」の「Java 8」を選択します。

  • Maven 3

  • ポート 8883 がファイアウォールで開放されていることを確認してください。 この記事のデバイス サンプルでは、ポート 8883 を介して通信する MQTT プロトコルを使用しています。 このポートは、企業や教育用のネットワーク環境によってはブロックされている場合があります。 この問題の詳細と対処方法については、「IoT Hub への接続 (MQTT)」を参照してください。

ダイレクト メソッドを使用してデバイス アプリを作成する

このセクションでは、デバイスをシミュレートする Java コンソール アプリを作成します。 アプリは、IoT hub からの再起動ダイレクト メソッド呼び出しをリッスンし、その呼び出しに直ちに応答します。 次にアプリは、しばらくスリープし、再起動プロセスをシミュレートしてから、報告されたプロパティを使用して、trigger-reboot バックエンド アプリに、再起動が完了したことを通知します。

  1. コマンド プロンプトで次のコマンドを実行し、dm-get-started フォルダーに simulated-device という名前の Maven プロジェクトを作成します。

    mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=simulated-device -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
    
  2. コマンド プロンプトで、simulated-device フォルダーに移動します。

  3. テキスト エディターを使用して、simulated-device フォルダー内の pom.xml ファイルを開き、次の依存関係を dependencies ノードに追加します。 この依存関係により、アプリの iot-service-client パッケージを使用して IoT Hub と通信できるようになります。

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

    注意

    Maven 検索を使用して、iot-device-client の最新バージョンを確認できます。

  4. dependencies ノードに、次の依存関係を追加します。 この依存関係によって、Apache SLF4J ログ記録ファサード用の NOP が構成され、ログ記録を実装するためにデバイス クライアント SDK によって使用されます。 この構成は省略可能ですが、省略した場合、アプリの実行時にコンソールに警告が表示される可能性があります。 デバイス クライアント SDK でのログ記録の詳細については、Samples for the Azure IoT device SDK for Java readme ファイルに含まれているログ記録を参照してください。

    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-nop</artifactId>
      <version>1.7.28</version>
    </dependency>
    
  5. dependencies ノードの後に、次の build ノードを追加します。 この構成では、Java 1.8 を使用してアプリをビルドするように Maven に指示しています。

    <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. pom.xml ファイルを保存して閉じます。

  7. テキスト エディターを使用して、simulated-device\src\main\java\com\mycompany\app\App.java ソース ファイルを開きます。

  8. ファイルに次の import ステートメントを追加します。

    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.time.LocalDateTime;
    import java.util.Scanner;
    import java.util.Set;
    import java.util.HashSet;
    
  9. 次のクラスレベル変数を App クラスに追加します。 {yourdeviceconnectionstring} を、IoT Hub にデバイスを登録した時に表示されたデバイス接続文字列に置き換えます。

    private static final int METHOD_SUCCESS = 200;
    private static final int METHOD_NOT_DEFINED = 404;
    
    private static IotHubClientProtocol protocol = IotHubClientProtocol.MQTT;
    private static String connString = "{yourdeviceconnectionstring}";
    private static DeviceClient client;
    
  10. ダイレクト メソッド ステータス イベントのコールバック ハンドラーを実装するには、次の入れ子になったクラスを App クラスに追加します。

    protected static class DirectMethodStatusCallback implements IotHubEventCallback
    {
      public void execute(IotHubStatusCode status, Object context)
      {
        System.out.println("IoT Hub responded to device method operation with status " + status.name());
      }
    }
    
  11. デバイス ツイン ステータス イベントのコールバック ハンドラーを実装するには、次の入れ子になったクラスを App クラスに追加します。

    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());
        }
    }
    
  12. プロパティ イベントのコールバック ハンドラーを実装するには、次の入れ子になったクラスを App クラスに追加します。

    protected static class PropertyCallback implements PropertyCallBack<String, String>
    {
      public void PropertyCall(String propertyKey, String propertyValue, Object context)
      {
        System.out.println("PropertyKey:     " + propertyKey);
        System.out.println("PropertyKvalue:  " + propertyKey);
      }
    }
    
  13. デバイスの再起動をシミュレートするスレッドを実装するには、次の入れ子になったクラスを App クラスに追加します。 スレッドは 5 秒間スリープしてから、報告された lastReboot プロパティを設定します。

    protected static class RebootDeviceThread implements Runnable {
      public void run() {
        try {
          System.out.println("Rebooting...");
          Thread.sleep(5000);
          Property property = new Property("lastReboot", LocalDateTime.now());
          Set<Property> properties = new HashSet<Property>();
          properties.add(property);
          client.sendReportedProperties(properties);
          System.out.println("Rebooted");
        }
        catch (Exception ex) {
          System.out.println("Exception in reboot thread: " + ex.getMessage());
        }
      }
    }
    
  14. デバイスにダイレクト メソッドを実装するには、次の入れ子になったクラスを App クラスに追加します。 シミュレートされたアプリが、reboot ダイレクト メソッドへの呼び出しを受け取ると、呼び出し元に受信確認を返し、再起動を処理するスレッドを起動します。

    protected static class DirectMethodCallback implements com.microsoft.azure.sdk.iot.device.DeviceTwin.DeviceMethodCallback
    {
      @Override
      public DeviceMethodData call(String methodName, Object methodData, Object context)
      {
        DeviceMethodData deviceMethodData;
        switch (methodName)
        {
          case "reboot" :
          {
            int status = METHOD_SUCCESS;
            System.out.println("Received reboot request");
            deviceMethodData = new DeviceMethodData(status, "Started reboot");
            RebootDeviceThread rebootThread = new RebootDeviceThread();
            Thread t = new Thread(rebootThread);
            t.start();
            break;
          }
          default:
          {
            int status = METHOD_NOT_DEFINED;
            deviceMethodData = new DeviceMethodData(status, "Not defined direct method " + methodName);
          }
        }
        return deviceMethodData;
      }
    }
    
  15. main メソッドのシグネチャを変更し、次の例外をスローします。

    public static void main(String[] args) throws IOException, URISyntaxException
    
  16. DeviceClient をインスタンス化するには、main メソッドのコードを次のコードに置き換えます。

    System.out.println("Starting device client sample...");
    client = new DeviceClient(connString, protocol);
    
  17. ダイレクト メソッド呼び出しのリッスンを開始するには、main メソッドに次のコードを追加します。

    try
    {
      client.open();
      client.subscribeToDeviceMethod(new DirectMethodCallback(), null, new DirectMethodStatusCallback(), null);
      client.startDeviceTwin(new DeviceTwinStatusCallback(), null, new PropertyCallback(), null);
      System.out.println("Subscribed to direct methods and polling for reported properties. Waiting...");
    }
    catch (Exception e)
    {
      System.out.println("On exception, shutting down \n" + " Cause: " + e.getCause() + " \n" +  e.getMessage());
      client.close();
      System.out.println("Shutting down...");
    }
    
  18. デバイス シミュレーターをシャットダウンするには、main メソッドに次のコードを追加します。

    System.out.println("Press any key to exit...");
    Scanner scanner = new Scanner(System.in);
    scanner.nextLine();
    scanner.close();
    client.close();
    System.out.println("Shutting down...");
    
  19. simulated-device\src\main\java\com\mycompany\app\App.java を保存して閉じます。

  20. simulated-device アプリをビルドし、エラーを修正します。 コマンド プロンプトで simulated-device フォルダーに移動し、次のコマンドを実行します。

    mvn clean package -DskipTests
    

IoT ハブ接続文字列を取得する

この記事では、デバイス上で直接メソッドを呼び出すバックエンド サービスを作成します。 IoT Hub を介してデバイス上で直接メソッドを呼び出すには、サービスにサービス接続アクセス許可が必要です。 既定では、どの IoT Hub も、このアクセス許可を付与する service という名前の共有アクセス ポリシーがある状態で作成されます。

サービス ポリシーの IoT Hub 接続文字列を取得するには、次の手順を実行します。

  1. Azure portal で、 [リソース グループ] を選択します。 ハブが配置されているリソース グループを選択し、リソースの一覧からハブを選択します。

  2. IoT ハブの左側のウィンドウで、 [共有アクセス ポリシー] を選択します。

  3. ポリシーの一覧から、サービス ポリシーを選択します。

  4. [プライマリ接続文字列] をコピーし、値を保存します。

Azure portal で IoT ハブから接続文字列を取得する方法を示すスクリーンショット。

IoT Hub の共有アクセス ポリシーとアクセス許可の詳細については、「アクセス制御とアクセス許可」を参照してください。

再起動をトリガーするサービス アプリを作成する

このセクションでは、次の操作を行う Java コンソール アプリを作成します。

  1. シミュレートされたデバイス アプリで再起動ダイレクト メソッドを呼び出します。

  2. 応答を表示します。

  3. デバイスから送信された報告されたプロパティをポーリングして、再起動が完了したタイミングを判断します。

このコンソール アプリは IoT Hub に接続して、ダイレクト メソッドを呼び出し、報告されたプロパティを読み取ります。

  1. dm-get-started という名前の空のフォルダーを作成します。

  2. コマンド プロンプトで次のコマンドを実行し、dm-get-started フォルダーに trigger-reboot という名前の Maven プロジェクトを作成します。

    mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=trigger-reboot -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
    
  3. コマンド プロンプトで、trigger-reboot フォルダーに移動します。

  4. テキスト エディターを使用して、trigger-reboot フォルダー内の pom.xml ファイルを開き、次の依存関係を dependencies ノードに追加します。 この依存関係により、アプリの iot-service-client パッケージを使用して IoT Hub と通信できるようになります。

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

    注意

    Maven 検索を使用して、iot-service-client の最新バージョンを確認できます。

  5. dependencies ノードの後に、次の build ノードを追加します。 この構成では、Java 1.8 を使用してアプリをビルドするように Maven に指示しています。

    <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. pom.xml ファイルを保存して閉じます。

  7. テキスト エディターを使用して、trigger-reboot\src\main\java\com\mycompany\app\App.java ソース ファイルを開きます。

  8. ファイルに次の import ステートメントを追加します。

    import com.microsoft.azure.sdk.iot.service.devicetwin.DeviceMethod;
    import com.microsoft.azure.sdk.iot.service.devicetwin.MethodResult;
    import com.microsoft.azure.sdk.iot.service.exceptions.IotHubException;
    import com.microsoft.azure.sdk.iot.service.devicetwin.DeviceTwin;
    import com.microsoft.azure.sdk.iot.service.devicetwin.DeviceTwinDevice;
    
    import java.io.IOException;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ExecutorService;
    
  9. 次のクラスレベル変数を App クラスに追加します。 {youriothubconnectionstring} は、先ほど「IoT ハブ接続文字列を取得する」でコピーしておいた IoT Hub 接続文字列に置き換えてください。

    public static final String iotHubConnectionString = "{youriothubconnectionstring}";
    public static final String deviceId = "myDeviceId";
    
    private static final String methodName = "reboot";
    private static final Long responseTimeout = TimeUnit.SECONDS.toSeconds(30);
    private static final Long connectTimeout = TimeUnit.SECONDS.toSeconds(5);
    
  10. 10 秒ごとにデバイス ツインから報告されたプロパティを読み取るスレッドを実装するには、次の入れ子になったクラスを App クラスに追加します。

    private static class ShowReportedProperties implements Runnable {
      public void run() {
        try {
          DeviceTwin deviceTwins = DeviceTwin.createFromConnectionString(iotHubConnectionString);
          DeviceTwinDevice twinDevice = new DeviceTwinDevice(deviceId);
          while (true) {
            System.out.println("Get reported properties from device twin");
            deviceTwins.getTwin(twinDevice);
            System.out.println(twinDevice.reportedPropertiesToString());
            Thread.sleep(10000);
          }
        } catch (Exception ex) {
          System.out.println("Exception reading reported properties: " + ex.getMessage());
        }
      }
    }
    
  11. main メソッドのシグネチャを変更し、次の例外をスローします。

    public static void main(String[] args) throws IOException
    
  12. シミュレートされたデバイスで再起動ダイレクト メソッドを呼び出すには、main メソッドのコードを次のコードに置き換えます。

    System.out.println("Starting sample...");
    DeviceMethod methodClient = DeviceMethod.createFromConnectionString(iotHubConnectionString);
    
    try
    {
      System.out.println("Invoke reboot direct method");
      MethodResult result = methodClient.invoke(deviceId, methodName, responseTimeout, connectTimeout, null);
    
      if(result == null)
      {
        throw new IOException("Invoke direct method reboot returns null");
      }
      System.out.println("Invoked reboot on device");
      System.out.println("Status for device:   " + result.getStatus());
      System.out.println("Message from device: " + result.getPayload());
    }
    catch (IotHubException e)
    {
        System.out.println(e.getMessage());
    }
    
  13. シミュレートされたデバイスから報告されたプロパティをポーリングするスレッドを開始するには、main メソッドに次のコードを追加します。

    ShowReportedProperties showReportedProperties = new ShowReportedProperties();
    ExecutorService executor = Executors.newFixedThreadPool(1);
    executor.execute(showReportedProperties);
    
  14. アプリを停止できるようにするには、main メソッドに次のコードを追加します。

    System.out.println("Press ENTER to exit.");
    System.in.read();
    executor.shutdownNow();
    System.out.println("Shutting down sample...");
    
  15. trigger-reboot\src\main\java\com\mycompany\app\App.java ファイルを保存して閉じます。

  16. trigger-reboot バックエンド アプリをビルドし、エラーを修正します。 コマンド プロンプトで trigger-reboot フォルダーに移動し、次のコマンドを実行します。

    mvn clean package -DskipTests
    

アプリの実行

これで、アプリを実行する準備が整いました。

  1. simulated-device フォルダーで、コマンド プロンプトから次のコマンドを実行し、IoT ハブからの再起動メソッド呼び出しのリッスンを開始します。

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

    再起動ダイレクト メソッドの呼び出しをリッスンする Java IoT Hub シミュレートされたデバイス アプリ

  2. trigger-reboot フォルダーで、コマンド プロンプトから次のコマンドを実行し、シミュレートされたデバイス上の再起動メソッドを IoT ハブから呼び出します。

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

    再起動ダイレクト メソッドを呼び出す Java IoT Hub サービス アプリ

  3. シミュレートされたデバイスは、再起動 ダイレクト メソッドの次の呼び出しに応答します。

    ダイレクト メソッドの呼び出しに応答する Java IoT Hub シミュレートされたデバイス アプリ

デバイス管理操作のカスタマイズと拡張を行う

IoT ソリューションでは、定義された一連のデバイス管理パターンを拡張したり、デバイス ツインと cloud-to-device メソッド プリミティブを使用してカスタム パターンを作成したりできます。 デバイス管理操作の他の例には、出荷時の設定への復帰、ファームウェアの更新、ソフトウェアの更新、電源管理、ネットワークと接続の管理、データの暗号化などがあります。

デバイスのメンテナンス期間

通常、デバイスは、中断やダウンタイムを最小限に抑えることができる時間に操作を実行するように構成します。 デバイスのメンテナンス期間は、デバイスがその構成を更新する必要がある時間を定義する一般的に使用されるパターンです。 バックエンド ソリューションは、デバイス ツインの必要なプロパティを使用して、メンテナンス期間を可能にするデバイスのポリシーを定義してアクティブにすることができます。 デバイスは、メンテナンス期間ポリシーを受信したときに、デバイス ツインの報告されたプロパティを使用してポリシーの状態を報告することができます。 その後、バックエンド アプリケーションは、デバイス ツインのクエリを使用して、デバイスが各ポリシーに対応していることを確認できます。

次のステップ

この記事では、ダイレクト メソッドを使用して、デバイスのリモート再起動をトリガーしました。 報告されるプロパティを使用してデバイスの最後の再起動時間を報告し、デバイス ツインのクエリを実行してクラウドからデバイスの最後の再起動時間を検出しました。

Raspberry Pi 3 B+ 参照イメージを使用した Azure IoT Hub のデバイス アップデートのアーティクル」でエンドツーエンドのイメージベースの更新など、IoT Hub とデバイス管理パターンの使用を続けます。

IoT ソリューションの拡張と複数のデバイスでのメソッドの呼び出しをスケジュールする方法については、ジョブのスケジュールとブロードキャストに関するページを参照してください。