Pump running duration using millis

Hello everyone! I am new to arduino and decided to replace delay with millis() but got stuck for a few days trying to solve this problem, so basically I need to replace this part

digitalWrite(pump, HIGH);
delay(5000);
digitalWrite(pump, LOW);

with millis()

I think the problem is that I use this delay not in a loop setup(), but in a separate loop, and I can’t get my head around how to change this problem, please see the code below. Your help will be much appreciated.

// set all moisture sensors PIN ID

int moisture1 = A4;

int moisture2 = A5;

int moisture3 = A6;

int moisture4 = A7;

// set water relays

int relay1 = 2;

int relay2 = 3;

int relay3 = 4;

int relay4 = 5;

//init valve nr

int x = 0;

// set water pump

int pump = 6;


// set Low level float and Low level LED

int FloatSensor=8;
boolean FloatSensorState = false;
int LowLed=7;

/* TIMER */
#include <SimpleTimer.h>
SimpleTimer timer;

//Water correct plant function

void waterPlant(int x) {


//Checking Low level float sensor state
FloatSensorState = digitalRead(FloatSensor); 

if (FloatSensorState == HIGH){

  
Serial.println( "TANK LEVEL - OK pump may run" );
digitalWrite(LowLed, LOW);
  

Serial.print("Moisture LOW ");

Serial.print(x-1);


Serial.print(" Opening solenoid: ");

Serial.print(x-1);



//Open valve x ==> x will contain value of correct relay[1-4]

digitalWrite(x, HIGH);


//We wait 0.5 seconds before opening pump so we are sure valve is open. This will prevent the pump from pushing water to a closed valve and risking the tubes to leak or wose, break loose.


delay(500);


digitalWrite(pump, HIGH);
delay(5000); //This is part which i need to change to millis();
digitalWrite(pump, LOW);



delay(500);

digitalWrite(x, LOW);

//Make sure all valves are closed again.

closeAll();

}

else {

   Serial.println("LOW LEVEL - Pump is disabled");
   digitalWrite(LowLed, HIGH);
   
   digitalWrite(pump, LOW);

  }

}

void setup() {

  Serial.begin(9600);


// declare relay as output

pinMode(relay1, OUTPUT);

pinMode(relay2, OUTPUT);

pinMode(relay3, OUTPUT);

pinMode(relay4, OUTPUT);

// declare pump as output

pinMode(pump, OUTPUT);

pinMode(FloatSensor, INPUT_PULLUP); //Arduino Internal Resistor 10K

// declare the Low Level ledPin as an OUTPUT:
pinMode (LowLed, OUTPUT); 

}


void loop() {



//Go to moisture checkup function to se if plants need watering
timer.run();
checkMoisture();


// wait 5 sec and repeat the process

Serial.print("wait 5 sec \n ++++++++++++++ END +++++++++++++ \n");



  
  Serial.println("Wait 5 and repeat process");
  delay(5000);
}


// check which plant need water

// and open the switch for that specific plant

void checkMoisture() {

Serial.println("Checking moisture level");

//print sensor values.
PrintSerialMoisture();
 
if (analogRead(moisture1) >= 550) {


waterPlant(relay1);

}

else {

  Serial.println("Moisture in Pot 1 OK");  

  }

if (analogRead(moisture2) >= 550) {

waterPlant(relay2);

}

else {
  
  Serial.println("Moisture in Pot 2 OK");
  
  }


if (analogRead(moisture3) >= 550) {

waterPlant(relay3);

}

else {
  
  Serial.println("Moisture in Pot 3 OK");
  
  }

if (analogRead(moisture4) >= 550) {
  

waterPlant(relay4);

}

else {
  
  Serial.println("Moisture in Pot 4 OK");  
  
  }

delay(2000);

if (analogRead(moisture1) <= 450 || analogRead(moisture2) <= 450 || analogRead(moisture3) <= 450 || analogRead(moisture4) <= 450) {

checkMoisture();


}

else {

closeAll();

}

}

