TimeAlarms.h - Some work, some wont.

Hey guys, I’ve done some searching but no one’s problem seems to match mine.

-Arduino IDE 1.6.5
-Arduino Uno

I’m building a simple greenhouse with an automated 12/12 light cycle and humidification every 30min for 10 min.

I’m using two different alarm types to -attempt- to achieve this.

-Alarm.alarmRepeat - To trigger the functions that turn the lights off and on
-Alarm.timerRepeat - To trigger the humidifier every 30min. I also have this at the end of the HumidifierON function to trigger the HumidifierOFF function after 10 min.

Alarm.alarmRepeat(20,00,0, LightsOff);  // 8:00am every day
    Alarm.alarmRepeat(23,52,50, LightsOn);  // 8:00pm every day
    Alarm.timerRepeat(humidPeriod, HumidifierON);  // How long will the humidifier stay on for?

The thing is, anything under Alarm.alarmRepeat does not get called.
But the humidifier works like a charm! it is called by Alarm.timerRepeat.

I’ve tried several different ways to trick it into working, I tried moving my alarms into the loop, changing the trigger time, using one zero instead of two in the min and sec spots, uploading from the 1.0.6 IDE, nothing works. I know my function is good because if I call it directly it turns the lights on and prints the status.

I even tried running the sample code (adjusted the trigger time to 1 min after upload and deleted the line to manually set time since my RTC is already set and keeping time nicely) and it would print the 15 sec timer every 15 sec but it would not trigger any of the alarm.alarmRepeat functions.

I’m at a loss here, any advice?

#include <Wire.h>
#include "RTClib.h"
#include <Time.h>
#include <TimeAlarms.h>
#include "DHT.h"
#define DHTTYPE DHT11   // Define the DHT 11 Humidity Sensor

//OUTPUTS
//RELAYS
const int humidRelay = 3;
const int lightRelay = 4;

//INPUTS
const int buttonOne = 6;
const int DHTPIN = 5;

// Variables:
const int humidActTime = 600;      //How long will the Humidifier run before it shuts off (in seconds)
const int humidPeriod  = 1800;    //How often to run the humidifier (in seconds)
bool lights;                      //variable to hold the status of the lights

DHT dht(DHTPIN, DHTTYPE);    //Initilize the DHT11
RTC_DS1307 RTC;              //Initilize the RTC

    time_t syncProvider(){     //this does the same thing as RTC_DS1307::get()
 RTC.now().unixtime();
    }
    
void setup() {
  // initialize the digital pin as an output.
  pinMode(lightRelay, OUTPUT); 
  pinMode(buttonOne, INPUT_PULLUP);  
  pinMode(humidRelay, OUTPUT);
  
    Serial.begin(9600); 
    Wire.begin();
    RTC.begin();
    dht.begin();
 syncProvider();
  if (! RTC.isrunning()) {
    Serial.println(F("RTC is NOT running!"));
  }
    else {
          Serial.println(F("RTC is running!"));
    }

    Alarm.alarmRepeat(20,00,0, LightsOff);  // 8:00pm every day
      Alarm.alarmRepeat(8,00,0, LightsOn);  // 8:00pm every day
    Alarm.timerRepeat(humidPeriod, HumidifierON);  // How long will the humidifier stay on for?
	Serial.println(F("Startup Completed")); 
}
// the loop routine runs over and over again forever:
void loop() {
  Serial.print(F("Time: "));
  printCurrentTime();
  Serial.print(F("Temperature C: "));
  Serial.println(getTempC());
  Serial.print(F("Humidity: "));
  Serial.println(getHumidity());
  Serial.println();
  Alarm.delay(1000); // wait one second between clock display
}

//FUNCTIONS


//Function to begin the humidifier sequence
void HumidifierON() {
   digitalWrite(humidRelay, HIGH); // Activate the humidifier relay
	 Serial.println(F(" - Humidifier Activated"));

  Alarm.timerOnce(humidActTime, HumidifierOFF);
  Alarm.delay(1000);
}

//Function to end the humidifier sequence
  void HumidifierOFF() {
  digitalWrite(humidRelay, LOW); // Set Humidifier LED Off
    Serial.println(F(" - Humidifier Deactivated"));  
  }

//Function to run all night transition events
void Night () {
  LightsOff();
}

