Home IoT Hub Series · 12

[12편] 머리가 멍한 이유가 공기 때문인지 확인하자 - CO2와 미세먼지 공기질 노드

[12편] 머리가 멍한 이유가 공기 때문인지 확인하자 - CO2와 미세먼지 공기질 노드 대표 이미지
시스템 아키텍처 및 데이터 파이프라인 안내
이 글은 2편: 두뇌 만들기에서 구축한 중앙 NodeMCU 서버에 연결되는 우리집 IoT 허브 구성 문서입니다. MH-Z19B와 PMS5003이 공기질 두 축을 동시에 보내 환기와 공기청정기 판단의 근거를 만듭니다. 수집된 데이터는 로컬 무선망 IoT_Hub_Net을 통해 중앙 서버의 13번 CO2와 14번 PM2.5 슬롯(/set?no13=CO2&no14=PM2.5)을 갱신하며, 20채널 스마트홈 통합 컨트롤러의 판단 근거로 사용됩니다.

MH-Z19B와 PMS5003을 함께 사용해 실내 공기질을 측정합니다. MH-Z19B는 CO2 농도를, PMS5003은 PM2.5/PM10 미세먼지 농도를 측정합니다. 둘 다 UART 직렬통신 센서이므로 SoftwareSerial로 읽고, 13번 슬롯에는 CO2, 14번 슬롯에는 PM2.5 값을 보냅니다.

준비물과 가격

부품수량개당 가격
Wemos D1 Mini1개2,000원
MH-Z19B CO2 센서1개20,000원
PMS5003 미세먼지 센서1개15,000원
점퍼 와이어8개
합계37,000원
이 편이 시리즈에서 가장 비싸다. CO2 센서가 2만 원인데, MH-Z19B 말고 더 저렴한 CCS811(TVOC+eCO2, 5천 원)을 써도 된다. 다만 CCS811은 상대값이라 정확도가 떨어진다.

핀 연결

[12편] 머리가 멍한 이유가 공기 때문인지 확인하자 - CO2와 미세먼지 공기질 노드 배선도
센서/모듈보드 연결
VCCVU (5V)
GNDGND
TXD2 (GPIO4)
RXD3 (GPIO0)
VCCVU (5V)
GNDGND
TXD6 (GPIO12)
RXD7 (GPIO13) ← PMS5003 RX는 안 써도 되지만 연결해둠
MH-Z19B와 PMS5003 모두 5V 전원이 필요하다. D1 Mini의 VU 핀(USB 5V)에서 둘 다 가져온다. TX/RX는 크로스 연결: 센서 TX → D1 Mini RX 핀.

선행 작업

라이브러리검색어
MH-Z19MH-Z19
PMS LibraryPMS Library

전체 코드

[12편] 머리가 멍한 이유가 공기 때문인지 확인하자 - CO2와 미세먼지 공기질 노드 - 전체 코드
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <SoftwareSerial.h>
#include <MHZ19.h>
#include <PMS.h>

const char* ssid     = "IoT_Hub_Net";
const char* password = "iothub1234";
const char* hubURL   = "http://192.168.1.1";

#define MHZ_RX  4   // D2
#define MHZ_TX  0   // D3
#define PMS_RX  12  // D6
#define PMS_TX  13  // D7
#define INTERVAL 30000

SoftwareSerial mhzSerial(MHZ_RX, MHZ_TX);
SoftwareSerial pmsSerial(PMS_RX, PMS_TX);
MHZ19 mhz;
PMS pms(pmsSerial);
PMS::DATA pmsData;

void setup() {
  Serial.begin(115200);
  mhzSerial.begin(9600);
  pmsSerial.begin(9600);
  mhz.begin(mhzSerial);
  pms.passiveMode();

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to IoT_Hub_Net");
  while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
  Serial.println("\nConnected!");
  Serial.println("Sensors warming up (180s)...");
  delay(180000); // CO2 센서 예열 3분
  Serial.println("Ready.");
}

void loop() {
  // CO2 읽기
  int co2 = mhz.getCO2();
  if (co2 < 0) co2 = 0;

  // 미세먼지 읽기
  pms.wakeUp();
  delay(30000); // PMS5003 안정화 대기
  pms.requestRead();
  int pm25 = 0;
  if (pms.readUntil(pmsData)) {
    pm25 = pmsData.PM_AE_UG_2_5;
  }
  pms.sleep();

  Serial.printf("CO2: %d ppm, PM2.5: %d ug/m3\n", co2, pm25);

  WiFiClient client; HTTPClient http;
  String url = String(hubURL) + "/set?no13=" + String(co2)
             + "&no14=" + String(pm25);
  http.begin(client, url);
  int code = http.GET(); http.end();
  Serial.print("HTTP "); Serial.print(code); Serial.println(" -> " + url);
  Serial.println();

  delay(INTERVAL);
}

업로드 및 확인

업로드 후 3분 정도 예열합니다. 시리얼 모니터에 CO2: 620 ppm, PM2.5: 35 ug/m3 같은 값이 출력되면 정상입니다. 두뇌 OLED의 13·14번 슬롯도 함께 확인합니다. 방 안에서 숨을 길게 내쉬면 CO2 값이 빠르게 올라가는 것을 볼 수 있습니다.

