ESP32ボードとMachbase NeoでIoTを構築する
概要
センサーを使ってIoTデータを収集する方法は、さまざまです。
従来は、Raspberry Piなどのシングルボードコンピューター(SBC)にセンサーを接続し、SBC上のデータベースやストレージへ直接保存する方法が使われてきました。ただし、I/Oピンの数には限りがあり、センサーとの有線接続も必要です。複数の場所にセンサーを設置する場合、配線や接続方法を慎重に検討しなければなりません。

物価上昇や高性能化に伴い、Raspberry Piの価格が上がっていることも、無視できない課題です。
そこで、マイクロコントローラーとセンサーを組み合わせ、Wi-Fi上でMQTTを使ってデータを送るスマートセンサーを作れば、さまざまな場所へ低コストで多数のセンサーを設置できます。本記事で使用するESP32ボードとセンサーの価格は、執筆時点の最新Raspberry Piの10分の1以下でした。
ESP32とセンサー
ESP32は、Arduinoと同様にプログラミングできるマイクロコントローラーで、Wi-FiとBluetooth、デュアルコアのRISC CPU、メモリ、ROMを備えています。Arduino IDEでファームウェアを開発し、USB経由で書き込むと、そのプログラムで動作します。
今回はESP-WROOM32ボードと、温度・湿度を測定するDHT-11センサーを使います。低コストで実用的なスマートセンサーを構成できます。


低消費電力で動作するため、スマートフォン用のモバイルバッテリーなどにつないでも長時間稼働できます。電源を確保しにくい場所にも設置しやすい構成です。
配線と設定
DHT-11のケーブルを、電源とGPIOピンに接続します。これだけで、センサー値を読み取る準備が整います。
データ線を接続したGPIO番号は、ファームウェアの定数に指定します。図の配線では、データ線をD15に接続しています。

