Hardware FixRecommendedDevice not working? Your driver may be the problemCheck updates for common hardware issues.Fix DriversHalloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix Now×
BETTESWORTHConstruction
air quality monitor

ESP32 Air Quality Monitor with Local Web Dashboard and OLED Display

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Build this monitor around an ESP32, an SCD40 or SCD41 CO₂ sensor, and an SSD1306 OLED. That minimum combination gives you a useful local ventilation monitor: CO₂, temperature, humidity, connection status, and sensor freshness on both the OLED and a browser dashboard. Add a PMS5003 when particulate matter matters, or a BME680 when you want environmental context and a relative gas-response signal.

This is not a regulatory air-quality station. CO₂ indicates ventilation and occupancy-related buildup; PM2.5 indicates fine particles; a BME680 indicates changes in a mixed gas environment. No single low-cost sensor measures every indoor pollutant or automatically produces a defensible official AQI.

As an Amazon Associate I earn from qualifying purchases.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What this ESP32 monitor actually measures

Use separate, honest labels instead of collapsing every reading into one unsupported “air quality” score.

Measurement Useful interpretation What it does not prove
CO₂ Ventilation and occupancy-related buildup That all other pollutants are low
PM2.5 Fine airborne particle concentration Particle chemistry or source
PM10 Larger inhalable particles Overall chemical safety
Temperature Thermal comfort and sensor context Air cleanliness
Relative humidity Moisture and comfort context The presence or absence of mold
BME680 gas signal Relative changes in a mixed gas environment Exact VOC, formaldehyde, or CO₂ concentration
AQI An index calculated from defined pollutant data A valid result from arbitrary ADC scaling

Call the readings CO₂ level, PM2.5 concentration, and VOC-related signal. Use “below this project’s configured alert threshold,” not “safe,” unless you are explicitly applying a named guideline and its required averaging period.

Popular on Amazon
Amazon Smart Air Quality Monitor – Know your air, Works with Alexa
  • Know your air – Amazon Smart Air Quality Monitor makes it easy to understand what’s in your indoor air.
  • Track and measure – Keep tabs on 5 key factors: particulate matter (PM 2.5), volatile organic compounds (VOCs), carbon monoxide (CO), humidity, and temperature.
  • Stay informed – Get an indication of current air quality from the color-coded LED, and an easy-to-understand air quality score in the Alexa app anytime.
  • Get notifications – If Alexa detects poor air quality, you can get notifications on your phone or even announcements on Echo devices.
  • Enable Routines to turn your Alexa-enabled devices such as air purifiers, dehumidifiers, and fans on and off when the indoor air quality changes.

Choose a sensor configuration

Priority Configuration Trade-off
Lowest complexity SCD40 or SCD41 + SSD1306 Ventilation-focused; no particulate measurement
Balanced indoor monitor SCD41 + BME680 + SSD1306 More context, cost, and calibration considerations
PM2.5 focus PMS5003 + ESP32 + OLED Larger, noisier, and higher power consumption
Smart-home integration ESPHome + Home Assistant Less custom firmware and UI control
Educational analog experiment MQ-135 + ESP32 ADC Relative signal only; poor quantitative reliability

Recommended sensors

The Sensirion SCD40 and SCD41 use photoacoustic NDIR sensing for CO₂ and include temperature and humidity compensation. The SCD40 is generally the lower-cost choice; the SCD41 is the higher-performance variant. Follow the current model-specific documentation for accuracy, operating conditions, calibration, and measurement timing.

The Bosch BME680 measures temperature, humidity, pressure, and gas resistance over I²C or SPI. Bosch also provides BSEC software for processed IAQ-related outputs. Treat its gas result as a relative response or estimate, not a direct measurement of a named pollutant.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The PMS5003 is a UART optical particle sensor. Adafruit documents 9600-baud output, a nominal 5 V supply, approximately 0–500 µg/m³ effective range, and active current that can reach about 100 mA. Verify the exact module and breakout documentation, especially UART signal levels, before connecting it to an ESP32 input.

