airpocketのアイコン画像
airpocket 2023年03月15日作成 (2023年03月15日更新) © MIT
製作品 製作品 閲覧数 2047
airpocket 2023年03月15日作成 (2023年03月15日更新) © MIT 製作品 製作品 閲覧数 2047

ESP32で作るセンサーノード

ESP32で作るセンサーノード

はじめに

昨年開催されたWeb×IoT メイ-カーズチャレンジ PLUSというハッカソンに参加し、水耕栽培用のスマートプランターを作って、OSHWとして公開してみました(正確にはデータは公開したもののドキュメントが作れてないのですが)。
このプロジェクトが岡山大会の最優秀賞に選出され、2023年の3月のグランプリ大会に向けて追加機能として、ESP32DevkitでIoT端末を制作してみます。

このデバイスを制作する目的は以下の二つです。

①スマートプランターの制御にRaspberry Pi 4B を使っており性能を生かし切れていないので、子機として動く装置を制作して有効活用したい。

ハッカソンで制作したデバイスは、ハッカソンと同時に行われた演習で使用したRaspberry Pi 4Bを制御に使用しましたが、かなりオーバースペックなものとなりました。そのため、このRaspberry Piにはスマートプランターの制御と同時にデータベースやBIツールのサーバ、Wi-Fiアクセスポイント等としての機能も持たせています。
Wi-Fi接続できる子機を用意して、Raspberry Piのサーバ機能をより活用してみます。

②なるべく消費電力を抑えたい。
バッテリー駆動、PV駆動などを考慮して、なるべく低消費電力にする。

今回は株式会社ニソール様よりご提供いただいた植物発電キットを使った駆動にも挑戦します。
植物発電キットはMg電池を利用した長期運用可能な発電システムと言うことです。
基本的にはMg一次電池として働きますが、土壌中に電極を埋設することにより、長寿命化が期待できるそうです。
効果についてはまだ検証中とのことですが、Mg一次電池としては十分期待できますのでこのシステムを使った運用も試してみます。

機器の構成

今回制作したデバイスの外観です。

キャプションを入力できます
上部の透明筐体はDAISOのガラス製のキャニスターを使用しています。
透明にしたのは照度センサを使用する為ですが、配線に真鍮線を使用してESP32の基板を見せるなど、外観重視のデモ仕様にしてますので実用には適していません。実使用を目指す場合、水密性の確保、高温対策、気温センサのための通風機構など、もっとまじめに筐体設計が必要です。

ESP32の裏に設置しているのは100F3Vの電気二重層キャパシタです。ESP32は起動時に大きな突入電流を消費しますので、キャパシタで容量を確保しています。耐圧3Vのキャパシタに3.3Vをかけている治安の悪い仕様ですのでもし同様の装置を制作する際には耐電圧3.3V以上のキャパシタを使用してください。

部品 個数 備考
ESP32 Dev kit C 1
100F3V電気二重層キャパシタ 1 蓄電用
BH1750 1 照度センサ
BMP280 1 気温湿度気圧センサ
静電容量式土壌水分量センサ 1
オルタネイト式スイッチ 1 マイコン電源用
回路用ケーブル、コネクタ、ユニバーサル基板等 お好みで

全体の構成

ESP32へは3V3ラインから電源を供給しています。
照度センサと温湿度センサはI2C通信で接続、土壌水分センサと電源電圧をADCピンで監視しています。
測定したデータはWiFiを通じてネットワーク内のサーバへMQTT通信にて送信します。
省電力化のため、Deepsleep機能をを使い、1回/時間の間欠駆動させています。

制御

制御に使えそうなマイコンボードはいろいろありますが、今回は入手性が良く、Wi-FiとSPIとI2CとADCが付いているESP32の開発ボードを使います。
ESP32にはDeepseep機能がありますが、LDOやUSB UART変換部分でそれなりの電力を消費する事が知られています。本気で省電力化するならばこのあたりも対策したいのですが、植物発電の電源出力が平均3V×20mA以上見込めるため、まずはこのまま実装します。

電源

発電にはNisoul様より提供していただいた植物発電キットを使用します。植物発電で使用するマグネシウム電極は理論値で-2.3V、実際には-1.0~-1.5V程度の起電力あるため、3.3Vに昇圧して使用します。また、制御に使用するESP32は起動時に大きな突入電流を必要とし、通信時にもそれなりの電力を消費します。植物発電ではこれらの電力を賄えないため、電気二重層コンデンサに蓄電し、起動時の消費電力を賄います。発電量はDeepsleep時の消費電力を上回るため、その間に稼働時に消費する電力を賄う予定です。

