この記事では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-thingCode 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-thingCode 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/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxCode language: Bash (bash)
${iot:Connection.Thing.ThingName}はポリシー変数です。このポリシー変数を使用するとモノの名前として評価されます。
arn:aws:iot:us-east-1:xxxxxxxxxxxxの部分は自身のアカウントIDに置き換えて下さい。アカウントIDは以下で取得可能です。
aws sts get-caller-identity|jq -r .AccountCode 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.pemCode 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のメッセージを単に破棄します。
エッジデバイスとクラウドとの接続は別の記事で解説します。
以上です。
参照



