この記事ではAWS IoT、AWS IoT Device Shadowについて解説します。AWS IoT、AWS IoT Device Shadowを使用することで、簡単にJetson Nanoなどのエッジデバイスをクラウドと連携させることが可能となります。エッジデバイスとクラウドを連携させることで、例えば動的にYOLOv5のモデルをクラウドからエッジデバイスに更新することが可能になります。
以下の操作はAWSアカウントが必要です。
AWS CLIのインストールとセットアップも必要です。
AWS IoT
AWS IoTを使用することで、MQTTという通信プロトコルを使用し、エッジデバイスとクラウドを簡単に接続することが可能となります。
AWS IoTの準備として・モノ
、・証明書
、・ポリシー
を作成し、・モノ
に証明書
をアタッチし・証明書
にポリシー
をアタッチします。
モノを作成
以下でモノ
を作成します。以下ではtest-thing
という名前のモノ
を作成します。
aws iot create-thing --thing-name test-thing
Code language: Bash (bash)
証明書を作成し、モノにアタッチ
以下で証明書を作成し、上で作成したモノ
、test-thing
にアタッチします。
$ aws iot create-keys-and-certificate --set-as-active --certificate-pem-outfile certificate.pem --public-key-outfile public.key --private-key-outfile private.key
{
"certificateArn": "arn:aws:iot:us-east-1:xxxxxxxxxxxx:cert/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
...
$ aws iot attach-thing-principal --principal arn:aws:iot:us-east-1:xxxxxxxxxxxx:cert/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --thing-name test-thing
Code language: Bash (bash)
aws iot attach-thing-principal--principal
で指定するARN(Amazon Resource Name)は、aws iot create-keys-and-certificate
で返されたcertificateArn
を指定します。
証明書は--certificate-pem-outfile
で指定したcertificate.pem
、秘密鍵は--private-key-outfile
で指定したprivate.key
に作成されます。
ポリシーを作成し、証明書にアタッチ
ポリシーはモノ(正確にはモノにアタッチされた証明書)の通信を制限するための機構で、具体的にはMQTTを使用してデータをパブリッシュ・サブスクライブする際の通信を制限することができます。
cat << EOS > thing-policy.json
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "iot:Connect",
"Resource": "arn:aws:iot:us-east-1:xxxxxxxxxxxx:client/\${iot:Connection.Thing.ThingName}"
},
{
"Effect": "Allow",
"Action": "iot:Publish",
"Resource": [
"arn:aws:iot:us-east-1:xxxxxxxxxxxx:topic/\$aws/things/\${iot:Connection.Thing.ThingName}/shadow/update",
"arn:aws:iot:us-east-1:xxxxxxxxxxxx:topic/\$aws/things/\${iot:Connection.Thing.ThingName}/shadow/delete",
"arn:aws:iot:us-east-1:xxxxxxxxxxxx:topic/\$aws/things/\${iot:Connection.Thing.ThingName}/shadow/get"
]
},
{
"Effect": "Allow",
"Action": "iot:Receive",
"Resource": [
"arn:aws:iot:us-east-1:xxxxxxxxxxxx:topic/\$aws/things/\${iot:Connection.Thing.ThingName}/shadow/get/*",
"arn:aws:iot:us-east-1:xxxxxxxxxxxx:topic/\$aws/things/\${iot:Connection.Thing.ThingName}/shadow/update/*",
"arn:aws:iot:us-east-1:xxxxxxxxxxxx:topic/\$aws/things/\${iot:Connection.Thing.ThingName}/shadow/delete/*"
]
},
{
"Effect": "Allow",
"Action": "iot:Subscribe",
"Resource": [
"arn:aws:iot:us-east-1:xxxxxxxxxxxx:topicfilter/\$aws/things/\${iot:Connection.Thing.ThingName}/shadow/get/*",
"arn:aws:iot:us-east-1:xxxxxxxxxxxx:topicfilter/\$aws/things/\${iot:Connection.Thing.ThingName}/shadow/update/*",
"arn:aws:iot:us-east-1:xxxxxxxxxxxx:topicfilter/\$aws/things/\${iot:Connection.Thing.ThingName}/shadow/delete/*"
]
},
{
"Effect": "Allow",
"Action": [
"iot:GetThingShadow",
"iot:UpdateThingShadow",
"iot:DeleteThingShadow"
],
"Resource": "arn:aws:iot:us-east-1:xxxxxxxxxxxx:thing/\${iot:Connection.Thing.ThingName}"
}
]
}
EOS
aws iot create-policy --policy-name thing-policy --policy-document file://thing-policy.json
aws iot attach-policy --policy-name thing-policy --target arn:aws:iot:us-east-1:xxxxxxxxxxxx:cert/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Code language: Bash (bash)
${iot:Connection.Thing.ThingName}
はポリシー変数です。このポリシー変数を使用するとモノ
の名前として評価されます。
arn:aws:iot:us-east-1:xxxxxxxxxxxx
の部分は自身のアカウントIDに置き換えて下さい。アカウントIDは以下で取得可能です。
aws sts get-caller-identity|jq -r .Account
Code language: Bash (bash)
またaws iot attach-policy --policy-name thing-policy --target
で指定する、arn:aws:iot:us-east-1:xxxxxxx...
はaws iot attach-thing-principal--principal
で使用したcertificateArn
を指定します。
注意点として以下のようなポリシーを使用してしまうと、このポリシーがアタッチされたモノ
はすべてのリソース(MQTTトピック)に対してパブリッシュ・サブスクライブすることが可能になります。これは別のモノ
へトピックをパブリッシュ(送信)することや、別のモノ
へのトピックをサブスクライブ(受信)することが可能になりますので一般的には危険で設定してはいけません。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iot:Publish",
"iot:Subscribe",
"iot:Receive"
],
"Resource": ["*"],
},
]
}
Code language: JSON / JSON with Comments (json)
AWS IoT Device Shadow
AWS IoT Device SDK v2 for Pythonを使用してAWS IoT Device Shadowの動作を確認します。
$ python3 -m pip install awsiotsdk
$ git clone https://github.com/aws/aws-iot-device-sdk-python-v2.git
$ curl -o AmazonRootCA1.pem https://www.amazontrust.com/repository/AmazonRootCA1.pem
Code language: Bash (bash)
aws-iot-device-sdk-python-v2/samples/shadow.py
を実行します。aws-iot-device-sdk-python-v2/samples/shadow.py
で指定するendpoint
はaws iot describe-endpoint --endpoint-type iot:Data-ATS
により取得します。
$ aws iot describe-endpoint --endpoint-type iot:Data-ATS
{
"endpointAddress": "xxxxxxxxxxxxxx-ats.iot.us-east-1.amazonaws.com"
}
$ python3 aws-iot-device-sdk-python-v2/samples/shadow.py --endpoint xxxxxxxxxxxxxx-ats.iot.us-east-1.amazonaws.com --key private.key --cert certificate.pem --client_id test-thing --ca_file AmazonRootCA1.pem --thing_name test-thing
Connecting to xxxxxxxxxxxxxx-ats.iot.us-east-1.amazonaws.com with client ID 'test-thing-jetson'...
Connected!
Subscribing to Update responses...
Subscribing to Get responses...
Subscribing to Delta events...
Requesting current shadow state...
Launching thread to read user input...
Thing has no shadow document. Creating with defaults...
Changed local shadow value to 'off'.
Updating reported shadow value to 'off'...
Update request published.
Finished updating reported shadow value to 'off'.
Enter desired value:
Code language: Bash (bash)
shadow.py
は以下のような機能を実現するためのサンプルです。
- 操作端末(ウェブアプリやスマートフォンアプリなど)で照明の色の変更を指示
- 変更の指示を受けた照明デバイスは、指定された色に従って照明の色を変更

