CloudWatch Events + LambdaでAWS IoTデバイスシャドウを制御する

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

ども、大瀧です。

AWS IoT デバイスシャドウは、デバイスの状態を管理するための機能です。デバイスがオフラインになることを見越して、オンラインになったタイミングで遅延反映できるようになっているのが特徴ですね。デバイスシャドウを使うためには、デバイス側ではIoTデバイスSDKを用いるのが定番ですが、管理アプリケーションの実装は割とふわっとしています。 そこで今回は、手軽にデバイスシャドウを制御する方法としてAWS Lambdaのスケジュールジョブ実行をご紹介します。

CloudWatch Events + Lambdaでできること

LambdaからAWS SDKを利用すれば、デバイスシャドウの読み取り/書き込みが可能です。一方、CloudWatch Eventsのスケジュール実行 *1は最短5分からCronライクにLambda関数の定期実行できるので、デバイスシャドウによるデバイスのスケジュール制御ができるわけです。以下のユースケースを思いつきました。

  • シャドウでデバイスのオン/オフを管理し、朝8時にオン夕方6時にオフなどのスケジュール運用
  • デモ用途でデバイスの状態を5分間隔でトグル

手順1. AWS IoTデバイスシャドウの構成

まず、AWS IoTで対象のデバイス(Thing)を作成し、[Update shadow]リンクからシャドウを登録します。今回はデモ用にデバイスのLEDを点灯させるので、点灯バターンとしてblinkPatternをシャドウに定義しました。"red"ならLEDを赤色に点灯、"green"なら緑色に点灯という仕様にします。

{
  "desired": {
    "blinkPattern": "green"
  },
  "reported": {
    "blinkPattern": "green"
  }
}

AWS IoTの管理画面では、以下のような感じです。

lambda-iot02

この後のLambdaからの接続のために、エンドポイント(パスはAWS SDKが吸収してくれるのでホスト名のみ)とThing名(今回はbx1-08)を控えておきます。

手順2. Lambdaの構成

今回はNode.jsで実装し、以下のコードでLambda Functionを定義しました。特に外部ライブラリは利用しないのでManagement Consoleの[Code]タブで記述しました。

console.log('Loading function');
var aws = require('aws-sdk');

var endpoint  = 'XXXXXXXXXXXX.iot.ap-northeast-1.amazonaws.com';
var thingName = 'bx1-08';

exports.handler = function(event, context) {
    // AWS IoT Data APIに接続
    var iotdata = new aws.IotData( { endpoint: endpoint } );
    // デバイスシャドウを取得
    var params = { thingName: thingName };
    iotdata.getThingShadow(params, function (err, data) {
        if (!err) {
            // シャドウドキュメントから現在の設定を取得
            var payload = JSON.parse(data.payload);
            var currentBlinkPattern = payload.state.desired.blinkPattern;
            console.log("Current Pattern : " + currentBlinkPattern);

            // redとgreenをトグルし、シャドウドキュメントに合わせたオブジェクトを生成
            if(currentBlinkPattern == 'red') {
                var desiredBlinkPattern = 'green';
            } else {
                var desiredBlinkPattern = 'red';
            }
            var desiredState = {
                state: {
                    desired: {
                        blinkPattern: desiredBlinkPattern
                    }
                }
            };
            
            // デバイスシャドウを書き込む
            var params = {
              thingName: thingName,
              payload: JSON.stringify(desiredState)
            };
            iotdata.updateThingShadow(params, function (err, data) {
                if (!err) {
                    context.succeed();
                } else {
                    context.fail(err);      
                }
            });
        } else {
            context.fail(err);      
        }
    });
};

当たり前ですが、JavascriptだとJSONを楽に扱えるので、シンプルに書くことができました。赤だったら緑に、緑なら赤にとデモ向けの簡単なロジックにしています。

Lambda関数に紐付けるIAMロールは以下のようにマネージドポリシーAWSIoTDataAccessを設定しました。

lambda-iot03

かなり緩めの設定なので、必要に応じてカスタムポリシーを定義しResourceで対象のThingを絞っても良いでしょう。以下のドキュメントを参照してください。

関数を定義したら、[Event sources]タブ - [+ Add event source]リンクからイベントソースを追加します。[Event source type]から「Scheduled Event」を選択し、任意のスケジュールを登録します。今回は5分おきにしました。

lambda-iot04

[Submit]をクリックすれば、設定完了です。

実行できているかは、[Monitoring]タブの[Invocations]で確認できます。ちょっと時間が経っている場合のスクリーンショットですが、1時間に12回実行されているので、5分おきなのがわかりますね。

lambda-iot05

また、IoTの設定でCloudWatch Logsを有効化しておけば、Lambdaのログの他にAWS IoT側でもログが取れます。UpdateThingShadowAPIがコールされていることがわかりますね。

lambda-iot06

AWS IoTのThingの画面を見ると、トグルしている様子がわかります。

lambda-iot07

一人でにコロコロ変わるので、見ていて面白いですw

まとめ

IoTデバイスシャドウにアプローチする例として、Lambdaのスケジュール実行をご紹介しました。Lambdaであれば、スケジュール実行以外にAPI Gatewayの組み合わせも使えるので、外部システムと連携させたいといったケースにも応用できそうですね。

ちなみに、今回のサンプルは今日まで開催のネプコンジャパン2016信和産業様ブースでBLE経由でデバイスを制御するデモで利用しています。興味のある方はぜひご来場ください!

脚注

  1. 以前のScheduled Event Source