Raspberry Pi

Raspberry Pi DS18B20 MQTT: Publish Multiple 1-Wire Temperature Probes

Enable 1-Wire on a Raspberry Pi, connect several DS18B20 temperature probes to one GPIO pin, read them from Python without extra libraries and publish named, validated readings over MQTT.

Several waterproof DS18B20 temperature probes connected to a Raspberry Pi on one 1-Wire bus, sending readings to the cloud in a raspberry pi ds18b20 mqtt project
Run this on your own MQTT brokerGet a private, managed MQTT broker on the Free plan and start from ready-made code samples.
Try it free Code samples No card required

A Raspberry Pi DS18B20 MQTT setup is the most robust way to measure temperatures in several places at once: freezer and fridge, flow and return pipes, an aquarium, a fermenter or a server rack. In this tutorial you will enable the 1-Wire bus, connect multiple waterproof probes to a single GPIO pin, read them from Python using only the kernel driver, and publish named, validated readings over MQTT.

Why the DS18B20 Is a Great Choice

The DS18B20 is a digital sensor, so cable length and electrical noise affect it far less than analogue sensors. Each probe has a unique 64-bit serial number burned in at the factory, which lets many probes share one data wire. Waterproof versions come in a stainless steel sleeve on a long cable, ready for liquids or outdoor use. Accuracy is about half a degree across the normal range, and resolution can be set up to 0.0625 °C.

Best of all, Raspberry Pi OS includes a kernel driver for it. You do not need any Python library to read the sensors; they appear as files.

Wiring One or Many Probes

All probes connect in parallel to the same three wires:

DS18B20 wire (waterproof probe) Raspberry Pi
Red: VDD 3.3 V (physical pin 1)
Black: GND GND (physical pin 6)
Yellow: DATA GPIO4 (physical pin 7)

Add one 4.7 k resistor between DATA and 3.3 V. That single pull-up serves the whole bus; do not add one per probe. Use three-wire (powered) mode as shown rather than parasitic power, which is less reliable with several probes. For long cable runs, a star layout with many branches is the hardest topology for 1-Wire; a single line with short stubs works best, and a lower pull-up such as 2.2 k can help on long buses.

Enabling 1-Wire

Enable the bus with raspi-config, or add the overlay yourself:

sudo raspi-config nonint do_onewire 0
# or, equivalently, add this line to /boot/firmware/config.txt:
# dtoverlay=w1-gpio,gpiopin=4
sudo reboot

After the reboot, list the detected probes:

ls /sys/bus/w1/devices/
cat /sys/bus/w1/devices/28-*/w1_slave

Each probe appears as a directory starting with 28-. The w1_slave file contains two lines: the first ends in YES when the CRC check passed, and the second ends with t= followed by the temperature in thousandths of a degree, for example t=21375 for 21.375 °C. The Raspberry Pi configuration documentation describes the 1-Wire overlay options.

Naming Your Probes

Serial numbers like 28-3c01d0752a8b mean nothing on a dashboard. Create probes.json mapping each serial to a short name that becomes part of the MQTT topic:

{
  "28-3c01d0752a8b": "freezer",
  "28-3c01d075f1e2": "fridge",
  "28-0316a2794bff": "outdoor"
}

To find which probe is which, warm one in your hand and see which reading rises. Probes not listed in the file are still published under their serial number, so a newly added probe never disappears silently.

Topic Layout

Topic Payload Retained
connectmq/demo/b81f2d/house/temp/<name> {"celsius": 4.2, "ts": ...} No
connectmq/demo/b81f2d/house/temp/all All probes in one JSON object No
connectmq/demo/b81f2d/house/status online / offline Yes

Per-probe topics suit dashboards and alert rules on a single value; the combined message is convenient for loggers that write one row per interval. Replace b81f2d with your own random string.

The Raspberry Pi DS18B20 MQTT Script

Save as ds18b20_mqtt.py:

#!/usr/bin/env python3
"""Read all DS18B20 probes on the 1-Wire bus and publish them to MQTT."""
import json
import os
import time
import uuid
from pathlib import Path

import paho.mqtt.client as mqtt

