Sensors
Beginner
Ten Thermometers on One Wire: DS18B20 and the 1-Wire Bus
Waterproof DS18B20 probes connect in parallel to a single GPIO. Measure the boiler, water heater, outdoor and room temperature at once and serve it all as one JSON.
Why the DS18B20
- ±0.5 °C accuracy between −10 and +85 °C, full range −55…+125 °C.
- Sold in a waterproof probe with a 1–3 m cable — drop it in water or strap it to a pipe.
- Every sensor has a unique 64-bit address, so dozens of sensors can share one data wire.
Parts
- ESP32 DevKit
- 2–10 DS18B20 sensors (probe version recommended)
- One 4.7 kΩ resistor for the whole bus
Wiring
All sensors are wired in parallel:
| DS18B20 | ESP32 |
|---|---|
| Red (VDD) | 3V3 |
| Black (GND) | GND |
| Yellow (DATA) | GPIO 4 + 4.7 kΩ to 3V3 |
For cables over 10 m, drop the resistor to 2.2 kΩ and use twisted pair.
Libraries
- OneWire
- DallasTemperature
Code
Polling is non-blocking: we start a conversion and read the result 800 ms later — the web server keeps answering instantly in the meantime.
#include <WiFi.h>
#include <WebServer.h>
#include <OneWire.h>
#include <DallasTemperature.h>
const char* WIFI_SSID = "YOUR_SSID";
const char* WIFI_PASS = "YOUR_PASSWORD";
const int ONE_WIRE_PIN = 4;
const int MAX_SENSORS = 10;
OneWire oneWire(ONE_WIRE_PIN);
DallasTemperature sensors(&oneWire);
WebServer server(80);
DeviceAddress addrs[MAX_SENSORS];
float temps[MAX_SENSORS];
int count = 0;
bool converting = false;
unsigned long requestedAt = 0;
unsigned long lastCycle = 0;
String addrToString(const uint8_t *a) {
char buf[17];
for (int i = 0; i < 8; i++) sprintf(buf + i * 2, "%02X", a[i]);
return String(buf);
}
void handleData() {
String json = "[";
for (int i = 0; i < count; i++) {
if (i) json += ",";
json += "{\"id\":\"" + addrToString(addrs[i]) + "\",\"t\":";
json += temps[i] == DEVICE_DISCONNECTED_C ? String("null") : String(temps[i], 2);
json += "}";
}
json += "]";
server.send(200, "application/json", json);
}
void setup() {
Serial.begin(115200);
sensors.begin();
count = sensors.getDeviceCount();
if (count > MAX_SENSORS) count = MAX_SENSORS;
Serial.printf("Found %d sensor(s)\n", count);
for (int i = 0; i < count; i++) {
sensors.getAddress(addrs[i], i);
sensors.setResolution(addrs[i], 12); // 0.0625 °C, ~750 ms per reading
temps[i] = DEVICE_DISCONNECTED_C;
Serial.println(" " + addrToString(addrs[i]));
}
sensors.setWaitForConversion(false);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) delay(500);
Serial.println(WiFi.localIP());
server.on("/data", handleData);
server.begin();
}
void loop() {
server.handleClient();
if (!converting && millis() - lastCycle > 5000) {
sensors.requestTemperatures(); // all sensors convert at once
requestedAt = millis();
converting = true;
}
if (converting && millis() - requestedAt > 800) {
for (int i = 0; i < count; i++) {
temps[i] = sensors.getTempC(addrs[i]);
Serial.printf("%s: %.2f °C\n", addrToString(addrs[i]).c_str(), temps[i]);
}
converting = false;
lastCycle = millis();
}
}
Which sensor is which
The order in which the library finds sensors does not match the order you wired them. So:
- Connect the sensors and open the Serial Monitor — you'll see a list of addresses.
- Hold one probe in your hand — its temperature goes up.
- Label the address (e.g.
28FF4A1B...→ "boiler, flow").
From then on, bind to addresses in Home Assistant or elsewhere — they never change.
Troubleshooting
- −127 °C — the sensor isn't responding: check the contact and the 4.7 kΩ resistor.
- 85 °C right after power-up — that's the default value; the conversion hasn't finished yet.
- Not all sensors found on a long line — lower the resistor and avoid a "star" layout (daisy-chain instead).
Ideas
- Heating monitoring: boiler flow/return and the temperature difference.
- Freezer watchdog with a Telegram alert above −12 °C.
- An aquarium thermostat driving a heater relay.