#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";
// MQTT topics
const char*TANK1_PERCENTAGE = "device/mano/data/watermonitoringsystem/tank/1/percentage";
const char*TANK2_PERCENTAGE = "device/mano/data/watermonitoringsystem/tank/2/percentage";
const char*TANK1_VOLUME = "device/mano/data/watermonitoringsystem/tank/1/volume";
const char*TANK2_VOLUME = "device/mano/data/watermonitoringsystem/tank/2/volume";
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 = 15;
const int tank2triggeroff = 14;
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();
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);
// 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) {
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;
// Convert tank fill percentages to strings
char tankFilledPercentage1Str[10]; // Adjust the size as needed based on the maximum expected length of your float
char tankFilledPercentage2Str[10]; // Adjust the size as needed based on the maximum expected length of your float
dtostrf(tankFilledPercentage1, 4, 2, tankFilledPercentage1Str); // Convert float to string
dtostrf(tankFilledPercentage2, 4, 2, tankFilledPercentage2Str); // Convert float to string
// Publish tank fill percentages
client.publish(TANK1_PERCENTAGE, tankFilledPercentage1Str);
client.publish(TANK2_PERCENTAGE, tankFilledPercentage2Str);
// 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
float litre1 = calculateLitres(waterheight1, 1);
float litre2 = calculateLitres(waterheight2, 2);
printVolumeAndPercentage(litre1, tankFilledPercentage1, litre2, tankFilledPercentage2);
}
// 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 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");
}
void reconnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
if (client.connect("espClient")) {
Serial.println("connected");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
void printVolumeAndPercentage(float litre1, float percentage1, float litre2, float percentage2) {
Serial.println("------------------------------------");
Serial.print("Tank 1 - Volume: ");
Serial.print(litre1);
Serial.println(" L");
Serial.print("Tank 1 - Filled Percentage: ");
Serial.print(percentage1);
Serial.println("%");
Serial.println("------------------------------------");
Serial.print("Tank 2 - Volume: ");
Serial.print(litre2);
Serial.println(" L");
Serial.print("Tank 2 - Filled Percentage: ");
Serial.print(percentage2);
Serial.println("%");
Serial.println("------------------------------------");
}
float calculateLitres(int waterheight, int tankNumber) {
if (waterheight == 0) {
return 0;
} else {
float tankvolume = pi * (tankNumber == 1 ? tank1radius : tank2radius) * (tankNumber == 1 ? tank1radius : tank2radius) * waterheight;
return tankvolume * 0.001;
}
}
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;
}
}
void intro() {
// Print introduction on LCD
lcd.clear();
lcd.println("WATER MONITORING");
lcd.setCursor(3, 1);
lcd.println("SYSTEM:2.0");
delay(1500);
lcd.clear();
lcd.setCursor(7, 0);
lcd.println("ALL");
lcd.setCursor(2, 1);
lcd.println("RIGHTSRESERVED");
delay(1000);
lcd.clear();
lcd.setCursor(1, 0);
lcd.println("MANOMOY MAITY");
delay(750);
}