Hackster is hosting Hackster Holidays, Ep. 7: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Friday!Stream Hackster Holidays, Ep. 7 on Friday!
Wei Pin ChowNARENDRANDaryl Chung Jia HungChee Wen JingChowSietYamDylanMingFoungSamuel Chee
Published © GPL3+

Rain Water Harvesting for Food and Beverage Industry System

Rain Water Harvesting for food and beverage industry monitoring and control system

IntermediateShowcase (no instructions)24 hours477
Rain Water Harvesting for Food and Beverage Industry System

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
×2
LED (generic)
LED (generic)
×7
Visual Studio 2019
Microsoft Visual Studio 2019
×1
Breadboard (generic)
Breadboard (generic)
×4
YFS201 Water Flow Sensor
×3
Water Level Sensor
×2
Rainwater Sensor
×1
Analogue Turbidity Sensor Module
×1
pH Sensor Module
×1
Compact RC Servo 1.8kg.cm
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Schematics

Rainwater harvesting system schematic

This part contains the schematic diagram for rainwater harvesting system

Rainwater harvesting system circuit diagram

Water Quality Monitoring System - Schematic

This part contains the schematic and circuit diagram for water quality monitoring system

Water Quality Monitoring System - circuit

Water Leakage Monitoring System Schematic

This part contains the schematic diagram of water leakage monitoring system

Water Leakage Monitoring System Circuit

Excessive Water Consumption Monitoring System - Schematic

This part contains the schematic and circuit diagram of excessive water consumption monitoring system.

Excessive Water Consumption Monitoring System - Circuit

Rainwater harvesting + Excessive water consumption Schematic

This part contains the combined system of rainwater harvesting and excessive water consumption system

Rainwater harvesting + Excessive water consumption Circuit

Water Quality + Water Leakage Schematic

This part contains the combined schematic diagram of water quality management system and water leakage monitoring system

Water Quality + Water Leakage Circuit

Code

Rainwater Harvesting System

Arduino
This part of code was for individual parts, only for rainwater harvesting system.
By: DARYL CHUNG JIA HUNG TP060584
// Defining global variables
// Variables for Water Level Sensor, Initialize Level of Water as 0.
#define WLsensorPower 7
#define WLsensorPin A0
int waterval = 0;

// Variables for Rain Detector
#define RDsensorPower 6
#define RDsensorPin 8

// Variables for Servo Motor
#include <Servo.h>
Servo myservo;

// Variables for RGB LEDs
int RED_LED = 5;
int BLUE_LED = 4;
int GREEN_LED = 3;

// Variables for manual function
String data;
char dl;
int lidflag=0;


void setup() {
  // put your setup code here, to run once:
// Setup for Water Level Sensor
pinMode(WLsensorPower, OUTPUT);
digitalWrite(WLsensorPower,LOW);

// Setup for Rain Detector
pinMode(RDsensorPower, OUTPUT);
digitalWrite(RDsensorPower,LOW);

// Setup for Servo Motor
myservo.attach(9);  // attaches the servo on pin 9 to the servo object

// Setup for LED Lights
pinMode(RED_LED, OUTPUT);
pinMode(BLUE_LED, OUTPUT);
pinMode(GREEN_LED, OUTPUT);
Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
// Code for Water Level Sensor
int waterlevel = readWLSensor();
Serial.print("Water level: ");
Serial.println(readWLSensor());
delay(1000);

// Code for Rain Drop Detector
// Get the reading from the function below and print it
int rainval = readRDSensor();
Serial.print("Digital Output: ");
Serial.println(rainval);
delay(200);

// Determine status of rain
if (rainval) {
	Serial.println("Status: Clear");
} else {
	Serial.println("Status: It's raining");
}
delay(200);	// Take a reading every second.
Serial.println();

// Determine status of rainwater collector's lid.
int servoangle = myservo.read(); // Read the current angle of the servo motor.
delay(200);

//Enable the manual function to open or close the rainwater collector's lid. 
  if(Serial.available())
  {
    data = Serial.readString();
    dl = data.charAt(0);
    switch(dl){
      case 'O': //Type 'O' = Open the lid
        myservo.write(80);
        lidflag=1;
        Serial.println("System is set to manual mode.");
        delay(100);
        break;

      case 'C': //Type 'C' = Close the lid
        myservo.write(170); 
        lidflag=1;
        Serial.println("System is set to manual mode.");
        delay(100);
        break;

      case 'A': //Type 'A' = To switch back to sensor dependent mode.
        lidflag=0;
        Serial.println("System is set to automatic mode.");
        delay(100);
        break;
    }
  }

  if(lidflag==0)
  {
  // Code for Servo Motor Position & Status of Water Level
    if (rainval == 1) 
    { // No rain condition
      myservo.write(170); // Lid is shut
      digitalWrite(GREEN_LED,LOW); // Green LED turns off
    }

    if (rainval == 0) 
    { // Rain Condition
      myservo.write(80); // Lid is open
      digitalWrite(GREEN_LED,LOW); // Green LED turns off
    }

    if(waterlevel >= 470 && rainval == 1)
    { // No Rain and Water Level Full Condition
      myservo.write(170); // Lid is shut
      digitalWrite(GREEN_LED,HIGH); // Green LED turns on
    }

    if (waterlevel >= 470 && rainval == 0) 
    { // Rain and water level full condition
      myservo.write(170); // Lid is shut
      digitalWrite(GREEN_LED,HIGH); // Green LED turns on
    }

  }


  // Code for Status of Rainwater Collector's Lid
  if (servoangle == 170)
  { // If the lid is closed
    digitalWrite(RED_LED, HIGH); // Red LED turns on
    digitalWrite(BLUE_LED, LOW); // Blue LED turns on
  }

  if (servoangle == 80)
  { // If the lid is opened
    digitalWrite(RED_LED, LOW); 
    digitalWrite(BLUE_LED, HIGH);
  }

}

