Automação IoT

Hidrômetro com MQTT: Leia Pulsos com um ESP32 e Acompanhe o Consumo de Água

Leia seu hidrômetro com um sensor reed, indutivo ou óptico e um ESP32, guarde o total com segurança entre reinícios, publique litros e vazão via MQTT e detecte vazamentos a partir de fluxo contínuo.

Hidrômetro residencial com um sensor preso sobre o mostrador e um ESP32 enviando leituras em uma montagem de hidrômetro 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

Um leitor de hidrômetro com MQTT transforma o mostrador no seu porão ou na sua caixa de medição em dados de consumo ao vivo: litros por dia, vazão atual e um alerta precoce quando a água continua correndo sem motivo. Neste tutorial você vai escolher o sensor certo para o seu hidrômetro, contar pulsos com um ESP32, manter o total seguro durante quedas de energia e publicá-lo em um broker MQTT. Você também vai adicionar uma lógica de detecção de vazamentos que flagra uma torneira pingando ou um cano estourado.

Escolhendo um sensor para o seu hidrômetro

A maioria dos hidrômetros residenciais é mecânica e não tem porta de dados. A leitura é feita detectando algo que se move uma vez por litro (ou a cada dez litros). Verifique seu hidrômetro antes de comprar peças:

Característica do hidrômetro Sensor Como funciona Observações
Cabo de saída de pulsos ou marcação "pulse-ready" Módulo de contato reed do fabricante do hidrômetro Fecha uma vez por litro ou a cada 10 litros O mais confiável, sinal limpo
Ímã giratório (alguns modelos) Chave reed ou sensor hall fixado por cima O ímã passa pelo sensor a cada volta Verifique com um app de bússola no celular
Meio disco metálico no ponteiro de litros Sensor de proximidade indutivo (ex.: LJ18A3-8-Z/BX) Detecta o metal quando ele passa Escolha comum; normalmente exige alimentação de 5-12 V e um conversor de nível ou divisor
Marcador reflexivo no mostrador Sensor reflexivo infravermelho (estilo TCRT5000) Detecta o segmento claro/escuro Sensível ao alinhamento e à luz ambiente
Nenhuma característica aproveitável Câmera com reconhecimento de dígitos (ESP32-CAM) Lê os dígitos opticamente O projeto "AI-on-the-edge-device" publica em MQTT por conta própria

Nunca abra nem modifique o hidrômetro; normalmente ele pertence à concessionária. Todos os sensores acima são presos ou fixados pelo lado de fora.

Ligando o ESP32

Este tutorial usa um sinal de pulso no GPIO 25 que vai para nível baixo uma vez por litro. Para uma chave reed, ligue-a entre o GPIO 25 e o GND e use o pull-up interno. Para um sensor indutivo NPN alimentado com 5 a 12 V, ligue sua saída ao GPIO 25 com o pull-up interno ativado; saídas NPN de coletor aberto puxam a linha para baixo e nunca a levam acima de 3,3 V, mas confira a folha de dados do seu sensor, pois alguns módulos incluem um pull-up para a própria tensão de alimentação e, nesse caso, um divisor de tensão é obrigatório.

Decisões de projeto que fazem diferença

Um leitor de hidrômetro parece simples, mas três detalhes decidem se os seus números são confiáveis:

  1. O total precisa sobreviver a reinícios. Se o ESP32 reiniciar e contar a partir de zero, seu gráfico de consumo diário quebra. O sketch armazena o total na flash (NVS) e permite ajustá-lo para coincidir com o mostrador físico.
  2. Desgaste da flash. Gravar na flash a cada pulso a desgasta rapidamente. Salve quando a contagem tiver mudado e no máximo a cada poucos minutos, aceitando que uma queda de energia pode perder alguns litros.
  3. Debounce. Contatos mecânicos trepidam, e um sensor indutivo pode oscilar na borda do metal. Um debounce curto por software evita contagens duplas.

Tópicos desta montagem:

connectmq/demo/<random-id>/water/main/telemetry     JSON every 60 s, retained
connectmq/demo/<random-id>/water/main/status        online/offline (Last Will), retained
connectmq/demo/<random-id>/water/main/set/total_l   command: set the total to match the dial

O sketch do hidrômetro MQTT para ESP32

Instale a PubSubClient, de Nick O'Leary, pelo Library Manager. A Preferences faz parte do core Arduino do ESP32.

#include <WiFi.h>
#include <PubSubClient.h>
#include <Preferences.h>

const char* WIFI_SSID = "YOUR_WIFI";
const char* WIFI_PASS = "YOUR_WIFI_PASSWORD";
const char* MQTT_HOST = "broker.connectmq.com";
const uint16_t MQTT_PORT = 1883;
const char* PREFIX = "connectmq/demo/w8m3d1/water/main";

const int PIN_PULSE = 25;
const float LITRES_PER_PULSE = 1.0;          // 10.0 em muitos módulos de pulso de fabricantes
const uint32_t SAVE_INTERVAL_MS = 5UL * 60 * 1000;
const uint32_t PUBLISH_INTERVAL_MS = 60UL * 1000;

