#include <Arduino.h>
#include<digitalWriteFast.h>
#include<LiquidCrystal_I2C.h>
#include<WiFi.h>
#include<PubSubClient.h>
// Set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x27, 16, 2);
// WiFi Credentials:
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* mqtt_server = "test.mosquitto.org";
WiFiClient espClient;
PubSubClient client(espClient);
// Define Pins
const int TRIGGPIN1 = 4;
const int TRIGGPIN2 = 19;
const int ECHOPIN1 = 5;
const int ECHOPIN2 = 18;
const int VALVE1 = 13;
const int VALVE2 = 12;
const int PUMP = 14;
const float SPEED_OF_SOUND = 0.034 / 2;
// Define Values
const int tank1sensorHeight = 95; // Height of the sensor in cm for Tank 1
const int tank2sensorHeight = 164; // Height of the sensor in cm for Tank 2
const int tank1height = 80; // In cm for Tank 1
const int tank2height = 150; // In cm for Tank 2
const int tank1radius = 45; // In cm for Tank 1
const int tank2radius = 50; // In cm for Tank 2
const int tank1triggerlevel = 87; // Trigger level for Pump to start for Tank1
const int tank2triggerlevel = 149; // Trigger level for Pump to start for Tank2
const int tank1triggeroff = 14;
const int tank2triggeroff = 30;
const double pi = 3.1415926535897932384626433832795; // Value of PI
int lastDistance1 = -1; // Initialize with a value that's outside the normal range of distances
int lastDistance2 = -1; // Initialize with a value that's outside the normal range of distances
long duration1;
long duration2;
int distance1;
int distance2;
void setup() {
Serial.begin(115200);
// Initialize the LCD
lcd.init();
// Turn on the backlight
lcd.backlight();
// Print introduction on LCD
intro();
// Set pin modes
pinMode(TRIGGPIN1, OUTPUT);
pinMode(ECHOPIN1, INPUT);
pinMode(TRIGGPIN2, OUTPUT);
pinMode(ECHOPIN2, INPUT);
pinMode(VALVE1, OUTPUT);
pinMode(VALVE2, OUTPUT);
pinMode(PUMP, OUTPUT);
delay(3000);
// Clear LCD
lcd.clear();
setupWiFi();
client.setServer(mqtt_server, 1883);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
ULSensor1();
ULSensor2();
int waterheight1;
int waterheight2;
// Calculate water height for Tank 1
if (distance1 <= 2) {
waterheight1 = tank1height; // Set to maximum possible water height
} else if (distance1 >= tank1sensorHeight) {
waterheight1 = 0; // Set to minimum water height (tank empty)
} else {
waterheight1 = tank1sensorHeight - distance1; // Calculate water height from sensor
if (waterheight1 > tank1height) {
waterheight1 = tank1height; // Cap water height at tank height
} else if (waterheight1 < 0) {
waterheight1 = 0; // Ensure water height doesn't become negative
}
}
// Calculate water height for Tank 2
if (distance2 <= 2) {
waterheight2 = tank2height; // Set to maximum possible water height
} else if (distance2 >= tank2sensorHeight) { // Adjusted for Tank 2
waterheight2 = 0; // Set to minimum water height (tank empty)
} else {
waterheight2 = tank2sensorHeight - distance2; // Calculate water height from sensor
if (waterheight2 > tank2height) {
waterheight2 = tank2height; // Cap water height at tank height
} else if (waterheight2 < 0) {
waterheight2 = 0; // Ensure water height doesn't become negative
}
}
// Calculate tank fill percentages
float tankFilledPercentage1 = (waterheight1 / (float)tank1height) * 100;
float tankFilledPercentage2 = (waterheight2 / (float)tank2height) * 100;
// Check if there's a change in the sensor readings
if (distance1 != lastDistance1 || distance2 != lastDistance2) {
// Print tank data via Serial
Serial.println("------------------------------------");
Serial.print("Tank 1 - Distance: ");
Serial.print(distance1);
Serial.println(" cm");
Serial.print("Tank 1 - Water Height: ");
Serial.print(waterheight1);
Serial.println(" cm");
Serial.print("Tank 1 - Tank Filled Percentage: ");
Serial.print(tankFilledPercentage1);
Serial.println("%");
Serial.println("------------------------------------");
Serial.print("Tank 2 - Distance: ");
Serial.print(distance2);
Serial.println(" cm");
Serial.print("Tank 2 - Water Height: ");
Serial.print(waterheight2);
Serial.println(" cm");
Serial.print("Tank 2 - Tank Filled Percentage: ");
Serial.print(tankFilledPercentage2);
Serial.println("%");
Serial.println("------------------------------------");
// Update LCD display
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Tank 1: ");
lcd.print(tankFilledPercentage1);
lcd.print("%");
lcd.setCursor(0, 1);
lcd.print("Tank 2: ");
lcd.print(tankFilledPercentage2);
lcd.print("%");
// Update VALVE status
if (distance1 >= tank1triggerlevel) {
digitalWriteFast(VALVE1, HIGH); // Turn on VALVE when tank is less than or equal to 10% full
} else if (distance1 <= tank1triggeroff) {
digitalWriteFast(VALVE1, LOW); // Turn off VALVE when tank is 100% full
}
if (distance2 >= tank2triggerlevel) {
digitalWriteFast(VALVE2, HIGH); // Turn on VALVE when tank is less than or equal to 10% full
} else if (distance2 <= tank2triggeroff) {
digitalWriteFast(VALVE2, LOW); // Turn off VALVE when tank is 100% full
}
// Update PUMP status
if (digitalRead(VALVE1) || digitalRead(VALVE2)) {
digitalWriteFast(PUMP, HIGH); // Turn on PUMP when either tank is less than or equal to 10% full
} else {
digitalWriteFast(PUMP, LOW); // Turn off PUMP when tank is 100% full
}
// Update last distance values
lastDistance1 = distance1;
lastDistance2 = distance2;
// Print tank volume and filled percentage
volume(waterheight1, tankFilledPercentage1, 1);
volume(waterheight2, tankFilledPercentage2, 2);
}
// Delay before next loop iteration
delay(500);
}
void ULSensor1() {
digitalWriteFast(TRIGGPIN1, LOW);
delayMicroseconds(2);
digitalWriteFast(TRIGGPIN1, HIGH);
delayMicroseconds(10);
digitalWriteFast(TRIGGPIN1, LOW);
duration1 = pulseIn(ECHOPIN1, HIGH);
distance1 = duration1 * SPEED_OF_SOUND + 1;
}
void ULSensor2() {
digitalWriteFast(TRIGGPIN2, LOW);
delayMicroseconds(2);
digitalWriteFast(TRIGGPIN2, HIGH);
delayMicroseconds(10);
digitalWriteFast(TRIGGPIN2, LOW);
duration2 = pulseIn(ECHOPIN2, HIGH);
distance2 = duration2 * SPEED_OF_SOUND + 1;
}
void intro() {
// Introductory Screen
lcd.println("WATER MONITORING");
lcd.setCursor(0, 1);
lcd.println("SYSTEM:1.0");
}
void volume(int waterheight, float tankFilledPercentage, int tankNumber) {
// Calculate volume of water in tank
if (waterheight == 0) {
Serial.print("Tank ");
Serial.print(tankNumber);
Serial.println(" is empty"); // Print a message indicating the tank is empty
} else {
float tankvolume = pi * (tankNumber == 1 ? tank1radius : tank2radius) * (tankNumber == 1 ? tank1radius : tank2radius) * waterheight;
float litre = tankvolume * 0.001;
// Print volume
Serial.print("Volume of Tank ");
Serial.print(tankNumber);
Serial.print(" is: ");
Serial.print(litre);
Serial.println(" L");
// Print tank filled percentage
Serial.print("Tank ");
Serial.print(tankNumber);
Serial.print(" filled percentage: ");
Serial.print(tankFilledPercentage);
Serial.println("%");
}
}
void spinner() {
static int8_t counter = 0;
const char* glyphs = "\xa1\xa5\xdb";
lcd.setCursor(15, 0);
lcd.print(glyphs[counter++]);
if (counter == strlen(glyphs)) {
counter = 0;
}
}
// Connecting to WiFi
void setupWiFi() {
delay(1000);
Serial.print("Connecting to ");
lcd.setCursor(0, 0);
lcd.print("Connecting to ");
Serial.println(ssid);
lcd.setCursor(0, 1);
lcd.print(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
spinner();
Serial.print(".");
delay(500);
}
Serial.println("\nConnected to WiFi");
}
// Reconnect to MQTT server
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect("espClient")) {
Serial.println("connected");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}