How to Build an ESP32 Air Quality Monitor with BME280
Live temperature, humidity, and pressure readings with a comfort label on OLED
Updated

What you'll build
This guide walks you through building an indoor air quality monitor with an ESP32, a BME280 temperature/humidity/pressure sensor, and a compact SSD1306 OLED display. The BME280 reads the room environment every two seconds and the OLED shows live temperature in degrees Celsius, relative humidity as a percentage, barometric pressure in hectopascals, and a plain-language comfort label that tells you whether conditions are comfortable, too cold, too hot, too humid, or too dry. Both the sensor and the display share the same I2C bus, so only four signal wires connect the entire project to the ESP32.
The BME280 is one of the most practical sensors for makers because it combines three environmental measurements in a single low-cost breakout board. You will learn how to initialise it over I2C, configure its oversampling and filtering registers for stable indoor readings, and convert raw register data into human-readable values using the Adafruit BME280 library. The project also demonstrates how to share an I2C bus between two peripherals at different addresses, draw formatted multi-line output on a 128x64 OLED, and structure a non-blocking sensor loop that keeps the display responsive without tying up the main loop with delays.
When you are finished you will have a desk-sized environment monitor that updates in real time and is useful from the moment you power it on. The code is straightforward to extend: add Wi-Fi to push readings to a dashboard, wire in an RGB LED that changes color with the comfort label, or log data to an SD card for overnight trends. If you already built the weather station that fetches forecast data from an API, this project is a natural companion -- one shows what the weather will be outside, the other shows what conditions are like right now in the room.
Wiring diagram
Wiring diagram
Components needed
Assembly
Wire the I2C bus
Connect the BME280 and OLED to the ESP32 shared I2C bus. Both sensors use the same SDA (GPIO 21) and SCL (GPIO 22) lines.
- Both the BME280 and OLED share the same I2C bus. The BME280 defaults to address 0x76, and the OLED to 0x3C, so they will not conflict.
- If your BME280 board has a different address, try 0x77 in the code.
- Double-check that VCC on both modules goes to 3.3V, not 5V, unless the breakout board has its own regulator.
Flash and verify
Upload the sketch and open Serial Monitor at 115200 baud. You should see temperature, humidity, and pressure readings every two seconds. The OLED will show the values and a comfort label.
- Breathe gently on the BME280 to see humidity and temperature respond in real time.
- The comfort label updates automatically based on simple thresholds you can adjust in the code.
Pin assignments
| Pin | Connection | Type |
|---|---|---|
| 3V3 | aqm-bme280-1 VCC | POWER |
| GND | aqm-bme280-1 GND | GROUND |
| GPIO 21 | aqm-bme280-1 SDA | I2C |
| GPIO 22 | aqm-bme280-1 SCL | I2C |
| 3V3 | aqm-oled-1 VCC | POWER |
| GND | aqm-oled-1 GND | GROUND |
| GPIO 21 | aqm-oled-1 SDA | I2C |
| GPIO 22 | aqm-oled-1 SCL | I2C |
Code
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_BME280.h>
#define OLED_SDA 21
#define OLED_SCL 22
#define OLED_RESET -1
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_BME280 bme;
unsigned long lastReadMs = 0;
const unsigned long READ_INTERVAL_MS = 2000;
float temperature = 0;
float humidity = 0;
float pressure = 0;
String comfortLabel(float temp, float hum) {
if (temp < 18) return "Cold";
if (temp > 28) return "Hot";
if (hum > 70) return "Humid";
if (hum < 30) return "Dry";
return "Comfortable";
}
void drawScreen() {
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.println("Air Quality Monitor");
display.drawLine(0, 10, SCREEN_WIDTH, 10, SSD1306_WHITE);
display.setCursor(0, 14);
display.print("Temp: ");
display.print(temperature, 1);
display.println(" C");
display.setCursor(0, 26);
display.print("Humid: ");
display.print(humidity, 1);
display.println(" %");
display.setCursor(0, 38);
display.print("Press: ");
display.print(pressure, 0);
display.println(" hPa");
display.drawLine(0, 50, SCREEN_WIDTH, 50, SSD1306_WHITE);
display.setCursor(0, 54);
display.print("Status: ");
display.println(comfortLabel(temperature, humidity));
display.display();
}
void setup() {
Serial.begin(115200);
delay(100);
Wire.begin(OLED_SDA, OLED_SCL);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("OLED init failed");
while (true) delay(1000);
}
if (!bme.begin(0x76)) {
Serial.println("BME280 not found at 0x76, trying 0x77");
if (!bme.begin(0x77)) {
Serial.println("BME280 init failed");
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("BME280 not found!");
display.println("Check wiring.");
display.display();
while (true) delay(1000);
}
}
bme.setSampling(Adafruit_BME280::MODE_NORMAL,
Adafruit_BME280::SAMPLING_X2,
Adafruit_BME280::SAMPLING_X16,
Adafruit_BME280::SAMPLING_X1,
Adafruit_BME280::FILTER_X16,
Adafruit_BME280::STANDBY_MS_500);
Serial.println("Air Quality Monitor ready");
}
void loop() {
if (millis() - lastReadMs >= READ_INTERVAL_MS) {
temperature = bme.readTemperature();
humidity = bme.readHumidity();
pressure = bme.readPressure() / 100.0;
lastReadMs = millis();
Serial.print("T: ");
Serial.print(temperature, 1);
Serial.print(" C H: ");
Serial.print(humidity, 1);
Serial.print(" % P: ");
Serial.print(pressure, 0);
Serial.println(" hPa");
}
drawScreen();
delay(100);
}
// Run this and build other cool things at schematik.ioReady to build this?
Open this project in Schematik to get the full wiring diagram, pin assignments, and deployable code for the ESP32 Air Quality Monitor.
Open in Schematik →Related guides
How to Build a Gesture-Controlled Mood Lamp with ESP32
ESP32 · Beginner

How to Build an ESP32 Weather Station with Clothing Advice
ESP32 · Intermediate
How to Build a Plant Disco Guardian with ESP32
ESP32 · Beginner
How to Build an ESP32 Pomodoro Focus Timer
ESP32 · Beginner