LINE通知機能付きCO2濃度検出器をM5stackで作ってみた(博多弁編)

大学3年の研究室配属直後に，自由工作課題として制作。2020年度というのもあり，新型コロナウイルス関連で制作してみました。電子工作初心者でも，かんたんに制作できるデバイスを用いているのでおススメです。

**準備するもの**
* M5stack
    BasicでももちろんGrayでも制作できるはずです。M5stackは電子工作初心者によく勧められているArduino IDEで開発でき，参考資料が多くあります。またカラーディスプレイ，Wi-Fi・Bluetooth通信，スピーカなど多様な機能が搭載されています。詳しくはこちらの記事から
『[人気急上昇中のマイコンモジュール「M5Stack」とは？特徴や使い方をわかりやすく紹介！](https://deviceplus.jp/mc-general/what-is-m5stack/)』
* CO2センサ
　私が使用したのは[**Almencla 二酸化炭素センサー MH-Z19**](https://www.amazon.co.jp/Almencla-%E4%BA%8C%E9%85%B8%E5%8C%96%E7%82%AD%E7%B4%A0%E3%82%BB%E3%83%B3%E3%82%B5%E3%83%BC-MH-Z19%E5%AE%A4%E5%86%85%E7%A9%BA%E6%B0%97%E8%B3%AA%E3%83%A2%E3%83%8B%E3%82%BF%E3%83%BC-%E5%86%85%E8%94%B5%E6%B8%A9%E5%BA%A6%E8%A3%9C%E5%84%9F/dp/B07XR6CT3X/ref=pd_sbs_421_2/356-5930991-4692902?_encoding=UTF8&pd_rd_i=B07XR6CT3X&pd_rd_r=40a675ed-815d-4270-b4c0-5b6ad485421d&pd_rd_w=VMqrN&pd_rd_wg=ZT0ty&pf_rd_p=c295905f-82f9-4d73-8142-c393a4211258&pf_rd_r=BX2NRX0HASYK1AGJWV94&psc=1&refRID=BX2NRX0HASYK1AGJWV94)。2023年1月21日現在は，僕が購入したときの2倍くらいの価格になってるので，他の検討をお勧めします。
* 開発環境：Arduino IDE
M5stackの開発にはArduino IDEの開発環境が必要です。インストール方法などはこちらから
『[Arduino IDEのインストールと設定 (Windows, Mac, Linux対応)](https://www.indoorcorgielec.com/resources/arduinoide%E8%A8%AD%E5%AE%9A/arduino-ide%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%A8%E8%A8%AD%E5%AE%9A/)』
* ジャンパワイヤー
* +αで
センサとM5stackの通信を安定化させ長期化させたいならば，はんだ付けする必要がある場合が出てきます。

# はじめに概要紹介
## 動作概要紹介
![スライド4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3117483/12c14bf1-9e3d-18ef-2093-1aa3fbb44ee8.jpeg)

* CO2濃度を随時センサから取得し，M5stack画面に表示させる
* CO2濃度が複数ある基準値を超えた場合，Wi-Fiを通じてLINEに通知される
※初心者作成図なので，誤りのある解釈となっているかもしれません

## 完成図
![スライド9.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3117483/0c492b6c-78bb-64c7-536a-6d637d413442.png)

## 動作フローチャート
![スライド5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3117483/e40ce14c-b382-34b5-33b2-b6530110af0d.jpeg)

* CO2濃度基準値は厚生労働省や文科省の基準に準じています
* 福岡出身のアイデンティティをちょこちょこ出していく

# 制作
## 回路図
![スライド6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3117483/5fbb4a74-af4f-01ed-cfb7-52d43d3de3b1.jpeg)
　上記の回路図を示します。Ｍ5stackは下画像のように接続子の対応が表記されているので，わかりやすいです。
![IMG_6464.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3117483/5cd4b2fb-a6a7-a0f5-4e8e-14efbbae3d9a.jpeg)

## Wi-Fi環境接続
M5stackを使用する室内Wi-Fi環境に接続します。私はこちらの記事をもとに作成しました。『[ESP32 Wifi経由でIFTTTへ接続しLINEへ通知](https://thousandiy.wordpress.com/2017/10/17/esp32_ifttt_line/)』
LINEへの通知は，多少のメールアドレス等の登録が必要となっています。添付記事を参考にしてみてください。
~~~Arduino:Wi-Fi環境設定
#include <MHZ19_uart.h>
#include <M5Stack.h>
#include <WiFi.h>
#include <WiFiClient.h>

const int rx_pin = 16; //Serial rx pin no
const int tx_pin = 17; //Serial tx pin no
MHZ19_uart mhz19;
//接続する室内Wi-FiのIDとパスワード
const char* ssid     = "NNN~NNN";
const char* password = "XXX~~XXX";

String makerEvent = "co2alert2"; // Maker Webhooks
String makerKey = "〇〇〇・・・〇〇〇"; // Maker Webhooks

const char* server = "maker.ifttt.com";  // Server URL
WiFiClient client;

bool checkWifiConnected() {
  // attempt to connect to Wifi network:
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    // wait 1 second for re-trying
    delay(1000);
  }

  Serial.print("Connected to ");
  Serial.println(ssid);
  return true;
}

void send(String value1, String value2, String value3) {
  while (!checkWifiConnected()) {
    Serial.print("Attempting to connect to WiFi");
    WiFi.begin(ssid, password);
  }

  Serial.println("\nStarting connection to server...");
  if (!client.connect(server, 80)) {
    Serial.println("Connection failed!");
  } else {
    Serial.println("Connected to server!");
    // Make a HTTP request:
    String url = "/trigger/" + makerEvent + "/with/key/" + makerKey;
    url += "?value1=" + value1 + "&value2=" + value2 + "&value3=" + value3;
    client.println("GET " + url + " HTTP/1.1");
    client.print("Host: ");
    client.println(server);
    client.println("Connection: close");
    client.println();
    Serial.print("Waiting for response "); //WiFiClientSecure uses a non blocking implementation

    int count = 0;
    while (!client.available()) {
      delay(50); //
      Serial.print(".");
    }
    // if there are incoming bytes available
    // from the server, read them and print them:
    while (client.available()) {
      char c = client.read();
      Serial.write(c);
    }

    // if the server's disconnected, stop the client:
    if (!client.connected()) {
      Serial.println();
      Serial.println("disconnecting from server.");
      client.stop();
    }
  }
}
~~~

## CO2濃度取得＆稼働！
~~~
void setup() {
  //Initialize serial and wait for port to open:
  //Serial.begin(115200);
  mhz19.begin(rx_pin, tx_pin);
  mhz19.setAutoCalibration(false);

  Serial.println("MH-Z19 is warming up now.");
  delay(3 * 1000); //
  
  M5.begin();
  M5.Lcd.setBrightness(100);
  M5.Lcd.fillScreen(WHITE);

  M5.Lcd.setCursor(0,0);
  M5.Lcd.setTextColor(BLACK,WHITE);
  M5.Lcd.setTextSize(4);
  M5.Lcd.print("CO2");

   WiFi.begin(ssid, password);
  while (!checkWifiConnected()) {
    WiFi.begin(ssid, password);
  }
}

int orange = 0;
int red = 0;
  
void loop() {

  int co2ppm = mhz19.getCO2PPM();
  
  M5.Lcd.setCursor(48,40);
  M5.Lcd.setTextSize(5);
  if(co2ppm > 10){
      M5.Lcd.fillRect(0,40,270,50,WHITE);
      M5.Lcd.fillRect(150,0,150,40,WHITE);
    if(co2ppm < 1000){
      M5.Lcd.setTextColor(GREEN,WHITE);//白地に緑色の文字
      M5.Lcd.print(co2ppm);//取得したCO2濃度値の表示
      M5.Lcd.print("ppm");//文字列"ppm"を表示
      orange = red = 0;
      M5.Lcd.drawJpgFile(SD,"/goodair.jpg",0,90,320,150,0,90);//SDカードに保存している"goodair.jpg"を表示
      }
    else if(co2ppm < 1500){
      M5.Lcd.setTextColor(GREENYELLOW,WHITE);
      M5.Lcd.print(co2ppm);
      M5.Lcd.print("ppm");
      orange = red = 0;
      M5.Lcd.drawJpgFile(SD,"/normalair.jpg",0,90,320,150,0,90);
      }
    else if(co2ppm < 3000){
      M5.Lcd.setTextColor(ORANGE,WHITE);
      M5.Lcd.print(co2ppm);
      M5.Lcd.print("ppm");
      M5.Lcd.drawJpgFile(SD,"/badair.jpg",0,90,320,150,0,90);
      red = 0;
      if(orange == 0){
        send("CO2Alert!!","Over1500!", "VENTILATE."); //任意の文字列3つ
        M5.Lcd.setCursor(150,0);
        M5.Lcd.setTextColor(ORANGE,WHITE);
        M5.Lcd.setTextSize(4);
        M5.Lcd.println("send");
        orange = 1;
        }
      }
    else{
      M5.Lcd.setTextColor(RED,WHITE);
      M5.Lcd.print(co2ppm);
      M5.Lcd.print("ppm");
      M5.Lcd.drawJpgFile(SD,"/worstair.jpg",0,90,320,150,0,90);
      if(red == 0){
        send("CO2Alert!!!!!","Over3000!!!!!", "VENTILATE!!!!!"); //任意の文字列3つ
        M5.Lcd.setCursor(150,0);
        M5.Lcd.setTextColor(ORANGE,WHITE);
        M5.Lcd.setTextSize(4);
        M5.Lcd.println("send");
        red = 1;
        }
      }
    }

    delay(1000);

}
~~~