diy/아두이노

이산화탄소 측정기(MH-Z14) 만들기 2

do121 2022. 10. 7. 11:20
#include "SoftwareSerial.h"
#include "U8glib.h"


U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE);


const int pwmPin = 6; // digital pin //mh-z14 결과값을 가져올 핀 지정

const int OUTPUT_PIN = 8;//reset


const long samplePeriod = 10000L;

long lastSampleTime = 0;

unsigned long starttime_esp = 0;
unsigned long sampletime_esp = 600000; // 10분 600,000 TIME BETWEEN MEASURES AND UPDATES

unsigned long starttime_reset = 0;
unsigned long sampletime_reset = 43200000; // 12시간 마다 reset

String apiKey = "";//자신의 thingspeak 채널의 Read API key 입력

String response1 = "";
String ip = "";
String cmd = "";

SoftwareSerial esp8266(2, 3); //TX/RX 설정, esp8266 객체생성
#define DEBUG true



String sendData(String command, const int timeout, boolean debug) {
  String response = "";
  esp8266.print(command); 
  long int time = millis();

  while ((time + timeout) > millis()) {
    while (esp8266.available()) {
      char c = esp8266.read(); 
      response += c;
    }
  }
  if (debug) {
    Serial.print(response);
    response;
  }

  return response;
}

void dis_oled2(String msg1, String msg2 = "", String msg3 = "", String msg4 = "", String msg5 = "") {

  int idx[] = {10, 23, 36, 49, 62};

  String str[5];

  str[0] = msg1;

  str[1] = msg2;

  str[2] = msg3;

  str[3] = msg4;

  str[4] = msg5;

  u8g.firstPage();

  do {

    u8g.setFont(u8g_font_unifont);

    for (int i = 0; i < 5; i++) {

      u8g.setPrintPos(0, idx[i]);

      u8g.print(str[i]);

    }

  } while (u8g.nextPage());

}

void setup() {
  dis_oled2("init ... ", "", "", "", "");

  Serial.begin(9600);
  pinMode(pwmPin, INPUT_PULLUP);


  //reset 설정
  digitalWrite(OUTPUT_PIN, HIGH);
  pinMode(OUTPUT_PIN, OUTPUT);

  /*소프트웨어 시리얼 시작*/
  esp8266.begin(9600);
  /*AT Command 이용*/
  dis_oled2("esp reset", "", "", "", "");
  sendData("AT+RST\r\n", 2000, DEBUG); //reset module
  dis_oled2("esp dual mode", "", "", "", "");
  sendData("AT+CWMODE=1\r\n", 1000, DEBUG); //dual mode로 설정
  dis_oled2("esp connecting", "", "", "", "");

  sendData("AT+CWJAP=\"router_name\",\"password\"\r\n", 5000, DEBUG); //사용할 공유기 설정

  delay(5000);

  ip = sendData("AT+CIFSR\r\n", 2000, DEBUG);
  ip.replace("AT+CIFSR", "");
  ip.replace("\r", "");
  ip.replace("\n", "");
  ip.replace("OK", "");

  dis_oled2(ip);
  delay(300);


  }

}

void loop() {
  long now = millis();
  int ppmPWM;
  if (Serial.available()) {
    String inString = Serial.readString();
    Serial.print(inString);
    esp8266.print(inString);

  }
  if (esp8266.available()) {
    char instr2 = esp8266.read();

    Serial.write(instr2);
    Serial.print(instr2);
  }
  if (now > lastSampleTime + samplePeriod) {
    lastSampleTime = now;

    ppmPWM  = readPPMPWM();
    //Serial.print(ppmV);
    //Serial.print("\t");
    Serial.println(ppmPWM);
    dis_oled2("CO2 PPM(800)", "now : " + String(ppmPWM) + "PPM", "", "", ip);
  }

  if ((millis() - starttime_esp) > sampletime_esp) {
    sendthings(ppmPWM);
    starttime_esp = millis();
  }

  //reset every 12hr
  if ((millis() - starttime_reset) > sampletime_reset) {
    digitalWrite(OUTPUT_PIN, LOW);
    starttime_reset = millis();
  }

}


int readPPMPWM() {
  while (digitalRead(pwmPin) == LOW) {}; // wait for pulse to go high
  long t0 = millis();
  while (digitalRead(pwmPin) == HIGH) {}; // wait for pulse to go low
  long t1 = millis();
  while (digitalRead(pwmPin) == LOW) {}; // wait for pulse to go high again
  long t2 = millis();
  long th = t1 - t0;
  long tl = t2 - t1;
  long ppm = 5000L * (th - 2) / (th + tl - 4);
  while (digitalRead(pwmPin) == HIGH) {}; // wait for pulse to go low
  delay(10); // allow output to settle.
  return int(ppm);
}

void sendthings(int pwm) {

  // TCP 연결
  Serial.println("send data to thingspeak");
  String cmd = "AT+CIPSTART=\"TCP\",\"";
  cmd += "184.106.153.149"; // api.thingspeak.com 접속 IP
  cmd += "\",80";           // api.thingspeak.com 접속 포트, 80
  esp8266.println(cmd);


  if (esp8266.find("Error")) {
    Serial.println("AT+CIPSTART error");
    return;
  }


  // GET 방식으로 보내기 위한 String, Data 설정
  String getStr = "GET /update?api_key=";
  getStr += apiKey;
  getStr += "&field4="; //필드명 지정
  getStr += String(pwm);
  getStr += "\r\n\r\n";

  // Send Data
  cmd = "AT+CIPSEND=";
  cmd += String(getStr.length());
  esp8266.println(cmd);
  Serial.println(getStr);
  if (esp8266.find(">")) {
    esp8266.print(getStr);
  }
  else {
    esp8266.println("AT+CIPCLOSE");
    // alert uesp8266
    Serial.println("AT+CIPCLOSE");
  }


}