//Function to run all day transition events
void Day () {
  LightsOn();
}

//Function to turn the lights on
void LightsOn() {
digitalWrite(lightRelay, HIGH); // Set Lights On
   Serial.println(F(" - Lights On")); 
   lights = true;
}

//Function to turn the lights off
void LightsOff() {
digitalWrite(lightRelay, LOW); // Set Lights Off
   Serial.println(F(" - Lights Off"));
   lights = false;
}

//Function to print the current time
void printCurrentTime(){
    DateTime now = RTC.now();
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.println();
}
//Function to get the Temp Celcius reading from the DHT11
float getTempC() {
    unsigned long previousMillis;
    unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > 250) {      //The sensor needs at least 250 mills between readings
    float t = dht.readTemperature();              //Get the current temperature from the DHT11 in Celcius
    previousMillis = currentMillis;
    return t;
  }
    else {
      getTempC();
    }
}

//Function to get the humidity reading from the DHT11
unsigned int getHumidity() {
    unsigned long previousMillis;
    unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > 250) {   //The sensor needs at least 250 mills between readings
    unsigned int h = dht.readHumidity();              //Get the current Humidity reading from the DHT11 in Celcius
    previousMillis = currentMillis;
    return h;
  }
    else {
      getHumidity();
    }
}

Have I already been buried?

Alarm.alarmRepeat(20,00,0, LightsOff); // 8:00pm every day
Alarm.alarmRepeat(8,00,0, LightsOn); // 8:00pm every day
Try:
Alarm.alarmRepeat(20,0,0, LightsOff); // 8:00PM every day
Alarm.alarmRepeat(8,0,0, LightsOn); // 8:00AM every day

The Alarm functions aren't working because they don't know the current time, as provided by the DS1307.

According to the docs for Time library, you have to tell it how to get the current time by calling this:

  setSyncProvider(getTimeFunction);
    Configure Time to automatically called the getTimeFunction() regularly. This function 
    should obtain the time from another service and return a time_t number, or zero if 
    the time is not known.

You must pass a function to be called by the Time library. Your code appears to have this kind of function:

    time_t syncProvider(){     //this does the same thing as RTC_DS1307::get()
 RTC.now().unixtime();
    }

...but it doesn't actually return anything. I think you mean this:

    time_t syncProvider(){     //this does the same thing as RTC_DS1307::get()
     return RTC.now().unixtime();
    }

You may have seen a warning about "not returning a value from a function."

Then you need to call setSyncProvider in your setup:

  setSyncProvider( syncProvider );

The Alarms and Timers library calls the Time library, which needs to call syncProvider to return the current time.

Cheers,
/dev

NFrank89:
Have I already been buried?

What does that mean?

  pinMode(buttonOne, INPUT_PULLUP);  
  pinMode(humidRelay, OUTPUT);
  
    Serial.begin(9600); 
    Wire.begin();
    RTC.begin();
    dht.begin();
 syncProvider();

Your formatting is so atrocious, quite a few people might have just moved on. The IDE has an auto-format feature. I suggest you use it.

And don’t reply saying I am nit-picking. You seem to be the one wondering why you didn’t get a response.

LarryD! I believe you were on the right track. Although I had already tried removing one of the 0’s from both min and sec, i hadn’t tried replacing all the zeros with other numbers and now it works!

so, my lights will kick on at 8,11,11 instead of 8,00,00

i was tipped off by this bit from a “for dummies” article

One tricky bit about using integers to get the hours, minutes, and seconds, is that they do not have a leading zero for values below 10. You need to add those in manually, both to make the clock look right (for example, 01:05) and to keep the hours minutes and seconds in the same place on the screen.

Adding the leading zeros is accomplished in the same way for hours, minutes and seconds:

if (h<10){ // Add a zero, if necessary, as above
lcd.print(0);
}
lcd.print(h); // Display the current hour

Source: http://www.dummies.com/how-to/content/how-to-display-the-time-for-your-arduino-clock-pro.html

I can add those lines to fix the code to trigger at 8,00,00 but I’m content with 11,11 for now :slight_smile:

:o

I feel like I just got a big finger shoved in my face but okay, thanks for the constructive critique. That could be why it got buried.

The formatting can get a little out of hand when you're 99% done with a sketch and you spend the next few hours shifting things all over the place trying to get it to work lol.

