Early Detection of Water Source Pollution

A system that monitor the water source condition and notify remotely in the event when there's possibility of water source being polluted.

BeginnerShowcase (no instructions)132
Early Detection of Water Source Pollution

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
The purchase platform of this was not sure. This component was bought before for previous usage.
×1
XL6009 4A Step Up Module
×1
3.7V 2000mAh Li-Ion Battery
×1
1x18650 Battery Holder
×1
40-Way 20cm Dupont Jumper Wire
×1
NODEMCU ESP32
×1
Gravity-Analog Turbidity Sensor For Arduino
×1
pH Sensor
×1
TP4056 Charging Module
×1
Solar Panel
×1
Plastic Container
×1

Software apps and online services

Arduino IDE
Arduino IDE
Blynk
Blynk

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Solder Wire, Lead Free
Solder Wire, Lead Free
Purchasing platform of this was not sure. The shown link is not the actual platform of where purchased was done.
Multimeter
Blade
Tape

Story

Read more

Schematics

pH Sensor

This is the schematic of the pH sensor connection.

Sensor Connection for UI

This is the schematic of the sensors connection for UI.

Turbidity Connection

This is the schematic of the turbidity sensor connection.

Power Unit Connection

This is the schematic of power unit connection.
Based on Bonestroo, H. (2022) Powering Arduino Uno with Solar Cell. Sensing the City. https://www.sensingthecity.com/powering-arduino-uno-with-solar-cell/

Code

pH Sensor Measurement Code

C/C++
This is the code for pH sensor measurement.
#define SensorPin A0        //pH meter Analog output to Arduino Analog Input0
#define Offset 29.904     //deviation compensate
#define samplingInterval 20
#define printInterval 800
#define ArrayLenth  40    //times of collection
#define uart  Serial
int pHArray[ArrayLenth];   //Store the average value of the sensor feedback
int pHArrayIndex = 0;
 
void loop(void)
{
  static unsigned long samplingTime = millis();
  static unsigned long printTime = millis();
  static float pHValue, voltage;
  if (millis() - samplingTime > samplingInterval)
  {
    pHArray[pHArrayIndex++] = analogRead(SensorPin);
    if (pHArrayIndex == ArrayLenth)pHArrayIndex = 0;
    voltage = avergearray(pHArray, ArrayLenth) * 5.0 / 1024;
    pHValue = -5.6604 * voltage + Offset;
    samplingTime = millis();
  }
  if (millis() - printTime > printInterval) //Every 800 ms, print a numerical
  {
    uart.print("Voltage:");
    uart.print(voltage, 2);
    uart.print("    pH value: ");
    uart.println(pHValue, 2);
    printTime = millis();
  }
}
double avergearray(int* arr, int number) {
  int i;
  int max, min;
  double avg;
  long amount = 0;
  if (number <= 0) {
    uart.println("Error number for the array to avraging!/n");
    return 0;
  }
  if (number < 5) { //less than 5, calculated directly statistics
    for (i = 0; i < number; i++) {
      amount += arr[i];
    }
    avg = amount / number;
    return avg;
  } else {
    if (arr[0] < arr[1]) {
      min = arr[0]; max = arr[1];
    }
    else {
      min = arr[1]; max = arr[0];
    }
    for (i = 2; i < number; i++) {
      if (arr[i] < min) {
        amount += min;      //arr<min
        min = arr[i];
      } else {
        if (arr[i] > max) {
          amount += max;  //arr>max
          max = arr[i];
        } else {
          amount += arr[i]; //min<=arr<=max
        }
      }//if
    }//for
    avg = (double)amount / (number - 2);
  }//if
  return avg;
}

UI Code

C/C++
This is the code for reading the sensor value and send it to the Blynk platform for monitor purpose.
#define BLYNK_TEMPLATE_ID "TMPL6sveHm8J_"
#define BLYNK_TEMPLATE_NAME "Water Monitor and Notifying System"
#define BLYNK_AUTH_TOKEN "YC5wcrClQd0eSBFI_PvhMvaPM-4sP-nu"

#define BLYNK_FIRMWARE_VERSION        "0.1.0"