Machbase Neoのインストール
MQTTで受信したデータを記録・保存するため、Machbase Neoをインストールします。公式ドキュメントから入手し、サーバーを起動してください。
標準設定では、接続先IPアドレスはNeoをインストールした機器のIP、MQTTポートは5653です。後でファームウェアにも、この情報を設定します。
__ __ _ _
| \/ | __ _ ___ | |__ | |__ __ _ ___ ___
| |\/| | / _` | / __| | '_ \ | '_ \ / _` | / __| / _ \
| | | | | (_| | | (__ | | | | | |_) | | (_| | \__ \ | __/
|_| |_| \__,_| \___| |_| |_| |_.__/ \__,_| |___/ \___|
_ __ ___ ___
| '_ \ / _ \ / _ \ v8.0.17 (fedc1d8f 2024-04-19T11:42:46)
| | | | | __/ | (_) | engine v8.0.18 (df3cccd1e)
|_| |_| \___| \___/ static_standard_windows_amd64 Windows 10.0 19045
2024/05/10 10:10:39.043 INFO scheduler started.
2024/05/10 10:10:39.044 INFO neosvr MACH Listen tcp://0.0.0.0:5656
2024/05/10 10:10:39.068 INFO grpcd gRPC TLS enabled
2024/05/10 10:10:39.069 INFO grpcd gRPC Listen tcp://0.0.0.0:5655
2024/05/10 10:10:39.069 INFO httpd HTTP token authentication disabled
2024/05/10 10:10:39.070 INFO httpd HTTP path /db for machbase api
2024/05/10 10:10:39.070 INFO httpd HTTP path /lakes for lake api
2024/05/10 10:10:39.071 INFO httpd HTTP path /metrics for the line protocol
2024/05/10 10:10:39.071 INFO httpd HTTP path /web for the web ui
2024/05/10 10:10:39.072 INFO httpd HTTP Listen tcp://0.0.0.0:5654
2024/05/10 10:10:39.073 INFO mqttd MQTT token authentication disabled
2024/05/10 10:10:39.073 INFO mqtt-tcp MQTT Listen tcp://[::]:5653Windowsにインストールした場合は、Windowsファイアウォールの「アプリを許可」から、machbase-neoが接続できるように設定します。

データを保存するテーブルを作成するため、ブラウザーで http://<サーバーIP>:5654 にアクセスします。上の起動ログでも、HTTPの待ち受けポートは5654と表示されています。
CREATE TAG TABLE tag (name VARCHAR(20) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE SUMMARIZED) WITH ROLLUP (hour)
これで、MQTTブローカーとしてデータを受け取るMachbase Neoと、保存先テーブルの準備ができました。以下の情報を手元に用意し、ファームウェアの開発に進みます。
Machbase NeoのIPアドレス(この例では192.168.1.131)
Machbase NeoのMQTTポート(標準設定では5653)
センサーデータを保存するタグテーブル名(この例ではTAG)
ファームウェアの開発
ファームウェアの動作
センサー値を読み取り、Machbase Neoへ送信するため、次の順序で処理します。
サンプルのファームウェアはGitHubで公開しています。
ネットワーク接続と初期設定
Wi-Fiへ接続します。SSIDとパスワードが必要です。
NTP(Network Time Protocol)で内蔵時計を同期します。
Machbase NeoのMQTTブローカーへ接続します。
DHT-11センサーを初期化します。
MQTTブローカーとの接続状態を確認し、切断されていれば再接続を試みます。
センサー値を読み取り、Machbase NeoがMQTTで受け取れるJSON形式に変換します。
JSONデータをMQTTトピックへpublishします。
一定時間待ってから、接続状態の確認に戻ります。
コードを見ながら、各処理を確認しましょう。
開発ツールとボード用モジュールのインストール
ESP32では、Arduino IDEを使って比較的簡単にファームウェアを開発できます。まずIDEをインストールし、Tools → Board → Board Managerから「esp32 by Espressif」を追加します。

ダウンロードやコンパイルを行うため、インストールには少し時間がかかります。
次に、ボードのUSBドライバーをインストールします。今回のボードはCP2102を使用しており、ドライバーはSilicon Labsから入手しました。
モジュールとドライバーをインストールしたら、ESP32をUSBで接続し、対応するUSBシリアルポートを設定します。Arduino IDEがボードを認識したら、簡単なサンプルをビルドして実行し、シリアルモニターで結果を確認できます。
センサードライバーとMQTTライブラリのインストール
Tools → Library Managerから、DHT-11用のドライバーとMQTTライブラリを追加します。「DHT sensor library by Adafruit」を検索してインストールしてください。

続いて「PubSubClient」を検索してインストールします。

必要なライブラリがそろえば、開発の準備は完了です。
センサーの設定
接続したGPIOピンの番号とセンサーのモデルを指定します。
#define DHTPIN 15
#define DHTTYPE DHT11
//DHTTYPE = DHT11, but there are also DHT22 and 21
DHT dht(DHTPIN, DHTTYPE); // constructor to declare our sensorsetup()でセンサーを初期化します。
dht.begin();Wi-Fi接続と時刻同期
まずWi-Fiへ接続し、NTPで時刻を同期します。ESP32にはWi-Fi機能が内蔵されているため、追加の通信ハードウェアは不要です。
// WiFi
const char *ssid = "MACHBASE_AP"; // Enter your Wi-Fi name
const char *password = "xxxxxxxxxx"; // Enter Wi-Fi password
WiFiClient wifi_connection;接続するアクセスポイントのSSIDとパスワードを設定します。
次のコードでWi-Fi接続を開始します。
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);このESP32ボードには、時計を保持するためのバックアップ電池がありません。時系列データを収集するには正確な現在時刻が必要なので、ネットワーク接続後にNTPで設定します。
//Time
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 3600*9;
const int daylightOffset_sec = 0;元の例は韓国時間に合わせるため、GMTから9時間のオフセットを指定しています。夏時間は使用しないので0です。NTPサーバーには pool.ntp.org を指定します。次の関数を呼び出すと、時刻が同期されます。
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);MQTTブローカーの設定と接続
Neoのインストール時に確認したIPアドレスとMQTTポートを、次のように設定します。
// MQTT
const char *mqtt_server = "192.168.1.131";
const char *topic = "db/append/TAG";
const int mqtt_port = 5653;
PubSubClient mqtt_client(wifi_connection);Wi-Fiへ接続した後、次のコードでMQTTへ接続します。失敗した場合は、接続できるまで再試行します。
メインループでも接続状態を確認し、切断されていれば再接続します。
// initialize mqtt client
void setup()
{
mqtt_client.setServer(mqtt_server, mqtt_port);
mqtt_client.setCallback(callback);
// other code omitted.
}
void reconnect() {
// Loop until we're reconnected
while (!mqtt_client.connected()) {
Serial.print("Attempting MQTT connection...");
String clientId = "ESP32-";
clientId += WiFi.localIP();
// Attempt to connect
if (mqtt_client.connect(clientId.c_str())) {
Serial.println("connected");
}
else {
Serial.print("failed, rc=");
Serial.print(mqtt_client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}MQTTによるデータ送信
MQTTトピック
MQTTはpublish/subscribe方式でデータをやり取りします。Neoのタグテーブルへ取り込む場合、トピックは「db/APIの種類/テーブル名」です。今回はappend APIを使うので、「db/append/TAG」へpublishします。
Machbase NeoはJSONまたはCSV形式でデータを受け取れます。この例ではJSONを使います。
タイムスタンプ
Machbase Neoの標準タイムスタンプは、ナノ秒単位の整数です。今回は秒単位の精度で十分なので、次のように実装します。
int64_t get_timestamp_milis() {
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000LL;
// return (tv.tv_sec * 1000LL + (tv.tv_usec / 1000LL));
}
... //miliseconds to nanoseconds
current_time = get_timestamp_milis() * 1000000LL;
...データの送信
MQTTで送るデータは、JSONまたはCSV形式にします。次のコードは、センサー値を読み取ってJSONに変換し、Machbase Neoへ送信する部分です。
// The DHT11 returns at most one measurement every 1s
float h = dht.readHumidity();
//Read the moisture content in %.
float t = dht.readTemperature();
//Read the temperature in degrees Celsius
snprintf (msg, MSG_BUFFER_SIZE, "[ [\"ESP32.hum\",%lld,%f],
[\"ESP32.tem\",%lld,%f] ]",
current_time, h, current_time, t);
Serial.print("Publish message: ");
Serial.println(msg);
mqtt_client.publish(topic, msg);完成したファームウェアをArduino IDEからESP32へ書き込むと、自動的に実行が始まります。IDEのシリアルモニターで動作を確認し、Neoのウェブ画面からクエリを実行すれば、データの取り込み状況も確認できます。

Machbase Neoでデータを活用する
保存したデータは、追加のツールをインストールせずに可視化・分析できます。NeoのTAG Analyzerを使えば、収集した温度・湿度を簡単にグラフ化できます。

Machbaseの時系列DBMSは、データを圧縮して保存するため、長期間の収集でも保存容量を抑えられます。高速なインデックスを使い、大量のデータも素早く検索できます。
今回はESP32を使い、ネットワーク接続できるスマートセンサーを作りました。Arduinoの豊富なセンサー対応と、Wi-Fi・MQTTによる送信を組み合わせれば、IoTの仕組みを簡単に構築できます。収集したデータは、Machbase Neoで可視化するなど、手軽に活用できます。


