AWSチュートリアル「スマートサーモスタット」に従って、M5Stack Core2 for AWSで「m5stack/Core2-for-AWS-IoT-EduKit」のproject「Smart-Thermostat」を実行します。前提条件として、「 M5Stack Core2 for AWSのATECC608Aを使ってAWS IoT Coreへアクセス」を参考にして、AWS IoT Coreにアクセス可能になっていることとします。

以下に記述されている「<CLIENT_ID>」 は、AWS IoT Coreで左側のメニューで「管理」→「モノ」を選択すると表示される「名前」を指します。

AWS IoT Coreのトピックルールの作成

トピックルールは、M5Stack Core2 for AWSがAWS IoT Coreパブリッシュしたメッセージを受信し、サンプリングされた音声レベルを調査し、変化に応じて Device Shadow の部屋の在室状況ステータスを更新します。

  1. AWS IoT Core マネジメントコンソールに移動し、「Act」、「ルール」、「作成」の順に選択します。
  2. ルールに名前「thermostatRule」を付けます。
  3. 以下のクエリを設定して、「アクションの追加」 を選択します。
  4. SELECT CASE state.reported.sound > 10 WHEN true THEN true ELSE false END AS state.desired.roomOccupancy FROM '$aws/things/<CLIENT_ID>/shadow/update/accepted' WHERE state.reported.sound <> Null
    
  5. 「AWS IoTのトピックにメッセージを再パブリッシュする」、「アクションの設定」の順に選択します。
  6. 「トピック」 には、「$$aws/things/<CLIENT_ID>/shadow/update 」を使用します。
  7. 「このアクションの実行のために AWS IoT アクセスを付与するロールを選択または作成」 で、「ロールの作成」 を選択すると、ポップアップが開き新しい IAM ロール名「Core2IotRole」を付けます。その後、「ロールの作成」 をクリックします。
  8. 「アクションの追加」 を選択して、アクションの設定を終了し、ルール作成フォームに戻ります。
  9. 作成したトピックルールを次に示します。

AWS IoT Eventsの入力の作成

AWS IoT Eventsの入力はインバウンドメッセージを探知器モデルにマッピングするための事前定義済みスキーマです。

  1. IoT Events マネジメントコンソール に移動します。左側のメニューを展開し、「入力」、「入力を作成」の順に選択します。
  2. 入力に 名前「thermostat」を付け、次のJSON ファイル「input.json」を作成します。
  3. input.json

    {
      "current": {
        "state": {
          "reported": {
            "sound": 10,
            "temperature": 35,
            "roomOccupancy": false,
            "hvacStatus": "HEATING"
          }
        },
        "version": 13
      },
      "timestamp": 1606282489
    }
    
  4. 「ファイルをアップロード」を選択し、作成したJSON ファイル「input.json」を選びます。
  5. 「作成」 を選択し、入力の作成を終了します。
  6. 作成した入力を次に示します。

AWS IoT Coreの Device Shadow の更新ルールの作成

HVAC コントロールアプリケーションの作成に使用するこのリソースに、Device Shadow の更新を転送する新しいルールを作成します。

  1. AWS IoT Core マネジメントコンソールに戻り、「Act」、「ルール」、「作成」の順に選択します。
  2. ルールに名前「Core2IotRule」を付けます。
  3. 以下のクエリを設定して、「アクションの追加」 を選択します。
  4. SELECT current.state as current.state, current.version as current.version, timestamp FROM '$aws/things/<CLIENT_ID>/shadow/update/documents
    
  5. 「IoT Events 入力にメッセージを送信」、「アクションの設定」 の順に選択します。
  6. 「入力名」で、IoT Events コンソールであらかじめ作成した入力リソース名「thermostat 」を見つけます。
  7. 「ロール」で 「ロールの作成」 を選択し、IAM ロール名「Core2IoTRole2」を付けます。その後「ロールの作成」を選択し、IoT Core が IoT Events にメッセージを送信する許可を与える新しい IAM ロールを確定します。
  8. 「アクションの追加」 を選択し、新しいルールアクションを確定し、ルール作成フォームに戻ります。
  9. 「ルールの作成」を選択し、ルールの作成を終了します。
  10. 作成したDevice Shadow の更新ルールを次に示します。

AWS IoT Events の探知器モデルの作成

AWS IoT Events の探知器モデルは有限ステートマシンで、1 つ以上の入力からのメッセージを処理し、モデルの状態を変更すべきかを判断します。

次のJSON ファイル「Detectormodels.json」を作成します。

Detectormodels.json