shadow.py
で使用されるAWS IoT Device Shadowはクラウドとエッジデバイスで共有される以下のJSON形式のデータを持ちます。
{
"state": {
"desired": {
"color": "red",
},
"reported": {
"color": "blue"
},
"delta": {
"color": "red",
}
},
"version": 1,
"timestamp": 1669898853
}
Code language: JSON / JSON with Comments (json)
サンプルshadow.py
を実際の製品として実装する際、照明の色の更新は以下の流れで行われます。
- 操作端末は
state.desired
に更新したい照明の色を設定する
- 照明デバイスは
state.desired
とstate.reported
の差分を受信しstate.desired
に書かれた値に照明の色を変更し- サンプルに照明の色を変更するコードはありません
state.reported
に変更した照明の色を報告する
IoT Device Shadowで重要なポイントは以下の通りです。
- 操作端末側は
state.desired
のみ変更します。 - 照明デバイスは
state.reported
のみ変更します。 state.desired
とstate.reported
に差分が発生した場合、state.delta
に差分情報が自動的に作成されます。- 差分情報をサブスクライブしている場合は、サブスクライブ設定時に指定したコールバック関数が呼び出されます。
version
は古いリクエストを捨てるために使用します。もしstate.desired
の更新が複数回実施され、state.delta
をサブスクライブするコールバックが複数回呼び出された場合、state.desired
の更新の順番にstate.delta
のコールバックが呼び出されるとは限らないため、サブスクライブしたversion
より古いversion
が届いた場合は破棄します。
下記の図で照明デバイスは最新のversion
を保存しておき、最新のversion
より値の低い、後から届いた"version": 1
のメッセージを単に破棄します。
エッジデバイスとクラウドとの接続は別の記事で解説します。
以上です。
参照