// turn pump & valves off just to be sure.

void closeAll() {

Serial.print(" Stopping pump + Closing valves!");

digitalWrite(pump, LOW);

digitalWrite(relay1, LOW);

digitalWrite(relay2, LOW);

digitalWrite(relay3, LOW);

digitalWrite(relay4, LOW);


}


void PrintSerialMoisture() {

Serial.print(F("Sensor 1: "));

Serial.println(analogRead(moisture1));

Serial.print(F("Sensor 2: "));

Serial.println(analogRead(moisture2));

Serial.print(F("Sensor 3: "));

Serial.println(analogRead(moisture3));

Serial.print(F("Sensor 4: "));

Serial.println(analogRead(moisture4));
}

If you don’t want the program to do anything else during this time, then delay is fine .

Here’s are interesting guide:

https://www.norwegiancreations.com/2017/09/arduino-tutorial-using-millis-instead-of-delay/

What kind

of editor are

you

using

that causes

all the extra

newlines?

Also, indentation is all over the place. Press Ctrl+T to let the IDE help you. Makes debugging sooooo much easier.

Couple of things to use millis() to do the timing:

  • The rest of the code needs to be non-blocking, all of it.
  • The starting and stopping become two completely separated tests. Start based on (the change of an) input (or whatever you want it to start). Stopping only based on the time (millis() - previousMillis >= interval) and the fact it is indeed running.
  • You need to preform the checks often. Aka, the checking to see if the motor needs to stop needs to be done often (aka be called ever loop())

And and extra tip. Once you start numbering variable => arrays :wink:

Have a look at how millis() is used to manage timing without blocking in Several Things at a Time.

And see Using millis() for timing. A beginners guide if you need more explanation.

...R

Thanks for replies guys,
in fact I want to add Blynk for my project later on, and as we know blynk doesn't like any long delays at all, so for instance if I change pump run time from Blynk app(sorry may be I need to post those questions in Blynk forum, however long delay problem may be common for all internet connections) and I I make pump to run lets say longer than 10-15 sec, Blynk app just times out and looses connection to the Arduino. So using any kind of timer is probably a good idea I thought..

I will adjust/clean up my code today as per your advises and post it here, (Thank you all for your advises, I am quite new to Arduino IDE so my code is a bit messy)

That does not only apply to internet things. It applies to ALL cases you want to pseudo do multiple things at the same time. Basic rule, let loop() loop as often as possible. Chapter number two (after chapter one, "Blink") of every Arduino tutorial should be called "And now NEVER use delay again!".