{
    "detectorModelDefinition": {
        "states": [
            {
                "stateName": "standby",
                "onInput": {
                    "events": [],
                    "transitionEvents": [
                        {
                            "eventName": "startHeating",
                            "condition": "($input.thermostat.current.state.reported.temperature <= $variable.heatingThresholdUnoccupied) || ($input.thermostat.current.state.reported.roomOccupancy && $input.thermostat.current.state.reported.temperature <= $variable.heatingThresholdOccupied) ",
                            "actions": [],
                            "nextState": "heating"
                        },
                        {
                            "eventName": "startCooling",
                            "condition": "($input.thermostat.current.state.reported.temperature >= $variable.coolingThresholdUnoccupied) || ($input.thermostat.current.state.reported.roomOccupancy && $input.thermostat.current.state.reported.temperature >= $variable.coolingThresholdOccupied) ",
                            "actions": [],
                            "nextState": "cooling"
                        }
                    ]
                },
                "onEnter": {
                    "events": [
                        {
                            "eventName": "setThresholds",
                            "condition": "true",
                            "actions": [
                                {
                                    "setVariable": {
                                        "variableName": "heatingThresholdUnoccupied",
                                        "value": "60"
                                    }
                                },
                                {
                                    "setVariable": {
                                        "variableName": "heatingThresholdOccupied",
                                        "value": "68"
                                    }
                                },
                                {
                                    "setVariable": {
                                        "variableName": "coolingThresholdOccupied",
                                        "value": "72"
                                    }
                                },
                                {
                                    "setVariable": {
                                        "variableName": "coolingThresholdUnoccupied",
                                        "value": "80"
                                    }
                                }
                            ]
                        },
                        {
                            "eventName": "setStandbyInShadow",
                            "condition": "true",
                            "actions": [
                                {
                                    "iotTopicPublish": {
                                        "mqttTopic": "'$aws/things/<CLIENT_ID>/shadow/update'",
                                        "payload": {
                                            "contentExpression": "'{\"state\":{\"desired\":{\"hvacStatus\":\"STANDBY\"}}}'",
                                            "type": "JSON"
                                        }
                                    }
                                }
                            ]
                        }
                    ]
                },
                "onExit": {
                    "events": []
                }
            },
            {
                "stateName": "cooling",
                "onInput": {
                    "events": [],
                    "transitionEvents": [
                        {
                            "eventName": "stopCooling",
                            "condition": "(!$input.thermostat.current.state.reported.roomOccupancy && $input.thermostat.current.state.reported.temperature < $variable.coolingThresholdUnoccupied) || ($input.thermostat.current.state.reported.roomOccupancy && $input.thermostat.current.state.reported.temperature < $variable.coolingThresholdOccupied) ",
                            "actions": [],
                            "nextState": "standby"
                        }
                    ]
                },
                "onEnter": {
                    "events": [
                        {
                            "eventName": "setCoolingInShadow",
                            "condition": "true",
                            "actions": [
                                {
                                    "iotTopicPublish": {
                                        "mqttTopic": "'$aws/things/<CLIENT_ID>/shadow/update'",
                                        "payload": {
                                            "contentExpression": "'{\"state\":{\"desired\":{\"hvacStatus\":\"COOLING\"}}}'",
                                            "type": "JSON"
                                        }
                                    }
                                }
                            ]
                        }
                    ]
                },
                "onExit": {
                    "events": []
                }
            },
            {
                "stateName": "heating",
                "onInput": {
                    "events": [],
                    "transitionEvents": [
                        {
                            "eventName": "stopHeating",
                            "condition": "(!$input.thermostat.current.state.reported.roomOccupancy && $input.thermostat.current.state.reported.temperature > $variable.heatingThresholdUnoccupied) || ($input.thermostat.current.state.reported.roomOccupancy && $input.thermostat.current.state.reported.temperature > $variable.heatingThresholdOccupied) ",
                            "actions": [],
                            "nextState": "standby"
                        }
                    ]
                },
                "onEnter": {
                    "events": [
                        {
                            "eventName": "setHeatingInShadow",
                            "condition": "true",
                            "actions": [
                                {
                                    "iotTopicPublish": {
                                        "mqttTopic": "'$aws/things/<CLIENT_ID>/shadow/update'",
                                        "payload": {
                                            "contentExpression": "'{\"state\":{\"desired\":{\"hvacStatus\":\"HEATING\"}}}'",
                                            "type": "JSON"
                                        }
                                    }
                                }
                            ]
                        }
                    ]
                },
                "onExit": {
                    "events": []
                }
            }
        ],
        "initialStateName": "standby"
    },
    "detectorModelName": "hvacApplication",
    "detectorModelDescription": "cloud application to manage HVAC state",
    "evaluationMethod": "BATCH"
}
  1. IoT Events マネジメントコンソール に移動します。
  2. 「探知器モデル」を選択します。
  3. 「アクション」を選択し、「探知器モデルのインポート」を選択します。
  4. 「インポート」を選択します。
  5. 「開く」を選択し、作成したJSON ファイル「Detectormodels.json」を選択して、「発行」を選択します。
  6. 「ロール」で、新しい IAM ロール名「edukit-iotevents」を入力します。
  7. 「保存して発行」を選択します。
  8. 作成した探知器モデル設定とモデル図を次に示します。

