Go Down

Topic: Time and TimeAlarms Libraries – Ask here for help or suggestions (Read 216990 times) previous topic - next topic

Bob808

Creating redundancy for a program that spans from one day to the other is plain crazy.
Assuming start hour is 9 in the morning and end hour is 8 in the evening everything is good as it's a 24 hour format. IF(start hour<reset hour && stop hour > reset hour) then run function.
Get's a bit messy when start hour is 9:30 and stop hour is 20:30. As you can have a reset at 9:45 and you need to get into minutes conditions.
And then everything goes haywire when your start program is at 22 hours and stop program is at 3 in the morning, and the reset happens in between.

PaulS

Quote
And then everything goes haywire when your start program is at 22 hours and stop program is at 3 in the morning, and the reset happens in between.

I don't see why. You know something needs to start at some time. If it is that time, start it.
You know something needs to end at some time. If it is that time, stop it.

I think your problem is that you are thinking in terms of "it needs to start at x:xx and end at x:xx, and be called over and over again in between.

That's not the best way to do that. Think in terns of setting a thisProcessShoudlBeRunning flag to true if it is 9:00PM. Set it to false if it is 3:00AM.

Then, independent of the time, test the flag to see if the process should be running.
The art of getting good answers lies in asking good questions.

Bob808

I don't know flags :)
So I should study some more.
I nailed the start stop time at the moment, it's doing it's job. Right now I'm interested in checking to see if it needs to be continuing the program at any power failure so I need to look into what you said.

I made it easier to compare times by creating a longer number from hours and minutes.
Code: [Select]

   int time = hour()*10000 + minute()*100 + second();
   int on = onH*10000 + onM*100;
   int off = offH*10000 + offM*100;

if (time == on)
{
  LightsOn();
}
if (time==off)
{
LightsOff();
}

For the start-up check I only used hours and minutes:
Code: [Select]

int time = hour()*100 + minute();
int on = onH*100 + onM;
int off = offH*100 + offM;

Bob808

#303
Sep 18, 2014, 01:42 am Last Edit: Sep 18, 2014, 01:48 am by Bob808 Reason: 1
the only thing in loop is the time comparing algorithm, and the math. the function gets called for the duration of a second when the time comes, and the off function as well. I don't know if there's a more efficient way to do it only for calling two functions at certain times. It may be, but I can't think of any.
It may be another way that incorporates the redundancy check and calls the functions at certain times, but I have no idea at the moment.


edit:
forgot to mention a critical aspect. the purpose of the contraption :)
So, it's meant to be used for an aquarium. Light/pump/feeder :)
At the moment I can scale the pump, I make it the same as the light, should be on for some time.
But the feeder is another story, as it has a short program of few seconds. If feeder is supposed to run at 10 o'clock and I have a power failure from 9:30 to 10:30 then the fish miss their breakfast :) And I'd worry while on vacation as power outs are common here.
So I'd have to implement some check bits that are written whenever it ran?

cattledog

Quote
I don't know if there's a more efficient way to do it only for calling two functions at certain times. It may be, but I can't think of any.


Quote
I don't know flags smiley
So I should study some more.


The way to call your functions only once instead of multiple times in the one second where your test conditions match the reading of the clock is to use a flag.

Take a look at this post by JimboZA  http://forum.arduino.cc/index.php?topic=267077.msg1883433#msg1883433  which discusses using flags for just this purpose.

Bob808

