IoT Hub を使用したクラウドからデバイスへのメッセージの送信 (Java)

Azure IoT Hub は、何百万ものデバイスとソリューション バックエンドの間に信頼性のある保護された双方向通信を確立するのに役立つ、フル マネージドのサービスです。

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

  • ソリューション バックエンドから IoT Hub 経由で単一のデバイスに cloud-to-device (C2D) メッセージを送信する

  • cloud-to-device メッセージをデバイスで受信する

  • ソリューション バックエンドから、IoT Hub からデバイスに送信されたメッセージの配信確認 ("フィードバック") を要求する

注意

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

この記事の最後に、次の 2 つの Java コンソール アプリを実行します。

  • HandleMessages: Microsoft Azure IoT SDK for Java に含まれているサンプル デバイス アプリ。これは、IoT ハブに接続し、cloud-to-device メッセージを受信します。

  • SendCloudToDevice: cloud-to-device メッセージを IoT Hub を介してデバイス アプリに送信し、その配信確認を受け取ります。

Note

IoT Hub には、Azure IoT device SDK を介して、多数のデバイス プラットフォームと言語 (C、Java、Python、JavaScript) に対する SDK サポートがあります。

cloud-to-device メッセージの詳細については、「IoT ハブから cloud-to-device メッセージを送信する」を参照してください。

前提条件

  • Azure サブスクリプション。 Azure サブスクリプションをお持ちでない場合は、開始する前に 無料アカウント を作成してください。

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

  • お使いの IoT ハブに登録されているデバイス。 デバイスをまだ登録していない場合は、Azure portal に登録します。

  • この記事では、Java 向けの Azure IoT SDK のサンプル コードを使用します。

    • GitHub から開発用マシンに SDK リポジトリをダウンロードするか、複製します。
    • 開発用マシンに Java SE Development Kit 8 がインストールされていることを確認します。 JDK 8 のダウンロードを利用するには、「長期サポート」の「Java 8」を選択します。
  • Maven 3

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

デバイスの接続文字列を取得する

この記事では、デバイスをシミュレートするサンプル アプリを実行します。これは、IoT Hub 経由で送信された cloud-to-device メッセージを受信します。 Microsoft Azure IoT SDK for Java に含まれる HandleMessages サンプル アプリは、IoT ハブに接続し、シミュレートされたデバイスとして動作します。 このサンプルは、IoT ハブに登録されているデバイスのプライマリ接続文字列を使用します。

IoT ハブに登録されているデバイスのプライマリ接続文字列を取得するには、次の手順に従います。

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

  2. IoT ハブの左側ペインの [デバイス管理] の下にある [デバイス] を選択します。

  3. デバイスの一覧から、該当するデバイスを選択します。

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

    Azure portal で IoT ハブに登録されているデバイスからプライマリ接続文字列を取得する方法を示すスクリーンショット。

デバイス アプリでメッセージを受信する

このセクションでは、HandleMessages サンプル デバイス アプリを実行して、IoT ハブ経由で送信された C2D メッセージを受信します。 新しいコマンド プロンプトを開き、Azure IoT Java SDK を解凍したフォルダーの下の azure-iot-sdk-java\iothub\device\iot-device-samples\handle-messages フォルダーに移動します。 {Your device connection string} プレースホルダーの値を IoT ハブに登録されているデバイスからコピーしたデバイス接続文字列に置き換えて、次のコマンドを実行します。

mvn clean package -DskipTests
java -jar ./target/handle-messages-1.0.0-with-deps.jar "{Your device connection string}"

サンプル デバイス アプリが正常に起動して IoT ハブに接続すると、次のように出力されます。

5/22/2023 11:13:18 AM> Press Control+C at any time to quit the sample.
     