WiFiClient net;
PubSubClient mqtt(net);
Preferences prefs;

volatile uint32_t pulses = 0;
volatile uint32_t lastPulseMs = 0;
uint64_t baseLitresX10 = 0;      // total armazenado, em unidades de 0,1 L
uint32_t savedPulses = 0, lastSaveMs = 0, lastPublishMs = 0, pulsesAtPublish = 0;
char clientId[32], topicStatus[96], topicTelemetry[96], topicSet[96];

void IRAM_ATTR onPulse() {
  uint32_t now = millis();
  if (now - lastPulseMs > 50) { pulses++; lastPulseMs = now; }   // debounce de 50 ms
}

double totalLitres() {
  noInterrupts(); uint32_t p = pulses; interrupts();
  return baseLitresX10 / 10.0 + p * LITRES_PER_PULSE;
}

void saveTotal() {
  noInterrupts(); uint32_t p = pulses; interrupts();
  if (p == savedPulses) return;                     // nada novo, sem gravar na flash
  prefs.putULong64("total_x10", baseLitresX10 + (uint64_t)(p * LITRES_PER_PULSE * 10));
  savedPulses = p;
}

void onMessage(char* topic, byte* payload, unsigned int len) {
  if (strcmp(topic, topicSet) != 0) return;
  char buf[24];
  len = min(len, (unsigned int)sizeof(buf) - 1);
  memcpy(buf, payload, len); buf[len] = 0;
  double litres = atof(buf);
  if (litres <= 0) return;
  noInterrupts(); pulses = 0; interrupts();
  baseLitresX10 = (uint64_t)(litres * 10);
  savedPulses = 0; pulsesAtPublish = 0;
  prefs.putULong64("total_x10", baseLitresX10);
  Serial.printf("Total set to %.1f L\n", litres);
}

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

void setup() {
  Serial.begin(115200);
  prefs.begin("water", false);
  baseLitresX10 = prefs.getULong64("total_x10", 0);

  pinMode(PIN_PULSE, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(PIN_PULSE), onPulse, FALLING);

  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }

  snprintf(clientId, sizeof(clientId), "water-%llx", ESP.getEfuseMac());
  snprintf(topicStatus, sizeof(topicStatus), "%s/status", PREFIX);
  snprintf(topicTelemetry, sizeof(topicTelemetry), "%s/telemetry", PREFIX);
  snprintf(topicSet, sizeof(topicSet), "%s/set/total_l", PREFIX);
  mqtt.setServer(MQTT_HOST, MQTT_PORT);
  mqtt.setCallback(onMessage);
  connectMqtt();
  lastSaveMs = lastPublishMs = millis();
}

void loop() {
  if (!mqtt.connected()) connectMqtt();
  mqtt.loop();
  uint32_t now = millis();

  if (now - lastSaveMs >= SAVE_INTERVAL_MS) { saveTotal(); lastSaveMs = now; }

  if (now - lastPublishMs >= PUBLISH_INTERVAL_MS) {
    noInterrupts(); uint32_t p = pulses; interrupts();
    float litresInterval = (p - pulsesAtPublish) * LITRES_PER_PULSE;
    float flowLpm = litresInterval / ((now - lastPublishMs) / 60000.0);
    char payload[160];
    snprintf(payload, sizeof(payload),
             "{\"total_l\":%.1f,\"flow_lpm\":%.2f,\"interval_l\":%.1f,\"rssi\":%d}",
             totalLitres(), flowLpm, litresInterval, WiFi.RSSI());
    mqtt.publish(topicTelemetry, payload, true);
    Serial.println(payload);
    pulsesAtPublish = p;
    lastPublishMs = now;
  }
}

Grave a placa, abra uma torneira e acompanhe o monitor serial. Depois, assine pelo seu computador no servidor MQTT público (gratuito), que serve apenas para testes e protótipos:

mosquitto_sub -h broker.connectmq.com -p 1883 -i water-view-2207 -t "connectmq/demo/w8m3d1/water/#" -v

Leia o mostrador físico e ajuste o total para coincidir com ele, em litros:

mosquitto_pub -h broker.connectmq.com -p 1883 -i water-set-2208 -t "connectmq/demo/w8m3d1/water/main/set/total_l" -m "482137"

O comando de ajuste propositalmente não é retido, para que seja aplicado uma única vez e não zere o total toda vez que o ESP32 se reconectar. Se algo não conectar, o tutorial de ESP32 com MQTT tem uma seção de solução de problemas passo a passo.

Detectando vazamentos com dados do hidrômetro MQTT

Os dados de consumo ganham valor quando avisam você. Dois padrões flagram a maioria dos vazamentos:

  • Fluxo contínuo. Na maioria das casas existem períodos de vazão zero a cada hora. Se interval_l estiver acima de zero em todos os intervalos de um minuto durante, digamos, duas horas, algo está correndo: a válvula de enchimento da caixa acoplada, uma torneira pingando ou uma zona de irrigação travada aberta.
  • Vazão alta por tempo demais. Uma mangueira ou um cano estourado aparece como um flow_lpm alto que se mantém por muito mais tempo do que um banho de chuveiro ou de banheira. Escolha um limite com base nos seus picos normais após uma semana de dados.

