ESP32 ile bir su deposu seviye sensörü, ilk IoT projeleri arasında en faydalı olanlardan biridir: "Ne kadar su kaldı?" sorusunu her yerden yanıtlar ve pompa kuru çalışmadan önce sizi uyarır. Bu eğitimde su geçirmez bir ultrasonik sensörü bağlayacak, mesafe ölçümünü doluluk yüzdesine ve litreye çevirecek ve ikisini de kararlı (debounce edilmiş) bir düşük seviye alarmıyla birlikte bir MQTT broker'ına yayınlayacaksınız.
Ultrasonik Depo Seviyesi Ölçümü Nasıl Çalışır?
Depo kapağına monte edilen ultrasonik sensör aşağıya kısa bir ses darbesi gönderir ve yankının su yüzeyinden geri dönmesinin ne kadar sürdüğünü ölçer. Mesafe, gidiş-dönüş süresinin yarısı ile ses hızının çarpımıdır. Su seviyesi ise basitçe depo derinliğinden bu mesafenin çıkarılmasıyla bulunur.
sensor (lid)
---------[S]--------- <- distance d measured by the sensor
| | |
| v |
|~~~~~~~~~~~~~~~~~~~| <- water surface
| | level = tank_depth - (d - mount_offset)
| |
--------------------- <- tank bottom
Ultrasonik ölçüm temassızdır; yani suyun içinde hiçbir şey bulunmaz ve köpürmeyen her sıvıyla çalışır. Zayıf noktaları ise minimum ölçüm mesafesi (sensöre yakın bir "kör bölge"), dönüştürücü üzerindeki yoğuşma ve dar depolarda depo duvarlarından veya borulardan gelen yankılardır. Üçü de iyi bir yerleşim ve filtrelemeyle yönetilebilir.
Malzeme Listesi
| Parça | Amaç |
|---|---|
| ESP32 DevKit (Wi-Fi'lı herhangi bir model) | Sensörü okur ve MQTT üzerinden yayınlar |
| JSN-SR04T veya AJ-SR04M su geçirmez ultrasonik sensör | Su yüzeyine olan mesafeyi ölçer |
| 1 kΩ ve 2 kΩ dirençler | 5 V echo sinyali için gerilim bölücü |
| 5 V güç kaynağı | Sensörü ve 5V pini üzerinden ESP32'yi besler |
| Kısa bir PVC boru parçası (isteğe bağlı) | Yankıları ve dalgalanmaları azaltan sakinleştirme borusu |
Daha ucuz olan HC-SR04 masa testi için iş görür, ancak su geçirmez değildir ve deponun üzerindeki nemli havada hızla korozyona uğrar. Gerçek bir kurulum için kabloya bağlı, sızdırmaz bir prob doğru tercihtir.
Sensörü ESP32'ye Bağlama
| JSN-SR04T pini | ESP32 pini | Notlar |
|---|---|---|
| 5V | 5V (VIN) | Güvenilir menzil için sensör 5 V'a ihtiyaç duyar |
| GND | GND | Ortak toprak |
| Trig | GPIO 5 | 3,3 V tetik darbesi kabul edilir |
| Echo | Bölücü üzerinden GPIO 18 | Seri 1 kΩ, GND'ye 2 kΩ: pinde yaklaşık 3,3 V |
Echo pinini doğrudan bağlamayın: ESP32 GPIO'ları 5 V toleranslı değildir. Bölücüyü kurmak birkaç saniye sürer ve bir kartı kurtarır.
Deponuzu Kalibre Etmek
Kod yazmadan önce bir şerit metreyle üç değeri ölçün:
- Montaj ofseti: sensör yüzünden "dolu" su çizgisine olan mesafe. Bunu sensörün kör bölgesinden büyük tutun; JSN-SR04T için bu genellikle 20 ila 25 cm'dir.
- Kullanılabilir derinlik: dolu çizgisinden çıkışa veya sizin için önemli olan en düşük seviyeye kadar olan mesafe.
- Dolu çizgisindeki litre cinsinden kapasite. Dikey bir silindir için litre, desimetrekare cinsinden kesit alanı ile desimetre cinsinden derinliğin çarpımına eşittir; düzensiz depolar için üreticinin verdiği değeri kullanın.
Doluluk yüzdesi bu durumda (usable_depth - (distance - mount_offset)) / usable_depth * 100 olur ve 0 ile 100 arasında sınırlandırılır.
ESP32 Su Deposu Seviye Sketch'i
Sketch yedi ölçüm alır, rastgele yankıları elemek için medyanı kullanır, seviyeyi, yüzdeyi ve litreyi hesaplar ve her 30 saniyede bir JSON mesajı yayınlar. Önce Library Manager'dan PubSubClient'ı kurun.
| Topic | Retained | Örnek payload |
|---|---|---|
connectmq/demo/tank-91c2/level |
evet | {"distance_cm":63.4,"level_cm":96.6,"percent":64.4,"litres":644} |
connectmq/demo/tank-91c2/alert |
evet | LOW veya OK |
connectmq/demo/tank-91c2/status |
evet | online / offline (Last Will) |
tank-91c2 ifadesini kendi rastgele tanımlayıcınızla değiştirin.
#include <WiFi.h>
#include <PubSubClient.h>
const char* WIFI_SSID = "YOUR_WIFI";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";
const char* MQTT_HOST = "broker.connectmq.com";
const uint16_t MQTT_PORT = 1883;
const char* CLIENT_ID = "tank-91c2-esp32";
const char* TOPIC_LEVEL = "connectmq/demo/tank-91c2/level";
const char* TOPIC_ALERT = "connectmq/demo/tank-91c2/alert";
const char* TOPIC_STATUS = "connectmq/demo/tank-91c2/status";
const int TRIG_PIN = 5;
const int ECHO_PIN = 18;
// Depo kalibrasyonu (santimetre / litre)
const float MOUNT_OFFSET_CM = 25.0; // sensör yüzünden dolu çizgisine
const float USABLE_DEPTH_CM = 150.0; // dolu çizgisinden boş çizgisine
const float CAPACITY_L = 1000.0;
// Alarm histerezisi: %20'nin altında alarm, %25'in üstünde temizle
const float LOW_ON_PCT = 20.0;
const float LOW_OFF_PCT = 25.0;
const uint32_t PUBLISH_INTERVAL_MS = 30000;
const float SOUND_CM_PER_US = 0.0343; // yaklaşık 20 santigrat derecede
WiFiClient net;
PubSubClient mqtt(net);
uint32_t lastPublish = 0;
bool lowAlarm = false;
bool alarmPublished = false;
float readDistanceOnce() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(5);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(20); // JSN-SR04T daha uzun bir tetik tercih eder
digitalWrite(TRIG_PIN, LOW);
unsigned long us = pulseIn(ECHO_PIN, HIGH, 30000); // 30 ms zaman aşımı
if (us == 0) return NAN;
return us * SOUND_CM_PER_US / 2.0;
}
float readDistanceMedian() {
const int N = 7;
float v[N];
int n = 0;
for (int i = 0; i < N; i++) {
float d = readDistanceOnce();
if (!isnan(d)) v[n++] = d;
delay(60); // yankıların sönmesini bekle
}
if (n < 3) return NAN;
for (int i = 1; i < n; i++) { // eklemeli sıralama
float key = v[i];
int j = i - 1;
while (j >= 0 && v[j] > key) { v[j + 1] = v[j]; j--; }
v[j + 1] = key;
}
return v[n / 2];
}
void connectWifi() {
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) delay(500);
}
void connectMqtt() {
while (!mqtt.connected()) {
if (mqtt.connect(CLIENT_ID, TOPIC_STATUS, 1, true, "offline")) {
mqtt.publish(TOPIC_STATUS, "online", true);
alarmPublished = false; // yeniden bağlandıktan sonra alarm durumunu tekrar yayınla
} else {
delay(5000);
}
}
}
void publishLevel() {
float d = readDistanceMedian();
if (isnan(d)) {
mqtt.publish(TOPIC_LEVEL, "{\"error\":\"no_echo\"}", true);
return;
}
float level = USABLE_DEPTH_CM - (d - MOUNT_OFFSET_CM);
level = constrain(level, 0.0f, USABLE_DEPTH_CM);
float pct = level / USABLE_DEPTH_CM * 100.0;
float litres = CAPACITY_L * pct / 100.0;
char json[160];
snprintf(json, sizeof(json),
"{\"distance_cm\":%.1f,\"level_cm\":%.1f,\"percent\":%.1f,\"litres\":%.0f,\"rssi\":%d}",
d, level, pct, litres, WiFi.RSSI());
mqtt.publish(TOPIC_LEVEL, json, true);
Serial.println(json);
bool prev = lowAlarm;
if (!lowAlarm && pct < LOW_ON_PCT) lowAlarm = true;
if (lowAlarm && pct > LOW_OFF_PCT) lowAlarm = false;
if (lowAlarm != prev || !alarmPublished) {
mqtt.publish(TOPIC_ALERT, lowAlarm ? "LOW" : "OK", true);
alarmPublished = true;
}
}
void setup() {
Serial.begin(115200);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
connectWifi();
mqtt.setServer(MQTT_HOST, MQTT_PORT);
connectMqtt();
publishLevel();
lastPublish = millis();
}
void loop() {
if (WiFi.status() != WL_CONNECTED) connectWifi();
if (!mqtt.connected()) connectMqtt();
mqtt.loop();
if (millis() - lastPublish >= PUBLISH_INTERVAL_MS) {
lastPublish = millis();
publishLevel();
}
}
Ölçümleri bilgisayarınızdan izleyin:
mosquitto_sub -h broker.connectmq.com -p 1883 -i tank-91c2-viewer -t "connectmq/demo/tank-91c2/#" -v
Seviye, alarm ve durum topic'leri retained olduğu için, herhangi bir anda bağlanan bir telefon paneli 30 saniyeye kadar beklemek yerine mevcut durumu anında gösterir. Retained bayrağı ve Last Will konusunda yeniyseniz, ESP32 MQTT Last Will yazısı ikisini de açıklıyor.
Alarm Neden Histerezis Kullanıyor?
Su yüzeyleri, özellikle bir pompa doldururken veya çekerken dalgalanır. Yüzde 20'de tek bir eşik olsaydı, 19,8 ile 20,3 arasında gidip gelen bir ölçüm alarmı her döngüde açıp kapatır ve tüm abonelere gereksiz mesaj yağdırırdı. İki eşik (20'nin altında açık, 25'in üstünde kapalı) bu gürültüyü emen bir ölü bölge oluşturur. Sketch ayrıca alarmı yalnızca durum değiştiğinde ve her yeniden bağlantıdan sonra bir kez yayınlar; bu da trafiği düşük, retained değeri ise doğru tutar.
Firmware'e dokunmadan ikinci bir katman ekleyebilirsiniz. ConnectMQ portalında eşik alarm kuralları bir topic'i izler ve bir değer belirlediğiniz sınırı aştığında alarm günlüğüne bir kayıt düşer; bu, cihaz mantığını bağımsız olarak kontrol etmek için kullanışlıdır.
ESP32 Su Deposu Seviye Sensörü İçin Doğruluk İpuçları
- Sensörü tam dikey monte edin ve dökülen su ile dalgaların ışına çarpmaması için girişten uzak tutun.
- Dar veya çalkantılı depolarda bir sakinleştirme borusu kullanın: kapaktan tabana uzanan ve tabana yakın küçük bir deliği olan bir PVC boru, sakin bir yüzey ve temiz bir yankı yolu sağlar.
- Kör bölgeye saygı gösterin. Su ilk 20 ila 25 cm'ye kadar yükselebiliyorsa sensörü kısa bir yükseltme borusuyla yukarı alın.
- Deponuz sıcak bir çatı arasında veya donan bir kulübedeyse sıcaklık kompanzasyonu yapın. Ses hızı hava sıcaklığıyla, santigrat derece başına kabaca 0,6 m/s artar; sensörün yanına konan bir DS18B20 bunu düzeltmenizi sağlar.
- Yoğuşmaya dikkat edin. Dönüştürücü üzerindeki damlacıklar "yankı yok" ölçümlerine yol açar. Kapakta küçük bir havalandırma deliği yardımcı olur.
- Birkaç seviyede elle yapılan ölçümle doğrulayın ve değerler örtüşene kadar
MOUNT_OFFSET_CMdeğerini ayarlayın.
Pille Çalışan Depolar
Uzaktaki depoların çoğu zaman şebeke elektriği yoktur. Yukarıdaki sketch Wi-Fi ve MQTT bağlantısını sürekli açık tutar ve bu da pilleri hızla tüketir. Güneş enerjili veya pilli bir düğüm için yapıyı değiştirin: uyanın, bir ölçüm alın, bağlanın, retained seviye ve alarmı yayınlayın, ardından 10 veya 15 dakikalığına deep sleep moduna geçin. Bu tasarımda retained mesajlar daha da önemlidir, çünkü cihaz zamanın büyük kısmında çevrim dışıdır. ESP32 deep sleep MQTT rehberi tüm deseni gösteriyor; ayrıca ESP32 uyurken hiç akım çekmemesi için sensörü bir MOSFET üzerinden besleyebilirsiniz.
Üretime Geçiş
broker.connectmq.com adresindeki genel test alanı geliştirme için mükemmeldir, ancak oradaki her şey topic'inizi tahmin eden herkes tarafından okunabilir. Sensörü kalıcı olarak kurmadan önce:
- Özel bir broker oluşturun ve portalda üretilen kullanıcı adını, parolayı ve client ID'yi kopyalayın.
WiFiClientSecure, 8883 portu ve ISRG Root X1 CA sertifikasına geçin.mqtt.connect("YOUR_CLIENT_ID", "YOUR_USERNAME", "YOUR_PASSWORD", TOPIC_STATUS, 1, true, "offline")ile bağlanın.
Birkaç depo için kendi broker'ınızı çalıştırmak, bakım yüküne nadiren değer; bu yüzden genellikle yönetilen bir MQTT broker tercih edilir. Önce barındırma seçeneklerini karşılaştırmak isterseniz buluttaki MQTT broker yaklaşımını okuyun; yapılandırılmış payload'lar için ise ArduinoJson MQTT rehberi snprintf'e göre daha temiz bir alternatiftir. Diğer sensör projeleri ESP32 IoT eğitiminde bir araya getirildi.
ConnectMQ ile Başlayın
Depo izleme sisteminiz özel ve şifreli bir uç noktayı hak ediyor. ConnectMQ, 8883 portunda TLS, otomatik üretilen kimlik bilgileri, canlı bir topic gezgini ve eşik alarm kurallarını tek bir portalda sunar. app.connectmq.com adresinde kredi kartı gerekmeden ücretsiz bir Serverless broker oluşturun ve sketch'te yalnızca üç satırı değiştirin.
Sık Sorulan Sorular
Su deposu için en iyi ultrasonik sensör hangisidir?
JSN-SR04T veya AJ-SR04M gibi sızdırmaz, su geçirmez bir prob. HC-SR04 masa testi için uygundur, ancak deponun üzerindeki neme uzun süre dayanamaz.
Sensörüm depo dolu olmadığı halde neden dolu gösteriyor?
Su veya bir engel kör bölgenin içindedir ya da yankı bir borudan veya duvardan sekiyordur. Sensörü yükseltin, açık bir alana yöneltin veya bir sakinleştirme borusu ekleyin.
ESP32 depo seviyesini ne sıklıkla yayınlamalı?
Çoğu ev tipi depo için 30 ila 60 saniyede bir fazlasıyla yeterlidir; seviyeler yavaş değişir. Pille çalışırken deep sleep ile 10 ila 15 dakikada bir yayın iyi bir dengedir.
Bunu mazot veya başka sıvılar için kullanabilir miyim?
Ultrasonik ölçüm köpürmeyen sıvıların çoğunda çalışır, ancak yakıt depoları için tehlikeli bölgelerde elektronik kullanımına ilişkin güvenlik kuralları vardır. Mevzuatı kontrol edin ve gerektiğinde sertifikalı ekipman kullanın.