...and now it works!

Uhhh... are you saying the alarms trigger at 8:11:11 (real time), but not at 8:00:00?

I'm a little skeptical, because until you add the "setSyncProvider( syncProvider );" line, there is no connection between the RTC and the Alarms. If you look at RTClib.h and .cpp, it does not include "Time.h" nor "TimeAlarms.h". Likewise, Time and TimeAlarms.h and .cpp do not include "RTClib.h". They don't know about each other.

There is some code in the Time library that makes the system time run off the Arduino internal millis() as a default "syncProvider". That will allow your sketch to cycle the lights every 12 hours, and the humidification every 30 minutes, but it won't be based on the RTC time. If you're happy with that, you may as well remove the RTC module and the RTC code.

If you do want the RTC accuracy, you must add that line. Then the system time will be synchronized with the DS1307 RTC once every 5 minutes. The internal millis() isn't real accurate, so the system time drifts a little during that interval. You can change that interval by calling setSyncInterval.

BTW, Have you used a separate sketch to set the DS1307 to the correct time and date?

Cheers,
/dev

Don’t use leading zeros in your code.

http://www.arduino.cc/en/Reference/IntegerConstants

Look at that link above, where it says “octal”. You don’t want octal, so don’t use leading zeros in code.

For display, however, things are different. You can use all the leading zeros you want for display.

I have modified one of the functions in your code. Try this instead:

//Function to print the current time
void printCurrentTime(){
    DateTime now = RTC.now();
    if ((now.hour())<10) Serial.print('0');
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    if ((now.minute())<10) Serial.print('0');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    if ((now.second())<10) Serial.print('0');
    Serial.print(now.second(), DEC);
    Serial.println();
}

Thanks for the tip odometer - I love how the community is so eager to help guide others :smiley:
The important part about that quote for me was the first line

One tricky bit about using integers to get the hours, minutes, and seconds, is that they do not have a leading zero for values below 10.

I understand your argument and updated my code accordingly! However the realization that ints do not hold a leading 0 and the possible implications of that is good for me to know.

/dev -

Your contribution was important as well. Your mention of adding the return statement was also vital. I believe I had it at an earlier point but deleted it and forgot to put it back while shifting things around trying to get it to work. It never gave me a compiler error though. The thing is, I tried adding the return back before I switched all the zeros to other numbers and it still would not trigger.

I’m okay with the times being shifted by 11min and 11sec for now. I’ll update this post when I try messing with it again.

I’m in a good spot now thanks to everyone! :smiley:

Here is my updated ‘atrocity’, now featuring auto format for your viewing pleasure :slight_smile:

#include <Wire.h>
#include "RTClib.h"
#include <Time.h>
#include <TimeAlarms.h>
#include "DHT.h"
#define DHTTYPE DHT11                               // Define the DHT 11 Humidity Sensor

//OUTPUTS
//RELAYS
const int humidRelay = 3;                           //What pin is the humidifier relay connected to?
const int lightRelay = 4;                           //What pin is the Light relay connected to?

//INPUTS
const int DHTPIN = 5;                               //What pin is the Humidity/temp sensor connected to?

//VARIABLES:
bool lights;                                        //variable to hold the status of the lights

//VARIABLES - User adjustable:
const int humidActTime = 600;                       //How long will the Humidifier run before it shuts off (in seconds)
const int humidPeriod  = 1800;                      //How often to run the humidifier (in seconds)

//INITIALIZATION:
DHT dht(DHTPIN, DHTTYPE);                           //Initilize the DHT11
RTC_DS1307 RTC;                                     //Initilize the RTC

