GWの宿題シリーズ最終回。
普通のM5Stack Core2をAWS IoTにデバイスとして登録してMQTTでやりとりしてみました。
普通のというのは、実はAWSとM5Stackがコラボ(?)しているM5Stack Core2 ESP32 IoT Development Kit for AWSというモノがあるのだけれども、わたしが見たときには売り切れで入手できなかったのです。
というわけで普通のM5Stack Core2でやってみようということになったのでした。
進めるにあたり、以下のエントリが参考になります。
- M5Stackシリーズの従来機でM5Stack Core2 for AWSを実現か?! | DevelopersIO
- M5Stack5 Core2 で M5Stack Basic と同じ AWS IoT コードが動かなかったが修正できたメモ – 1ft-seabass.jp.MEMO
エントリを参考に、段取りは概ねこんな感じ。
- AWS IoT Coreをプロビジョニング
- モノにデバイスを登録
- Policy作成
- 証明書作成・取得
- PlatformIOでプログラムを書く
- 手元のWiFiや、↑で取得した証明書を書き込む
- Run!
M5Stack Core2側のコードはこんな感じ(※注:C/C++初心者)。
#include <WiFiClient.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <WiFi.h>
#include <M5Core2.h>
const String SSID = "CHANGEME";
const String WIFI_PASSWORD = "CHANGEME";
const String AWS_IOT_ENDPOINT = "CHANGEME-ats.iot.ap-northeast-1.amazonaws.com";
const int AWS_IOT_PORT = 8883;
const String AWS_IOT_DEVICE_NAME = "CHANGEME";
const String pubTopic = "CHANGEME";
const String subTopic = "CHANGEME";
const int subQoS = 0;
// AmazonRootCA1.cer
static const char AWS_IOT_ROOT_CA[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
...CHANGEME...
-----END CERTIFICATE-----
)EOF";
// XXXXXXXXXX-certificate.pem.crt
static const char AWS_IOT_DEVICE_CERT[] PROGMEM = R"KEY(
-----BEGIN CERTIFICATE-----
...CHANGEME...
-----END CERTIFICATE-----
)KEY";
// XXXXXXXXXX-private.pem.key
static const char AWS_IOT_DEVICE_PRIVATE_KEY[] PROGMEM = R"KEY(
-----BEGIN RSA PRIVATE KEY-----
...CHANGEME...
-----END RSA PRIVATE KEY-----
)KEY";
WiFiClientSecure httpsClient;
PubSubClient mqttClient(httpsClient);
void connect()
{
while (WiFi.status() != WL_CONNECTED)
{
WiFi.begin(SSID.c_str(), WIFI_PASSWORD.c_str());
Serial.println("Waiting for WiFi... ");
while (WiFi.status() != WL_CONNECTED)
{
delay(1000);
}
}
Serial.println("WiFi connected");
Serial.printf("IP address: %s\n", WiFi.localIP().toString().c_str());
Serial.println("[AWS IoT]");
while (!mqttClient.connected())
{
if (!mqttClient.connect(AWS_IOT_DEVICE_NAME.c_str()))
{
Serial.print("Connect Failed. Error state=");
Serial.print(mqttClient.state());
Serial.println("");
delay(10000);
}
}
Serial.println("Connected.");
if (mqttClient.connected())
{
if (mqttClient.subscribe(subTopic.c_str(), subQoS))
{
Serial.printf("Subscribed.\ntopic=%s\n", subTopic.c_str());
}
else
{
Serial.printf("Subscribe Failed.\nError state=%d\n", mqttClient.state());
}
}
}
void mqttCallback(char *topic, byte *payload, unsigned int length)
{
DynamicJsonDocument doc(4096);
deserializeJson(doc, payload);
const char *message = doc["message"];
Serial.println("-----");
Serial.println(message);
Serial.println("-----");
}
void loop()
{
if (WiFi.status() != WL_CONNECTED || !mqttClient.connected())
{
connect();
}
mqttClient.loop();
delay(10000);
}
void setup()
{
M5.begin(true, true, false, true);
Serial.begin(9600);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.setTextSize(2);
M5.Lcd.clear(BLACK);
M5.Lcd.println("Connect to AWS IoT Core");
httpsClient.setCACert(AWS_IOT_ROOT_CA);
httpsClient.setCertificate(AWS_IOT_DEVICE_CERT);
httpsClient.setPrivateKey(AWS_IOT_DEVICE_PRIVATE_KEY);
mqttClient.setServer(AWS_IOT_ENDPOINT.c_str(), AWS_IOT_PORT);
mqttClient.setCallback(mqttCallback);
connect();
}
困った話1:動作確認方法
AWS Management ConsoleにMQTTのテストクライアントがあるので便利に使えました。
困った話2:接続できないときのデバッグ
とっても難しい。 MQTTのクライアントから得られる情報が、、、ほぼない(わたしが知らないだけかも)。
というわけでCloudWatchを見ましょう。 なんとなく意味はわかりますね(?)
Connect.Success
Connect.AuthError
Subscribe.Success
Subscribe.AuthError
困った話3:AWS IoTに接続できない
mqttClient.connect()
がfalse
mqttClient.status()
が-1
CloudWatchを見ると Connect.AuthError
になっているようでした。
→デバイスに対するPolicyを以下に変更して改善(123456789012
はアカウントID)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iot:*",
"Resource": [
"arn:aws:iot:ap-northeast-1:123456789012:client/${iot:Connection.Thing.ThingName}"
]
}
]
}
困った話4:トピックをサブスクライブできない
mqttClient.subscribe()
はtrue
- でも実際はsubscribeできていない(MQTTが切断されてるっぽくて再接続しちゃう)
CloudWatchを見ると Connect.Success
で Subscribe.AuthError
になってました。
→デバイスに対するPolicyにトピック関連を追加して改善(123456789012
はアカウントID)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iot:*",
"Resource": [
"arn:aws:iot:ap-northeast-1:123456789012:client/${iot:Connection.Thing.ThingName}"
]
},
{
"Effect": "Allow",
"Action": "iot:*",
"Resource": [
"arn:aws:iot:ap-northeast-1:123456789012:topic/*",
"arn:aws:iot:ap-northeast-1:123456789012:topicfilter/*"
]
}
]
}
まとめ
- 普通のM5Stack Core2 IoT開発キットでもAWS IoT Coreに接続してMQTTでメッセージのやりとりは簡単!
- でもおそらくM5Stack Core2 ESP32 IoT Development Kit for AWSのほうが簡単!
- M5Stack Core2 ESP32 IoT Development Kit for AWSならAWS謹製入門ワークショップ AWS IoT EduKit :: AWS IoT EduKitができる
なんと今日見たら在庫が復活してました
→M5Stack Core2 for AWS - ESP32 IoT開発キット - SWITCH-SCIENCE
お好きなほうをどうぞ!!!