//This is a function used to get the water level reading.
int readWLSensor() {
  digitalWrite(WLsensorPower, HIGH);        // Turn the sensor ON
  delay(10);                              // Wait 10 ms
  waterval = analogRead(WLsensorPin);       // Read the analog value from sensor
  digitalWrite(WLsensorPower,LOW);          // Turn the sensor OFF
  return waterval;                        // Send updated reading.
}

//  This function returns the rain detector output
int readRDSensor() {
	digitalWrite(RDsensorPower, HIGH);	// Turn the sensor ON
	delay(10);							// Wait 10 ms
	int rainval = digitalRead(RDsensorPin);	// Read the sensor output
	digitalWrite(RDsensorPower, LOW);		// Turn the sensor OFF
	return rainval;							// Return the value
}

Water Quality Monitoring System

Arduino
This part of code was the individual code for only the water quality monitoring system.
By: CHOW SIET YAM DYLAN MING FOUNG TP062069
#include <Wire.h>

int greenLedPin = 11;
int redLedPin = 10;
float calibration_value = 32;
float calibration_value1 = 52;
int phval = 0;
unsigned long int avgval;
int buffer_arr[10], temp;
float ph_act;

void setup() 
{
  Serial.begin(9600); // Initialize serial communication
  pinMode(greenLedPin, OUTPUT);
  pinMode(redLedPin, OUTPUT);
}

//Turbidity sensor
void loop() 
{
  int sensorValue = analogRead(A0);
  int turbidity = map(sensorValue, 0, 640, 100, 0) + calibration_value1;
  Serial.print("Turbidity: ");
  Serial.print(turbidity);
  Serial.println(" NTU");
  delay(1000); // Wait for 1 second before taking another reading

//pH sensor
  for (int i = 0; i < 10; i++) 
  {
    buffer_arr[i] = analogRead(A1);
    delay(30);
  }

  for (int i = 0; i < 9; i++) 
  {
    for (int j = i + 1; j < 10; j++) 
    {
      if (buffer_arr[i] > buffer_arr[j]) 
      {
        temp = buffer_arr[i];
        buffer_arr[i] = buffer_arr[j];
        buffer_arr[j] = temp;
      }
    }
  }

  avgval = 0;
  for (int i = 2; i < 8; i++)
  avgval += buffer_arr[i];

  float volt = (float)avgval * 5.0 / 1024 / 6;
  float ph_act = -5.70 * volt + calibration_value;

  Serial.print("pH Value: ");
  Serial.println(ph_act);

  //Condition for LEDs
  if (ph_act >= 6.5 && ph_act <= 8.5 && turbidity <= 5) 
  {
    Serial.println("The water can be consumed.");
    digitalWrite(redLedPin, LOW);
    digitalWrite(greenLedPin, HIGH);
  }
  else 
  {
    Serial.println("The water is not safe to consume.");
    digitalWrite(redLedPin, HIGH);
    digitalWrite(greenLedPin, LOW);
  }

  delay(1000);
}

Excessive water consumption monitoring system

Arduino
This part of code was for individual part: Excessive water consumption monitoring system
By: CHEE WEN JING TP059605
// Define Water Level Sensor Pins
#define WATER_LEVEL_SENSOR A5 // analog input pin for the sensor
#define WATER_LEVEL_POWER_PIN 0 // pin to turn on the sensor
#define WATER_LEVEL_RED_LED 11 // pin connected to the resistor and red LED
#define WATER_LEVEL_GREEN_LED 10 // pin connected to the resistor and green LED

// Define Water Level Variables
int waterLevelValue;

/*YF- S201 water Flow sensor code for Arduino */
#define Output_Pin 2 // signal pin for the water flow sensor
#define WATER_FLOW_YELLOW_LED 12 // pin connected to the resistor and the yelloe LED

volatile int  Pulse_Count;
unsigned int  Liter_per_hour;
unsigned long Current_Time, Loop_Time;
float totalUsage = 0; // Variable to store the total tap water usage

void setup()
{ 
  pinMode(WATER_LEVEL_POWER_PIN, OUTPUT);   // configure D3 pin as an OUTPUT of water level snesor
  digitalWrite(WATER_LEVEL_POWER_PIN, LOW); // turn the water level sensor OFF
  pinMode(Output_Pin, INPUT); // configure D2 pin as input of water flow sensor
  pinMode(WATER_LEVEL_RED_LED, OUTPUT); // set water level LED pin as output
  pinMode(WATER_LEVEL_GREEN_LED, OUTPUT); // set water level LED pin as output

  pinMode(WATER_FLOW_YELLOW_LED, OUTPUT); // set water flow LED pin as output
  Serial.begin(9600); 
  attachInterrupt(0, Detect_Rising_Edge, RISING);
  Current_Time = millis();
  Loop_Time = Current_Time;
} 

