Home

Guide no. 56

ESP32 and BME280: the board serves a web page with temperature, humidity, pressure and a chart that updates by itself.

By Ada Intelisano · informaticait.it technical team

Download the PDF (A4, 5 pages) Free to print and share, without changes — CC BY-ND 4.0
In short
  • BME280 on SDA (21) and SCL (22), powered at 3.3 V.
  • The board serves the page and answers /data with JSON.
  • The browser draws the chart, with no external libraries.
  • You open it with the IP address or with meteo.local.
Time: 1 hourLevel: next stepsBefore: guides no. 27 and 33

The temperature, humidity and pressure in your home on your phone, with a chart that grows by itself. The ESP32 does everything: it reads the sensor, holds a small web page and answers the browser. No external services, no subscriptions: it works inside your own Wi-Fi network.

1The parts

  • a FireBeetle 2 ESP32-E board with the pins already soldered
  • a BME280 sensor (here the SparkFun one with soldered pins), breadboard and four jumper wires
  • your home Wi-Fi network (2.4 GHz) with its name and password
New word: BME280A Bosch sensor that measures three things: temperature (from −40 to 85 °C), humidity and air pressure (from 300 to 1100 hPa). It talks I²C, like the displays in guide no. 44. Bosch states, under typical conditions, ±0.5 °C, ±3 % humidity (between 20 and 80 %) and ±1 hPa: the sensor warms itself up a little, so keep it away from the board; a comparison with other sensors is in guide no. 25.

2Connect the sensor

FireBeetle 2 ESP32-E and BME2802/D927/D4ESP32-WROOM-32EespressifFireBeetle 2 ESP32-ERST3V3GNDENSCKMOSIMISOSCLSDAD9D7D6D5D3D2TXRXVCC3V3GNDSCLSDAA4A3A2A1A0D13D12D11D10GND3.3VSDASCLGND3.3VSCKSDISDOCSBME2803V3 → 3.3VGND → GNDSCL (GPIO 22) → SCLSDA (GPIO 21) → SDAfour female-female jumpersinformaticait.it

Four wires: 3V3, GND, SDA (GPIO 21), SCL (GPIO 22). The SparkFun BME280 runs at 3.3 V only: do not connect it to the VCC pin, which carries 5 V. The I²C address is 0x77, the one the sketch expects.

3How it works

The weather station on your phone2/D927/D4ESP32-WROOM-32EespressifFireBeetle 2 ESP32-ERST3V3GNDENSCKMOSIMISOSCLSDAD9D7D6D5D3D2TXRXVCC3V3GNDSCLSDAA4A3A2A1A0D13D12D11D10GND3.3VSDASCLGND3.3VSCKSDISDOCSBME280router Wi-FiWeather stationTemp.21.4 °CHum.48 %Press.1013 hPa/dataJSONinformaticait.it
New word: JSONA simple way of writing data that programs read in a flash: {"t":21.4,"u":48,"p":1013}. The board sends just these few characters every 5 seconds; the browser does the drawing.
New word: mDNSAn easy name for the board on the network: instead of remembering an address like 192.168.1.37 you type meteo.local.

4The sketch

Write your network name and password in the first lines. The page is inside the sketch, between R"rawliteral( and )rawliteral": it is HTML with a little JavaScript that asks for /data and draws the chart on a canvas. No external libraries: the page works even without Internet access.

// Networked weather station: the board reads the BME280 and serves a web page with the values and a chart that updates by itself.
#include <WiFi.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <Adafruit_BME280.h>

const char* NETWORK = "your-network-name";
const char* PASSWORD = "your-network-password";

WebServer server(80);
Adafruit_BME280 bme;

