BME280 with ESP32: Wiring, I2C Address, and Code That Works
BME280 with ESP32: Wiring, I2C Address, and Code That Works
Temperature, humidity, and barometric pressure from a sensor the size of a fingernail, over two wires. The BME280 is the best value in environmental sensing — once you get past its one famous trap: the address.
Four wires: VIN→3.3V, GND→GND, SCL→GPIO 22, SDA→GPIO 21. Then the trap: the I2C address is 0x76 or 0x77 depending on the module batch, and “sensor not found” almost always means you guessed the wrong one. Run an I2C scanner first, pass the address it prints to bme.begin(), done.
Wiring (I2C mode)
| BME280 pin | ESP32 DevKitC pin | Note |
|---|---|---|
| VIN / VCC | 3V3 | Most modules accept 3.3–5V on VIN; 3.3V is always safe |
| GND | GND | — |
| SCL / SCK | GPIO 22 | Default I2C clock |
| SDA / SDI | GPIO 21 | Default I2C data |
| CS, SDO | leave unconnected | Only used for SPI mode / address select on bare modules |
GPIO 21/22 are the ESP32’s standard I2C pair and both are on the safe pin list. Modules include pull-up resistors on the breakout board, so no external resistors are needed for short wires.
Step 1 — Find the address before writing any other code
Flash the I2C scanner example — you can even run it in the simulator first to see what the output looks like. It prints every address that answers on the bus. BME280s answer at 0x76 or 0x77; write yours down. (Its sibling the BMP280 lives at the same addresses — the BMP280 example uses identical wiring and driver family, so everything on this page applies there too.)
Step 2 — The sketch
#include <Wire.h>
#include <Adafruit_BME280.h>
Adafruit_BME280 bme; // I2C mode
void setup() {
Serial.begin(115200);
Wire.begin(21, 22); // SDA, SCL — explicit beats assumed
if (!bme.begin(0x76)) { // ← use the address YOUR scanner printed
Serial.println("BME280 not found — check wiring and address");
while (1) delay(10);
}
}
void loop() {
Serial.printf("Temp: %.1f C Humidity: %.0f %% Pressure: %.1f hPa\n",
bme.readTemperature(),
bme.readHumidity(),
bme.readPressure() / 100.0f);
delay(2000);
}
Libraries: Adafruit BME280 plus Adafruit Unified Sensor from the Arduino Library Manager.
Getting numbers you can trust
- Self-heating is real. Mounted inside a closed box next to a warm ESP32, the BME280 reads 1–2°C high. Vent the enclosure or offset in software — measure your own bias, don’t copy someone else’s constant.
- Pressure is altitude. Feed
readAltitude(seaLevelhPa)your local sea-level pressure from a weather station, or use it the other way: known altitude → calibrate pressure. - Don’t hammer it. One reading per second is plenty for weather; faster sampling just warms the die.
- Long cable runs fail silently. I2C was designed for centimeters, not meters. Past ~30cm of wire, expect ghosts — lower the bus speed with
Wire.setClock(100000)or shorten the run.
When it still says “not found”
In order of likelihood: wrong address (rerun the scanner), SDA/SCL swapped (the single most common wiring error — try flipping them), VIN on 5V with a 3.3V-only clone module, or a cold solder joint on the header. If you want to see the bus instead of guessing, our Logic Analyzer Rig decodes I2C live in the browser — you watch the ESP32 clock out the address byte and the sensor ACK it, or not.
More in the Knowledge Base: DHT22 Wiring & Code · Powering Your Project · All guides →