Using millis to add 1 minute relay delay

First of all, I’m doing this to prevent my solenoid from turning on and off too often and burning out.

I’m making a thermostat that kicks on a solenoid+relay when the realTemperature goes below my setTemperature and I’m having some trouble coming up with the right code to give the solenoid a one minute delay after it hits the SetTemperature before coming back on again. For some reason, this code doesn’t seem to be working… Any thoughts?

void relaySwitcher(int realTemperature, int tempSetting, int relay){   
  unsigned long currentMillis=millis();
  unsigned long interval=60000;
  unsigned long previousMillis = 0;
  if (currentMillis - previousMillis >= interval){
    previousMillis = currentMillis;
      if (actualValue < sliderSetting) {
        digitalWrite(relay, HIGH);
        } else {
        digitalWrite(relay, LOW);
      }
  }
}

unsigned long previousMillis = 0;

put that above the void setup() area. you need to keep it, otherwise it resets everytime

You: previousMillis = currentMillis; then you: unsigned long previousMillis = 0; in the next call to the function.

What do you think will happen?

As an alternative to putting it at global scope, make this line:

static unsigned long previousMillis = 0;

So it only gets initialized once and keeps its value between calls to that function.

enum State {
  OFF = 0,
  DELAYING = 1,
  ON = 2
} state;

unsigned long delayingFromMs;

void setup() {
  state = OFF;
}

