Uma montagem Raspberry Pi DS18B20 MQTT é a forma mais robusta de medir temperaturas em vários pontos ao mesmo tempo: freezer e geladeira, tubulações de ida e retorno, um aquário, um fermentador, um painel elétrico ou um rack de servidores. Neste tutorial você vai ativar o barramento 1-Wire, ligar várias sondas à prova d'água a um único pino GPIO, lê-las em Python usando apenas o driver do kernel e publicar leituras nomeadas e validadas via MQTT.
Por que o DS18B20 é uma ótima escolha
O DS18B20 é um sensor digital, então o comprimento do cabo e o ruído elétrico o afetam muito menos do que os sensores analógicos. Cada sonda tem um número de série único de 64 bits gravado de fábrica, o que permite que muitas sondas compartilhem o mesmo fio de dados. As versões à prova d'água vêm em uma capa de aço inox com cabo longo, prontas para líquidos ou uso externo. A precisão é de cerca de meio grau na faixa normal, e a resolução pode chegar a 0,0625 °C.
O melhor de tudo: o Raspberry Pi OS já inclui um driver de kernel para ele. Você não precisa de nenhuma biblioteca Python para ler os sensores; eles aparecem como arquivos.
Ligando uma ou várias sondas
Todas as sondas são ligadas em paralelo aos mesmos três fios:
| Fio do DS18B20 (sonda à prova d'água) | Raspberry Pi |
|---|---|
| Vermelho: VDD | 3,3 V (pino físico 1) |
| Preto: GND | GND (pino físico 6) |
| Amarelo: DATA | GPIO4 (pino físico 7) |
Adicione um resistor de 4,7 k entre DATA e 3,3 V. Esse único pull-up atende o barramento inteiro; não coloque um por sonda. Use o modo de três fios (alimentado), como mostrado, em vez da alimentação parasita, que é menos confiável com várias sondas. Em cabos longos, uma topologia em estrela com muitas ramificações é a mais difícil para o 1-Wire; uma linha única com derivações curtas funciona melhor, e um pull-up menor, como 2,2 k, pode ajudar em barramentos longos.
Ativando o 1-Wire
Ative o barramento com o raspi-config ou adicione o overlay manualmente:
sudo raspi-config nonint do_onewire 0
# ou, de forma equivalente, adicione esta linha a /boot/firmware/config.txt:
# dtoverlay=w1-gpio,gpiopin=4
sudo reboot
Depois de reiniciar, liste as sondas detectadas:
ls /sys/bus/w1/devices/
cat /sys/bus/w1/devices/28-*/w1_slave
Cada sonda aparece como um diretório que começa com 28-. O arquivo w1_slave contém duas linhas: a primeira termina em YES quando a verificação de CRC passou, e a segunda termina com t= seguido da temperatura em milésimos de grau, por exemplo t=21375 para 21,375 °C. A documentação de configuração do Raspberry Pi descreve as opções do overlay 1-Wire.
Dando nome às sondas
Números de série como 28-3c01d0752a8b não dizem nada em um dashboard. Crie um probes.json que associe cada número de série a um nome curto, que passará a fazer parte do topic MQTT:
{
"28-3c01d0752a8b": "freezer",
"28-3c01d075f1e2": "fridge",
"28-0316a2794bff": "outdoor"
}
Para descobrir qual sonda é qual, aqueça uma delas na mão e veja qual leitura sobe. Sondas que não estão no arquivo continuam sendo publicadas com o número de série, então uma sonda recém-adicionada nunca some sem aviso.
Estrutura de topics
| Topic | Payload | Retained |
|---|---|---|
connectmq/demo/b81f2d/house/temp/<name> |
{"celsius": 4.2, "ts": ...} |
Não |
connectmq/demo/b81f2d/house/temp/all |
Todas as sondas em um único objeto JSON | Não |
connectmq/demo/b81f2d/house/status |
online / offline |
Sim |
Os topics por sonda são ideais para dashboards e regras de alerta sobre um único valor; a mensagem combinada é prática para loggers que gravam uma linha por intervalo. Substitua b81f2d por uma string aleatória sua.
O script Raspberry Pi DS18B20 MQTT
Salve como 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 # sonda desconectada
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 é o valor de reset ao ligar
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()
Nenhuma biblioteca de sensor é necessária; a paho-mqtt é a única dependência:
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
O script relê o probes.json a cada ciclo, então você pode renomear uma sonda sem reiniciar. Sondas ausentes ou com falha aparecem como null na mensagem combinada em vez de serem descartadas, o que torna um cabo rompido visível no dashboard.
As armadilhas clássicas
- Uma leitura de exatamente 85,0 °C: a sonda devolveu seu valor padrão de inicialização antes de concluir uma conversão, normalmente por alimentação fraca ou alimentação parasita. O script descarta esse valor.
- O
w1_slavemostraNOna primeira linha: o CRC falhou por causa de ruído ou de um cabo longo. O script tenta de novo até três vezes. - Sondas aparecem e somem do diretório: conexões frouxas ou barramento sobrecarregado; verifique as soldas e o valor do pull-up.
- Nenhum diretório
28-: o 1-Wire não está ativado, o fio de dados não está no GPIO4 ou falta o pull-up. - Ciclos lentos com muitas sondas: cada conversão de 12 bits leva até cerca de três quartos de segundo, e o kernel lê as sondas uma após a outra. Dez sondas levam, portanto, vários segundos por ciclo, o que não é problema com um intervalo de 60 segundos.
Trocando resolução por velocidade
A maioria das aplicações não precisa de passos de 0,0625 °C. Os kernels atuais expõem um arquivo resolution para cada sonda, então você pode reduzi-la e encurtar o tempo de conversão:
cat /sys/bus/w1/devices/28-3c01d0752a8b/resolution
echo 10 | sudo tee /sys/bus/w1/devices/28-3c01d0752a8b/resolution
Com 10 bits o passo é de 0,25 °C e cada conversão termina em uma fração do tempo de 12 bits, o que ajuda quando um barramento tem muitas sondas ou você quer atualizações mais rápidas. A configuração fica na memória volátil da sonda, então volta ao padrão após um ciclo de energia, a menos que você também a grave na EEPROM da sonda; consulte a documentação do w1_therm do seu kernel antes de gravar na EEPROM.
Pense também em onde a sonda fica, e não só em quão precisa ela é. Uma sonda presa a um cano mede o cano com mais precisão quando está bem fixada com uma abraçadeira metálica e coberta por isolamento. Uma sonda no freezer deve ficar suspensa no ar, sem encostar em uma embalagem congelada, a menos que você queira saber justamente a temperatura do alimento.
Acompanhando as leituras
mosquitto_sub -h broker.connectmq.com -p 1883 -i watch-b81f2d \
-t 'connectmq/demo/b81f2d/house/#' -v
Você verá uma mensagem por sonda e depois a mensagem combinada, a cada minuto. No servidor MQTT público esses topics ficam visíveis para todo mundo, então use apenas dados de teste e um prefixo aleatório; ele serve para testes e protótipos, não para dados de produção.
Próximos passos
Um barramento 1-Wire combina muito bem com um nó compacto; o script roda sem alterações em um nó sensor MQTT com Raspberry Pi Zero 2 W. Se você também quiser medir umidade, combine-o com o guia Raspberry Pi DHT22 MQTT, que usa o mesmo estilo de topics. Para gráficos de longo prazo, a stack Raspberry Pi com Grafana e InfluxDB assina esses topics pelo Telegraf e guarda meses de histórico.
Configuração para produção
Alarmes de freezer e monitoramento de aquecimento merecem uma conexão privada e criptografada. O ConnectMQ é um broker MQTT gerenciado: crie um broker no portal e rode o script com 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
No portal do ConnectMQ, uma regra de alerta por limite em home/kitchen/temp/freezer, por exemplo acima de -12 °C, registra um alerta que você pode revisar no log de alertas. Rode o script como serviço do systemd para que ele reinicie depois de quedas de energia; o tutorial MQTT com Raspberry Pi traz o modelo.
Comece com o ConnectMQ
Envie as leituras das suas sondas para um broker MQTT na nuvem que dashboards, loggers e regras de alerta possam acessar de qualquer lugar. Crie um broker ConnectMQ gratuito no plano Serverless, sem cartão de crédito, cole as credenciais geradas no seu ambiente e conecte via TLS na porta 8883.
Perguntas frequentes
Quantas sondas DS18B20 posso ligar a um único pino do Raspberry Pi?
Muitas sondas podem compartilhar um único barramento graças aos seus números de série únicos. Na prática, o comprimento do cabo e a topologia limitam você antes do espaço de endereços; algumas unidades a algumas dezenas em um barramento bem cabeado é algo realista.
Por que meu DS18B20 marca 85 graus?
85,0 °C é o valor que o sensor guarda depois de ligado, antes da primeira conversão. Normalmente indica um problema de alimentação ou uma leitura feita cedo demais; descarte o valor e verifique a ligação.
Preciso de uma biblioteca Python para ler um DS18B20?
Não. Os drivers de kernel w1-gpio e w1-therm expõem cada sonda como um arquivo em /sys/bus/w1/devices, que o Python puro consegue ler.
Posso usar outro pino GPIO para o 1-Wire?
Sim. Defina dtoverlay=w1-gpio,gpiopin=17 (ou outro pino) em /boot/firmware/config.txt e reinicie.



