「AmbientでIoTをはじめよう」の第3回は最近スイッチサイエンスでも取り扱いを始めたM5Stackを使い、 センサデータをクラウドに送信して記録する事例を紹介します。

M5StackはArduinoとMicroPythonとEspressif社のESP-IDFという開発環境が使えます。 ここではArduinoで制御する例を紹介します。 MicroPythonで制御する例は「M5Stackでセンサデータを測定し、クラウドに送る (MicroPython編)」をご覧ください。

M5Stack

M5StackはEspressif社のマイコンESP32が搭載されたコンパクトなIoT端末です。 ESP32と電池、320 x 240 TFTカラーディスプレイ、microSDカードスロット、スピーカーなどが搭載されたM5Stack Basicがベースになる製品です。 ESP32が搭載されているのでWi-FiとBluetoothで通信でき、SPI、I2Cでセンサなどを制御できます。 5.4cm x 5.4cmのコンパクトなケースに入っていて、拡張モジュールを積み重ねることで機能を追加できます。

M5Stack Basicに加速度、ジャイロ、磁気を計測可能な9軸センサ、MPU9250を加えたM5Stack Gray(9軸IMU搭載)という製品や、 GPSモジュールやユニバーサル基板モジュールといった拡張モジュールがあります。

詳細は次のサイトをご覧ください。

M5Stackを使うためのArduinoの環境設定

公式サイトにWindows/Mac/Linuxでのインストール方法が解説されています。 ここでは簡単にMacでのインストールの流れを紹介します。

  • USBドライバのインストール

    M5StackとUSBで通信するために、USBドライバ「SiLabs CP2104 Driver」をダウンロードしてインストールします。

  • ESP32 Arduino Coreのインストール

    公式サイトの説明に従ってESP32 Arduino Coreをインストールします。

  • M5Stackライブラリのダウンロード

    Arduino IDEのライブラリマネージャーを使うか、Gitを使う方法があります。 どちらかの方法でM5Stackライブラリをダウンロードします。

以上でArduinoの環境設定は終わりです。

Arduino環境とM5Stackの動作確認

設定したArduino環境とM5Stackの動作確認をします。 Arduino IDEを立ち上げて、

  • M5StackをUSBケーブルでPCに接続
  • Arduino IDE メニューの「ツール」→「ボード」で「M5Stack-Core-ESP32」を選択

  • 「ツール」→「シリアルポート」で「/dev/cu.SLAB_USBtoUART」を選択
  • 「ファイル」→「スケッチ例」→「M5Stack」→「Basics」→「Hello」を選択
  • ビルドしてマイコンボードに書き込む

プログラムがダウンロードされ、M5Stackの画面が消え、「hello world」と出力されれば 環境設定はokです。

温湿度・気圧センサBME280を使う

M5Stackのケースの底に近い部分にはBUS PORTとI/O PORTと呼ばれるスロットがあります。 BUS PORT、I/O PORTとも一方がピン、反対側がソケットで、向かい合うピンとソケットは同じ信号がでています。 ジャンパワイヤを使ってセンサなどをつなぐことができます。各ピン/ソケットの意味はシールに書かれています。

その中にI2C通信で使うSDA、SCLと3.3V、GNDがあるので、BME280モジュールをそこにつなぎます。 SDA、SCLは対向する側ではそれぞれ21、22と書かれていますが、同じ信号です。 この他にスイッチサイエンスのBME280モジュールにはSDOとCSBというピンがあります。 BME280をI2Cインタフェースで使う時はCSBを3.3Vに接続します。 SDOはI2Cアドレスを決めるのに使い、GNDに接続することでI2Cアドレスが0x76になります。

M5StackBME280モジュール
GNDSDO
SCL(22)SCK
SDA(21)SDI
3V3CSB
GNDGND
3V3Vcore
Vio

必要な部品をまとめました。M5StackとBME280モジュールをつなぐケーブルは 「M5Stack Basic」に含まれています。

部品個数
M5Stack Basic1個
BME280搭載 温湿度・気圧センサモジュール1個
ピンヘッダL型1×401個

プログラム

Ambientライブラリのインストール

