M5Stack + MH-Z19B でCO2モニタ作成(ソースコードあり)

テレワークで籠っているとパフォーマンスが落ちがちで、どうやら室内のCO2濃度が影響しているらしいのでモニタリングしたい。
でもAmazonで測定器調べると妙に高い。センサだけなら安い。
というわけで自作してみました

準備

用意したものは以下

M5Stack

モニタ、バッテリ、Wifi、その他諸々接続済なArduino互換IoTモジュール。4,000円くらい。
手軽にIoTや電子工作やるなら Raspberry pi よりもオススメかも。

M5Stack Basic
スイッチサイエンス

( 最近 M5Stack Core2 という後継が出たみたいだけどどこも売り切れ…。)

MH-Z19B

比較的安価なCO2計測モジュール。それでもAmazonで3,000円。AliExpressで2,000円するけど…。
AmazonのはAliExpressからの輸入業者っぽいのでAliで直接買った方がいいかも。
※Amazonで買う場合は「お届け日」を要確認。一月以上かかることも

何も付いていないもの、コネクタ+ケーブル付きのもの、ピンヘッダ付きのものがあるが、
AliExpressで買うならピンヘッダ付きのものがオススメ。
(コネクタ+ケーブル付きのものを買ったので、下記ジャンパーピンのコネクタが別途必要になった)

ジャンパーピンのコネクタ(オス)とハウジング

コネクタ+ケーブル付きのMH-Z19Bの場合、コネクタをM5Stackに接続するために必要。
こういうセットを買うか……

620pcs Dupont Connector 2.54mm, Dupont Cable Jumper Wire Pin Header Housing Kit, Male Crimp Pins+Female Pin Terminal Connector

もしくは秋月電子の通販なら必要分だけ購入できる

作業

MH-Z19Bケーブルへのコネクタピン取り付け

MH-Z19B付属のコネクタの端子がブレッドボードの規格でないことを届いてから知ったので追加購入。
被膜剥いてコネクタのツメ4か所を圧着してハウジングをかぶせる。

必要なのは赤(Vin)、黒(GND)、青(TX)、緑(RX)のケーブルなのでとりあえずソコだけ。
参考: データシート

ググるとなんか専用のペンチ使ってるガチ勢ばかりでしたが、普通のラジペンでもまあ大丈夫でした

M5Stackとの配線

以下のように接続する。ブレッドボードを使う必要がなく、配線が楽でうれしい。
* 赤(Vin): 5V
* 黒(gnd): G
* 青(tx): 17ピン
* 緑(rx): 16ピン

tx/rxはコード上の番号指定に合わせること(16-17ピンはサンプルコード準拠)。
あと、M5Stackは画面更新のたびにジッジッ鳴いてうるさいが、25ピンとGNDを短結すると収まる(何でやねん)

コーディング

今回はArduino IDEで開発。よってC++。
以下が得られた知見

  • MH-Z19Bのためのライブラリが提供されている。サンプルコードもある
  • C++とかいうレガシー言語だとCollection周りが貧弱すぎてしんどい。Kotlin in Arduinoが欲しい……
  • 単純な線グラフの逐次描画は TFT_eSprite でスプライトを使って、
    右端の一列に drawPixel して scroll(-1, 0) で左に送って更新していくのが簡潔で描画も軽い。
    ググるとよく出てくる M5.Lcd のdraw系で頑張るのは処理が面倒なうえ描画も遅い

コード

画面上部にCO2センサ値を、下部にセンサ値の推移グラフを表示するコードです。
意外とそこらのサイトにシンプルなやつが転がってなかったのでほぼ自前。
1000ppmを超えたら要換気らしいので、それ以上の領域を黄色く表示しています

#include <M5Stack.h>
#include "MHZ19.h"                                        

#define RX_PIN 16
#define TX_PIN 17
#define BAUDRATE 9600

#define DELAY 2000
#define GRAPH_MAX 3000
#define GRAPH_MIN 1
#define GRAPH_X 0
#define GRAPH_Y 40
#define GRAPH_HEIGHT 200
#define GRAPH_WIDTH 320
#define GRAPH_WARN_HEIGHT 132

MHZ19 myMHZ19;
HardwareSerial mySerial(1);
TFT_eSprite graph = TFT_eSprite(&M5.Lcd);

void setup(){
    M5.begin();
    M5.Lcd.setTextSize(3);
    Serial.begin(9600);

    mySerial.begin(BAUDRATE, SERIAL_8N1, RX_PIN, TX_PIN);
    myMHZ19.begin(mySerial);
    myMHZ19.autoCalibration();

    graph.setColorDepth(8);
    graph.createSprite(GRAPH_WIDTH, GRAPH_HEIGHT + 1);
    graph.fillSprite(TFT_BLACK);
    graph.fillRect(0, 0, GRAPH_WIDTH, GRAPH_WARN_HEIGHT, M5.Lcd.color565(152, 152, 0));
    graph.pushSprite(GRAPH_X, GRAPH_Y);
}

void loop(){
    M5.Lcd.setCursor(0, 0);

    int CO2 = myMHZ19.getCO2();
    M5.Lcd.print("CO2: ");
    M5.Lcd.print(CO2);
    M5.Lcd.println("ppm ");

    graph.pushSprite(GRAPH_X, GRAPH_Y);
    graph.scroll(-1, 0);
    graph.fillRect(GRAPH_WIDTH -1, 0, GRAPH_WIDTH, GRAPH_WARN_HEIGHT, M5.Lcd.color565(152, 152, 0));
    int p = CO2 / (GRAPH_MAX / GRAPH_HEIGHT);
    graph.drawPixel(GRAPH_WIDTH -1, GRAPH_HEIGHT - p, TFT_WHITE);

    delay(DELAY);
}
  • MH-Z19B は気温も取得できるんですが、整数値のうえ看過できないレベルの誤差があるので表示から除外しました。
    26℃台の室内で30℃になるレベル。起動直後からコレなので本体熱拾ってるわけでもなさそう

    • おとなしく別途 DHT-11 でも使った方がマシ
    • もしくはハズレ個体引いただけ…?

MH-Z19Bのキャリブレーション

屋外などで20分放置したりして基準値をリセットする必要があるっぽい?
参考: mh-z19bのZEROキャリブレーションの方法 – Qiita

コードの中で autoCalibration() 呼んでるから不要かもしれない?

表示

以下のようになりました。かなり簡単に基準値超えるのでマメな換気が大事。

(↑窓ふたつ開けたらあっという間に濃度が下がった)

掛かった費用と手間を考えると市販品のセンサ買った方が楽なのだけど
自作するとCO2濃度をフックしてSlackに通知出せたり、Ambientでロギング出来たりするのでオススメ

スポンサーリンク
レクタングル(大)
レクタングル(大)