Starting...
Beginning setup.
Successfully read input parameters.
Using communication protocol MQTT.
2023-05-23 09:51:06,062 INFO (main) [com.microsoft.azure.sdk.iot.device.transport.ExponentialBackoffWithJitter] - NOTE: A new instance of ExponentialBackoffWithJitter has been created with the following properties. Retry Count: 2147483647, Min Backoff Interval: 100, Max Backoff Interval: 10000, Max Time Between Retries: 100, Fast Retry Enabled: true
2023-05-23 09:51:06,187 DEBUG (main) [com.microsoft.azure.sdk.iot.device.ClientConfiguration] - Device configured to use software based SAS authentication provider
2023-05-23 09:51:06,187 INFO (main) [com.microsoft.azure.sdk.iot.device.transport.ExponentialBackoffWithJitter] - NOTE: A new instance of ExponentialBackoffWithJitter has been created with the following properties. Retry Count: 2147483647, Min Backoff Interval: 100, Max Backoff Interval: 10000, Max Time Between Retries: 100, Fast Retry Enabled: true
2023-05-23 09:51:06,202 DEBUG (main) [com.microsoft.azure.sdk.iot.device.DeviceClient] - Initialized a DeviceClient instance using SDK version 2.1.5
Successfully created an IoT Hub client.
Successfully set message callback.
2023-05-23 09:51:06,205 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.mqtt.MqttIotHubConnection] - Opening MQTT connection...
2023-05-23 09:51:06,218 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.mqtt.Mqtt] - Sending MQTT CONNECT packet...
2023-05-23 09:51:07,308 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.mqtt.Mqtt] - Sent MQTT CONNECT packet was acknowledged
2023-05-23 09:51:07,308 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.mqtt.Mqtt] - Sending MQTT SUBSCRIBE packet for topic devices/US60536-device/messages/devicebound/#
2023-05-23 09:51:07,388 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.mqtt.Mqtt] - Sent MQTT SUBSCRIBE packet for topic devices/US60536-device/messages/devicebound/# was acknowledged
2023-05-23 09:51:07,388 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.mqtt.MqttIotHubConnection] - MQTT connection opened successfully
2023-05-23 09:51:07,388 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.IotHubTransport] - The connection to the IoT Hub has been established
2023-05-23 09:51:07,404 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.IotHubTransport] - Updating transport status to new status CONNECTED with reason CONNECTION_OK
2023-05-23 09:51:07,404 DEBUG (main) [com.microsoft.azure.sdk.iot.device.DeviceIO] - Starting worker threads
2023-05-23 09:51:07,408 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.IotHubTransport] - Invoking connection status callbacks with new status details

CONNECTION STATUS UPDATE: CONNECTED
CONNECTION STATUS REASON: CONNECTION_OK
CONNECTION STATUS THROWABLE: null

The connection was successfully established. Can send messages.
2023-05-23 09:51:07,408 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.IotHubTransport] - Client connection opened successfully
2023-05-23 09:51:07,408 INFO (main) [com.microsoft.azure.sdk.iot.device.DeviceClient] - Device client opened successfully
Opened connection to IoT Hub. Messages sent to this device will now be received.
Press any key to exit...

AppMessageCallback クラスの execute メソッドは、IotHubMessageResult.COMPLETE を返します。 この状態によって、メッセージが正常に処理されたこと、およびメッセージはデバイスのキューから安全に削除できることが IoT Hub に通知されます。 デバイスは、使用しているプロトコルに関係なく、処理が正常に完了したときに、この値を返す必要があります。

MQTT ではなく AMQP と HTTPS を使用する場合、デバイスは次の処理もできます。

  • メッセージを破棄します。この場合、IoT Hub は将来の使用に備えてメッセージをデバイスのキュー内に保持します。
  • メッセージを拒否します。この場合、メッセージはデバイスのキューから完全に削除されます。

デバイスがメッセージを完了、破棄、または拒否することを妨げる問題が発生した場合、IoT Hub は一定のタイムアウト期間が経過した後で、メッセージの配信をキューに入れます。 このような理由から、同じメッセージを複数回受信した場合に生成される結果が毎回同じになるように、デバイス アプリ内のメッセージ処理ロジックをべき等にする必要があります。

cloud-to-device メッセージのライフサイクルと、IoT Hub が cloud-to-device メッセージを処理する方法の詳細については、「IoT ハブから cloud-to-device メッセージを送信する」を参照してください。

注意

トランスポートとして AMQP の代わりに HTTPS を使用した場合、DeviceClient インスタンスが IoT Hub からのメッセージをチェックする頻度は低くなります (最小 25 分の間隔)。 MQTT、AMQP、および HTTPS のサポートの相違点の詳細については、「cloud-to-device 通信に関するガイダンス」と「通信プロトコルの選択」を参照してください。

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