BROKER = os.getenv("MQTT_HOST", "broker.connectmq.com")
PORT = int(os.getenv("MQTT_PORT", "1883"))
USERNAME = os.getenv("MQTT_USERNAME")
PASSWORD = os.getenv("MQTT_PASSWORD")
CLIENT_ID = os.getenv("MQTT_CLIENT_ID", f"ds18b20-{uuid.uuid4().hex[:8]}")
PREFIX = os.getenv("MQTT_PREFIX", "connectmq/demo/b81f2d/house")
INTERVAL = int(os.getenv("PUBLISH_INTERVAL", "60"))
W1_DIR = Path("/sys/bus/w1/devices")
NAMES_FILE = Path(os.getenv("PROBES_FILE", "probes.json"))


def load_names():
    try:
        return json.loads(NAMES_FILE.read_text())
    except (OSError, json.JSONDecodeError):
        return {}


def read_probe(device: Path, retries: int = 3):
    """Return degrees Celsius, or None if the probe gives no valid reading."""
    for _ in range(retries):
        try:
            lines = (device / "w1_slave").read_text().strip().splitlines()
        except OSError:
            return None  # probe unplugged
        if len(lines) == 2 and lines[0].endswith("YES") and "t=" in lines[1]:
            millis = int(lines[1].split("t=")[1])
            if millis != 85000:  # 85.0 °C is the power-on reset value
                celsius = millis / 1000.0
                if -55.0 <= celsius <= 125.0:
                    return celsius
        time.sleep(0.2)
    return None


def on_connect(client, userdata, flags, reason_code, properties):
    if reason_code.is_failure:
        print(f"Connection refused: {reason_code}")
        return
    print(f"Connected as {CLIENT_ID}")
    client.publish(f"{PREFIX}/status", "online", qos=1, retain=True)


client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=CLIENT_ID)
client.on_connect = on_connect
client.will_set(f"{PREFIX}/status", "offline", qos=1, retain=True)
client.reconnect_delay_set(min_delay=1, max_delay=60)
if USERNAME:
    client.username_pw_set(USERNAME, PASSWORD)
if PORT == 8883:
    client.tls_set()
client.connect(BROKER, PORT, keepalive=60)
client.loop_start()

try:
    while True:
        started = time.monotonic()
        names = load_names()
        now = int(time.time())
        combined = {}
        for device in sorted(W1_DIR.glob("28-*")):
            name = names.get(device.name, device.name)
            celsius = read_probe(device)
            if celsius is None:
                combined[name] = None
                print(f"{name}: no valid reading")
                continue
            combined[name] = round(celsius, 2)
            payload = {"celsius": round(celsius, 2), "ts": now}
            client.publish(f"{PREFIX}/temp/{name}", json.dumps(payload), qos=1)
        client.publish(
            f"{PREFIX}/temp/all", json.dumps({"probes": combined, "ts": now}), qos=1
        )
        print(combined)
        time.sleep(max(0, INTERVAL - (time.monotonic() - started)))
except KeyboardInterrupt:
    pass
finally:
    client.publish(f"{PREFIX}/status", "offline", qos=1, retain=True).wait_for_publish(2)
    client.loop_stop()
    client.disconnect()

No sensor library is needed; paho-mqtt is the only dependency:

mkdir -p ~/ds18b20-mqtt && cd ~/ds18b20-mqtt
python3 -m venv .venv && source .venv/bin/activate
pip install "paho-mqtt>=2.0"
python ds18b20_mqtt.py

The script re-reads probes.json every cycle, so you can rename a probe without restarting. Missing or failing probes are reported as null in the combined message instead of being dropped, which makes a broken cable visible on the dashboard.

The Classic Pitfalls

  1. A reading of exactly 85.0 °C: the probe returned its power-on default before completing a conversion, typically caused by a weak supply or parasitic power. The script discards it.
  2. w1_slave shows NO in the first line: the CRC failed because of noise or a long cable. The script retries up to three times.
  3. Probes appear and disappear from the directory: loose connections or an overloaded bus; check solder joints and the pull-up value.
  4. No 28- directories at all: 1-Wire is not enabled, the data wire is not on GPIO4, or the pull-up is missing.
  5. Slow cycles with many probes: each 12-bit conversion takes up to about three quarters of a second, and the kernel reads probes one after another. Ten probes therefore take several seconds per cycle, which is fine at a 60-second interval.

