#define BLYNK_TEMPLATE_ID "TMPL6reEdDVm7"
#define BLYNK_TEMPLATE_NAME "Water Level Monitoring System"
#define BLYNK_AUTH_TOKEN "Dw2k-uSHD98hBKYkYcUGvHtYt0m88U6l"
#include <WiFi.h>
#include <BlynkSimpleEsp32.h>
// WiFi Credentials
char ssid[] = "Wokwi-GUEST";
char pass[] = "";
// ===== PIN SETUP =====
#define TRIG_PIN 5
#define ECHO_PIN 18
#define VALVE_LED 22 // simulate solenoid valve
#define BUZZER 21
BlynkTimer timer;
// Variables
long duration;
float distance;
int displayLevel;
bool manualOverride = false;
// TANK CONFIGURATION (Adjust these values based on your physical tank)
const int TANK_EMPTY_DISTANCE = 20; // Distance in cm when tank is empty
const int TANK_FULL_DISTANCE = 2; // Distance in cm when tank is full
// ===== MANUAL CONTROL FROM BLYNK =====
// V2 is a Switch Widget in the Blynk App
BLYNK_WRITE(V2) {
manualOverride = param.asInt();
}
// ===== SENSOR + CONTROL FUNCTION =====
void sendSensorData() {
// 1. Ultrasonic trigger pulse
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
// 2. Read echo duration
duration = pulseIn(ECHO_PIN, HIGH, 30000);
// 3. Calculate distance in cm
distance = duration * 0.034 / 2;
// 4. INVERSE MAPPING
// This converts distance (20cm to 2cm) into a percentage (0% to 100%)
// constrain() ensures we don't get negative percentages or values over 100
float clampedDistance = constrain(distance, TANK_FULL_DISTANCE, TANK_EMPTY_DISTANCE);
displayLevel = map(clampedDistance, TANK_EMPTY_DISTANCE, TANK_FULL_DISTANCE, 0, 100);
// 5. Send Data to Blynk
Blynk.virtualWrite(V0, displayLevel); // V0: Gauge or Level Widget (0-100)
// Debugging output to Serial Monitor
Serial.print("Raw Distance: ");
Serial.print(distance);
Serial.print(" cm | Level: ");
Serial.print(displayLevel);
Serial.println("%");
// ===== CONTROL LOGIC =====
if (!manualOverride) {
if (distance > 18) {
// LOW LEVEL (Empty) → OPEN VALVE
digitalWrite(VALVE_LED, HIGH);
digitalWrite(BUZZER, LOW);
Blynk.virtualWrite(V1, 1); // V1: LED Widget for Valve Status
Serial.println("STATUS: LOW - Valve ON");
}
else if (distance > 5) {
// MEDIUM LEVEL → KEEP VALVE OPEN
digitalWrite(VALVE_LED, HIGH);
digitalWrite(BUZZER, LOW);
Blynk.virtualWrite(V1, 1);
Serial.println("STATUS: MEDIUM - Valve ON");
}
else {
// FULL LEVEL → CLOSE VALVE & ALERT
digitalWrite(VALVE_LED, LOW);
digitalWrite(BUZZER, HIGH); // Alarm sounds when full
Blynk.virtualWrite(V1, 0);
Serial.println("STATUS: FULL - Valve OFF / ALARM ON");
}
}
else {
// MANUAL OVERRIDE (Force Valve ON)
digitalWrite(VALVE_LED, HIGH);
digitalWrite(BUZZER, LOW);
Blynk.virtualWrite(V1, 1);
Serial.println("STATUS: MANUAL MODE - Valve ON");
}
Serial.println("----------------------");
}
void setup() {
Serial.begin(115200);
// Pin Modes
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
pinMode(VALVE_LED, OUTPUT);
pinMode(BUZZER, OUTPUT);
// Initialize Blynk
Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);
// Setup timer to run every 1 second
timer.setInterval(1000L, sendSensorData);
}
void loop() {
Blynk.run();
timer.run();
}