Delay of relay with millis

Hi, I hope I can get help finding the key to my problem here I'm doing some relay control Most of the time I have found out on youtube and read here. my english is limited so i use google translate. Now to my problem i have four relays that i am trying to control in the following way.

Two relays pull at start at a certain temp relay two turns off and relay three pulls to start a cooling fan and then I want relay one to drop after a 24 hours this was easy to solve with millis so far I have got everything working but I want relay 4 to draw when relay two releases and be drawn for ten minutes to then release.

Now I do not want anyone to just be kind and write the line because then I will not learn anything I want to understand what I am doing. :slight_smile:

How do I get the program to read where in the calculation it is and how do I get it from there to count 10 minutes and then break or should I let relay three somehow trigger a calculation?

Grateful for all the clues I can get Regards Ronny

Hi Ronny,

You define some more variables of type unsigned long to take additional snapshots of millis()

there is some kind of event that could be seen as "Now the ten minutes start"
if this happends (example you switch on a relay

unsigned long startTime;

startTime = millis()

and then do the standard if-condition with this variable startTime

if (currentTime - startTime  >= 10*60*1000) {
// the ten minutes are over take action

best regards Stefan

#include <OneWire.h>
#include <DallasTemperature.h>
#include <LiquidCrystal_I2C.h>
#define ONE_WIRE_BUS 2

OneWire oneWire(ONE_WIRE_BUS);

DallasTemperature sensors(&oneWire);

float Celsius = 0;
float SystemOff = 100;
float CoolingSystem = 60;
float powerOff = 90;

boolean Shutdown = true ;

#define RELAY1 4
#define RELAY2 7
#define RELAY3 8

LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x3F, 20, 4); // Change to (0x27,16,2) for 16x2 LCD.
void setup() {



// Initiate the LCD:

void loop() {

if (Celsius >= SystemOff)digitalWrite(RELAY1,LOW);
if (Celsius >= SystemOff)digitalWrite(RELAY2,LOW);
if (Celsius >= SystemOff)Shutdown = false;
if (Celsius >= CoolingSystem && Shutdown == true)digitalWrite(RELAY2,HIGH);
if (Celsius >= powerOff)digitalWrite(RELAY3,LOW);


Celsius = sensors.getTempCByIndex(0);

Serial.println(" C ");

lcd.setCursor(0, 0);
lcd.print("Temperature: ");
lcd.setCursor(2, 1);




This is my basic code that I have got to work

#define RELAY1 4
#define RELAY2 7
#define RELAY3 8
#define RELAY4 3
const long interval =20000;
const long interval_2 =10000;

unsigned long previousTime_1 = 0;
unsigned long previousTime_2 = 0;

void setup() {
// put your setup code here, to run once:


void loop() {
// put your main code here, to run repeatedly:
unsigned long currentMillis = millis ();

if (currentMillis - previousTime_1 >= interval)
previousTime_1 = currentMillis;

if (currentMillis - previousTime_1 >= interval_2)
previousTime_2 = currentMillis;

This is the code I’m playing with that I do not understand. The times are not right because I can not sit for 24 hours to see if it works :slight_smile: when I have made this work I will move it to the main code

Stefan thanks for the answer and here is my code hope you do not laugh too much now when I expose my ignorance but I learn it is not easy when I just did coded in Basic and pascal 35 years ago


no laughing about beeing a beginner. If you write a good joke it is different.

if you ahve any questions about the demo-codes just ask them.

explaining non-blocking-timing based on function millis():

delay() is blocking. As long as the delay is “delaying” nothing else of the code can be executed.
Now there is a technique of non-blocking timing.
The basic principle of non-blocking timing is fundamental different from using delay()
You have to understand the difference first and then look into the code.
otherwise you might try to “see” a “delay-analog-thing” in the millis()-code which it really isn’t
Trying to see a “delay-analog-thing” in millis() makes it hard to under stand millis()
Having understood the basic principle of non-blocking timing based on millis() makes it easy to understand.

imagine baking a frosted pizza
the cover says for preparation heat up oven to 200°C
then put pizza in.
Baking time 10 minutes

You are estimating heating up needs 3 minutes
You take a look onto your watch it is 13:02
You start reading the newspaper and from time to time looking onto your watch
watch 13:02 not yet time
watch 13:03 not yet time
watch 13:04 not yet time
watch 13:05 when did I start 13:02 OK 13:05 - 13:02 = 3 minutes time to put pizza into the oven

New basetime 13:05
watch 13:06 not yet time
watch 13:07 not yet time
watch 13:08 not yet time
watch 13:09 not yet time
watch 13:10 not yet time
watch 13:11 not yet time
watch 13:12 not yet time
watch 13:13 not yet time
watch 13:14 not yet time
watch 13:15 when did I start 13:05 OK 13:15 - 13:05 = 10 minutes time to eat pizza (yum yum)

You did a repeated comparing how much time has passed by
This is what non-blocking timing does

In the code looking at “How much time has passed by” is done

currentTime - startTime >= bakingTime

bakingTime is 10 minutes

13:06 - 13:05 = 1 minute >= bakingTime is false
13:07 - 13:05 = 2 minutes >= bakingTime is false

13:14 - 13:05 = 9 minutes >= bakingTime is false
13:15 - 13:05 = 10 minutes >= bakingTime is TRUE time for timed action!!

if (currentTime - previousTime >= period) {

it has to be coded exactly this way because in this way it manages the rollover from Max back to zero
of the function mills() automatically

and a demo-code

unsigned long currentMillis;

unsigned long Period = 1000; // after 1000 milliseconds a "period" has passed by
unsigned long LastTime_Period_Elapsed;

unsigned long SlowDownPeriod = 20;  // print a new character every 20 milliseconds so your eyes can follow the serial-output
unsigned long LastTime_SlowDownPeriod_Elapsed;

unsigned long DoubleCrossPeriod = 5 * SlowDownPeriod; // every 5th character shall be a #
unsigned long LastTime_DoubleCrossPeriod_Elapsed;

int NumberOfElapsedPeriods = 0;

const char dot = '.';
const char doubleCross = '#';
char CharToPrint;

void setup() {
  LastTime_Period_Elapsed = millis();
  LastTime_SlowDownPeriod_Elapsed = millis();
  LastTime_DoubleCrossPeriod_Elapsed = millis();

void loop() {  // main-loop is running at high speed
  currentMillis = millis(); // update timing-variable each time the main-loop starts again

  visualiseLooping();       // this function gets called with every run of the loop
                            // but contains logic to execute parts of its code 
                            // only if a certain amount of time has passed by

  // this part shows the same principle check if a certain amount of time has passed by
  // if yes execute commands inside the if-condition

  // the variable period contains the number of milliseconds
  // if THIS number of milliseconds has passed by the if-condition becomes true
  // ==> the code inside the if-condition is executed 
  if (currentMillis - LastTime_Period_Elapsed >= Period) { 
    LastTime_Period_Elapsed = currentMillis; // first thing to do is updating this variable 
    NumberOfElapsedPeriods ++;
    Serial.println(" seconds is over");

// every time a certain amount of time has passed by a character is printed to the serial monitor
// for your application you just put your code that shall be executed in such a timing-pattern 
// inside the if-condition that checks the time that has passed by

void visualiseLooping() {
  if (currentMillis - LastTime_DoubleCrossPeriod_Elapsed >= DoubleCrossPeriod) {
    LastTime_DoubleCrossPeriod_Elapsed = currentMillis;
    CharToPrint = doubleCross;
  else {
    CharToPrint = dot;

  if (currentMillis - LastTime_SlowDownPeriod_Elapsed >= SlowDownPeriod) {
    LastTime_SlowDownPeriod_Elapsed = currentMillis;

and here is a variant that I peronally prefer

unsigned long DemoTimerA = 0; // variables that are used to store timeInformation
unsigned long DemoTimerB = 0; 
unsigned long DemoTimerC = 0; 
unsigned long DoDelayTimer = 0; 

boolean TimePeriodIsOver (unsigned long &expireTime, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - expireTime >= TimePeriod )
    expireTime = currentMillis; // set new expireTime
    return true;                // more time than TimePeriod) has elapsed since last time if-condition was true
  else return false;            // not expired

void setup() 
  Serial.println("Program started activate Show timestamp in serial monitor");

void loop() 
  if (  TimePeriodIsOver(DemoTimerA,1000)  )
      Serial.println(" TimerA overDue");
  if (  TimePeriodIsOver(DemoTimerB,2000)  )
      Serial.println("                TimerB overDue");

  if (  TimePeriodIsOver(DemoTimerC,3000)  )
      Serial.println("                               TimerC overDue");

  if (  TimePeriodIsOver(DoDelayTimer,20000)  )
      Serial.println("every 20 seconds execute delay(3500)... to make all other timers overdue");

best regards Stefan