Build a web thermometer with the DS18B20

Read the precise DS18B20 temperature sensor on the ESP32 and show the temperature, plus the lowest and highest value, on a live web page.
  • Level:Intermediate
  • Duration: 45 min
  • Ages 12+
  • Platform: ESP32

Tools for this lesson

Helpful for this build. Open a tool to see tips and more projects that use it.

Build a web thermometer with the DS18B20 – EEMENTOR STEM™ lesson

The DS18B20 is one of the most accurate temperature sensors in the Sensor Kit, good to about half a degree. In this lesson the ESP32 reads it over the 1-Wire bus and serves a web page with the current temperature in big numbers, plus the lowest and highest value since it started. Leave it by a window or in the fridge and check it from your phone.

What you'll learn

  • How to read the DS18B20 on the ESP32 with the 1-Wire bus
  • How to keep a running minimum and maximum
  • How to send several values to a web page as JSON
  • How to reset values from a button on the page

What you need

  • ESP32 board, expansion board and USB cable (ESP32 IoT Starter Kit)
  • DS18B20 temperature module (45-in-1 Sensor Kit)
  • A 2.4 GHz Wi-Fi network
  • Breadboard and jumper wires (ESP32 IoT Starter Kit)

Wiring

Breadboard wiring diagram: Build a web thermometer with the DS18B20
Breadboard view. Check each connection against the wiring table below.
From To
DS18B20 module S ESP32 GPIO 27
DS18B20 module + 3V3
DS18B20 module − GND

Sensor modules from different makers can label and order their pins differently. Always follow the labels printed on your module.

The sketch

Install two libraries in the Arduino IDE: OneWire (by Paul Stoffregen) and DallasTemperature (by Miles Burton).

Replace YOUR_WIFI_NAME and YOUR_WIFI_PASSWORD with your own network details (2.4 GHz only). Open the Serial Monitor at 115200 baud to see the address, then open it in a browser on a phone or computer on the same Wi-Fi.

#include <WiFi.h>
#include <WebServer.h>
#include <OneWire.h>
#include <DallasTemperature.h>

const char* WIFI_NAME = "YOUR_WIFI_NAME";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";
const int SENSOR_PIN = 27;

OneWire oneWire(SENSOR_PIN);
DallasTemperature sensors(&oneWire);
WebServer server(80);

float current = NAN, lowest = NAN, highest = NAN;
unsigned long lastRead = 0;

const char PAGE[] = R"rawliteral(
<!DOCTYPE html><html><head><meta charset='utf-8'>
<meta name='viewport' content='width=device-width, initial-scale=1'><title>Thermometer</title></head>
<body style='font-family:sans-serif;padding:16px;text-align:center'>
<h1>Thermometer</h1>
<p style='font-size:64px;margin:10px' id='now'>--</p>
<p>Lowest <b id='low'>--</b> &nbsp; Highest <b id='high'>--</b></p>
<button onclick="fetch('/reset')">Reset min / max</button>
<script>
async function update() {
  const d = await (await fetch('/data')).json();
  const show = (v) => v === null ? '--' : v.toFixed(1) + ' °C';
  document.getElementById('now').textContent = show(d.now);
  document.getElementById('low').textContent = show(d.low);
  document.getElementById('high').textContent = show(d.high);
}
setInterval(update, 2000);
update();
</script></body></html>
)rawliteral";

String number(float v) {
  return isnan(v) ? "null" : String(v, 2);   // JSON has no NaN, so send null
}

void setup() {
  Serial.begin(115200);
  sensors.begin();

  WiFi.begin(WIFI_NAME, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED) delay(500);
  Serial.print("Open http://");
  Serial.println(WiFi.localIP());

  server.on("/", []() { server.send(200, "text/html", PAGE); });
  server.on("/data", []() {
    String json = "{\"now\":" + number(current) + ",\"low\":" + number(lowest) + ",\"high\":" + number(highest) + "}";
    server.send(200, "application/json", json);
  });
  server.on("/reset", []() {
    lowest = current;
    highest = current;
    server.send(200, "text/plain", "ok");
  });
  server.begin();
}

void loop() {
  server.handleClient();

  if (millis() - lastRead >= 2000) {
    lastRead = millis();
    sensors.requestTemperatures();
    float t = sensors.getTempCByIndex(0);
    if (t == DEVICE_DISCONNECTED_C) {
      Serial.println("No DS18B20 found");
      return;
    }
    current = t;
    if (isnan(lowest) || t < lowest) lowest = t;
    if (isnan(highest) || t > highest) highest = t;
  }
}

How it works

The DS18B20 sends its readings digitally over the 1-Wire bus, so the signal doesn't lose accuracy over a long cable the way an analog voltage would. The module has the pull-up resistor the bus needs already on board. requestTemperatures() asks the sensor to measure, and getTempCByIndex(0) reads the first sensor on the bus. You could connect several on the same pin.

The sketch keeps three numbers: the current, lowest and highest temperature. They start as NAN ("not a number") until the first reading arrives. JSON has no way to write NaN, so the number() function sends null instead, and the page shows "--". The page asks for /data every two seconds; the Reset button calls /reset, which sets the minimum and maximum back to the current value.

Try this next

  • Turn the big number blue below 18 °C and red above 26 °C.
  • Add Fahrenheit next to Celsius.
  • Remember the time of the lowest and highest reading using the internet time from the alarm clock capstone.

Troubleshooting

  • It never connects to Wi-Fi: check the network name and password (both are case-sensitive) and make sure the network is 2.4 GHz.
  • The page doesn't open: the phone or computer must be on the same Wi-Fi as the ESP32, not on mobile data.
  • "No DS18B20 found": check the S wire on GPIO 27 and the + and − wires.
  • The temperature shows 85.0 °C: that's the sensor's start-up value. It means the power is unstable; check the + wire.
  • Compile error about OneWire.h or DallasTemperature.h: install both libraries.

Build it yourself

Everything used in this lesson comes in one kit, with parts tested by our engineers.

ESP32 IoT Starter Kit | Arduino IDE Compatible | Free Tutorials $57.00

Shop the kit