AWS-IoT-Core

【AWS IoT】M5StackとCloudWatchで部屋の温度を監視してみた

はじめに

こんにちは、omkです。
最近、「M5Stack Core2 AWS IoT EduKit」を購入してIoTに挑戦しはじめました。
手始めに部屋の温度を監視してみましたので本記事で紹介いたします。

個人的な話題ですが、私は暖房が苦手で、部屋の温度が高くなってくると段々意識が遠のいていきます。
なので今回はCloudWatchで部屋の温度を監視して一定以上温度が高くなっている場合にSlackに通知することとします。
通知を受けたら人力でエアコンの温度を調整します。

構成

デバイスで測った室温をMQTTでTopicにパブリッシュして、それを受けてLambdaでカスタムメトリクスとしてCloudWatchにプットする構成です。
あとはCloudWatchでアラームを設定してSlackに通知します。

やってみた

AWS IoT Core

IoT Coreでモノを作成します。
AWS IoT > 管理 > モノ > モノを作成 でモノの作成画面に移ります。

AWS IoTと接続する際に利用するデバイス証明書は「新しい証明書を自動生成 (推奨)」を選択することで発行してもらえます。
あとでダウンロードしましょう。

証明書に割り当てるポリシーはざっくり以下のものにしました。
これだと制限無しの状態なので必要に応じた権限の策定をおすすめします。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iot:*",
      "Resource": "*"
    }
  ]
}

これで必要な設定が完了しました。
「モノを作成」を選択して証明書をダウンロードします。

それぞれをダウンロードしたらモノが利用可能な状態です。

M5StackからMQTTで通信

利用するデバイスは「M5Stack Core2 AWS IoT EduKit」です。
これのMPU6886に標準で温度計が付いているのでこれを使って室温を測定します。

こんな感じになりました。

main.cpp

#include <M5Core2.h>
#include <WiFiClient.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>

//Temperature
#define M5STACK_MPU6886

//WiFi Definition
#define WIFI_SSID "{SSID}"
#define WIFI_PASSWORD "{PASSWORD}"

//AWS Definition
#define AWS_ENDPOINT "{AWS IoT Endpoint}"
#define MQTT_PORT 8883
#define PUBLISH_TOPIC DEVICE_NAME "/publish"
#define SUBSCRIBE_TOPIC DEVICE_NAME "/subscribe"

//Device Difinition
#define DEVICE_NAME "m5stack"
#define QOS 0

WiFiClientSecure https_client;
PubSubClient mqtt_client(https_client);

// certs.cpp
extern const char *root_ca;
extern const char *certificate;
extern const char *private_key;

// Local Temper
float temp = 0.0F;
void callback(char *, byte *, unsigned int);

// WiFi接続
void connect_wifi()
{
  M5.Lcd.print("WiFi Connecting to ");
  M5.Lcd.println("");
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED)
  {
    M5.Lcd.print(".");
    delay(500);
  }
  M5.Lcd.println("Connected");
  M5.Lcd.printf("IPv4: %s", WiFi.localIP().toString().c_str());
  M5.Lcd.println("");
}

// AWS IoT 接続
bool connect_awsiot()
{
  https_client.setCACert(root_ca);
  https_client.setCertificate(certificate);
  https_client.setPrivateKey(private_key);
  mqtt_client.setServer(AWS_ENDPOINT, MQTT_PORT);
  mqtt_client.setCallback(callback);

  while (!mqtt_client.connected())
  {
    M5.Lcd.println("MQTT connection...");
    if (mqtt_client.connect(DEVICE_NAME))
    {
      M5.Lcd.println("Connected");

      mqtt_client.subscribe(SUBSCRIBE_TOPIC, QOS);
      M5.Lcd.println("Subscribed.");
      delay(1000); 

      return true;
    }
    else
    {
      M5.Lcd.printf("Failed, rc=%d", mqtt_client.state());
      M5.Lcd.println("");
      return false;
    }
  }
}

void publish()
{
  String temp_s = String(temp, 2);
  int length = temp_s.length();
  char msg[length];
  temp_s.toCharArray(msg, length + 1);
  mqtt_client.publish(PUBLISH_TOPIC, msg);
}

void callback(char *topic, byte *payload, unsigned int length)
{
}

void setup()
{
  M5.begin();
  // WiFi 接続
  connect_wifi();
  if (connect_awsiot())
  {
    // AWS IoT 接続
    delay(500);

    // Set Screen
    M5.Lcd.clear();
    M5.Lcd.setTextSize(2);
    M5.Lcd.setCursor(5, 5);
    M5.Lcd.print("Now temp:");
    M5.Lcd.setTextSize(5);
  }
}