Trading Resolution for Speed

Most applications do not need 0.0625 °C steps. Current kernels expose a resolution file for each probe, so you can lower it and shorten the conversion time:

cat /sys/bus/w1/devices/28-3c01d0752a8b/resolution
echo 10 | sudo tee /sys/bus/w1/devices/28-3c01d0752a8b/resolution

At 10 bits the step is 0.25 °C and each conversion finishes in a fraction of the 12-bit time, which helps when a bus carries many probes or you want faster updates. The setting lives in the probe's volatile memory, so it resets after a power cycle unless you also save it to the probe's EEPROM; check the kernel's w1_therm documentation for your version before writing to EEPROM.

Also think about where the probe sits rather than only how precise it is. A probe taped to a pipe measures the pipe more accurately when it is held tight with a metal clip and covered by insulation. A probe in a freezer should hang in the air, not touch a frozen package, unless the food temperature is what you want to know.

Watching the Readings

mosquitto_sub -h broker.connectmq.com -p 1883 -i watch-b81f2d \
  -t 'connectmq/demo/b81f2d/house/#' -v

You will see one message per probe, then the combined message, every minute. On the public MQTT test broker these topics are visible to everyone, so stick with test data and a random prefix.

Where to Go Next

A 1-Wire bus is a natural fit for a compact node; the script runs unchanged on a Raspberry Pi Zero 2 W MQTT sensor node. If you also want humidity, combine it with the Raspberry Pi DHT22 MQTT guide, which uses the same topic style. For long-term charts, the Raspberry Pi Grafana and InfluxDB stack subscribes to these topics through Telegraf and keeps months of history.

Production Setup

Freezer alarms and heating monitoring deserve a private, encrypted connection. ConnectMQ is a fully managed MQTT service: create a broker in the portal, then run the script with TLS:

export MQTT_PORT=8883
export MQTT_USERNAME=YOUR_USERNAME
export MQTT_PASSWORD=YOUR_PASSWORD
export MQTT_CLIENT_ID=YOUR_CLIENT_ID
export MQTT_PREFIX=home/kitchen
python ds18b20_mqtt.py

In the ConnectMQ portal, a threshold alert rule on home/kitchen/temp/freezer, for example above -12 °C, records an alert you can review in the alerts log. Run the script as a systemd service so it restarts after power cuts; the Raspberry Pi MQTT tutorial has the template.

Get Started with ConnectMQ

Send your probes to an MQTT broker in the cloud that dashboards, loggers and alert rules can reach from anywhere. Create a free ConnectMQ broker on the Serverless plan, no credit card needed, paste the generated credentials into your environment and connect over TLS on port 8883.

Frequently Asked Questions

How many DS18B20 probes can I connect to one Raspberry Pi pin?

Many probes can share a single bus thanks to their unique serial numbers. In practice, cable length and topology limit you before the address space does; a handful to a few dozen on a well-wired bus is realistic.

Why does my DS18B20 read 85 degrees?

85.0 °C is the value the sensor holds after power-on before its first conversion. It usually indicates a supply problem or a read that happened too early; discard it and check wiring.

Do I need a Python library to read a DS18B20?

No. The w1-gpio and w1-therm kernel drivers expose each probe as a file in /sys/bus/w1/devices, which plain Python can read.

Can I use a different GPIO pin for 1-Wire?

Yes. Set dtoverlay=w1-gpio,gpiopin=17 (or another pin) in /boot/firmware/config.txt and reboot.

Related articles

Pico W vs Pico 2 W for MQTT: RP2040 vs RP2350 Performance, Memory and TLS

The Pico 2 W keeps the Pico W's footprint and Wi-Fi chip but swaps the RP2040 for the faster RP2350. This comparison looks at what that means for MQTT devices: CPU, memory, TLS, security features, software support, and which board to buy for which project.

8 min read

Raspberry Pi RFID MQTT Access Logging with the RC522 Reader

Wire an RC522 RFID reader to a Raspberry Pi, read tags in Python, check them against a local allowlist and publish every access attempt as an MQTT event that loggers, dashboards and alerting tools can consume.

7 min read

All articles →

Your private MQTT broker is a few clicks away

Create an account, get your broker credentials and connect your first device — no servers to install, patch or scale.