//Setup Function
void setup() {
  // Initialize the digital pins.
  pinMode(lightRelay, OUTPUT);
  pinMode(buttonOne, INPUT_PULLUP);
  pinMode(humidRelay, OUTPUT);

  Serial.begin(9600);
  Wire.begin();
  RTC.begin();
  dht.begin();

  if (! RTC.isrunning()) {
    Serial.println(F("RTC is NOT running!"));
  }
  else {
    Serial.println(F("RTC is running!"));
  }
  //Set the RTC time to the date & time this sketch was compiled
  RTC.adjust(DateTime(__DATE__, __TIME__));
  setSyncProvider( syncProvider );                   //and sync the arduino clock with the RTC

  //SET ALARMS:
  Alarm.alarmRepeat(19, 11, 11, LightsOff);          // 8:00pm every day
  Alarm.alarmRepeat(8, 11, 11, LightsOn);            // 8:00pm every day
  Alarm.timerRepeat(humidPeriod, HumidifierON);      // How long will the humidifier stay on for?

  Serial.println(F("Startup Completed"));

}
//DAS LOOP!
void loop() {
  Serial.print(F("Time: "));
  printCurrentTime();
  Serial.print(F("Temperature C: "));
  Serial.println(getTempC());
  Serial.print(F("Humidity: "));
  Serial.println(getHumidity());
  Serial.println();
  Alarm.delay(1000);                                // wait one second between clock display
}

//FUNCTIONS

//Function to sync the arduino clock with the RTC
time_t syncProvider() {
  return RTC.now().unixtime();
}

//Function to begin the humidifier sequence
void HumidifierON() {
  digitalWrite(humidRelay, HIGH);                   // Activate the humidifier relay
  Serial.println(F(" - Humidifier Activated"));

  Alarm.timerOnce(humidActTime, HumidifierOFF);
  Alarm.delay(1000);
}

//Function to end the humidifier sequence
void HumidifierOFF() {
  digitalWrite(humidRelay, LOW);                    //Turn Humidifier Off
  Serial.println(F(" - Humidifier Deactivated"));
}

//Function to run all night transition events
void Night () {
  LightsOff();
}

//Function to run all day transition events
void Day () {
  LightsOn();
}

//Function to turn the lights on
void LightsOn() {
  digitalWrite(lightRelay, HIGH);                   //Turn Lights On
  Serial.println(F(" - Lights On"));
  lights = true;
}

//Function to turn the lights off
void LightsOff() {
  digitalWrite(lightRelay, LOW);                    //Turn Lights Off
  Serial.println(F(" - Lights Off"));
  lights = false;
}

//Function to print the current time
void printCurrentTime() {
  DateTime now = RTC.now();
  if ((now.hour()) < 10) Serial.print('0');
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  if ((now.minute()) < 10) Serial.print('0');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  if ((now.second()) < 10) Serial.print('0');
  Serial.print(now.second(), DEC);
  Serial.println();
}

//Function to get the Temp Celcius reading from the DHT11
float getTempC() {
  unsigned long previousMillis;
  unsigned long currentMillis;
  unsigned int i;
  for (i = 0; i <= 1; i++) {
    if (i == 1) {
      previousMillis = millis();
    }
    if (i == 2) {
      currentMillis = millis();
    }
  }
  if (currentMillis - previousMillis > 250) {     //The sensor needs at least 250 mills between readings
    float t = dht.readTemperature();              //Get the current temperature from the DHT11 in Celcius
    previousMillis = currentMillis;
    i = 0;
    return t;
  }
  else {
    getTempC();
  }
}

//Function to get the humidity reading from the DHT11
unsigned int getHumidity() {
  unsigned long previousMillis;
  unsigned long currentMillis;
  unsigned int i;
  for (i = 0; i <= 1; i++) {
    if (i == 1) {
      previousMillis = millis();
    }
    if (i == 2) {
      currentMillis = millis();
    }
  }
  if (currentMillis - previousMillis > 250) {       //The sensor needs at least 250 mills between readings
    unsigned int h = dht.readHumidity();            //Get the current %Humidity reading from the DHT11
    previousMillis = currentMillis;
    i = 0;
    return h;
  }
  else {
    getHumidity();
  }
}

Would you guys mind having a quick look at this function for me? I just want to know if this is the most efficient way to achieve my desired results.

Most sample code runs in the setup and loop functions and that’s where I snagged the structure for doing what I’m trying to do. But I’m trying to move this into a function and keep everything as local/modular as possible.

previousMillis would usually be initialized in Setup and conditionally updated by the Loop.

So I tried to simulate setup and loop functions with a for statement in my function.

Thoughts?

//Function to get the humidity reading from the DHT11
unsigned int getHumidity() {
  unsigned long previousMillis;
  unsigned long currentMillis;
  unsigned int i;
  for (i = 0; i <= 1; i++) {
    if (i == 1) {
      previousMillis = millis();
    }
    if (i == 2) {
      currentMillis = millis();
    }
  }
  if (currentMillis - previousMillis > 250) {       //The sensor needs at least 250 mills between readings
    unsigned int h = dht.readHumidity();            //Get the current %Humidity reading from the DHT11
    previousMillis = currentMillis;
    i = 0;
    return h;
  }
  else {
    getHumidity();
  }
}

Much better, thanks! :slight_smile:

 for (i = 0; i <= 1; i++) {
    if (i == 1) {
      previousMillis = millis();
    }
    if (i == 2) {
      currentMillis = millis();
    }
  }

When will “i” ever be 2? OK, I withdraw that. But still, what does the above achieve?

Won’t this be the same?

      previousMillis = millis();
      currentMillis = millis();

unsigned int getHumidity() {
  unsigned long previousMillis;
  unsigned long currentMillis;
  unsigned int i;
  for (i = 0; i <= 1; i++) {
    if (i == 1) {
      previousMillis = millis();
    }
    if (i == 2) {
      currentMillis = millis();
    }
  }
  if (currentMillis - previousMillis > 250) {       //The sensor needs at least 250 mills between readings
    unsigned int h = dht.readHumidity();            //Get the current %Humidity reading from the DHT11
    previousMillis = currentMillis;
    i = 0;
    return h;
  }
  else {
    getHumidity();
  }
}

I don’t understand what previousMillis is for here. It’s a local variable, so it disappears at the end of the function. So:

   previousMillis = currentMillis;   // <---- what does this achieve?
    i = 0;
    return h;

Ditto for “i”.

That may as well read:

    return h;

Same in your getTempC function.

NFrank89:
Would you guys mind having a quick look at this function for me?

Please do not cross-post. This wastes time and resources as people attempt to answer your question on multiple threads.

Threads merged.

This is the very function I am asking about in this thread. Please don’t start a new thread to split up discussion about this project.

Thank you for putting it where you feel it belongs. I originally posted that in this thread but edited it out because thought I might get in trouble since that particular function has nothing to do with my timeAlarms. I think I was busy making the other post before I ever saw your question about it in this thread. It was already my next question on the list, I just didn't want things to get too off topic in this thread for future readers.

Thanks for taking a look at it Gammon!
I’ll try to explain my thought process here then hopefully you can help me see where I’ve gone wrong.

Edit: after writing this I came up with an “improved” method which I wrote at the bottom of this post. Maybe read that first so you can see which issues I already caught before spending too much time trying to make sense of my explanation below lol.

  unsigned long previousMillis;
  unsigned long currentMillis;
  unsigned int i;
  for (i = 0; i <= 1; ++i) {
    if (i == 1) {
      previousMillis = millis();
    }
    if (i == 2) {
      currentMillis = millis();
    }
  }

So in the lines above I am trying to simulate a setup and loop function so that i can establish a legitimate initial value for previousMillis without initializing it each time the function is called.
The way this works in my head is the first time the function gets called we define our variables without initializing them (the data for each is void at this point right?)
then the for comes in and says
yup, i is less than 1, ++i Increment i (i changed this from i++ to save a cycle)
Next we hit the ‘if’ statement. Is i == 1? Yes it is!
so then we load the current millis value into previousMillis.
we hit the next if statement and no, i is not equal to 2 yet so we skip it.
the next if subtracts previousMillis from currentMillis (okay i see i messed up here, because there is no data in currentMillis. I can change the variable declaration at the beginning of the function to currentMillis = millis())
If currentMillis - previousMillis > 250 then go ahead and read the sensor. then set previous millis to current millis (i just realized this negates me ever needing to have i == 1 again because we just set previous millis to our last sensor read so we wont need to generate an initial value for previousMillis ever again)
if currentMillis - previousMillis is not greater than 250 then
else getHumidity(repeat the function)
on the second run through the function the variable declarations do not modify the values they hold so now i = 1,and previous millis still holds the value it acquired when i == 1 the first time through the for statement.
NOW we get to the for statement and i == 1 so ++i (now i==2)
the first following if statement (i==1) gets skipped and the second if is true (i==2) so we get a value for currentMillis.
Now we hit the third if statement again, 250ms probably hasn’t passed so it is false and calls the function again. Now we go through again, i==2 still so currentMillis gets updated, lets assume it has been more than 250ms since the first pass when previousMillis was initialized so currentMillis - previousMillis > 250 and the following lines are allowed to run.
so we read the sensor, load it into h and return h
i=0 is intended to reset the function back to it’s initial state once it has got a reading by allowing the first if to be run again. (I’m already realizing i don’t need this but explaining it for the sake of seeing where i went wrong)

