state function

I need a function to be performed only once every day, using time from a RTC (DS3231).
I read following code by bricoleau in How do I create an if statement based on RTC time? - Programming Questions - Arduino Forum using a state function:

  static byte trigger = 1;

  if(now.hour() > 20 || (now.hour() == 20 && now.minute() >= 12)){
    if (trigger) {
      event();
      trigger = 0;
    }
  }
  else {
    trigger = 1;
  }

Does the first statement static byte trigger = 1; have to be placed in setup?

If it is in the same loop as the if function, I think trigger will always be set to 1 at every loop?

Also I do not understand how the conditions in the if statement would make this function be performed just once per day?

And how does this if function have to be defined to run once an hour? Like this:? if (now.minute() == 12) ?

brice3010:
Does the first statement

static byte trigger = 1;

have to be placed in setup?

If it is in the same loop as the if function, I think trigger will always be set to 1 at every loop?

No, that’s the purpose of the ‘static’ keyword.

and a static variable is initialised once at compile time only.

6v6gt:
and a static variable is initialised once at compile time only.

aaaaaaaaaaaaaaahhhh ;D great big light shining now, thanks both of you.

Now the other question: how do the conditions in the first if by bricoleau get this condition being met only once per day?

have to be placed in setup?
Place this in a function that runs regularly.

static keeps the variable from resetting.
Set trigger = 1; after the alarm time, then things will happen only once.

Use a Flag variable to enable once per hour operation.
if (now.minute() == 12 && enableFlag == true)
{
enableFlag = false; //disable this condition
. . .
}
if (now.minute() == 13) // at this time we are free to enable the flag again
{
enableFlag = true;
}

larryd:
(...)

Use a Flag variable to enable once per hour operation.
if (now.minute() == 12 && enableFlag == true)
{
enableFlag = false; //disable this condition
. . .
}
if (now.minute() == 13) // at this time we are free to enable the flag again
{
enableFlag = true;
}

But this is another way of writing bricoleau's state function?
Here enableFlag must be 1 first time, then it is set by the if function loop? So instead of "trigger", you use "enableFlag"?

Pretend you’re the processor and step through it manually. Repeatedly enter ‘loop()’ from the top and execute each statement in sequence – just like the processors does. Keep track of hours, minutes, and trigger on a piece of paper.

Watch what happens as you enter loop() before the time is 20:12.

Watch what happens as you enter loop() the FIRST time that time equals 20:12.

Watch what happens as you enter loop() the on subsequent times that time equals 20:12.

Watch what happens as you enter loop() when the time is greater than 20:12.

Watch what happens as you enter loop() the FIRST time that time equals 00:00.

Repeat the cycle. You might just have another aaaaaaaaaaaaaaahhhh moment.

gfvalvo:
Pretend you’re the processor and step through it manually. Repeatedly enter ‘loop()’ from the top and execute each statement in sequence -- just like the processors does. Keep track of hours, minutes, and trigger on a piece of paper.

Watch what happens as you enter loop() before the time is 20:12.

Watch what happens as you enter loop() the FIRST time that time equals 20:12.

Watch what happens as you enter loop() the on subsequent times that time equals 20:12.

Watch what happens as you enter loop() when the time is greater than 20:12.

Watch what happens as you enter loop() the FIRST time that time equals 00:00.

Repeat the cycle. You might just have another aaaaaaaaaaaaaaahhhh moment.

Indeed, you just got another kudo ;D thanks!! I will remember this post forever.

Here enableFlag must be 1 first time, then it is set by the if function loop? So instead of “trigger”, you use “enableFlag”?

You can use as many flags as you need.

A flag can also be a number, ex:

if (counter < 4 && now.minute() == 12) //happens 4 (0-3) times at 12 min after the hour 
{ 
  counter++;
  . . . 
}

if (counter != 0 && now.minute() == 13) //at this time we are free to enable the flag again
{
   counter = 0;
}

A flag allows something to happen at a ‘given time’.
You then disable the flag.
You then enable the flag as needed after the ‘given time’ has past.

You could also do something like this with the dateTime library:
(untested)

setup()
{
time_t eventTime = makeTime(&tm); // time of day that you want an event
}

loop()
{
...
if (now() >= eventTime)
  {
  eventTime += SECS_PER_DAY;
  doDailyEventStuff();
  }
...
}

aarg:
You could also do something like this with the dateTime library:
(untested)

setup()

{
time_t eventTime = makeTime(&tm); // time of day that you want an event
}

loop()
{
...
if (now() >= eventTime)
  {
  eventTime += SECS_PER_DAY;
  doDailyEventStuff();
  }
...
}

Hi aarg, nice to know. But in this case I use no library for DS3231; just #define DS3231_I2C_ADDRESS 0x68
and direct register requests. The example by bricoleau had been adjusted by me for that purpose in my actual program.
I use

  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set DS3231 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);

..from :https://tronixlabs.com.au/news/tutorial-using-ds1307-and-ds3231-realtime-clock-modules-with-arduino/

Actually, if you use == you risk the chance of missing the target time if the processor is busy doing something else. If you use > or >= you solve that problem.

aarg:
Actually, if you use == you risk the chance of missing the target time if the processor is busy doing something else. If you use > or >= you solve that problem.

Thanks!! Very useful.. But I guess this applies for seconds, not for minutes or hours?

brice3010:
Thanks!! Very useful.. But I guess this applies for seconds, not for minutes or hours?

Yes, but it's harmless and more straightforward to use >= for those also.

aarg:
Yes, but it's harmless and more straightforward to use >= for those also.

But not in the case of bricoleau's example:

static byte trigger = 1;

  if(now.hour() > 20 || (now.hour() == 20 && now.minute() >= 12)){
    if (trigger) {
      event();
      trigger = 0;
    }
  }
  else {
    trigger = 1;
  }

This only works if now.hour()== 20 etc..
Or am i wrong?

brice3010:
But not in the case of bricoleau's example:

static byte trigger = 1;

if(now.hour() > 20 || (now.hour() == 20 && now.minute() >= 12)){
    if (trigger) {
      event();
      trigger = 0;
    }
  }
  else {
    trigger = 1;
  }



This only works if now.hour()== 20 etc..
Or am i wrong?

It looks to me like this would trigger any time the hour is greater than 20. Seems strange. Am I wrong? Isn't the idea to restrict it to a specific hour, minute and second?

aarg:
It looks to me like this would trigger any time the hour is greater than 20. Seems strange. Am I wrong? Isn't the idea to restrict it to a specific hour, minute and second?

Have a look at post#6; I did the check and it only triggers once, when it is 20:12.

brice3010:
Have a look at post#6; I did the check and it only triggers once, when it is 20:12.

Edit - that is because 20:10 is still less than 21:00

My question is, why is that check in there at all? It makes no sense. This code will trigger twice, once at 20:12, and once again at 21:00. Is that what you want?

aarg:
How do you explain that? When one input to a logical "or" is true, the other is a "don't care".

Copied from gfvalvo:

Watch what happens as you enter loop() before the time is 20:12. event not executed

Watch what happens as you enter loop() the FIRST time that time equals 20:12. event executed, trigger=0

Watch what happens as you enter loop() the on subsequent times that time equals 20:12. event not executed

Watch what happens as you enter loop() when the time is greater than 20:12. event not executed

Watch what happens as you enter loop() the FIRST time that time equals 00:00. trigger set to 1

Read what I said instead of just parroting someone. Unless you missed my edit, in which case, sorry. This code will trigger an event twice a day.