この章の終わりには、ソリューションで次のようなことができるようになります。
この章では、スマートサーモスタットからの入力を分析したり、対応するHVAC システムの動作を特定したりするコードを作成せずに、サーバーレスアプリケーションを構築します。IoT Events を使用して探知器モデルと呼ばれるリソースをデプロイします。このリソースは、IoT Core ルールによって転送された Device Shadow メッセージを処理し、状態が「heating」、「cooling」、または「standby」に変更された場合に評価して、状態変更の更新についてスマートサーモスタットにメッセージを返信します。
以下は作成する探知器モデルです
     
  
ご覧のとおり、HVAC アプリケーションには「heating」、「cooling」、「standby」の 3 つの状態が存在します。アプリケーションは常にいずれかの状態にあり、「standby」状態に初期化されます。スマートサーモスタットから新しいメッセージが到着すると、探知器モデルは条件付きロジックに対して入力を評価し、モデルが新しい状態に移行すべきかどうかを決定します
例えば、「standby」状態であっても、華氏 80 度 (摂氏 26 度) 以上の新しい温度の読み込みが到着した場合、モデルは「cooling」状態への移行を評価します。「cooling」状態に入ると、モデルは IoT Core に新しいメッセージをパブリッシュし、{ "state": { "desired": { "hvacStatus": "COOLING" } } } のようなメッセージを使用して、スマートサーモスタットの Device Shadow の更新を求めます。「データ同期」の章で行った作業に基づき、希望するノードでのこれらの新しいコマンドは受信され、デバイスの状態は、LEDを赤、青、またはオフに更新することで、コマンドを反映するよう更新されます。
IoT Events での探知器モデル作成方法の詳細は、このワークショップの範疇外です。その代わり、以下に探知器モデルを開始、実行するためのステップを示します。このモデルの動作方法を理解できるよう、主要な箇所にはヒントが記載されています。AWS IoT Events の利用を開始するには、 デベロッパーガイド や、 AWS IoT Events初級ハンズオン をご確認ください。
上の画像に表示された探知器モデルを作成するには、次のステップを完了してください。
まず、次のコンテンツを使用して、ローカルパソコンにファイルを作成します。ファイルに model.json などの名前を付けます。このJSONドキュメントに**«CLIENT_ID»**が複数ありますが、この部分はデバイス画面やシリアルモニター出力に表示された Core2 for AWS のシリアル番号に書き換えます。
{
    "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"
}
次に、AWS IoT Events コンソールに新しい探知器モデルをインポートするステップで、このファイルを使用します。
これで IoT Events に探知器モデルがデプロイされました。新しいメッセージがスマートサーモスタットからパブリッシュされると、前の章で作成した IoT Core ルールがメッセージを IoT Events 入力リソースに転送します。その後 IoT Events がメッセージのコピーを、入力からこのような利用中の探知器モデルにプッシュし、状態の変更を評価します。
モデルの主要な特徴について説明します。モデルの各状態 (heating、cooling、standby) はほとんど同じです。standby 状態には、状態を変更すべきかどうか決定するために、すべての状態が使用する数のしきい値を設定するという、追加のアクションが 1 つ存在します。これらは、初めて standby に移行する前に、1 度の初期化状態において設定することもできますが、デモを簡素化するため standby に含まれています。
残りの状態の設定は似通っています。メッセージをスマートサーモスタットの Device Shadow にパブリッシュする OnEnter イベントがあります。これは HVAC の現在の状態を示します。各メッセージが処理された後評価される、条件付きの移行もあります。これは状態を変更すべきかどうかを確認します。例えば、モデルが heating 状態にあり、stopHeating の条件付きの式が true と評価した場合、モデルは standby 状態に移行します。standby 状態には 2 つの移行があり、それぞれ heating または cooling に移行します。このモデルでは、直接 heating から cooling またはその反対に移動するのではなく、常に standby 状態を通過するようシステムで簡素化されています。条件付きの移行ロジックは、2 つの温度の境界を考慮します。1 つは部屋に人がいるとき、もう 1 つは部屋に人がいないときです。
以下は stopHeating とラベル付けされた heating 状態からの移行のサンプルです。2 つのブーリアン式が OR || ロジックで結びつけられています。この式は、「部屋に人がおらず、人がいない期間の部屋の温度がある程度暖かい場合、または部屋に人がおり、人にとって部屋が十分に暖かい場合、暖房を停止する」ことを表しています。
(!$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)
すべてがこのモジュールの手順どおり設定されている場合、LEDが更新されることでスマートサーモスタットの状態の変更を確認でき、エンドツーエンドのソリューションが完成します。
次の章に進む前に、ソリューションが想定どおり設定されているかを検証できます
注: 温度センサーはキットのハウジング内に存在し、コードにはハードコードのオフセットが含まれます。読み込みによって、温度には華氏 10 度 (摂氏 5 度) ほどの差が生じる可能性があります。
ソリューションが予測どおりに動作している場合、 まとめ に移動します。
AWS IoT Kit now features direct access to 
    AWS re:Post
    
        
    
, which is a community-driven, questions-and-answers service. Search re:Post using the 
    AWS IoT Kit
    
        
    
 tag to see if your question has been asked and answered. If not, ask a new question using the AWS IoT Kit tag.