ESP32 e Arduino

ESP32 DS18B20 MQTT: Várias Sondas de Temperatura em um Único Barramento

Ligue várias sondas DS18B20 a um único GPIO do ESP32, descubra seus endereços ROM, leia-as sem bloquear e publique cada sonda em seu próprio topic no broker.connectmq.com.

Três sondas DS18B20 à prova d'água compartilhando um fio até um ESP32 em um monitoramento de temperatura esp32 ds18b20 mqtt
Rode isso no seu próprio broker MQTTTenha um broker MQTT privado e gerenciado no plano Free e comece com exemplos de código prontos.
Teste grátis Exemplos de código Sem cartão de crédito

Uma montagem ESP32 DS18B20 MQTT permite que um único pino GPIO leia várias sondas de temperatura à prova d'água e publique cada uma em seu próprio topic. Neste tutorial, você vai ligar vários sensores DS18B20 em um barramento 1-Wire, identificá-los pelo endereço ROM, lê-los sem bloquear o cliente MQTT e publicar no broker.connectmq.com com um topic por sonda.

Por que o DS18B20 funciona bem em monitoramento multiponto

O DS18B20 é um sensor de temperatura digital com um endereço ROM único de 64 bits gravado de fábrica. Como cada sonda tem seu próprio endereço, dezenas delas podem compartilhar os mesmos três fios: alimentação, terra e dados. Isso o torna ideal para tarefas como:

  • Temperaturas de ida e retorno de um sistema de aquecimento.
  • Várias prateleiras de uma geladeira ou câmara fria.
  • Leituras de aquário, lago e ar ambiente a partir de um único controlador.
  • Monitoramento de pontos quentes em baterias ou gabinetes.

As versões à prova d'água em aço inoxidável são baratas e robustas, com precisão de cerca de meio grau na faixa típica. A desvantagem é a velocidade: uma conversão completa de 12 bits leva até 750 ms, e é por isso que leituras não bloqueantes importam quando há MQTT envolvido.

Peças e bibliotecas

  • Uma placa de desenvolvimento ESP32.
  • Dois ou mais sensores DS18B20 (TO-92 ou sonda à prova d'água).
  • Um resistor de 4,7 kOhm para o pull-up do barramento.
  • Arduino IDE 2.x com o pacote de placas esp32.
  • Bibliotecas: OneWire (de Paul Stoffregen, ou o fork mantido para ESP32), DallasTemperature de Miles Burton e PubSubClient.

Ligando várias sondas a um pino do ESP32

Todas as sondas são ligadas em paralelo:

Fio da sonda (cores típicas) Conecta em Observações
Vermelho (VDD) 3V3 do ESP32 Use alimentação normal, não o modo parasita
Preto (GND) GND do ESP32
Amarelo (DATA) GPIO 4 do ESP32 Um resistor de 4,7 kOhm do DATA para 3V3 para todo o barramento

Use apenas um resistor de pull-up para o barramento, posicionado perto do ESP32. As cores dos fios variam entre fornecedores, então confira o datasheet das suas sondas. Para trechos maiores que alguns metros, use cabo de par trançado, mantenha um barramento linear em vez de estrela e considere um pull-up mais forte, como 2,2 kOhm.

Organização de topics por sonda

Cada sonda publica em um topic que contém seu endereço ROM, de modo que os topics permanecem estáveis independentemente da ordem em que o barramento é enumerado:

Topic Retido Exemplo de payload
connectmq/demo/dsb2q6h/ds18b20/28ff641e8316034f/temperature Sim 21.62
connectmq/demo/dsb2q6h/ds18b20/summary Não {"28ff641e8316034f":21.62,"28aa1b2c3d4e5f60":4.12}
connectmq/demo/dsb2q6h/status Sim online / offline

Os topics por sonda são retidos para que um dashboard aberto depois mostre imediatamente o último valor de cada sonda. O topic de resumo é conveniente para consumidores que querem uma mensagem por ciclo. Ambos ficam dentro dos oito níveis de topic permitidos na área pública.

O sketch ESP32 DS18B20 MQTT

#include <WiFi.h>
#include <PubSubClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>

const char* WIFI_SSID     = "YOUR_WIFI_SSID";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";
const char* MQTT_HOST     = "broker.connectmq.com";
const uint16_t MQTT_PORT  = 1883;
const char* PREFIX        = "connectmq/demo/dsb2q6h";   // use seu próprio id aleatório
const uint8_t ONE_WIRE_PIN = 4;
const uint8_t MAX_PROBES   = 10;
const uint32_t INTERVAL_MS = 10000;
const uint32_t CONVERSION_MS = 750;                       // resolução de 12 bits

OneWire oneWire(ONE_WIRE_PIN);
DallasTemperature sensors(&oneWire);
WiFiClient   net;
PubSubClient mqtt(net);

DeviceAddress probes[MAX_PROBES];
char probeIds[MAX_PROBES][17];
uint8_t probeCount = 0;
String clientId, topicStatus;

unsigned long lastRequest = 0;
bool conversionPending = false;

void addressToHex(const DeviceAddress addr, char* out) {
  for (uint8_t i = 0; i < 8; i++) sprintf(out + i * 2, "%02x", addr[i]);
  out[16] = '\0';
}

void discoverProbes() {
  sensors.begin();
  probeCount = 0;
  uint8_t found = sensors.getDeviceCount();
  for (uint8_t i = 0; i < found && probeCount < MAX_PROBES; i++) {
    if (sensors.getAddress(probes[probeCount], i)) {
      sensors.setResolution(probes[probeCount], 12);
      addressToHex(probes[probeCount], probeIds[probeCount]);
      Serial.printf("Probe %u: %s\n", probeCount, probeIds[probeCount]);
      probeCount++;
    }
  }
  sensors.setWaitForConversion(false);   // nós mesmos esperamos, sem bloquear
  Serial.printf("%u probe(s) found\n", probeCount);
}

void connectWifi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED) delay(400);
  Serial.printf("Wi-Fi OK, IP %s\n", WiFi.localIP().toString().c_str());
}

