LambdaからIoT経由でArduino Yúnへ(後編)

投稿者:

こちらの記事はLambdaからIoT経由でArduino Yúnへ(前編)の後編で、実際にどんなことをしたかについて書いています。

AWS IoT Thingの準備

先日AWS IoTをArduino Yúnで使うで書いたようにまずはAWS IoTにThingや証明書を準備します。ここではThingの名前をs3thingとしました。(my-Yúnとかにするべきだったかも。)

IoT

  • Thing
  • Policy
  • 証明書

を用意。

この証明書がArduino Yúnにセットアップされているものとして話を進めます。このあたりの設定については先日の記事に書いています。

topic
このs3thingのペインを開いてMQTT Topicのところをメモしておきましょう。これを後に出てくるLambda関数で使います。

IAMロールの準備

AWS LambdaがS3やIoTにアクセスするための権限をAWS IAMロールとして用意する必要があるので、マネジメントコンソールのIAMの画面で新しいロールを作ります。今回はLambda_S3IoTという名前にしました。

role_lambda
作成画面のAWS サービスロールの選択はAWS Lambdaにします。

role
ポリシーのアタッチの画面で

  • AmazonS3FullAccess
  • AWSIoTFullAccess
  • CloudWatchLogsFullAccess

を追加します。CloudWatchLogsFullAccessを追加することでLambdaのデバッグがCloudWatchのログで可能になります。

S3バケットの準備

後に出てくるLambda関数はS3にファイルをアップロードしたのをきっかけに呼び出したいので、S3にはそれ用のバケットを用意しておきます。

s3
ここではsandbox.bucketという名前にしておきました。

Lambda関数の準備

Lambda関数は、マネジメントコンソールのLambda関数作成画面にリストされる「s3-get-object-python」ブループリントのコードをベースにしました。

これをlambda_function.pyという名前でファイルに保存しました。変更点は主にAWS IoTのためのコードを追加していることです。具体的には以下の3点です。

Lambdaにデフォルトで含まれるバージョンではなく最新のboto3を使う
Lambdaには初めから(デプロイパッケージをアップロードしなくても)AWSを操作できるPythonモジュールのboto3が利用可能になっていますが、そのバージョンにはAWS IoT向けのコードが入っていないようです。そのため後述の通り、別途最新のboto3を追加したLambdaデプロイパッケージを作ることになるのですが、単にboto3モジュールをデプロイパッケージに含めるだけだと、Lambda関数はそのboto3を無視してデフォルトのboto3を読み込んでしまいます。
そこで、LAMBDA_TASK_ROOT環境変数をPythonパスの一番先に追加して、デプロイパッケージのboto3を読み込ませるというわけです。
※このデフォルトのboto3を避ける方法はこちらを参考にさせてもらいました。

AWS IoTで作ったThingのMQTT topicを指定する
コードの中の、iot.publishのtopic部分には先ほどメモしておいた、$awsから始まるMQTT topicを入れます。
topic='$aws/things/s3thing/shadow/update'
Thingのステータスをアップデートするためのリクエスト内容を用意する
リクエスト内容はstateの中にdesiredがあり、desiredの中にアップデートしたいデータが入るという構造にします。(参考ページ:Device Shadow Document Syntax

Lambdaデプロイパッケージ(zipファイル)の作成

Lambda関数で最新のboto3モジュールを使うために、boto3とLambda関数書かれたPythonファイルを1つのzipファイルにまとめます。

AWS Lambdaのデプロイパッケージの作成についてのドキュメントを見ると様々な方法が紹介されていますが、私の場合はMacOSでVirtualenvを使って、こんなターミナルコマンドでboto3のモジュールを用意しました。

# 適当なディレクトリを作る
mkdir awsiot
# そのディレクトリに入る
cd awsiot
# さらに適当なディレクトリ(ここではENV)を作る
mkdir ENV
# ENVディレクトリを仮想環境のための場所にする
virtualenv ENV
# 仮想環境に入る
source ENV/bin/activate
# boto3をインストールする
pip install boto3
# デプロイパッケージを置く適当なディレクトリ(ここではupload)を作る
mkdir upload
# 仮想環境に入っているモジュールをuploadディレクトリに移動する
mv ENV/lib/python2.7/site-packages/* upload/

ここまでやると

modules
こんな風に、uploadディレクトリにモジュールが入っているはずです。

lambda_function
uploadディレクトリにLambda関数を書いたPythonファイルlambda_function.pyを追加します。

zip
そしてuploadディレクトリの内容をZIPファイルに圧縮します。この時uploadディレクトリを圧縮するのではなく、uploadディレクトリの中身を圧縮します。これでLambdaのデプロイパッケージ(ZIPファイル)ができます。

Lambdaにデプロイ

lambda
マネジメントコンソールのLambdaの画面でLambda関数を作ります。

  • RuntimeはPython
  • Code entry typeはZIPファイルのアップロード
  • Roleは先に作ったIAMロールLambda_S3IoTを指定

Lambda関数ができたらそれを呼び出すイベントソースの設定をします。Event sourcesタブを開いてAdd event sourceをクリックします。

eventsource
LambdaのイベントソースはS3、バケットは先に作っておいたsandbox.bucket、イベントの種類はObject Createdを指定します。(ここではAllにしていますがPostだけでも良いと思います。)

Arduino Yúnのスケッチ

ここからは物理的なデバイス、Arduino Yúnの準備です。

前回AWS IoT Arduino Yún SDKのサンプルスケッチBasicPubSubを試しましたが、今回はThingShadowEchoを使います。

ThingShadowEcho
先日同様、aws_iot_config.hファイルにはAWS IoTで証明書を作った時に出てきたdefine文をペーストしてあるものとします。

そしてThingShadowEcho.inoファイルのmsg_callback_delta関数の終わりには、

このような、S3のオブジェクト数と日時を取り出すコードを追加してみました。

serial
スケッチをArduino Yúnに読み込ませ、Arduino IDEのシリアルターミナルを開いて、S3のバケットにファイルをアップロードすると、こんな風に、オブジェクト数と日時が表示されます。

ようやくできたよ!

7セグメントLEDを点けてみた

DSC_0097-30
このIoTから届くS3のオブジェクト数をシリアル接続7セグメント4桁LED(赤)に表示させてみました。

当初思ったような、CloudWatchのアラートが発生したらArduino Yúnがモーターをぐるぐる回す、というところまではできていませんが、もう後はこれの延長なのだからできますよね?きっと。

気がついたことなど

AWS IoTから届くデータが大きすぎるとArduino Yúnがメモリ不足でエラーとなってしまいます。そのためThingのstateには少ししか情報を置きませんでした。