void loop()
{
  // Modify Screen
  M5.IMU.getTempData(&temp);
  M5.Lcd.setCursor(100, 100);
  M5.Lcd.print(temp);

  // Publish Message
  mqtt_client.loop();
  publish();
  delay(60000);
}

MQTT部分は、ほぼほぼこちらの記事からお借りしてほんのちょっとだけ自分なりに書き換えています(大変勉強させていただいております)。

処理の内容としては最初にWiFiとAWS IoTに接続して、1分おきに部屋の温度を測ってトピックに送ります。

ちなみに、AWS IoTでのMQTTのキープアライブについて公式から引用します。
https://docs.aws.amazon.com/ja_jp/general/latest/gr/iot-core.html

デフォルトのキープアライブ間隔は 1,200 秒です。クライアントがキープアライブ間隔として 0 をリクエストすると、デフォルトのキープアライブ間隔が使用されます。クライアントがキープアライブ間隔として 1,200 秒を超える値をリクエストした場合も、デフォルトのキープアライブ間隔が使用されます。クライアントが 1 秒以上 30 秒未満のキープアライブ間隔をリクエストすると、サーバーはクライアントが 30 秒のキープアライブ間隔をリクエストしたものとして処理します。

PubSubClientのデフォルトはキープアライブ15秒となっていますので、公式の記述によると30秒間のリクエストとして扱われます。
よって1分おきにパブリッシュしようとしても接続が切れていてパブリッシュ出来ないという事象が発生します。

これに対してPubSubClientでの定義を更新してキープアライブの持続時間を変更します。

PubSubClient.h

// MQTT_KEEPALIVE : keepAlive interval in Seconds. Override with setKeepAlive()
#ifndef MQTT_KEEPALIVE
#define MQTT_KEEPALIVE 1200
#endif

// MQTT_SOCKET_TIMEOUT: socket timeout interval in Seconds. Override with setSocketTimeout()
#ifndef MQTT_SOCKET_TIMEOUT
#define MQTT_SOCKET_TIMEOUT 1200
#endif

これでデバイスの設定が完了したのでビルドしてM5Stackに流し込みます。

M5Stackの電源を入れます。

モノのアクティビティからデバイスの接続状況を確認します。

モノが接続されました。

次にAWSコンソールでMQTTテストクライアントを開いて「m5stack/publish」のトピックをサブスクライブし、本トピックに室温が送られてくることを確認します。

メッセージが送られて来ました。
25℃です。

AWS IoT ルールとアクションの設定

メッセージを受け取るところまで出来たのでこのメッセージに記載された室温をCloudWatchカスタムメトリクスとして登録します。

まずは、クエリを投げて対象のメッセージを扱えるようにします。

ACTのルールで新規ルールを作成します。

「m5stack/publish」に流れてくるメッセージは全部室温なので以下のクエリを設定しました。

SELECT * FROM 'm5stack/publish'

次にアクションを設定します。
CloudWatchにカスタムメトリクスとして登録するためにAWS Lambdaを利用します。
「メッセージデータを渡すLambda関数を呼び出す」を選択して、新しくLamdbaを作成して割り当てます。
今回はPythonを利用します。

import json
import boto3

def lambda_handler(event, context):
    # TODO implement
    client = boto3.client('cloudwatch')
    client.put_metric_data(
        Namespace='m5stack',
        MetricData=[
            {
                'MetricName': 'temperature',
                'Dimensions': [
                    {
                        'Name': 'ThingName',
                        'Value': 'm5stack'
                    },
                ],
                'Value': event,
            },
        ]
    )

eventの中身が丸々floatで室温が渡されてくる設計(?)なのでそのままメトリクスとして割り当てます。
これがメッセージが届くたびに呼び出されるので1分毎に呼び出されるイメージです。
これのLambdaをアクションに設定してルールの作成が完了です。
LambdaにはCloudWatchの権限を付けておきます。

またM5Stackからメッセージを流して、Lambdaが起動されたこと、CloudWatchにメトリクスが上がっていることを確認します。

ちゃんとメトリクスが登録されています。

あとはちゃっちゃとアラームを設定してSNSとChatbotを連携したらアラームの通知がSlackに来ることを確認します。

アラーム状態になりました。

Slackに通知が来ました。

これで室温をCloudWatchで監視してアラームを飛ばすことを実現しました。

おわりに

初めてのIoTでしたが、色々な情報が管理できるようになると便利ですね。
もっと使い方を考えていこうと思います。

返信を残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA