Simple fan/humidity automation

Let me start by saying I have no knowledge of programming. Ive been looking at example code for about 2 weeks, copying, pasting, modifying, uploading, repeat. Now, i fully plan on reading my face off and continuing my Arduino education because I see all the potential it offers but I'm in a bit of a time crunch. Hoping you guys can help.

I grow gourmet and medicinal mushrooms as a hobby. Lion's Mane, Shitake, King Oyster, and Beech. My old setup was to run an exhaust fan 24/7 and use a cycle timer to kick on a fogger for humidy every 15 mins for 1 minute. This is not very efficient as it clears all the fog out of the tent very quickly with the fan always on.

I wired 4 independent outlets to a sainsmart 4 channel mechanical relay. Right now i only need to control 2 of the outlets. It works I just cant figure out the programming in time. I needed to get my mushrooms cultures in the tent a few days ago and im going to have allot of hours of work go to waste if I dont get em in some fresh, humid air.

I want to turn on the top outlet(fan) for 5 minutes every 15 minutes. I want to turn on the bottom outlet(fogger) for the last 1 minute of the 5 minute fan cycle. So the fogger and the fan are both on for the last minute of the 5 minute fan cycle. So 1 minute of overlap so the fan can disperse the fog and everything shuts off for 15 minutes. repeat.

Sorry if this is extremely vague but I feel its a really simple sketch, probably because of how limited my programming knowledge is. If you have ANY questions feel free to ask, even if it's about mushroom cultivation =D

Now, i fully plan on reading my face off and

Geez, I've read 7 books in the last week. I had no idea that reading could make your face fall off. Good thing that didn't happen.

I want to turn on the top outlet(fan) for 5 minutes every 15 minutes.

Do NOT use delay(). Look at the blink without delay example. The on and off durations do not need to be the same Turn the relay pin on, and set the interval to 5 minutes. Turn the relay pin off and set the interval to 10 minutes.

I want to turn on the bottom outlet(fogger) for the last 1 minute of the 5 minute fan cycle.

If you understand what the blink without delay example is doing, you can see that the on time can be used to control two different off times. One of the times is the time to turn the fogger relay pin off. The other is the time to turn the fan relay pin off.

Here’s a program which has four event timers.

const unsigned long MILLISECONDS_PER_SECOND = 1000;
const unsigned long MILLISECONDS_PER_MINUTE = MILLISECONDS_PER_SECOND * 60;
const unsigned long MILLISECONDS_PER_HOUR = MILLISECONDS_PER_MINUTE * 60;
const unsigned long MILLISECONDS_PER_DAY = MILLISECONDS_PER_HOUR * 24;
const unsigned long INTERVAL_BETWEEN_ON_TIMES[] = {MILLISECONDS_PER_DAY, MILLISECONDS_PER_DAY, MILLISECONDS_PER_DAY, MILLISECONDS_PER_DAY};
const unsigned long TIME_UNTIL_FIRST_ON[] = {0, MILLISECONDS_PER_HOUR * 2, MILLISECONDS_PER_HOUR * 4, MILLISECONDS_PER_HOUR * 6};
const unsigned long ON_TIME_INTERVAL[] = {MILLISECONDS_PER_MINUTE * 15, MILLISECONDS_PER_MINUTE * 90, MILLISECONDS_PER_HOUR * 2, MILLISECONDS_PER_MINUTE * 10};
const byte RELAYS_IN_USE = 4;

const byte RELAY_PIN[] = {4, 5, 6, 7};
const boolean ACTIVE_STATE = 1;
const boolean INACTIVE_STATE = 0; //!ACTIVE_STATE; // would this work?

unsigned long lastTransitionTime[RELAYS_IN_USE];

boolean startedFlag[RELAYS_IN_USE];
boolean relayOnFlag[RELAYS_IN_USE];
unsigned long programStartTime;

void setup()
{
  unsigned long now = millis();

  for (int i = 0; i < RELAYS_IN_USE; i++)
  {
    pinMode (RELAY_PIN[i], OUTPUT); // define mode for pin 8 as output
    turnOff(i);
    lastTransitionTime[i] = now;
    startedFlag[i] = 0;
  }
}

void loop()
{
  unsigned long now = millis();
  for (int i = 0; i < RELAYS_IN_USE; i++)
  {
    if (startedFlag[i])
    {
      if (relayOnFlag[i])
      {
        if (now - lastTransitionTime[i] > ON_TIME_INTERVAL[i])
        {
          turnOff(i);
        }
      }
      else // relay not on
      {
        if (now - lastTransitionTime[i] > INTERVAL_BETWEEN_ON_TIMES[i])
        {
          lastTransitionTime[i] += INTERVAL_BETWEEN_ON_TIMES[i];
          turnOn(i);
        }
      }
    }
    else // not started
    {
      if (now - lastTransitionTime[i] > TIME_UNTIL_FIRST_ON[i])
      {
        lastTransitionTime[i] += TIME_UNTIL_FIRST_ON[i];
        startedFlag[i] = 1;
        turnOn(i);
      }
    }
  }
}
void turnOn(byte relayIndex)
{
  relayOnFlag[relayIndex] = 1;
  digitalWrite(RELAY_PIN[relayIndex], ACTIVE_STATE);
}

void turnOff(byte relayIndex)
{
  relayOnFlag[relayIndex] = 0;
  digitalWrite(RELAY_PIN[relayIndex], INACTIVE_STATE);
}

There are three main constant arrays to set the timers.

The constant “INTERVAL_BETWEEN_ON_TIMES” is used to indicate how often a relay should turn on. I set all these constants to one day.

const unsigned long INTERVAL_BETWEEN_ON_TIMES[] = {MILLISECONDS_PER_DAY, MILLISECONDS_PER_DAY, MILLISECONDS_PER_DAY, MILLISECONDS_PER_DAY};

Each of the four relays will turn on once every 24 hours but not necessarily at the same time.

Another constant “ON_TIME_INTERVAL” is used to indicate how long the relay should be on.

const unsigned long ON_TIME_INTERVAL[] = {MILLISECONDS_PER_MINUTE * 15, MILLISECONDS_PER_MINUTE * 90, MILLISECONDS_PER_HOUR * 2, MILLISECONDS_PER_MINUTE * 10};

I used the following times to fill the array. 15 minutes, 90 minutes, 2 hours and the final relay will be turned on for 10 minutes.

The time the relay will be off is the value of “INTERVAL_BETWEEN_ON_TIMES” minus the value of “ON_TIME_INTERVAL”.

I doubt you want all the relays to turn on at the same time once the Arduino has been started, so there’s a constant “” which is used to indicate how long to wait after the Arduino has been turn on before a relay should be turned on.

const unsigned long TIME_UNTIL_FIRST_ON[] = {0, MILLISECONDS_PER_HOUR * 2, MILLISECONDS_PER_HOUR * 4, MILLISECONDS_PER_HOUR * 6};

In this example, the first relay will turn on for the first time right when the Arduino is powered on. This first relay will be on for 15 minutes and then turn off for 23 hours and 45 minutes. The second relay won’t turn on until 2 hours after the Arduino has been turned on. The second relay will be on for an hour and a half (90 minutes) and then turn off for 22 hours and 30 minutes.

Hopefully you can figure out when the other relays would first turn on and see how often the relays will turn on for and for how long.

The longest time interval you can use is 49 days. The code should work fine (if it works) indefinitely but you can’t set any of the above mentioned time constants for more than 49 days.

The code compiles but I haven’t tested it.

It would be a good idea to add some debug statements to the code, and set the time intervals for short time intervals so you can observe if the timers work as expected.

Make sure you set the array “RELAY_PIN” to the pin numbers you’re using.

It should be relatively easy to change the number of relays being used. Just change the value of “RELAYS_IN_USE” and add or remove constants from the arrays as appropriate.

tripleduece249: Let me start by saying I have no knowledge of programming. Ive been looking at example code for about 2 weeks, copying, pasting, modifying, uploading, repeat.

is it me, or are these two sentences at complete odd's with each other ?

here is my adaption of blink without delay. I do not know if you need to write your pins HIGH or LOW to turn them on or off.

the idea is that the blink without delay will increment the ticker once for every minute counted. then at 10 minutes, turn on the fan, at 14 turn on the humidifier and at 15 turn everything off and reset ticker.

// pin assignments
const int fan =  5;      // the number of the fan pin
const int atomizer =  6;

// Global variables that will change :
int fan = HIGH;             // change to LOW if reversed
int atomizer = HIGH;        // change to LOW if reversed
unsigned long previousMillis = 0;        
int ticker = 0;

// constants won't change :
const long interval = 60000;        // interval to count 1 minute


void setup() {
  // set the digital pin as output:
  pinMode(fan, OUTPUT);
  pinMode(atomizer, OUTPUT);
}

void loop()
{

  if(millis() - previousMillis >= interval) {
    previousMillis = millis();   
    ticker ++;    // increments ticker by 1 for each minute counted.
  }

if (ticker==10){
  digitalWrite(fan,HIGH);
}

if(ticker==14){
  digitalWrite(atomizer,HIGH);
}

if (ticker==15){
  digitalWrite(fan,LOW);
  digitalWrite(atomizer,LOW);
  ticker=0;
}

dave-in-nj: here is my adaption of blink without delay. I do not know if you need to write your pins HIGH or LOW to turn them on or off.

the idea is that the blink without delay will increment the ticker once for every minute counted. then at 10 minutes, turn on the fan, at 14 turn on the humidifier and at 15 turn everything off and reset ticker.

// pin assignments
const int fan =  5;      // the number of the fan pin
const int atomizer =  6;

// Global variables that will change : int fan = HIGH;             // change to LOW if reversed int atomizer = HIGH;        // change to LOW if reversed unsigned long previousMillis = 0;         int ticker = 0;

// constants won't change : const long interval = 60000;        // interval to count 1 minute

void setup() {  // set the digital pin as output:  pinMode(fan, OUTPUT);  pinMode(atomizer, OUTPUT); }

void loop() {

 if(millis() - previousMillis >= interval) {    previousMillis = millis();      ticker ++;    // increments ticker by 1 for each minute counted.  }

if (ticker==10){  digitalWrite(fan,HIGH); }

if(ticker==14){  digitalWrite(atomizer,HIGH); }

if (ticker==15){  digitalWrite(fan,LOW);  digitalWrite(atomizer,LOW);  ticker=0; }

I get what you are doing here but this doesn't compile. const int fan = 5; // the number of the fan pin const int atomizer = 6;

// Global variables that will change : int fan = HIGH; // change to LOW if reversed int atomizer = HIGH; // change to LOW if reversed

The variables conflict. So i changed the glovbal variable names to int fanGV and int atomizerGV and chnaged it anywhere i saw HIGH or LOW. It compiled so ill mess around with it some more. Thanks for the input

tripleduece249: I get what you are doing here but this doesn't compile. const int fan = 5; // the number of the fan pin const int atomizer = 6;

// Global variables that will change : int fan = HIGH; // change to LOW if reversed int atomizer = HIGH; // change to LOW if reversed

The variables conflict.

yup, you are correct, I was too quick. just delete those two lines and add a final bracket to close the void loop at the end of the sketch,

dave-in-nj: yup, you are correct, I was too quick. just delete those two lines and add a final bracket to close the void loop at the end of the sketch,

Sorry, delete what lines? i just changed the variable names and it seems like both relays turn on right away and just stay on.

tripleduece249: I get what you are doing here ..........................

the idea is to create a timer and every time it counts to 1 minute, it increments a ticker. then you just list the number of ticks you want before you turn on the fan and the atomizer. it is a beginner type use of blink without delay and can do two things for you. if you tried to count after each change, you would wind up with a lot of lines and your face falling off (again) it is sloppy because it turns the fan ON after it is already on. ditto the atomizer. but the simplicity should be evident in that you could change the values at any time to overlap however you wanted. this also hinges on your 15 minute cycle. if you wanted a longer fan run time you would need to alter the last if() if you wanted the atomizer to come on later or earlier, or run longer or shorter, you would need to do that by changing things around a bit. as a note, this is not exact. the timer for the Arduino can be off minutes a day/week, so even though it might be only a few seconds off per 15 minutes, it would be good enough.

do your relays need to be HIGH to LOW to run ?

try this :

// pin assignments
const int fan =  5;      // the number of the fan pin
const int atomizer =  6;

// Global variables that will change :
int fanState = HIGH;             // change to LOW if reversed
int atomizerState = HIGH;        // change to LOW if reversed
unsigned long previousMillis = 0;
int ticker = 0;

// constants won't change :
const long interval = 60000;        // interval to count 1 minute


void setup() {
  // set the digital pin as output:
  pinMode(fan, OUTPUT);
  pinMode(atomizer, OUTPUT);
}

void loop()
{

  if (millis() - previousMillis >= interval) {
    previousMillis = millis();
    ticker ++;    // increments ticker by 1 for each minute counted.
  }

  if (ticker == 10) {
    digitalWrite(fan, fanState);
  }

  if (ticker == 14) {
    digitalWrite(atomizer, atomizerState);
  }

  if (ticker == 15) {
    digitalWrite(fan, -fanState);
    digitalWrite(atomizer, -atomizerState);
    ticker = 0;
  }
} // end of void loop

tripleduece249: Sorry, delete what lines? i just changed the variable names and it seems like both relays turn on right awat and just stay on.

We think of digital pins as typically either high or low when the sketch starts, it will cycle things on and off so you may get a 'bump' in your outputs while the Arduino starts and before it can run the sketch. also, some relays boards us a HIGH to energize the relay, others use a LOW. if you SOURCE (provide 5v) power to the relays board, it has to be HIGH to turn on. if you DRAIN (bring to ground), then your pin has to be LOW to energize the relay. as a note, you can change the interval to something much lower to do bench testing. PITA to have to wait 15 minutes to find out it is not working as desired. try 6,000 for 6 second ticker timing.

dave-in-nj: We think of digital pins as typically either high or low when the sketch starts, it will cycle things on and off so you may get a 'bump' in your outputs while the Arduino starts and before it can run the sketch. also, some relays boards us a HIGH to energize the relay, others use a LOW. if you SOURCE (provide 5v) power to the relays board, it has to be HIGH to turn on. if you DRAIN (bring to ground), then your pin has to be LOW to energize the relay. as a note, you can change the interval to something much lower to do bench testing. PITA to have to wait 15 minutes to find out it is not working as desired. try 6,000 for 6 second ticker timing.

I believe HIGH. I tried this again and same thing. Relays are always on. I changed HIGH to LOW. Still same thing

dave-in-nj: We think of digital pins as typically either high or low when the sketch starts, it will cycle things on and off so you may get a 'bump' in your outputs while the Arduino starts and before it can run the sketch. also, some relays boards us a HIGH to energize the relay, others use a LOW. if you SOURCE (provide 5v) power to the relays board, it has to be HIGH to turn on. if you DRAIN (bring to ground), then your pin has to be LOW to energize the relay. as a note, you can change the interval to something much lower to do bench testing. PITA to have to wait 15 minutes to find out it is not working as desired. try 6,000 for 6 second ticker timing.

Alright, Ive been messing around with the code and this is what is looks like

// pin assignments const int fan = 7; // the number of the fan pin const int atomizer = 8;

// Global variables that will change : int fanState = HIGH; // change to LOW if reversed int atomizerState = HIGH; // change to LOW if reversed unsigned long previousMillis = 0; int ticker = 0;

// constants won't change : const long interval = 1000; // interval to count 1 minute

void setup() { // set the digital pin as output: pinMode(fan, OUTPUT); pinMode(atomizer, OUTPUT); }

void loop() {

if (millis() - previousMillis >= interval) { previousMillis = millis(); ticker ++; // increments ticker by 1 for each minute counted. }

if (ticker == 2) { digitalWrite(fan, LOW); }

if (ticker == 3) { digitalWrite(atomizer, LOW); }

if (ticker == 4) { digitalWrite(fan, -fanState); digitalWrite(atomizer, HIGH); ticker = 0; } } // end of void loop

When i start it, both relays turn on for 1 cycle, then they both turn off, then they go into the proper cycle. pin 7 on, pin 8 on, both off, repeat

I would go ahead and change this line as well

if (ticker == 4) { digitalWrite(fan, -fanState); // change to HIGH and delete -fanSate digitalWrite(atomizer, HIGH); ticker = 0;

a suggestion when doing code.

you have

const long interval = 1000; // interval to count 1 minute

you could use

// const long interval = 60000; // interval to count 1 minute

const long interval = 1000; // interval to count 1 SECOND

or, just change the note. it can be a PITA to keep it straight, but when the program gets long, is does work out better to come back and figure out what is working.

when trying to figure things out, I use two or three lines and just comment them out. the fact there are 2 or 3 lines shows me that I changed something at that point. whatever works for you.

Thanks to everyone that contributed. @DuaneDegn - i copied your code and modified it and I like the flexibility it has but I couldn't get the cycle running at the right intervals. I'm sure with some more time I would have figured it out and I'll def save the code because I'm sure I'll be improving and adding to my current set up.

@dave-in-nj-I ended up getting it running using your code. The simplicity is what did it for me. It works well but i still have not figured out why when I first plug it in, it does a full cycle with both relays always on. Then it shuts both off for a full cycle. After that it does exactly what its supposed to. I set it to turn the fan on every 10 minutes for 5 minutes. The last two minutes of the fan cycle the fogger kicks on and they both turn off at the same time, leaving a bunch of fog in the air.