この記事では、Device Update for IoT Hub コンポーネント列挙子の実装例を示します。 この例を参照して、IoT デバイス用のカスタム コンポーネント列挙子を実装できます。 コンポーネントは、ホスト デバイスとの合成関係があるデバイス レベルの ID です。
この記事では、Contoso Virtual Vacuum という仮想 IoT デバイスを使用するコンポーネント列挙子を示します。 コンポーネント列挙子は、"プロキシ更新" 機能を実装するために使用されます。
プロキシ更新 は、1 回の無線によるデプロイで、同じ IoT デバイス上の複数のコンポーネントや、IoT デバイスに接続された複数のセンサーを更新できます。 プロキシ更新では、コンポーネントを更新するためのインストール順序がサポートされています。 また、インストール前、インストール、インストール後の機能を使用した複数ステップの更新もサポートされています。
プロキシ更新が適用されるユース ケースは次のとおりです。
- デバイスのパーティションを対象とする特定の更新ファイル。
- デバイスのアプリ/コンポーネントを対象とする特定の更新ファイル。
- ネットワーク プロトコル (たとえば、USB や CAN バスなど) を介して IoT デバイスに接続されたセンサーを対象とした特定の更新ファイル。
詳細については、「プロキシ更新と複数コンポーネントの更新」を参照してください。
デバイス更新エージェントは、ホスト デバイスで実行されます。 これは、各更新プログラムを特定のコンポーネント、または同じハードウェア クラスのコンポーネント グループ (つまり、同じソフトウェアまたはファームウェアの更新を必要とする) に送ることができます。
コンポーネント列挙子とは?
コンポーネント列挙子とは、デバイス更新エージェントの拡張機能であり、ホスト デバイスの Azure IoT Hub 接続を介して、無線での更新に必要なすべてのコンポーネントに関する情報を提供します。
デバイス更新エージェントは、デバイスとコンポーネントに依存しません。 エージェント自体では、更新時にホスト デバイス上の (または接続されている) コンポーネントについては何も認識されません。
プロキシ更新を有効にするために、デバイス ビルダーは、デバイス上の更新可能なすべてのコンポーネントを識別し、各コンポーネントに一意の名前を割り当てる必要があります。 また、同じハードウェア クラスのコンポーネントにグループ名を割り当てることができるので、同じグループ内のすべてのコンポーネントに同じ更新プログラムをインストールできます。 これで、更新プログラムのコンテンツ ハンドラーは、正しいコンポーネントに更新プログラムをインストールして適用できます。
プロキシ更新フローの各部分の役割を次に示します。
デバイス ビルダー
デバイスを設計してビルドします。
デバイス更新エージェントとその依存関係を統合します。
デバイス固有のコンポーネント列挙子拡張機能を実装し、デバイス更新エージェントに登録します。
コンポーネント列挙子は、コンポーネント インベントリまたは構成ファイルの情報を使用して、静的コンポーネント データ (デバイス更新で必要) を動的データ (ファームウェアのバージョン、接続状態、ハードウェア ID など) で拡張します。
デバイス上の (または接続されている) 1 つまたは複数のコンポーネントを対象とする 1 つ以上の子更新プログラムを含むプロキシ更新プログラムを作成します。
ソリューション オペレーターに更新プログラムを送信します。
ソリューション オペレーター
更新プログラムとマニフェストをデバイス更新サービスにインポートします。
更新プログラムをデバイス グループにデプロイします。
デバイス更新エージェント
デバイス ツインまたはモジュール ツインを介して IoT Hub から更新情報を取得します。
デバイス上の 1 つまたは複数のコンポーネントを対象としたプロキシ更新を処理するために、"ステップ ハンドラー" を呼び出します。
この記事の例には、2 つの更新プログラム (
host-fw-1.1
とmotors-fw-1.1
) があります。 親ステップ ハンドラーは、子更新ごとに子ステップ ハンドラーを呼び出して、子更新のマニフェスト ファイルで指定されているCompatibilities
プロパティに一致するすべてのコンポーネントを列挙します。 次に、ハンドラーは、すべての対象コンポーネントに対して、子更新プログラムをダウンロードしてインストールし、適用します。一致するコンポーネントを取得するために、子更新はコンポーネント列挙子が提供する
SelectComponents
API を呼び出します。 一致するコンポーネントがない場合、子更新はスキップされます。親更新と子更新からすべての更新結果を収集し、それらの結果を IoT Hub に報告します。
子ステップ ハンドラー
- 子更新プログラムのコンテンツと互換性のあるコンポーネント インスタンスのリストを反復処理します。 詳細は、ステップ ハンドラーを参照してください。
実稼働環境では、デバイス ビルダーは既存のハンドラーを使用するか、または無線での更新に必要な任意のインストーラーを呼び出すカスタム ハンドラーを実装できます。 詳細については、カスタム更新コンテンツ ハンドラーの実装に関する記事を参照してください。
Virtual Vacuum コンポーネント
この記事では、仮想 IoT デバイスを使用して、主要な概念と機能を示します。 Contoso Virtual Vacuum デバイスは、5 つの論理コンポーネントで構成されています。
- ホスト ファームウェア
- ホスト ブート ファイル システム
- ホスト ルート ファイル システム
- 3 つのモーター (左ホイール、右ホイール、バキューム)
- 2 つのカメラ (前面と背面)
次のディレクトリ構造によって、コンポーネントがシミュレートされます。
/usr/local/contoso-devices/vacuum-1/hostfw
/usr/local/contoso-devices/vacuum-1/bootfs
/usr/local/contoso-devices/vacuum-1/rootfs
/usr/local/contoso-devices/vacuum-1/motors/0 /* left motor */
/usr/local/contoso-devices/vacuum-1/motors/1 /* right motor */
/usr/local/contoso-devices/vacuum-1/motors/2 /* vacuum motor */
/usr/local/contoso-devices/vacuum-1/cameras/0 /* front camera */
/usr/local/contoso-devices/vacuum-1/cameras/1 /* rear camera */
各コンポーネントのディレクトリには、各コンポーネントのモック ソフトウェア バージョン番号を格納する JSON ファイルが含まれています。 JSON ファイルの例として、firmware.json や diskimage.json などがあります。
このデモでは、コンポーネントのファームウェアを更新するために、ターゲット コンポーネントのディレクトリに firmware.json または diskimage.json (更新ペイロード) をコピーします。
以下に、firmware.json ファイルの例を示します。
{
"version": "0.5",
"description": "This component is generated for testing purposes."
}
注意
Contoso Virtual Vacuum には、プロキシ更新のデモを実行するためのソフトウェアまたはファームウェアのバージョンが含まれています。 それ以外の機能は提供されません。
コンポーネント列挙子を実装する (C 言語)
要件
component_enumerator_extension.hpp で宣言されている次のすべての API を実装します。
機能 | 引数 | 戻り値 |
---|---|---|
char* GetAllComponents() |
なし | "すべての" ComponentInfo 値の配列が含まれている JSON 文字列。 詳細については、「戻り値の例」を参照してください。 |
char* SelectComponents(char* selector) |
更新対象コンポーネントを選択するために使用する 1 つ以上の名前と値のペアを含む JSON 文字列 | ComponentInfo 値の配列が含まれている JSON 文字列。 詳細については、「戻り値の例」を参照してください。 |
void FreeComponentsDataString(char* string) |
以前に GetAllComponents または SelectComponents 関数で返された文字列バッファーへのポインター |
なし |
ComponentInfo
ComponentInfo
JSON 文字列には、次のプロパティを含める必要があります。
名前 | 種類 | 説明 |
---|---|---|
id |
string | コンポーネントの一意の ID (デバイス スコープ)。 たとえば、ハードウェアのシリアル番号、ディスク パーティション ID、コンポーネントの一意のファイル パスなどです。 |
name |
string | コンポーネントの論理名。 このプロパティは、デバイス ビルダーが、同じ device クラスのすべてのデバイスで利用可能なコンポーネントに割り当てる名前です。たとえば、すべての Contoso Virtual Vacuum デバイスには、左ホイールを駆動するモーターが含まれています。 Contoso は、このモーターの共通 (論理) 名として "左モーター" を割り当て、グローバルに一意であるハードウェア ID ではなく、このコンポーネントを簡単に参照できるようにしました。 |
group |
string | このコンポーネントが属するグループ。 たとえば、すべてのモーターが "モーター" グループに属している場合があります。 |
manufacturer |
string | 物理ハードウェア コンポーネントの場合、このプロパティは製造元またはベンダーの名前です。 ディスク パーティションやディレクトリなどの論理コンポーネントの場合は、デバイス ビルダーの定義済みの値を使用できます。 |
model |
string | 物理ハードウェア コンポーネントの場合、このプロパティはモデル名です。 ディスク パーティションやディレクトリなどの論理コンポーネントの場合、このプロパティには、デバイス ビルダーの定義済みの値を指定できます。 |
properties |
object | 任意のオプションのデバイス固有のプロパティが含まれている JSON オブジェクト。 |
Contoso Virtual Vacuum コンポーネントに基づく ComponentInfo
コードの例を次に示します。
{
"id": "contoso-motor-serial-00000",
"name": "left-motor",
"group": "motors",
"manufacturer": "contoso",
"model": "virtual-motor",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/0",
"firmwareDataFile": "firmware.json",
"status": "connected",
"version" : "motor-fw-1.0"
}
}
戻り値の例
GetAllComponents
関数から返される JSON ドキュメントを次に示します。 これは、Contoso Virtual Vacuum コンポーネント列挙子の実装例に基づきます。
{
"components": [
{
"id": "hostfw",
"name": "hostfw",
"group": "firmware",
"manufacturer": "contoso",
"model": "virtual-firmware",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/hostfw",
"firmwareDataFile": "firmware.json",
"status": "ok",
"version" : "host-fw-1.0"
}
},
{
"id": "bootfs",
"name": "bootfs",
"group": "boot-image",
"manufacturer": "contoso",
"model": "virtual-disk",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/bootfs",
"firmwareDataFile": "diskimage.json",
"status": "ok",
"version" : "boot-fs-1.0"
}
},
{
"id": "rootfs",
"name": "rootfs",
"group": "os-image",
"manufacturer": "contoso",
"model": "virtual-os",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/rootfs",
"firmwareDataFile": "diskimage.json",
"status": "ok",
"version" : "root-fs-1.0"
}
},
{
"id": "contoso-motor-serial-00000",
"name": "left-motor",
"group": "motors",
"manufacturer": "contoso",
"model": "virtual-motor",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/0",
"firmwareDataFile": "firmware.json",
"status": "ok",
"version" : "motor-fw-1.0"
}
},
{
"id": "contoso-motor-serial-00001",
"name": "right-motor",
"group": "motors",
"manufacturer": "contoso",
"model": "virtual-motor",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/1",
"firmwareDataFile": "firmware.json",
"status": "ok",
"version" : "motor-fw-1.0"
}
},
{
"id": "contoso-motor-serial-00002",
"name": "vacuum-motor",
"group": "motors",
"manufacturer": "contoso",
"model": "virtual-motor",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/2",
"firmwareDataFile": "firmware.json",
"status": "ok",
"version" : "motor-fw-1.0"
}
},
{
"id": "contoso-camera-serial-00000",
"name": "front-camera",
"group": "cameras",
"manufacturer": "contoso",
"model": "virtual-camera",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/camera\/0",
"firmwareDataFile": "firmware.json",
"status": "ok",
"version" : "camera-fw-1.0"
}
},
{
"id": "contoso-camera-serial-00001",
"name": "rear-camera",
"group": "cameras",
"manufacturer": "contoso",
"model": "virtual-camera",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/camera\/1",
"firmwareDataFile": "firmware.json",
"status": "ok",
"version" : "camera-fw-1.0"
}
}
]
}
以下の JSON ドキュメントが SelectComponents
関数から返されます。 これは、Contoso コンポーネント列挙子の実装例に基づきます。
以下に、motors コンポーネント グループを選択するための入力パラメーターを示します。
{
"group" : "motors"
}
パラメーターの出力を以下に示します。 すべてのコンポーネントが motors グループに属します。
{
"components": [
{
"id": "contoso-motor-serial-00000",
"name": "left-motor",
"group": "motors",
"manufacturer": "contoso",
"model": "virtual-motor",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/0",
"firmwareDataFile": "firmware.json",
"status": "ok",
"version" : "motor-fw-1.0"
}
},
{
"id": "contoso-motor-serial-00001",
"name": "right-motor",
"group": "motors",
"manufacturer": "contoso",
"model": "virtual-motor",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/1",
"firmwareDataFile": "firmware.json",
"status": "ok",
"version" : "motor-fw-1.0"
}
},
{
"id": "contoso-motor-serial-00002",
"name": "vacuum-motor",
"group": "motors",
"manufacturer": "contoso",
"model": "virtual-motor",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/2",
"firmwareDataFile": "firmware.json",
"status": "ok",
"version" : "motor-fw-1.0"
}
}
]
}
以下に、hostfw という名前の単一のコンポーネントを選択するための入力パラメーターを示します。
{
"name" : "hostfw"
}
以下に、hostfw コンポーネントのパラメーターの出力を示します。
{
"components": [
{
"id": "hostfw",
"name": "hostfw",
"group": "firmware",
"manufacturer": "contoso",
"model": "virtual-firmware",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/hostfw",
"firmwareDataFile": "firmware.json",
"status": "ok",
"version" : "host-fw-1.0"
}
}
]
}
注意
上記の例では、必要に応じて、name
プロパティで選択されたコンポーネントの任意のインスタンスに新しい更新情報を送信できることを示しています。 たとえば、left-motor と right-motor で motor-fw-1.0
を引き続き使用しながら、vacuum-motor に motor-fw-2.0
更新をデプロイします。
インベントリ ファイル
上記の Contoso Virtual Vacuum コンポーネント列挙子の実装例では、デバイス固有のコンポーネントの情報が component-inventory.json ファイルから読み取られます。 この実装例は、デモンストレーションのみを目的としています。
運用環境のシナリオでは、一部のプロパティは、実際のコンポーネントから直接取得する必要があります。 これには、id
、manufacturer
、model
のようなプロパティがあります。
デバイス ビルダーは、name
と group
のプロパティを定義します。 これらの値は、定義した後に変更してはなりません。 name
プロパティは、デバイス内で一意である必要があります。
component-inventory.json file の例
注意
このファイルの内容は、GetAllComponents
関数から返された値とほぼ同じです。 しかし、このファイルの ComponentInfo
には version
と status
のプロパティが含まれていません。 コンポーネント列挙子は、実行時にこれらのプロパティに値を設定します。
たとえば、hostfw の場合、プロパティ properties.version
の値は、指定された (モック) firmwareDataFile
値 (/usr/local/contoso-devices/vacuum-1/hostfw/firmware.json) から設定されます。
{
"components": [
{
"id": "hostfw",
"name": "hostfw",
"group": "firmware",
"manufacturer": "contoso",
"model": "virtual-firmware",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/hostfw",
"firmwareDataFile": "firmware.json",
}
},
{
"id": "bootfs",
"name": "bootfs",
"group": "boot-image",
"manufacturer": "contoso",
"model": "virtual-disk",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/bootfs",
"firmwareDataFile": "diskimage.json",
}
},
{
"id": "rootfs",
"name": "rootfs",
"group": "os-image",
"manufacturer": "contoso",
"model": "virtual-os",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/rootfs",
"firmwareDataFile": "diskimage.json",
}
},
{
"id": "contoso-motor-serial-00000",
"name": "left-motor",
"group": "motors",
"manufacturer": "contoso",
"model": "virtual-motor",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/0",
"firmwareDataFile": "firmware.json",
}
},
{
"id": "contoso-motor-serial-00001",
"name": "right-motor",
"group": "motors",
"manufacturer": "contoso",
"model": "virtual-motor",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/1",
"firmwareDataFile": "firmware.json",
}
},
{
"id": "contoso-motor-serial-00002",
"name": "vacuum-motor",
"group": "motors",
"manufacturer": "contoso",
"model": "virtual-motor",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/2",
"firmwareDataFile": "firmware.json",
}
},
{
"id": "contoso-camera-serial-00000",
"name": "front-camera",
"group": "cameras",
"manufacturer": "contoso",
"model": "virtual-camera",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/camera\/0",
"firmwareDataFile": "firmware.json",
}
},
{
"id": "contoso-camera-serial-00001",
"name": "rear-camera",
"group": "cameras",
"manufacturer": "contoso",
"model": "virtual-camera",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/camera\/1",
"firmwareDataFile": "firmware.json",
}
}
]
}
次のステップ
この記事の例では C を使用しました。C++ のソース コード例については、以下を参照してください。
Contoso Virtual Vacuum デバイスに接続されているコンポーネントのさまざまなサンプル更新については、プロキシ更新のデモを参照してください。