Bill of materials

  • ESP32 development board with 3.3 V GPIO, accessible I²C pins, and a hardware UART.
  • SCD40 or SCD41 breakout for the minimum build.
  • 128×64 SSD1306 I²C OLED breakout.
  • Stable USB power supply and a good-quality cable.
  • Optional BME680 breakout.
  • Optional PMS5003 and suitable cable or level-shifting hardware.
  • Ventilated enclosure, jumper wires, and a breadboard or soldered prototyping board.

Check the exact board pinout rather than assuming that every ESP32 variant exposes the same GPIO numbers. Espressif’s ESP32 documentation describes the family’s Wi-Fi, I²C, UART, SPI, ADC, and power features, but board layouts differ.

Wiring

Use one shared I²C bus for the OLED, SCD4x, and BME680:

OLED SDA       → ESP32 SDA, example GPIO 21
OLED SCL       → ESP32 SCL, example GPIO 22
SCD40/SCD41    → same SDA and SCL bus
BME680         → same SDA and SCL bus
All devices    → common GND
PMS5003 TX     → ESP32 hardware-UART RX pin

GPIO 21 and 22 are example assignments, not universal requirements. Set the pins in firmware according to your board’s pinout. The PMS5003 is typically powered from 5 V and may consume considerably more current than the I²C sensors. Its TX connection must be electrically compatible with the ESP32’s 3.3 V input; do not assume a purchased module is safe without checking its documentation or using appropriate level shifting.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For the OLED, connect VCC to 3.3 V when the module supports it, GND to GND, and SDA/SCL to the I²C bus. Common OLED modules use address 0x3C, but your scanner—not a copied example—should determine the actual address.

Scan the I²C bus before writing the full program

Install the ESP32 board package, select the correct board, upload this diagnostic sketch, and open Serial Monitor at 115200 baud:

Also popular on Amazon
16 in 1 Air Quality Monitor Indoor 7" High-Precision Real-Time CO2 Monitor | 7" HD Large Air Quality Tester with Alerts for CO2, TVOC, PM2.5 PM1.0 PM10, HCHO Temp & Humidity AQI &Time Air Meter for Home
  • 【16-in-1 Air Quality Monitor Indoor】Experience the ultimate indoor air quality monitoring with our 16-in-1 Air Quality Monitor, offering real-time detection of 9 key parameters including CO2, PM2.5, PM1.0, PM10, HCHO, TVOC, Temperature, Humidity, AQI, and Time. With 7 distinct AQI alert buzzers, this air quality tester ensures your family breathes with ease.(*Note: "16-in-1" refers to the combination of 9 key detectable parameters and 7 types of AQI alert buzzers.)
  • 【Crystal Clear 7-inch Large Display】Enjoy a 7-inch LED display for sharp, clear air quality readings. Provides an instant, comprehensive view of your indoor air without navigating through menus, with three brightness settings for any lighting condition
  • 【External High-Precision Sensors with 0.001 Accuracy】Equipped with advanced external high-precision sensors, this device delivers unmatched accuracy (0.001 units) by directly sampling the air. Its innovative multi-sensor array and enhanced airflow design detect even the slightest environmental changes, allowing for instant response and optimal safety. (*Note: Avoid touching the sensors or exposing them to perfumes/strong odors to maintain accuracy.)
  • 【Real-Time AQI Alert Buzzers】Our air quality monitor provides real-time monitoring and alerts for pollutants like CO2, PM2.5, PM1.0, PM10, HCHO, TVOC, Temperature, Humidity, and AQI, with 7 distinct alert functions. Stay informed with clear alerts and rest easy with a mute button to silence alarms. Your health and comfort are our priority. Toggle between Fahrenheit and Celsius instantly with a double-press of the "Power" button on this air quality detector.
  • 【Up to 8 Hours of Runtime & Flexible USB-C Charging】 Enjoy up to 8 hours of continuous air quality monitoring on a full charge. The USB-C charging interface offers flexible power options and is compatible with widely available USB-C cables, while the included AC adapter provides convenient charging at home. Designed for effortless monitoring wherever you need it—from bedrooms and living spaces to your car and beyond.
#include <Wire.h>

void setup() {
  Serial.begin(115200);
  Wire.begin(21, 22);
  Serial.println("I2C scan");

  for (uint8_t address = 1; address < 127; address++) {
    Wire.beginTransmission(address);
    uint8_t error = Wire.endTransmission();
    if (error == 0) {
      Serial.printf("Found device at 0x%02Xn", address);
    }
  }
}

