modalsoul’s blog

これは“失敗”と呼べるかもしれないが、ぼくは“学習体験”と呼びたい

M5StickC PlusとMH-Z19Bで二酸化炭素濃度を計測する

WFHだとオフィスと違い空間が狭く空調が効いていないので、どうしても二酸化炭素濃度が上昇しがち

CO₂センサーガジェットが色々リリースされているけれど、CO₂センサーモジュールとM5StickC PlusでCO₂センサーを作ってみた。

MH-Z19B

非分散型赤外線(NDIR)方式のCO₂センサー(ただし、これはMH-Z19Bのfake品らしい)

そこそこ安かったし、動作は問題なさそうなので気にしない

構成

M5StickC PlusとMH-Z19Bで計測し、Googleスプレッドシートに記録する。

実装

Googleスプレッドシート

M5StickC Plusからjsonを受け、受信した日時とppm値をスプレッドシートに追記していく。

function doPost(e) {
  var ss  = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName('シート1');
  var PostData = JSON.parse(e.postData.contents);
  var date = new Date();
  var now = Utilities.formatDate( date, 'Asia/Tokyo', 'yyyy/MM/dd HH:mm:ss');
  sheet.appendRow([now, PostData.co2]);
  return ContentService.createTextOutput('OK');
}

M5StickC Plus

配線

f:id:modal_soul:20210616220155j:plain

MH-Z19Bに付属したケーブルを切断しジャンパケーブルと接続している。

M5StickC Plus MH-Z19B
5V V+(緑)
GND V-(青)
G26 Rx(黒)
G0 Tx(黄)

ライブラリ

github.com

コード

計測は5分間隔。計測したCO₂濃度はM5StickC Plusのディスプレイにも表示する。1

#include <HTTPClient.h>
#include <M5StickCPlus.h>
#include <MHZ19_uart.h>
#include <WiFiMulti.h>

#define INTERVAL 300000
#define RX_PIN 0
#define TX_PIN 26

const char* ssid     = "<SSID>";
const char* password = "<PASSWORD>";
String url = "https://script.google.com/macros/s/****/exec";
MHZ19_uart myMHZ19;
WiFiMulti wifiMulti;

void setup() {
  M5.begin();
  myMHZ19.begin(TX_PIN, RX_PIN);
  myMHZ19.setAutoCalibration(true);
  wifiMulti.addAP(ssid, password);
  M5.Lcd.setTextColor(WHITE);
  M5.Lcd.setTextSize(2);
  M5.Lcd.setRotation(1);
}

void updateDisplay(int ppm) {
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setCursor(10, 10);
  M5.Lcd.printf("CO2: %d ppm\n", ppm);  
}

void storePPM(int ppm) {
  if((wifiMulti.run() == WL_CONNECTED)) {
    HTTPClient http;  
    http.begin(url);
    http.addHeader("Content-Type", "Content-Type: application/json");
    int httpCode = http.POST("{\"co2\":\"" + String(ppm) + "\"}"); 
    if(httpCode <= 0) {
      M5.Lcd.printf("Store failed, error:%s\n", http.errorToString(httpCode).c_str());
    }
  }
}

void loop() {
    int ppm;
    ppm = myMHZ19.getPPM();
    updateDisplay(ppm);
    storePPM(ppm);
    delay(INTERVAL);
}

計測結果

f:id:modal_soul:20210618003950p:plain

絶対値の精度はいまいち不明だが、傾向は把握できたのでOK