M5Stack Core2 for AWSでSmart-Thermostatの実行」で、AWS IoT Eventsの探知器モデルを使ってモデルの状態を判断しましたが、Device Shadowに保存されたM5Stack Core2 for AWSからのデータを、Lambda関数を使って判断してその結果をDevice Shadowに保存し、M5Stack Core2 for AWSにcallback通知します。

AWSチュートリアル「スマートサーモスタット」に対する変更方針

  • AWSチュートリアル「スマートサーモスタット」をベースに、AWS IoTのトピックルールで使用するアクション「AWS IoTのトピックにメッセージを再パブリッシュする」と「IoT Events 入力にメッセージを送信」を、「メッセージデータを渡す Lambda 関数を呼び出す」に変更する。
  • Lambda 関数では「sound」の値を使用して「hvacStatus」を判断し、この結果をLambda 関数からDevice Shadowにパブリッシュします。
  • M5Stack Core2 for AWSのファームウェアはスマートサーモスタットのコードと同じとし、AWS IoT Device SDK for Embedded C を使用してDevice Shadowによりデータ転送を行います。

AWS IoT のトピックルールにLambda関数の登録

M5Stack Core2 for AWSでパブリッシュしたメッセージをAWS IoT Coreで受信して、Lambda関数で処理するために次のように設定します。

  1. AWS IoT Core マネジメントコンソールに移動し、「Act」、「ルール」、「作成」の順に選択します。
  2. ルールに名前「Core2IotLambdaRule」を付けます。
  3. 以下のクエリを設定して、「アクションの追加」 を選択します。
  4. SELECT current.state as current.state, current.version as current.version, timestamp FROM '$aws/things/<CLIENT_ID>/shadow/update/documents'
    
  5. 「メッセージデータを渡す Lambda 関数を呼び出す」、「アクションの設定」の順に選択します。
  6. 「新しい Lambda 関数を作成」をクリックし、「関数名」 に「thermostatlambda1 」、「ランタイム」に「Node.js」、「アクセス権限」に「基本的な Lambda アクセス権限で新しいロールを作成」を選択して「関数の作成」ボタンをクリックします。次のLambda 関数の作成画面が表示されます。
  7. 「設定」タブ、左側メニュ「アクセス権限」をそれぞれ選択し、実行ロールに管理ポリシー「 AWSIoTDataAccess」を追加します。これにより「GetThingShadow」「UpdateThingShadow」の実行を許可します。
  8. 実行ロールに管理ポリシー「 AWSIoTDataAccess」を追加しないでLambda 関数「thermostatlambda1 」を実行すると、例外「ForbiddenException」が発生します。

  9. 「アクションの追加」 を選択して、アクションの設定を終了し、ルール作成フォームに戻ります。
  10. 作成したトピックルールを次に示します。

Device Shadowを処理するLambda 関数の作成

作成したLambda 関数「thermostatlambda1」を次に示します。

  • 13行目で、「getThingShadow」メソッドによりDevice Shadow の内容を読み込みます。
  • 23行目で、「sound」の値が「50」以上の場合、「hvacStatus」を「COOLING」、それ以外は「hvacStatus」を「STANDBY」にします。
  • 44行目で、「updateThingShadow」メソッドによりDevice Shadow にパブリッシュします。

thermostatlambda1/index.js

var aws = require('aws-sdk');

var endpoint  = 'xxxxxxx.amazonaws.com';
var thingName = 'yyyyyyyy';

exports.handler = async (event) => {
    // TODO implement
    console.log('exports.handler 01');
    var iotdata = new aws.IotData( { endpoint: endpoint } );
    console.log("event JSON:", JSON.stringify(event, null, 2));

    var params = { thingName: thingName };
    iotdata.getThingShadow(params, function (err, data) {
        if (!err) {
            // シャドウドキュメントから現在の設定を取得
            var payload = JSON.parse(data.payload);
            console.log("payload : " + JSON.stringify(payload, null, 2));
            var sound = payload.state.reported.sound;
            console.log("sound : " + sound);
            //var currentBlinkPattern = payload.state.desired.blinkPattern;
            
            var status ;
            if(sound > 50){
                status = "COOLING";
            }
            else{
                status = "STANDBY";
            }
                
            var desiredState = {
                state: {
                    desired: {
                        hvacStatus: status
                    }
                }
            };
 

            // デバイスシャドウを書き込む
            var params = {
              thingName: thingName,
              payload: JSON.stringify(desiredState)
            };
            iotdata.updateThingShadow(params, function (err, data) {
                if (!err) {
                    context.succeed();
                } else {
                    context.fail(err);      
                }
            });
        }
        else{
            console.log("getThingShadow error "+err);
        }

    });
    console.log('exports.handler end');
};