※キャパシタはメインの3.3VラインとGNDラインの間に挟んでいるだけのため、初期の充電時にESP32を接続していると起動に失敗し続けます。キャパシタの電圧が3Vを超えてからESP32を接続する必要があります。

開発環境

「ファイル」⇒「開発環境」
追加のボードマネージャのURLに「https://dl.espressif.com/dl/package_esp32_index.json」
を追記して「OK」⇒「OK」
「ツール」⇒「ボード」⇒「ボードマネージャ」
から、「esp32」で検索して「esp32 by Espressif Systems」をインストール

これでESP32の開発ボードが使用できます。
こちらのサイトなどでも詳しく説明されています。
https://spiceman.jp/esp32-arduino-ide/

センサ

植物育成環境及び蓄電状況のセンシングのため、次のセンサ類を使用します。

項目 型番 接続方法
照度センサ BH1750 I2C
温度・湿度・気圧センサ BMP280 I2C
静電容量式土壌水分量センサ - ESP32搭載ADC

接続

回路図作成中です

プログラム

プログラムはArduino IDEで書きました。

ライブラリ

以下のライブラリが必要です。事前にインストールしてからコンパイルしてください。

Arduino BME280 library by Adafruit
BH1750 by Chrstopher Laws
PubSubClient

プログラム

// ESP32センサーノード // 依存ライブラリを事前にインストールしてください。 // Adafruit BME280 Library by Adafruit Ver 2.2.2 // BH1750 by Christopher Laws Ver 1.3.0 // PubSubClient by Nick O'Leary Ver 2.8.0 // // 接続先Wi-Fi APのSSID及びPASSを設定してください。2.4GHzのみ対応しています。5GHzは使用できません。 // データ送信にはMQTTを使用しています。接続先MQTTブローカーのIPアドレスを設定してください。 // 測定データは照度、気温、湿度、気圧、土壌水分センサ電圧、電源電圧を測定してそれぞれのTopicに送信します。 #include <WiFi.h> #include <PubSubClient.h> //MQTTライブラリ #include <BH1750.h> //照度センサライブラリ #include <Wire.h> //I2C接続ライブラリ #include <Adafruit_Sensor.h> //Adafruit センサライブラリ #include <Adafruit_BME280.h> //Adafruit 温湿度センサライブラリ #define AD_PIN 35 //土壌水分センサ測定用 #define DO_PIN 32 //土壌水分センサ電源用 省電力化のため、測定時のみ通電するため。 #define AD_PIN2 34 //電源電圧測定用 昇圧後、キャパシタの充電電位 int deepSleepSec = 3600; // BH1750 BH1750 lightMeter; //照度センサ // BME280 Adafruit_BME280 bme; // I2C const char ssid[] = "****"; //接続先Wi-Fiのssid const char pass[] = "****"; //Wi-Fiのパスワード // MQTT const char mqttBrokerAddress[] = "***.***.***.***"; // MQTTサーバーのIPかホスト名 const int mqttBrokerPort = 1883; // MQTTのポート. デフォルトは1883 WiFiClient wifiClient; PubSubClient mqttClient(wifiClient); void connectWiFi(); void connectMqtt(); void setup() { Serial.begin(115200); Wire.begin(); lightMeter.begin(); bme.begin(0x76); pinMode(AD_PIN, ANALOG); pinMode(AD_PIN2, ANALOG); pinMode(DO_PIN, OUTPUT); connectWiFi(); connectMqtt(); } void loop() { float lux; float temp; float hum; float pressure; int soil; int voltage; if (WiFi.status() == WL_DISCONNECTED) { connectWiFi(); } if (!mqttClient.connected()) { connectMqtt(); } //照度測定及びmqtt送信 topic:TopicLux char luxChar[8]; lux = lightMeter.readLightLevel(); dtostrf(lux, 5, 2, luxChar); mqttClient.publish("TopicLux", luxChar); Serial.print("Light: "); Serial.print(lux); Serial.println(" lx"); //温度測定及びmqtt送信 topic:TopicTemp char tempChar[6]; temp = bme.readTemperature(); dtostrf(temp, 4, 2, tempChar); mqttClient.publish("TopicTemp", tempChar); Serial.print("Temp: "); Serial.print(temp); Serial.println(" *C"); //湿度測定及びmqtt送信 topic:Topic:Hum char humChar[6]; hum = bme.readHumidity(); dtostrf(hum, 4, 2, humChar); mqttClient.publish("TopicHum", humChar); Serial.print("Hum: "); Serial.print(hum); Serial.println(" %"); //気圧測定及びmqtt送信 topic:TopicPress char pressChar[6]; pressure = bme.readPressure()/100.0; dtostrf(pressure, 4, 2, pressChar); mqttClient.publish("TopicPress", pressChar); Serial.print("press: "); Serial.print(pressure); Serial.println(" hPa"); //土壌水分量測定 topic:TopicSoil char soilChar[8]; digitalWrite(DO_PIN, HIGH); delay(5000); soil = analogReadMilliVolts(AD_PIN); dtostrf(soil, 5, 2, soilChar); mqttClient.publish("TopicSoil", soilChar); Serial.printf("Soil water content%d[mV]\n", soil); //充電電圧測定 topic:TopicVoltage char voltageChar[8]; voltage = analogReadMilliVolts(AD_PIN2); dtostrf(voltage, 5, 2, voltageChar); mqttClient.publish("TopicVoltage", voltageChar); Serial.printf("Voltage:%d[mV]\n", voltage); mqttClient.publish("outTopic", "good night..."); delay(1000); mqttClient.loop(); Serial.println("good night..."); // deep sleep timer設定 単位:us 3600000000=1hour esp_sleep_enable_timer_wakeup(3600000000); esp_deep_sleep_start(); } void connectWiFi() { WiFi.begin(ssid, pass); Serial.print("WiFi connecting..."); while(WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(100); } Serial.print(" connected. "); Serial.println(WiFi.localIP()); } void connectMqtt() { mqttClient.setServer(mqttBrokerAddress, mqttBrokerPort); mqttClient.setCallback(mqttReceiveCallback); while( ! mqttClient.connected() ) { Serial.println("Connecting to MQTT..."); String clientId = "ESP32-" + String(random(0xffff), HEX); if ( mqttClient.connect(clientId.c_str()) ) { Serial.println("connected"); mqttClient.publish("outTopic","hello world"); mqttClient.subscribe("inTopic"); } delay(1000); randomSeed(micros()); } } void mqttReceiveCallback(char* topic, byte* payload, unsigned int length) { Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] "); for (int i=0;i<length;i++) { Serial.print((char)payload[i]); } Serial.println();