Ok, I kind of got it, it's like a light switch but how does that help my redundancy?
I can't quite figure it out how to implement it, I mean the logic behind it.
The only benefit of flags right now is that the function gets called only once, not for a whole second (which is not much anyway, but for efficiency's sake let's say I'll do it).

JimboZA


The only benefit of flags right now is that the function gets called only once, not for a whole second (which is not much anyway, but for efficiency's sake let's say I'll do it).


Well it's more than that.... if you're switching on an LED at the start of the appropriate second and leaving it on for 5 minutes, yeah it's just a waste of effort but maybe no biggy if you re-switch it on a zillion times. But  in my case I was writing an eeprom and they have a limited number of writes before they wear out. In fact, an Arduino built-in eeprom can take 100k writes: loop() runs faster than 150k per second, so if I didn't prevent the writes after the first time, I'd wear out the eeprom in under a second. (Apart from the fact that I wanted the temp written at a specific time, not a minute later.)
Johannesburg hams call me: ZS6JMB on Highveld rep 145.7875 (-600 & 88.5 tone)
Dr Perry Cox: "Help me to help you, help me to help you...."
Your answer may already be here: https://forum.arduino.cc/index.php?topic=384198.0

Bob808

Oh yes, I can totally understand that. I don't even use the eeprom on the RTC pcb :) as I don't want to "consume" it by mistake. I just use a breadboarded one.
Writing on EEPROM should only be called once if it is enough.
I'm just switching pins on and off so it really doesn't matter. But I want to get familiar with flags as I always wondered if I have something in loop and I need it to have a delay, then it would delay the whole loop so that's not always good.

Bob808

#308
Sep 19, 2014, 12:32 am Last Edit: Sep 19, 2014, 01:11 am by Bob808 Reason: 1
I guess I've done it with flags. This way it works, I set the time, when the time comes the function gets called, the LED is on. When the Off time comes, LED goes off.
Also I've watched in console, the function gets called only one time, and the flag stays on for the whole second. For the OFF I've switched values as I'm using the flag value for the pin output value.
Here's a bit of code, tell me please if it's correctly implemented.



Code: [Select]
.............................
boolean alarm = false;
boolean alarm2 = true;
..............................................
void loop ()
{
...................................................
  readEEPROM(addr,0);          
   onH=rec;                
   readEEPROM(addr,1);        
   onM=rec;                
   readEEPROM(addr,2);        
   offH=rec;
   readEEPROM(addr,3);        
   offM=rec;

  int time = hour()*10000 + minute()*100+second();
  int on = onH*10000 + onM*100;
  int off = offH*10000 + offM*100;

if (time == on)
     {
             if(alarm == false)
                   {
                           alarm = true;
                           LightsOn();
                   }
      }
if (time !=on)
      {
              alarm= false;
       }

if (time==off)
      {
               if(alarm2==true)
                      {
                             alarm2 = false;
                             LightsOff();
                       }
        }
if(time !=off)
        {
 alarm2=true;
        }
}

void LightsOn()
          {                        
                 digitalWrite(light, alarm);
                 Serial.println("Lights On");
           }

void LightsOff()
         {                        
                 digitalWrite(light, alarm2);
                 Serial.println("Lights Off");  
          }





//later edit:
No, I didn't have it, but now I think I do. Each time on or off function are called they flip the flag.


Code: [Select]
.............................
boolean flag = false;

..............................................
void loop ()
{
...................................................
  readEEPROM(addr,0);          
   onH=rec;                
   readEEPROM(addr,1);        
   onM=rec;                
   readEEPROM(addr,2);        
   offH=rec;
   readEEPROM(addr,3);        
   offM=rec;

  int time = hour()*10000 + minute()*100+second();
  int on = onH*10000 + onM*100;
  int off = offH*10000 + offM*100;

if (time == on)
     {
             if(flag == false)
                   {                            
                           LightsOn();
                           flag = true;
                   }
      }


if (time==off)
      {
               if(flag == true)
                      {                              
                             LightsOff();
                             flag = false;
                       }
        }

}

void LightsOn()
          {                        
                 digitalWrite(light, HIGH);
                 Serial.println("Lights On");
           }

void LightsOff()
         {                        
                 digitalWrite(light, LOW);
                 Serial.println("Lights Off");  
          }

Bob808

#309
Sep 19, 2014, 01:28 am Last Edit: Sep 19, 2014, 01:46 am by Bob808 Reason: 1
And I think I nailed the redundancy as well.
Since I'm comparing integers instead of hours & minutes separately it's easier.
First, I need to write the flag to EEPROM each time it's changed. I guess that wouldn't be many writes for two on/off cycles a day.

This would be the code that takes care of power losses:

Code: [Select]
if (time > on && flag == true)
 {
     LightsOn();
 }
if (time < on && flag == true)
 {
   LightsOn();
 }


//later edit:

no, not enough, if the power-out began before the on function could run, the flag would be still false. and if it runs and the flag is true and then in the middle of the program the power goes out, it has a true flag, but it still has to run it.

Bob808

I think I'm done this time with redundancy. It works out.
I also added a poorly made paint visual for all 8 cases that might happen at boot. Two major cases, where On time is smaller than Off time, and in reverse. One could call them "day time" and "night time". Each have their quirks.
In the photo there's the 24 hour span black line, the red line is the normal program of the light. The thicker black lines represent blackout periods, green 0/1 are the normal flags corresponding to each on/off state of the light and the blue 0/1 are the flags  read at boot from blackout.
I tested the code in a normal on<off flag=1 and on<reset<off and it triggered the LED.

Code: [Select]

boolean flag = false;
.............................
void setup(){
.............................
    readEEPROM(addr,0);         
    onH=rec;               
    readEEPROM(addr,1);         
    onM=rec;               
    readEEPROM(addr,2);         
    offH=rec;
    readEEPROM(addr,3);       
    offM=rec;
int time = hour()*100 + minute();
int on = onH*100 + onM;
int off = offH*100 + offM;
readEEPROM(addr,4);
flag = rec;

if(on<off){
                    if(time>on && time <off && flag == 1)
                      {
                        LightsOn();
                      }
                     if(time>on && time<off && flag == 0)
                      {
                        LightsOn();
                        writeEEPROM(addr,4,1);
                      }
                     if(time>on && time>off && flag == 1)
                      {
                        writeEEPROM(addr,4,0);
                      }
                     if(time<on && time<off && flag == 1)
                      {
                        writeEEPROM(addr,4,0);
                      }
}

if(on>off){
                    if(time>on && time>off && flag == 1)
                    {
                       LightsOn();
                    }
                    if(time<on && time<off && flag == 1)
                    {
                      LightsOn();
                    }
                    if(time>on && time>off && flag == 0)
                    {
                      LightsOn();
                      writeEEPROM(addr,4,1);
                    }
                    if(time<on && time> off && flag == 1);
                    {
                      writeEEPROM(addr,4,0);
                    }
}
}
void loop () {
     readEEPROM(addr,0);         
    onH=rec;               
    readEEPROM(addr,1);         
    onM=rec;               
    readEEPROM(addr,2);         
    offH=rec;
    readEEPROM(addr,3);       
    offM=rec;
    readEEPROM(addr,4);
    flag=rec;
   int time = hour()*10000 + minute()*100+second();
   int on = onH*10000 + onM*100;
   int off = offH*10000 + offM*100;

if (time == on)
{
  if(flag == false)
  {
   
  LightsOn();
  flag = true;
  writeEEPROM(addr,4,1);
  }
}

if (time==off)
{
if(flag==true)
{
 
  LightsOff();
  flag = false;
  writeEEPROM(addr,4,0);
}
}
}


One think that I'd like to ask.
If I keep this in setup, it works at boot only. But I'd like to put it in loop so it updates when I change the times from the LCD menu.
Is it too much for the processor? Also I will add the pump as well and the feeder (that's another story, should be easier).

PaulS

A couple of suggestions. First:
Code: [Select]
    readEEPROM(addr,0);         
    onH=rec;               

is silly. readEEPROM() should not be writing to a global variable. It should be returning a value, so you can:
Code: [Select]
   onH = readEEPROM(addr, 0);

Second:
Code: [Select]
                    if(time>on && time <off && flag == 1)
flag is a boolean. You should be comparing to true or false, not 1 or 0. The comparison is not needed, anyway. flag == true will result in true only if flag contains true, so the == true but is unnecessary. As far as comparing to false, use !flag rather than flag == false.
The art of getting good answers lies in asking good questions.

Bob808

Like this?

Code: [Select]

............................
void setup()
{
............................
    onH=readEEPROM(addr,0);                         
    onM=readEEPROM(addr,1);                           
    offH= readEEPROM(addr,2);           
    offM=readEEPROM(addr,3);   
    flag = readEEPROM(addr,4);
  int time = hour()*100 + minute();
  int on = onH*100 + onM;
  int off = offH*100 + offM;

if(on<off){
                    if(time>on && time <off && flag)
                      {
                        LightsOn();
                      }
                     if(time>on && time<off && !flag)
                      {
                        LightsOn();
                        writeEEPROM(addr,4,1);
                      }
                     if(time>on && time>off && flag)
                      {
                        writeEEPROM(addr,4,0);
                      }
                     if(time<on && time<off && flag)
                      {
                        writeEEPROM(addr,4,0);
                      }
}

if(on>off){
                    if(time>on && time>off && flag)
                    {
                       LightsOn();
                    }
                    if(time<on && time<off && flag)
                    {
                      LightsOn();
                    }
                    if(time>on && time>off && !flag)
                    {
                      LightsOn();
                      writeEEPROM(addr,4,1);
                    }
                    if(time<on && time> off && flag);
                    {
                      writeEEPROM(addr,4,0);
                    }
}
}
void loop () {
...............................
    onH= readEEPROM(addr,0);             
    onM= readEEPROM(addr,1);             
    offH=readEEPROM(addr,2);   
    offM=readEEPROM(addr,3);
    flag=readEEPROM(addr,4);
   int time = hour()*10000 + minute()*100+second();
   int on = onH*10000 + onM*100;
   int off = offH*10000 + offM*100;

if (time == on)
{
  if(!flag)
  {
  LightsOn();
  flag;
  writeEEPROM(addr,4,1);
  }
}
if (time==off)
{
if(flag)
{
  LightsOff();
  !flag;
  writeEEPROM(addr,4,0);
}
}
}


PaulS

Quote
Like this?

Assuming you've made the necessary changes to readEEPROM(), almost.

Code: [Select]
                    if(time>on && time <off && flag)
                      {
                        LightsOn();
                      }
                     if(time>on && time<off && !flag)
                      {
                        LightsOn();
                        writeEEPROM(addr,4,1);
                      }
                     if(time>on && time>off && flag)
                      {
                        writeEEPROM(addr,4,0);
                      }
                     if(time<on && time<off && flag)
                      {
                        writeEEPROM(addr,4,0);
                      }

I don't like compound ifs, if they can be avoided, and they can here,

Code: [Select]
if(time>on && time <off)
{
   if(flag)
  {
  }
  else
  {
  }
}
else if(...


Alternatively, decide if flag is the first filter, and then decide on an action based on time in the if(flag) body.

Code: [Select]
  flag;
does nothing.

Code: [Select]
  !flag;
does nothing.
The art of getting good answers lies in asking good questions.

Bob808

I got carried away with flag and !flag :)

Code: [Select]


if(on<off){
                    if(time>on && time <off){                 
                        if(flag)
                        {  LightsOn(); }                       
                                                             }
          else if(time>on && time<off){
                        if(!flag)
                        {     LightsOn();
                              writeEEPROM(addr,4,1);}
                                                           }
         else if(time>on && time>off){
                        if(flag)
                         {writeEEPROM(addr,4,0);}
                                                          }
        else if(time<on && time<off){
                      if(flag)
                      {writeEEPROM(addr,4,0);}
                                                        }
          }

if(on>off){
                    if(time>on && time>off){
                      if(flag)
                      {LightsOn();}
                                                            }                   
            else if(time<on && time<off){
                      if(flag)
                      {LightsOn();}
                                                            }
           else if(time>on && time>off){
                      if(!flag)
                      {LightsOn();
                      writeEEPROM(addr,4,1);}
                                                           }                   
          else if(time<on && time> off){
                      if(flag)
                      {writeEEPROM(addr,4,0);}
                                                          }
}



and

Code: [Select]
byte readEEPROM(int addr, unsigned int eeaddress)                //EEPROM read function
  {
  Wire.beginTransmission(addr);
  Wire.write((int)(eeaddress >> 8));
  Wire.write((int)(eeaddress & 0xFF));
  Wire.endTransmission();
  Wire.requestFrom(addr, 1);
  Wire.read();
  }

Go Up