デバイス ツインの概要 (Java)

デバイス ツインは、デバイスに関する情報 (メタデータ、構成、状態など) を格納する JSON ドキュメントです。 IoT Hub は、IoT Hub に接続する各デバイスにデバイス ツインを保持します。

Note

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

次の場合にデバイス ツインを使用します。

  • ソリューション バックエンドからデバイス メタデータを格納する。

  • デバイス アプリで利用できる機能や状態 (たとえば、使用される接続方法) などの現在の状態に関する情報をレポートする。

  • デバイス アプリとバックエンド アプリの間で実行時間の長いワークフロー (ファームウェアや構成の更新など) の状態を同期する。

  • デバイス メタデータ、構成、または状態を照会する。

デバイス ツインは、同期のほか、デバイスの構成と状態の照会に対応しています。 デバイス ツインの使用方法など、デバイス ツインの詳細については、デバイス ツインの理解に関するページを参照してください。

IoT ハブには、次の要素を含むデバイス ツインが格納されます。

  • タグ。 ソリューション バックエンドからのみアクセスできるデバイス メタデータです。

  • 必要なプロパティ。 ソリューション バックエンドから変更でき、デバイス アプリから監視できる JSON オブジェクトです。

  • 報告されるプロパティ。 デバイス アプリから変更でき、ソリューション バックエンドから読み取り可能な JSON オブジェクトです。

タグとプロパティには配列を含めることはできませんが、入れ子になったオブジェクトを含めることができます。

次の図は、デバイス ツイン組織を示しています。

デバイス ツインの概念図のスクリーンショット。

さらに、ソリューション バックエンドは、上記のすべてのデータに基づいてデバイス ツインに対してクエリを実行できます。 デバイス ツインの詳細については、デバイス ツインの理解に関するページを参照してください。 クエリ実行の詳細については、IoT Hub クエリ言語に関するページを参照してください。

この記事で取り上げるテクニック:

  • シミュレートされたデバイス アプリを使用して、その接続チャネルをデバイス ツインで報告されたプロパティとして報告します。

  • 以前に作成したタグとプロパティのフィルターを使用して、バックエンド アプリからデバイスに対してクエリを実行します。

この記事では、次の 2 つの Java コンソール アプリを作成します。

  • add-tags-query: タグの追加とデバイス ツインのクエリを実行する Java バックエンド アプリ。
  • simulated-device: IoT ハブに接続してその接続状態を報告するシミュレートされたデバイス アプリ。

Note

デバイスとバックエンド アプリの両方の構築に使用できる SDK ツールに関する詳細については、「Azure IoT Hub SDK」を参照してください。

前提条件

  • Azure サブスクリプション内の IoT ハブ。 ハブがまだない場合は、「IoT ハブの作成」の手順に従うことができます。

  • お使いの IoT ハブに登録されているデバイス。 IoT ハブにデバイスがない場合は、「デバイスを登録する」の手順に従います。

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

  • Maven 3

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

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

この記事では、デバイス ツインに必要なプロパティを追加した後、ID レジストリに対してクエリを実行し、適切に更新された報告されるプロパティを持つデバイスをすべて検索するバックエンド サービスを作成します。 そのサービスには、必要なデバイス ツインのプロパティを変更するためのサービス接続アクセス許可と、ID レジストリに対してクエリを実行するためのレジストリ読み取りアクセス許可が必要となります。 その 2 つのアクセス許可だけを含んだ既定の共有アクセス ポリシーは存在しないため、共有アクセス ポリシーを独自に作成する必要があります。

サービス接続レジストリ読み取りのアクセス許可を付与する共有アクセス ポリシーを作成し、そのポリシーの接続文字列を取得するには、次の手順を実行します。

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

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

  3. ポリシー一覧の上にある最初のメニューから、[共有アクセス ポリシーの追加] を選びます。

  4. 右側の [共有アクセス ポリシーの追加] ウィンドウで、serviceAndRegistryRead などのポリシーのわかりやすい名前を入力します。 [アクセス許可][レジストリ読み取り][サービス接続] を選び、[追加] を選びます。

    新しい共有アクセス ポリシーを追加する方法を示すスクリーン キャプチャ。

  5. ポリシーの一覧から、新しいポリシーを選択します。

  6. [プライマリ接続文字列] のコピー アイコンを選び、その値を保存します。

    接続文字列を取得する方法を示すスクリーン キャプチャ。

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

報告されたプロパティを更新するデバイス アプリを作成する