AmbientはIoTデータを受信し、蓄積して可視化するクラウドサービスです。 Ambientを使うには最初にユーザー登録をして、チャネルを生成します。 Ambientの準備は第1回「温度、湿度、気圧を測定し、記録する」の「Ambient」側の準備をご覧ください。

Ambientにデータを送信するライブラリはESP8266/ESP32用のものを使います。

  • GithubのAmbientライブラリページをアクセスする
  • ページ右上の「Clone or download」の「Download ZIP」をクリックし、ZIP型式のライブラリをダウンロードする

  • Arduino IDEを立ち上げ、「スケッチ」→「ライブラリをインクルード」→「.ZIP形式のライブラリをインストール」を選択し、ダウンロードしたファイルを選択する

「スケッチ」→「ライブラリをインクルード」を選択し「Ambient ESP8266 lib」が表示されればライブラリは正しくインストールされています。

BME280をアクセスする

BME280をアクセスし、温度、湿度、気圧を測定してM5StackのLCDに出力してみます。 プログラムはライブラリと一緒にスケッチ例としてインストールされています。 Arduino IDEを立ち上げ、「ファイル」→「スケッチ例」→「Ambient ESP8266 lib」→「M5Stack」→「BME280_test」を選択するとロードできます。

/*
* M5StackとBME280をI2C接続し、温度、湿度、気圧を測定しプリントアプトする
*/
#include <M5Stack.h>
#include <Wire.h>
#include "BME280.h"
BME280 bme280;
void setup(){
M5.begin();
Wire.begin(); // I2Cの初期化
Serial.begin(74880);
pinMode(21, INPUT_PULLUP); //デファルトのSDAピン21 のプルアップの指定
pinMode(22, INPUT_PULLUP); //デファルトのSCLピン22 のプルアップの指定
bme280.begin(); // BME280の初期化
M5.Lcd.printf("BME280 test\r\n"); // LCD display
}
void loop() {
float temp, humid, pressure;
// BME280で温度、湿度、気圧を測定する
temp = (float)bme280.readTemperature();
humid = (float)bme280.readHumidity();
pressure = (float)bme280.readPressure();
M5.Lcd.printf("temp: %2.2f", temp);
M5.Lcd.printf(" humid: %0.2f", humid);
M5.Lcd.printf(" pressure: %f\r\n", pressure);
delay(5000);
}

BME280ライブラリはESP8266用のBME280ライブラリがそのまま使えます。 BME280をI2Cで使う時はSDAとSCLをプルアップする必要があります。 スイッチサイエンスのESP8266モジュールにはプルアップ抵抗が載っていませんが、プログラムでプルアップするので大丈夫です。

    pinMode(21, INPUT_PULLUP);
    pinMode(22, INPUT_PULLUP);

BME280のデータをAmbientに送る

次にBME280のデータをAmbientに送信します。Ambientにデータを送信するライブラリはESP8266/ESP32共通で、 M5Stackでも同じものを使います。Ambientに関係する部分だけを抜き出すと、次のようになります。 setup()関数でAmbientの初期化をおこない、loop()関数でセンサの値を読んで、その値を.set()でパケットにセットし、 .send()でAmbientに送信しています。

#include "Ambient.h" // Ambientのヘッダーをインクルード
Ambient ambient; // Ambientオブジェクトを定義
unsigned int channelId = 100; // AmbientのチャネルID
const char* writeKey = "writeKey"; // ライトキー
void setup() {
...
ambient.begin(channelId, writeKey, &client); // チャネルIDとライトキーを指定してAmbientの初期化
}
void loop() {
... // センサーの値を読む
// センサー値をAmbientに送信する
ambient.set(1, data1);
ambient.set(2, data2);
ambient.send();
}

プログラムはArduino IDEを立ち上げ、「ファイル」→「スケッチ例」→「Ambient ESP8266 lib」→「M5Stack」→「Ambient_BME280」を選択するとロードできます。

プログラムをビルドし、M5Stackに書き込むと、BME280で温度、湿度、気圧を測定し、データがAmbientに送信されます。 Ambientのチャネルページを見ると、次のようにデータが確認できます。

温湿度・気圧・空気品質センサBME680を使う