#define BLYNK_PRINT Serial
//#define BLYNK_DEBUG

#define APP_DEBUG

// Declare pin
#define pH_Vpin V0
#define turbidity_Vpin V1
#define indicator_Vpin V2
#define turbidity_pin 34
#define pH_pin 35

// Uncomment your board, or configure a custom board in Settings.h
//#define USE_ESP32_DEV_MODULE
//#define USE_ESP32C3_DEV_MODULE
//#define USE_ESP32S2_DEV_KIT
//#define USE_WROVER_BOARD
//#define USE_TTGO_T7
//#define USE_TTGO_T_OI

#include "BlynkEdgent.h"

void setup()
{
  Serial.begin(115200);
  delay(100);

  BlynkEdgent.begin();
}

void loop() {
  BlynkEdgent.run();

  float pHValue = analogRead(pH_pin);
  int turbidityValue = analogRead(turbidity_pin);
  
  Blynk.virtualWrite(pH_Vpin, pHValue);
  Blynk.virtualWrite(turbidity_Vpin, turbidityValue);
  
}

void trigerIndicator () {

  if ( (pHValue >= 9 && <= 6.5) || (turbidityValue >= 50)){
    Blynk.virtualWrite (V2,1);
    else 
    Blynk.virtualWrite (V2,0);
  }
}

Turbidity Sensor Measurement Code

C/C++
This is the code for Turbidity sensor measurement.
#include <LiquidCrystal_I2C.h>
#include <Wire.h>


LiquidCrystal_I2C lcd(0x27, 16, 2);


int Turbidity_Sensor_Pin = A0;

float Turbidity_Sensor_Voltage;

int samples = 600;

float ntu; // Nephelometric Turbidity Units


void setup() {

  Serial.begin(9600); // for debugging purposes

  pinMode(Turbidity_Sensor_Pin, INPUT);

  lcd.init();                 //Init the LCD

  lcd.backlight();            //Activate backlight    

  lcd.home();

}




void loop() {

   Turbidity_Sensor_Voltage = 0;

    /* its good to take some samples and take the average value. This can be quite handy

     *  in situations when the values fluctuates a bit. This way you can take the average value

     *  i am going to take 600 samples

     */

    for(int i=0; i<samples; i++)

    {

        Turbidity_Sensor_Voltage += ((float)analogRead(Turbidity_Sensor_Pin)/1023)*5;

    }

   

    Turbidity_Sensor_Voltage = Turbidity_Sensor_Voltage/samples;

    // uncomment the following two statments to check the voltage.

    // if you see any variations, take necessary steps to correct them

    // once you are satisfied with the voltage value then again you can comment these lines

   

    Serial.println("Voltage:");

    Serial.println(Turbidity_Sensor_Voltage);

     

    Turbidity_Sensor_Voltage = round_to_dp(Turbidity_Sensor_Voltage,2);

    if(Turbidity_Sensor_Voltage < 2.5){

      ntu = 3000;

    }else{

      ntu = -1120.4*square(Turbidity_Sensor_Voltage)+ 5742.3*Turbidity_Sensor_Voltage - 4352.9;

    }

    lcd.clear();

    lcd.setCursor(0,0);

    lcd.print(Turbidity_Sensor_Voltage);

    lcd.print(" V");

 

    lcd.setCursor(0,1);

    lcd.print(ntu);

    lcd.print(" NTU");

    delay(10);

}




float round_to_dp( float in_value, int decimal_place )

{

  float multiplier = powf( 10.0f, decimal_place );

  in_value = roundf( in_value * multiplier ) / multiplier;

  return in_value;

}

Notification Feature Code

C/C++
This is the code for the notification.
// Water Pollution Notifying System with Webpage Monitoring

#define BLYNK_TEMPLATE_ID "TMPL69c7QScMV"
#define BLYNK_DEVICE_NAME "Notifying"
#define BLYNK_AUTH_TOKEN "TYPE HERE "


#include <ArduinoJson.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <BlynkSimpleEsp32.h>
#include <UniversalTelegramBot.h>
#include <WebServer.h>


