Raspberry Pi

Raspberry Pi DS18B20 MQTT : publier plusieurs sondes de température 1-Wire

Activez le 1-Wire sur un Raspberry Pi, connectez plusieurs sondes de température DS18B20 sur une seule broche GPIO, lisez-les en Python sans bibliothèque supplémentaire et publiez en MQTT des mesures nommées et validées.

Plusieurs sondes de température étanches DS18B20 reliées à un Raspberry Pi sur un même bus 1-Wire et envoyant leurs mesures vers le cloud via MQTT
Essayez-le sur votre propre broker MQTTObtenez un broker MQTT privé et managé avec l’offre Free et partez d’exemples de code prêts à l’emploi.
Essayer gratuitement Exemples de code Aucune carte bancaire requise

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

  1. 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.
  2. w1_slave affiche NO sur la première ligne : le CRC a échoué à cause du bruit ou d'un câble long. Le script réessaie jusqu'à trois fois.
  3. Des sondes apparaissent et disparaissent du répertoire : connexions lâches ou bus surchargé ; vérifiez les soudures et la valeur du pull-up.
  4. 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.
  5. 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.

Articles liés

Journal d'accès RFID MQTT sur Raspberry Pi avec le lecteur RC522

Câblez un lecteur RFID RC522 sur un Raspberry Pi, lisez les badges en Python, vérifiez-les dans une liste blanche locale et publiez chaque tentative d'accès sous forme d'événement MQTT exploitable par vos outils de journalisation, tableaux de bord et alertes.

8 min de lecture

Installer Mosquitto sur Raspberry Pi comme broker MQTT local sécurisé

Installez Mosquitto sur un Raspberry Pi, sécurisez-le avec des mots de passe et une configuration de listener raisonnable, testez-le avec mosquitto_pub et mosquitto_sub, et découvrez quand un broker local doit faire un pont vers un broker cloud.

9 min de lecture

Tous les articles →

Votre broker MQTT privé, à quelques clics

Créez un compte, récupérez les identifiants de votre broker et connectez votre premier appareil — aucun serveur à installer, mettre à jour ou dimensionner.