void loop ()    
{
  // turn the water level sensor ON
  digitalWrite(WATER_LEVEL_POWER_PIN, HIGH);
  // wait 10 milliseconds
  delay(10);
  // Check Water Level
  waterLevelValue = analogRead(WATER_LEVEL_SENSOR);
  Serial.println("\n");
  Serial.println(waterLevelValue);

  if (waterLevelValue > 590)
  {
    Serial.println("Water Level: High ");
  }

  if (waterLevelValue > 550 && waterLevelValue <= 590)
  {
    Serial.println("Water Level: Medium ");
  }

  if (waterLevelValue > 420 && waterLevelValue <= 550)
  {
    Serial.println("Water Level: Low ");
  }

  if (waterLevelValue <= 420)
  {
    Serial.println("Water Level: Empty ");

    Current_Time = millis();
    if (Current_Time >= (Loop_Time + 50)) // Delay of 50ms
    {
      // check water flow
      Loop_Time = Current_Time;
      Liter_per_hour = (Pulse_Count * 60 / 7.5);
      Serial.print("Flow Rate: ");
      Serial.print(Liter_per_hour, DEC);
      Serial.println(" Liter/hour");
      // Calculate total water usage (liters) by dividing flow rate by 3600 (seconds in an hour)
      totalUsage += Liter_per_hour / 3600.0;
      Serial.print("Total Usage: ");
      Serial.print(totalUsage, 2); // Display total usage with 2 decimal places
      Serial.println(" Liters");
      Pulse_Count = 0;
      delay(200);
    }
  }

  // monitor LED condition
  if (waterLevelValue > 590) // high condition
  {
    digitalWrite(WATER_LEVEL_RED_LED, LOW);
    digitalWrite(WATER_LEVEL_GREEN_LED, HIGH);
    digitalWrite(WATER_FLOW_YELLOW_LED, LOW);
  }
  if (waterLevelValue > 550 && waterLevelValue <= 590) // medium condition
  {
    digitalWrite(WATER_LEVEL_RED_LED, LOW);
    digitalWrite(WATER_LEVEL_GREEN_LED, HIGH);
    digitalWrite(WATER_FLOW_YELLOW_LED, LOW);
  }
  if (waterLevelValue > 420 && waterLevelValue <= 550) // low condition
  {
    digitalWrite(WATER_LEVEL_RED_LED, LOW);
    digitalWrite(WATER_LEVEL_GREEN_LED, HIGH);
    digitalWrite(WATER_FLOW_YELLOW_LED, LOW);
  }
  if (waterLevelValue <= 420) // empty condition
  {
    digitalWrite(WATER_LEVEL_RED_LED, HIGH);
    digitalWrite(WATER_LEVEL_GREEN_LED, LOW);
    digitalWrite(WATER_FLOW_YELLOW_LED, HIGH);
  }
  delay(200);
}

void Detect_Rising_Edge ()
{ 
   Pulse_Count++;
} 

Water Leakage Detection System

Arduino
this part was the code for only water leakage detection system.
By: CHEE MAN SHING SAMUEL TP060828
// Initialising PIN connection
byte LED_GREEN = 13;
byte LED_RED = 12;
byte sensorInterrupt = 0;  // 0 = digital pin 2
byte sensorPin       = 2;
byte sensorInterrupt1 = 1;  // 1 = digital pin 3
byte sensorPin1       = 3;

// The hall-effect flow sensor outputs approximately 4.5 pulses per second per
// litre/minute of flow.
float calibrationFactor = 4.5;

volatile byte pulseCount;  
volatile byte pulseCount1;

float flowRate;
float flowRate1;
float difference;
unsigned long oldTime;

void setup()
{
  
  // Initialize a serial connection for reporting values to the host
  Serial.begin(9600);
  pinMode(LED_RED, OUTPUT);
  pinMode(LED_GREEN, OUTPUT);
  pinMode(sensorPin, INPUT);
  digitalWrite(sensorPin, HIGH);
  pinMode(sensorPin1, INPUT);
  digitalWrite(sensorPin1, HIGH);

  pulseCount         = 0;
  flowRate           = 0.0;
  oldTime            = 0;
  pulseCount1        = 0;
  flowRate1          = 0.0;
  difference         = 0;

  // The Hall-effect sensor is connected to pin 2 which uses interrupt 0.
  // Configured to trigger on a FALLING state change (transition from HIGH
  // state to LOW state)
  attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
  attachInterrupt(sensorInterrupt1, pulseCounter1, FALLING);
}

/**
 * Main program loop
 */
void loop()
{
 
delay(100);
   
   if((millis() - oldTime) > 1000)    // Only process counters once per second
  { 
    // Disable the interrupt while calculating flow rate and sending the value to
    // the host
    detachInterrupt(sensorInterrupt);
    detachInterrupt(sensorInterrupt1);
        
    // Because this loop may not complete in exactly 1 second intervals we calculate
    // the number of milliseconds that have passed since the last execution and use
    // that to scale the output. We also apply the calibrationFactor to scale the output
    // based on the number of pulses per second per units of measure (litres/minute in
    // this case) coming from the sensor.
    flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;
    flowRate1 = ((1000.0 / (millis() - oldTime)) * pulseCount1) / calibrationFactor;
    difference = flowRate - flowRate1;
    if(difference > 1)
    {
    digitalWrite(LED_RED, HIGH); // turn the red LED on
    digitalWrite(LED_GREEN, LOW);
    delay(1000); // wait for a second
    }               
    else
    {
    digitalWrite(LED_GREEN, HIGH);   // turn the green LED on
    digitalWrite(LED_RED, LOW);
    delay(1000); // wait for a second
    }
    
    // Note the time this processing pass was executed. Note that because we've
    // disabled interrupts the millis() function won't actually be incrementing right
    // at this point, but it will still return the value it was set to just before
    // interrupts went away.
    oldTime = millis();
      
    unsigned int frac;
    
    // Print the flow rate for this second in litres / minute
    Serial.print("Flow rate of 1st Sensor: ");
    Serial.print(int(flowRate));  // Print the integer part of the variable
    Serial.print("L/min");
    Serial.print("\n");
    Serial.print("Flow rate of 2nd Sesnor: ");
    Serial.print(int(flowRate1));  // Print the integer part of the variable
    Serial.print("L/min");
    Serial.print("\n");
    Serial.print("Difference: ");
    Serial.print(int(difference));  // Print the integer part of the variable
    Serial.print("L/min");
    Serial.print("\n");
    Serial.print("\n");

    // Reset the pulse counter so we can start incrementing again
    pulseCount = 0;
    pulseCount1 = 0;
    
    // Enable the interrupt again now that we've finished sending output
    attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
    attachInterrupt(sensorInterrupt1, pulseCounter1, FALLING);
  }
}

// Interrupt Service Routine
void pulseCounter()
{
  // Increment the pulse counter
  pulseCount++;
}
void pulseCounter1()
{
  // Increment the pulse counter
  pulseCount1++;
}

Rainwater Harvesting + Excessive water consumption monitoring system

