Une installation Raspberry Pi DS18B20 MQTT est la manière la plus robuste de mesurer des températures à plusieurs endroits à la fois : congélateur et réfrigérateur, départ et retour de chauffage, aquarium, fermenteur ou baie serveur. Dans ce tutoriel, vous activerez le bus 1-Wire, connecterez plusieurs sondes étanches sur une seule broche GPIO, les lirez en Python avec le seul pilote du noyau, et publierez en MQTT des mesures nommées et validées.
Pourquoi le DS18B20 est un excellent choix
Le DS18B20 est un capteur numérique : la longueur de câble et le bruit électrique l'affectent bien moins que les capteurs analogiques. Chaque sonde possède un numéro de série unique de 64 bits gravé en usine, ce qui permet à de nombreuses sondes de partager un même fil de données. Les versions étanches sont logées dans un tube en acier inoxydable au bout d'un long câble, prêtes pour les liquides ou l'extérieur. La précision est d'environ un demi-degré sur la plage normale, et la résolution peut descendre jusqu'à 0,0625 °C.
Mieux encore, Raspberry Pi OS inclut un pilote noyau pour ce capteur. Aucune bibliothèque Python n'est nécessaire pour lire les sondes : elles apparaissent sous forme de fichiers.
Câbler une ou plusieurs sondes
Toutes les sondes se branchent en parallèle sur les trois mêmes fils :
| Fil du DS18B20 (sonde étanche) | Raspberry Pi |
|---|---|
| Rouge : VDD | 3,3 V (broche physique 1) |
| Noir : GND | GND (broche physique 6) |
| Jaune : DATA | GPIO4 (broche physique 7) |
Ajoutez une résistance de 4,7 k entre DATA et 3,3 V. Ce seul pull-up dessert tout le bus ; n'en ajoutez pas un par sonde. Utilisez le mode trois fils (alimenté) comme indiqué plutôt que l'alimentation parasite, moins fiable avec plusieurs sondes. Pour les grandes longueurs de câble, une topologie en étoile avec de nombreuses branches est la plus difficile pour le 1-Wire ; une ligne unique avec de courtes dérivations fonctionne le mieux, et un pull-up plus faible, comme 2,2 k, peut aider sur les bus longs.
Activer le 1-Wire
Activez le bus avec raspi-config, ou ajoutez l'overlay vous-même :
sudo raspi-config nonint do_onewire 0
# ou, de manière équivalente, ajoutez cette ligne à /boot/firmware/config.txt :
# dtoverlay=w1-gpio,gpiopin=4
sudo reboot
Après le redémarrage, listez les sondes détectées :
ls /sys/bus/w1/devices/
cat /sys/bus/w1/devices/28-*/w1_slave
Chaque sonde apparaît comme un répertoire commençant par 28-. Le fichier w1_slave contient deux lignes : la première se termine par YES lorsque le contrôle CRC a réussi, et la seconde se termine par t= suivi de la température en millièmes de degré, par exemple t=21375 pour 21,375 °C. La documentation de configuration du Raspberry Pi décrit les options de l'overlay 1-Wire.
Nommer vos sondes
Des numéros de série comme 28-3c01d0752a8b ne veulent rien dire sur un tableau de bord. Créez un fichier probes.json qui associe chaque numéro de série à un nom court, intégré ensuite au topic MQTT :
{
"28-3c01d0752a8b": "freezer",
"28-3c01d075f1e2": "fridge",
"28-0316a2794bff": "outdoor"
}
Pour savoir quelle sonde est laquelle, réchauffez-en une dans votre main et regardez quelle mesure augmente. Les sondes absentes du fichier sont tout de même publiées sous leur numéro de série : une sonde nouvellement ajoutée ne disparaît donc jamais en silence.
Organisation des topics
| Topic | Payload | Retenu |
|---|---|---|
connectmq/demo/b81f2d/house/temp/<name> |
{"celsius": 4.2, "ts": ...} |
Non |
connectmq/demo/b81f2d/house/temp/all |
Toutes les sondes dans un seul objet JSON | Non |
connectmq/demo/b81f2d/house/status |
online / offline |
Oui |
Les topics par sonde conviennent aux tableaux de bord et aux règles d'alerte sur une valeur unique ; le message combiné est pratique pour les enregistreurs qui écrivent une ligne par intervalle. Remplacez b81f2d par votre propre chaîne aléatoire.
Le script Raspberry Pi DS18B20 MQTT
Enregistrez-le sous 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 # sonde débranchée
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 est la valeur de réinitialisation à la mise sous tension
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()
Aucune bibliothèque de capteur n'est nécessaire ; paho-mqtt est la seule dépendance :
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
Le script relit probes.json à chaque cycle : vous pouvez donc renommer une sonde sans redémarrer. Les sondes absentes ou défaillantes sont signalées par null dans le message combiné au lieu d'être ignorées, ce qui rend un câble coupé visible sur le tableau de bord.
Les pièges classiques
- Une mesure d'exactement 85,0 °C : la sonde a renvoyé sa valeur par défaut de mise sous tension avant d'avoir terminé une conversion, généralement à cause d'une alimentation faible ou du mode parasite. Le script l'écarte.
w1_slaveafficheNOsur la première ligne : le CRC a échoué à cause du bruit ou d'un câble long. Le script réessaie jusqu'à trois fois.- Des sondes apparaissent et disparaissent du répertoire : connexions lâches ou bus surchargé ; vérifiez les soudures et la valeur du pull-up.
- Aucun répertoire
28-: le 1-Wire n'est pas activé, le fil de données n'est pas sur GPIO4 ou le pull-up manque. - Cycles lents avec beaucoup de sondes : chaque conversion 12 bits prend jusqu'à environ trois quarts de seconde, et le noyau lit les sondes l'une après l'autre. Dix sondes demandent donc plusieurs secondes par cycle, ce qui ne pose pas de problème avec un intervalle de 60 secondes.
Échanger de la résolution contre de la vitesse
La plupart des applications n'ont pas besoin d'un pas de 0,0625 °C. Les noyaux actuels exposent un fichier resolution pour chaque sonde : vous pouvez l'abaisser et raccourcir le temps de conversion :
cat /sys/bus/w1/devices/28-3c01d0752a8b/resolution
echo 10 | sudo tee /sys/bus/w1/devices/28-3c01d0752a8b/resolution
En 10 bits, le pas est de 0,25 °C et chaque conversion se termine en une fraction du temps nécessaire en 12 bits, ce qui aide lorsqu'un bus porte beaucoup de sondes ou que vous voulez des mises à jour plus rapides. Ce réglage réside dans la mémoire volatile de la sonde : il est réinitialisé après une coupure d'alimentation, sauf si vous l'enregistrez aussi dans l'EEPROM de la sonde ; consultez la documentation w1_therm de votre version du noyau avant d'écrire dans l'EEPROM.
Pensez aussi à l'emplacement de la sonde, et pas seulement à sa précision. Une sonde fixée sur un tuyau mesure plus fidèlement la température du tuyau lorsqu'elle est serrée par un collier métallique et recouverte d'isolant. Dans un congélateur, une sonde doit pendre dans l'air sans toucher un produit congelé, sauf si c'est la température des aliments qui vous intéresse.
Observer les mesures
mosquitto_sub -h broker.connectmq.com -p 1883 -i watch-b81f2d \
-t 'connectmq/demo/b81f2d/house/#' -v
Vous verrez un message par sonde, puis le message combiné, toutes les minutes. Sur le serveur MQTT public gratuit, ces topics sont visibles par tout le monde : contentez-vous de données de test et d'un préfixe aléatoire.
Pour aller plus loin
Un bus 1-Wire se prête naturellement à un nœud compact ; le script fonctionne sans modification sur un nœud capteur MQTT Raspberry Pi Zero 2 W. Si vous voulez aussi l'humidité, combinez-le avec le guide Raspberry Pi DHT22 MQTT, qui utilise le même style de topics. Pour des courbes à long terme, la pile Grafana et InfluxDB sur Raspberry Pi s'abonne à ces topics via Telegraf et conserve des mois d'historique. Ces sondes s'intègrent aussi très bien dans une maison connectée : Home Assistant, Jeedom et Domoticz savent tous communiquer en MQTT.
Mise en production
Les alarmes de congélateur et la surveillance du chauffage méritent une connexion privée et chiffrée. ConnectMQ est un broker MQTT managé : créez un broker dans le portail, puis lancez le script avec 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
Dans le portail ConnectMQ, une règle d'alerte de seuil sur home/kitchen/temp/freezer, par exemple au-dessus de -12 °C, enregistre une alerte que vous pouvez consulter dans le journal des alertes. Exécutez le script comme service systemd pour qu'il redémarre après une coupure de courant ; le tutoriel MQTT sur Raspberry Pi en fournit le modèle.
Démarrer avec ConnectMQ
Envoyez vos sondes vers un broker MQTT dans le cloud que tableaux de bord, enregistreurs et règles d'alerte peuvent atteindre de partout. Créez un broker ConnectMQ gratuit avec l'offre Serverless, sans carte bancaire, collez les identifiants générés dans votre environnement et connectez-vous en TLS sur le port 8883.
Questions fréquentes
Combien de sondes DS18B20 peut-on connecter sur une broche du Raspberry Pi ?
De nombreuses sondes peuvent partager un même bus grâce à leurs numéros de série uniques. En pratique, la longueur de câble et la topologie vous limitent avant l'espace d'adressage ; de quelques sondes à quelques dizaines sur un bus bien câblé, c'est réaliste.
Pourquoi mon DS18B20 affiche-t-il 85 degrés ?
85,0 °C est la valeur que le capteur conserve après la mise sous tension, avant sa première conversion. Elle indique généralement un problème d'alimentation ou une lecture trop précoce ; écartez-la et vérifiez le câblage.
Faut-il une bibliothèque Python pour lire un DS18B20 ?
Non. Les pilotes noyau w1-gpio et w1-therm exposent chaque sonde sous forme de fichier dans /sys/bus/w1/devices, que du Python standard peut lire.
Peut-on utiliser une autre broche GPIO pour le 1-Wire ?
Oui. Indiquez dtoverlay=w1-gpio,gpiopin=17 (ou une autre broche) dans /boot/firmware/config.txt et redémarrez.