Ok, now after reading carefully all the above advises modified my code to the non blocking(hided all variables in plantbotVar.h, but they are just ints), removed delays in loop and it all works fine apart of that timer.setTimeout(5000, pumpOn),still not doing its job (I decided to use simpleTimer library for now before I get full understanding of millis();

So pump is not starting at all, however void pumpOn() clearly states digitalWrite(pump, HIGH);

…probably I am missing something very trivial… :confused:

#include "plantbotcred.h"
#include "plantbotVar.h"
#include <SimpleTimer.h>
SimpleTimer timer;


// Interval is how long we wait


//Water correct plant function
void waterPlant(int x) {

  //Checking Low level float sensor state
  FloatSensorState = digitalRead(FloatSensor);

  if (FloatSensorState == HIGH) {

    Serial.println( "TANK LEVEL - OK pump may run" );
    digitalWrite(LowLed, LOW);

    Serial.print("Moisture LOW ");

    Serial.print(x - 1);

    Serial.print(" Opening solenoid: ");

    Serial.print(x - 1);

    //Open valve x ==> x will contain value of correct relay[1-4]

    digitalWrite(x, HIGH);


    //We wait 0.5 seconds before opening pump so we are sure valve is open. This will prevent the pump from pushing water to a closed valve and risking the tubes to leak or wose, break loose.


    delay(500);

//The code below is the one which I try to substitude with millis or simpleTimer   
//    digitalWrite(pump, HIGH);   ///////////////////////////
//    delay(3000);                //Run pump for 3 seconds///
//    digitalWrite(pump, HIGH);  //////////////////////////

    timer.setTimeout(5000, pumpOn);//This doesn't work, timer just ignoring it  ???


    delay(500);

    digitalWrite(x, LOW);

    //Make sure all valves are closed again.

    closeAll();

  }

  else {

    Serial.println("LOW LEVEL - Pump is disabled");
    digitalWrite(LowLed, HIGH);

    digitalWrite(pump, LOW);

  }

}

///Turning pump on
void pumpOn(){
  
  digitalWrite(pump, HIGH);
  
  }

void setup() {

  Serial.begin(9600);

  // declare relay as output

  pinMode(relay1, OUTPUT);

  pinMode(relay2, OUTPUT);

  pinMode(relay3, OUTPUT);

  pinMode(relay4, OUTPUT);

  // declare pump as output
  pinMode(pump, OUTPUT);
  
  pinMode(FloatSensor, INPUT_PULLUP); //Arduino Internal Resistor 10K

  // declare the Low Level ledPin as an OUTPUT:
  pinMode (LowLed, OUTPUT);

  timer.setInterval(1000, checkMoisture);

  
}

void loop() {


 timer.run();


  //checkManualstatus();   //Add manual button watering
}

// check which plant need water

// and open the solenoid for that specific plant

void checkMoisture() {

  Serial.println("Checking moisture level");

  //print sensor values.
  PrintSerialMoisture();

  if (analogRead(moisture1) >= 550) {
    waterPlant(relay1);

  }

  else {

    Serial.println("Moisture in Pot 1 OK");

  }

  if (analogRead(moisture2) >= 550) {
    waterPlant(relay2);

  }

  else {
    Serial.println("Moisture in Pot 2 OK");
  }


  if (analogRead(moisture3) >= 550) {
    waterPlant(relay3);

  }

  else {
    Serial.println("Moisture in Pot 3 OK");
  }
  
  if (analogRead(moisture4) >= 550) {
    waterPlant(relay4);
  }
  else {
    Serial.println("Moisture in Pot 4 OK");
  }

  delay(2000);

  if (analogRead(moisture1) <= 450 || analogRead(moisture2) <= 450 || analogRead(moisture3) <= 450 || analogRead(moisture4) <= 450) {

    checkMoisture();   
  }

  else {
    closeAll();
  }

}

// turn pump & valves off just to be sure.

void closeAll() {

  Serial.print(" Stopping pump + Closing valves!");
  digitalWrite(pump, LOW);
  digitalWrite(relay1, LOW);
  digitalWrite(relay2, LOW);
  digitalWrite(relay3, LOW);
  digitalWrite(relay4, LOW);

}


void PrintSerialMoisture() {

  Serial.print(F("Sensor 1: "));

  Serial.println(analogRead(moisture1));

  Serial.print(F("Sensor 2: "));

  Serial.println(analogRead(moisture2));

  Serial.print(F("Sensor 3: "));

  Serial.println(analogRead(moisture3));

  Serial.print(F("Sensor 4: "));

  Serial.println(analogRead(moisture4));
}

septillion:
That does not only apply to internet things. It applies to ALL cases you want to pseudo do multiple things at the same time. Basic rule, let loop() loop as often as possible. Chapter number two (after chapter one, "Blink") of every Arduino tutorial should be called "And now NEVER use delay again!".

totally agree with you regarding delays! unfortunately it very often it is omitted and most tutorials show you examples with delays(), like in my case, a very simple thing, need to run pump for certain amount of time using millis or any other library based on millis, but just can't find info on the internet how to do that

millis timer stripped down to the basics:

unsigned long myRunningTimer;
unsigned long myTimerInterval = 3000; //(3sec)

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

}

void loop() {
 if(millis() - myRunningTimer >= myTimerInterval){
  Serial.println("Resetting Timer");
  myRunningTimer = millis();
 }

}