このセクションでは、myDeviceId としてハブに接続される Java コンソール アプリを作成し、そのデバイス ツインの報告されたプロパティを更新して、接続に携帯ネットワークが使用されていることを確認します。

  1. コマンド プロンプトで次のコマンドを使用して、iot-java-twin-getstarted フォルダー内に 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-device-client パッケージを使用して IoT ハブと通信できるようになります。

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

    private static String connString = "{yourdeviceconnectionstring}";
    private static IotHubClientProtocol protocol = IotHubClientProtocol.MQTT;
    private static String deviceId = "myDeviceId";
    

    このサンプル アプリでは、DeviceClient オブジェクトをインスタンス化するときに protocol 変数が使用されます。

  10. デバイス ツインの更新に関する情報を出力するには、次のメソッドを App クラスに追加します。

    protected static class DeviceTwinStatusCallBack implements IotHubEventCallback {
        @Override
        public void execute(IotHubStatusCode status, Object context) {
          System.out.println("IoT Hub responded to device twin operation with status " + status.name());
        }
      }
    
  11. main メソッドのコードを次のコードに置き換えます。

    • IoT Hub と通信するデバイス クライアントを作成します。

    • デバイス ツインのプロパティを格納する Device オブジェクトを作成します。

    DeviceClient client = new DeviceClient(connString, protocol);
    
    // Create a Device object to store the device twin properties
    Device dataCollector = new Device() {
      // Print details when a property value changes
      @Override
      public void PropertyCall(String propertyKey, Object propertyValue, Object context) {
        System.out.println(propertyKey + " changed to " + propertyValue);
      }
    };
    
  12. 報告されるプロパティ connectivityType を作成して IoT Hub に送信する次のコードを main メソッドに追加します。

    try {
      // Open the DeviceClient and start the device twin services.
      client.open();
      client.startDeviceTwin(new DeviceTwinStatusCallBack(), null, dataCollector, null);
    
      // Create a reported property and send it to your IoT hub.
      dataCollector.setReportedProp(new Property("connectivityType", "cellular"));
      client.sendReportedProperties(dataCollector.getReportedProp());
    }
    catch (Exception e) {
      System.out.println("On exception, shutting down \n" + " Cause: " + e.getCause() + " \n" + e.getMessage());
      dataCollector.clean();
      client.closeNow();
      System.out.println("Shutting down...");
    }
    
  13. 次のコードを main メソッドの末尾に追加します。 Enter キーが押されるまで待機することで、IoT Hub がデバイス ツイン操作の状態を報告するための時間を取ることができます。

    System.out.println("Press any key to exit...");
    
    Scanner scanner = new Scanner(System.in);
    scanner.nextLine();
    
    dataCollector.clean();
    client.close();
    
  14. main メソッドのシグネチャを変更し、下の例外を追加します。

    public static void main(String[] args) throws URISyntaxException, IOException
    
  15. simulated-device\src\main\java\com\mycompany\app\App.java ファイルを保存して閉じます。

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

    mvn clean package -DskipTests
    

目的のプロパティおよびクエリ ツインを更新するサービス アプリを作成する