시리얼 모니터

업로드가 끝나면 Arduino IDE의 툴 → 시리얼 모니터를 열고 보드레이트를 115200으로 맞춥니다. 다음은 정상 동작을 확인하기 위한 시리얼 모니터 출력 예시입니다. 이 로그는 실제 캡처가 아니라, MH-Z19B와 PMS5003 값이 13번·14번 슬롯으로 들어가는지 확인하는 예시입니다.

[BOOT] Home IoT Node #12 - CO2 and PM2.5
[UART] MH-Z19B ready, PMS5003 wake
[SENSOR] co2=742ppm pm2_5=11ug/m3
[FILTER] fan_warmup=30s, abc=enabled
[HTTP] GET /set?no13=742&no14=11
[HUB] 200 OK - slots no13/no14 updated
[POWER] peak current OK, next sample in 300000 ms
  • Connected 또는 connected가 보이면 Wi-Fi 연결 단계는 통과한 것입니다.
  • HTTP 200 또는 200 OK가 보이면 두뇌 서버에 값이 전달된 것입니다.
  • 값이 갱신되지 않으면 먼저 URL의 슬롯 번호와 센서 배선을 함께 확인합니다.

안 될 때 체크포인트

증상원인해결
CO2가 0만 나옴TX/RX 반대MH-Z19B TX를 D2(RX)에, RX를 D3(TX)에 크로스 연결했는지 확인합니다.
PM2.5가 항상 0PMS5003 슬립/웨이크 타이밍PMS5003은 wakeUp 후 30초 정도 기다려야 합니다. 코드는 이 대기 시간을 반영했습니다.
두 센서 모두 안 읽힘SoftwareSerial 충돌ESP8266은 SoftwareSerial이 불안정할 수 있습니다. 하나는 HardwareSerial로 옮기거나 읽기 간격을 늘립니다.

현장 추가 체크포인트

이 노드는 코드만 보면 짧아 보일 수 있지만, 실제 집에 붙이면 센서 위치·전원·무선망·노이즈 때문에 값이 쉽게 흔들립니다. 아래 항목은 두뇌 서버에 잘못된 판단 근거가 들어가지 않도록 현장에서 먼저 점검할 내용입니다.

증상가능한 원인현장 해결 방법
CO2가 계속 400ppm 근처에만 있음ABC 자동보정이 밀폐된 방을 외기 기준으로 잘못 보정함창문을 자주 열지 않는 공간은 ABC를 끄고, 충분히 환기한 뒤 수동 기준값을 잡습니다.
PM2.5가 항상 0 또는 너무 낮음PMS5003 팬 웨이크업 시간이 부족하거나 흡입구가 막힘측정 전 30초 이상 팬을 돌리고, 흡입·배출구 앞을 케이스로 막지 않습니다.
두 UART 센서가 번갈아 실패함ESP8266 SoftwareSerial 두 개를 동시에 안정적으로 처리하기 어려움읽기 순서를 분리하고 간격을 늘리거나, 장기 운영은 ESP32처럼 UART가 넉넉한 보드로 옮깁니다.
요리할 때 먼지값이 과하게 튐기름 입자와 수증기가 PMS5003 내부에 직접 유입됨주방 직상부를 피하고, 짧은 피크는 로그로 남기되 알림은 이동평균 기준으로 판단합니다.

다음 글 예고

전력 사용량은 ACS712 전류 센서로 집 전체 소비전력을 추정하는 구성입니다.

준비물: Wemos D1 Mini (2,000원), ACS712 20A (2,500원)

공기질 센서 활용 & 설치 가이드 (MH-Z19B + PMS5003)

CO2와 미세먼지는 눈에 안 보이지만 집중력·수면·건강에 직접 영향을 줍니다. 두 센서를 우리집 IoT 허브에 붙이면 '지금 환기해야 하는지'를 숫자로 알 수 있습니다.

활용 기준

  • 환기 타이밍 알림: CO2가 1000ppm을 넘으면 허브가 스마트폰으로 '창문 환기 필요' 알림을 보냅니다. 밀폐된 겨울철 방에서 특히 유용합니다.
  • 수면·집중 환경 관리: 침실 CO2가 밤새 1500ppm까지 오르면 아침에 개운하지 않습니다. 자기 전 수치를 확인해 환기 후 취침하는 것이 좋습니다. 서재는 800ppm 이하로 유지하면 집중력이 유지됩니다.
  • 요리 중 미세먼지 감시: 굽거나 튀길 때 PM2.5가 순식간에 수백 ㎍/㎥까지 치솟습니다. 주방 근처 수치로 환풍기를 언제 더 돌릴지 판단합니다.
  • 공기청정기·환풍기 자동연동: PM2.5가 '나쁨'에 들어가면 스마트플러그로 공기청정기를 켜고, 좋아지면 끄도록 허브에 규칙을 넣습니다.
  • 아이방 관리: 아이는 호흡량이 많아 미세먼지에 민감합니다. 아이방 전용 임계값을 더 엄격하게 잡아 알림받습니다.