O primeiro padrão precisa de estado ao longo do tempo e se encaixa bem no Node-RED ou em um pequeno assinante em Python. O segundo é um limite simples; no portal da ConnectMQ você pode criar uma regra de alerta por limite em flow_lpm e ver os alertas disparados no log de alertas. Para detecção pontual embaixo de pias e máquinas de lavar, combine isso com sensores dedicados do guia de detecção de vazamento de água; o hidrômetro diz que a água está correndo, o sensor no piso diz onde.

Consumo diário e mensal

O ESP32 publica um total acumulado em vez de números diários, e isso é proposital: totais são fáceis de manter corretos, e qualquer assinante pode derivar o consumo diário, semanal ou mensal pela diferença entre o primeiro e o último total de cada período. Telegraf com InfluxDB, o helper utility meter do Home Assistant ou um pequeno script gravando em SQLite funcionam assim. Mantenha o dispositivo simples e faça a aritmética de calendário mais adiante, onde fusos horários e períodos de faturamento são mais fáceis de tratar do que em um microcontrolador.

Checklist de precisão e confiabilidade

  1. Compare com o mostrador toda semana no primeiro mês e ajuste LITRES_PER_PULSE ou a posição do sensor se as leituras derivarem.
  2. Verifique contagens duplas tirando 10 litros medidos em um balde; a contagem deve aumentar exatamente 10 pulsos a 1 L por pulso.
  3. Proteja o sensor da condensação. Caixas de hidrômetro e canos de água fria suam; use um sensor vedado e mantenha o ESP32 em um gabinete seco.
  4. Cuidado com o Wi-Fi em porões e caixas de medição. Sinais fracos causam reconexões; a telemetria retida e o status do Last Will deixam as quedas visíveis.
  5. Recorra ao seu encanador ou à concessionária para qualquer coisa que envolva o próprio hidrômetro.

Migrando para um broker privado

O consumo de água revela rotinas diárias e quando a casa está vazia, o que o torna dado pessoal no sentido da LGPD, e qualquer pessoa poderia publicar no seu tópico de ajuste no servidor MQTT público. Quando o leitor estiver funcionando, mude para um broker privado com credenciais e TLS. Um broker MQTT gerenciado como a ConnectMQ oferece isso sem hospedar nada em casa. Use WiFiClientSecure com o certificado ISRG Root X1 do Let's Encrypt, a porta 8883 e as credenciais do portal:

#include <WiFiClientSecure.h>
WiFiClientSecure net;                      // no lugar de WiFiClient
// setup(): net.setCACert(ISRG_ROOT_X1_PEM);
// mqtt.setServer("broker.connectmq.com", 8883);
// mqtt.connect("YOUR_CLIENT_ID", "YOUR_USERNAME", "YOUR_PASSWORD", topicStatus, 1, true, "offline");

O consumo de água se encaixa naturalmente ao lado dos dados de eletricidade de um monitor de energia residencial. Para mais ideias de automação, veja o guia de automação IoT e, para as contrapartidas de hospedagem, a visão geral sobre broker MQTT na nuvem.

Acompanhe seu consumo de água com a ConnectMQ

A ConnectMQ oferece ao seu leitor de hidrômetro um broker MQTT privado e protegido por TLS, com explorador de tópicos ao vivo e regras de alerta por limite para avisos de vazamento baseados em vazão. Crie um broker no plano Serverless (Free) em app.connectmq.com, sem cartão de crédito, e receba suas primeiras leituras em minutos.

Perguntas frequentes

Posso ler qualquer hidrômetro com MQTT?

A maioria dos hidrômetros mecânicos pode ser lida por fora com um sensor reed, indutivo ou óptico, ou com uma câmera que lê os dígitos. Hidrômetros inteligentes com protocolos sem fio precisam, em vez disso, de um receptor compatível.

Quantos litros um pulso representa?

Depende do hidrômetro e do sensor. Um sensor no ponteiro de litros normalmente gera um pulso por litro, enquanto módulos de pulso dos fabricantes costumam gerar um pulso a cada 10 litros. Confira com o mostrador para confirmar.

O total se perde após uma queda de energia?

Não com o sketch acima. O total é salvo na flash do ESP32 a cada poucos minutos quando muda, então no máximo alguns minutos de pulsos podem se perder, e você pode ressincronizar com o comando de ajuste.

Como detecto um vazamento lento?

Procure vazão em todos os intervalos durante um período longo, como duas horas de madrugada. Residências normais têm períodos regulares de vazão zero, então um fluxo pequeno e contínuo é um forte indício de vazamento.

Artigos relacionados

Guia de Configuração do Zigbee2MQTT: do Coordenador ao Painel

Instale o Zigbee2MQTT com Docker, configure o coordenador e a conexão MQTT, pareie e renomeie dispositivos, controle-os via MQTT e veja seus estados em um painel, testando primeiro no servidor MQTT público (gratuito).

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.