Automação IoT

Construa um Monitor de Qualidade do Ar Interno com Sensores de CO2 e PM2.5 e MQTT

Ligue um sensor de CO2 SCD41 e um sensor de partículas PMS5003 a um ESP32, publique as leituras como JSON via MQTT e configure alertas de ventilação quando o ar ficar abafado ou empoeirado.

Pequeno monitor de qualidade do ar interno com sensores de CO2 e PM2.5 em uma placa ESP32 enviando dados via Wi-Fi
Rode isso no seu próprio broker MQTTTenha um broker MQTT privado e gerenciado no plano Free e comece com exemplos de código prontos.
Teste grátis Exemplos de código Sem cartão de crédito

Um monitor de qualidade do ar interno que mede CO2 e partículas finas avisa quando um ambiente precisa de ar fresco ou filtragem muito antes de as pessoas se sentirem cansadas ou começarem a tossir. Neste tutorial você vai construir um com um ESP32, um sensor de CO2 Sensirion SCD41 e um sensor de partículas Plantower PMS5003, publicar as leituras como JSON via MQTT e configurar alertas de ventilação em um broker ConnectMQ.

O Que os Sensores Medem

  • CO2 (ppm) é o melhor indicador de ventilação em ambientes ocupados. O ar externo fica em torno de 400 a 450 ppm. Orientações de ventilação de edifícios costumam usar valores por volta de 800 a 1.000 ppm como sinal de que o suprimento de ar fresco é insuficiente para o número de pessoas no ambiente. O SCD41 é um verdadeiro sensor NDIR fotoacústico, não uma estimativa a partir de leituras de VOC.
  • PM2.5 (microgramas por metro cúbico) mede partículas finas vindas de cozimento, velas, poluição externa ou poeira de obras. O PMS5003 usa espalhamento de laser e reporta PM1.0, PM2.5 e PM10.
  • Temperatura e umidade vêm de brinde com o SCD41 e dão contexto para o conforto.

A medição de VOC é uma extensão útil. Um Sensirion SGP41 ou um Bosch BME680 adiciona um índice de VOC que responde a produtos de limpeza e à emissão de gases de materiais. Ele ficou fora do projeto principal para manter o código curto.

Peças e Ligações

Peça Pino Pino do ESP32 Observações
SCD41 VDD 3V3 As placas breakout geralmente incluem pull-ups
SCD41 GND GND
SCD41 SDA GPIO 21 Dados I2C
SCD41 SCL GPIO 22 Clock I2C
PMS5003 VCC 5V (VIN) O ventilador precisa de 5 V
PMS5003 GND GND
PMS5003 TX GPIO 16 (RX2) O nível lógico de dados do sensor é 3,3 V
PMS5003 RX GPIO 17 (TX2) Opcional, apenas para comandos

Use o Arduino IDE 2.x com o pacote de placas esp32 (core 3.x) e instale Sensirion I2C SCD4x (versão 1.x) e PubSubClient pelo Library Manager. O frame do PMS5003 é interpretado diretamente no sketch, então nenhuma biblioteca extra é necessária.

Posicione o monitor na altura da respiração, longe de janelas, portas e difusores de insuflamento, e mantenha a entrada do PMS5003 desobstruída. Um sensor ao lado de uma janela aberta mede o ar externo, não o do ambiente.

O Sketch Completo

#include <WiFi.h>
#include <Wire.h>
#include <PubSubClient.h>
#include <SensirionI2cScd4x.h>

const char* WIFI_SSID = "YOUR_WIFI";
const char* WIFI_PASS = "YOUR_WIFI_PASSWORD";

// Broker público de testes. Em produção use 8883 + WiFiClientSecure e as credenciais do portal.
const char* BROKER = "broker.connectmq.com";
const int   PORT   = 1883;
const char* TOPIC  = "connectmq/demo/iaq-3hv9/office-201/air";

const unsigned long PUBLISH_MS = 30000;

WiFiClient net;
PubSubClient mqtt(net);
SensirionI2cScd4x scd4x;
HardwareSerial pmsSerial(2);

uint16_t co2 = 0;
float tempC = NAN, rh = NAN;
uint16_t pm1 = 0, pm25 = 0, pm10 = 0;
bool pmValid = false;
unsigned long lastPublish = 0;

// Lê um frame de 32 bytes do PMS5003: 0x42 0x4D, comprimento, 13 palavras de dados, checksum
bool readPms() {
  static uint8_t buf[32];
  while (pmsSerial.available() >= 32) {
    if (pmsSerial.peek() != 0x42) { pmsSerial.read(); continue; }
    pmsSerial.readBytes(buf, 32);
    if (buf[1] != 0x4D) continue;
    uint16_t sum = 0;
    for (int i = 0; i < 30; i++) sum += buf[i];
    uint16_t check = (buf[30] << 8) | buf[31];
    if (sum != check) continue;
    // valores de "ambiente atmosférico"
    pm1  = (buf[10] << 8) | buf[11];
    pm25 = (buf[12] << 8) | buf[13];
    pm10 = (buf[14] << 8) | buf[15];
    return true;
  }
  return false;
}