この記事では、IoT Hub を介して cloud-to-device メッセージを送信するバックエンド サービスを作成します。 cloud-to-device メッセージを送信するサービスには、サービス接続のアクセス許可が必要となります。 既定では、どの IoT Hub も、このアクセス許可を付与する service という名前の共有アクセス ポリシーがある状態で作成されます。

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

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

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

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

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

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

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

C2D メッセージを送信する

このセクションでは、クラウドからデバイスへのメッセージを、シミュレーション済みデバイス アプリに送信する Java コンソール アプリを作成します。 デバイスからのデバイス ID と IoT ハブの接続文字列が必要です。

  1. コマンド プロンプトで次のコマンドを使用して、send-c2d-messages という Maven プロジェクトを作成します。 このコマンドが 1 つの長いコマンドであることに注意してください。

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

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

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

    注意

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

  4. pom.xml ファイルを保存して閉じます。

  5. テキスト エディターを使用し、send-c2d-messages\src\main\java\com\mycompany\app\App.java ファイルを開きます。

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

    import com.microsoft.azure.sdk.iot.service.*;
    import java.io.IOException;
    import java.net.URISyntaxException;
    
  7. 次のクラス レベルの変数を App クラスに追加し、 {yourhubconnectionstring}{yourdeviceid} を先にメモした値に置き換えます。

    private static final String connectionString = "{yourhubconnectionstring}";
    private static final String deviceId = "{yourdeviceid}";
    private static final IotHubServiceClientProtocol protocol =    
        IotHubServiceClientProtocol.AMQPS;
    
  8. main メソッドを次のコードで置き換えます。 このコードは、IoT Hub に接続し、デバイスにメッセージを送信して、デバイスがメッセージを受信して処理したことを示す受信確認を受け取るまで待機します。

    public static void main(String[] args) throws IOException,
        URISyntaxException, Exception {
      ServiceClient serviceClient = ServiceClient.createFromConnectionString(
        connectionString, protocol);
    
      if (serviceClient != null) {
        serviceClient.open();
        FeedbackReceiver feedbackReceiver = serviceClient
          .getFeedbackReceiver();
        if (feedbackReceiver != null) feedbackReceiver.open();
    
        Message messageToSend = new Message("Cloud to device message.");
        messageToSend.setDeliveryAcknowledgement(DeliveryAcknowledgement.Full);
    
        serviceClient.send(deviceId, messageToSend);
        System.out.println("Message sent to device");
    
        FeedbackBatch feedbackBatch = feedbackReceiver.receive(10000);
        if (feedbackBatch != null) {
          System.out.println("Message feedback received, feedback time: "
            + feedbackBatch.getEnqueuedTimeUtc().toString());
        }
    
        if (feedbackReceiver != null) feedbackReceiver.close();
        serviceClient.close();
      }
    }
    

    注意

    わかりやすくするために、この記事では再試行ポリシーは実装しません。 運用環境のコードでは、「一時的な障害の処理」の記事で推奨されているように、再試行ポリシー (指数関数的バックオフなど) を実装することをお勧めします。

  9. Maven を使用して send-c2d-messages アプリをビルドするには、コマンド プロンプトで simulated-device フォルダーに移動し、次のコマンドを実行します。

    mvn clean package -DskipTests
    

アプリケーションの実行

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

  1. azure-iot-sdk-java\iothub\device\iot-device-samples\handle-messages フォルダーのコマンド プロンプトで、{Your device connection string} プレースホルダーの値を IoT ハブの登録済みデバイスからコピーしたデバイス接続文字列に置き換えて次のコマンドを実行します。 この手順は、IoT ハブにテレメトリを送信し、ハブから送信された cloud-to-device メッセージをリッスンするサンプル デバイス アプリを開始します。

    java -jar ./target/handle-messages-1.0.0-with-deps.jar "{Your device connection string}"
    

    コンソール ウィンドウで実行されているサンプル デバイス アプリのスクリーンショット。

  2. コマンド プロンプトの send-c2d-messages フォルダーで、次のコマンドを実行して cloud-to-device メッセージを送信し、フィードバックの確認を待機します。

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

    コンソール ウィンドウで実行されているサンプル サービス アプリのスクリーンショット。

次のステップ

この記事では、cloud-to-device メッセージを送受信する方法を学習しました。