void loop() {}

You should see one or more hexadecimal addresses. If the result is empty, check power, ground, SDA/SCL order, selected GPIOs, pull-up resistors, and wire length. Multiple breakout boards may each include pull-ups; excessive parallel pull-ups can make the bus unreliable.

Test each device independently

  1. OLED: initialize the display and show a test message. If it stays blank, verify the address, dimensions, reset-pin configuration, and whether the controller is SSD1306 or SH1106.
  2. SCD40/SCD41: start periodic measurements and print CO₂, temperature, and humidity. Allow the sensor to warm up and obtain valid measurements before interpreting them.
  3. BME680: confirm temperature, humidity, pressure, and gas-resistance output. Handling, solvents, cooking fumes, cleaning products, and enclosure materials can change the gas signal.
  4. PMS5003: confirm its 5 V supply, common ground, UART RX connection, 9600-baud configuration, fan operation, and frame parser.
  5. Wi-Fi: connect separately and print the assigned IP address.
  6. Web server: serve a plain test page before combining sensor rendering and JavaScript.

Testing in this order turns a confusing combined failure into a specific wiring, power, address, or software problem.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Install the firmware dependencies

A custom Arduino implementation normally uses:

  • WiFi.h from the ESP32 Arduino core;
  • WebServer.h for a simple HTTP server;
  • Wire.h for I²C;
  • an SSD1306 library such as Adafruit SSD1306;
  • an SCD4x Arduino driver;
  • a BME680 library, optionally with Bosch BSEC;
  • a PMS5003 parser library or a UART frame parser.

Pin the ESP32 Arduino-core version and library versions in the project repository. APIs and behavior can change, so “latest” is not a permanent reproducibility label.

Connect to Wi-Fi without blocking the monitor

The Arduino-ESP32 Wi-Fi documentation provides station-mode examples. A bounded connection attempt should look like this:

#include <WiFi.h>

const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";

void connectWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  unsigned long start = millis();

  while (WiFi.status() != WL_CONNECTED &&
         millis() - start < 20000) {
    delay(250);
    Serial.print(".");
  }

  if (WiFi.status() == WL_CONNECTED) {
    Serial.print("nIP address: ");
    Serial.println(WiFi.localIP());
  } else {
    Serial.println("nWi-Fi connection failed");
  }
}

In the completed firmware, retry periodically rather than waiting forever. Sensor sampling and OLED updates should continue when Wi-Fi is unavailable. Show an offline status and never erase a valid sensor reading merely because the network disappeared.

Use a non-blocking firmware design

Keep independent timers for sensor reads, OLED refresh, Wi-Fi reconnect attempts, logging, and other work. Long delays make the dashboard appear frozen and can prevent timely serial parsing.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Store each reading with its value, validity flag, and timestamp. For example:

struct Readings {
  float temperatureC;
  float humidityRH;
  uint16_t co2Ppm;
  float pm25;
  float pm10;
  float gasResistance;
  unsigned long lastUpdate;
  bool co2Valid;
  bool particulateValid;
  bool bmeValid;
};

When a read fails, retain the previous value only while marking it stale. After a defined timeout, return null, --, or a clear sensor-error state instead of presenting old data as current.

Also popular on Amazon
hiBCTR 2-Pack BME680 4-in-1 Environmental Sensor Module, 5V | Temperature, humidity, pressure, and VOC gas monitoring, for Arduino, Raspberry Pi, ESP32 air quality projects
  • 4-in-1 Environmental Monitoring​​: Simultaneously measures temperature (-40°C to +85°C), humidity (±3% RH), barometric pressure, and VOC gases (IAQ index output).
  • ​​Multi-Protocol Interface​​: 5V compatible with I2C (3.4MHz max) and SPI (10MHz 3/4-wire) for Arduino/Raspberry Pi/ESP32 integration.
  • Ultra-Low Power Operation​​: Current as low as 2.1μA (1Hz temp/humidity) to 3.7μA (triple-sensor mode) with selectable sensor activation.
  • ​​Industrial-Grade Precision​​: VOC response time <1s (new sensor), ±1.5% RH humidity hysteresis, and IAQ air quality indexing capability.
  • ​​Ready-to-Use Module​​: Includes pre-soldered BME680 chip with labeled VCC/GND/SCL/SDA/SDO/CS pins (2x module per order).