void connectWifi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) delay(250);
}

void connectMqtt() {
  while (!mqtt.connected()) {
    String id = "iaq-" + String((uint32_t)ESP.getEfuseMac(), HEX);
    if (!mqtt.connect(id.c_str())) delay(3000);
  }
}

void setup() {
  Serial.begin(115200);
  Wire.begin(21, 22);
  pmsSerial.begin(9600, SERIAL_8N1, 16, 17);

  scd4x.begin(Wire, SCD41_I2C_ADDR_62);
  scd4x.stopPeriodicMeasurement();      // caso estivesse rodando após um soft reset
  delay(500);
  if (scd4x.startPeriodicMeasurement() != 0) {
    Serial.println("SCD41 not found, check wiring");
  }

  connectWifi();
  mqtt.setServer(BROKER, PORT);
  mqtt.setBufferSize(512);
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) connectWifi();
  if (!mqtt.connected()) connectMqtt();
  mqtt.loop();

  if (readPms()) pmValid = true;

  bool ready = false;
  if (scd4x.getDataReadyStatus(ready) == 0 && ready) {
    uint16_t c; float t, h;
    if (scd4x.readMeasurement(c, t, h) == 0 && c != 0) {
      co2 = c; tempC = t; rh = h;
    }
  }

  if (millis() - lastPublish >= PUBLISH_MS && co2 > 0) {
    lastPublish = millis();
    char msg[256];
    snprintf(msg, sizeof(msg),
      "{\"co2_ppm\":%u,\"temp_c\":%.1f,\"rh\":%.1f,\"pm1\":%u,\"pm25\":%u,\"pm10\":%u,\"pm_valid\":%s,\"rssi\":%d}",
      co2, tempC, rh, pm1, pm25, pm10, pmValid ? "true" : "false", WiFi.RSSI());
    mqtt.publish(TOPIC, msg);
    Serial.println(msg);
  }
}

O SCD41 produz uma nova medição a cada cinco segundos no modo periódico, e o PMS5003 transmite frames aproximadamente uma vez por segundo. O sketch guarda os valores mais recentes e publica a cada 30 segundos, o que é mais que suficiente para a qualidade do ar de um ambiente.

Veja os Dados Chegarem

Assine a partir de um terminal:

mosquitto_sub -h broker.connectmq.com -p 1883 -i iaq-view-3hv9 -t "connectmq/demo/iaq-3hv9/#" -v

Você deverá ver mensagens como:

connectmq/demo/iaq-3hv9/office-201/air {"co2_ppm":742,"temp_c":23.4,"rh":41.8,"pm1":3,"pm25":6,"pm10":7,"pm_valid":true,"rssi":-58}

Respire suavemente perto do SCD41 e o valor de CO2 sobe em menos de um minuto. Acenda um fósforo por perto e apague-o, e o PM2.5 dispara. Ambos são verificações rápidas de que os sensores e o parser funcionam. O servidor MQTT público (gratuito) é ideal para esta etapa de testes, porque você não precisa de conta, mas não deve receber dados de produção.

Migrando para um Broker Privado com TLS

Os dados de ar de um ambiente revelam quando há pessoas presentes, então monitores em produção devem usar um broker privado. Crie um broker no portal do ConnectMQ e altere o código de conexão:

#include <WiFiClientSecure.h>

WiFiClientSecure net;              // substitui o WiFiClient
const int PORT = 8883;

// em setup(), antes de mqtt.setServer():
// Carregue o certificado ISRG Root X1 (Let's Encrypt) para validação completa:
// net.setCACert(ISRG_ROOT_X1_PEM);

// em connectMqtt():
// mqtt.connect("YOUR_CLIENT_ID", "YOUR_USERNAME", "YOUR_PASSWORD");

Use o client ID exatamente como foi emitido, porque o ConnectMQ vincula client IDs às credenciais. Nosso tutorial de MQTT com ESP32 explica com mais detalhes o tratamento de certificados no ESP32.

Alertas de Ventilação

Configure regras de alerta por limite no portal do ConnectMQ para os campos co2_ppm e pm25. Pontos de partida sugeridos, que você deve adaptar às orientações locais e ao uso do ambiente:

Nível CO2 PM2.5 Ação sugerida
Bom abaixo de 800 ppm abaixo de 12 Nada a fazer
Moderado 800 a 1.200 ppm 12 a 35 Aumentar a ventilação, verificar o filtro
Ruim acima de 1.200 ppm acima de 35 Abrir janelas ou reforçar a ventilação, encontrar a fonte das partículas

As regras disparam a cada valor que cruza o limite, e o log de alertas mantém o histórico para que você veja quais ambientes ficam abafados com regularidade em determinados horários. Para acionar um ventilador ou um damper automaticamente, assine o topic de ar a partir de um fluxo Node-RED ou de uma automação do Home Assistant e acione o atuador pelo topic de comando MQTT dele. A integração MQTT do Home Assistant faz o monitor aparecer como entidades de sensor com poucas linhas de YAML.

