All About Water Systems (Ultrasonic + WaterFlow + Rain Sensors)

About This Project

Sometimes when I take a bath, the water stops. I checked that the water tank is empty and I have to call the water engineer to fix the water. I wish I could know the water problem earlier so when I know Cayenne I have an idea to make My Water System connected to my Mobile Device.

My current water system has 2 water tanks. The water from the underground flows into Blue Tanks using Grundfos pump, it’s filtered with sands and then go thru the Orange Tanks. Orange Tanks distribute the water using a small pump to home.

Sometimes the water from the ground is not flowing into the Blue Tank so I need the water flow sensor so we know when the Grundfos Pump starts flowing the water or not. If the water flows sensor slower than usually it means either I need to tweak the ‘pipe button’ or fix the underground pipe.

For the Orange Tank, sometimes I have to know if water flowing into Orange Tanks or not. If the water flows slower (or even stops) than usually, it means it’s time to clean up the water filter.

What’s Connected

  • Arduino Uno WIFI Developer Editions
  • Arduino Ethernet Shield W5500 (I know it’s ridiculous to have an ethernet over Uno WIFI, but because until now I cannot connect UNO Wifi to Cayenne, so I decided to buy W5500 Maybe someday I will remove the ethernet shield if Uno WIFI can connect to cayenne). You can check the thread here Please make support for Arudino Uno WiFi - #6 by kreggly
  • 2 Pcs Ultrasonic HC-SR04
  • 2 Pcs Water Flow Sensors
  • 2 Pcs Arduino Relay
  • 1 Contactor Schneider LC1D09M7 220V for Grundfos Pump
  • 1 MY2 AC 220V/240V - 5A DPDT Electromagnetic Power Control Relay OMRON
  • 1 Rain Sensors (This is Bonus because in the Future I want to develop the system if Rain comes I want to all windows closed automatically)

Arduino Pin

D2 water flow sensor blue tank *
D3 water flow sensor orange tank *
D4 ultrasonic blue tank - echo
D5 ultrasonic blue tank - trigger
D6 ultrasonic orange tank - echo
D7 ultrasonic orange tank - trigger
D8 relay blue tank
D9 relay orange tank
A0 rain sensor