Build the local dashboard

The simplest architecture is a web server on the ESP32:

Browser → HTTP request → ESP32
                         ├── HTML/CSS/JavaScript
                         └── JSON sensor readings

Use routes such as:

  • GET / — dashboard page;
  • GET /api/readings — latest values and timestamps;
  • GET /api/status — firmware version, uptime, RSSI, IP address, and error flags.

An example JSON response is:

{
  "co2_ppm": 812,
  "temperature_c": 22.8,
  "humidity_rh": 47.2,
  "pm25_ugm3": 5,
  "pm10_ugm3": 8,
  "gas_resistance_ohms": 183420,
  "sensor_age_ms": 1240,
  "wifi_rssi_dbm": -58
}

Poll every 2–10 seconds, depending on the sensor schedule. Do not confuse browser refresh with measurement speed: a page can refresh every five seconds while a sensor produces a new sample less often.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
async function updateReadings() {
  try {
    const response = await fetch("/api/readings", {cache: "no-store"});
    if (!response.ok) throw new Error("HTTP " + response.status);
    const data = await response.json();

    document.querySelector("#co2").textContent = `${data.co2_ppm} ppm`;
    document.querySelector("#temperature").textContent =
      `${data.temperature_c.toFixed(1)} °C`;
    document.querySelector("#humidity").textContent =
      `${data.humidity_rh.toFixed(1)} %`;
  } catch (error) {
    document.querySelector("#status").textContent =
      "Dashboard cannot reach the ESP32";
  }
}

setInterval(updateReadings, 5000);
updateReadings();

Use responsive cards with large values and small units. Include a visible timestamp or sensor age, Wi-Fi status, and an offline or stale state. A good OLED layout can rotate through three pages:

  • CO₂, temperature, and humidity;
  • PM2.5 and PM10;
  • VOC-related signal and Wi-Fi status.

Local dashboard, cloud service, or Home Assistant?

A local ESP32 dashboard needs no cloud account, has low latency, and keeps readings on the local network. Its limitations are equally important: it is unreachable when the device or local network is down, the IP address may change, and it has little historical storage unless you add it.

A cloud service can provide remote access and long-term charts, but introduces account management, API keys, internet dependency, rate limits, and privacy concerns. Never publish Wi-Fi passwords or cloud API keys in source code. If you use ThingSpeak or another service, verify current plan limits and API requirements separately.

For an existing smart home, ESPHome with Home Assistant is often the faster route to history, dashboards, automations, and alerts. ESPHome’s web server is intended to view and edit device state, not to replace a full general-purpose application backend.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Interpretation: avoid homemade AQI

Keep these concepts separate:

  1. Raw sensor value: an ADC count or resistance.
  2. Concentration: a measured quantity with units, such as µg/m³.
  3. Guidance threshold: a configured value that triggers a project warning.
  4. Official AQI: a pollutant-specific index calculated using defined units, averaging periods, breakpoint tables, and a jurisdiction.

A weighted average of MQ-135 and MQ-2 ADC values is not equivalent to the U.S. EPA AQI. If you implement an official-style index, link to the current U.S. EPA/AirNow AQI methodology and identify the pollutant, units, averaging period, breakpoint revision, and jurisdiction. Otherwise, use labels such as CO₂: 812 ppm, PM2.5: 5 µg/m³, and VOC sensor signal: improving.

MQ-135 modules can be useful for demonstrating analog sensing, but their output varies with heater temperature, humidity, calibration gas, resistor values, supply voltage, sensor variation, warm-up, enclosure, airflow, and cross-sensitivity. Do not present a normalized MQ-135 number as a trustworthy 0–500 AQI.