Arduino
This code compiled the rainwater harvesting system and excessive water consumption monitoring system together, which was the final Arduino code being uploaded to one of the Arduino device.
By: CHOW WEI PIN TP062490
// Define Water Level Sensor Pins
#define WATER_LEVEL_SENSOR A5 // analog input pin for the sensor
#define WATER_LEVEL_POWER_PIN 0 // pin to turn on the sensor
#define WATER_LEVEL_RED_LED 11 // pin connected to the resistor and red LED
#define WATER_LEVEL_GREEN_LED 10 // pin connected to the resistor and green LED

// Define Water Level Variables
int waterLevelValue;

/*YF- S201 water Flow sensor code for Arduino */
#define Output_Pin 2 // signal pin for the water flow sensor
#define WATER_FLOW_YELLOW_LED 12 // pin connected to the resistor and the yelloe LED

volatile int  Pulse_Count;
unsigned int  Liter_per_hour;
unsigned long Current_Time, Loop_Time;
float totalUsage = 0; // Variable to store the total tap water usage

// Daryl's part
// Defining global variables
// waterval = 560 for full water level
// Variables for Water Level Sensor, Initialize Level of Water as 0.
#define WLsensorPower 7
#define WLsensorPin A0
int waterval = 0;
int servoangle;
String data;
char dl;
int lidflag=0;
// Variables for Rain Detector
#define RDsensorPower 6
#define RDsensorPin 8

// Variables for Servo Motor
#include <Servo.h>
Servo myservo;

// Variables for RGB LEDs
int RED_LED = 5;
int BLUE_LED = 4;
int GREEN_LED = 3;

void setup()
{ 
  pinMode(WATER_LEVEL_POWER_PIN, OUTPUT);   // configure D3 pin as an OUTPUT of water level snesor
  digitalWrite(WATER_LEVEL_POWER_PIN, LOW); // turn the water level sensor OFF
  pinMode(Output_Pin, INPUT); // configure D2 pin as input of water flow sensor
  pinMode(WATER_LEVEL_RED_LED, OUTPUT); // set water level LED pin as output
  pinMode(WATER_LEVEL_GREEN_LED, OUTPUT); // set water level LED pin as output
  pinMode(WATER_FLOW_YELLOW_LED, OUTPUT); // set water flow LED pin as output
  Serial.begin(9600); 
  attachInterrupt(0, Detect_Rising_Edge, RISING);

  Current_Time = millis();
  Loop_Time = Current_Time;

  // Daryl's part
  // Setup for Water Level Sensor
  pinMode(WLsensorPower, OUTPUT);
  digitalWrite(WLsensorPower,LOW);

  // Setup for Rain Detector
  pinMode(RDsensorPower, OUTPUT);
  digitalWrite(RDsensorPower,LOW);

  // Setup for Servo Motor
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object

  // Setup for LED Lights
  pinMode(RED_LED, OUTPUT);
  pinMode(BLUE_LED, OUTPUT);
  pinMode(GREEN_LED, OUTPUT);

} 

void loop ()    
{
  digitalWrite(WATER_LEVEL_POWER_PIN, HIGH);  // turn the sensor ON
  delay(10);                      // wait 10 milliseconds
  // Check Water Level
  waterLevelValue = analogRead(WATER_LEVEL_SENSOR);
  
  Serial.print(waterLevelValue);
  Serial.print("W");
  
  if (waterLevelValue > 590)
  {
    //edited
    // Serial.print("Water Level: ");
    // Serial.println("High");

    digitalWrite(WATER_LEVEL_RED_LED, LOW);
    digitalWrite(WATER_LEVEL_GREEN_LED, HIGH);
    digitalWrite(WATER_FLOW_YELLOW_LED, LOW);
  }
  if (waterLevelValue > 550 && waterLevelValue <= 590)
  {
    //edited
    // Serial.print("Water Level: ");
    // Serial.println("Medium");

    digitalWrite(WATER_LEVEL_RED_LED, LOW);
    digitalWrite(WATER_LEVEL_GREEN_LED, HIGH);
    digitalWrite(WATER_FLOW_YELLOW_LED, LOW);
  }
  if (waterLevelValue > 420 && waterLevelValue <= 550)
  {
    //edited
    // Serial.print("Water Level: ");
    // Serial.println("Low");

    digitalWrite(WATER_LEVEL_RED_LED, LOW);
    digitalWrite(WATER_LEVEL_GREEN_LED, HIGH);
    digitalWrite(WATER_FLOW_YELLOW_LED, LOW);
  }
  if (waterLevelValue <= 420)
  {
    // Serial.println("Water Level: Empty ");
    digitalWrite(WATER_LEVEL_RED_LED, HIGH);
    digitalWrite(WATER_LEVEL_GREEN_LED, LOW);
    digitalWrite(WATER_FLOW_YELLOW_LED, HIGH);

    Current_Time = millis();
    if (Current_Time >= (Loop_Time + 30)) // Delay of 50ms for calculating flow rate
    {
      // check water flow
      Loop_Time = Current_Time;
      Liter_per_hour = (Pulse_Count * 60 / 7.5);
      // Serial.print("Flow Rate: ");
      
      
      Pulse_Count = 0;
      // Serial.print(Liter_per_hour, DEC);
      // Serial.println(" Liter/hour");
      // Calculate total water usage (liters) by dividing flow rate by 3600 (seconds in an hour)
      totalUsage += Liter_per_hour / 3600.0;
      // Serial.print("Total Usage: ");
      
      

      // Serial.println(" Liters");
      Pulse_Count = 0;
      digitalWrite(WATER_FLOW_YELLOW_LED, HIGH);
      delay(50);
    }
  }
  Serial.print(Liter_per_hour, DEC);
  Serial.print("F");
  Serial.print(totalUsage, 2); // Display total usage with 2 decimal places
  Serial.print("T");
  delay(50);

  // Daryls' part
  //to open and close the lid manually
  if(Serial.available()){
    data = Serial.readString();
    dl = data.charAt(0);
    switch(dl){
      case 'O': //first character is O = open the lid
        myservo.write(80);
        lidflag=1;
        delay(200);
        break;
      case 'C': //first character is C = close the lid
        myservo.write(170); 
        lidflag=1;
        delay(200);
        break;
      case 'A':
        lidflag=0;
        break;
    }
  }

  // Code for Water Level Sensor
  int waterlevel = readWLSensor();
  
  Serial.print(readWLSensor());
  Serial.print("L");
  delay(30);


  // Code for Rain Drop Detector
  // Get the reading from the function below and print it
  int rainval = readRDSensor();
  
  Serial.print(rainval);
  Serial.print("R");


  // Determine status of rain
  // if (rainval) {
  //   Serial.println("Status: Clear");
  // } else {
  //   Serial.println("Status: It's raining");
  // }
  delay(200);  // Take a reading every second.
  // Serial.println();


  // Determine status of rainwater collector's lid.
  int servoangle = myservo.read(); // Read the current angle of the servo motor.
  delay(100);

  if(lidflag==0)
  {
    if (rainval == 1) { // No rain condition
      myservo.write(170);
      digitalWrite(GREEN_LED,LOW); // Green LED turns off
    }


    if (rainval == 0) { // Rain Condition
      myservo.write(80);
      digitalWrite(GREEN_LED,LOW); // Green LED turns off
    }
    if (waterlevel >= 420 && rainval == 0) { // Rain and water level full condition
      myservo.write(170);
      digitalWrite(GREEN_LED,HIGH); // Green LED turns on
    }
  }
  // Code for Servo Motor Position & Status of Water Level


  // Code for Status of Rainwater Collecter's Lid
  if (servoangle == 170){ // If the lid is closed
    digitalWrite(RED_LED, HIGH); // Red LED turns on
    digitalWrite(BLUE_LED, LOW); // Blue LED turns on
  }


  if (servoangle == 80){ // If the lid is opened
    digitalWrite(RED_LED, LOW); 
    digitalWrite(BLUE_LED, HIGH);
  }
  
  Serial.print(servoangle);
  Serial.print("A");
  Serial.print("\n");
  delay(1500);
}


void Detect_Rising_Edge ()
{ 
   Pulse_Count++;
} 

// Daryl's part
//This is a function used to get the water level reading.
int readWLSensor() {
  digitalWrite(WLsensorPower, HIGH);        // Turn the sensor ON
  delay(10);                              // Wait 10 ms
  waterval = analogRead(WLsensorPin);       // Read the analog value from sensor
  digitalWrite(WLsensorPower,LOW);          // Turn the sensor OFF
  return waterval;                        // Send updated reading.
}


//  This function returns the rain detector output
int readRDSensor() {
  digitalWrite(RDsensorPower, HIGH);  // Turn the sensor ON
  delay(10);              // Allow power to settle
  int rainval = digitalRead(RDsensorPin); // Read the sensor output
  digitalWrite(RDsensorPower, LOW);   // Turn the sensor OFF
  return rainval;             // Return the value
}

// total usage = flow rate (litre/hour) * total delay time + total usage

Water Quality Monitoring + Leakage Monitoring

Arduino
This code compiled the water quality monitoring system and leakage monitoring system, then this was the final code being uploaded to the other Arduino device for the specific system.
By: CHOW WEI PIN TP062490
// Initialising PIN connection
byte LED_GREEN = 7;
byte LED_RED = 6;
byte sensorInterrupt = 0;  // 0 = digital pin 2
byte sensorPin       = 2;
byte sensorInterrupt1 = 1;  // 1 = digital pin 3
byte sensorPin1       = 3;

// The hall-effect flow sensor outputs approximately 4.5 pulses per second per
// litre/minute of flow.
float calibrationFactor = 4.5;

volatile byte pulseCount;  
volatile byte pulseCount1;

float flowRate;
unsigned int flowMilliLitres;
unsigned long totalMilliLitres;
float flowRate1;
unsigned int flowMilliLitres1;
unsigned long totalMilliLitres1;
float difference;
unsigned long oldTime;

#include <Wire.h>

int greenLedPin = 11;
int redLedPin = 10;
float calibration_value = 33;
float calibration_value1 = 51.5;
int phval = 0;
unsigned long int avgval;
int buffer_arr[10], temp;
float ph_act;

void setup()
{
  
  // Initialize a serial connection for reporting values to the host
  Serial.begin(9600);
  pinMode(LED_RED, OUTPUT);
  pinMode(LED_GREEN, OUTPUT);
  pinMode(sensorPin, INPUT);
  digitalWrite(sensorPin, HIGH);
  pinMode(sensorPin1, INPUT);
  digitalWrite(sensorPin1, HIGH);

  pulseCount         = 0;
  flowRate           = 0.0;
  oldTime            = 0;
  pulseCount1        = 0;
  flowRate1          = 0.0;
  difference         = 0;

  // The Hall-effect sensor is connected to pin 2 which uses interrupt 0.
  // Configured to trigger on a FALLING state change (transition from HIGH
  // state to LOW state)
  attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
  attachInterrupt(sensorInterrupt1, pulseCounter1, FALLING);

  pinMode(greenLedPin, OUTPUT);
  pinMode(redLedPin, OUTPUT);
}

