ESP8266-Based Air-Quality & Temperature-Humidity Sensor

The goal of this project was to make a simple environmental sensor and connect it to Home Assistant. For this I used a Wemos D1 mini board as the controller, a DHT22 sensor and an MQ-2 smoke sensor (later changed to an MQ-135 air-quality sensor).

The Main Board:

Wiring is very simple for this project. The Wemos board provides 5V power from the usb cable, so no extra power supply circuit is needed. Then the sensors are connected to pins D5 (DHT22) and A0 (MQ-2). I also added a indicator LED to pin D2.

Code:

The ESP8266 connects to the Wi-Fi, then to Home Assistant's MQTT server. Then it reads the sensors at a 3s interval, and checks if the difference to the previous reading is greater than 0.5 before sending it to the server, so it doesn't spam it with readings. It also blinks the LED if a new reading is found.

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <MQ2.h>
#include <PubSubClient.h>
#include <DHT.h>

#define wifi_ssid "SSID"
#define wifi_password "PASSWORD"

#define mqtt_server "SERVER_IP"
#define mqtt_user "homeassistant"
#define mqtt_password "HOMEASSISTANTPASSWORD"

#define humidity_topic "home/env_sensor/humidity"
#define temperature_topic "home/env_sensor/temperature"

#define airquality_LPG_topic "home/env_sensor/airquality/lpg"
#define airquality_CO_topic "home/env_sensor/airquality/co"
#define airquality_SMOKE_topic "home/env_sensor/airquality/smoke"

//temperature/humidity sensor
DHT dht;

//air-quality sensor
int airSensor = A0;
MQ2 mq2(airSensor);

WiFiClient espClient;
PubSubClient client(espClient);

void setup_wifi() {
  delay(10);
  WiFi.begin(wifi_ssid, wifi_password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
}

void reconnect() {
  while (!client.connected()) {
    // Attempt to connect to mqtt
    if (client.connect("ESP8266Client", mqtt_user, mqtt_password)) {
      Serial.println("Connected");
    } else {
      delay(5000);
    }
  }
}

bool checkBound(float newValue, float prevValue, float maxDiff) {
  return !isnan(newValue) &&
         (newValue < prevValue - maxDiff || newValue > prevValue + maxDiff);
}

long lastMsg = 0;
float temp = 0.0;
float hum = 0.0;
float lpg = -1.0;
float co = -1.0;
float smoke = -1.0;
float diff = 0.5;
bool isLedOn = false;

void setup() {
    //led pin
    pinMode(D2, OUTPUT);

    //airquality sensor setup
    mq2.begin();
    Serial.begin(9600);

    //dht22 setup
    dht.setup(D5);     

    //setup server
    setup_wifi();
    client.setServer(mqtt_server, 1883);
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
  
  if (isLedOn) {
      digitalWrite(D2, LOW);
      isLedOn = false;
  }
  
  long now = millis();
  if (now - lastMsg > 3000) {
    lastMsg = now;
    bool anyChanged = false;

    delay(dht.getMinimumSamplingPeriod());
    float newTemp = dht.getTemperature();
    float newHum = dht.getHumidity();

    float newLpg = mq2.readLPG();
    float newCo = mq2.readCO();
    float newSmoke = mq2.readSmoke();

    if (checkBound(newTemp, temp, diff)) {
      temp = newTemp;
      client.publish(temperature_topic, String(temp).c_str(), true);
      anyChanged = true;
    }

    if (checkBound(newHum, hum, diff)) {
      hum = newHum;
      client.publish(humidity_topic, String(hum).c_str(), true);
      anyChanged = true;
    }

    if (checkBound(newLpg, lpg, diff)) {
      lpg = newLpg;
      client.publish(airquality_LPG_topic, String(lpg).c_str(), true);
      anyChanged = true;
    }

    if (checkBound(newCo, co, diff)) {
      co = newCo;
      client.publish(airquality_CO_topic, String(co).c_str(), true);
      anyChanged = true;
    }

    if (checkBound(newSmoke, smoke, diff)) {
      smoke = newSmoke;
      client.publish(airquality_SMOKE_topic, String(smoke).c_str(), true);
      anyChanged = true;
    }

    if (anyChanged) {
        digitalWrite(D2, HIGH);
        isLedOn = true;
        delay(500);
    }
  }
}

3D Printed Shell:

I used Fusion 360 to design the shell. The 50x70mm perfboard slides in perfectly, so no screws are needed to keep it in place, and the slots allow for heat generated from the microcontroller to escape.

Get it on Thingiverse

Results: