前回 Greengrass Core を単体で Raspberry Pi で動かすチュートリアルを試しましたが、やはり複数デバイスを連携させてこそ Greengrass のメリットは大きいと思いますので、公式ドキュメントで公開されているロボットアームのシナリオの例を試してみたいと思います。
Thing の準備
このシナリオでは AWS IoT の Thing を3つ使いますので、AWS IoT の管理コンソールから下記の名前で Thing を用意しておきます。(Thingの作成方法はここでは割愛させていただきます)
- GGC_Thing:Greengrass Core 用
- RobotArm_Thing:RobotArm 用
- Switch_Thing:RobotArm のスイッチ用
AWS Greengrass Group の作成
前回のチュートリアルの例ではWebのコンソールから各コンポーネントを作成しましたが、今回のシナリオでは AWS CLI から操作していきます。まずは Greengrass Group の作成です。 aws greengrass create-group
コマンドで作成できます。
$ aws greengrass create-group --name "RobotArm_Group" { "Name": "RobotArm_Group", "LastUpdatedTimestamp": "2017-12-29T10:57:26.251Z", "CreationTimestamp": "2017-12-29T10:57:26.251Z", "Id": "c4768328-4dce-4e41-9fd2-3ce8e943072e", "Arn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/groups/c4768328-4dce-4e41-9fd2-3ce8e943072e" }
作成された Greengrass Group の情報は aws greengrass get-group
コマンドで参照できます。
$ aws greengrass get-group --group-id c4768328-4dce-4e41-9fd2-3ce8e943072e { "Name": "RobotArm_Group", "LastUpdatedTimestamp": "2017-12-29T10:57:26.251Z", "CreationTimestamp": "2017-12-29T10:57:26.251Z", "Id": "c4768328-4dce-4e41-9fd2-3ce8e943072e", "Arn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/groups/c4768328-4dce-4e41-9fd2-3ce8e943072e" }
Greengrass Core 定義の作成
Greengrass Core とその設定情報のリストである Greengrass Core 定義を作成します。 Greengrass のコンポーネントの多くは、まず 定義
を作成して、実際の Thing の情報などを含む バージョン
を作成するという流れのようなので、まずは定義自体を作成します。
$ aws greengrass create-core-definition --name "RobotArm_CoreDefinition" { "Name": "RobotArm_CoreDefinition", "LastUpdatedTimestamp": "2017-12-29T11:03:41.101Z", "CreationTimestamp": "2017-12-29T11:03:41.101Z", "Id": "5272397b-ec69-4259-bb5c-6043daade271", "Arn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/cores/5272397b-ec69-4259-bb5c-6043daade271" }
作成した Greengrass Core 定義は下記のように参照できます。
$ aws greengrass get-core-definition --core-definition-id 5272397b-ec69-4259-bb5c-6043daade271 { "Name": "RobotArm_CoreDefinition", "LastUpdatedTimestamp": "2017-12-29T11:03:41.101Z", "CreationTimestamp": "2017-12-29T11:03:41.101Z", "Id": "5272397b-ec69-4259-bb5c-6043daade271", "Arn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/cores/5272397b-ec69-4259-bb5c-6043daade271" }
続いて Greengrass Core 定義のバージョンを作成します。 --core-definition-id
には先ほど作成した Greengrass Core 定義の ID を指定します。また、 --cores
には Greengrass Core の Thing の情報を指定します。 json でリストを指定できるようになっていますが、現状では一つの Greengrass Core 定義に指定できる
Core デバイスは一つです。 CertificateArn
は Thing の証明書の arn を、 ThingArn
には Thing の arn を指定します。また、 Id
は任意の内容を指定できるようなので、ここでは 1 を設定しておきます。 SyncShadow
は Thing の Shadow を同期するかどうかの設定で、 true を指定しておきます。
$ aws greengrass create-core-definition-version --core-definition-id "5272397b-ec69-4259-bb5c-6043daade271" --cores '[{ "CertificateArn": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:cert/bdd9d49f5218a3c647f40f63a944887b12c0c46503904338fb4bbbd6f3e19d4d", "Id": "1", "SyncShadow": true, "ThingArn": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:thing/GGC_Thing" }]' { "Arn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/cores/5272397b-ec69-4259-bb5c-6043daade271/versions/c72d9131-69ab-4be5-9123-2ee9709d193b", "Version": "c72d9131-69ab-4be5-9123-2ee9709d193b", "CreationTimestamp": "2017-12-29T11:09:08.632Z", "Id": "5272397b-ec69-4259-bb5c-6043daade271" }
作成された Greengrass Core 定義のバージョン情報は下記のように参照できます。
$ aws greengrass get-core-definition-version --core-definition-id 5272397b-ec69-4259-bb5c-6043daade271 --core-definition-version-id c72d9131-69ab-4be5-9123-2ee9709d193b { "Definition": { "Cores": [ { "CertificateArn": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:cert/bdd9d49f5218a3c647f40f63a944887b12c0c46503904338fb4bbbd6f3e19d4d", "ThingArn": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:thing/GGC_Thing", "SyncShadow": true, "Id": "1" } ] }, "Version": "c72d9131-69ab-4be5-9123-2ee9709d193b", "CreationTimestamp": "2017-12-29T11:09:08.632Z", "Id": "5272397b-ec69-4259-bb5c-6043daade271", "Arn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/cores/5272397b-ec69-4259-bb5c-6043daade271/versions/c72d9131-69ab-4be5-9123-2ee9709d193b" }
デバイス定義の作成
Greengrass Core と連携させるデバイスの Thing と設定データのリストであるデバイス定義を作成します。デバイス定義も Greengrass Core 定義と同じように、定義自体を作成した上でバージョンを作成します。まずは定義の作成です。
$ aws greengrass create-device-definition --name "RobotArm_DeviceDefinition" { "Name": "RobotArm_DeviceDefinition", "LastUpdatedTimestamp": "2017-12-29T11:22:45.786Z", "CreationTimestamp": "2017-12-29T11:22:45.786Z", "Id": "081b65a9-e057-4395-80f0-d455f224eb23", "Arn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/devices/081b65a9-e057-4395-80f0-d455f224eb23" }
作成されたデバイス定義は下記のように参照できます。
$ aws greengrass get-device-definition --device-definition-id 081b65a9-e057-4395-80f0-d455f224eb23 { "Name": "RobotArm_DeviceDefinition", "LastUpdatedTimestamp": "2017-12-29T11:22:45.786Z", "CreationTimestamp": "2017-12-29T11:22:45.786Z", "Id": "081b65a9-e057-4395-80f0-d455f224eb23", "Arn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/devices/081b65a9-e057-4395-80f0-d455f224eb23" }
続いてデバイス定義のバージョンを作成します。 --device-definition-id
には先ほど作成したデバイス定義の ID を指定します。 --devices
でデバイスの Thing のリストを指定します。このシナリオでは前述のように RobotArm_Thing と Switch_Thing を使用します。 CertificateArn
と ThingArn
はそれぞれのデバイスの証明書の arn とデバイスの arn を指定します。 Id
は任意なので連番で振っておきます。 SyncShadow
は Thing の Shadow を同期するかの設定で、 Switch の方では必要ないので false にしておきます。
$ aws greengrass create-device-definition-version --device-definition-id "081b65a9-e057-4395-80f0-d455f224eb23" --devices '[ { "Id": "1", "CertificateArn": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:cert/c5e6d39f7bd79018296f63900f9f36e13d05649ead14d20d7f5ab4de3a812175", "SyncShadow": true, "ThingArn": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:thing/RobotArm_Thing" }, { "Id": "2", "CertificateArn": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:cert/a20b621e056d59f071cd3eb907d574a90b2dd88c03098caa36b8ea120cbfcb33", "SyncShadow": false, "ThingArn": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:thing/Switch_Thing" } ]' { "Arn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/devices/081b65a9-e057-4395-80f0-d455f224eb23/versions/4a19989a-7fa7-4322-8425-f8570f625758", "Version": "4a19989a-7fa7-4322-8425-f8570f625758", "CreationTimestamp": "2017-12-29T11:26:30.554Z", "Id": "081b65a9-e057-4395-80f0-d455f224eb23" }
作成されたデバイス定義のバージョン情報は下記のように参照できます。
$ aws greengrass get-device-definition-version --device-definition-id 081b65a9-e057-4395-80f0-d455f224eb23 --device-definition-version-id 4a19989a-7fa7-4322-8425-f8570f625758 { "Definition": { "Devices": [ { "CertificateArn": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:cert/c5e6d39f7bd79018296f63900f9f36e13d05649ead14d20d7f5ab4de3a812175", "ThingArn": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:thing/RobotArm_Thing", "SyncShadow": true, "Id": "1" }, { "CertificateArn": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:cert/a20b621e056d59f071cd3eb907d574a90b2dd88c03098caa36b8ea120cbfcb33", "ThingArn": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:thing/Switch_Thing", "SyncShadow": false, "Id": "2" } ] }, "Version": "4a19989a-7fa7-4322-8425-f8570f625758", "CreationTimestamp": "2017-12-29T11:26:30.554Z", "Id": "081b65a9-e057-4395-80f0-d455f224eb23", "Arn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/devices/081b65a9-e057-4395-80f0-d455f224eb23/versions/4a19989a-7fa7-4322-8425-f8570f625758" }
Thing のポリシー変更
Thing 作成時には証明書を作成してポリシーをアタッチしますが、各デバイスがどこまでの操作をできるかというのはそのポリシーの内容によって決まります。今回はひとまず AWS IoT や Greengrass の全ての操作が行えるように、 AWS IoT の管理コンソールから、 GGC_Thing、 RobotArm_Thing、 Switch_Thing にアタッチされているポリシーを下記のように変更しておきます。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iot:*", "greengrass:*" ], "Resource": [ "*" ] } ] }
Lambda Function の用意
デバイスで動作させる Lambda Function を用意します。このシナリオでは AWS Greengrass Core SDK の一部として提供されている2つの Lambda Function を使用します。 SDK は AWS IoT コンソールからダウンロードできます。コンソールの左メニューの ソフトウェア
メニューを選択し、 AWS Greengrass Core SDK の ダウンロードの設定
をクリックします。
Python 以外に Node.js や Java の SDK も取得できますが、今回は Python 版を選択して、 Greengrass Core SDK のダウンロード
をクリックします。
ダウンロードした圧縮ファイルを解凍し、 examples/Storyline というディレクトリの中にある2つの zip ファイルを使用します。 AWS Lambda コンソールから関数を作成します。詳細は割愛しますが、 uptimeLambda という関数名で storyline_uptimeLambda.zip を登録し、 Handler には uptimeLambda.uptime_handler を指定します。登録できたら Actions
メニューの 新しいバージョンを発行
をクリックしてバージョンを発行しておきます。そしてあとで次のバージョンを発行した時に Greengrass 側での参照先を変更しなくても良いように、エイリアスを作成しておきます。 Actions
メニューの エイリアスの作成
をクリックします。
エイリアス名に storyLineUptime と入力し、バージョンには先ほど発行したバージョンを選択して 作成
をクリックします。
これでひとまず uptimeLambda 関数は登録できたので、次に messageLambda という関数名で storyline_messageLambda.zip を登録し、 Handler には messageLambda.message_handler を指定します。バージョンの発行も同様に行い、エイリアスも storyLineMessage という名前で作成しておきます。
Lambda Function 定義の作成
次にデバイス上で動作させる Lambda Function の定義を作成します。こちらも定義自体を作成した後にバージョンを作成します。まずは定義自体の作成です。
$ aws greengrass create-function-definition --name "RobotArm_FunctionDefinition" { "Name": "RobotArm_FunctionDefinition", "LastUpdatedTimestamp": "2017-12-29T11:48:57.249Z", "CreationTimestamp": "2017-12-29T11:48:57.249Z", "Id": "1ed0c6f7-c34e-4ed1-a8d4-740f99d62778", "Arn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/functions/1ed0c6f7-c34e-4ed1-a8d4-740f99d62778" }
作成された定義情報は下記のように参照できます。
$ aws greengrass get-function-definition --function-definition-id 1ed0c6f7-c34e-4ed1-a8d4-740f99d62778 { "Name": "RobotArm_FunctionDefinition", "LastUpdatedTimestamp": "2017-12-29T11:48:57.249Z", "CreationTimestamp": "2017-12-29T11:48:57.249Z", "Id": "1ed0c6f7-c34e-4ed1-a8d4-740f99d62778", "Arn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/functions/1ed0c6f7-c34e-4ed1-a8d4-740f99d62778" }
続いて Lambda Function 定義のバージョンを作成します。 --function-definition-id
には先ほど作成した Lambda Function 定義の ID を指定します。 --functions
で使用する Lambda Function のリストを指定します。 FunctionArn
には先ほど登録した Lambda Function のエイリアスの arn を指定します。AWS Lambda のコンソールでエイリアスの arn を確認するには、 限定条件
メニューから該当のエイリアスを選択します。
該当のエイリアスの情報が表示されますので、右上にある ARN がエイリアスの ARN になります。
Executable
には Lambda Function のハンドラを指定し、 MemorySize
と Timeout
はここではそれぞれ 128000 と 3 にしておきます。 Id
には任意の値を指定できるので、ここではそれぞれ uptime-lambda と message-lambda としておきます。
$ aws greengrass create-function-definition-version --function-definition-id "1ed0c6f7-c34e-4ed1-a8d4-740f99d62778" --functions '[ { "Id": "uptime-lambda", "FunctionArn": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:uptimeLambda:storyLineUptime", "FunctionConfiguration": { "Executable": "uptimeLambda.uptime_handler", "MemorySize": 128000, "Timeout": 3 } }, { "Id": "message-lambda", "FunctionArn": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:messageLambda:storyLineMessage", "FunctionConfiguration": { "Executable": "messageLambda.message_handler", "MemorySize": 128000, "Timeout": 3 } }]' { "Arn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/functions/1ed0c6f7-c34e-4ed1-a8d4-740f99d62778/versions/a203e6af-74b8-4a52-baf4-10c648e0f3fb", "Version": "a203e6af-74b8-4a52-baf4-10c648e0f3fb", "CreationTimestamp": "2017-12-29T12:57:05.869Z", "Id": "1ed0c6f7-c34e-4ed1-a8d4-740f99d62778" }
作成されたバージョン情報は下記のように確認できます。
$ aws greengrass get-function-definition-version --function-definition-id 1ed0c6f7-c34e-4ed1-a8d4-740f99d62778 --function-definition-version-id a203e6af-74b8-4a52-baf4-10c648e0f3fb { "Definition": { "Functions": [ { "FunctionConfiguration": { "Executable": "messageLambda.message_handler", "MemorySize": 128000, "Timeout": 3 }, "Id": "message-lambda", "FunctionArn": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:messageLambda:storyLineMessage" }, { "FunctionConfiguration": { "Executable": "uptimeLambda.uptime_handler", "MemorySize": 128000, "Timeout": 3 }, "Id": "uptime-lambda", "FunctionArn": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:uptimeLambda:storyLineUptime" } ] }, "Version": "a203e6af-74b8-4a52-baf4-10c648e0f3fb", "CreationTimestamp": "2017-12-29T12:57:05.869Z", "Id": "1ed0c6f7-c34e-4ed1-a8d4-740f99d62778", "Arn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/functions/1ed0c6f7-c34e-4ed1-a8d4-740f99d62778/versions/a203e6af-74b8-4a52-baf4-10c648e0f3fb" }
サブスクリプション定義の作成
AWS Greengrass Group 内でのメッセージの送受信方法を指定するためのサブスクリプションの定義を作成します。まずは定義自体の作成です。
$ aws greengrass create-subscription-definition --name "RobotArm_SubscriptionDefinition" { "Name": "RobotArm_SubscriptionDefinition", "LastUpdatedTimestamp": "2017-12-29T13:07:19.866Z", "CreationTimestamp": "2017-12-29T13:07:19.866Z", "Id": "2eb1f6e4-a960-4796-8e0d-e67adbdeabd7", "Arn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/subscriptions/2eb1f6e4-a960-4796-8e0d-e67adbdeabd7" }
作成された定義情報は下記のように参照可能です。
$ aws greengrass get-subscription-definition --subscription-definition-id 2eb1f6e4-a960-4796-8e0d-e67adbdeabd7 { "Name": "RobotArm_SubscriptionDefinition", "LastUpdatedTimestamp": "2017-12-29T13:07:19.866Z", "CreationTimestamp": "2017-12-29T13:07:19.866Z", "Id": "2eb1f6e4-a960-4796-8e0d-e67adbdeabd7", "Arn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/subscriptions/2eb1f6e4-a960-4796-8e0d-e67adbdeabd7" }
続けてサブスクリプション定義のバージョンを作成します。 --subscription-definition-id
には先ほど作成したサブスクリプション定義の ID を指定します。 --subscriptions
にはサブスクリプションの内容を json で指定します。 Id
は任意の内容を指定できるのでここでは連番を振っておきます。 Source
にはメッセージの送信元、 Target
にはメッセージの受取先、 Subject
にはメッセージをフィルタするために対象の MQTT トピックを指定しておきます。 Shadow のアップデートや Lambda Function の実行など、使用する全てのパターンについて指定が必要なので長くなりますが、下記のようにコマンドを実行します。
$ aws greengrass create-subscription-definition-version --subscription-definition-id "2eb1f6e4-a960-4796-8e0d-e67adbdeabd7" --subscriptions '[ { "Id": "1", "Source": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:thing/Switch_Thing", "Subject": "$aws/things/RobotArm_Thing/shadow/update", "Target": "GGShadowService" }, { "Id": "2", "Source": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:thing/RobotArm_Thing", "Subject": "/topic/state", "Target": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:uptimeLambda:storyLineUptime" }, { "Id": "3", "Source": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:thing/RobotArm_Thing", "Subject": "$aws/things/RobotArm_Thing/shadow/update", "Target": "GGShadowService" }, { "Id": "4", "Source": "GGShadowService", "Subject": "$aws/things/RobotArm_Thing/shadow/update/delta", "Target": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:thing/RobotArm_Thing" }, { "Id": "5", "Source": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:uptimeLambda:storyLineUptime", "Subject": "/topic/metering", "Target": "cloud" }, { "Id": "6", "Source": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:messageLambda:storyLineMessage", "Subject": "$aws/things/RobotArm_Thing/shadow/update", "Target": "GGShadowService" }, { "Id": "7", "Source": "cloud", "Subject": "/topic/update", "Target": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:messageLambda:storyLineMessage" }, { "Id": "8", "Source": "GGShadowService", "Subject": "$aws/things/RobotArm_Thing/shadow/update/accepted", "Target": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:thing/Switch_Thing" }, { "Id":"9", "Source":"GGShadowService", "Subject":"$aws/things/RobotArm_Thing/shadow/update/rejected", "Target": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:thing/Switch_Thing" }, { "Id":"10", "Source":"GGShadowService", "Subject": "$aws/things/RobotArm_Thing/shadow/update/accepted", "Target": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:thing/RobotArm_Thing" }, { "Id":"11", "Source":"GGShadowService", "Subject": "$aws/things/RobotArm_Thing/shadow/update/rejected", "Target": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:thing/RobotArm_Thing" } ]' { "Arn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/subscriptions/2eb1f6e4-a960-4796-8e0d-e67adbdeabd7/versions/c75cc6e2-af57-48fb-8f6a-42e9a5f74d10", "Version": "c75cc6e2-af57-48fb-8f6a-42e9a5f74d10", "CreationTimestamp": "2017-12-29T13:14:34.243Z", "Id": "2eb1f6e4-a960-4796-8e0d-e67adbdeabd7" }
作成されたバージョン情報は下記のように参照できます。
$ aws greengrass get-subscription-definition-version --subscription-definition-id 2eb1f6e4-a960-4796-8e0d-e67adbdeabd7 --subscription-definition-version-id c75cc6e2-af57-48fb-8f6a-42e9a5f74d10 { "Definition": { "Subscriptions": [ { "Source": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:thing/Switch_Thing", "Target": "GGShadowService", "Id": "1", "Subject": "$aws/things/RobotArm_Thing/shadow/update" }, { "Source": "GGShadowService", "Target": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:thing/RobotArm_Thing", "Id": "10", "Subject": "$aws/things/RobotArm_Thing/shadow/update/accepted" }, { "Source": "GGShadowService", "Target": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:thing/RobotArm_Thing", "Id": "11", "Subject": "$aws/things/RobotArm_Thing/shadow/update/rejected" }, { "Source": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:thing/RobotArm_Thing", "Target": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:uptimeLambda:storyLineUptime", "Id": "2", "Subject": "/topic/state" }, { "Source": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:thing/RobotArm_Thing", "Target": "GGShadowService", "Id": "3", "Subject": "$aws/things/RobotArm_Thing/shadow/update" }, { "Source": "GGShadowService", "Target": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:thing/RobotArm_Thing", "Id": "4", "Subject": "$aws/things/RobotArm_Thing/shadow/update/delta" }, { "Source": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:uptimeLambda:storyLineUptime", "Target": "cloud", "Id": "5", "Subject": "/topic/metering" }, { "Source": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:messageLambda:storyLineMessage", "Target": "GGShadowService", "Id": "6", "Subject": "$aws/things/RobotArm_Thing/shadow/update" }, { "Source": "cloud", "Target": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:messageLambda:storyLineMessage", "Id": "7", "Subject": "/topic/update" }, { "Source": "GGShadowService", "Target": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:thing/Switch_Thing", "Id": "8", "Subject": "$aws/things/RobotArm_Thing/shadow/update/accepted" }, { "Source": "GGShadowService", "Target": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:thing/Switch_Thing", "Id": "9", "Subject": "$aws/things/RobotArm_Thing/shadow/update/rejected" } ] }, "Version": "c75cc6e2-af57-48fb-8f6a-42e9a5f74d10", "CreationTimestamp": "2017-12-29T13:14:34.243Z", "Id": "2eb1f6e4-a960-4796-8e0d-e67adbdeabd7", "Arn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/subscriptions/2eb1f6e4-a960-4796-8e0d-e67adbdeabd7/versions/c75cc6e2-af57-48fb-8f6a-42e9a5f74d10" }
ロガー定義の作成
AWS Greengrass Core や Lambda Function でのログの出力先を指定するためのロガー定義を作成します。まずは定義を作成します。
$ aws greengrass create-logger-definition --name "RobotArm_LoggerDefinition" { "Name": "RobotArm_LoggerDefinition", "LastUpdatedTimestamp": "2017-12-29T13:27:55.886Z", "CreationTimestamp": "2017-12-29T13:27:55.886Z", "Id": "ee0ee151-cc1e-4959-a810-0cc15d4f32fa", "Arn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/loggers/ee0ee151-cc1e-4959-a810-0cc15d4f32fa" }
作成されたロガー定義は下記のように参照可能です。
$ aws greengrass get-logger-definition --logger-definition-id ee0ee151-cc1e-4959-a810-0cc15d4f32fa { "Name": "RobotArm_LoggerDefinition", "LastUpdatedTimestamp": "2017-12-29T13:27:55.886Z", "CreationTimestamp": "2017-12-29T13:27:55.886Z", "Id": "ee0ee151-cc1e-4959-a810-0cc15d4f32fa", "Arn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/loggers/ee0ee151-cc1e-4959-a810-0cc15d4f32fa" }
続いてバージョンを作成します。 --logger-definition-id
には先ほど作成した定義情報の ID を指定します。 --loggers
には各ログの出力設定を json で指定します。 Component
で Greengrass Core か Lambda Function かを指定します。保存先としては Greengrass Core デバイスのファイルシステムか CloudWatch を指定できます。今回はファイルシステムに保存するため、 Type
には FileSystem を指定しています。 Id
には任意の値を指定できますので、今回はそれぞれ system-logs と lambda-logs を指定します。
$ aws greengrass create-logger-definition-version --logger-definition-id "ee0ee151-cc1e-4959-a810-0cc15d4f32fa" --loggers '[ { "Id": "system-logs", "Component": "GreengrassSystem", "Level": "INFO", "Space": 5120, "Type": "FileSystem" }, { "Id": "lambda-logs", "Component": "Lambda", "Level": "DEBUG", "Space": 5120, "Type": "FileSystem" }]' { "Arn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/loggers/ee0ee151-cc1e-4959-a810-0cc15d4f32fa/versions/3f1abcab-6b7a-44a0-b5f6-01bc3139334c", "Version": "3f1abcab-6b7a-44a0-b5f6-01bc3139334c", "CreationTimestamp": "2017-12-29T13:31:19.917Z", "Id": "ee0ee151-cc1e-4959-a810-0cc15d4f32fa" }
作成されたバージョン情報は下記のように参照できます。
$ aws greengrass get-logger-definition-version --logger-definition-id ee0ee151-cc1e-4959-a810-0cc15d4f32fa --logger-definition-version-id 3f1abcab-6b7a-44a0-b5f6-01bc3139334c { "Definition": { "Loggers": [ { "Type": "FileSystem", "Space": 5120, "Component": "Lambda", "Id": "lambda-logs", "Level": "DEBUG" }, { "Type": "FileSystem", "Space": 5120, "Component": "GreengrassSystem", "Id": "system-logs", "Level": "INFO" } ] }, "Version": "3f1abcab-6b7a-44a0-b5f6-01bc3139334c", "CreationTimestamp": "2017-12-29T13:31:19.917Z", "Id": "ee0ee151-cc1e-4959-a810-0cc15d4f32fa", "Arn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/loggers/ee0ee151-cc1e-4959-a810-0cc15d4f32fa/versions/3f1abcab-6b7a-44a0-b5f6-01bc3139334c" }
AWS Greengrass Group の更新
ここまでで作成した各コンポーネントを使用するように、最初に定義だけ作成した Greeengrass Group のバージョン情報を作成します。パラメータに Greengrass Core 定義バージョンなどの arn を指定します。
$ aws greengrass create-group-version --group-id "c4768328-4dce-4e41-9fd2-3ce8e943072e" \ --core-definition-version-arn "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/cores/5272397b-ec69-4259-bb5c-6043daade271/versions/c72d9131-69ab-4be5-9123-2ee9709d193b" \ --function-definition-version-arn "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/functions/1ed0c6f7-c34e-4ed1-a8d4-740f99d62778/versions/a203e6af-74b8-4a52-baf4-10c648e0f3fb" \ --device-definition-version-arn "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/devices/081b65a9-e057-4395-80f0-d455f224eb23/versions/4a19989a-7fa7-4322-8425-f8570f625758" \ --logger-definition-version-arn "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/loggers/ee0ee151-cc1e-4959-a810-0cc15d4f32fa/versions/3f1abcab-6b7a-44a0-b5f6-01bc3139334c" \ --subscription-definition-version-arn "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/subscriptions/2eb1f6e4-a960-4796-8e0d-e67adbdeabd7/versions/c75cc6e2-af57-48fb-8f6a-42e9a5f74d10" { "Arn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/groups/c4768328-4dce-4e41-9fd2-3ce8e943072e/versions/fa439940-037b-431b-9103-3f65e8d52032", "Version": "fa439940-037b-431b-9103-3f65e8d52032", "CreationTimestamp": "2017-12-29T13:45:10.072Z", "Id": "c4768328-4dce-4e41-9fd2-3ce8e943072e" }
作成されたバージョン情報は下記のように参照できます。
$ aws greengrass get-group-version --group-id c4768328-4dce-4e41-9fd2-3ce8e943072e --group-version-id fa439940-037b-431b-9103-3f65e8d52032 { "Definition": { "CoreDefinitionVersionArn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/cores/5272397b-ec69-4259-bb5c-6043daade271/versions/c72d9131-69ab-4be5-9123-2ee9709d193b", "LoggerDefinitionVersionArn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/loggers/ee0ee151-cc1e-4959-a810-0cc15d4f32fa/versions/3f1abcab-6b7a-44a0-b5f6-01bc3139334c", "FunctionDefinitionVersionArn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/functions/1ed0c6f7-c34e-4ed1-a8d4-740f99d62778/versions/a203e6af-74b8-4a52-baf4-10c648e0f3fb", "DeviceDefinitionVersionArn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/devices/081b65a9-e057-4395-80f0-d455f224eb23/versions/4a19989a-7fa7-4322-8425-f8570f625758", "SubscriptionDefinitionVersionArn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/definition/subscriptions/2eb1f6e4-a960-4796-8e0d-e67adbdeabd7/versions/c75cc6e2-af57-48fb-8f6a-42e9a5f74d10" }, "Version": "fa439940-037b-431b-9103-3f65e8d52032", "CreationTimestamp": "2017-12-29T13:45:10.072Z", "Id": "c4768328-4dce-4e41-9fd2-3ce8e943072e", "Arn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/groups/c4768328-4dce-4e41-9fd2-3ce8e943072e/versions/fa439940-037b-431b-9103-3f65e8d52032" }
デプロイの作成
ここまででひとまず Greengrass Group の設定が完了したので、 Greengrass Core デバイスに設定内容をデプロイします。 --deployment-type
にはデプロイ種別を指定します。今回は新規のデプロイなので、 NewDeployment を指定します。
$ aws greengrass create-deployment --deployment-type NewDeployment --group-id c4768328-4dce-4e41-9fd2-3ce8e943072e --group-version-id fa439940-037b-431b-9103-3f65e8d52032 { "DeploymentId": "4b5a6bb0-bc30-40f7-8911-7d056f35b702", "DeploymentArn": "arn:aws:greengrass:ap-northeast-1:XXXXXXXXXXXX:/greengrass/groups/c4768328-4dce-4e41-9fd2-3ce8e943072e/deployments/4b5a6bb0-bc30-40f7-8911-7d056f35b702" }
デプロイのステータスは下記のように参照可能です。
$ aws greengrass get-deployment-status --deployment-id 4b5a6bb0-bc30-40f7-8911-7d056f35b702 --group-id c4768328-4dce-4e41-9fd2-3ce8e943072e { "DeploymentType": "NewDeployment", "DeploymentStatus": "InProgress", "UpdatedAt": "2017-12-29T13:51:52.407Z" }
まだ Greengrass Core デバイスを起動しておらず、デプロイが受け取られていないため、 DeploymentStatus
が InProgress になっています。デバイスが起動してデプロイが受け取られると Success に変わります。
Greengrass Core 接続情報の更新
他のデバイスが Greengrass Core に接続するための情報を更新します。 Core と連携デバイスはまずクラウドにアクセスしてこの情報を参照した上で、対象の Core デバイスに接続することになります。 --thing-name
には Greengrass Core デバイスの Thing 名を指定します。 --connectivity-info
には接続情報のリストを json で渡します。 Id
には任意の値を指定できるのでここでは 1 としています。 HostAdress
は Core デバイスの IP アドレスを指定し、 PortNumber
には Core デバイスのポート番号を指定します。
$ aws greengrass update-connectivity-info --thing-name "GGC_Thing" --connectivity-info '[ { "Id": "1", "HostAddress": "192.168.10.11", "PortNumber": 8883 }]' { "Version": "e112af49-c242-4899-8d6d-c4e8d5017cf6" }
更新された接続情報は下記のように参照できます。
$ aws greengrass get-connectivity-info --thing-name GGC_Thing { "ConnectivityInfo": [ { "PortNumber": 8883, "HostAddress": "192.168.10.11", "Id": "1" } ] }
デバイス上で動かすプログラムの用意
Switch_Thing と RobotArm_Thing で動作させるためのプログラムを用意します。今回はお試しということで、ローカルの Mac 上に Vagrant で Ubuntu の VM を作成してそこで実行します。(Vagrant での環境の作り方等は割愛) プログラムはこのシナリオのサンプル用としてあらかじめ提供されているものをそのまま使用します。
まずは AWS IoT デバイス SDK for C++ のリポジトリを git clone します。
$ git clone https://github.com/aws/aws-iot-device-sdk-cpp.git Cloning into 'aws-iot-device-sdk-cpp'... remote: Counting objects: 554, done. remote: Total 554 (delta 0), reused 0 (delta 0), pack-reused 554 Receiving objects: 100% (554/554), 547.85 KiB | 525.00 KiB/s, done. Resolving deltas: 100% (192/192), done. Checking connectivity... done.
リポジトリのディレクトリに入って build 用のディレクトリを作成します。
$ cd aws-iot-device-sdk-cpp/ $ mkdir build
Makefile を作成します。
$ cd build
$ cmake ../.
RobotArm_Thing 用のプログラムをビルドします。
$ make robot-arm-sample
Swith_Thing 用のプログラムをビルドします。
$ make switch-sample
ビルドが成功していれば、 build/bin ディレクトリにバイナリが生成されています。
$ ls -ltr bin/ total 7712 -rwxr-xr-x 1 vagrant vagrant 4148216 Dec 29 14:19 robot-arm-sample drwxr-xr-x 1 vagrant vagrant 136 Dec 29 14:20 certs -rwxr-xr-x 1 vagrant vagrant 3747600 Dec 29 14:20 switch-sample drwxr-xr-x 1 vagrant vagrant 136 Dec 29 14:20 config
RobotArm_Thing と Swith_Thing それぞれの証明書とプライベートキー、AWS IoT CA 証明書を build/bin/certs ディレクトリ配下の robotArm ディレクトリと switch ディレクトリに格納します。
$ ls -ltr bin/certs/robotArm/ total 12 -rw-r--r-- 1 vagrant vagrant 1758 Dec 29 14:35 root-ca.pem -rw-r--r-- 1 vagrant vagrant 1679 Dec 29 14:35 c5e6d39f7b-private.pem.key -rw-r--r-- 1 vagrant vagrant 1224 Dec 29 14:35 c5e6d39f7b-certificate.pem.crt $ $ ls -ltr bin/certs/switch/ total 12 -rw-r--r-- 1 vagrant vagrant 1758 Dec 29 14:35 root-ca.pem -rw-r--r-- 1 vagrant vagrant 1675 Dec 29 14:35 a20b621e05-private.pem.key -rw-r--r-- 1 vagrant vagrant 1220 Dec 29 14:35 a20b621e05-certificate.pem.crt
各プログラムの設定ファイルは build/bin/config ディレクトリにあります。
$ ls -ltr bin/config/ total 8 -rw-r--r-- 1 vagrant vagrant 836 Dec 29 14:19 RobotArmConfig.json -rw-r--r-- 1 vagrant vagrant 875 Dec 29 14:20 SwitchConfig.json
それぞれ AWS IoT エンドポイントと証明書などの設定を更新します。更新後の差分は下記の通り。
$ diff RobotArmConfig.json.bak RobotArmConfig.json 2c2 < "endpoint": "", --- > "endpoint": "greengrass.iot.ap-northeast-1.amazonaws.com", 6,8c6,8 < "root_ca_relative_path": "", < "device_certificate_relative_path": "", < "device_private_key_relative_path": "", --- > "root_ca_relative_path": "certs/robotArm/root-ca.pem", > "device_certificate_relative_path": "certs/robotArm/c5e6d39f7b-certificate.pem.crt", > "device_private_key_relative_path": "certs/robotArm/c5e6d39f7b-private.pem.key", $ $ diff SwitchConfig.json.bak SwitchConfig.json 2c2 < "endpoint": "", --- > "endpoint": "greengrass.iot.ap-northeast-1.amazonaws.com", 6,8c6,8 < "root_ca_relative_path": "", < "device_certificate_relative_path": "", < "device_private_key_relative_path": "", --- > "root_ca_relative_path": "certs/robotArm/root-ca.pem", > "device_certificate_relative_path": "certs/switch/a20b621e05-certificate.pem.crt", > "device_private_key_relative_path": "certs/switch/a20b621e05-private.pem.key",
Greengrass Core の実行
ここまでで RobotArm_Thing と Swith_Thing でのプログラムの実行準備はできたので、先に Greengrass Core を起動します。 Greengrass Core の設定や起動等については前回の記事を参照ください。今回も同様に Raspberry Pi で稼働させます。
$ sudo ./greengrassd start Stopping greengrass daemon of PID: 1260 Waiting. Stopped greengrass daemon, exiting with success Setting up greengrass daemon Validating hardlink/softlink protection Validating execution environment Found cgroup subsystem: cpu Found cgroup subsystem: cpuacct Found cgroup subsystem: blkio Found cgroup subsystem: memory Found cgroup subsystem: devices Found cgroup subsystem: freezer Found cgroup subsystem: net_cls Starting greengrass daemon Greengrass successfully started with PID: 5588
ちなみに Greengrass Core を起動すると先ほどのデプロイが実行されるので、ステータスが Success に変わります。
$ aws greengrass get-deployment-status --deployment-id 4b5a6bb0-bc30-40f7-8911-7d056f35b702 --group-id c4768328-4dce-4e41-9fd2-3ce8e943072e { "DeploymentType": "NewDeployment", "DeploymentStatus": "Success", "UpdatedAt": "2017-12-29T15:00:14.785Z" }
デバイスコードの実行
それでは RobotArm_Thing と Switch_Thing でのプログラムを実行します。まずは RobotArm_Thing のプログラムです。 build/bin ディレクトリ配下の robot-arm-sample を実行します。
$ ./robot-arm-sample [INFO] Fri Dec 29 15:07:49 2017 :878 [OpenSSL Wrapper] [140324204885824] [ConnectTCPSocket:L215] : resolved greengrass.iot.ap-northeast-1.amazonaws.com to 52.192.148.221 [INFO] Fri Dec 29 15:07:52 2017 :337 [Sample - RobotArm] [140324204885824] [RunSample:L168] : GGC connectivity information found for this Device! 400 [INFO] Fri Dec 29 15:07:52 2017 :346 [Sample - RobotArm] [140324204885824] [RunSample:L222] : Attempting Connect with: GGC Endpoint : 192.168.10.11 GGC Endpoint Port : 8883 [INFO] Fri Dec 29 15:07:52 2017 :347 [Sample - RobotArm] [140324204885824] [RunSample:L230] : Using CA at : /vagrant/aws-iot-device-sdk-cpp/build/bin/c4768328-4dce-4e41-9fd2-3ce8e943072e_root_ca1.pem [INFO] Fri Dec 29 15:07:52 2017 :351 [OpenSSL Wrapper] [140324204885824] [ConnectTCPSocket:L215] : resolved 192.168.10.11 to 192.168.10.11 [INFO] Fri Dec 29 15:07:52 2017 :538 [Network Read] [140324161402624] [HandleConnack:L228] : Network Connect Response. Success : SDK Code 0. [INFO] Fri Dec 29 15:07:53 2017 :39 [Sample - RobotArm] [140324204885824] [RunSample:L248] : Connected to GGC arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:thing/GGC_Thing in Group c4768328-4dce-4e41-9fd2-3ce8e943072e!! Sending Inital State ------- {"state":{"reported":{"myState":"off"}}} Waiting for an update!
このプログラムは起動時に状態を off として Shadow を更新して待機します。起動後に AWS IoT コンソールから RobotArm_Thing の Device Shadow を確認すると下記のようになっています。
{ "reported": { "myState": "off" } }
myState に変更があると /topic/metering トピックにメッセージを発行します。
それでは続いて Switch_Thing のプログラムを起動します。 build/bin ディレクトリ配下の switch-sample を実行します。
$ ./switch-sample [INFO] Fri Dec 29 15:13:21 2017 :47 [OpenSSL Wrapper] [140588581013312] [ConnectTCPSocket:L215] : resolved greengrass.iot.ap-northeast-1.amazonaws.com to 52.192.176.176 [INFO] Fri Dec 29 15:13:25 2017 :358 [Sample - Switch] [140588581013312] [RunSample:L139] : GGC connectivity information found for this Device!! [INFO] Fri Dec 29 15:13:25 2017 :363 [Sample - Switch] [140588581013312] [RunSample:L193] : Attempting Connect with: GGC Endpoint : 192.168.10.11 GGC Endpoint Port : 8883 [INFO] Fri Dec 29 15:13:25 2017 :364 [Sample - Switch] [140588581013312] [RunSample:L201] : Using CA at : /vagrant/aws-iot-device-sdk-cpp/build/bin/c4768328-4dce-4e41-9fd2-3ce8e943072e_root_ca1.pem [INFO] Fri Dec 29 15:13:25 2017 :369 [OpenSSL Wrapper] [140588581013312] [ConnectTCPSocket:L215] : resolved 192.168.10.11 to 192.168.10.11 [INFO] Fri Dec 29 15:13:25 2017 :562 [Network Read] [140588537530112] [HandleConnack:L228] : Network Connect Response. Success : SDK Code 0. [INFO] Fri Dec 29 15:13:26 2017 :63 [Sample - Switch] [140588581013312] [RunSample:L219] : Connected to GGC arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:thing/GGC_Thing in Group c4768328-4dce-4e41-9fd2-3ce8e943072e!! Please enter 1 (turn on) or 0 (turn off) to control the robot arm, q to quit:
入力待ち状態になりますので、 RobotArm_Thing の状態を on にする場合は 1 を、 off にする場合は 0 を入力します。終了するには q を入力します。先ほどの起動時は off になっていますので、 on にしてみます。
Please enter 1 (turn on) or 0 (turn off) to control the robot arm, q to quit: 1 Publishing message to cloud {"state":{"desired":{"myState":"on"}}}
RobotArm_Thing のプログラムのコンソールには下記のように出力されます。
-- Published state to /topic/metering (Should be routed to uptimelambda!) -- ------- Robot Arm State -------- on
Device Shadow を確認すると下記のように更新されています。
{ "desired": { "myState": "on" }, "reported": { "myState": "on" } }
また、 /topic/metering トピックには下記のようなメッセージが publish されています。
Robot arm turned ON
今度はクラウド側から状態を変更してみます。 /topic/update に Subscribe し、下記の json を publish します。
{"state":"off"}
すると RobotArm_Thing のプログラムを動かしているコンソールで下記のように出力されます。
-- Published state to /topic/metering (Should be routed to uptimelambda!) -- ------- Robot Arm State -------- off
Device Shadow は下記のようになります。
{ "desired": { "myState": "off" }, "reported": { "myState": "off" } }
/topic/metering には下記のように publish されます。
Robot arm turned OFF
まとめ
ひとまず Greengrass Core と他のデバイスを連携させて動かすことができましたが、今回は用意されているシナリオをそのまま動かしただけで、具体的にデバイスで動かすプログラムはどのように実装したら良いのか、サブスクリプションの各設定はどのような意味なのかはまだちゃんと理解できていません。コンソールから設定を変更してデプロイすることで各デバイスに反映されるのは便利だと思いますので、使い方をもう少し把握したいと思います。また、今回のシナリオで用意されていたデバイスコードは C++ のコードでしたが、 Python 等でも実装できそうなので、そちらも確認してみたいと思います。