void loop()
{
 
delay(30);
   
   if((millis() - oldTime) > 1000)    // Only process counters once per second
  { 
    // Disable the interrupt while calculating flow rate and sending the value to
    // the host
    detachInterrupt(sensorInterrupt);
    detachInterrupt(sensorInterrupt1);
        
    // Because this loop may not complete in exactly 1 second intervals we calculate
    // the number of milliseconds that have passed since the last execution and use
    // that to scale the output. We also apply the calibrationFactor to scale the output
    // based on the number of pulses per second per units of measure (litres/minute in
    // this case) coming from the sensor.
    flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;
    flowRate1 = ((1000.0 / (millis() - oldTime)) * pulseCount1) / calibrationFactor;
    difference = flowRate - flowRate1;
    if(difference > 1)
    {
      digitalWrite(LED_RED, HIGH); // turn the red LED on
      digitalWrite(LED_GREEN, LOW);
      delay(50); // wait for a second
    }               
    else
    {
      digitalWrite(LED_GREEN, HIGH);   // turn the green LED on
      digitalWrite(LED_RED, LOW);
      delay(50); // wait for a second
    }
    
    // Note the time this processing pass was executed. Note that because we've
    // disabled interrupts the millis() function won't actually be incrementing right
    // at this point, but it will still return the value it was set to just before
    // interrupts went away.
    oldTime = millis();
      
    unsigned int frac;
    
    // Print the flow rate for this second in litres / minute
    // Serial.print("Flow rate of 1st Sensor: ");
    // Serial.print(int(flowRate));  // Print the integer part of the variable
    // Serial.print("L/min");
    // Serial.print("\n");
    // Serial.print("Flow rate of 2nd Sesnor: ");
    // Serial.print(int(flowRate1));  // Print the integer part of the variable
    // Serial.print("L/min");
    // Serial.print("\n");
    // Serial.print("Difference: ");
    // Serial.print(int(difference));  // Print the integer part of the variable
    // Serial.print("L/min");
    // Serial.print("\n");
    // Serial.print("\n");

    // Reset the pulse counter so we can start incrementing again
    pulseCount = 0;
    pulseCount1 = 0;
    
    // Enable the interrupt again now that we've finished sending output
    attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
    attachInterrupt(sensorInterrupt1, pulseCounter1, FALLING);
  }
  int sensorValue = analogRead(A0);
  int turbidity = map(sensorValue, 0, 640, 100, 0) + calibration_value1;
  // Serial.print("Turbidity: ");
  // Serial.print(turbidity);
  // Serial.println(" NTU");
  delay(50); // Wait for 1 second before taking another reading

  //pH sensor
  for (int i = 0; i < 10; i++) 
  {
    buffer_arr[i] = analogRead(A1);
    delay(30);
  }

  for (int i = 0; i < 9; i++) 
  {
    for (int j = i + 1; j < 10; j++) 
    {
      if (buffer_arr[i] > buffer_arr[j]) 
      {
        temp = buffer_arr[i];
        buffer_arr[i] = buffer_arr[j];
        buffer_arr[j] = temp;
      }
    }
  }

  avgval = 0;
  for (int i = 2; i < 8; i++)
  avgval += buffer_arr[i];

  float volt = (float)avgval * 5.0 / 1024 / 6;
  float ph_act = -5.70 * volt + calibration_value;

  // Serial.print("pH Value: ");
  // Serial.println(ph_act);

  //Condition for LEDs
  if (ph_act >= 6.5 && ph_act <= 8.5 && turbidity <= 5) 
  {
    
    //Serial.println("The water can be consumed.");
    digitalWrite(redLedPin, LOW);
    digitalWrite(greenLedPin, HIGH);
  }
  else 
  {
    //Serial.println("The water is not safe to consume.");
    digitalWrite(redLedPin, HIGH);
    digitalWrite(greenLedPin, LOW);
  }
  Serial.print(ph_act);
  Serial.print("W");
  
  Serial.print(turbidity);
  Serial.print("X");

  Serial.print(int(flowRate));  // Print the integer part of the variable
  Serial.print("Y");

  Serial.print(int(flowRate1));  // Print the integer part of the variable
  Serial.print("Z");

  Serial.print(int(difference));  // Print the integer part of the variable
  Serial.println("D");
  delay(1200);
  
}

// Insterrupt Service Routine
void pulseCounter()
{
  // Increment the pulse counter
  pulseCount++;
}
void pulseCounter1()
{
  // Increment the pulse counter
  pulseCount1++;
}

GUI code

C#
This part contain the code for the GUI for the overall system. The GUI was created using Windows Form through Visual Studio
By: CHOW WEI PIN TP062490
using System;
using System.ComponentModel;
using System.IO.Ports;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;

namespace MSESGUI
{
    public partial class Form1 : Form
    {
        // Declare a SerialPort object to use for the connection
        //private SerialPort serialPort1;
        private Series series;
        string serialDataIn1,serialDataIn2;
        sbyte indexOfF, indexOfW, indexOfL, indexOfR, indexOfA, indexOfT;
        sbyte indexOfpH, indexOfNTU, indexOfFI, indexOfFO, indexOfD;
        string dataFlowSensor, dataWaterLevelSensor1, dataWaterLevelSensor2, dataRainSensor, dataServermotor,dataTotalUsage;
        string pHvalue, NTUlevel, Flow1, Flow2, Difference;
        float floatpHvalue;
        int turbidity;

        public Form1()
        {
            InitializeComponent();
           
        }

        private void ScanPortButton_Click(object sender, EventArgs e)
        {
            ConnectionPanel.Focus();
            //scan for available port
            string[] ports = SerialPort.GetPortNames();

            //add each available port to the list
            if (ports.Length == 0)
            {
                MessageBox.Show("No ports found.");
                BaudRateList.Enabled = false;
                ConnectButton.Enabled = false;
            }
            else
            {
                foreach (string port in ports)
                {
                    PortList.Items.Add(port);
                }
                // Enable the BaudRateList and ConnectButton
                BaudRateList.Enabled = true;
                ConnectButton.Enabled = true;
            }
        }

        private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
        {
            this.BeginInvoke(new EventHandler(ProcessData2));
        }

        private void DisconnectButton2_Click(object sender, EventArgs e)
        {
            try
            {
                // Close the serial port
                serialPort2.Close();
                // Enable the UI controls that were disabled while connected
                ScanPortButton2.Enabled = true;
                PortList2.Enabled = true;
                BaudRateList2.Enabled = true;
                ConnectButton2.Enabled = true;
                // Disable the DisconnectButton
                DisconnectButton2.Enabled = false;
                DisconnectButton2.SendToBack();
                timer2.Stop();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Failed to disconnect from serial port: {ex.Message}");
            }
        }
        private void timer1_Tick(object sender, EventArgs e)
        {
            if (!backgroundWorker1.IsBusy)
            {
                backgroundWorker1.RunWorkerAsync();
            }
        }

