Aquarium Water Top up with Pump Run Time Monitor

Hi,

First off a little introduction, I'm completely new to arduino but do have a pretty good electronics knowledge, I've purchased a couple of Arduino books and starter kits to learn, I've built a few of the basic projects and successfully written the code.

I'm now looking for some help with a project I've started making...

I have a ready made off the shelf Infra-Red based liquid level sensor, this is mounted inside an aquarium, when the water level in the aquarium drops (evaporation) the sensors output goes high (+5v)

and when the sensor is covered with a liquid its output goes low 0v (the output actually varies dependent on how much the sensor is covered, for me thou I'm happy to use it as a digital input).

So what I need to happen is when the water level drops it turns on a 240v pump to fill the aquarium
once the level is ok again, the pump stops.

So far I've built my circuit, written the code and all is well :slight_smile:

/*
Aquarium Automatic Top Off 
*/


const int PumpDelay=1000; // Delay time before pump starts to avoid stuttery operation
const int LevelSensor=12;  // Connect to Display Tank IR Level Sensor
const int WaterPump=2; // Water Pump via Relay 


#define LEDGreen 5  // Level OK LED
#define LEDRed 6   // Level Low LED

void setup() {

pinMode(LevelSensor, INPUT_PULLUP); // Display Tank IR Sensor
pinMode(WaterPump, OUTPUT); // Water Pump
pinMode(LEDGreen, OUTPUT);  // Level OK LED
pinMode(LEDRed, OUTPUT); // Level Low LED

digitalWrite(WaterPump, LOW); // Pump OFF by default

}

void loop() {

if(digitalRead(LevelSensor) == HIGH)
{
  delay(PumpDelay);
  digitalWrite(WaterPump, LOW);
  digitalWrite(LEDRed, LOW);
  digitalWrite(LEDGreen, HIGH);
}
else
{
  delay(PumpDelay);
  digitalWrite(WaterPump, HIGH);
  digitalWrite(LEDRed, HIGH);
  digitalWrite(LEDGreen, LOW);
}

}

The above code works perfectly however I wanted to add to this some way of monitoring how long the pump has been running for, (in case the level senor fails) and if the pump run time exceeds a predetermined time threshold then it will shut off the pump, turn on an error led and halt the loop until a reset button is pushed.

I tried to achieve this with the code below and was so excited when it compiled thinking I've cracked it, that was until I physically wired it up and realized it doesn't work.

With the sensor placed in water it boots up and the green led comes on as expected, i take the sensor out of water and the red led comes on as expected, after that it just halts and goes no further...

/*
Aquarium Automatic Top Off - With Pump Run Monitor, IF Pump Runs for more than preset time then there is a possible issue with level
sensor so turn off pump and turn on Error LED and wait for Reset button to be pushed to restart the loop 
*/
const int PUMPMAXRUNTIME=5000; // Set Max Time Pump Runs befor Time Out Interlock Occurs 

int LevelSensor=2;  // Connect to Display Tank IR Level Sensor

int WaterPump=4; // Water Pump via Relay 


int LEDGreen=5;  // Level OK LED
int LEDRed=6;   // Level Low LED
int LEDError=7;  // Pump has run too long via "PumpMAXRunTime" and possible sensor fault LED


int PumpDelay=1000; // Delay time before pump starts to avoid stuttery opeation

long startTime; // for Pump run Time Calculation (millis curent time)
long duration;  // for Pump run Time Calculation (run time duration minus millis current time)


void setup() {

pinMode(LevelSensor, INPUT); // Display Tank IR Sensor
pinMode(WaterPump, OUTPUT); // Water Pump
pinMode(LEDGreen, OUTPUT);  // Level OK LED
pinMode(LEDRed, OUTPUT); // Level Low LED
pinMode(LEDError, OUTPUT); // Pump has run too long and possible ensor fault LED

digitalWrite(WaterPump, LOW); // Pump OFF by default


}

void loop() {

if(digitalRead(LevelSensor) == LOW)
{
  delay(PumpDelay);
  digitalWrite(WaterPump, HIGH);
  digitalWrite(LEDRed, HIGH);
  digitalWrite(LEDGreen, LOW);
}
else
{
  delay(PumpDelay);
  digitalWrite(WaterPump, LOW);
  digitalWrite(LEDRed, LOW);
  digitalWrite(LEDGreen, HIGH);
}


if(digitalRead(WaterPump) == HIGH)
{
  startTime = millis();
  while(digitalRead(WaterPump) == HIGH);
  long duration = millis() - startTime;
}

if(digitalRead(duration) >= PUMPMAXRUNTIME)  // If pump runs for more than this time turn on Error LED & Halt Program until Reset)
 {
   digitalWrite(WaterPump, LOW);
   digitalWrite(LEDError, HIGH);
   digitalWrite(LEDGreen, LOW);
   digitalWrite(LEDRed, LOW);
   exit(0);
 }
}

Any suggestions would be greatly appreciated, I guess I need to fully understand the millis function which I kind of do but struggling with the: start timer, if timer over runs, then stop, if not then carry on as normal.

In my world / understanding I'm basically trying to create a delay on timer

I've seen a few examples where others include librarys although id rather learn how to do it properly myself.

liteworx:
Hi,

I've written the code below to work with an infrared based water level sensor:

[LEVEL SENSOR](http://" https://www.robotshop.com/uk/gravity-liquid-level-sensor-fs-ir02.html?gclid=EAIaIQobChMI8_WWnJXu3gIV7xXTCh08Xwn1EAQYAiABEgKvvvD_BwE")

/*

Aquarium Automatic Top Off
*/

const int PumpDelay=1000; // Delay time before pump starts to avoid stuttery operation
const int LevelSensor=12;  // Connect to Display Tank IR Level Sensor
const int WaterPump=2; // Water Pump via Relay

#define LEDGreen 5  // Level OK LED
#define LEDRed 6   // Level Low LED

void setup() {

pinMode(LevelSensor, INPUT_PULLUP); // Display Tank IR Sensor
pinMode(WaterPump, OUTPUT); // Water Pump
pinMode(LEDGreen, OUTPUT);  // Level OK LED
pinMode(LEDRed, OUTPUT); // Level Low LED

digitalWrite(WaterPump, LOW); // Pump OFF by default

}

void loop() {

if(digitalRead(LevelSensor) == HIGH)
{
  delay(PumpDelay);
  digitalWrite(WaterPump, LOW);
  digitalWrite(LEDRed, LOW);
  digitalWrite(LEDGreen, HIGH);
}
else
{
  delay(PumpDelay);
  digitalWrite(WaterPump, HIGH);
  digitalWrite(LEDRed, HIGH);
  digitalWrite(LEDGreen, LOW);
}

}




The above code works perfectly however I wanted to add to this some way of monitoring how long the pump has been running for, (in case the level senor fails) and if the pump run time exceeds a predetermined time threshold then it will shut off the pump, turn on an error led and halt the loop until a reset button is pushed. 

I tried to achieve this with the code below and was so excited when it compiled thinking I've cracked it, that was until I physically wired it up and realized it doesn't work.

With the sensor placed in water it boots up and the green led comes on as expected, i take the sensor out of water and the red led comes on as expected, after that it just halts and goes no further... 



/*
Aquarium Automatic Top Off - With Pump Run Monitor, IF Pump Runs for more than preset time then there is a possible issue with level
sensor so turn off pump and turn on Error LED and wait for Reset button to be pushed to restart the loop
*/
const int PUMPMAXRUNTIME=5000; // Set Max Time Pump Runs befor Time Out Interlock Occurs

int LevelSensor=2;  // Connect to Display Tank IR Level Sensor

int WaterPump=4; // Water Pump via Relay

int LEDGreen=5;  // Level OK LED
int LEDRed=6;   // Level Low LED
int LEDError=7;  // Pump has run too long via "PumpMAXRunTime" and possible sensor fault LED

int PumpDelay=1000; // Delay time before pump starts to avoid stuttery opeation

long startTime; // for Pump run Time Calculation (millis curent time)
long duration;  // for Pump run Time Calculation (run time duration minus millis current time)

void setup() {

pinMode(LevelSensor, INPUT); // Display Tank IR Sensor
pinMode(WaterPump, OUTPUT); // Water Pump
pinMode(LEDGreen, OUTPUT);  // Level OK LED
pinMode(LEDRed, OUTPUT); // Level Low LED
pinMode(LEDError, OUTPUT); // Pump has run too long and possible ensor fault LED

digitalWrite(WaterPump, LOW); // Pump OFF by default

}

void loop() {

if(digitalRead(LevelSensor) == LOW)
{
  delay(PumpDelay);
  digitalWrite(WaterPump, HIGH);
  digitalWrite(LEDRed, HIGH);
  digitalWrite(LEDGreen, LOW);
}
else
{
  delay(PumpDelay);
  digitalWrite(WaterPump, LOW);
  digitalWrite(LEDRed, LOW);
  digitalWrite(LEDGreen, HIGH);
}

if(digitalRead(WaterPump) == HIGH)
{
  startTime = millis();
  while(digitalRead(WaterPump) == HIGH);
  long duration = millis() - startTime;
}

if(digitalRead(duration) >= PUMPMAXRUNTIME)  // If pump runs for more than this time turn on Error LED & Halt Program until Reset)
 {
   digitalWrite(WaterPump, LOW);
   digitalWrite(LEDError, HIGH);
   digitalWrite(LEDGreen, LOW);
   digitalWrite(LEDRed, LOW);
   exit(0);
 }
}



I expect there's some obvious errors in my code as i'm totally new to this but if anyone could point me in the right direction it would be appreciated

first off, welcome.
when you create your posts, there are some handy tools to make you post easier to read.
you can find more in How To Use This Forum
it can be found at the top of every forum as a sticky post.
the bit about code tags, the part that puts your code into boxes to they are more readable.
is item #7
when you preview your post (bottom right option)
you get two windows, the view and then the edit.
on the edit you have a couple links of a chain. that is how to post clickable links.

Many thanks for "tidying up" my post, in future i'll check and follow the rules before posting :slight_smile:

If anyone has any suggestions in how I get my project to work it would be great.

Getting to the point that I may just add another float switch to monitor if the water level goes to high,
that'd be a whole lot easier than trying to get my head around "timing" :confused:

it seems the only change you made was in the attempt at timing.

if(digitalRead(WaterPump) == HIGH)
 {
 startTime = millis();
 while(digitalRead(WaterPump) == HIGH);
 long duration = millis() - startTime;
 }
 
 if(digitalRead(duration) >= PUMPMAXRUNTIME) // If pump runs for more than this time turn on Error LED & Halt Program until Reset)
 {
 digitalWrite(WaterPump, LOW);
 digitalWrite(LEDError, HIGH);
 digitalWrite(LEDGreen, LOW);
 digitalWrite(LEDRed, LOW);
 exit(0);
 }
 }

for timing, you should not try to create a second event, but rather use the first event.
the bit of code is called - blink without delay. (google blink without delay) aka BWD
this will need you to create a few flags. It also seems in BWD you are always doing the thing you do not care about.
an odd sort of way of doing things.

next =

You want to know of the pump has started, but really need to know if the last time through the loop is it was not running. This was the error. You re-set on every loop as long as the pump was running
first, At the end of loop(), you need to fix the pump running status

pump_running = WaterPump
} // END OF LOOP

