Greetings everyone. Been toiling many hours to solve a problem with the cycle timer portion of my multi-function garden controller project. The finished code is lengthy but is attached in my second post.
the cycle timer which operates a fan - is dependent on the lighting on and off times in the code.
the lighting timer portion of the code is working - just the cycle timer is the problem.
General overview:
Press button
5 - set lights on time
6 - set lights off time
7 - set cycle time - ie. cycle every x hours
8 - set cycle on time - ie. on for x minutes
By default the fan cycle timer is designed to run only during lights on hours.
Working on a 24 hour timer - I need to be able to, if say I've set the lights on at 09:00 and off at 22:00 and the fan to cycle once every two hours for 15 minutes - that part I can do and make it work - for a 1 to 4 hour cycle timer with a whole bunch of messy code but still the real problem is when the lights are set to on at say 10:00 and off at 04:00 then I'm a little lost. I will be honest, the clock is someone else' creation entirely but the rest came with a lot of research and learning so please know, I am still new to this and are not looking for any handouts - just some guidance.
Here is the section for fan cycle - I have turned some things off but just to show where i'm trying to go with it .
//*************** Fan Cycle****************
{
initial_lightsOn[ad7] = EEPROM.read(ad7);
init_lightsOn = initial_lightsOn[ad7];
initial_lightsOff[ad8] = EEPROM.read(ad8);
init_lightsOff = initial_lightsOff[ad8];
initial_fanCyc_time[ad9] = EEPROM.read(ad9);
init_fanCyc_Time = initial_fanCyc_time[ad9];
initial_fanOn_time[ad10] = EEPROM.read(ad10);
init_fanOn_Time = initial_fanOn_time[ad10];
if (init_lightsOff >= 12)
// int j = init_fanCyc_Time;
//int k = i * j;
for (int i = 0; i <= 24; i++) {
if ((Hour == (init_lightsOn + i)) && (Min < init_fanOn_Time) && (relayState4 = HIGH))
relayState4 = LOW;
else
//if (Min >= init_fanOn_Time)
// relayState4 = HIGH;
digitalWrite(relay4, relayState4);
Serial.print(i);
//delay(100);
}
}
apparently too big to submit so I can only submit a snipet. If more is needed please say and I can add more.
If you are looking for snippets of answers, then what you posted is fine. If you want a complete answer, you'll go read the stickies that you were supposed to read before posting, and learn what to do to post ALL of your code.
It would be far simpler to change all of your hour:minute on and off times to minutes since midnight.
You clearly need to break your code into functions, and call some of them conditionally. There is, for example, no reason to call the function that determines whether the fan should be turned on or off if it is dark.
One should, using your system, NOT be allowed to set an off time that is earlier than the on time. You are obviously allowing that now. If the lights need to be on from 10PM to 4AM, then there are TWO cycles - one from 10PM to midnight and one from midnight to 4AM.
...and sorry, should have mentioned that with the lights on-time setting at 10:00 AM and off-time setting at 04:00 AM - off-time needs to happen the following day.
Also, I've been trying to find a way to get the relayState to stay LOW after the first pass through the for loop and not go HIGH until after init_fanCycle_Time has ended and then stay HIGH until the next cycle - it would seem if I can find a way to do that then I just need to compare with init_fanOn_Time, init_lightsOn and dayupg?
Thinking about this now... the real problem I'm having is getting the relayState to stay LOW after the first pass. If I can get that to happen then everything else should fall into place.
These names don't mean a thing. A one letter, meaningless, name maps to an address at run time. So does a 47 letter descriptive name. You are not saving anything by using meaningless names.
You need to get in the habit, now, of properly indenting your code. Two if statements on adjacent lines do NOT start in the same column.
You also need to get in the habit of always using curly braces after if and for statements, even if there is only one statement in the body.
Here are the latest changes.
The top portion - if (init_lightsOff >= 12) works when lights off is set any time after noon 12:00 and before midnight or 00:00.
But the bottom portion - if (init_lightsOff <= 12) is not quite there yet - what I'm trying to do with (day = day + 1) is make it compare with init_lightsOff on the following day...I know is wishful thinking but is what needs to happen just not sure how.
if (init_lightsOff >= 12)
{
for (int i = 0; i <= 23; i++) {
int cyc = init_fanCyc_Time;
int val = i * cyc;
if ((Hour == (init_lightsOn + val)) && (Hour < init_lightsOff) && (Min < init_fanOn_Time) && (relayState4 = HIGH))
{
relayState4 = LOW;
} else {
if (Min >= init_fanOn_Time)
{
relayState4 = HIGH;
}
digitalWrite(relay4, relayState4);
}
}
}
if (init_lightsOff <= 12)
{
for (int i = 0; i <= 23; i++) {
int cyc = init_fanCyc_Time;
int val = i * cyc;
if ((Hour >= (init_lightsOn + val)) && (Min < init_fanOn_Time) && (relayState4 = HIGH)
|| (day = day + 1) && (Hour < init_lightsOff))
{
relayState4 = LOW;
} else {
if ((Hour > init_lightsOff) && (day = day + 1) && (Min >= init_fanOn_Time))
{
relayState4 = HIGH;
}
digitalWrite(relay4, relayState4);
}
}
}
}
Another good habit to get into is posting the whole sketch when you make changes. Working with snippets is too error prone.
Your names could use a bit more work too. Why use relay4 when you could use Fan or FanRelay or FanRelayPin? It's easier for me to understand and more importantly, may stop you making a silly avoidable mistake.
Ok, made some name changes to everything related to the cycle timer - should be much more clear.
Again, this is working code with the exception of the - if (init_lightsOff <= 12) section.
The (init_lightsOff >= 12)section functions properly when lights off is set to any time after 12:00 and before 00:00(midnight)....but the bottom section - if (init_lightsOff <= 12) will go LOW (function properly) for any lightsOn setting that is (Hour >= (init_lightsOn + val) but not functioning properly in the AM hours or if (Hour <= 12) - what I'm trying to do with (day = day + 1) is make it compare with init_lightsOff on the following day...this is what needs to happen somehow, I suspect.... just not sure how.
If someone is willing and able to help would be truly wonderful!
attached is the updated sketch.
For applications like this that run on a daily basis, it is much easier to use minutes past midnight for all times (1440 in a day). Of course you would use the RTC in 24 hour mode.
Rather than start and stop times, store a start time and interval length. The modulo (remainder) operator then automatically takes care of intervals that span midnight.
A simple program demonstrates this approach, turning a fan on at 23:58 and off again at 00:02. The "minutes past midnight" time is just calculated in a for loop.
It works for intervals that do not span midnight -- test this yourself.
This is easily extended to use seconds past midnight for higher accuracy.
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
unsigned int start_minutes = 23 * 60 + 58; //start at 23:58
unsigned int duration = 4; //off after 4 minutes at 0:02
Serial.print("start time in minutes past midnight ");
Serial.print(start_minutes);
Serial.print(", duration ");
Serial.println(duration);
for (int i = 0; i < 10; i++) { //counte some minutes, beginning at 23:57, modulo 1440
int now_minutes = (23 * 60 + 57 + i) % 1440; //time, minutes past midnight
Serial.print(now_minutes);
Serial.print("\t");
unsigned int t = (now_minutes - start_minutes + 1440) % 1440; //time on, modulo 1440
Serial.print( t );
Serial.print("\tfan state= ");
if ( t < duration) fan(1); //fan should be on
else fan(0); //fan should be off
}
}
void fan(int on) {
Serial.println(on);
}
void loop() {
// put your main code here, to run repeatedly:
Output:
start time in minutes past midnight 1438, duration 4
1437 1439 fan state= 0
1438 0 fan state= 1
1439 1 fan state= 1
0 2 fan state= 1
1 3 fan state= 1
2 4 fan state= 0
3 5 fan state= 0
4 6 fan state= 0
5 7 fan state= 0
6 8 fan state= 0
Simple function that encapsulates the above approach:
// timer_state function determines whether the current time in minutes past midnight
// is within the timed interval start and start+duration, also in minutes past midnight
// range may span midnight. duration must be less than one day (1440).
byte timer_state(unsigned int start, unsigned int duration, unsigned int now) {
unsigned int time_on = (now - start + 2880) % 1440; //multiply minutes per day by two for safety
if (time_on < duration) return 1; //within interval
return 0; //not within interval
}
Thank you, Mr Remington! You put me on a path that ultimately helped me think a few things through more logically based on the general needs the typical user of a garden controller. Been quite busy so don't think I gave up.
The cycle timer problem was resolved by taking PaulS' suggestion and eliminating the need to have it running only during lightsOn and instead made it run during lightsOn and lightsOff. But as I was adding hysteresis in the "fan cycle" and "temp and humidity controlled fan" section I noticed another issue - using the same fan relay activated by three separate snippets of code...but that's for my next post - hope to see you there.
jremington:
It works for intervals that do not span midnight -- test this yourself.
Thanks again for this jremington, I think it will resolve some bugs I'm getting in a different section altogether.
I've been trying to get this to work in my sketch but maybe this is my problem. What do you mean by span midnight? will only cycle within a 24 hour, 1440 min period of a daily set point...or?