I am trying to figure out timing for an egg incubator but i just cannot seem to correctly figure this out.
Using a Uno R3, 4x20 LCD, DS3231 rtc module.
On my LCD display i want to show on line 3 the lockdown day - something to show me the progress pre and after lockdown set.
I am using a DS3231 rtc module with the RTClib.h library.
The rtc alarm1 i am setting 19 days from the now() time as the lockdown time.
This alarm1 time is stored as dd as day and then time as hh:mm:ss
Alarm times does not store yyyy-mm
I have been trying to figure out the best way to display an upcoming lockdown and past lockdown time.
Here my dates is messing with me, example like yesterday the now() date was 31st, my alarm1 time were day 1 and time 10:30 then daysDiff would be 30 and should be 0 days difference.
There were a few other issues with this dates and every time figuring out a new approach but failing - now i need some masters help please.
Here is only the code concerning what i am trying as there are over a 1300 lines of code
DateTime now = rtc.now();
DateTime alarm1 = rtc.getAlarm1();
char alarm1Date[9] = "DD hh:mm";
alarm1.toString(alarm1Date);
int daysDiff = now.day() - alarm1.day();
Serial.print("daysDiff = ");
Serial.println(daysDiff);
Serial.println();
if (daysDiff < 0) {
// past lockdown time
lcd.setCursor(0, 2);
lcd.print("Set new Hatch Day!");
Serial.print("Condition 1");
}
if (daysDiff == 0 && now.hour() <= alarm1.hour() && now.minute() <= alarm1.minute()) {
// lockdown almost on hh:mm time
lcd.setCursor(0, 2);
lcd.print("Lockdown at: ");
lcd.print(alarm1.hour());
lcd.print(":");
lcd.print(alarm1.minute());
Serial.print("Condition 2");
}
if (daysDiff == 0 && now.hour() >= alarm1.hour() && now.minute() >= alarm1.minute()) {
// lockdown arrived
lcd.setCursor(0, 2);
lcd.print("Lockdown Time!");
Serial.print("Condition 3");
}
Indeed, the DS3231 allows you to set alarms based on a day of the month (1–31), day of the week , hours , minutes , and seconds , but not the month or year.
A simple solution when you set the alarm, would be to record in EEPROM the actual full information ➜ then it's trivial using the DateTime and TimeSpan classes to calculate the elapsed time between "now" and the set date.
Using UNIX time it becomes a unsigned 32 bit number. That can be shrunk bu eliminating the seconds and minutes if not needed. You can go online with a UNIX time calculator and simply enter the end and it will give you the time it is to trip in Unix time format. If you are using one of the ESP modules you can get the time from the internet.
I did play around but it will take some time to determine if the desired outcome would be displayed correctly - will try and try until i get some meaningful display.
timespan we need the full date
EEPROM... lets not use this for now
Connected to internet - no
I do have my code changed a bit, hopefully(hold thumbs) it could work.
DateTime now = rtc.now();
DateTime alarm1 = rtc.getAlarm1();
char alarm1Date[20]; // full date and time
// Calculate the year and month
int year = now.year();
int month = now.month();
if (alarm1.day() < now.day() || (alarm1.day() == now.day() && alarm1.hour() < now.hour()) || (alarm1.day() == now.day() && alarm1.hour() == now.hour() && alarm1.minute() < now.minute())) {
month++;
if (month > 12) {
month = 1;
year++;
}
}
// Format the date string
snprintf(alarm1Date, sizeof(alarm1Date), "%04d-%02d-%02d %02d:%02d:%02d", year, month, alarm1.day(), alarm1.hour(), alarm1.minute(), alarm1.second());
// Calculate the difference in seconds
DateTime fullAlarm1(year, month, alarm1.day(), alarm1.hour(), alarm1.minute(), alarm1.second());
TimeSpan timeDiff = fullAlarm1 - now;
// Convert the difference to days and hours
int daysDiff = timeDiff.days();
int hoursDiff = timeDiff.hours() % 24; // Get the remaining hours after full days
// Determine AM or PM
int alarmHour = alarm1.hour();
char period[] = "AM";
if (alarmHour >= 12) {
period[0] = 'P';
if (alarmHour > 12) {
alarmHour -= 12;
}
} else if (alarmHour == 0) {
alarmHour = 12;
}
Serial.println();
Serial.print("Alarm 1 Date: ");
Serial.println(alarm1Date);
Serial.print("daysDiff = ");
Serial.println(daysDiff);
Serial.print("Hours left: ");
Serial.println(hoursDiff);
if (daysDiff > 0) {
lcd.setCursor(0, 2);
lcd.print("Set new Hatch Day!");
Serial.print("Condition 1");
}
if (daysDiff == 0 && hoursDiff <= 24) {
lcd.setCursor(0, 2);
lcd.print("Lockdown at ");
lcd.print(alarm1.hour());
lcd.print(":");
lcd.print(alarm1.minute());
lcd.print(period);
Serial.print("Condition 2");
}
if (daysDiff == 0 && hoursDiff < 0) {
lcd.setCursor(0, 2);
lcd.print("Lockdown Time!");
Serial.print("Condition 3");
}
Serial.println();
how do you know a date has been set ? do you turn your arduino off ?
if you know there is a pending alarm and it was set for 19 days in the future, then you can indeed calculate when it was set based on the current time.
Alarm is set with a push button adding 19 days to the now() date
DateTime targetTime = now + TimeSpan(hatchdays, 0, 0, 0); // (dd, hh, mm, ss)
// Set Alarm 1 to trigger targetTime days from now with mode DS3231_A1_Date
rtc.setAlarm1(targetTime, DS3231_A1_Date);
hatchdays is value programmed into EEPROM
Testing over 2 days time i can get the dates example as the following,
Current time: 2024/9/4 8:38:15
Alarm 1 time: 2024/9/6 8:37:17
The issue would become if i set a new hatchdays (19 days) date in December, the rollover to 2025 as yyyy and month 1 as mm would be the issue as we specified the year and month as ```
int year = now.year();
int month = now.month();
If you know the alarm was not yet triggered then you know you are in the 19 days window before the alarm day.
You could do maths checking the current month and day and make guesses or a simple algorithm would be to try to guess:
You get the current day and set the hour min sec at the target date
You add 19 days and check if you have the target day. If not you subtract one day and test again. You do this until you hit the right day, it’s a simple while or for loop using DateTime and TimeSpan
It has already been mentioned that doing all your time calculations in Epoch Time rather than year, month, day, hour, minute, second would simplify your life greatly. That advice is still valid.
I'm tuning in late, and I don't see a complete sketch which would help me be sure when I say…
… in my experience, coming from the DS1307 which had no alarm functions, using them off the RTC is just way too much trouble.
If you are using the alarm interrupt to wake up a sleeping processor, that's one thing. If your device is on all the time, it is quite simple to compare times, so the alarm time can be held in a variable and directly compared to the time it is now, alarm!
A key here is using Unix Epoch time, the number of seconds since the beginning of time (1 JAN 1970) which (still) fits in a signed 32 bit integer.
These times can be directly compared ==, <, > and so forth.
Your RTC library may have convenient calls to work with epoch time, if not, there are those that do.
The serial result is 957279679 and this date is Tuesday, May 2, 2000 3:01:19 PM GMT
The alarm1 only has dd hh:mm:ss as 2 15:1:19
So then we created our "own" unix time
DateTime alarm1WithYearMonth(now.year(), now.month(), alarm1.day(), alarm1.hour(), alarm1.minute(), alarm1.second());
// Calculate the Unix time for the alarm with the current year and month
unsigned long alarmUnixTime = alarm1WithYearMonth.unixtime();
// Calculate the time difference in seconds
long timeSinceAlarm = currentUnixTime - alarmUnixTime;
Though i am busy testing the dates going into a new year i currently have:
Alarm 1 time: 2025/1/2 15:1:19
Now time: 2024/12/31 23:59:8
Showing a complete sketch will not help you much, this part of the code is sufficient i guess to calculating time differences and not any other confusing code to deal with.
Using the RTClib library this has no short comings as per data we can extract as per the rtc datasheet.