M5StickCからAWS IoT Coreへの温湿度情報のPublish(送信)
Contents
M5StickCとAWS IoT Core
Raspberry Pi から Python でAWS(Amazon Web Services)の IoT Core にデータを Publish(送信)する記事は以前に書いた。
今回は M5Stack社の M5StickC に接続した温湿度センサー(BME280)の情報をAWS IoT Core にPublish したので記事として残しておく。
尚、AWS IoT Core と Edge端末とは送信(Publish)の他に受信(Subscribe)する事もできるが今回は送信のみのプログラムとしている。
受信(Subscribe)については別記事で書くつもりだ。
またプログラムは Arduino IDE で C++ で作成している。
全体構成図
全体構成図は以下の通り。
- M5StickC と 温湿度気圧センサー(BME280)とはGrove互換端子で接続する
- M5StickC は Wi-Fi 接続で でMQTTプロトコルでAWS IoT Core と接続する
- AWS IoT Core とは公開鍵、秘密鍵方式で接続する
- 温度、湿度、気圧、電圧等のデータは JSON 形式(暗号化されている)で約5分間隔で送信する
必要な機器
M5StickC
M5StickC は M5Stack社の製品でチップは ESP32-PICO を搭載している。
- 4MBフラッシュ+520K RAMメモリ
- TFT LCD(TFT液晶ディスプレイ)
- Wi-Fi、Bluetooth
- リチウムイオンポリマーバッテリー内蔵(80mAh)
- 電源ボタン+ボタン×2個
- USB Type-Cコネクター
- HY2.0-4P(Grove互換コネクター)
- LED×1個
- 赤外線送信
- 拡張コネクター
- 3軸加速度センサー+3軸ジャイロセンサー(6軸)
- マイクロフォン内蔵
などの特徴があるが、詳細なスペックは以前の記事を参照して欲しい。
HY2.0-4P(Grove互換コネクター)に温湿度センサー(BME280)を接続した。
M5StickC は下記の M5StickC Plus に置き換わっている。
スイッチサイエンスでは M5StickC(本体のみ)がまだ販売されていた。
温湿度センサー
温湿度及び気圧を測定できる BME280 モジュールを使用した。
M5StickC と BME280 との配線は前述の全体構成図を参照して欲しい。
BME280 モジュールは電圧レギュレータを積んでいるタイプなので M5StickC からの 5V 出力も受け取ることができる。
購入したモジュールはピンとモジュールが別々になっているのではんだ付けをした。
はんだ付けについては以前の記事を参照して欲しい。
Grove汎用ケーブル
M5StickC と BME280モジュールとの接続に使用した。
AWS側の設定
事前にAWS(Amazon Web Services)側で IoT Core 等の設定を行う。
AWSのコンソールにログインをして IoT Core サービスを検索して選択する。
モノの作成
IoT Core のメニューから管理ー>モノー>「作成」ボタンをクリックする。
AWS IoT モノを作成するから「単一のモノを作成する」ボタンをクリックする。
- 名前:M5Stick-C-test
タイプは未設定でも良いのだが M5StickC との接続は初めてなので分類の為にタイプを作成しておくことにした(任意)。
「タイプの作成」ボタンをクリックする。
- 名前:M5Stick-C
- 説明:M5Stick-C
- タグ:未設定
を入力して下にスクロールする。
「モノのタイプを作成」ボタンをクリックする。
タイプが作成されてモノのタイプで選択されているので下にスクロールする。
グループは特に作成せずに(任意)下にスクロールして「次へ」ボタンをクリックする。
証明書
モノが作成されたので続いて証明書を作成する。
複数の証明書の作成方法があるが推奨の1-Click証明書作成の「証明書を作成」ボタンをクリックする。
- このモノの証明書(xxxx-certificate.pem.crt)
- パブリックキー(xxxx-public.pem.key)
- プライベートキー(xxxx-private.pem.key)
が作成されるのでダウンロードリンクから3つのファイルをダウンロードして適当なフォルダーに保存する(xxxxの部分は毎回こ異なる)。
このモノの証明書とプライベートキーの中身は後程 config.h に記述する為に使用する。
パブリックキーは IoT Core 側に必要なキーなのでプログラム中では使用しないが、一応ダウンロードしておく。
ファイルの保存後は AWS IoT のルートCAダウンロードのリンクをクリックする。
新しいタブでページが開くので “Amazon Root CA 1”のリンクをクリックする。
表示される証明書をテキストファイルに貼り付けて任意の名前をつけて(AmazonRootCAxxxx.pem)ローカルディスクに保存する。
このキーの中身は後程 config.h に記述する為に使用する。
先程の画面に戻って「有効化」ボタンをクリックして証明書を有効化する。
この後、ポリシーを作成してアタッチするのだが「ポリシーをアタッチ」ボタンをクリックするとまだアタッチできるポリシーが無いので、先にポリシーを作成する為に「完了」ボタンをクリックする。
ポリシーの作成
左のメニューから安全性ー>ポリシーから「作成」ボタンをクリックする。
- 名前:M5Stick-C-Test-Policy
を入力してアクション欄に iot と入力するとサジェスト機能で選択可能な一覧が表示される。
まずは接続可能な端末を許可する為のポリシー “iot:Connect” を選択する。
選択するとリソースARNが自動的に設定されるので replaceWithAClientId の部分を SKSTC* に打ち替えて許可にチェックを入れる。
“*” はワイルドカードなので SKSTC で始まるClient IDのみ、接続を許可する設定になる。
続けて Publish(端末側からの送信、IoT Coreにとっては受信)と Subscribe(受信)の設定を行う為に「ステートメントを追加」ボタンをクリックする。
今回のテストプログラムでは M5StickC での受信は行わないがポリシーとしては設定をしておく。
先程と同様の手順で、
- iot:Connect:client/SKSTC*
- iot:Publish:topic/dt/TempAndHumi/*
- iot:Subscribe:topicfilter/cmd/device/*
を設定して、それぞれ許可にチェックをいれて下にスクロールして「作成」ボタンをクリックする。
Publish 及び Subscribe は topic でフィルタリングしている。
topic は MQTT でメッセージを仕分けるためのキーで “/”(スラッシュ)で階層構造を設定する事ができる。
任意の階層構造に出来るのだが、AWSのデザインペーパーのMQTT Telemetry Topic Syntaxにて推奨構成が載っていたので参照して欲しい。
下にスクロールして「作成」ボタンをクリックする。
ポリシーが正常に作成されたので “M5Stick-C-Test-Policy” をクリックしてみる。
作成されたポリシーがテキストで表示される。
XXXXXXXXXXXX部はアカウントID。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iot:Connect",
"Resource": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:client/SKSTC*"
},
{
"Effect": "Allow",
"Action": "iot:Publish",
"Resource": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:topic/dt/TempAndHumi/*"
},
{
"Effect": "Allow",
"Action": "iot:Subscribe",
"Resource": "arn:aws:iot:ap-northeast-1:XXXXXXXXXXXX:topicfilter/cmd/device/*"
}
]
}
アタッチ
証明書に先ほど作成したポリシーをアタッチする。
メニューから安全性ー>証明書を選択して先程作成した証明書をクリックする。
アクションー>ポリシーのアタッチを選択する。
証明書にポリシーをアタッチする。
先程作成したポリシー(M5Stick-C-Test-Policy)をチェックして「アタッチ」ボタンをクリックする。
エンドポイント
プログラム中で使用するエンドポイントを控えておく。
メニューから管理ー>モノで該当のモノを選択後に相互作用で表示されるRest API エンドポイントを後ほど config.h に記述するので控えておく。
今は左のメニューで”設定”を選択するとエンドポイントが表示される。
以上で AWS 側の設定は終了。
料金について
AWS IoT Core は有料のサービスだ。
現時点(2021年6月)の東京リージョンでのおそよの料金だが、
- 1台の端末
- 1年間接続をしたまま
- MQTT または HTTP でのメッセージ
- 1日1,000件のメッセージ、1年間で365,000件のメッセージ
- 1メッセージは128 KB以下(追加料金無し)
の場合は1台辺り、
- 接続料金:0.0504576ドル/年
- メッセージ料金:0.438ドル/年
で約 0.488ドル/年の計算になる。
尚、LoRaWAN での接続は料金体系が異なる。
またデバイスシャドウやルールエンジン(特定の条件の時に別のサービスのアクションを実行)などは別料金になる。
無料枠もあるので詳しい最新の料金体系は AWS の公式ページを参照して欲しい。
Arduino IDEの設定
プログラムはこちらのサイトを参考にさせて貰った。
Arduino IDE にて事前に必要なライブラリーをインストールする。
PubSubClientのインストール
Arduino IDE を起動してスケッチー>ライブラリをインクルードー>ライブラリを管理を選択する。
検索欄で “PubSubClient” で検索して「インストール」ボタンでインストールする。
バージョン 2.8.0 をインストールした。
ArduinoJsonのインストール
同様の手順で ArduinoJson ライブラリーをインストールする。
バージョン 6.18.0 をインストールした。
BME280のインストール
同様の手順で Adafruit BME280 Library をインストールする。
バージョン 2.1.4 をインストールした。
プログラム
プログラムは、
- m5stickc-bme280-awsiotcore.ino
- config.h
の2つのファイルから構成されていて同じフォルダーに保存している。
m5stickc-bme280-awsiotcore.ino
/**
* Created on 2021-06-02
*
* M5Stick-Cに繋いだBME280で温湿度気圧を測定
* 検出情報を指定した秒数間隔でAWS IoT CoreにPublishする
*
* @author: Souichirou Kikuchi
*/
#include <M5StickC.h>
#include <WiFiClient.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <esp_sleep.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <ArduinoJson.h>
#include <stdio.h>
#include "config.h"
#define S_PERIOD 300 // Deep Sleepする秒数
Adafruit_BME280 bme;
void setupM5StickC() {
M5.begin();
delay(10 * 1000); // 10秒待機
setCpuFrequencyMhz(80); // CPU周波数80以上にしないと無線は使用できない
M5.Axp.begin(false,false,false,false,true); // 省電力の為、DCDC3をオフ
M5.Axp.ScreenBreath(10); // 画面の輝度を下げる
M5.Lcd.setRotation(1); // LCDの方向を変える
M5.Lcd.setTextSize(2); // フォントサイズを2にする
M5.Lcd.setTextColor(WHITE, BLACK); // 文字を白、背景を黒
M5.Lcd.setCursor(10, 10); // カーソル位置
}
int setupWiFi() { // Wi-Fi接続
int cnt = 0; // 接続試行回数
const int MAX_RETRY = 30; // 最大接続待ち秒数
WiFi.disconnect(true);
delay(1000);
WiFi.begin(ssid, password);
Serial.println("Connecting...");
while ((WiFi.status() != WL_CONNECTED) and (cnt < MAX_RETRY)){ // 最大1秒✕MAX_RETRY回待機する
delay(1000);
cnt++;
}
if (cnt >= MAX_RETRY) { // MAX_RETRY秒間接続できなかった
Serial.println("Connect NG...");
return 0;
}
Serial.println("Connected");
Serial.println(WiFi.localIP()); // M5Stick-CのIP Address
return 1;
}
WiFiClientSecure httpsClient;
PubSubClient mqttClient(httpsClient);
void setupClient() { // AWS IoT Coreとの接続認証
const int port = 8883;
httpsClient.setCACert(rootCA);
httpsClient.setCertificate(deviceCert);
httpsClient.setPrivateKey(privateKey);
mqttClient.setServer(endpoint, port);
}
int connectToAWSIoT() { // AWS IoT Coreとの接続
int cnt = 0; // 接続試行回数
const int MAX_RETRY = 10; // 最大リトライ回数
while (!mqttClient.connected() and (cnt < MAX_RETRY)) { // MAX_RETRY回数接続をリトライする
if (!mqttClient.connect(clientId)) {
cnt++;
delay(1000);
}
}
if (cnt >= MAX_RETRY){ // 接続回数オーバー
return 0;
} else {
return 1;
}
}
void display(float temp, float humi, float press, float vbat) {
// 温度、湿度、気圧、バッテリーの電圧をディスプレイに表示(検証時のみ表示する)
M5.Lcd.fillScreen(BLACK); // 一旦黒くクリア
M5.Lcd.setCursor(10, 10); // カーソル位置
M5.Lcd.printf("temp: %4.1f'C\r\n", temp);
M5.Lcd.printf("humi:%4.1f%%\r\n", humi);
M5.Lcd.printf("press:%4.0fhPa\r\n", press);
M5.Lcd.printf("vbat: %4.2fV\r\n", vbat);
}
void publish(float temp_p, float humi_p, float press_p, float vbat_p) { // JSON形式を組み立ててPublishする
const char* pubTopic = "dt/TempAndHumi/1";
const int capacity = JSON_OBJECT_SIZE(8);
configTzTime("JST-9", "ntp.nict.jp", "time.google.com", "ntp.jst.mfeed.ad.jp"); // NTP Serverと同期する
struct tm timeInfo;
getLocalTime(&timeInfo); // 現在時刻を取得
char date_time[20];
sprintf(date_time, "%04d-%02d-%02d %02d:%02d:%02d",
timeInfo.tm_year + 1900,
timeInfo.tm_mon + 1,
timeInfo.tm_mday,
timeInfo.tm_hour,
timeInfo.tm_min,
timeInfo.tm_sec
);
StaticJsonDocument<capacity> env_inf; // JSONファイルを組み立てる
env_inf["clientId"] = clientId; // 端末ID
env_inf["date_time"] = date_time; // 現在時刻
env_inf["temperature"] = temp_p; // 温度
env_inf["Humidity"] = humi_p; // 湿度
env_inf["pressure"] = press_p; // 気圧
env_inf["Voltage"] = vbat_p; // 電圧
char jsonBuffer[512];
serializeJson(env_inf, jsonBuffer);
mqttClient.publish(pubTopic, jsonBuffer); // AWS IoT CoreにPublish
}
void setup() { // Deep Sleepからの復帰はsetupが実行される
float temp; // 温度
float humi; // 湿度
float press; // 気圧
float vbat; // 電圧
int cnt = 0; // 試行回数
const int MAX_RETRY = 10; // 最大試行回数
// sprintf("setup %s","1");
setupM5StickC(); // M5Stick-C初期設定
if (setupWiFi()) { // Wi-Fi接続
Serial.println("Wi-Fi Connected!");
setupClient(); // AWS IoT Coreとの接続認証
Wire.begin(); // I2Cの初期化
while ((!bme.begin(0x76)) and (cnt < MAX_RETRY)) { // BME280の初期化
M5.Lcd.println("BME280 init failed"); // 初期化失敗
cnt++;
delay(500);
}
if (cnt < MAX_RETRY) { // BME280の初期化成功
Serial.println("BME280 initialized");
temp = bme.readTemperature(); // 温度の取得
humi = bme.readHumidity(); // 湿度の取得
press = bme.readPressure()/100; // 気圧の取得(pa→hPaに変換」)
vbat = (M5.Axp.GetVbatData() * 1.1 / 1000); // バッテリーの電圧
if (connectToAWSIoT()) { // AWS IoT Coreに接続成功なら
mqttClient.loop();
display(temp, humi, press, vbat); // M5Stick-CのLCDに表示
publish(temp, humi, press, vbat); // AWS IoT CoreにPublish
}
}
}
delay(10);
WiFi.disconnect(true); // WiFi切断
esp_deep_sleep(1000000LL * S_PERIOD); // S_PERIOD秒Deep Sleepする
}
void loop() {
}
config.h
端末毎に異なる設定情報やセキュアな情報を config.h に保存している。
const char* clientId = "SKSTC0001";
const char* ssid = "Your SSID";
const char* password = "Your Wi-Fi Password";
const char* endpoint = "XXXXXXXXX-ats.iot.ap-northeast-1.amazonaws.com";
const char* rootCA = R"(
-----BEGIN CERTIFICATE-----
MIIDQTCCAimg ・・・
・
・
・
-----END CERTIFICATE-----
)";
const char* deviceCert = R"(
-----BEGIN CERTIFICATE-----
MIIDWTCCAkGgA ・・・
・
・
・
-----END CERTIFICATE-----
)";
const char* privateKey = R"(
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQ ・・・
・
・
・
-----END RSA PRIVATE KEY-----
)";
clientId | 端末を識別するID SKSTC0001 を設定していて後半の 0001 の部分は連番で端末毎に変更可能だが先頭の SKSTC の部分はポリシーで設定しているので変更は出来ない。 |
ssid | Wi-FiのSSIDを設定する |
password | Wi-Fiのパスワードを設定する |
endpoint | 先程控えておいたエンドポイントを設定する |
rootCA | 先程ダウンロードした AmazonRootCAxxxx.pem の中身を貼り付ける |
deviceCert | 先程ダウンロードしたこのモノの証明書(xxxx-certificate.pem.crt)の中身を貼り付ける。 |
privateKey | 先程ダウンロードしたプライベートキー(xxxx-private.pem.key)の中身を貼り付ける。 |
補足説明
簡単にプログラムの補足説明をしておく。
ライブラリーのインクルード
10~19行目で必要なライブラリーをインクルードしている。
S_PERIOD
S_PERIOD で Deep Sleep(待機)する秒数を指定する。
300秒(5分)を指定する事でおよそ5分間隔で温湿度、気圧を測定して AWS IoT Core に Publish(送信)する。
ESP32 の Deep Sleep モードは消費電力を 10µA~150µA まで抑えることが出来るので電池モードで動作させる際には有効だ。
setupM5StickC()
CPUの周波数やスクリーンの輝度、方向、フォントサイズなど M5StickC の初期設定を行っている。
setupWiFi()
config.h の接続情報を元に Wi-Fi に接続している。
接続されるまで 1秒間 × 30回待機して、時間内に接続できなかった時は後続の処理はスキップする。
setupClient()
AWS IoT Core との接続認証情報の設定を行う。
connectToAWSIoT()
AWS IoT Core と接続を行う。
最大リトライ回数分繰り返す。
display()
M5stickC の LCD(ディスプレイ)へ温度、湿度、気圧、電圧を表示する。
もし電池稼働で消費電力を抑えたい時はこの関数は呼ばなくても良い。
publish()
JSON 形式で送信情報を組み立てて AWS IoT Core に Publish(送信)する。
送信前に NTP Server に接続して現在時刻を取得している。
送信している項目は以下の通り。
- 端末ID
- 現在時刻
- 温度
- 湿度
- 気圧
- 電圧
setup()
Deep Sleep 明けにまずこの関数が呼ばれる。
前述の関数達を呼び出して Wi-Fi接続、AWS IoT Coreとの接続認証を行った後、BME280 より温湿度、気圧を取得する。
電圧を取得後、ディスプレイへの表示、AWS IoT Core への Publish(送信)を行った後、S_PERIOD で指定した秒数分だけ Deep Sleep する。
Deep Sleep 前に WiFi.disconnect(true) で Wi-Fi を切断をしているのは「知的好奇心 for IoT」さんの記事を参考にさせて貰った。
loop()
setup中で Deep Sleep しているのでこの関数は呼ばれない。
プログラムのコンパイルと書き込み
パソコンとの接続
パソコンと M5stickC を USB-TypeC ケーブルで接続する。
ツールの設定
Arduino IDE を起動してツールー>ボードー>ESP32 Arduinoー>M5Stick-C を選択する。
尚、Arduino IDE のインストール&初期設定については以前の記事を参照して欲しい。
もし一覧に M5Stick-C が表示されない時はツールー>ボードマネジャーから esp32 をインストールまたは最新版にバージョンアップする。
2021年6月20日時点の最新バージョンは 1.0.6。
ツールでの設定項目は以下の通り。
ボード | M5Stick-C |
Upload Speed | 150000 書き込みエラーが発生するようであれば速度を落としてみる |
Partition Schema | 初期値を選択した。 大きなサイズのプログラムを書き込む時でサイズエラーになってしまう時は NO OTA を選択する。 OTAについては以前の記事を参照して欲しい。 |
Core Debug Level | なし プログラムが上手く動作せずデバッグ情報を埋め込みたい時にレベルに別に “エラー” から “verbose” まで指定する。 |
シリアルポート | M5stickCが接続されているシリアルポート(COMx)を選択する。 Windows環境での COMポートの確認方法は以前の記事を参照して欲しい。 |
コンパイルと書き込み
スケッチー>マイコンボードに書き込むを選択(または Ctrl+u)するとプログラムをコンパイル後、マイコンボードに書き込まれる。
※コンパイルのみの時は Ctrl+r
プログラムが正常に書き込まれると “ボードへの書き込みが完了しました。” のメッセージが表示される。
実行結果の確認
ボードへの書き込み後、M5stickC の電源をオフにしない限りプログラムは自動的に動き始める。
※電源オフはディスプレイを正面時の左側のボタンを長押し。
AWS IoT Core にて正常にメッセージが受信できているかを確認する。
AWSコンソールにログインをして IoT core のサービスに移動後、テストー>MQTTテストクライアントのページで “トピックのフィルター” 欄に “#” を入力して「サブスクライブ」ボタンをクリックする。
※ “#”(シャープ)は topic ではワイルドカードに相当する。
“dt/TempAndHumi/#” の様な指定の仕方も可能だ。
サブスクリプション欄に受信したメッセージ(JSON形式)が表示される。
尚、M5stickCの電源をオンのままにしておくと AWS IoT Core へメッセージを送信し続けて料金が加算されてしまう。
テスト終了後や何らかの理由でこの端末からの AWS IoT Core へのアクセスを停止したい時は、安全性ー>証明書から該当の証明書右にある “・・・”(3点)をクリックして “無効化” を選択するとステータスが無効になる。
終わりに
以上で M5stickC から AWS IoT Core への温湿度、気圧情報の送信のプログラムの記事を終了とする。
この記事が何処かで誰かの役に立つことを願っている。
尚、当記事中の商品へのリンクはAmazonアソシエイトへのリンクが含まれています。Amazonのアソシエイトとして、当メディアは適格販売により収入を得ていますのでご了承ください。
最近のコメント