前回のPostでは、Raspberry Pi を使いBME280(測定器)からのデータを、別ノードにあるMySQLへ蓄積。蓄積したデータをGraganaで可視化するところまでを行いました。
構築後しばらく運用を続けていると、BME280からデータを受け取るだけの為に、Raspberry Piを利用するといのは、いささかオーバースペックではないか?と感じるようになってきました。
なにより電源を切るのにshutdownする必要があるというのが、結構面倒くさいポイントなのです。
部屋に昔買ったESP32という、Wi-Fi が搭載された低消費電力なマイクロプロセッサが転がっていました。普及している Arduino の開発環境を利用してプログラムを書き込めたりと触っていて楽しいおもちゃです。Arduino も転がっていましたが、こちらは、そのままでは Wi-Fi を使えないので 今回の用途ではESP32がベストマッチなのです。
Raspberry Pi の代わりにESP32を使う
部屋に転がっていたのは、ESP32-DevKitC というもので、一番開発に使いやすい標準的なボードです。
昔、秋月で購入しました。ESP32-DevKitC 4MB メモリ8M版の価格があまり変わらないので、いろいろ実験したい方はそっちのが良いかもです。
この DevKitは横幅が割と広くて中国製の安い小さなブレッドボードに刺すと横幅が目一杯で使いにくいんですよね。このサンハヤトのブレッドボードなら、1列余裕ができるので各種信号を引き出しやすいのです。ESP32で遊ぶ方は一枚持っていると良いかも。
さて、先の記事で Raspberry Pi が担っていた仕事をESP32にさせられるかどうか軽く調べてみるとなんの問題も無さそうです。
- I2C通信でBME280からデータを取得
Wireライブラリ(標準ライブラリ)を利用
Switch Scienceのリポジトリにあるサンプルコードを流用 - TCP/IP通信
WiFiライブラリ(標準ライブラリ)を利用 - http server機能
ESPAsyncWebServerライブラリを利用
サーバ側の仕組みは変わりませんので新しく調整するのは、ESP32から先だけになります。
スイッチサイエンスのサンプルを変更
Switch Scienceのリポジトリにあるサンプルコードをベースに、Wi-Fi に接続するコードとWebServerを立ち上げ、測定値を返すコードを追加していきます。
Wi-Fiのセットアップ
エラー処理が甘過ぎかもですが、SSIDとパスフレーズをWiFi.begin()へ渡すだけです。IPアドレスはDHCPで取得がデフォルトの動作です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include <WiFi.h> #define SSID "xxxx" #define PASS "xxxx" setup() 内で Serial.begin(9600); while (!Serial); WiFi.mode(WIFI_STA); WiFi.begin(SSID,PASS); Serial.print("WiFi connection..."); while (WiFi.status() != WL_CONNECTED){ Serial.print("."); delay(100); } Serial.println(" Connected."); Serial.print("IP Addless: "); Serial.println(WiFi.localIP()); |
AsyncWebServerのセットアップ
GETメソッドで / へリクエストが届いたら、readBME280() をコールして返値をString型に変換し返します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <ESPAsyncWebServer.h> // TCP/8081 Port AsyncWebServer server(8081); setup()内で // setup WebServer server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ request -> send(200,"text/plane", String(readBME280())); }); server.begin(); Serial.println("Starting WebServer"); |
測定値読み出し部分の変更
サンプルコードでは定期的に測定値を読み出す為に loop() 内で読み出しを行っていましたが、今回はAsyncWebServerから呼び出されてから測定値を読み込みます。
loop()内のコードを、AsyncWebServerからコールされる関数内に移動します。
ごく希にセンサーからの数値が異常な値が返る事がありましたので、数値チェックをして、異常値だった場合に再取得するようなコードを入れました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
#define MAX_LEN 40 char buf[MAX_LEN]; #define MAX_THR_TEMP (70 * 100) #define MIN_THR_TEMP (-30 * 100) #define MAX_THR_PRES (1500 * 100) #define MIN_THR_PRES (500 * 100) #define MAX_THE_HUM (100 * 1024) #define MIN_THR_HUM 0 void loop(){ } bool isNormally(signed long temp, unsigned long press, unsigned long hum){ if (temp >= MAX_THR_TEMP || temp <= MIN_THR_TEMP) return false; if (press >= MAX_THR_PRES || press <= MIN_THR_PRES) return false; if (hum >= MAX_THE_HUM || hum <= MIN_THR_HUM) return false; return true; } char *readBME280() { double temp_act = 0.0, press_act = 0.0,hum_act=0.0; signed long int temp_cal; unsigned long int press_cal,hum_cal; bzero(buf, MAX_LEN); do { readData(); temp_cal = calibration_T(temp_raw); press_cal = calibration_P(pres_raw); hum_cal = calibration_H(hum_raw); sleep(0.5); } while (!isNormally(temp_cal, press_cal, hum_cal)); temp_act = (double)temp_cal / 100.0; press_act = (double)press_cal / 100.0; hum_act = (double)hum_cal / 1024.0; snprintf(buf, MAX_LEN, "%3.2f,%4.2f,%3.2f\n", temp_act, press_act, hum_act); Serial.print(buf); return buf; } |
パッチファイル
サンプルファイルからの差分です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
--- BME280.ino.orig 2022-05-28 02:57:16.194636431 +0900 +++ BME280.ino 2022-05-29 01:20:59.964714229 +0900 @@ -1,0 +2,2 @@ +#include <WiFi.h> +#include <ESPAsyncWebServer.h> @@ -25,0 +28,15 @@ +#define SSID "xxxxx" +#define PASS "xxxxx" +AsyncWebServer server(8081); + +#define MAX_LEN 40 +char buf[MAX_LEN]; + +#define MAX_THR_TEMP (70 * 100) +#define MIN_THR_TEMP (-30 * 100) +#define MAX_THR_PRES (1500 * 100) +#define MIN_THR_PRES (500 * 100) +#define MAX_THE_HUM (100 * 1024) +#define MIN_THR_HUM 0 + + @@ -40,0 +58,13 @@ + while (!Serial); + + WiFi.mode(WIFI_STA); + WiFi.begin(SSID,PASS); + Serial.print("WiFi connection..."); + while (WiFi.status() != WL_CONNECTED){ + Serial.print("."); + delay(100); + } + Serial.println(" Connected."); + Serial.print("IP Addless: "); + Serial.println(WiFi.localIP()); + @@ -46,0 +77,11 @@ + + // setup WebServer + server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ + request -> send(200,"text/plane", String(readBME280())); + }); + + server.begin(); + Serial.println("Starting WebServer"); +} + +void loop(){ @@ -48,0 +90,9 @@ +bool isNormally(signed long temp, unsigned long press, unsigned long hum){ + if (temp >= MAX_THR_TEMP || temp <= MIN_THR_TEMP) + return false; + if (press >= MAX_THR_PRES || press <= MIN_THR_PRES) + return false; + if (hum >= MAX_THE_HUM || hum <= MIN_THR_HUM) + return false; + return true; +} @@ -50,2 +100 @@ -void loop() -{ +char *readBME280() { @@ -56,5 +105,10 @@ - readData(); - - temp_cal = calibration_T(temp_raw); - press_cal = calibration_P(pres_raw); - hum_cal = calibration_H(hum_raw); + bzero(buf, MAX_LEN); + + do { + readData(); + temp_cal = calibration_T(temp_raw); + press_cal = calibration_P(pres_raw); + hum_cal = calibration_H(hum_raw); + sleep(0.5); + } while (!isNormally(temp_cal, press_cal, hum_cal)); + @@ -64,9 +118,4 @@ - Serial.print("TEMP : "); - Serial.print(temp_act); - Serial.print(" DegC PRESS : "); - Serial.print(press_act); - Serial.print(" hPa HUM : "); - Serial.print(hum_act); - Serial.println(" %"); - - delay(1000); + + snprintf(buf, MAX_LEN, "%3.2f,%4.2f,%3.2f\n", temp_act, press_act, hum_act); + Serial.print(buf); + return buf; @@ -73,0 +123 @@ + |
Raspberry Pi と交換
かなりコンパクトになりました。しかしジャンパーが美しくないです。突然の電源OFFも問題なし。リセットボタンを押してから復帰まで5秒もかかりません。この状態で2,3日動かして問題がなかったのでユニバーサル基板に換えてみました。
最初のRaspberry Pi の半分以下の面積です。
データの取得先をRaspberry PiのIPアドレスからESP32のIPアドレスへ書き換えるだけで、サーバ側の変更は完了です。
最初にセンサー側で複雑なことはさせないという設計方針は間違っていなかったようです。
BME280センサーモジュールを購入してから、かなりの期間放置してました。というのは、その時に浸かったジャンパーが接触不良でI2C通信が不安定で、その原因がよくわからなかったんです。
面倒くさがらずにさっさとオシロをつないでI2C信号を見ればよかった・・・