// The page: HTML and JavaScript. Every 5 seconds it asks for /data and adds a point to the chart (the last 60).
const char PAGE[] PROGMEM = R"rawliteral(
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"><title>Weather station</title>
<style>body{font-family:sans-serif;margin:16px;background:#f4f7f5}h1{font-size:20px}
.v{display:inline-block;background:#fff;border-radius:8px;padding:10px 14px;margin:4px;min-width:90px}
.v b{display:block;font-size:24px;color:#1f7a3a}canvas{background:#fff;border-radius:8px;width:100%;max-width:600px}</style>
</head><body><h1>Weather station</h1>
<div class="v">Temperature<b id="t">--</b></div><div class="v">Humidity<b id="u">--</b></div><div class="v">Pressure<b id="p">--</b></div>
<canvas id="g" width="600" height="260"></canvas>
<script>
const points = [];
function draw() {
  const c = document.getElementById('g').getContext('2d');
  c.clearRect(0, 0, 600, 260);
  if (points.length < 2) return;
  const min = Math.min(...points) - 0.5, max = Math.max(...points) + 0.5;
  c.fillStyle = '#555'; c.fillText(max.toFixed(1) + ' °C', 4, 12); c.fillText(min.toFixed(1) + ' °C', 4, 254);
  c.strokeStyle = '#1f7a3a'; c.lineWidth = 2; c.beginPath();
  points.forEach((v, i) => {
    const x = 50 + i * 540 / 59, y = 250 - (v - min) / (max - min) * 240;
    i ? c.lineTo(x, y) : c.moveTo(x, y);
  });
  c.stroke();
}
async function update() {
  const d = await (await fetch('/data')).json();
  document.getElementById('t').textContent = d.t.toFixed(1) + ' °C';
  document.getElementById('u').textContent = d.u.toFixed(0) + ' %';
  document.getElementById('p').textContent = d.p.toFixed(0) + ' hPa';
  points.push(d.t); if (points.length > 60) points.shift();
  draw();
}
update(); setInterval(update, 5000);
</script></body></html>
)rawliteral";

void mainPage() {
  server.send_P(200, "text/html", PAGE);
}

void data() {   // the readings in JSON format, for example {"t":21.4,"u":48,"p":1013}
  String j = "{\"t\":" + String(bme.readTemperature(), 1) +
             ",\"u\":" + String(bme.readHumidity(), 0) +
             ",\"p\":" + String(bme.readPressure() / 100.0, 0) + "}";   // from pascals to hectopascals
  server.send(200, "application/json", j);
}

void setup() {
  Serial.begin(115200);
  if (!bme.begin(0x77)) Serial.println("BME280 not found: check the wires");
  WiFi.mode(WIFI_STA);
  WiFi.begin(NETWORK, PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.print("\nOpen http://");
  Serial.println(WiFi.localIP());
  MDNS.begin("meteo");                 // or http://meteo.local
  server.on("/", mainPage);
  server.on("/data", data);
  server.begin();
}

void loop() {
  server.handleClient();
}

5Try it

✓ What you should seeThe Serial Monitor (115200) shows “Open http://192.168…”. Open that address, or http://meteo.local, from a phone on the same network: you see the three values and, after a few updates, the line of the chart. Breathe on the sensor: the humidity goes up.
If it doesn't work
  • “BME280 not found”: SDA and SCL are swapped, or the sensor is not getting 3.3 V.
  • The page does not open: is the phone on another network (guest network or mobile data)? Try the numeric address.

6Challenge yourself

Try it yourself
  • Add a second line to the chart for humidity, in another color.
  • Have the board keep the last 60 readings in an array, so the chart is already full when you open the page.
✓ What you learned
  • the ESP32 can act as a web server for your network;
  • the page loads once, then the browser only asks for the data in JSON;
  • a canvas with a few lines of JavaScript is enough for a chart.
Sources: DFRobot, FireBeetle 2 ESP32-E wiki (DFR0654) · SparkFun, BME280 Hookup Guide; Bosch Sensortec, BME280 datasheet rev. 1.24 · Adafruit, BME280 library · Espressif, arduino-esp32: WebServer and ESPmDNS · informaticait guides no. 25, 27, 33 and 44

Useful products

Other guides

All our guides →
Loading...
Back to top