        private void OpenButton_Click(object sender, EventArgs e)
        {
            //open the lid by sending command to servo motor
            string o1 = "O80";
            serialPort1.Write(o1);
            OpenButton.SendToBack();
            
        }

        private void OffButton_Click(object sender, EventArgs e)
        {
            string c1 = "C170";
            serialPort1.Write(c1);
            CloseButton.SendToBack();
            
        }

        private void timer2_Tick(object sender, EventArgs e)
        {
            if (!backgroundWorker2.IsBusy)
            {
                backgroundWorker2.RunWorkerAsync();
            }
        }

        private void ScanPortButton2_Click(object sender, EventArgs e)
        {
            ConnectionPanel2.Focus();
            //scan for available port
            string[] ports2 = SerialPort.GetPortNames();

            //add each available port to the list
            if (ports2.Length == 0)
            {
                MessageBox.Show("No ports found.");
                BaudRateList2.Enabled = false;
                ConnectButton2.Enabled = false;
            }
            else
            {
                foreach (string port in ports2)
                {
                    PortList2.Items.Add(port);
                }
                // Enable the BaudRateList and ConnectButton
                BaudRateList2.Enabled = true;
                ConnectButton2.Enabled = true;
            }
        }
        private void ConnectButton2_Click(object sender, EventArgs e)
        {
            // Get the selected port and baud rate from the UI
            string selectedPort = PortList2.SelectedItem.ToString();
            int selectedBaudRate = int.Parse(BaudRateList2.SelectedItem.ToString());

            // Create a new SerialPort object with the selected settings
            serialPort2.BaudRate = selectedBaudRate;
            serialPort2.PortName = selectedPort;
            try
            {
                // Open the serial port
                serialPort2.Open();

                // Disable the UI controls that aren't relevant while connected
                ScanPortButton2.Enabled = false;
                PortList2.Enabled = false;
                BaudRateList2.Enabled = false;
                ConnectButton2.Enabled = false;
                ConnectButton2.SendToBack();

                // Enable the DisconnectButton
                DisconnectButton2.Enabled = true;
                timer2.Start();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Failed to connect to {selectedPort} at {selectedBaudRate} baud: {ex.Message}");
            }
        }

        private void WaterQualityCheck_Click(object sender, EventArgs e)
        {
            
            floatpHvalue = float.Parse(pHvalue);
            turbidity = int.Parse(NTUlevel);

            if(floatpHvalue>=6.5 && floatpHvalue<=8.5 && turbidity<=5)
            {
                WaterQualityPic.SizeMode = PictureBoxSizeMode.Zoom;
                WaterQualityPic.Image = imageList1.Images[0];
            }
            else
            {
                WaterQualityPic.SizeMode = PictureBoxSizeMode.Zoom;
                WaterQualityPic.Image = imageList1.Images[1];
            }
            phLevelText.Text = pHvalue;

            NTUText.Text = NTUlevel;
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            this.BeginInvoke(new EventHandler(ProcessData));
            
        }

        private void autobutton_Click(object sender, EventArgs e)
        {
            string auto = "A";
            serialPort1.Write(auto);
        }

        private void ConnectButton_Click(object sender, EventArgs e)
        {
            // Get the selected port and baud rate from the UI
            string selectedPort = PortList.SelectedItem.ToString();
            int selectedBaudRate = int.Parse(BaudRateList.SelectedItem.ToString());

            // Create a new SerialPort object with the selected settings
            serialPort1.BaudRate = selectedBaudRate;
            serialPort1.PortName = selectedPort;
            try
            {
                // Open the serial port
                serialPort1.Open();

                // Disable the UI controls that aren't relevant while connected
                ScanPortButton.Enabled = false;
                PortList.Enabled = false;
                BaudRateList.Enabled = false;
                ConnectButton.Enabled = false;
                ConnectButton.SendToBack();

                // Enable the DisconnectButton
                DisconnectButton.Enabled = true;
               
                timer1.Start();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Failed to connect to {selectedPort} at {selectedBaudRate} baud: {ex.Message}");
            }
        }
        private void DisconnectButton_Click(object sender, EventArgs e)
        {
            try
            {
                // Close the serial port
                serialPort1.Close();

                // Enable the UI controls that were disabled while connected
                ScanPortButton.Enabled = true;
                PortList.Enabled = true;
                BaudRateList.Enabled = true;
                ConnectButton.Enabled = true;
                // Disable the DisconnectButton
                DisconnectButton.Enabled = false;
                DisconnectButton.SendToBack();
                timer1.Stop();  
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Failed to disconnect from serial port: {ex.Message}");
            }
        }

