Home/ Projects/ Live web dashboard
Project 15 of 16 Network Advanced

Live web dashboard

Serve a page showing temperature, humidity and light level, refreshing on its own so you never reload it. You will meet the reason embedded web work is fiddly: the board has little memory, so you build the page as a small template and send only the numbers on refresh rather than the whole document. Leave it running and the kit stops being a desk toy.

ESP32 & ESP8266 IoT Automation Kit
One of 16 projects in the ESP32 & ESP8266 IoT Automation Kit — the parts below are from that kit.

What this project uses

Every item is in the kit — nothing extra to buy.

Everything for this project

ESP32 & ESP8266 IoT Automation Kit

All 24 parts in one box, with this project and 15 more to build from them.

AED 180.00 See the kit
Need only these parts? Order them loose · from AED 106.07
Used in this project tick what you still need
Also needed untick if you already have them
Selected parts AED 106.07

One of each part. Packs (resistor assortment, jumper wires) already hold more than a single build needs. Backorder parts ship once they arrive — the kit above has every part boxed today. Delivery is free on orders AED 150.00+.

Sketch for this project

Written for the board in the kit. Copy it into the Arduino IDE; change the pin numbers if you wire it differently.

15 Live web dashboard Arduino C++
/*
  15 — Live web dashboard
  Board: ESP32.  Parts: DHT11, photoresistor, 10 kΩ resistor.
  Library: "DHT sensor library" (Adafruit) + Adafruit Unified Sensor.

  Wiring:
    DHT11:         VCC -> 3V3, GND -> GND, DATA -> GPIO 4
    Photoresistor: one leg -> 3V3, other leg -> GPIO 34 AND -> 10 kΩ -> GND
                   (GPIO 34 is on ADC1, which keeps working while WiFi is on;
                    ADC2 pins do not)

  A page showing temperature, humidity and light, refreshing on its own. The
  board has little memory, so the page is a small template sent once and the
  browser fetches only the numbers (/data, as JSON) every 2 seconds.
*/

#include <WiFi.h>
#include <WebServer.h>
#include "DHT.h"

const char* WIFI_SSID = "YOUR-WIFI-NAME";
const char* WIFI_PASS = "YOUR-WIFI-PASSWORD";
const int DHT_PIN = 4, LDR_PIN = 34;

DHT dht(DHT_PIN, DHT11);
WebServer server(80);
float lastT = NAN, lastH = NAN; int lastLight = 0;
unsigned long lastRead = 0;

const char PAGE[] PROGMEM = R"HTML(<!doctype html><html><head><meta name=viewport content='width=device-width,initial-scale=1'>
<title>Room dashboard</title><style>body{font-family:sans-serif;background:#111;color:#eee;text-align:center;padding:30px}
.card{display:inline-block;margin:10px;padding:24px 32px;background:#222;border-radius:14px;min-width:140px}
.v{font-size:44px;font-weight:700}.l{color:#999;font-size:14px}</style></head><body>
<h2>ESP32 room dashboard</h2>
<div class=card><div class=v id=t>--</div><div class=l>temperature &deg;C</div></div>
<div class=card><div class=v id=h>--</div><div class=l>humidity %</div></div>
<div class=card><div class=v id=li>--</div><div class=l>light (0-4095)</div></div>
<p class=l id=age>waiting for data</p>
<script>
async function tick(){try{const r=await fetch('/data');const d=await r.json();
t.textContent=d.t.toFixed(1);h.textContent=d.h.toFixed(0);li.textContent=d.light;age.textContent='updated '+new Date().toLocaleTimeString();}
catch(e){age.textContent='board not answering';}}
tick();setInterval(tick,2000);
</script></body></html>)HTML";

void readSensors() {
  if (millis() - lastRead < 2000) return;      // DHT11 limit
  lastRead = millis();
  float t = dht.readTemperature(), h = dht.readHumidity();
  if (!isnan(t)) lastT = t;
  if (!isnan(h)) lastH = h;
  lastLight = analogRead(LDR_PIN);
}

void setup() {
  Serial.begin(115200);
  dht.begin();
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
  Serial.println();
  Serial.print("Open http://"); Serial.println(WiFi.localIP());

  server.on("/", []() { server.send_P(200, "text/html", PAGE); });
  server.on("/data", []() {
    String j = "{\"t\":" + String(isnan(lastT) ? 0 : lastT, 1)
             + ",\"h\":" + String(isnan(lastH) ? 0 : lastH, 0)
             + ",\"light\":" + String(lastLight) + "}";
    server.send(200, "application/json", j);
  });
  server.begin();
}

void loop() {
  readSensors();
  server.handleClient();
}
Photoresistor must be on an ADC1 pin (GPIO 34) — ADC2 stops working with WiFi on.

More from this kit

All projects →

Root
Online — usually replies instantly
Catalog assistant: verify final stock/price on the product page before checkout.