It looks like I am relying on the assumption that calling getHumidity() at the end of the function does NOT open a new ‘instance’ of getHumidity() with it’s own variables, but just keeps re-running the function until the 3rd if statement is true and returns a value. If i am wrong about that then i can see why this would not work very well.

After explaining this step by step I’ve found a few spots where i can make improvements here is my modified code.

//Function to get the humidity reading from the DHT11
unsigned int getHumidity() {
  unsigned long previousMillis;                     // the third if statement is expected to be false until
  unsigned long currentMillis = millis();
  unsigned int i;
  for (i = 0; i < 1; i++) {
    if (i == 1) {
      previousMillis = millis();
    }
    if (currentMillis - previousMillis > 250) {       //The sensor needs at least 250 mills between readings
      unsigned int h = dht.readHumidity();            //Get the current %Humidity reading from the DHT11
      previousMillis = currentMillis;
      return h;
    }
    else {
      getHumidity();
    }
  }
}

So my new code stores a value for currentMillis every pass through the function, at the for statement on the first pass, i is set to 0 and incremented to 1 so that the following if can run and store the current millis value in previousMillis. the following if statement tests the difference against 250 and reads the sensor if it is greater than 250, then returns the value and exits the function. If the difference is less than 250 the function calls itself for a second pass through (via the else statement). on the second pass i == 1 and the for statement increments it to i == 2.
2 does not trigger anything it just prevents the following if statement from ever running again throughout the life of the program (until a reset) because we are now setting our previousMillis value at the end of each sensor read so the first if statement is no longer needed for setting an initial value for perviousMillis.

so the whole reasoning behind the for statement is to create an initial previousMilis value the first time the function is ever run in this program. from that point forward each sensor read will update the previousMillis value for us.

If the variables are lost each time the function is called then I just need to make i and previousMillis global variables right?

I stopped reading halfway down, sorry.

The way this works in my head is the first time the function gets called we define our variables without initializing them (the data for each is void at this point right?)

No, that isn't right. Local variables are re-created each time the function is called, with random values. They don't persist from one call to the next. Make them static to keep their values.

eg,

  static unsigned long previousMillis;                   
  static unsigned long currentMillis = millis();

yup, i is less than 1, ++i Increment i (i changed this from i++ to save a cycle)

That won't make any difference. Either way the compiler has to increment i by one.

Next we hit the 'if' statement. Is i == 1? Yes it is!
so then we load the current millis value into previousMillis.
we hit the next if statement and no, i is not equal to 2 yet so we skip it.
the next if subtracts previousMillis from currentMillis

Well no, because you are still in the loop. You execute the loop 3 times before doing anything else.

  • First iteration: do nothing
  • Second iteration (i == 1): previousMillis = millis();
  • Third iteration (i == 2): currentMillis = millis();

That loop has achieved nothing at all. It doesn't do one iteration when you call the function the first time, and so on. It does 3 iterations each time you call the function.

If the variables are lost each time the function is called then I just need to make i and previousMillis global variables right?

You could do that, or make them static like I said above.


unsigned int getHumidity() {
...
  if (whatever) {       //The sensor needs at least 250 mills between readings
  }
  else {
    getHumidity();
  }
}

This is recursing, that is the function is calling itself. You will very very quickly use up your stack space and crash, if it does that more than a few times.


Bearing in mind that you seem to have a delay in your main loop, all this other stuff is not needed. How about replacing the entire function by:

unsigned int getHumidity() {
  return dht.readHumidity();
}
  for (i = 0; i < 1; i++) {
    if (i == 1) {
      previousMillis = millis();
    }

Make a loop that executes once. What does that achieve?

    if (i == 1) {

The loop exits when i == 1 so this will never be true, so you may as well omit it.

Seriously, and I don’t mean to be unkind, read up some C or C++ tutorials. Your code is extremely complex, and it looks like you are throwing in loops because you heard about them somewhere.

You seem to have made getHumidity( ) into a recursive function. That is generally a bad idea.