        private void plotwaterusage()
        {
            
            try
            {
                if(serialPort1.IsOpen==true)
                {
                    
                    waterusagechart.Invoke((MethodInvoker)(()=> waterusagechart.Series["Flow Rate"].Points.AddXY(DateTime.Now.ToLongTimeString(), Convert.ToInt32(int.Parse(dataFlowSensor)))));
                    //waterusagechart.Refresh();
                }
            }
                catch(Exception ex)
            {
                MessageBox.Show("Exception: " + ex.Message);
            }
        }
        private void ProcessData2(object sender, EventArgs e)
        {
            try
            {
                serialDataIn2 = serialPort2.ReadLine();
                // Check if any of the index values is -1
                if (serialDataIn2.IndexOf("X") == -1 ||
                    serialDataIn2.IndexOf("W") == -1 ||
                    serialDataIn2.IndexOf("Y") == -1 ||
                    serialDataIn2.IndexOf("Z") == -1 ||
                    serialDataIn2.IndexOf("D") == -1 )
                {
                    // Skip processing the line
                    return;
                }
                indexOfpH = Convert.ToSByte(serialDataIn2.IndexOf("W"));
                indexOfNTU = Convert.ToSByte(serialDataIn2.IndexOf("X"));
                indexOfFI = Convert.ToSByte(serialDataIn2.IndexOf("Y"));
                indexOfFO = Convert.ToSByte(serialDataIn2.IndexOf("Z"));
                indexOfD = Convert.ToSByte(serialDataIn2.IndexOf("D"));

                //assign values to variable
                pHvalue = serialDataIn2.Substring(0, indexOfpH);
                NTUlevel = serialDataIn2.Substring(indexOfpH + 1, (indexOfNTU - indexOfpH) - 1);
                Flow1 = serialDataIn2.Substring(indexOfNTU + 1, (indexOfFI - indexOfNTU) - 1);
                Flow2 = serialDataIn2.Substring(indexOfFI + 1, (indexOfFO - indexOfFI) - 1);
                Difference = serialDataIn2.Substring(indexOfFO + 1, (indexOfD - indexOfFO) - 1);
                flowrate1.Text = Flow1;
                flowrate2.Text = Flow2;

                differenceText.Text = Difference;
                if(int.Parse(Difference)>1)
                {
                    LeakageText.Text = "There is leakage in the piping system";
                    WaterLeakagePic.Image = imageList2.Images[0];
                    
                    LeakageTimeBox.Text = DateTime.Now.ToLongTimeString();
                }
                else
                {
                    LeakageText.Text = "No leakage detected";
                    
                    WaterLeakagePic.Image = imageList2.Images[1];
                }
            }
            catch (Exception error)
            {
                MessageBox.Show(error.Message);
            }

        }
        private void ProcessData(object sender, EventArgs e)
        { 
            try
            {
                serialDataIn1 = serialPort1.ReadLine();
                // Check if any of the index values is -1
                if (serialDataIn1.IndexOf("F") == -1 ||
                    serialDataIn1.IndexOf("W") == -1 ||
                    serialDataIn1.IndexOf("L") == -1 ||
                    serialDataIn1.IndexOf("R") == -1 ||
                    serialDataIn1.IndexOf("A") == -1 ||
                    serialDataIn1.IndexOf("T") == -1)
                {
                    // Skip processing the line
                    return;
                }
                indexOfW = Convert.ToSByte(serialDataIn1.IndexOf("W"));
                indexOfF = Convert.ToSByte(serialDataIn1.IndexOf("F"));
                indexOfT = Convert.ToSByte(serialDataIn1.IndexOf("T"));
                indexOfL = Convert.ToSByte(serialDataIn1.IndexOf("L"));
                indexOfR = Convert.ToSByte(serialDataIn1.IndexOf("R"));
                indexOfA = Convert.ToSByte(serialDataIn1.IndexOf("A"));
                
                dataWaterLevelSensor1 = serialDataIn1.Substring(0, indexOfW);
                dataFlowSensor = serialDataIn1.Substring(indexOfW + 1,(indexOfF - indexOfW) - 1);
                dataTotalUsage = serialDataIn1.Substring(indexOfF + 1, (indexOfT - indexOfF) - 1);
                dataWaterLevelSensor2 = serialDataIn1.Substring(indexOfT + 1, (indexOfL - indexOfT) - 1);
                dataRainSensor = serialDataIn1.Substring(indexOfL + 1, (indexOfR - indexOfL) - 1);
                dataServermotor = serialDataIn1.Substring(indexOfR + 1, (indexOfA - indexOfR) - 1);

                //water storage level
                int waterlevel = int.Parse(dataWaterLevelSensor1);
                if (waterlevel<=420)
                {
                    WaterUsageCheckImg.SizeMode = PictureBoxSizeMode.Zoom;
                    WaterUsageCheckImg.Image = waterusagechecklist.Images[0];
                }
                else
                {
                    WaterUsageCheckImg.SizeMode = PictureBoxSizeMode.StretchImage;
                    WaterUsageCheckImg.Image = waterusagechecklist.Images[1];
                }
                //rain status
                int RainStatus = int.Parse(dataRainSensor);
                if (RainStatus == 1)
                {
                    RainStatusText.Text = "No Rain";
                }
                else
                {
                    RainStatusText.Text = "It's Raining";
                }
                // lid status
                int ServerMotorAngle = int.Parse(dataServermotor);
                if (ServerMotorAngle == 170)
                {
                    LidStatusText.Text = "Lid Closed";
                }
                else if (ServerMotorAngle == 80)
                {
                    LidStatusText.Text = "Lid Open";
                }
                int RainwaterLevel = int.Parse(dataWaterLevelSensor2);
                if(RainwaterLevel>300)
                {

                    WaterLevelBar1.Value = RainwaterLevel;
                    // Calculate the percentage
                    int percentage = (int)((float)RainwaterLevel / WaterLevelBar1.Maximum * 100);
                    // Set the text to show the percentage
                    WaterLevelBar1.Text = percentage + "%";
                }
                else
                {
                    WaterLevelBar1.Value = 0;
                    WaterLevelBar1.Text = "0%";
                }
                //total usage  
                waterusagetext.Text = dataTotalUsage;
                //int flowrate = int.Parse(dataFlowSensor);
                //MessageBox.Show("5");
                if (int.Parse(dataFlowSensor)>0)
                {
                    flowratetext.Text = dataFlowSensor;
                    Thread masterthread;
                    masterthread = new Thread(plotwaterusage);
                    masterthread.Start();
                }
            }
            catch (Exception error)
            {     
                MessageBox.Show(error.Message);
            }
        }
    }
}

Credits

Wei Pin Chow
1 project • 2 followers
NARENDRAN
20 projects • 22 followers
Daryl Chung Jia Hung
1 project • 1 follower
Chee Wen Jing
1 project • 0 followers
ChowSietYamDylanMingFoung
1 project • 0 followers
Samuel Chee
1 project • 0 followers
For APU

Comments