void connectMqtt() {
  while (!mqtt.connected()) {
    if (mqtt.connect(clientId.c_str(), topicStatus.c_str(), 1, true, "offline")) {
      mqtt.publish(topicStatus.c_str(), "online", true);
      Serial.println("MQTT connected");
    } else {
      Serial.printf("MQTT failed, state %d\n", mqtt.state());
      delay(5000);
    }
  }
}

void publishReadings() {
  String summary = "{";
  for (uint8_t i = 0; i < probeCount; i++) {
    float c = sensors.getTempC(probes[i]);
    bool valid = (c != DEVICE_DISCONNECTED_C) && (c != 85.0f);   // 85.0 = valor de power-on

    String topic = String(PREFIX) + "/ds18b20/" + probeIds[i] + "/temperature";
    char value[16];
    if (valid) snprintf(value, sizeof(value), "%.2f", c);
    else       snprintf(value, sizeof(value), "error");
    mqtt.publish(topic.c_str(), value, true);

    if (i) summary += ",";
    summary += "\"" + String(probeIds[i]) + "\":" + (valid ? String(value) : String("null"));
  }
  summary += "}";
  String topic = String(PREFIX) + "/ds18b20/summary";
  mqtt.publish(topic.c_str(), summary.c_str());
  Serial.println(summary);
}

void setup() {
  Serial.begin(115200);
  discoverProbes();

  clientId    = "esp32-ds18b20-" + String((uint32_t)ESP.getEfuseMac(), HEX);
  topicStatus = String(PREFIX) + "/status";

  connectWifi();
  mqtt.setServer(MQTT_HOST, MQTT_PORT);
  mqtt.setBufferSize(1024);   // espaço para um resumo de até 10 sondas
  connectMqtt();
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) connectWifi();
  if (!mqtt.connected()) connectMqtt();
  mqtt.loop();                                // continua rodando durante as conversões

  unsigned long now = millis();
  if (!conversionPending && now - lastRequest >= INTERVAL_MS) {
    sensors.requestTemperatures();            // inicia a conversão em todas as sondas de uma vez
    lastRequest = now;
    conversionPending = true;
  }
  if (conversionPending && now - lastRequest >= CONVERSION_MS) {
    conversionPending = false;
    publishReadings();
  }
}

Testando as sondas

Assine todo o prefixo:

mosquitto_sub -h broker.connectmq.com -p 1883 -i ds-view-2q6h -t "connectmq/demo/dsb2q6h/#" -v

Segure uma sonda na mão e veja seu topic subir enquanto as outras ficam estáveis. Essa também é a forma mais rápida de descobrir qual sonda física corresponde a qual endereço ROM: etiquete cada cabo à medida que avança. Lembre-se de que a área pública de testes é visível para qualquer pessoa, então serve para experimentos e não para monitoramento real; veja a página do servidor MQTT público (gratuito) para conhecer seus limites.

Como funciona a leitura não bloqueante

requestTemperatures() envia um único comando "convert" para todas as sondas ao mesmo tempo, então dez sondas levam os mesmos 750 ms que uma. Com setWaitForConversion(false), a chamada retorna imediatamente e o loop continua chamando mqtt.loop() enquanto as sondas trabalham. Só depois de passado o tempo de conversão o sketch lê cada sonda pelo endereço, o que leva alguns milissegundos por sonda.

Se você não precisa de passos de 0,0625 grau, reduza a resolução. Com 10 bits, a conversão leva cerca de 188 ms e o passo passa a ser de 0,25 grau, o que é mais que suficiente para monitorar ambientes ou geladeiras.

Dando nomes amigáveis às sondas

Os endereços ROM são estáveis, mas não são legíveis. Duas abordagens funcionam bem:

  1. Mapear no firmware. Mantenha uma pequena tabela de endereço para nome, como flow, return ou freezer, e use o nome no topic. É simples, mas cada troca de sonda exige regravar o firmware.
  2. Mapear mais adiante. Mantenha o endereço no topic e deixe o consumidor, por exemplo um fluxo do Node-RED ou o dashboard, traduzir endereços em nomes. Substituir uma sonda passa a significar editar um mapeamento, e não o firmware.