Hope this helps.

JMeller:
millis timer stripped down to the basics:

unsigned long myRunningTimer;

unsigned long myTimerInterval = 3000; //(3sec)

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

}

void loop() {
if(millis() - myRunningTimer >= myTimerInterval){
  Serial.println(“Resetting Timer”);
  myRunningTimer = millis();
}

}




Hope this helps.

Thank you for your help, just tried to implement your code in my project (Marked your recommendation as //recommended by JMELLER from arduino forum, but unfortunately still no joy, pump is cutting in but only for an instance and changes in unsigned long myTimerInterval = 3000; are not affecting the code at all…
just thinking is this because millis() are not running in the loop, but then the code structure is such that pumping process void has to stay in a separate void…

I think the problem is in not in the millis() but somewhere in the general code layout…

// set all moisture sensors PIN ID

int moisture1 = A4;
int moisture2 = A5;
int moisture3 = A6;
int moisture4 = A7;

// set water relays
int relay1 = 2;
int relay2 = 3;
int relay3 = 4;
int relay4 = 5;

//init valve nr

int x = 0;

// set water pump

int pump = 6;


// set Low level float and Low level LED
int FloatSensor = 8;
boolean FloatSensorState = false;
int LowLed = 7;


unsigned long myRunningTimer;
unsigned long myTimerInterval = 3000; //(3sec) // Interval is how long we wait



//Water correct plant function
void waterPlant(int x) {

  //Checking Low level float sensor state
  FloatSensorState = digitalRead(FloatSensor);

  if (FloatSensorState == HIGH) {

    Serial.println( "TANK LEVEL - OK pump may run" );
    digitalWrite(LowLed, LOW);

    Serial.print("Moisture LOW ");

    Serial.print(x - 1);

    Serial.print(" Opening solenoid: ");

    Serial.print(x - 1);

    //Open valve x ==> x will contain value of correct relay[1-4]

    digitalWrite(x, HIGH);


    //We wait 0.5 seconds before opening pump so we are sure valve is open. This will prevent the pump from pushing water to a closed valve and risking the tubes to leak or wose, break loose.


    delay(500);

    //The code below is the one which I try to substitude with millis or simpleTimer
    //    digitalWrite(pump, HIGH);   ///////////////////////////
    //    delay(3000);                //Run pump for 3 seconds///
    //    digitalWrite(pump, HIGH);  //////////////////////////



//The code extract below is implementation recommended by JMELLER from arduino forum

    pumpOn();

    if (millis() - myRunningTimer >= myTimerInterval) {

      Serial.println("Resetting Timer");
      myRunningTimer = millis();

    }
    
    delay(500);

    digitalWrite(x, LOW);
////////////////////////////////////////////////////////////


    //Make sure all valves are closed again.
    closeAll();

  }

  else {

    Serial.println("LOW LEVEL - Pump is disabled");
    digitalWrite(LowLed, HIGH);

    digitalWrite(pump, LOW);

  }

}

///Turning pump on
void pumpOn() {

  digitalWrite(pump, HIGH);

}

void setup() {

  Serial.begin(9600);

  // declare relay as output

  pinMode(relay1, OUTPUT);

  pinMode(relay2, OUTPUT);

  pinMode(relay3, OUTPUT);

  pinMode(relay4, OUTPUT);

  // declare pump as output
  pinMode(pump, OUTPUT);

  pinMode(FloatSensor, INPUT_PULLUP); //Arduino Internal Resistor 10K

  // declare the Low Level ledPin as an OUTPUT:
  pinMode (LowLed, OUTPUT);

}

void loop() {

  checkMoisture();

}

// check which plant need water
// and open the solenoid for that specific plant
void checkMoisture() {

  Serial.println("Checking moisture level");

  //print sensor values.
  PrintSerialMoisture();

  if (analogRead(moisture1) >= 550) {
    waterPlant(relay1);
  }

  else {
    Serial.println("Moisture in Pot 1 OK");
  }

  if (analogRead(moisture2) >= 550) {
    waterPlant(relay2);
  }

  else {
    Serial.println("Moisture in Pot 2 OK");
  }

  if (analogRead(moisture3) >= 550) {
    waterPlant(relay3);

  }

  else {
    Serial.println("Moisture in Pot 3 OK");
  }

  if (analogRead(moisture4) >= 550) {
    waterPlant(relay4);
  }
  else {
    Serial.println("Moisture in Pot 4 OK");
  }

  delay(2000);

  if (analogRead(moisture1) <= 450 || analogRead(moisture2) <= 450 || analogRead(moisture3) <= 450 || analogRead(moisture4) <= 450) {

    checkMoisture();
  }

  else {
    closeAll();
  }

}

// turn pump & valves off just to be sure.

void closeAll() {

  Serial.print(" Stopping pump + Closing valves!");
  digitalWrite(pump, LOW);
  digitalWrite(relay1, LOW);
  digitalWrite(relay2, LOW);
  digitalWrite(relay3, LOW);
  digitalWrite(relay4, LOW);
}


void PrintSerialMoisture() {

  Serial.print(F("Sensor 1: "));

  Serial.println(analogRead(moisture1));

  Serial.print(F("Sensor 2: "));

  Serial.println(analogRead(moisture2));

  Serial.print(F("Sensor 3: "));

  Serial.println(analogRead(moisture3));

  Serial.print(F("Sensor 4: "));

  Serial.println(analogRead(moisture4));
}

The concept of millis() isn’t that hard. You know how to read a clock? Can you also note when it’s 5 minutes from now? If you can, congratulations, you know how to use millis() :wink:

millis() is just a clock (not an alarm clock though!). Only a clock that started at an arbitrary moment and in milliseconds. But does that matter? With a that does not run on time you can time 5 minutes as well. And you just have to remember 5 minutes is 5 x 60 x 1000 = 300000ms

Libraries can help a lot but I doubt it makes things simpler here.

Thing is, I still see a lot of delay()'s in your latest code. Same for numbered variables :wink:

[edit]You posted inbtween. Just act as if this post came before it :confused:

I wonder if you are assuming that the function waterPlant() operates for some time until the plant is watered? It won't. It will just run for 500 millisecs and then turn the valves off.

IMHO you need to rethink the overall logic. If it was my project I think my code in loop() would be something like this

void loop() {
  checkWetness();
  operateValves();
  operatePump();
}

The checkWetness() function would just read all the sensors and save the data
The operateValves() function would turn on or off the relevant valves depending on the wetness
The operatePump() function would turn on the pump if any valve is open - otherwise turn it off

More generally ...
Do not use delay() when you are using millis() for timing.
When using millis() for timing the time needs to be checked regularly - every time loop() repeats
When using more than one analog input it is a good idea to discard the first reading after a change of input pin - for example

adcVal[n] = analogRead(adcPin[n]); // this value is ignored
adcVal[n] = analogRead(adcPin[n]);

...R

Robin2 beat me to it... +1
When creating/troubleshooting code, break it down into calling functions:

unsigned long myRunningTimer;
unsigned long myTimerInterval = 3000; //(3sec)

void setup() {
  Serial.begin(9600);
}

void loop() {
doThis (millis()); // call function with the value of millis()
}

void doThis(unsigned long myVariable){ // myVariable = value of... in this instance= millis()
 if(myVariable - myRunningTimer >= myTimerInterval){
  Serial.println("Resetting Timer");
  myRunningTimer = myVariable;
 }
}

Edit: Function explanation.

Thank you guys! Honestly, this brilliant idea which you wrote just now, got into my mind 5 minutes ago:) basically void loop() is the one which is counting millis by going in circles :), so no loop = millis don't count and nothing works! Like anything else amazing thing are so simple! I will try to reconfigure the code to your recomendations!