M5Stack Core2 for AWSでSmart-Thermostatの実行

M5Stack Core2 for AWSをリセットして実行します。Serial Monitorの出力を次に示します。ログ「Delta – hvacStatus state changed to COOLING」により、「hvacStatus」の値が「STANDBY」から「COOLING」に変化したcallbackが発生したことが確認できます。

   ・・・
?[0;32mI (10762) I2S: PLL_D2: Req RATE: 44100, real rate: 90909.000, BITS: 16, CLKM: 11, BCK: 5, MCLK: 11.338, SCLK: 2909088.000000, diva: 64, divb: 21?[0m
?[0;32mI (11072) MAIN: *****************************************************************************************?[0m
?[0;32mI (11072) MAIN: On Device: roomOccupancy false?[0m
?[0;32mI (11072) MAIN: On Device: hvacStatus STANDBY?[0m
?[0;32mI (11082) MAIN: On Device: temperature 70.634026?[0m
?[0;32mI (11082) MAIN: On Device: sound 22?[0m
?[0;32mI (11092) MAIN: Update Shadow: {"state":{"reported":{"temperature":70.634026,"sound":22,"roomOccupancy":false,"hvacStatus":"STANDBY"}}, "clientToken":"xxxxxx-0"}?[0m
?[0;32mI (13402) MAIN: *****************************************************************************************?[0m
?[0;32mI (13402) MAIN: Stack remaining for task 'aws_iot_task' is 2036 bytes?[0m
?[0;32mI (14422) MAIN: ************* hvac_Callback?[0m
?[0;32mI (14422) MAIN: Delta - hvacStatus state changed to COOLING?[0m
?[0;32mI (14422) MAIN: setting side LEDs to blue?[0m
?[0;32mI (14452) MAIN: Update accepted?[0m
?[0;32mI (14602) MAIN: *****************************************************************************************?[0m
?[0;32mI (14602) MAIN: On Device: roomOccupancy false?[0m
?[0;32mI (14602) MAIN: On Device: hvacStatus COOLING?[0m
?[0;32mI (14612) MAIN: On Device: temperature 76.786415?[0m
?[0;32mI (14612) MAIN: On Device: sound 19?[0m
?[0;32mI (14622) MAIN: Update Shadow: {"state":{"reported":{"temperature":76.786415,"sound":19,"roomOccupancy":false,"hvacStatus":"COOLING"}}, "clientToken":"xxxxxxx-1"}?[0m
?[0;32mI (14652) MAIN: *****************************************************************************************?[0m
?[0;32mI (14652) MAIN: Stack remaining for task 'aws_iot_task' is 2036 bytes?[0m
?[0;32mI (15672) MAIN: Update accepted?[0m
?[0;32mI (15852) MAIN: *****************************************************************************************?[0m
?[0;32mI (15852) MAIN: On Device: roomOccupancy false?[0m
?[0;32mI (15852) MAIN: On Device: hvacStatus COOLING?[0m
?[0;32mI (15862) MAIN: On Device: temperature 67.747856?[0m
?[0;32mI (15862) MAIN: On Device: sound 6?[0m
?[0;32mI (15872) MAIN: Update Shadow: {"state":{"reported":{"temperature":67.747856,"sound":6,"roomOccupancy":false,"hvacStatus":"COOLING"}}, "clientToken":"xxxxxxx-2"}?[0m
?[0;32mI (15902) MAIN: *****************************************************************************************?[0m
   ・・・

AWS IoT Core マネジメントコンソールに移動し、「管理」「モノ」から対応するモノ「xxxxx」を選択し、表示された「Device Shadow」タブを選択し、「Classic Shadow」を選択すると次のように表示されます。

CloudWatchマネジメントコンソールに移動し、「ログ」「ロググループ」から対応する「/aws/lambda/thermostatlambda1」を選択し、表示されたログを確認します。Lambda 関数「thermostatlambda1」により読み出されたDevice Shadowの内容が表示されます。Lambda 関数「thermostatlambda1」からDevice Shadowの内容が更新されていることが確認できます。