I am setting up some code where each day (for 14 days) a variable (Tset) is given a value specified in an array (TempProg) containing the 14 values. I have a RTC on the project so I can determine the starting day and the current day and calculate the difference. See basic code example below.
The obvious limitation of this method is that I cannot work between months (if StartDay =28, now.day() = 3, I would get negative values). So how can I count the number of days that have passed (even between months) so that the correct value in the array is used?
I like the idea of using the clock to determine the day, rather than counting 1440 minutes from the start to specify that 24 hrs (1 day) has passed, because I don't want to build the code around absolute 24 hour periods. Even if the code is started at 23:00 on day 1, I want it to switch to "day 2" in one hour and use the appropriate value in the array.
I'm sure there is some "trick" that I'm not seeing for doing this. Maybe someone else has some insight.
Thanks so much,
Nate
int TempProg[] = {26,27,29,22,24,30,18,24,23,29,22,23,26,29};
int StartDay;
int Tset;
void setup(){
Serial.begin(115200);
Wire.begin();
RTC.begin(); //Start clock
DateTime now = RTC.now(); //specify "now" as the current datetime
StartDay = now.day(); //get current day
}
void loop() {
DateTime now = RTC.now();
int elapsed_days = now.day() - StartDay; //calculate difference between current day and start day as elapsed days
Tset = TempProg[elapsed_days]; // set Tset to the appropriate value from TempProg array
}
Even if the code is started at 23:00 on day 1, I want it to switch to "day 2" in one hour and use the appropriate value in the array.
I may have misunderstood what you are trying to do but would it not be good enough just to trigger the daily event when the program is started then when the hour goes from 23 to 00 ? Does it matter what Month it is ?
No, you are very correct. It does not matter the month. That sounds like reasonable solution.
How would I apply such a trigger? I assume with a comparison between the current hour and the previous hour, but I'm having a hard time envisioning how to code that and then move through the array.
Read the hour from the RTC each time through loop(). Compare the current hour with the previous time you read it. If the previous hour was 23 and the current hour is 0 (may need to be 00) then increment the index to the array. If not, save the current hour as the previous hour and go round loop() again.
An alternative would be to use the TimeAlarms library and trigger a repeating daily alarm at the appropriate time to increment the array index.
For now I'm using the TimerAlarms.h method, but if I get tight on memory I may go to the first method you suggested which doesn't require loading the additional libraries (Time.h, and TimeAlarms.h).
For those interested here's the general approach.
int previous = 0;
int TempProg[] = {26,27,29,22,24,22,26,30,32,28,24,22,21,24};
int Tset=TempProg[0];
void setup(){
Serial.begin(115200);
Wire.begin();
RTC.begin(); //Start clock
DateTime now = RTC.now(); //specify "now" as the current datetime
setTime(now.hour(),now.minute(), now.second(), now.month(), now.day(), now.year());
Alarm.alarmRepeat(23,59,59, newTset);
}
void loop() {
}
void newTset() {
int next = previous + 1;
Tset = TempProg[next];
previous = next;
}
Both good points.
In the posted code I had removed the Alarm.delay() line and all other loop() code, but for completeness I should have left at least Alarm.delay in.
I have just added a section which reset the array index when it reaches the limit. Thank you, that is a good practice, though I do plan to stop the experiment at the end of array.
I assume with a comparison between the current hour and the previous hour, but I'm having a hard time envisioning how to code that and then move through the array.
I'm not understanding why you need an array at all, if you only want to do something (count?) when the day changes (as it does when the hour ibecomes 0).
The question was actually in two parts. The first was the primary issue and involved identifying the number of days that had passed (not in absolute time, but in calendar days) since the code had started. This was then used to reference that day's value from the array.
So you are right, the array is not necessary for counting days, but the final goal was not counting days. Counting days was simply a necessary step to reach the final goal of properly specifying each calendar day's specific Tset value from an array.
The method to find the number of days when the period spans more than one month is to
do your subtraction as normal.
if you get a negative result (<0), add the number of days in the previous month to the result.
E.g. 28th September to 3rd October
3 - 28 = -25 (a negative result, so must have gone into the next month)
-25 +30 (September has 30 days) = 5
February is a little more complicated, as you have to take the leap year into account. If (year %4 == 0) then +1 day can be used to account for the leap day. That will be good until 28/2/2100
Very nice! I like it, though it is a bit involved, what with having to keep track of how many days are in the previous month etc.
Still I knew there should be a way to do this simply (if not simply) with mathematics, but was unable to see it for myself. Thank you for the insight and I hope I would be able to use this as inspiration in future coding endeavors.
natemiller77:
Very nice! I like it, though it is a bit involved, what with having to keep track of how many days are in the previous month etc.
Keep the number of days per month in an array (31,28,31,30, etc) and index into it by: (previous month = this month - 1 ) -1 (to account for the array index starting at 0). Don't forget to allow for the month change at the new year: if(this month == 1) then previous month = 12.
Still I knew there should be a way to do this simply (if not simply) with mathematics, but was unable to see it for myself. Thank you for the insight and I hope I would be able to use this as inspiration in future coding endeavors.
I presume you don't need the maths for dates past 28/02/2100.
Thanks for your help and sorry I didn't get back in touch. Here's what I have put together for this (see code below). I'm running up against memory limitations so I am trying to streamline as much of this as I can. I realize using two arrays (one for leap years and one for non-leap years) is probably not efficient, or really appropriate, but I'm not certain how I could simply out 28 or 29 and whether doing that with a set of if statements uses less memory that simply having these two arrays.
Any thoughts on the proper structure for this function? Any other areas that could be refined? I'm trying to learn better, more efficient coding practice, so any comments on how to make this better would be appreciated.
Thanks,
Nate
void newTmax() {
DateTime now = RTC.now(); //get time
int MonthDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; //specify days in each month
int MonthDays_leap[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; //specify days in each month in leap year
int today = now.day(); //define today's numerical day
int elapsedDays = today - startDay; //calculate the number of elapsed days since the start day
int previous_month = (now.month() - 1) - 1; //calculate the index for the previous month (keeping in mind
//that the indexing starts at 0
if (now.month() == 1) { //if the current month is 1, the previous month was 12
previous_month = 12;
}
//if in the above substraction elapsed days is <0 the experiment has gone into a second month (start = 28, today = 2,
//elapsedDays = 2-28 = -26. Additionally if the current year is divisible evenly by 4, its a leap year and Feb has 28
//days. The number of elapsed days if you have gone into a new month is the negative value from substraction, plus the
//number of days in the previous month. The code below applies this math, keeping track of leap years.
if (elapsedDays < 0 && now.year() % 4 == 0) {
elapsedDays = elapsedDays + MonthDays_leap[previous_month];
} else if (elapsedDays < 0 && now.year() % 4 != 0) {
elapsedDays = elapsedDays + MonthDays[previous_month];
} else if (elapsedDays >= 0) {
elapsedDays = today - startDay;
}
if (elapsedDays > TempProgSize) { //if the elapsed days exceed the number of assigned temperature
elapsedDays = 0; //values, use a roll-over and go back to the beginning.
}
Tmax = TempProg[elapsedDays]; //once you have determined what day of the experiment you are in
} //select that value from the TempProg array
void newTmax() {
DateTime now = RTC.now(); //get time
byte MonthDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; //specify days in each month
if(now.year() % 4 == 0) { //if its a leap year assign February (entry [1]) 29 days
MonthDays[1] = 29;
}
int today = now.day(); //define today's numerical day
int elapsedDays = today - startDay; //calculate the number of elapsed days since the start day
int previous_month = (now.month() - 1) - 1; //calculate the index for the previous month (keeping in mind
//that the indexing starts at 0
if (now.month() == 1) { //if the current month is 1, the previous month was 12
previous_month = 12;
}
//if in the above substraction elapsed days is <0 the experiment has gone into a second month (start = 28, today = 2,
//elapsedDays = 2-28 = -26. Additionally if the current year is divisible evenly by 4, its a leap year and Feb has 28
//days. The number of elapsed days if you have gone into a new month is the negative value from substraction, plus the
//number of days in the previous month. The code below applies this math, keeping track of leap years.
if (elapsedDays < 0 ) {
elapsedDays = elapsedDays + MonthDays[previous_month];
} else if (elapsedDays >= 0) {
elapsedDays = today - startDay;
}
if (elapsedDays > TempProgSize) { //if the elapsed days exceed the number of assigned temperature
elapsedDays = 0; //values, use a roll-over and go back to the beginning.
}
Tmax = TempProg[elapsedDays]; //once you have determined what day of the experiment you are in
} //select that value from the TempProg array
int previous_month = (now.month() - 1) - 1; //calculate the index for the previous month (keeping in mind
//that the indexing starts at 0
if (now.month() == 1) { //if the current month is 1, the previous month was 12
previous_month = 12;
}
Question: If the month index is zero based, why is December 12? Shouldn't it be 11?
BTW untested but I think you can simplify the bottom part of your code to something like this:
[...]
if (elapsedDays < 0) {
elapsedDays += MonthDays[previous_month]; // Start w/ days from previous month
if ((previous_month == 2) && (now.year() % 4) == 0) // Is it a leap year?
elapsedDays++; // Yes. Add 1 more day.
}
if (elapsedDays > TempProgSize) { //if the elapsed days exceed the number of assigned temperature
elapsedDays = 0; //values, use a roll-over and go back to the beginning.
}
Tmax = TempProg[elapsedDays]; //once you have determined what day of the experiment you are in
} //select that value from the TempProg
Regards,
Brad
KF7FER
EDIT: Removed else clause from first "if" since elapsedDays was already set correctly.