A segunda abordagem escala melhor. Ela também corresponde à forma como um gateway Modbus RS485 normalmente publica identidades brutas de registradores e deixa uma camada superior atribuir o significado.

Detectando uma sonda com falha ou ausente

Uma sonda que para de reportar silenciosamente é pior que uma que reporta um erro, porque um topic retido continua mostrando o último valor bom para sempre. O sketch trata isso de duas formas. Primeiro, publica a string error no topic retido da sonda quando a leitura retorna -127 ou 85, para que o número desatualizado seja sobrescrito. Segundo, a mensagem de resumo contém null para essa sonda, o que a maioria dos consumidores trata como lacuna e não como zero.

Você pode ir além publicando o número de sondas encontradas no boot, por exemplo em um topic retido ds18b20/count, e comparando-o com o número esperado no dashboard. Se um cabo for cortado, a contagem cai na próxima redescoberta e a diferença fica evidente. Para usos críticos, observe também a idade das mensagens: se o topic de uma sonda não muda há três intervalos, trate o dispositivo como problemático mesmo que o status ainda diga online.

Checklist de solução de problemas

Sintoma Causa Solução
0 sondas encontradas Pull-up ausente ou pino errado Adicione 4,7 kOhm do DATA para 3V3, confira ONE_WIRE_PIN
Leitura -127 Sonda desconectada ou barramento ruidoso Verifique as emendas, encurte o cabo, reduza o valor do pull-up
Leitura 85.0 Lida antes de a conversão terminar, ou falha de alimentação Mantenha a espera de 750 ms, use alimentação normal
Algumas sondas somem em trechos longos Ligação em estrela ou capacitância excessiva Use um barramento linear com par trançado
Mensagem de resumo ausente Payload maior que o buffer Aumente o setBufferSize
Sondas encontradas só após reiniciar Sonda conectada com o sistema ligado Chame discoverProbes() periodicamente ou por comando

Configuração para produção

Quando as sondas protegem algo importante, como um freezer, migre para um broker autenticado. Crie um em app.connectmq.com, mude para WiFiClientSecure na porta 8883 com o certificado ISRG Root X1 e conecte com YOUR_CLIENT_ID, YOUR_USERNAME e YOUR_PASSWORD. No portal do ConnectMQ, adicione uma regra de alerta por limite no topic da sonda do freezer e você terá um alarme básico de sobretemperatura sem escrever código de backend. Se você mede energia junto com temperatura, o monitor de energia com SCT-013 publica em uma estrutura compatível, e o projeto ESP32 DHT22 adiciona umidade em um único ponto.

Comece com o ConnectMQ

O monitoramento com várias sondas, como nas câmaras frias de um frigorífico, precisa de um broker que esteja sempre disponível quando uma sonda ultrapassar um limite. O ConnectMQ é um broker MQTT gerenciado com TLS, mensagens retidas, explorador de topics ao vivo e regras de alerta, e o plano gratuito Serverless não exige cartão de crédito. Aponte este sketch para o seu próprio broker e navegue pelo hub do tutorial de IoT com ESP32 para o próximo projeto.

Perguntas frequentes

Quantos sensores DS18B20 um pino do ESP32 suporta?

O protocolo permite muitos dispositivos por barramento, e de dez a vinte funcionam de forma confiável com boa fiação e alimentação normal. O comprimento do cabo e a topologia limitam você muito antes do espaço de endereços.

Por que um DS18B20 às vezes lê 85 graus?

85.0 é o valor de reset do scratchpad na energização. Ele aparece quando a leitura acontece antes de uma conversão terminar, muitas vezes após uma falha de alimentação. Trate-o como erro.

Cada sonda deve ter seu próprio topic MQTT?

Topics retidos por sonda simplificam os dashboards e mantêm o último valor disponível. Uma mensagem de resumo por ciclo é um complemento útil para consumidores que querem todos os valores juntos.

Posso usar alimentação parasita para economizar um fio?

Pode, mas ela é menos confiável em trechos longos e com muitas sondas. Use alimentação normal de três fios sempre que possível.

Artigos relacionados

Exemplo de MQTT com ESP-IDF: Monte um Cliente esp-mqtt do Zero

Monte um projeto ESP-IDF a partir de uma pasta vazia com o componente esp-mqtt: configuração do Wi-Fi em modo station, o handler de eventos MQTT, publicação e inscrição, propriedades do MQTT 5 e TLS com o bundle de certificados.

8 min de leitura

Usando os Recursos do MQTT 5 do esp-mqtt no ESP32 com ESP-IDF

Um projeto ESP-IDF prático que ativa o MQTT 5.0 no esp-mqtt e usa user properties, expiração de mensagens, topic aliases, expiração de sessão e response topics com um broker MQTT 5 real.

8 min de leitura

Todos os artigos →

Seu broker MQTT privado está a poucos cliques de distância

Crie uma conta, receba as credenciais do seu broker e conecte seu primeiro dispositivo — sem servidores para instalar, atualizar ou escalar.