デモ機を使ってみる

デモ機を使ってみます。

設置する前にキャパシタを充電します。
装置の導体内部のスライドスイッチを下側(黒側)に下げてESP32への電源供給をカットします。
ここでは見やすい様に本体を分解していますが、未分解状態でも本体下部から六角レンチなどL字の棒を使って引張り下げることができます。
キャプションを入力できます

導体下部には3PINと2PINのコネクタがあります。2PINコネクタが電源供給用のコネクタのため、3.3Vの電源を供給します。
3PINコネクタは土壌水分センサ接続用です。
キャプションを入力できます

充電状態のインジケータはありませんので、キャパシタの端子を直接測定して充電電圧を確認します。3V以上蓄電されれば、ESP32は起動可能です。
キャプションを入力できます

今回は、植物発電キットを電源に使用するため、先に電極の埋設処理をしておきました。
穴を掘って電極を設置、
キャプションを入力できます

埋め戻して植物を植え付け。
キャプションを入力できます

一週間ほどで電圧が上がってきました。
キャプションを入力できます

昇圧ボードで3.3Vにあげてからデバイスを接続しています。
キャプションを入力できます

今回は、Raspberry Piをサーバにして、MQTTブローカーをNode-RED上で起動しています。Node-REDで受け取ったデータは、同じくラズパイ上のMariaDBに記録してGrafanaで可視化しました。
キャプションを入力できます

まとめ

久しぶりにESP32 Devkitを使用してデバイスを作ってみました。
ありがちなセンサ端末ですが、既存のライブラリやOSSを使うとさくさく作れるのが楽しいですね。
最近は、IoTのデータ蓄積と可視化はラズパイ上のNode-RED+MariaDB+Grafanaを多用しています。センサノードに何を使おうとMQTTで投げてしまえば後処理は同じ仕様の使いまわしで済むのでめちゃくちゃ便利でおすすめです。維持コストもゼロ円です。
クラウドでもデータが見たい場合は、Node-REDから先をGAS+Googleスプレッドシート+Glideにすればこれまた維持コストゼロです。

airpocketのアイコン画像
電子工作、プログラミング、AI、DIY、XR、IoT M5Stack / Raspberry Pi / Arduino / spresense / K210 / ESP32 / Maix / maicro:bit / oculus / Jetson Nano / minipupper etc
ログインしてコメントを投稿する