温湿度・気圧に加えて、空気品質を測定できるBME680というセンサがあります。 これもM5Stackにつなげてみます。

BME680センサチップはI2CとSPIの両方のインタフェースを持っていますが、 スイッチサイエンス社が扱っているPimoroni社のモジュールはI2Cインタフェースのみに対応し、 5本のピンでアクセスするようになっています。これを次のようにM5Stackに接続します。

M5StackBME680モジュール
3V32-6V
SDA(21)SDA
SCL(22)SCL
GNDGND

信号の並び順がM5StackとPimoroni社のBME680モジュールとで違うので、 順番を入れ替える小さな基板を作ってBME680をM5Stackにつなぎました。 BME280をつないだ時と同様にジャンパワイヤでつないでも構いません。

BME680をアクセスするライブラリはAdafruitのものを使いました。 そのままだとコンパイルエラーになるので、一部修正を加えています。

プログラムはArduino IDEを立ち上げ、 「ファイル」→「スケッチ例」→「Ambient ESP8266 lib」→「M5Stack」→「Ambient_BME680」を選択するとロードできます。

/*
* M5StackとBME680をI2C接続し、温度、湿度、気圧を測定しプリントアプトする
*/
#include <M5Stack.h>
#include <Wire.h>
#include "Adafruit_BME680.h"
#include "Ambient.h"
#define PERIOD 60
Adafruit_BME680 bme680; // I2C
WiFiClient client;
Ambient ambient;
const char* ssid = "your ssid";
const char* password = "your password";
unsigned int channelId = 100; // AmbientのチャネルID
const char* writeKey = "writeKey"; // ライトキー
void setup(){
M5.begin();
Wire.begin(); // I2Cの初期化
Serial.begin(74880);
WiFi.begin(ssid, password); // Wi-Fi APに接続
while (WiFi.status() != WL_CONNECTED) { // Wi-Fi AP接続待ち
delay(100);
}
Serial.print("WiFi connected\r\nIP address: ");
Serial.println(WiFi.localIP());
if (!bme680.begin()) {
Serial.println("Could not find a valid BME680 sensor, check wiring!");
while (1) {
delay(0);
}
}
// Set up oversampling and filter initialization
bme680.setTemperatureOversampling(BME680_OS_8X);
bme680.setHumidityOversampling(BME680_OS_2X);
bme680.setPressureOversampling(BME680_OS_4X);
bme680.setIIRFilterSize(BME680_FILTER_SIZE_3);
bme680.setGasHeater(320, 150); // 320*C for 150 ms
ambient.begin(channelId, writeKey, &client); // チャネルIDとライトキーを指定してAmbientの初期化
// LCD display
M5.Lcd.printf("BME680 test\r\n");
}
void loop() {
int t = millis();
float temp, humid, pressure, gas;
// BME680で温度、湿度、気圧を測定する
if (! bme680.performReading()) {
Serial.println("Failed to perform reading :(");
return;
}
temp = (float)bme680.temperature;
humid = (float)bme680.humidity;
pressure = (float)bme680.pressure / 100.0;
gas = (float)bme680.gas_resistance / 1000.0;
M5.Lcd.printf("temp: %2.2f", temp);
M5.Lcd.printf(" humid: %0.2f", humid);
M5.Lcd.printf(" pressure: %f", pressure);
M5.Lcd.printf(" gas: %f\r\n", gas);
// 温度、湿度、気圧、CO2、TVOCの値をAmbientに送信する
ambient.set(1, String(temp).c_str());
ambient.set(2, String(humid).c_str());
ambient.set(3, String(pressure).c_str());
ambient.set(4, String(gas).c_str());
ambient.send();
t = millis() - t;
t = (t < PERIOD * 1000) ? (PERIOD * 1000 - t) : 1;
delay(t);
}

まとめ

M5Stackは5.4cm x 5.4cmのコンパクトなケースにESP32、電池、320 x 240 TFTカラーディスプレイなどが搭載されたIoT端末です。 拡張モジュールを積み重ねることで機能を拡張していけます。ArduinoとMicroPythonでプログラミングできることも魅力です。 簡単な実験から本番での使用まで幅広く使えるIoT端末です。

この記事はアンビエントデーターの下島が担当しました。