Lendo os Dados ao Longo do Tempo

Leituras isoladas dizem menos do que os padrões diários. Em uma sala de reunião típica, o CO2 sobe continuamente durante cada reunião e volta a cair quando a sala esvazia; a velocidade com que ele cai mostra quão bem a sala é ventilada. Uma sala que continua acima de 1.000 ppm uma hora depois que todos saíram tem um problema de ventilação, não de ocupação. O PM2.5, por outro lado, geralmente fica baixo em ambientes internos e mostra picos curtos causados por cozimento, impressão, limpeza ou eventos externos, como picos de trânsito e fumaça de queimadas.

Para manter esse histórico, rode um subscriber que grave cada mensagem em um banco de dados de séries temporais, ou deixe o Telegraf assinar os topics de ar. Compare os ambientes lado a lado e olhe para a pior hora de cada dia em vez da média, porque as médias escondem os momentos em que as pessoas realmente sentem o ar abafado. Compartilhar um gráfico semanal simples com a equipe de facilities muitas vezes basta para mudar uma agenda de ventilação.

Se você usa vários monitores, nomeie cada topic pelo ambiente e não pelo dispositivo, para que uma placa substituída publique no mesmo lugar e o histórico continue sem interrupção.

Dicas de Calibração e Precisão

  1. Autocalibração do CO2. O SCD41 vem com a autocalibração automática ativada por padrão, que pressupõe que o sensor veja regularmente ar fresco no nível externo. Em ambientes que nunca são totalmente ventilados, desative-a e faça uma recalibração forçada ao ar livre.
  2. Aquecimento. Ignore os primeiros minutos de leituras após ligar.
  3. Autoaquecimento. Mantenha o ESP32 e qualquer regulador de tensão longe do SCD41, ou a leitura de temperatura ficará alta.
  4. Vida útil do sensor de partículas. O ventilador e o laser do PMS5003 se desgastam. Em implantações longas, coloque-o para dormir entre as leituras usando o pino SET.
  5. Umidade e PM. Sensores ópticos de partículas leem a mais em ar muito úmido, porque as gotículas de água espalham a luz. Trate com cautela as leituras de PM acima de cerca de 80 por cento de umidade relativa.

Escalando para um Edifício Inteiro

Um monitor por sala de reunião ou zona de planta aberta é uma boa densidade. Cada dispositivo precisa de suas próprias credenciais e de um topic sob a hierarquia do edifício, por exemplo acme/ist01/hq/f03/meeting-301/air. Um piloto com uma dúzia de monitores mais um dashboard cabe nas 25 conexões do plano Serverless gratuito. Combinar a qualidade do ar com sensores de ocupação de escritório e monitoramento de HVAC mostra se o ar abafado vem de gente demais ou de ventilação de menos, e esses mesmos topics podem alimentar um gêmeo digital do edifício. Um broker MQTT gerenciado elimina a necessidade de rodar qualquer servidor no edifício, e o guia de automação IoT lista mais projetos para construir sobre o mesmo broker.

Comece com o ConnectMQ

Crie um broker Serverless gratuito em app.connectmq.com, sem cartão de crédito. Grave o sketch com suas credenciais, abra o explorador de topics ao vivo e configure seu primeiro alerta de CO2. O ConnectMQ cuida de TLS, autenticação e disponibilidade.

Perguntas frequentes

Que nível de CO2 indica que um ambiente precisa de mais ventilação?

Muitas diretrizes de ventilação tratam valores sustentados acima de cerca de 1.000 ppm como sinal de ar fresco insuficiente para a ocupação. Siga as orientações locais e observe as tendências em vez de leituras isoladas.

Um sensor de VOC pode substituir um sensor de CO2 de verdade?

Não. Sensores que reportam "CO2 equivalente" o estimam a partir dos VOCs e podem errar bastante. Use um sensor NDIR ou fotoacústico como o SCD41 para medir o CO2 real.

Com que frequência o monitor de qualidade do ar interno deve publicar?

A cada 30 a 60 segundos é mais que suficiente. A qualidade do ar muda ao longo de minutos, e publicar com menos frequência economiza energia e tráfego no broker.

O PMS5003 precisa de 5 V?

O ventilador dele precisa de alimentação de 5 V, mas a saída serial usa lógica de 3,3 V, então o pino TX pode ser ligado diretamente a uma entrada do ESP32.

Artigos relacionados

Guia de Configuração do Zigbee2MQTT: do Coordenador ao Painel

Instale o Zigbee2MQTT com Docker, configure o coordenador e a conexão MQTT, pareie e renomeie dispositivos, controle-os via MQTT e veja seus estados em um painel, testando primeiro no servidor MQTT público (gratuito).

8 min de leitura

Todos os artigos →

Seu broker MQTT privado está a poucos cliques de distância

Crie uma conta, receba as credenciais do seu broker e conecte seu primeiro dispositivo — sem servidores para instalar, atualizar ou escalar.