だんだん寒くなってきてストーブを付ける機会も増えてきたので、そうなると気になるのが息苦しさです。ストーブつけると換気しなきゃいけないのは当たり前なんですが、息苦しくなってきたら換気するとか、なんとなく1時間に1回ちょっと窓あけるみたいなことやってるんですが、あんまり効率的じゃないなあと思ったので、CO2センサーを買ってCO2濃度を可視化すればいいじゃん!となり作りました。
半年ぐらい前に構想してたんですが、コロナくん騒ぎでCO2センサーが中国から全然届かず届いた頃には夏になっていたので着手が今になってしまいましたが、電子工作初心者的なメモを含めてログ。
モニターはM5Stack、CO2センサーはMH-Z14A
プロトタイプなんでM5Stackのディスプレイに出してみることにしました。適当なESP32ボードでもいいかと思ったんですが今手元にあるのがM5ぐらいだったので。ディスプレイは電力食うのでたぶんあんまり長時間稼働させるには向いてないんですけど、M5は小さいバッテリーも積んでるし、とにかくらくちんなので。
MH-Z14A NDIR CO2 SENSOR FOR CARBON DIOXIDE DETECTION--Winsen
CO2センサーは色々世の中に出てるんですが、WINSENのMH-Z14Aという奴にしました。0-10000rpmまで対応してる。Amazonとかでも売ってますがお高い。AliExpressで15ドルぐらい。簡易温度計も積んでます。(余談ですが、結構アバウト。市販の温度計と合わせてみて、DHT12使ったほうが精度が良かったのでわたしは温度はDHT12をつないで取るようにしました)
Aruduino IDE使ってCで書いた
世の中には色々参考記事が転がってるのでそれを参考にして色々やってたんですが、
- M5StackのプログラミングはUIFlow(Python)ではなくArduino IDEを使った
- UIFlow便利なんですが、よくコードがアップデートされないことがあって困った
- MH-Zシリーズのライブラリを作ってくれてる人がいたので使わせてもらった
という感じ。Pythonの方が慣れてるから早いんですが、まあ別にそんな難しいコードでもないので。
最初、 データシート とにらめっこしてあーでもないこーでもない...とやってたんですが、良く出来てるライブラリがあったのでこれをそのまま利用。Arduino IDEからもそのまま検索できるのでらくらくです。
Ambientを使ってビジュアライズ
で、これらをAmbient使ってビジュアライズしました。
M5StackはコアがESP32なのでWi-Fi積んでます。つまり通信簡単にできるので、各種IoTサービスがそのまま使えますね。データを蓄積していくと、やはり一点のデータでみるだけでは見えてこない変化が見えてくるので、ビジュアライズすることは非常に大事です。例えば換気するとCO2濃度がもりもりさがりますし、センサーを窓に持っていくと外気温に近くなります。湿度もごりごり変化する。
Ambientさんは、データの蓄積を1年しか行ってくれませんがそれでも個人で遊ぶには十分すぎるほど。ひとまずは、このまましばらく運用してみようかなと思っております。1週間、1ヶ月とデータ蓄積していくとたぶん面白い。ついでに外気温も別のセンサーでとれるとベターかもしれませんね。
ただグラフ化する以上のこと、例えば特定の値になったらWebhook送るみたいなのはできないので、そこまで活用できるようになったら他のも検討してみようかなという感じ。
以下、最終的なソース。抜粋。ややこしいのはライブラリがやってくれてるので簡単ですね。
#include <M5Stack.h> #include <WiFi.h> #include <Wire.h> #include <SoftwareSerial.h> #include <MHZ.h> #include <Ambient.h> // UART2(16, 17)を使う MHZ co2(16, 17, 2, MHZ14A); // Wi-FiはAmbient使うのに必要なので WiFiClient client; const char* ssid = "SSID"; const char* password = "SSIDPASS"; // Ambientのキーとか Ambient ambient; unsigned int channelId = 1234; const char* writeKey = "WRITE_KEY"; void setup(){ M5.begin(); Wire.begin(); M5.Power.begin(); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); } ambient.begin(channelId, writeKey, &client); pinMode(2, INPUT); delay(100); // プレヒートは必ず行う。じゃないと安定しない if (co2.isPreHeating()) { while (co2.isPreHeating()) { delay(5000); } } delay(2000); } void loop() { int ppm_uart = co2.readCO2UART(); if (ppm_uart > 0) { M5.Lcd.print("CO2 PPM: "); M5.Lcd.println(ppm_uart); ambient.set(1, ppm_uart); int temperature = co2.getLastTemperature(); M5.Lcd.print(", Temp: "); M5.Lcd.println(temperature); ambient.set(2, temperature); ambient.send(); } delay(60000); }
ハマりどころ
普段Web周りのコードしか書いてないので、こういうローレベルデバイス扱うと??ってなることがよくあったので個人的なメモです。こういうのって、正直コードは全然難しくないんですけど、コードは論理的に正しいのにちゃんと動かない...みたいなのが多発するので、マシンの気持ちになることがとても大事でした。
- デバイスは安定するのに時間がかかる
- 例えば今回だとCO2センサーのプレヒートは必ず必要
- これ終わらないとほとんど正常な値でない データシートにも書いてある
- 製品によってはエージングが必要だったりもする
- 異常な値出ることもあるので適切にフィルタリングする
- 自然界の出来事を読むセンサーなので変な検出することもある
- データの取得時間が短かすぎると異常値ばかり返ってくることもある
- 困ったら助けてインターネット
?となったらデータシート読むことが大事です。あとはセンサーの仕組みを調べてみるとかもヒントになるかも。
電子系は全然触れてこなかったのでブレッドボードの使い方知っててLチカできるってレベルだったのが、ひとまずデータシート読んだりArduinoで色々組んだりできるようになったので、もうちょっと遊んでみようと思います。ESP32系のマイコン、Wi-Fi積んでるのがめちゃくちゃ優秀すぎて恋しそう。
ひとまず、次のステップとして
- 外気温計の増設
- ユニバーサル基板とスズメッキ線とかでなんかいい感じにコンパクトにする
- ブレッドボードから外したい
- ESP32系の汎用機に入れ替えて24時間運用する (M5Stackは別の開発で使いたい)
- 小型ディスプレイつないで常時表示はしておきたい
- Ambientから別のサービスに移行するか自作してCO2アラート、湿度アラートを作る
とかとかそのへんができると便利だなーと思っております。