M5Stack Core2 for AWSでSmart-Thermostatの実行

取得したproject「Smart-Thermostat」をコンパイルして実行します。M5Stack Core2 for AWSの表示画面を次に示します。

Serial Monitorの出力を次に示します。「roomOccupancy true」となり、状態が「hvacStatus STANDBY」から「hvacStatus COOLING」に遷移していることが確認できます。

   ・・・
?[0;32mI (99653) MAIN: Delta - roomOccupancy state changed to 1?[0m
?[0;32mI (99813) MAIN: *****************************************************************************************?[0m
?[0;32mI (99813) MAIN: On Device: roomOccupancy true?[0m
?[0;32mI (99813) MAIN: On Device: hvacStatus STANDBY?[0m
?[0;32mI (99823) MAIN: On Device: temperature 69.884949?[0m
?[0;32mI (99823) MAIN: On Device: sound 123?[0m
?[0;32mI (99833) MAIN: Update Shadow: {"state":{"reported":{"temperature":69.884949,"sound":123,"roomOccupancy":true,"hvacStatus":"STANDBY"}}, "clientToken":"0123779b0168220201-69"}?[0m
?[0;32mI (99863) MAIN: *****************************************************************************************?[0m
?[0;32mI (99863) MAIN: Stack remaining for task 'aws_iot_task' is 2036 bytes?[0m
?[0;32mI (100883) MAIN: Update accepted?[0m
?[0;32mI (101063) MAIN: *****************************************************************************************?[0m
?[0;32mI (101063) MAIN: On Device: roomOccupancy true?[0m
?[0;32mI (101063) MAIN: On Device: hvacStatus STANDBY?[0m
?[0;32mI (101073) MAIN: On Device: temperature 74.825577?[0m
?[0;32mI (101073) MAIN: On Device: sound 84?[0m
?[0;32mI (101083) MAIN: Update Shadow: {"state":{"reported":{"temperature":74.825577,"sound":84,"roomOccupancy":true,"hvacStatus":"STANDBY"}}, "clientToken":"0123779b0168220201-70"}?[0m
?[0;32mI (101113) MAIN: *****************************************************************************************?[0m
?[0;32mI (101113) MAIN: Stack remaining for task 'aws_iot_task' is 2036 bytes?[0m
?[0;32mI (102133) MAIN: Update accepted?[0m
?[0;32mI (102183) MAIN: Delta - hvacStatus state changed to COOLING?[0m
?[0;32mI (102183) MAIN: setting side LEDs to blue?[0m
?[0;32mI (102313) MAIN: *****************************************************************************************?[0m
?[0;32mI (102313) MAIN: On Device: roomOccupancy true?[0m
?[0;32mI (102313) MAIN: On Device: hvacStatus COOLING?[0m
?[0;32mI (102323) MAIN: On Device: temperature 69.031212?[0m
?[0;32mI (102323) MAIN: On Device: sound 38?[0m
?[0;32mI (102333) MAIN: Update Shadow: {"state":{"reported":{"temperature":69.031212,"sound":38,"roomOccupancy":true,"hvacStatus":"COOLING"}}, "clientToken":"0123779b0168220201-71"}?[0m
?[0;32mI (102363) MAIN: *****************************************************************************************?[0m
?[0;32mI (102363) MAIN: Stack remaining for task 'aws_iot_task' is 2036 bytes?[0m
?[0;32mI (103393) MAIN: Update accepted?[0m
?[0;32mI (103463) MAIN: Delta - hvacStatus state changed to STANDBY?[0m
?[0;32mI (103463) MAIN: clearing side LEDs?[0m
?[0;32mI (103573) MAIN: *****************************************************************************************?[0m
?[0;32mI (103573) MAIN: On Device: roomOccupancy true?[0m
?[0;32mI (103573) MAIN: On Device: hvacStatus STANDBY?[0m
?[0;32mI (103583) MAIN: On Device: temperature 80.096695?[0m
   ・・・