AWS CLI で AWS IoT Sitewise の階層化されたアセットモデルを作成してみた
前回の記事で、AWS IoT SiteWise にてアセットモデルを階層化してセンサーデータを可視化しました。
その際、アセットモデルの作成は全てマネジメントコンソールで行いましたが、「定義の変換」や「メトリクス」 のプロパティで利用する計算式の入力方法が特殊だったかと思います。
そこで今回は、この計算式の設定を AWS CLI で行ってみます。また、階層をまたいだ計算式の設定方法も紹介したいと思います。
はじめに
本記事は下記のドキュメントを参考にしながら、実際の手順や気になった点を確認してみたものになります。
実際に試してみて初めて判明した内容も含んでいますので、ドキュメントと合わせてご覧いただけると幸いです。
課題
先程も書きましたが、アセットモデルを作成するとき一部のアセットプロパティ(メトリクスやデータ変換など)では計算式を設定することがあります。(例:華氏を摂氏に変換)
しかし、マネジメントコンソールで計算式を設定するときは、テキストのコピペで入力することができず、下記のような操作が必要になります。(以下は前回の記事からの引用です)
数式が単純だったり数が少なければコンソールからの入力でも問題ありませんが、モデルの階層をまたいでプロパティを参照するような複雑な計算式になるとうまく入力ができないことがあり、ちゃぶ台をひっくり返したくなります。
そこで、次の章より簡単なサンプルを交えつつ、AWS CLI による設定方法を見ていきたいと思います。
AWS CLI で単純なアセットモデルを作成する
手始めに簡単なアセットモデルを作成してみましょう。作成するモデルは次のようなアセットプロパティを持つものとします。
- Measurements(センサーデータ)
- 温度(プロパティ名:
temperature
)- データ型:
DOUBLE
- 単位:
℃
- データ型:
- 湿度(プロパティ名:
humidity
)- データ型:
DOUBLE
- 単位:
%
- データ型:
- 温度(プロパティ名:
- Metrics (温度の 5 分間の平均)
- プロパティ名:
avg_temperature
- プロパティ名:
上記の内容に沿った設定内容を Yaml もしくは JSON ファイルとして作成します。(今回は Yaml で作成)
--- assetModelName: Sample Asset Model assetModelProperties: # 温度 - name: temperature dataType: DOUBLE unit: '℃' type: measurement: {} # 湿度 - name: humidity dataType: DOUBLE unit: '%' type: measurement: {} # アセットプロパティのタイプ:Metrics(温度 の5分間の平均) - name: avg_temperature dataType: DOUBLE type: metric: expression: avg(my_var_temperature) variables: - name: my_var_temperature value: propertyId: temperature window: tumbling: interval: 5m
Yaml ファイルが作成できたら下記のコマンドでアセットモデルを作成します。
$ aws iotsitewise create-asset-model \ --cli-input-yaml file://sample-asset-model.yaml
コマンドと Yaml ファイルの詳細については下記を参照して下さい。
コマンドが実行できたら、コンソールで内容を確認してみましょう。
温度と湿度のプロパティが作成されていますね。
メトリクスも「温度の5分間の平均」として作成できていました。
設定内容のポイント
ここでポイントになるのは、温度の平均を定義しているプロパティの「20行目以降の箇所」です。(下記は該当箇所より抜粋)
ここでは数式を avg(my_var_temperature)
と定義しています。
metric: expression: avg(my_var_temperature) variables: - name: my_var_temperature value: propertyId: temperature
しかし、直感的に捉えると平均値の数式は avg(temperature)
となってほしいですし、実際にコンソールで確認すると下記のように表示されます。
ここで先程の Yaml ファイルを改めて確認すると「計算式で参照するアセットプロパティ(temperature
)を my_var_temperature
という変数に渡して計算式にセット」していることが分かります。
(下記は該当箇所を抜粋したもの)
metric: expression: avg(my_var_temperature) variables: - name: my_var_temperature value: propertyId: temperature
このように内部で変数化して計算式を組み立てているので、コンソール上でもテキストでコピペができないようになっているものと考えられます。
なお、この変数名はなんでもいいですが正規表現 ^[a-z][a-z0-9_]*$
にマッチしたものである必要があります。
コンソールで設定したアセットモデルの詳細
ここまでの内容で、アセットプロパティで計算式をセットする時に対象のプロパティを内部で変数化することが分かりました。では逆に、コンソールで設定した数式はどうなっているか見てみましょう。
先程 CLI で作成したモデル「Sample Asset Model」は削除して、改めて同じ内容のモデルをコンソール上で作成しておきます。
コンソール上でモデルが作成できたら、モデルの詳細を確認してみましょう。
モデルの詳細を参照するのは describe-asset-model
コマンドを使います。
$ aws iotsitewise describe-asset-model \ --asset-model-id [コンソールで作成したアセットモデルの ID ]
すると、下記のようなレスポンスを受け取ることができます。
{ "assetModelId": "91902cd8-bbca-4c22-a112-54d262e06ae3", "assetModelArn": "arn:aws:iotsitewise:ap-northeast-1:[AWS_ACCOUNT_ID]:asset-model/91902cd8-bbca-4c22-a112-54d262e06ae3", "assetModelName": "Sample Asset Model", "assetModelProperties": [ { "id": "9044fc52-6ff5-432d-be49-9e3b191ef1e0", "name": "temperature", "dataType": "DOUBLE", "unit": "℃", "type": { "measurement": {} } }, { "id": "61b7c464-b83e-4c16-b755-c43ad51f6443", "name": "humidity", "dataType": "DOUBLE", "unit": "%", "type": { "measurement": {} } }, { "id": "79f9393f-0396-4a99-9592-52618a693c7c", "name": "avg_temperature", "dataType": "DOUBLE", "type": { "metric": { "expression": "avg(var_temperature)", "variables": [ { "name": "var_temperature", "value": { "propertyId": "9044fc52-6ff5-432d-be49-9e3b191ef1e0" } } ], "window": { "tumbling": { "interval": "5m" } } } } } ], "assetModelHierarchies": [], "assetModelCompositeModels": [], "assetModelCreationDate": "2022-04-12T17:51:21+09:00", "assetModelLastUpdateDate": "2022-04-12T17:51:25+09:00", "assetModelStatus": { "state": "ACTIVE" } }
上記の通り、メトリクスの数式には var_temperature
という変数で温度のプロパティ ID (9044fc52-6ff5-432d-be49-9e3b191ef1e0
) がセットされていることが分かりました。
どうやら同じ階層内でプロパティを参照する場合は、var_[対象のプロパティ名]
という形で変数が作成されるようです。
なお、この propertyId
を設定する時は「プロパティ ID」もしくは「プロパティ名」が指定可能です。
AWS CLI で階層化したアセットモデルを作成する
以上で AWS CLI による基本的なモデルの作成方法が分かりました。
次は階層化したアセットモデルを作成して、さらに下位モデルのプロパティから統計値を計算するメトリクスを作成してみたいと思います。
具体的には前回の階層化されたアセットモデルを AWS CLI で作ってみます。
作成するモデルはそれぞれ次のようなアセットプロパティを持つものとします。
- 下位アセットモデル(モデル名:
Lower Test Model
)- Measurements(センサーデータ)
- クロック数(プロパティ名:
clock
)- データ型:DOUBLE
- 単位:
Hz
- 温度(プロパティ名:
temperature
)- データ型:DOUBLE
- 単位:
℃
- クロック数(プロパティ名:
- Transforms(クロック数
clock
の単位をMHz
に変換)- プロパティ名:
clock_MHz
- プロパティ名:
- Metrics(クロック数
clock_MHz
の平均)- プロパティ名:
avg_clock
- 平均値を取る間隔:1分間
- プロパティ名:
- Measurements(センサーデータ)
- 上位アセットモデル(モデル名:
Upper Test Model
)- Metrics(下位モデルのアセット全体のクロック数の平均)
- プロパティ名:
total_avg_clock
- 平均値を取る間隔:1分間
- プロパティ名:
- Metrics(下位モデルのアセット全体のクロック数の平均)
下位アセットモデルの作成
最初に下位モデルを作成します。(上位モデルから下位モデルを参照するので下位モデルから作成します)
先程と同じようにメトリクスの数式には my_var_clock_mhz
という変数に、同じモデル内の clock_MHz
プロパティを入れて計算式にセットしています。
--- assetModelName: Lower Test Model assetModelProperties: - name: clock dataType: DOUBLE unit: Hz type: measurement: {} - name: temperature dataType: DOUBLE unit: "℃" type: measurement: {} - name: clock_MHz dataType: DOUBLE unit: MHz type: transform: expression: var_clock/1000000 variables: - name: var_clock value: propertyId: clock - name: avg_clock dataType: DOUBLE type: metric: expression: avg(my_var_clock_mhz) variables: - name: my_var_clock_mhz value: propertyId: clock_MHz window: tumbling: interval: 1m
先程と同様に create-asset-model
コマンドでアセットモデルを作成します。
$ aws iotsitewise create-asset-model \ --cli-input-yaml file://create-asset-model-lower.yaml
上位アセットモデルの作成
次に下記の Yaml ファイルを作成して上位モデルを作成します。
--- assetModelName: Upper Test Model assetModelProperties: - name: total_avg_clock dataType: DOUBLE type: metric: expression: avg(my_lower_model_metrics) variables: - name: my_lower_model_metrics value: propertyId: [参照先の下位モデルのメトリクス(avg_clock)のプロパティ ID ] hierarchyId: device_hierarchy window: tumbling: interval: 1m assetModelHierarchies: - name: device_hierarchy childAssetModelId: [下位モデルのモデル ID]
ファイルができたら同じようにcreate-asset-model
コマンドでアセットモデルを作成します。
$ aws iotsitewise create-asset-model \ --cli-input-yaml file://create-asset-model-upper.yaml
コンソールで確認すると「コンソール上で設定した場合」と同じようにメトリクスが定義されていました。
メトリクスで参照されている階層(device_hierarchy
)も定義できていることが分かります。
設定内容のポイント
ポイントは 11〜 13 行目の内容です。 (下記は該当箇所の抜粋)
metric: expression: avg(my_lower_model_metrics) variables: - name: my_lower_model_metrics value: propertyId: [参照先の下位モデルのメトリクス(avg_clock)のプロパティ ID ] hierarchyId: device_hierarchy
先程の「下位モデル」や冒頭の「単純なアセットモデル」の Yaml ファイルでは、計算式に設定するプロパティを propertyId
の指定だけで行っていました。
今回は階層をまたいだ下位モデルのプロパティを参照するため、対象の「階層ID(hierarchyId
)」と「その階層にある対象のプロパティ(propertyId
)」の両方を指定しています。これにより参照すべきプロパティを特定することができるようになります。
階層をまたがない場合なら同じ階層のプロパティを参照することになるので、propertyId
には「プロパティ名」を指定できますが、階層をまたぐ場合は ID そのものを指定する必要があります。
一方で hierarchyId
は「階層ID」もしくは「階層名」をセットすることができます。
なお、propertyId
と childAssetModelId
の値については、事前に作成した下位モデルの内容から取得してセットする必要があります。(下記は該当箇所より抜粋)
metric: expression: avg(my_lower_model_metrics) variables: - name: my_lower_model_metrics value: propertyId: [参照先の下位モデルのメトリクス(avg_clock)のプロパティ ID ] hierarchyId: device_hierarchy window: tumbling: interval: 1m assetModelHierarchies: - name: device_hierarchy childAssetModelId: [下位モデルのモデル ID]
ぞれぞれの意味は下記のとおりです。
propertyId
: 参照している下位モデルのメトリクス(avg_clock
)のプロパティIDchildAssetModelId
: 参照している下位モデル(Lower Test Model
)のモデルID
各 ID は次のコマンドで取得可能です。(マネジメントコンソール上からも確認できます)
- 下位モデルのモデル ID
$ aws iotsitewise list-asset-models \ --query "assetModelSummaries[?name=='Lower Test Model'].id"
- 参照先の下位モデルのメトリクス(
avg_clock
)のプロパティID
$ aws iotsitewise describe-asset-model \ --asset-model-id [上記コマンドで取得したモデル ID] \ --query "assetModelProperties[?name=='avg_clock'].id"
コンソールで設定したアセットモデルの詳細
先程と同じように、CLI ではなくコンソール上で設定した場合の設定内容も見てみましょう。今回は「階層をまたいで設定した上位モデルのメトリクスの計算式」を見てみます。
先程 CLI で作成した上位モデル (Upper Test Model
)を削除して、コンソール上で同じ設定内容で作成し直します。
以下のように計算式の見た目は変わっていません。(作り直したのでプロパティ ID は変わっています)
次に describe-asset-model
コマンドで作成したモデルの詳細を見てみましょう。
aws iotsitewise describe-asset-model \ --asset-model-id [コンソールで作成したアセットモデルの ID ]
次のようなレスポンスが得られました。
{ "assetModelId": "3e527ae5-3820-4019-a18d-6f011baf6ef8", "assetModelArn": "arn:aws:iotsitewise:ap-northeast-1:[AWS_ACCOUNT_ID]:asset-model/3e527ae5-3820-4019-a18d-6f011baf6ef8", "assetModelName": "Upper Test Model", "assetModelProperties": [ { "id": "d5f26461-701e-41e6-aca9-bbf15742eb3c", "name": "total_avg_clock", "dataType": "DOUBLE", "type": { "metric": { "expression": "avg(v_lowertestmode_device_hierarchy_avg_clock)", "variables": [ { "name": "v_lowertestmode_device_hierarchy_avg_clock", "value": { "propertyId": "cbf2bbe3-34ee-4e56-bf55-8956a67ca696", "hierarchyId": "a3179b56-17df-460b-a84f-2fa27215c987" } } ], "window": { "tumbling": { "interval": "1m" } } } } } ], "assetModelHierarchies": [ { "id": "a3179b56-17df-460b-a84f-2fa27215c987", "name": "device_hierarchy", "childAssetModelId": "823c183c-ea4d-492a-8878-8fb32190f1d3" } ], "assetModelCompositeModels": [], "assetModelCreationDate": "2022-04-12T19:49:53+09:00", "assetModelLastUpdateDate": "2022-04-12T19:49:59+09:00", "assetModelStatus": { "state": "ACTIVE" } }
注目ポイントは 12 行目(と 15 行目)です。
これまでに何度も説明していますが、アセットプロパティで計算式をセットする際は対象のプロパティを変数化して計算式に渡します。
今回は v_lowertestmode_device_hierarchy_avg_clock
という変数になっていることが上記の 12 行目から分かります。そして、この変数名の構成を少し分解してみると次のような3つのブロックから成る書式である事が分かります。
v_[ブロックA]_[ブロックB]_[ブロックC]
- ブロックA
- 階層定義で参照している下位のモデル名(
Lower Test Model
)lowertestmode
の部分
- 階層定義で参照している下位のモデル名(
- ブロックB
- 階層名
device_hierarchy
の部分
- 階層名
- ブロックC
- 参照したい下位アセットのメトリクス名
avg_clock
の部分
- 参照したい下位アセットのメトリクス名
網羅的に確認したわけではありませんが、モデル名や階層名を色々変えて検証してみた所、各ブロックで下記のような変換が行われた変数がセットされているようでした。
- 英大文字の削除 or 小文字に変換
- スペースの削除
- ハイフン(
-
)の削除
これは、内部で変数として利用できる文字として、正規表現 ^[a-z][a-z0-9_]*$
にマッチしたものに限る制約に則った変換が実行されていると考えられます。
ちなみに CLI で作成した場合は、設定ファイル(JSON, YAML)で指定した変数がそのままセットされます。
「内部で使われている変数」を把握しておくといいケース
あまりケースとしては多くないかもしれませんが、初めにコンソールで設定したアセットモデルを後から AWS CLI などで更新する際は「内部で使われている変数」を事前に確認しておく必要があります。
アセットモデルのコンソール画面では「内部で使われている変数」は確認できないので describe-asset-model
コマンド等を使って事前に確認しておきましょう。
なお、後でアセットモデルを更新する場合は、update-asset-model
コマンドを使いますが、設定ファイルの記述方法や注意すべきポイントは create-asset-model
コマンドと同様です。
最後に
AWS CLI でアセットモデルを作成してみたことで、マネジメントコンソールだとメトリクスなどの計算式がコピペで設定できない理由の一端を垣間見ることができました。
非常に細かい点を交えた内容になりましたが、どなたかのお役に立てれば幸いです。
以上です。