Also popular on Amazon
Sale
GoveeLife Smart Air Quality Monitor with PM2.5 H5106, LED Display Wired | Indoor temperature humidity sensors, 2s refresh, 2-year data storage, for home & office, 2.4G Wi-Fi only
  • High Accuracy & Fast Refresh Data: With this smart sensor, the PM2.5 accuracy is ±15 µg/m³ while temperature and humidity accuracies are ±0.54°F and ±3%RH.The two-second correction data feature shows the latest changes in PM2.5, temperature, and humidity.Keep sensor clear for accurate detection.
  • Multifunctional Air Quality Detector: The GoveeLife Air Quality Monitor conveniently measures 3 important indexes for indoor air quality, including PM2.5, temperature, and humidity.
  • Switchable Display: Press the top button for the clock & PM2.5 display. Long press for 2 seconds to switch to bright screen mode & night mode. The LED indicator displays 4 levels of ambient air quality. 2.4G Wi-Fi is required to display the time.
  • Connect with GoveeHome Appliances: Set your target air quality and link with your other GoveeHome smart appliances. GoveeLife air purifiers, humidifiers, and space heaters will turn on and off automatically when the indoor air quality changes.
  • H5106 needs to be connected to a power source and supports GoveeLife devices: Smart Air Purifiers - H7126, H7120, H7124, H712C, H7122, H7123; Humidifiers - H7140; Fans - H7100, H7102

Placement, warm-up, and calibration

  • Allow each sensor to reach its normal operating state before interpreting trends.
  • Keep sensors away from the ESP32 regulator, USB converter, and other heat sources.
  • Provide enclosure vents without directing strong drafts across the sensing elements.
  • Keep condensation away from electronics and sensing openings.
  • Give the PMS5003 unobstructed intake and exhaust airflow; keep its warm fan exhaust away from temperature and humidity sensors.
  • For CO₂, compare against a known-good reference or outdoor/known-fresh-air condition while following the manufacturer’s calibration guidance. Do not assume automatic baseline calibration is appropriate in every room.

A DIY comparison is not laboratory calibration. Compare this monitor with a known-good reference, a second sensor, or controlled events such as occupancy, opening a window, cooking, or ventilation. Look for plausible direction and response time, not just a matching number.

Troubleshooting

OLED is blank

Run the I²C scanner, verify SDA/SCL and power, try the detected address, confirm the display dimensions and reset-pin setting, shorten the wires, and check whether the module uses SH1106 instead of SSD1306.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

No I²C devices appear

Check common ground, supply voltage, pin definitions, pull-ups, connector orientation, and whether the breakout is actually powered. Test one device at a time.

PMS5003 reports zero

Check the specified 5 V supply, current capacity, common ground, UART RX pin, 9600-baud setting, frame parser, fan, airflow, and conflicts with the USB serial port. Confirm the purchased breakout’s signal-level requirements.

CO₂ is fixed or implausibly low

Check initialization and periodic measurement commands, stale-value handling, room-air access, operating time, calibration assumptions, and whether the sensor is sealed inside the enclosure.

Dashboard loads but values do not change

Open /api/readings directly, inspect the browser console, verify route spelling and JSON syntax, check polling frequency, and ensure sensor reads do not block the web server. Cross-origin settings matter only when the page is hosted on a different origin.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Wi-Fi fails or the IP changes

Use a connection timeout, retry periodically, print the assigned IP at boot, and consider a DHCP reservation. An mDNS hostname can help, but support varies by router and client. The OLED should still show local readings while Wi-Fi is offline.

The device resets randomly

Start with power: use a stable supply, a short capable USB cable, and enough current for Wi-Fi and the PM fan. Then investigate voltage drop, watchdog resets, memory fragmentation from repeated String allocation, blocking code, and invalid sensor-data handling.

Useful extensions

  • Rolling averages and trend arrows to reduce noisy displays.
  • Clearly documented alert thresholds and warning states.
  • MQTT for local publishing.
  • Home Assistant or ESPHome integration.
  • SD-card or server-side historical logging.
  • OTA firmware updates.
  • Captive-portal Wi-Fi setup instead of hard-coded credentials.
  • Touch, e-paper, or larger displays.
  • Reduced sampling and Wi-Fi duty cycles for battery experiments.

Continuous Wi-Fi and a continuously running PMS5003 fan make a complete battery-powered monitor substantially more demanding than an I²C-only node. Measure the assembled device before calling it low-power.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Leave a Reply

Your email address will not be published. Required fields are marked *

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.