추천 설치 장소

  • 호흡 높이: 앉았을 때 코높이인 책상 높이(바닥에서 약 1~1.5m)가 실제 마시는 공기와 가장 비슷합니다.
  • 직접 바람 피하기: 창문·환풍구·에어컨 토출구 바로 앞은 순간값이 튀어 평소 상태를 못 봅니다. 30cm 이상 떨어뜨립니다.
  • 주방 연기 직격 주의: 가스레인지 바로 위는 PMS5003 팬에 기름 연기가 쌓여 수명이 줄어듭니다. 조금 떨어진 곳에 설치합니다.
  • CO2와 먼지 배치: CO2는 사람 활동 중심(거실·침실), 먼지 센서는 외부 유입과 요리 영향을 보는 위치가 좋습니다. 둘을 같은 허브에 두되 완전 밀폐 케이스는 피해 공기가 통하게 합니다.

실전 팁 & 주의점

  • MH-Z19B 예열·ABC 보정: 전원 후 약 3분 예열해야 값이 안정됩니다. ABC(자동보정)는 하루 중 최저값을 400ppm 외기 기준으로 잡는데, 창문을 거의 안 여는 방에서는 오차가 생기니 필요시 끄고 수동 보정합니다.
  • PMS5003 팬 수명·먼지 유입: 내부 팬은 소모품(수명 약 3년)입니다. 상시 구동 대신 몇 분 간격으로만 측정하면 팬과 먼지 유입을 아껴 오래 씁니다.
  • 기준값: CO2는 1000ppm 이하 권장(1500ppm↑ 졸림·집중저하). 미세먼지는 PM2.5 '좋음' 0~15, '보통' 16~35, '나쁨' 36~75, '매우나쁨' 76㎍/㎥ 이상(국내 기준)입니다.
  • UART 2개 주의: 두 센서 모두 UART라 SoftwareSerial을 겹쳐 쓰면 데이터가 깨집니다. 하드웨어 시리얼이 여러 개인 ESP32를 쓰거나, SoftwareSerial은 한쪽만 쓰고 속도(9600bps)를 지킵니다.

자주 묻는 질문

Q. CO2가 계속 높은데 사람이 문제인가요? 사람 호흡이 주원인입니다. 인원이 많거나 문을 닫아두면 빠르게 오릅니다. 10분 환기로 대부분 400~600ppm으로 떨어집니다.

Q. 미세먼지는 어느 수치부터 조심하나요? PM2.5 기준 36㎍/㎥부터 '나쁨'입니다. 이때부터 창문을 닫고 공기청정기를 가동합니다. 76 이상이면 실외활동도 자제가 좋습니다.

Q. 두 값이 서로 안 맞을 때는요? CO2는 환기(창문), 미세먼지는 여과(공기청정기)로 대응이 다릅니다. 미세먼지가 나쁜 날엔 창문 대신 청정기를, CO2만 높으면 짧게 환기합니다.

우리집 IoT HUB 20슬롯 시스템 맵

이 글은 2편의 중앙 두뇌 서버와 3~19편의 분산 엣지 노드가 함께 구성하는 20채널 홈 IoT 시스템의 일부입니다. 필요한 편으로 이동해 슬롯과 센서 흐름을 함께 확인합니다.

[1편] 우리집 IoT 허브 전체 그림[2편] 중앙 두뇌 서버 만들기 · 슬롯 1~20[3편] 집 안 온습도, 감으로 보지 말고 숫자로 보자 · 슬롯 1·2[4편] 문 닫았나 계속 신경 쓰일 때 · 슬롯 9[5편] 냉장고가 제대로 돌고 있는지 눈으로 확인하자 · 슬롯 12[6편] 창문 열어도 될까? · 슬롯 3[7편] 욕실 곰팡이 생기기 전에 습도부터 잡자 · 슬롯 19[8편] 보일러가 실제로 도는지 배관 온도로 확인하자 · 슬롯 5·17[9편] 외출했는데 가스레인지가 켜져 있지 않을까? · 슬롯 6[10편] 가스 냄새가 나기 전에 먼저 경고받자 · 슬롯 7[11편] 집을 비웠을 때 불꽃 징후를 먼저 잡자 · 슬롯 8[12편] 머리가 멍한 이유가 공기 때문인지 확인하자 · 슬롯 13·14[13편] 전기세 무지 나오네, 이번 기회에 눈으로 보자 · 슬롯 15[14편] 물 새는지, 얼마나 쓰는지 숫자로 보자 · 슬롯 16[15편] 비 오는 줄 모르고 창문 열어두지 않게 · 슬롯 18[16편] 불 껐나, 문 잠갔나 한 번에 확인하자 · 슬롯 11·10[17편] 리모컨 없이 에어컨을 IoT 허브에서 제어하자 · 슬롯 4[18편] 강아지 밥그릇이 비었는지 눈으로 보자 · 슬롯 20[19편] 사람 있을 때만 시원하게, 없을 땐 아끼자 · 슬롯 1·4[20편] 집 안 상태가 한 화면에 보이기 시작했다 · 슬롯 전체