void loop() {
  switch(state) {
  case OFF:
    if(tempIsLow()) {
      state = DELAYING;
      delayingFromMs = millis();
    }
    else {
      // do nothing;
    }
    break;

  case DELAYING:
    if(tempIsLow()) {
      if(millis() - delayingFromMs > 1000L * 60L) {
        turnSolenoidOn();
        state = ON;
      }
    }
    else {
      state = OFF;
    }
    break;

  case ON:
    if(tempIsLow()) {
      // do nothing
    }
    else {
      turnSolenoidOff()l
      state = OFF;
    }
    break;
  }
}
  if (currentMillis - previousMillis >= interval){
    previousMillis = currentMillis;
      if (actualValue < sliderSetting) {

The place to change the last event time is when the event occurs, not when some amount of time has elapsed. Obviously currentMillis and previousMillis are stupid names since they do not reflect what they actually contain.

Is there any hysteresis in your thermal control loop?

You all are the coolest. I decided to give enum a try because it seems awesome (This is one of my first coding projects so everything seems awesome).

As of now, it’s working as I want. My new question, as I need to sort of triple this code to account for humidity levels (h), humidity solenoids (humdRelay), carbon dioxide levels (co2) and my co2 fresh air intake relay (co2Relay), is:
How do I go about turning my loop-embedded switch function into something more general that can be called 3 times using different variables each time?

I should also say, I’m using this code in conjunction with the Blynk app for and using it to display my temperature as well as provide a virtual thermostat from my phone…

Here’s what I have:

#include <Bridge.h>
#include <BlynkSimpleYun.h>
#include <Wire.h>
#include "SparkFunHTU21D.h"
#include "kSeries.h"
#include <SimpleTimer.h>

SimpleTimer timer;
HTU21D myClimate;

int tempSlider = 30;
int tempRelay = 10;

int t;

enum State {
  OFF = 0,
  DELAYING = 1,
  ON = 2
} state;

unsigned long delayingFromMs;

char auth[] = "derp";


void setup() {
  Blynk.begin(auth);
  state = OFF;
  pinMode(tempRelay, OUTPUT);
  myClimate.begin();

}

BLYNK_READ(0) {  // temp display
  float celsiusTemp = myClimate.readTemperature();
  t = (celsiusTemp * 9.0) / 5.0 + 32.0; //convert to fahrenheit
  Blynk.virtualWrite(0, t);
}

//Temperature Setting in Blynk on Virtual Pin 2
BLYNK_WRITE(2) {
  tempSlider = param.asInt();
}

void loop() {
  Blynk.run();
  float celsiusTemp = myClimate.readTemperature();
  t = (celsiusTemp * 9.0) / 5.0 + 32.0; //convert to fahrenheit

  switch (state)
  {
    case OFF:
      if (t < tempSlider) {
        state = DELAYING;
        delayingFromMs = millis();
      }
      break;
    case DELAYING:
      if (t < tempSlider) {
        if (millis() - delayingFromMs > 1000L * 60L) {
          digitalWrite(tempRelay, HIGH);
          state = ON;
        }
      }
      else {
        state = OFF;
      }
      break;

    case ON:
      {
        if (t < tempSlider) {
          // do nothing
        } else {
          digitalWrite(tempRelay, LOW);
          state = OFF;
        }
        break;
      }
  }
}

and the specific code I’m looking to simplify to be called multiple times with different parameters…

switch (state)
  {
    case OFF:
      if (t < tempSlider) {
        state = DELAYING;
        delayingFromMs = millis();
      }
      break;
    case DELAYING:
      if (t < tempSlider) {
        if (millis() - delayingFromMs > 1000L * 60L) {
          digitalWrite(tempRelay, HIGH);
          state = ON;
        }
      }
      else {
        state = OFF;
      }
      break;

    case ON:
      {
        if (t < tempSlider) {
          // do nothing
        } else {
          digitalWrite(tempRelay, LOW);
          state = OFF;
        }
        break;
      }
  }

Something like…

void loop{
     switch(state, co2, co2Slider, co2Relay);
}

switch(state, int actualValue, setValue, relayValue)
{
    case OFF:
      if (actualValue < setValue) {
        state = DELAYING;
        delayingFromMs = millis();
      }
      break;

etc etc etc

But that doesn’t seem to work.

Any Thoughts?

The problem is that all three properties are sharing the same delayingFromMs variable.

A switch/case is a statement not a declared function in your code. It takes only one expression.

Create a new void function that is passed your multiple values, and contains your switch/case statement code. You will now need different "enum States" of different names and when you pass this variable to your function it will be by reference. This means putting a "&" in front of the variable to allow the function to modify it. As you will need the different states to be modified and kept track of differently.

It looks like you know what to do with your actualValue, setValue, relayValue, but you have to give these variables in your new function a proper type. Since you declared the variables that you are using in your main loop as 'int' these all need to be int too.

delayingFromMs can likely remain a global timer for all three, but if you want different timers then they need to be made and passed by reference too.

This is tough.

I’m definitely having troubles with the reference variable and the enum… I’m kind of guessing here… Doesn’t seem like a very beginner topic from my searching :confused:

But here’s what I have… definitely doesn’t work, but am I on the right track?

#include <Bridge.h>
#include <BlynkSimpleYun.h>
#include <Wire.h>
#include "SparkFunHTU21D.h"
#include "kSeries.h"
#include <SimpleTimer.h>

SimpleTimer timer;
HTU21D myClimate;

int tempSlider = 30;
int tempRelay = 10;

int humdSlider = 30;
int humdRelay =  5;

float t;
float h;

enum State {
  OFF = 0,
  DELAYING = 1,
  ON = 2
} state;
  
enum tempState {
  tempOFF = 0,
  tempDELAYING = 1,
  tempON = 2
} tempstate;

enum humdState {
  humdOFF = 0,
  humdDELAYING = 1,
  humdON = 2
} humdstate;

unsigned long delayingFromMsTemp;
unsigned long delayingFromMsHumd;



char auth[] = "????";


void setup() {
  Blynk.begin(auth);
  state = OFF;
  tempstate = tempOFF;
  humdstate = humdOFF;
  pinMode(tempRelay, OUTPUT);
  pinMode(humdRelay, OUTPUT);
  myClimate.begin();

}

// Temperature display in Blynk
BLYNK_READ(0) {  
  float celsiusTemp = myClimate.readTemperature();
  t = (celsiusTemp * 9.0) / 5.0 + 32.0; //convert to fahrenheit
  Blynk.virtualWrite(0,t);
}

//Temperature Setting in Blynk on Virtual Pin 2
BLYNK_WRITE(2) {
  tempSlider = param.asInt();
}

//Humidity display in Blynk
BLYNK_READ(0) {  
  float h = myClimate.readHumidity();
  Blynk.virtualWrite(1,h);
}

//Humidity Setting in Blynk on Virtual Pin 2
BLYNK_WRITE(2) {
  humdSlider = param.asInt();
}

void loop() {
  Blynk.run();
  float celsiusTemp = myClimate.readTemperature();
  t = (celsiusTemp * 9.0) / 5.0 + 32.0; //convert to fahrenheit
  float h = myClimate.readHumidity();
  
  derp(&tempstate, t, tempSlider, tempRelay, delayingFromMsTemp);
  derp(&humdstate, h, humdSlider, humdRelay, delayingFromMsHumd);

}

void derp(int &state, int actualValue, int setValue, int relayValue, int delayingFromMs) {
  switch(state)
  {
    case OFF:
      if (actualValue < setValue) {
        state = DELAYING;
        delayingFromMs = millis();
      }
      break;
    case DELAYING:
      if (actualValue < setValue) {
        if (millis() - delayingFromMs > 1000L * 60L) {
          digitalWrite(relayValue, HIGH);
          state = ON;
        }
      }
      else {
        state = OFF;
      }
      break;

    case ON:
      {
        if (actualValue < setValue) {
          // do nothing
        } else {
          digitalWrite(relayValue, LOW);
          state = OFF;
        }
        break;
      }
  }
}

Note that if you are sticking with using enum there is a bit of a hack you need to do to pass the variables to your functions.

See the FAQ on this page. This work around is easy.

When you pass it to your function you don't declare it as an 'int', but what you called it. in this case 'State'. For it not to be confusing don't call your State variables things like state. That will only mess with your head and any one trying to help you.

And the enum variable that is used in your function, in this case 'derp', does not need to be called state. It can be called something else to help you understand that your function is working on this variable.

EDIT: You don't need to make more enum structures. Just declare new variables.

enum sensorState {
  OFF,
  DELAYING,
  ON
};
sensorState temperatureSensor = OFF;
sensorState CO2Sensor = OFF;
sensorState carbonSensor = OFF;
//or whatever, etc.

When you call a function you don't need to put the & symbol in front of the variable you are passing to it. Only when defining the function parameter need it.

If your timers are unsigned longs, the function needs to be passed unsigned longs as well, not ints.

I'm having a really tough time wrapping my head around this....

Let's start with the EASY >:( hack :)

So I'm creating a separate state.h file... and in that file....

I'm putting:

enum sensorState { OFF, DELAYING, ON };

?

tab.h

enum sensorState {
  OFF,
  DELAYING,
  ON
};
sensorState var1 = OFF;
sensorState var2 = OFF;
sensorState var3 = OFF;

//Call em whatever

Main Sketch

#include "tab.h"
void setup() {
  // put your setup code here, to run once:

}

void loop() {
  // put your main code here, to run repeatedly:
  doSomething(var1, 30);//Hey! I am doing something with my temp sensor state. I hope it does something useful
}

void doSomething(sensorState &mystate, int someVariable) {
  switch (mystate)
  case OFF:
  // :(
  break;
};

Cool. I’m awfully close, but I’m having some issues with adding my library… It doesn’t seem to want to compile- it seems to have to do with adding in that .h file… Should I be adding this into the libraries folder in the same way as most libraries (and it’s just my .h file, yes?) or can i put it next to the .ino in the sketch folder? Either way actually hasn’t seemed to work.

#include "relay.h"
#include <Bridge.h>
#include <BlynkSimpleYun.h>
#include <Wire.h>
#include "SparkFunHTU21D.h"
#include "kSeries.h"
#include <SimpleTimer.h>


SimpleTimer timer;
HTU21D myClimate;

int tempSlider = 30;
int tempRelay = 10;

int humdSlider = 30;
int humdRelay =  5;

float t;
float h;

unsigned long delayingFromMsTemp;
unsigned long delayingFromMsHumd;

char auth[] = "b828e244f8b94392af33e13c346a4244";


void setup() {
  Blynk.begin(auth);

  pinMode(tempRelay, OUTPUT);
  pinMode(humdRelay, OUTPUT);
  myClimate.begin();

}

BLYNK_READ(0) {  // temp display
  float celsiusTemp = myClimate.readTemperature();
  t = (celsiusTemp * 9.0) / 5.0 + 32.0; //convert to fahrenheit
  Blynk.virtualWrite(0, t);
}

//Temperature Setting in Blynk on Virtual Pin 2
BLYNK_WRITE(2) {
  tempSlider = param.asInt();
}

//Humidity display in Blynk
BLYNK_READ(0) {
  float h = myClimate.readHumidity();
  Blynk.virtualWrite(1, h);
}

//Humidity Setting in Blynk on Virtual Pin 2
BLYNK_WRITE(2) {
  humdSlider = param.asInt();
}

void loop() {
  Blynk.run();
  float celsiusTemp = myClimate.readTemperature();
  t = (celsiusTemp * 9.0) / 5.0 + 32.0; //convert to fahrenheit
  float h = myClimate.readHumidity();

  derp(tempState, t, tempSlider, tempRelay, delayingFromMsTemp);
  derp(humdState, h, humdSlider, humdRelay, delayingFromMsHumd);

}

void derp(sensorState &myState, int actualValue, int setValue, int relayValue, unsigned long delayingFromMs) {
  switch (myState)
  {
    case OFF:
      if (actualValue < setValue) {
        myState = DELAYING;
        delayingFromMs = millis();
      }
      break;
    case DELAYING:
      if (actualValue < setValue) {
        if (millis() - delayingFromMs > 1000L * 60L) {
          digitalWrite(relayValue, HIGH);
          myState = ON;
        }
      }
      else {
        myState = OFF;
      }
      break;

    case ON:
      {
        if (actualValue < setValue) {
          // do nothing
        } else {
          digitalWrite(relayValue, LOW);
          myState = OFF;
        }
        break;
      }
  }
}

And my relay.h file:

enum sensorState {
  OFF,
  DELAYING,
  ON
};
sensorState tempState = OFF;
sensorState humdState = OFF;
sensorState co2State = OFF;

Are you adding a tab by using the in-IDE option?

|500x491

It should just drop the .h file directly into the correct sketch folder when done like this.

Yep, I used the tab in the ide and made the 'relay.h' file and saved the entire thing as a sketch folder as usual.

|500x338

This is my error message, but I'm having zero problems with Blynk libraries in any of my other (also, more Blynk-heavy) sketches.

Arduino: 1.6.4 (Linux), Board: "Arduino Yún"

Build options changed, rebuilding all
Using library relay in folder: /home/zee/Arduino/libraries/relay (legacy)
Using library Bridge in folder: /home/zee/Arduino/libraries/Bridge 
Using library Blynk in folder: /home/zee/Arduino/libraries/blynk-library-0.3.0 
Using library Wire in folder: /home/zee/Desktop/arduino-1.6.4/hardware/arduino/avr/libraries/Wire 
Using library SparkFun HTU21D Humidity and Termperature Sensor Breakout in folder: /home/zee/Arduino/libraries/SparkFun_HTU21D_Breakout_Arduino_Library-master 
Using library kSeries in folder: /home/zee/Arduino/libraries/kSeries (legacy)
Using library SimpleTimer in folder: /home/zee/Arduino/libraries/SimpleTimer (legacy)

/home/zee/Desktop/arduino-1.6.4/hardware/tools/avr/bin/avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -mmcu=atmega32u4 -DF_CPU=16000000L -DARDUINO=10604 -DARDUINO_AVR_YUN -DARDUINO_ARCH_AVR -DUSB_VID=0x2341 -DUSB_PID=0x8041 -DUSB_MANUFACTURER="Unknown" -DUSB_PRODUCT="Arduino Yun" -I/home/zee/Desktop/arduino-1.6.4/hardware/arduino/avr/cores/arduino -I/home/zee/Desktop/arduino-1.6.4/hardware/arduino/avr/variants/yun -I/home/zee/Arduino/libraries/relay -I/home/zee/Arduino/libraries/Bridge/src -I/home/zee/Arduino/libraries/blynk-library-0.3.0 -I/home/zee/Desktop/arduino-1.6.4/hardware/arduino/avr/libraries/Wire -I/home/zee/Arduino/libraries/SparkFun_HTU21D_Breakout_Arduino_Library-master/src -I/home/zee/Arduino/libraries/kSeries -I/home/zee/Arduino/libraries/SimpleTimer /tmp/build1370233910885866603.tmp/sketch_nov04x.cpp -o /tmp/build1370233910885866603.tmp/sketch_nov04x.cpp.o 
In file included from /home/zee/Arduino/libraries/blynk-library-0.3.0/Blynk/BlynkApi.h:17:0,
                 from /home/zee/Arduino/libraries/blynk-library-0.3.0/Blynk/BlynkProtocol.h:18,
                 from /home/zee/Arduino/libraries/blynk-library-0.3.0/BlynkSimpleYun.h:18,
                 from sketch_nov04x.ino:3:
sketch_nov04x.ino: In function 'void BlynkWidgetRead0(BlynkReq&)':
/home/zee/Arduino/libraries/blynk-library-0.3.0/Blynk/BlynkHandlers.h:64:10: error: redefinition of 'void BlynkWidgetRead0(BlynkReq&)'
     void BlynkWidgetRead ## pin  (BlynkReq& request)
          ^
/home/zee/Arduino/libraries/blynk-library-0.3.0/Blynk/BlynkHandlers.h:70:31: note: in expansion of macro 'BLYNK_READ_2'
 #define BLYNK_READ(pin)       BLYNK_READ_2(pin)
                               ^
sketch_nov04x.ino:49:1: note: in expansion of macro 'BLYNK_READ'
/home/zee/Arduino/libraries/blynk-library-0.3.0/Blynk/BlynkHandlers.h:64:10: error: 'void BlynkWidgetRead0(BlynkReq&)' previously defined here
     void BlynkWidgetRead ## pin  (BlynkReq& request)
          ^
/home/zee/Arduino/libraries/blynk-library-0.3.0/Blynk/BlynkHandlers.h:70:31: note: in expansion of macro 'BLYNK_READ_2'
 #define BLYNK_READ(pin)       BLYNK_READ_2(pin)
                               ^
sketch_nov04x.ino:37:1: note: in expansion of macro 'BLYNK_READ'
sketch_nov04x.ino: In function 'void BlynkWidgetWrite2(BlynkReq&, const BlynkParam&)':
/home/zee/Arduino/libraries/blynk-library-0.3.0/Blynk/BlynkHandlers.h:61:10: error: redefinition of 'void BlynkWidgetWrite2(BlynkReq&, const BlynkParam&)'
     void BlynkWidgetWrite ## pin (BlynkReq& request, const BlynkParam& param)
          ^
/home/zee/Arduino/libraries/blynk-library-0.3.0/Blynk/BlynkHandlers.h:69:31: note: in expansion of macro 'BLYNK_WRITE_2'
 #define BLYNK_WRITE(pin)      BLYNK_WRITE_2(pin)
                               ^
sketch_nov04x.ino:55:1: note: in expansion of macro 'BLYNK_WRITE'
/home/zee/Arduino/libraries/blynk-library-0.3.0/Blynk/BlynkHandlers.h:61:10: error: 'void BlynkWidgetWrite2(BlynkReq&, const BlynkParam&)' previously defined here
     void BlynkWidgetWrite ## pin (BlynkReq& request, const BlynkParam& param)
          ^
/home/zee/Arduino/libraries/blynk-library-0.3.0/Blynk/BlynkHandlers.h:69:31: note: in expansion of macro 'BLYNK_WRITE_2'
 #define BLYNK_WRITE(pin)      BLYNK_WRITE_2(pin)
                               ^
sketch_nov04x.ino:44:1: note: in expansion of macro 'BLYNK_WRITE'
Multiple libraries were found for "relay.h"
 Used: /home/zee/Arduino/libraries/relay
 Not used: /home/zee/Desktop/arduino-1.6.4/libraries/relay
Multiple libraries were found for "Bridge.h"
 Used: /home/zee/Arduino/libraries/Bridge
 Not used: /home/zee/Desktop/arduino-1.6.4/libraries/Bridge
Multiple libraries were found for "BlynkSimpleYun.h"
 Used: /home/zee/Arduino/libraries/blynk-library-0.3.0
 Not used: /home/zee/Desktop/arduino-1.6.4/libraries/blynk-library-0.3.0
Multiple libraries were found for "SparkFunHTU21D.h"
 Used: /home/zee/Arduino/libraries/SparkFun_HTU21D_Breakout_Arduino_Library-master
 Not used: /home/zee/Desktop/arduino-1.6.4/libraries/SparkFun_HTU21D_Breakout_Arduino_Library-master
Multiple libraries were found for "kSeries.h"
 Used: /home/zee/Arduino/libraries/kSeries
 Not used: /home/zee/Desktop/arduino-1.6.4/libraries/kSeries
Multiple libraries were found for "SimpleTimer.h"
 Used: /home/zee/Arduino/libraries/SimpleTimer
 Not used: /home/zee/Desktop/arduino-1.6.4/libraries/SimpleTimer
Error compiling.