this only gets changed at the end of the loop, or in an if() statement as needed.

now to look at how to make this work.

if WaterPump == HIGH // for this loop it is running
time_start= millis() // millis being the system clock and them is a long in your variable declare

But, if you look at that, it will always re-set time_start on every loop because the pump is running.
We have to stop that from being reset.

if pump_running == LOW // last loop it was not running
if WaterPump == HIGH // this loop it is running
time_start= millis() // millis is the system clock . Declare a long in your variable declaration

see how the pump_running was low, before and only if it was low, can it enter the if() section
this time the pump is running, so you set the time.

Now, on to the timer part
… but it too is at risk from being changed
so...

if (WaterPump == HIGH)
duration = millis() - then

...you can put it behind a bit that stops calculation when the pump is turned off.

now, if pump_running was HIGH on the last loop and is now LOW on this loop, then you want to add the running time to your total
again, you want to add, but you do not, you look to see if the change from HIGH to LOW occurred.

if (WaterPump== LOW)
if (pump_running == HIGH)
total_time = total_time + duration

this should tell you the total milliseconds, but not the last run time.
The last run time will be wiped every time the pump starts.

serialPrint (“last run time was “)
serialPrintln (duration)
serialPrint (“total run time = “)
serialPrintln (total_time)

the next problem is to get this to read minutes or hours and minutes.

Many thanks Dave, i'm going to try and get my head around this and re-write the code to suit :slight_smile:

I just gave you some clues.
you need to read up on Blink Without Delay a bit.

once you can mimic the instructions, you should be able to get things working.

play around with BWD and you can begin to understand the basic concept.

once you have a true understanding, it becomes a tool and like any tool, you can use it in many different ways.
I am sure I am not the only person to ever use a lighter or hammer to remove a bottle top.