*. Note: WARNING! You have to put the water flow sensor to pin D1 and D2 ONLY because the water flow sensor need to use interrupts and for Arduino UNO it’s only available on pin D1 and D2 (https://www.arduino.cc/en/Reference/AttachInterrupt)

Triggers & Alerts

  • If Orange Tank bellow 75% Turn on Blue Switch (Grundfos Pump)
  • If Orange Tanks above 95% Tun off Blue Switch
  • If Blue Tanks above 95% Turn off Blue Switch
  • If Orange Tanks bellow 50% Email Alert (Something problem in the water systems)

Scheduling

  • Turn on Blue Switch (Grundfos Pum) at 5 am - 6 am (the lowest electrical use in My Home)

Dashboard Screenshots

Web Dashboard:

Mobile Dashboard:

Trigger:

Schedule:

Water Flow for Blue Tanks in L/minute:

Rain Sensor in %:
0% means not raining at all
100% means full flood, please prepare your boat, because the flood is already reach the top of the roof T_T

Photos of the Project

(Take some pictures of your project living in the wild!)

Hardware:


Ultrasonic Placement:

Whole System with Tanks:

Code:

//Remove This Someday when UnoWifiDev can connect to Cayenne (Can't Wait That Time Comes ^^)
//#include <UnoWiFiDevEd.h>

//#define CAYENNE_DEBUG         // Uncomment to show debug messages
//#define CAYENNE_PRINT Serial  // Comment this out to disable prints and save space
#include <CayenneEthernetW5500.h>

// Cayenne authentication token. This should be obtained from the Cayenne Dashboard.
char token[] = "XXXXXXXX";

// Water Flow --> Only Works ON Pin 2 and Pin 3 for Uno, check https://www.arduino.cc/en/Reference/AttachInterrupt
#define VIRTUAL_PIN_WATERFLOW_1 V2
#define VIRTUAL_PIN_WATERFLOW_2 V3

int flowPin = 2;    //This is the input pin on the Arduino, Only Can be setup in Port 2 and 3
int flowPin2 = 3;
double flowRate;    //This is the value we intend to calculate. 
double flowRate2;
volatile int count;    //This integer needs to be set as volatile to ensure it updates correctly during the interrupt process.  
volatile int count2;
unsigned int getcount; //Getcount from count for flowRate
unsigned int getcount2;     

// Rain Sensor
float rain_level;
int rain_percentage;
int rain_bottom = 1022; 
int rain_top = 2;
int rain_distance =  rain_bottom - rain_top;
const int rainPin=A0; 
#define VIRTUAL_RAIN V10

// Ultrasonic
#define VIRTUAL_PIN_ULTRASONIC_1 V4
#define VIRTUAL_PIN_ULTRASONIC_PERCENT_1 V5
const int echoPin = 4; // Echo Pin 
const int trigPin = 5; // Trigger Pin 
float water_level;
float water_percentage;
int water_bottom = 42; 
int water_top = 32;
int water_distance = water_bottom - water_top;

#define VIRTUAL_PIN_ULTRASONIC_2 V6
#define VIRTUAL_PIN_ULTRASONIC_PERCENT_2 V7
const int echoPin2 = 6; // Echo Pin 
const int trigPin2 = 7; // Trigger Pin
float water_level2;
float water_percentage2;
int water_bottom2 = 75; 
int water_top2 = 19;
int water_distance2 = water_bottom2- water_top2;

void setup()
{
  Serial.begin(9600);
  Cayenne.begin(token);

  // Water Flow
  pinMode(flowPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(flowPin), Flow, RISING);  

  pinMode(flowPin2, INPUT);
  attachInterrupt(digitalPinToInterrupt(flowPin2), Flow2, RISING);  

  // Ultrasonic 
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);  

  pinMode(trigPin2, OUTPUT);
  pinMode(echoPin2, INPUT);   

  // Rain
  pinMode(rainPin, INPUT);
  pinMode(VIRTUAL_RAIN, OUTPUT);
}

void loop()
{
  Cayenne.run();

  // Water Flow
  getWaterFlow();
  
  // Ultrasonic
  getDistance();    

  // Rain
  rain_level = analogRead(rainPin);
  rain_percentage = 100 * ((rain_distance - rain_level)/rain_distance);
}


// Water Flow
void Flow()
{
   count++; //Every time this function is called, increment "count" by 1
}

void Flow2()
{
   count2++; //Every time this function is called, increment "count" by 1
}


static unsigned long lastSecond;
void getWaterFlow()
{
  if (micros() - lastSecond >= 1000000L)
  {
	lastSecond += 1000000;

	noInterrupts(); //Disable the interrupts on the Arduino
	  getcount = count;
	  getcount2 = count2;
	  count = 0;      // Reset the counter so we start counting from 0 again
	  count2 = 0;       
	interrupts();   //Enables interrupts on the Arduino

	//Start the math for Blue Tank
	flowRate = (getcount * 2.25);        //Take counted pulses in the last second and multiply by 2.25mL 
	flowRate = flowRate * 60;         //Convert seconds to minutes, giving you mL / Minute
	flowRate = flowRate / 1000;       //Convert mL to Liters, giving you Liters / Minute
  
	//Start the math for Orange Tank
	flowRate2 = (getcount2 * 2.25);        //Take counted pulses in the last second and multiply by 2.25mL 
	flowRate2 = flowRate2 * 60;         //Convert seconds to minutes, giving you mL / Minute
	flowRate2 = flowRate2 / 1000;       //Convert mL to Liters, giving you Liters / Minute
  
	//Serial.println(flowRate);         //Print the variable flowRate to Serial  
	Cayenne.virtualWrite(VIRTUAL_PIN_WATERFLOW_1, flowRate);
  
	//Serial.println(flowRate);         //Print the variable flowRate to Serial  
	Cayenne.virtualWrite(VIRTUAL_PIN_WATERFLOW_2, flowRate2);  
  }
}


// Ultrasonic 
float duration;
long HR_dist = 0; // Calculated Distance
unsigned long previousMillisUltraSonic = 0;

