Bir su sayacı MQTT okuyucusu, bodrumunuzdaki kadranı canlı tüketim verilerine dönüştürür: günlük litre, anlık debi ve suyun akmaması gerektiği halde akmaya devam ettiğinde erken uyarı. Bu eğitimde sayacınıza uygun sensörü seçecek, bir ESP32 ile darbeleri sayacak, toplamı elektrik kesintilerine karşı koruyacak ve onu bir MQTT broker'a yayınlayacaksınız. Ayrıca damlayan bir musluğu veya patlamış bir boruyu yakalayan sızıntı tespit mantığı da ekleyeceksiniz.
Su Sayacınız için Sensör Seçimi
Ev tipi su sayaçlarının çoğu mekaniktir ve bir veri portu yoktur. Bunları litre başına (veya on litre başına) bir kez hareket eden bir şeyi algılayarak okursunuz. Parça almadan önce sayacınızı kontrol edin:
| Sayaç özelliği | Sensör | Nasıl çalışır | Notlar |
|---|---|---|---|
| Darbe çıkış kablosu veya "pulse-ready" işareti | Sayaç üreticisinin reed kontak modülü | Litre veya 10 litre başına bir kez kapanır | En güvenilir, temiz sinyal |
| Dönen mıknatıs (bazı sayaçlarda) | Üstüne bantlanan reed anahtar veya hall sensörü | Mıknatıs her turda sensörün önünden geçer | Bir telefon pusula uygulamasıyla kontrol edin |
| Litre kadranında metal yarım disk | Endüktif yakınlık sensörü (ör. LJ18A3-8-Z/BX) | Metali geçerken algılar | Yaygın tercih; genellikle 5-12 V besleme ve bir seviye dönüştürücü veya bölücü gerektirir |
| Kadranda yansıtıcı işaret | Kızılötesi yansıtıcı sensör (TCRT5000 tipi) | Parlak/koyu bölümü algılar | Hizalamaya ve ortam ışığına duyarlı |
| Kullanılabilir özellik yok | Rakam tanımalı kamera (ESP32-CAM) | Rakamları optik olarak okur | "AI-on-the-edge-device" projesi kendisi MQTT'ye yayın yapar |
Sayacın kendisini asla açmayın veya değiştirmeyin; genellikle su idaresine aittir. Yukarıdaki sensörlerin hepsi dışarıdan klipsle takılır veya bantlanır.
ESP32 Bağlantıları
Bu eğitim, GPIO 25 üzerinde litre başına bir kez low seviyesine inen bir darbe sinyali kullanır. Bir reed anahtar için onu GPIO 25 ile GND arasına bağlayın ve dahili pull-up'ı kullanın. 5 ile 12 V arasında beslenen bir NPN endüktif sensör için çıkışını dahili pull-up etkin olarak GPIO 25'e bağlayın; NPN açık kollektör çıkışlar hattı low seviyesine çeker ve asla 3,3 V'un üzerine sürmez. Ancak sensörünüzün veri sayfasını kontrol edin; bazı modüllerde besleme voltajına bağlı bir pull-up bulunur ve bu durumda bir voltaj bölücü gerekir.
Önemli Tasarım Kararları
Bir su sayacı okuyucusu basit görünür, ancak sayılarına güvenilip güvenilemeyeceğini üç ayrıntı belirler:
- Toplam yeniden başlatmalardan sağ çıkmalıdır. ESP32 yeniden başlayıp sıfırdan sayarsa günlük tüketim grafiğiniz bozulur. Sketch toplamı flash'ta (NVS) saklar ve onu fiziksel kadranla eşleşecek şekilde ayarlamanıza olanak tanır.
- Flash aşınması. Her darbede flash'a yazmak onu hızla yıpratır. Sayım değiştiğinde ve en fazla birkaç dakikada bir kaydedin; bir elektrik kesintisinin birkaç litreyi kaybettirebileceğini kabul edin.
- Debounce. Mekanik kontaklar zıplar ve endüktif bir sensör metalin kenarında titreşebilir. Kısa bir yazılımsal debounce çift sayımları önler.
Bu proje için topic'ler:
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
ESP32 Su Sayacı MQTT Sketch'i
Library Manager'dan Nick O'Leary'nin PubSubClient kütüphanesini kurun. Preferences, ESP32 Arduino core'unun bir parçasıdır.
#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; // birçok üretici darbe modülü için 10.0
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; // saklanan toplam, 0,1 L birimiyle
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; } // 50 ms debounce
}
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; // yeni bir şey yok, flash'a yazma yok
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;
}
}
Kartı programlayın, bir musluğu açın ve seri monitörü izleyin. Ardından bilgisayarınızdan abone olun:
mosquitto_sub -h broker.connectmq.com -p 1883 -i water-view-2207 -t "connectmq/demo/w8m3d1/water/#" -v
Fiziksel kadranı okuyun ve toplamı litre cinsinden onunla eşleşecek şekilde ayarlayın:
mosquitto_pub -h broker.connectmq.com -p 1883 -i water-set-2208 -t "connectmq/demo/w8m3d1/water/main/set/total_l" -m "482137"
Ayar komutu bilerek retained yapılmaz; böylece bir kez uygulanır ve ESP32 her yeniden bağlandığında toplamı sıfırlamaz. Bağlantıda bir sorun olursa ESP32 MQTT eğitimi adım adım bir sorun giderme bölümü içerir.
Su Sayacı MQTT Verilerinden Sızıntı Tespiti
Tüketim verileri sizi uyardığında değer kazanır. İki örüntü sızıntıların çoğunu yakalar:
- Sürekli akış. Çoğu evde her saat sıfır akışlı dönemler vardır.
interval_lörneğin iki saat boyunca her bir dakikalık aralıkta sıfırın üzerindeyse bir şey akıyordur: bir klozet dolum vanası, damlayan bir musluk veya açık kalmış bir sulama bölgesi. - Çok uzun süren yüksek akış. Patlamış bir hortum veya boru, bir duş ya da banyodan çok daha uzun süren yüksek bir
flow_lpmolarak görünür. Bir haftalık veriden sonra normal zirvelerinize göre bir eşik seçin.
İlk örüntü zaman içinde durum tutmayı gerektirir ve Node-RED'e veya kısa bir Python abonesine iyi uyar. İkincisi basit bir eşiktir; ConnectMQ portalında flow_lpm için bir eşik uyarı kuralı oluşturabilir ve tetiklenen uyarıları uyarı günlüğünde görebilirsiniz. Lavabo ve çamaşır makinelerinin altında noktasal tespit için bunu su sızıntısı tespiti rehberindeki özel sensörlerle birleştirin; sayaç suyun aktığını, zemin sensörü ise nerede aktığını söyler.
Günlük ve Aylık Tüketim
ESP32 günlük rakamlar yerine bir kümülatif toplam yayınlar ve bu bilinçli bir tercihtir: toplamları doğru tutmak kolaydır ve her abone, her dönemdeki ilk ve son toplam arasındaki farkı alarak günlük, haftalık veya aylık tüketimi türetebilir. InfluxDB ile Telegraf, Home Assistant'ın utility meter yardımcısı veya SQLite'a yazan küçük bir betik bu şekilde çalışır. Cihazı basit tutun ve takvim hesaplamalarını, saat dilimleri ile fatura dönemlerinin bir mikrodenetleyiciye göre çok daha kolay yönetildiği akış aşağısında yapın.
Doğruluk ve Güvenilirlik Kontrol Listesi
- İlk ay boyunca her hafta kadranla karşılaştırın ve ölçümler kayarsa
LITRES_PER_PULSEdeğerini veya sensör konumunu ayarlayın. - Bir kovaya ölçülü 10 litre doldurarak çift sayımı kontrol edin; darbe başına 1 L'de sayım tam olarak 10 darbe artmalıdır.
- Sensörü yoğuşmadan koruyun. Sayaç çukurları ve soğuk su boruları terler; sızdırmaz bir sensör kullanın ve ESP32'yi kuru bir kutuda tutun.
- Bodrumlarda Wi-Fi'ye dikkat edin. Zayıf sinyaller yeniden bağlanmalara neden olur; retained telemetri ve Last Will durumu kesintileri görünür kılar.
- Sayacın kendisiyle ilgili her şey için tesisatçınıza veya su idaresine başvurun.
Özel Bir Broker'a Geçiş
Su kullanımı günlük rutinleri ve evin ne zaman boş olduğunu ortaya koyar; paylaşımlı bir broker'da ise herkes ayar topic'inize yayın yapabilir. Okuyucu çalıştığında kimlik bilgileri ve TLS içeren özel bir broker'a geçin. ConnectMQ gibi yönetilen bir MQTT broker, evde hiçbir şey barındırmadan bunu sağlar. Let's Encrypt için ISRG Root X1 sertifikasıyla WiFiClientSecure, 8883 portu ve portaldan aldığınız kimlik bilgilerini kullanın:
#include <WiFiClientSecure.h>
WiFiClientSecure net; // WiFiClient yerine
// 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");
Su tüketimi, bir ev enerji izleyiciden gelen elektrik verilerinizin yanına doğal olarak oturur. Daha fazla otomasyon fikri için IoT otomasyon rehberine, barındırma ödünleşimleri için buluttaki MQTT broker genel bakışına göz atın.
Su Kullanımınızı ConnectMQ ile Takip Edin
ConnectMQ, sayaç okuyucunuza canlı bir topic gezgini ve akışa dayalı sızıntı uyarıları için eşik uyarı kuralları içeren, TLS ile korunan özel bir MQTT broker sunar. app.connectmq.com adresinde kredi kartı gerektirmeden ücretsiz bir Serverless broker oluşturun ve ilk ölçümlerinizin dakikalar içinde gelmesini sağlayın.
Sık Sorulan Sorular
Her su sayacını MQTT ile okuyabilir miyim?
Mekanik sayaçların çoğu dışarıdan bir reed, endüktif veya optik sensörle ya da rakamları okuyan bir kamerayla okunabilir. Kablosuz protokollü akıllı sayaçlar ise bunun yerine uyumlu bir alıcı gerektirir.
Bir darbe kaç litreyi temsil eder?
Sayaca ve sensöre bağlıdır. Litre kadranındaki bir sensör tipik olarak litre başına bir darbe verirken, üretici darbe modülleri çoğu zaman 10 litre başına bir darbe verir. Doğrulamak için kadranla karşılaştırın.
Elektrik kesintisinden sonra toplam kaybolur mu?
Yukarıdaki sketch ile hayır. Toplam, değiştiğinde birkaç dakikada bir ESP32'nin flash belleğine kaydedilir; bu nedenle en fazla birkaç dakikalık darbe kaybolabilir ve ayar komutuyla yeniden senkronize edebilirsiniz.
Yavaş bir sızıntıyı nasıl tespit ederim?
Gece iki saat gibi uzun bir dönem boyunca her aralıkta akış olup olmadığına bakın. Normal hanelerde düzenli sıfır akışlı dönemler olur; bu yüzden sürekli küçük akış güçlü bir sızıntı göstergesidir.