// Telegram bot parameters
#define BOT_TOKEN "TYPE HERE "
#define CHAT_ID "TYPE HERE"


// Virtual pin for the switch button
#define VIRTUAL_PIN_SWITCH V1


// Wi-Fi network credentials
const char* ssid = "TYPE HERE";
const char* password = "TYPE HERE";


// Initialize the Telegram bot client
WiFiClientSecure client;
UniversalTelegramBot bot(BOT_TOKEN, client);


// Web server parameters
WebServer server(80);


// Structure to store the time and date
struct DateTime {
  String message;
  String time;
};


const int MAX_DATA_ENTRIES = 100; // Maximum number of data entries to store
DateTime dataEntries[MAX_DATA_ENTRIES]; // Array to store the data entries
int dataCount = 0; // Counter for the number of data entries


void handleRoot() {
  // Generate the HTML response
  String html = "<html><body>";
  html += "<h1>Water Pollution Notifying System</h1>";
  html += "<h2>Data Entries:</h2>";


  // Display the stored data entries
  for (int i = 0; i < dataCount; i++) {
    html += "<p>Message: " + dataEntries[i].message + "</p>";
    html += "<p>Time: " + dataEntries[i].time.substring(11) + "</p>";
    html += "<p>Date: " + dataEntries[i].time.substring(0, 10) + "</p>";
    html += "<hr>";
  }


  html += "</body></html>";


  // Send the response to the client
  server.send(200, "text/html", html);
}


void setup() {
  // Start serial communication
  Serial.begin(115200);


  configTime(0, 0, "pool.ntp.org"); // Set NTP time server
  setenv("TZ", "UTC-8", 1); // Set time zone to GMT+8
  tzset(); // Update the system's time zone


  // Connect to Wi-Fi network
  WiFi.begin(ssid, password);
  client.setCACert(TELEGRAM_CERTIFICATE_ROOT); // Add root certificate for api.telegram.org
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  Serial.println("Connected to Wi-Fi");


  // Start Blynk
  Blynk.begin(BLYNK_AUTH_TOKEN, ssid, password);
  Serial.println("Connected to Blynk");


  // Set the switch widget to push mode
  Blynk.setProperty(VIRTUAL_PIN_SWITCH, "mode", "push");


  // Clear the switch widget state
  Blynk.virtualWrite(VIRTUAL_PIN_SWITCH, 0);


  // Set up the web server
  server.on("/", handleRoot);
  server.begin();
}


void loop() {
  // Run the Blynk event loop
  Blynk.run();


  // Handle client requests
  server.handleClient();
}


// Function to send a message to Telegram and store the data entry
void sendMessage(String message) {
  if (!client.connect("api.telegram.org", 443)) {
    Serial.println("Connection to Telegram failed");
    return;
  }


  // Send the message to Telegram
  bot.sendMessage(CHAT_ID, message, "Markdown");


  // Store the data entry
  DateTime dataEntry;
  dataEntry.message = message;
  dataEntry.time = getTimeDateString();
  
  // Add the data entry to the array
  dataEntries[dataCount] = dataEntry;
  dataCount++;


  Serial.println("Message sent to Telegram and stored");
}


// Handle the switch widget state change
BLYNK_WRITE(VIRTUAL_PIN_SWITCH) {
  int switchState = param.asInt();


  Serial.print("Switch state changed: ");
  Serial.println(switchState);


  if (switchState == 1) {
    sendMessage("*Water is Polluted!*");
  }
}


// Function to get the current time and date as a string
String getTimeDateString() {
  // Get the current time
  time_t now = time(nullptr);
  
  // Convert the time to a string
  struct tm* timeinfo;
  timeinfo = localtime(&now);
  
  char buffer[20];
  strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeinfo);
  
  return String(buffer);
}

Credits

FOONG YI BIN
1 project • 1 follower
Keith Maate Kwijuka
1 project • 1 follower
Nicholas Tjoe
1 project • 1 follower
Paramasudhen Ravendran
1 project • 1 follower
YUTO TAHARA
1 project • 1 follower
NARENDRAN
20 projects • 22 followers

Comments