void getDistance(){ 
  unsigned long currentMillisUltraSonic = millis();
  
  // Check sensor data every 250 milliseconds
  if (currentMillisUltraSonic - previousMillisUltraSonic >= 5000) {  
	
	digitalWrite(trigPin, LOW); 
	delayMicroseconds(2); 
	digitalWrite(trigPin, HIGH);
	delayMicroseconds(10); 
	digitalWrite(trigPin, LOW);
	duration = pulseIn(echoPin, HIGH);
	duration = duration/58.2;
	Cayenne.virtualWrite(VIRTUAL_PIN_ULTRASONIC_1, duration);
	
	water_percentage = (100 * (water_top + water_distance - duration)) / water_distance;
	Cayenne.virtualWrite(VIRTUAL_PIN_ULTRASONIC_PERCENT_1, water_percentage);
	

	digitalWrite(trigPin2, LOW); 
	delayMicroseconds(2); 
	digitalWrite(trigPin2, HIGH);
	delayMicroseconds(10); 
	digitalWrite(trigPin2, LOW);
	duration = pulseIn(echoPin2, HIGH);
	duration = duration/58.2;
	Cayenne.virtualWrite(VIRTUAL_PIN_ULTRASONIC_2, duration);

	water_percentage2 = (100 * (water_top2 + water_distance2 - duration)) / water_distance2;
	Cayenne.virtualWrite(VIRTUAL_PIN_ULTRASONIC_PERCENT_2, water_percentage2);
	
	previousMillisUltraSonic = currentMillisUltraSonic;
  }
}

// Rain
CAYENNE_OUT(VIRTUAL_RAIN)
{
  Cayenne.virtualWrite(VIRTUAL_RAIN, rain_percentage);
}

Video

6 Likes

Great project! But I couldn’t understand what are the HC-SR04 for. They measure the current tank water level?

Yes. absolutely. You can see in the dashboard there is measure distance from ultrasonic. Each tank has 1 ultrasonic, because I put ultrasonic on the top of the tank, I need to convert it so it can be easily read with percentage instead of distance. I attached the widget percentage on the bottom of the dashboard so my wife can easily understand. :grinning:

Great!

1 Like

Dear @bestes or anyone in cayenne experts,

It’s been a while I haven’t check my device and when I checked it’s not working. I have tried followed the instructions on how to update the script for cayenne, create a new dashboard since the old one has been warned, but the dashboard is still not working. It is only shows static number. Even the simples one switch relay on / off is not working, can someone help what’s wrong with my code?

Here is my updated code:

#include <UnoWiFiDevEd.h>

//#include <UnoWiFiDevEd.h>

//#define CAYENNE_DEBUG         // Uncomment to show debug messages
//#define CAYENNE_PRINT Serial  // Comment this out to disable prints and save space
//#include <CayenneEthernetW5500.h>
#include <CayenneMQTTEthernetW5500.h>

// Cayenne authentication token. This should be obtained from the Cayenne Dashboard.
//char token[] = "xxx";

// Cayenne authentication info. This should be obtained from the Cayenne Dashboard.
char username[] = "xxxx";
char password[] = "xxxx";
char clientID[] = "xxxx";


// Water Flow --> Only Works ON Pin 2 and Pin 3 for Uno, check https://www.arduino.cc/en/Reference/AttachInterrupt
//#define VIRTUAL_PIN_WATERFLOW_1 V2
//#define VIRTUAL_PIN_WATERFLOW_2 V3

const int VIRTUAL_PIN_WATERFLOW_1 = 2;
const int VIRTUAL_PIN_WATERFLOW_2 = 3;

int flowPin = 2;    //This is the input pin on the Arduino, Only Can be setup in Port 2 and 3
int flowPin2 = 3;
double flowRate;    //This is the value we intend to calculate. 
double flowRate2;
volatile int count;    //This integer needs to be set as volatile to ensure it updates correctly during the interrupt process.  
volatile int count2;
unsigned int getcount; //Getcount from count for flowRate
unsigned int getcount2;     

// Rain Sensor
float rain_level;
int rain_percentage;
int rain_bottom = 319; 
int rain_top = 2;
int rain_distance =  rain_bottom - rain_top;
const int rainPin=A0; 
//#define VIRTUAL_RAIN V10
const int VIRTUAL_RAIN = 10;

// Ultrasonic for Blue Tank
#define VIRTUAL_PIN_ULTRASONIC_1 V4
#define VIRTUAL_PIN_ULTRASONIC_PERCENT_1 V5
const int echoPin = 4; // Echo Pin 
const int trigPin = 5; // Trigger Pin 
float water_level;
float water_percentage;
int water_bottom = 62; 
int water_top = 30;
int water_distance = water_bottom - water_top;

// Ultrasonic for Orange Tank
//#define VIRTUAL_PIN_ULTRASONIC_2 V6
//#define VIRTUAL_PIN_ULTRASONIC_PERCENT_2 V7
const int VIRTUAL_PIN_ULTRASONIC_2 = 6;
const int VIRTUAL_PIN_ULTRASONIC_PERCENT_2 = 7;


const int echoPin2 = 6; // Echo Pin 
const int trigPin2 = 7; // Trigger Pin
float water_level2;
float water_percentage2;
int water_bottom2 = 64; 
int water_top2 = 20;
int water_distance2 = water_bottom2- water_top2;

void setup()
{
  Serial.begin(9600);
  //Cayenne.begin(token);
  Cayenne.begin(username, password, clientID);

  // Water Flow
  pinMode(flowPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(flowPin), Flow, RISING);  

  pinMode(flowPin2, INPUT);
  attachInterrupt(digitalPinToInterrupt(flowPin2), Flow2, RISING);  

  // Ultrasonic 
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);  

  pinMode(trigPin2, OUTPUT);
  pinMode(echoPin2, INPUT);   

  // Rain
  pinMode(rainPin, INPUT);
  pinMode(VIRTUAL_RAIN, OUTPUT);
}

void loop()
{
  Cayenne.loop();

  // Water Flow
  getWaterFlow();
  
  // Ultrasonic
  getDistance();    

  // Rain
  rain_level = analogRead(rainPin);
  rain_percentage = 100 * ((rain_distance - rain_level)/rain_distance);
}


// Water Flow
void Flow()
{
   count++; //Every time this function is called, increment "count" by 1
}

void Flow2()
{
   count2++; //Every time this function is called, increment "count" by 1
}


static unsigned long lastSecond;
void getWaterFlow()
{
  if (micros() - lastSecond >= 1000000L)
  {
	lastSecond += 1000000;

	noInterrupts(); //Disable the interrupts on the Arduino
	  getcount = count;
	  getcount2 = count2;
	  count = 0;      // Reset the counter so we start counting from 0 again
	  count2 = 0;       
	interrupts();   //Enables interrupts on the Arduino

	//Start the math for Blue Tank
	flowRate = (getcount * 2.25);        //Take counted pulses in the last second and multiply by 2.25mL 
	flowRate = flowRate * 60;         //Convert seconds to minutes, giving you mL / Minute
	flowRate = flowRate / 1000;       //Convert mL to Liters, giving you Liters / Minute
  
	//Start the math for Orange Tank
	flowRate2 = (getcount2 * 2.25);        //Take counted pulses in the last second and multiply by 2.25mL 
	flowRate2 = flowRate2 * 60;         //Convert seconds to minutes, giving you mL / Minute
	flowRate2 = flowRate2 / 1000;       //Convert mL to Liters, giving you Liters / Minute
  
	//Serial.println(flowRate);         //Print the variable flowRate to Serial  
	Cayenne.virtualWrite(VIRTUAL_PIN_WATERFLOW_1, flowRate);
  
	//Serial.println(flowRate);         //Print the variable flowRate to Serial  
	Cayenne.virtualWrite(VIRTUAL_PIN_WATERFLOW_2, flowRate2);  
  }
}


// Ultrasonic 
float duration;
long HR_dist = 0; // Calculated Distance
unsigned long previousMillisUltraSonic = 0;

void getDistance(){ 
  unsigned long currentMillisUltraSonic = millis();
  
  // Check sensor data every 250 milliseconds
  if (currentMillisUltraSonic - previousMillisUltraSonic >= 10000) {  
	
	digitalWrite(trigPin, LOW); 
	delayMicroseconds(2); 
	digitalWrite(trigPin, HIGH);
	delayMicroseconds(10); 
	digitalWrite(trigPin, LOW);
	duration = pulseIn(echoPin, HIGH);
	duration = duration/58.2;
	Cayenne.virtualWrite(VIRTUAL_PIN_ULTRASONIC_1, duration);
	
	water_percentage = (100 * (water_top + water_distance - duration)) / water_distance;
	Cayenne.virtualWrite(VIRTUAL_PIN_ULTRASONIC_PERCENT_1, water_percentage);
	

	digitalWrite(trigPin2, LOW); 
	delayMicroseconds(2); 
	digitalWrite(trigPin2, HIGH);
	delayMicroseconds(10); 
	digitalWrite(trigPin2, LOW);
	duration = pulseIn(echoPin2, HIGH);
	duration = duration/58.2;
	Cayenne.virtualWrite(VIRTUAL_PIN_ULTRASONIC_2, duration);

	water_percentage2 = (100 * (water_top2 + water_distance2 - duration)) / water_distance2;
	Cayenne.virtualWrite(VIRTUAL_PIN_ULTRASONIC_PERCENT_2, water_percentage2);
	
	previousMillisUltraSonic = currentMillisUltraSonic;
  }
}

// Rain
//CAYENNE_OUT(VIRTUAL_RAIN)
void RainPercentage(int VIRTUAL_RAIN)
{
  Cayenne.virtualWrite(VIRTUAL_RAIN, rain_percentage);
}


// Default function for sending sensor data at intervals to Cayenne.
// You can also use functions for specific channels, e.g CAYENNE_OUT(1) for sending channel 1 data.
CAYENNE_OUT_DEFAULT()
{
  // Write data to Cayenne here. This example just sends the current uptime in milliseconds on virtual channel 0.
  Cayenne.virtualWrite(0, millis());
  // Some examples of other functions you can use to send data.
  //Cayenne.celsiusWrite(1, 22.0);
  //Cayenne.luxWrite(2, 700);
  //Cayenne.virtualWrite(3, 50, TYPE_PROXIMITY, UNIT_CENTIMETER);
}

// Default function for processing actuator commands from the Cayenne Dashboard.
// You can also use functions for specific channels, e.g CAYENNE_IN(1) for channel 1 commands.
CAYENNE_IN_DEFAULT()
{
  CAYENNE_LOG("Channel %u, value %s", request.channel, getValue.asString());
  //Process message here. If there is an error set an error message using getValue.setError(), e.g getValue.setError("Error message");
}

add #define CAYENNE_DEBUG adnd check the output in the serial moniotor.

Won’t ultrasonic sensor face problems due to evaporation of tank water in long run ? Won’t a system based on pressure be more viable ?

there are some industrial grade sensor which do the job if you want.

I did some research but, found sensors way too industrial. They were very high ranged. I want to monitor domestic tanks on roof. If u have any recommendations ?

there might be some sensor which can measure the tank level, but the best solution is to use a float switch to detect the water level when it reaches the top end.

@lemeraemail FYI, I have used this cheap ultrasonic sensor (buy from aliexpress) almost a year without problem before cayenne updated with the new systems and suddenly I cannot monitor anything from my dashboard.

I think the hardware itself still works, but I have to do much effort to check & update the script first before I can make it work again in my cayenne dashboard.

@willy add #define CAYENNE_DEBUG in your code and check the serial monitor output. This will help you find out what is the issue. Is it something related to cayenne code and connection or some error with sensor.

@shramik_salgaonkar I will do that later because I’m far away from the device at the right moment and I have been shut down the device since it’s not working, thanks for the advice anyway. I’ll let you know if I have done the debug.

can you PM me your Account email. we will also check at our end if the issue is related to the web push we did.

sure, i have sent you a message.

rain-water-sensor-liquid-level-sensor-module-depth-of-detection-arduino