IoT Hub のモジュール ツインの理解と使用
IoT Hub では、デバイス ID ごとに最大 50 のモジュール ID を作成できます。 モジュールの ID ごとに、モジュール ツインは暗黙的に生成されます。 モジュール ツインは、デバイス ツインと同様、モジュールの状態に関する情報 (メタデータ、構成、状態など) を格納する JSON ドキュメントです。 Azure IoT Hub は、IoT Hub に接続したモジュールごとにモジュール ツインを管理します。
この記事は、「IoT Hub のデバイス ツインの理解と使用」をすでに読んでいることを前提としています。
デバイス側では、IoT Hub デバイスのソフトウェア開発キット (SDK) を使用して、それぞれが IoT Hub への独立した接続を確立するモジュールを作成できます。 この機能により、デバイスのさまざまなコンポーネントごとに個別の名前空間を使用することができます。 たとえば、3 つの異なるセンサーが付いた自動販売機があるとします。 各センサーは、社内の異なる部署によって管理されています。 各センサーのモジュールを作成して、部門が管理するセンサーにのみジョブを送信したりメソッドを直接送信したりできるようにすることで、競合やユーザー エラーを回避できます。
モジュール ID とモジュール ツインは、デバイス ID とデバイス ツインと同様の機能を、より細かい粒度で提供します。 このより細かい粒度により、オペレーティング システム ベースのデバイスやファームウェア デバイスなどの複数のコンポーネントで構成され、この機能をサポートするデバイスの各コンポーネントの構成と状態を特定できます。 モジュール形式のソフトウェア コンポーネントを含む IoT デバイスを使用する場合、モジュール ID とモジュール ツインを使用することで、コンポーネントの管理を分割できます。 マイクロソフトは、モジュール ツインの一般可用性により、モジュール ツイン レベルですべてのデバイス ツイン機能をサポートすることを目指しています。
Note
この記事で説明されている機能は、Standard レベルの IoT Hub でのみ使用できます。 Basic および Standard または Free レベルの IoT Hub の詳細については、ソリューションに適した IoT Hub のレベルの選択に関するページを参照してください。
この記事では、次の内容について説明します。
- モジュール ツインの構造: タグ、必要なプロパティ、報告されるプロパティ。
- デバイス アプリケーションとソリューション バックエンドがモジュール ツインに対して実行できる操作。
報告されるプロパティ、device-to-cloud メッセージ、ファイルのアップロードのどれを使用するべきかの指針については、「device-to-cloud 通信に関するガイダンス」を参照してください。
必要なプロパティ、ダイレクト メソッド、cloud-to-device メッセージの使用に関する指針については、「cloud-to-device 通信に関するガイダンス」を参照してください。
モジュール ツイン
モジュール ツインには、モジュールに関連する次のような情報が格納されます。
デバイス上のモジュールと IoT Hub がモジュールの状態と構成を同期するために使用できます。
実行時間の長い操作にクエリを行い、ターゲットを設定するために使用するソリューション バックエンド。
モジュール ツインのライフサイクルは、対応するモジュール ID にリンクされます。 モジュール ツインは、IoT Hub でモジュール ID を作成または削除したときに、暗黙的に作成または削除されます。
モジュール ツインは、次の情報を含む JSON ドキュメントです。
タグ。 バックエンド アプリが読み取りおよび書き込みを行うことができる JSON ドキュメントのセクション。 タグは、デバイス上のモジュールからは認識されません。 タグは、クエリの目的で設定されます。
必要なプロパティ。 モジュールの構成や状態を同期するために、報告されるプロパティと共に使用します。 バックエンド アプリは必要なプロパティを設定でき、モジュール アプリはそれらをを読み取ることができます。 モジュール アプリでは、必要なプロパティに対する変更を知らせる通知を受け取ることもできます。
報告されるプロパティ。 モジュールの構成や状態を同期するために、必要なプロパティと共に使用します。 モジュール アプリは報告されるプロパティを設定でき、バックエンド アプリはそれらを読み取りクエリを実行できます。
モジュール ID のプロパティ。 モジュール ツインの JSON ドキュメントのルートには、ID レジストリに格納される対応するモジュール ID の読み取り専用プロパティが含まれます。
次の例は、モジュール ツインの JSON ドキュメントを示しています。
{
"deviceId": "devA",
"moduleId": "moduleA",
"etag": "AAAAAAAAAAc=",
"status": "enabled",
"statusReason": "provisioned",
"statusUpdateTime": "0001-01-01T00:00:00",
"connectionState": "connected",
"lastActivityTime": "2015-02-30T16:24:48.789Z",
"cloudToDeviceMessageCount": 0,
"authenticationType": "sas",
"x509Thumbprint": {
"primaryThumbprint": null,
"secondaryThumbprint": null
},
"version": 2,
"tags": {
"deploymentLocation": {
"building": "43",
"floor": "1"
}
},
"properties": {
"desired": {
"telemetryConfig": {
"sendFrequency": "5m"
},
"$metadata" : {...},
"$version": 1
},
"reported": {
"telemetryConfig": {
"sendFrequency": "5m",
"status": "success"
},
"batteryLevel": 55,
"$metadata" : {...},
"$version": 4
}
}
}
最上位レベルでは、モジュール ツイン オブジェクトには、モジュール ID プロパティと、tags
および reported
と desired
の両方のプロパティのコンテナー オブジェクトが含まれています。 properties
コンテナーには、「モジュール ツインのメタデータ」と「オプティミスティック コンカレンシー」セクションで説明されているいくつかの読み取り専用の要素 ($metadata
と $version
) が含まれています。
報告されるプロパティの例
前の例では、モジュール ツインには batteryLevel
reported プロパティが含まれています。 このプロパティでは、最後に報告されたバッテリ レベルに基づいて、モジュール上でクエリや操作を実行できます。 別の例には、モジュール アプリにモジュールの報告機能や接続オプションが含まれています。
Note
reported プロパティにより、関心の対象がプロパティの最新の既知の値である場合のシナリオが簡素化されます。 時系列などのタイムスタンプ付きイベントのシーケンスでモジュール テレメトリを処理する場合は、device-to-cloud メッセージを使用します。
必要なプロパティの例
前の例では、telemetryConfig
モジュール ツインの desired プロパティと reported プロパティが、バックエンド アプリとモジュール アプリによって使用され、このモジュールのテレメトリ構成が同期されます。 次に例を示します。
バックエンド アプリでは、desired プロパティが必要な構成値で設定されます。 以下は、ドキュメント内の必要なプロパティ セットを使用した部分です。
... "desired": { "telemetryConfig": { "sendFrequency": "5m" }, ... }, ...
モジュール アプリには、モジュールが接続されている場合、変更がすぐに通知されます。 接続されていない場合、モジュール アプリは接続時にモジュールの再接続フローに従います。 その後、モジュール アプリが更新された構成 (またはエラー条件。
status
プロパティを使用) を報告します。 報告されるプロパティの部分を次に示します。"reported": { "telemetryConfig": { "sendFrequency": "5m", "status": "success" } ... }
バックエンド アプリは、モジュール ツインのクエリを実行することによって、複数のモジュールとの間で行われる構成操作の結果を追跡できます。
Note
上記のスニペットは、モジュール構成とその状態をエンコードするための例の 1 つであり、読みやすいように最適化されています。 IoT Hub は、モジュール ツインの必要なプロパティや報告されたプロパティに対して、モジュール ツイン用の特定のスキーマを強制しません。
重要
IoT プラグ アンド プレイでは、いくつかの追加プロパティを使用して、必要なプロパティと報告されるプロパティに対する変更を同期するスキーマを定義します。 ソリューションで IoT プラグ アンド プレイを使用する場合は、ツインのプロパティを更新するときにプラグ アンド プレイ規則に従う必要があります。 詳細と例については、IoT プラグ アンド プレイの書き込み可能なプロパティをご覧ください。
バック エンドの操作
バックエンド アプリは、HTTPS を介して公開される次のアトミック操作を使用して、モジュール ツインを操作します。
ID を条件にモジュールを取得する。 この操作は、タグ、必要なシステム プロパティ、報告されるシステム プロパティを含むモジュール ツインのドキュメントを返します。
モジュール ツインを部分的に更新する。 この操作は、モジュール ツイン内の tags または desired プロパティを部分的に更新します。 部分的な更新は JSON ドキュメントとして表され、プロパティが追加または更新されます。
null
に設定されたプロパティが削除されます。 次の例では、{"newProperty": "newValue"}
の値を持つ新しい必要なプロパティが作成され、existingProperty
の既存の値が"otherNewValue"
で上書きされ、otherOldProperty
が削除されます。 それ以外、既にある必要なプロパティまたはタグは変更されません。{ "properties": { "desired": { "newProperty": { "nestedProperty": "newValue" }, "existingProperty": "otherNewValue", "otherOldProperty": null } } }
必要なプロパティの置換 この操作は、既存の desired プロパティをすべて完全に上書きし、
properties/desired
を新しい JSON ドキュメントに置き換えます。タグの置換 この操作は、既存の tags をすべて完全に上書きし、
tags
を新しい JSON ドキュメントに置き換えます。ツイン通知の受信 この操作は、ツインが変更されたときに通知します。 モジュール ツインの変更通知を受信するには、IoT ソリューションでルートを作成し、データ ソースの値を twinChangeEvents に設定する必要があります。 既定では、このようなルートは存在しないため、ツイン通知は送信されません。 変化率が高すぎる場合、または内部エラーなどの理由のために、IoT Hub はすべての変更を含む 1 つの通知のみを送信する場合があります。 そのため、アプリケーションに信頼性の高い監査とすべての中間状態のログ記録が必要な場合は、device-to-cloud メッセージを使用する必要があります。 ツイン通知メッセージで返されるプロパティと本文の詳細については、非テレメトリ イベント スキーマに関するページを参照してください。
上述の操作はすべてオプティミスティック コンカレンシーをサポートしており、「IoT Hub へのアクセスの制御」の記事で定義されているとおり、ServiceConnect アクセス許可を必要とします。
これらの操作に加えて、バックエンド アプリは SQL に似た IoT Hub クエリ言語を使用してモジュール ツインのクエリを実行できます。
モジュールの操作
モジュール アプリは、次のアトミック操作を使用して、モジュール ツインを操作します。
モジュール ツインを取得する この操作は、必要なシステム プロパティ、報告されるシステム プロパティを含む、現在接続されているモジュールのモジュール ツインのドキュメントを返します。
報告されるプロパティの部分的な更新 この操作では、現在接続されているモジュールの報告されるプロパティを部分的に更新できます。
必要なプロパティの監視 現在接続されているモジュールでは、必要なプロパティの更新が行われたときに通知をするように設定できます。
「IoT Hub へのアクセスの制御」の記事に定義されているように、上述の操作にはすべて DeviceConnect アクセス許可が必要です。
Azure IoT device SDK を使用すると、多数の言語とプラットフォームで上述の操作を簡単に使用できます。
タグやプロパティの形式
タグ、必要なプロパティ、報告されるプロパティは JSON オブジェクトであり、次のような制限があります。
キー: JSON オブジェクト内のすべてのキーは UTF-8 でエンコードされ、大文字と小文字が区別され、最大 1 KB の長さです。 UNICODE 制御文字列 (セグメント C0 と C1)、
.
、$
、SP は使用できません。値:JSON オブジェクトのすべての値には、ブール値、数値、文字列、オブジェクトの JSON 型を使用できます。 配列もサポートされています。
使用できる整数の範囲は、-4503599627370496 (最小値) から 4503599627370495 (最大値) までです。
文字列値は UTF-8 でエンコードされ、最大長は 4 KB です。
深さ: タグ、必要なプロパティ、およびレポートされるプロパティにおける JSON オブジェクトの深さは最大で 10 です。 たとえば、次のオブジェクトは有効です。
{ ... "tags": { "one": { "two": { "three": { "four": { "five": { "six": { "seven": { "eight": { "nine": { "ten": { "property": "value" } } } } } } } } } } }, ... }
モジュール ツインのサイズ
IoT Hub では tags
の値に 8 KB のサイズ制限が適用され、properties/desired
と properties/reported
の値にそれぞれ 32 KB のサイズ制限が適用されます。 これらの合計には、$version
や $metadata/$lastUpdated
などの読み取り専用の要素は含まれません。
ツインのサイズは、次のように計算されます。
IoT Hub は、各プロパティのキーと値の長さを累積的に計算して追加します。
プロパティ キーは、UTF8 でエンコードされた文字列と見なされます。
単純なプロパティ値は、UTF8 でエンコードされた文字列、数値 (8 バイト)、またはブール値 (4 バイト) と見なされます。
UTF8 でエンコードされた文字列のサイズは、UNICODE 制御文字 (セグメント C0 と C1) を除くすべての文字をカウントして計算されます。
複合プロパティ値 (入れ子になったオブジェクト) は、プロパティ キーの合計サイズと、そこに含まれるプロパティ値に基づいて計算されます。
ドキュメントのサイズが上述の制限を超えると、IoT Hub はすべての操作を拒否して、エラーを返します。
モジュール ツインのメタデータ
IoT Hub は、各 JSON オブジェクトが最後に更新されたときのタイムスタンプを、モジュール ツインの必要なプロパティと報告されるプロパティに保持します。 タイムスタンプは UTC であり、ISO8601 形式の YYYY-MM-DDTHH:MM:SS.mmmZ
でエンコードされます。
次に例を示します。
{
...
"properties": {
"desired": {
"telemetryConfig": {
"sendFrequency": "5m"
},
"$metadata": {
"telemetryConfig": {
"sendFrequency": {
"$lastUpdated": "2016-03-30T16:24:48.789Z"
},
"$lastUpdated": "2016-03-30T16:24:48.789Z"
},
"$lastUpdated": "2016-03-30T16:24:48.789Z"
},
"$version": 23
},
"reported": {
"telemetryConfig": {
"sendFrequency": "5m",
"status": "success"
},
"batteryLevel": "55%",
"$metadata": {
"telemetryConfig": {
"sendFrequency": "5m",
"status": {
"$lastUpdated": "2016-03-31T16:35:48.789Z"
},
"$lastUpdated": "2016-03-31T16:35:48.789Z"
},
"batteryLevel": {
"$lastUpdated": "2016-04-01T16:35:48.789Z"
},
"$lastUpdated": "2016-04-01T16:24:48.789Z"
},
"$version": 123
}
}
...
}
この情報は、オブジェクトのキーによって削除される更新を保持するために、JSON の構造のリーフだけでなくすべてのレベルで保持されます。
オプティミスティック コンカレンシー
タグ、必要なプロパティ、報告されたプロパティはすべて、オプティミスティック コンカレンシーをサポートします。 ツイン プロパティの更新の順序を保証する必要がある場合は、次の更新を送信する前に、報告されたプロパティのコールバックを待って、アプリケーション レベルで同期を実装することを検討してください。
モジュール ツインには、RFC7232 に従って、ツインの JSON 表現を表す ETag (etag
プロパティ) があります。 バックエンド アプリからの条件付き更新操作で etag
プロパティを使用すると、一貫性を保持できます。 このオプションにより、tags
コンテナーに関連する操作の一貫性が確保されます。
モジュール ツインが必要とする、および報告されるプロパティにも、増分が保証された $version
の値があります。 ETag と同様に、バージョン値を使用して更新の一貫性を強制できます。 たとえば、reported プロパティ用のモジュール アプリ、または desired プロパティ用のバックエンド アプリなどです。
バージョンは、監視エージェント (必要なプロパティを監視するモジュール アプリなど) が取得操作に関する結果と更新の通知の間の競合を調整する場合に便利です。 詳細については、「モジュールの再接続フロー」セクションを参照してください。
モジュールの再接続フロー
IoT Hub では、desired プロパティの更新通知は接続されていないモジュール用に保持されません。 つまり、接続しているモジュールは必要なプロパティの完全なドキュメントを取得し、さらに更新通知にサブスクライブする必要があります。 更新通知と完全取得で競合が発生する場合、次のフローを実行する必要があります。
- モジュール アプリを IoT hub に接続する。
- モジュール アプリを、必要なプロパティの更新通知にサブスクライブする。
- モジュール アプリで、必要なプロパティの完全なドキュメントを取得する。
$version
が取得した完全なドキュメントのバージョン以下の場合、モジュール アプリではすべての通知を無視できます。 IoT Hub ではバージョンが常に増分されるため、このようなアプローチが可能になります。
次のステップ
この記事で説明した概念を試すには、次の IoT Hub のチュートリアルをご覧ください。