このセクションでは、myDeviceId に関連付けられている IoT Hub 内のデバイス ツインに、場所のメタデータをタグとして追加する Java アプリを作成します。 このアプリは、IoT ハブで米国内にあるデバイスのクエリを実行した後、携帯ネットワーク接続を報告しているデバイスのクエリを実行します。

  1. 開発用コンピューターで、iot-java-twin-getstarted という名前の空のフォルダーを作成します。

  2. コマンド プロンプトで次のコマンドを使用して、iot-java-twin-getstarted フォルダー内に add-tags-query という名前の Maven プロジェクトを作成します。

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

  4. テキスト エディターを使用して、add-tags-query フォルダー内の 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. テキスト エディターを使用して、add-tags-query\src\main\java\com\mycompany\app\App.java ファイルを開きます。

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

    import com.microsoft.azure.sdk.iot.service.devicetwin.*;
    import com.microsoft.azure.sdk.iot.service.exceptions.IotHubException;
    
    import java.io.IOException;
    import java.util.HashSet;
    import java.util.Set;
    
  9. 次のクラスレベル変数を App クラスに追加します。 {youriothubconnectionstring} を、「IoT ハブ接続文字列を取得する」でコピーしておいた IoT ハブ接続文字列に置き換えます。

    public static final String iotHubConnectionString = "{youriothubconnectionstring}";
    public static final String deviceId = "myDeviceId";
    
    public static final String region = "US";
    public static final String plant = "Redmond43";
    
  10. main メソッドのシグネチャを、次の throws 句を含むように更新します。

    public static void main( String[] args ) throws IOException
    
  11. main メソッドのコードを、DeviceTwin オブジェクトと DeviceTwinDevice オブジェクトを作成する次のコードに置き換えます。 DeviceTwin オブジェクトは、IoT Hub との通信を処理します。 DeviceTwinDevice オブジェクトは、プロパティとタグを使用してデバイス ツインを表現します。

    // Get the DeviceTwin and DeviceTwinDevice objects
    DeviceTwin twinClient = DeviceTwin.createFromConnectionString(iotHubConnectionString);
    DeviceTwinDevice device = new DeviceTwinDevice(deviceId);
    
  12. 次の try/catch ブロックを main メソッドに追加します。

    try {
      // Code goes here
    } catch (IotHubException e) {
      System.out.println(e.getMessage());
    } catch (IOException e) {
      System.out.println(e.getMessage());
    }
    
  13. デバイス ツインの region タグと plant タグを更新するには、次のコードを try ブロックに追加します。

    // Get the device twin from IoT Hub
    System.out.println("Device twin before update:");
    twinClient.getTwin(device);
    System.out.println(device);
    
    // Update device twin tags if they are different
    // from the existing values
    String currentTags = device.tagsToString();
    if ((!currentTags.contains("region=" + region) && !currentTags.contains("plant=" + plant))) {
      // Create the tags and attach them to the DeviceTwinDevice object
      Set<Pair> tags = new HashSet<Pair>();
      tags.add(new Pair("region", region));
      tags.add(new Pair("plant", plant));
      device.setTags(tags);
    
      // Update the device twin in IoT Hub
      System.out.println("Updating device twin");
      twinClient.updateTwin(device);
    }
    
    // Retrieve the device twin with the tag values from IoT Hub
    System.out.println("Device twin after update:");
    twinClient.getTwin(device);
    System.out.println(device);
    
  14. IoT hub でデバイス ツインのクエリを実行するには、前の手順で追加した try ブロックの後ろに次のコードを追加します。 このコードは、2 つのクエリを実行します。 各クエリでは、最大 100 台のデバイスが返されます。

    // Query the device twins in IoT Hub
    System.out.println("Devices in Redmond:");
    
    // Construct the query
    SqlQuery sqlQuery = SqlQuery.createSqlQuery("*", SqlQuery.FromType.DEVICES, "tags.plant='Redmond43'", null);
    
    // Run the query, returning a maximum of 100 devices
    Query twinQuery = twinClient.queryTwin(sqlQuery.getQuery(), 100);
    while (twinClient.hasNextDeviceTwin(twinQuery)) {
      DeviceTwinDevice d = twinClient.getNextDeviceTwin(twinQuery);
      System.out.println(d.getDeviceId());
    }
    
    System.out.println("Devices in Redmond using a cellular network:");
    
    // Construct the query
    sqlQuery = SqlQuery.createSqlQuery("*", SqlQuery.FromType.DEVICES, "tags.plant='Redmond43' AND properties.reported.connectivityType = 'cellular'", null);
    
    // Run the query, returning a maximum of 100 devices
    twinQuery = twinClient.queryTwin(sqlQuery.getQuery(), 3);
    while (twinClient.hasNextDeviceTwin(twinQuery)) {
      DeviceTwinDevice d = twinClient.getNextDeviceTwin(twinQuery);
      System.out.println(d.getDeviceId());
    }
    
  15. add-tags-query\src\main\java\com\mycompany\app\App.java ファイルを保存して閉じます。

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

    mvn clean package -DskipTests
    

アプリの実行

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

  1. add-tags-query フォルダーのコマンド プロンプトで、次のコマンドを実行して、add-tags-query サービス アプリを実行します。

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

    add-tags-query サービス アプリを実行するコマンドからの出力のスクリーンショット。

    デバイス ツインに plant タグと region タグが追加されていることを確認できます。 最初のクエリはデバイスを返しますが、2 つ目のクエリは返しません。

  2. simulated-device フォルダーのコマンド プロンプトで、次のコマンドを実行して、報告されるプロパティ connectivityType をデバイス ツインに追加します。

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

    デバイス クライアントによって、報告されるプロパティ connectivity Type が追加される

  3. add-tags-query フォルダーのコマンド プロンプトで、次のコマンドを実行して、add-tags-query サービス アプリの 2 回目の実行を行います。

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

    タグの値を更新し、デバイスのクエリを実行する Java IoT Hub サービス アプリ

    デバイスによって connectivityType プロパティが IoT Hub に送信されているため、2 回目のクエリではデバイスが返ります。

この記事では、次の内容について説明します。

  • バックエンド アプリからタグとしてデバイス メタデータを追加しました
  • デバイス ツインでデバイス接続情報を報告しました
  • SQL に似た IoT Hub クエリ言語を使用して、デバイス ツイン情報のクエリを実行しました

次のステップ

参照: