ezTime icon indicating copy to clipboard operation
ezTime copied to clipboard

secondChanged/minuteChanged triggeres not always

Open dakky opened this issue 4 years ago • 13 comments

Hello

I have a problem with the secondChanged method: in one method of my class it does return true only about every 2-5 minutes, in another method of the same class it triggeres as espected every second.

code sample (stripped down to the basics)

void AnyClass::methodA() {
    Serial.println("entered method A")
    uint8_t hours = clockTimezoned.hour();
    uint8_t minutes = clockTimezoned.minute();

    if (secondChanged()) {
        Serial.printf("Time %u:%u", hours, minutes);
    }
}

void AnyClass::methodB() {
    if (secondChanged()) {
        Serial.println("Testing B");
    }
}

the main loop:

loop() {
    events();
    AnyClass.methodA();
    AnyClass.methodB();
}

As result I see:

  • an enormous amount of entered method A, which is expected and serves only a proof, that this method is really called
  • every second Testing B which is also expected
  • every 2-5 minutes Time X:X, which is the problem.

Any idea whats wrong here and how to fix/debug this any further?

dakky avatar May 20 '20 14:05 dakky

Hi, I too an experiencing reliability issues minuteChanged() and secondChanges() it seems to be linked to when an MQTT message is received and acted upon around the time the clock transitions from 59 seconds to zero seconds and minutes are incremented. It seems as though the 'timing' to increment minutes is missed. The clock does correct itself after a minute or two. The error occurs randomly and not for every transition from 59 to 0. Like you I have events() in my main loop. In the manual the description of events() refers to 'loop functions' i.e in the plural so I am wondering if events() need to be called more than once in different functions. I am using an ESP8266 BTW. To me it is fundamental that time increments with 100% reliability or otherwise this library cannot be used.

bobcroft avatar May 20 '20 18:05 bobcroft

It's really only meant to be polling once, because internally there is a variable _last_read_t used to determine if the change was already presented. Never thought of wanting to check it from two places, usually people just have a loop and need to do this themselves if they want to prevent flicker of a display. I guess you'll just have to store it yourself in the second place and see if it changed.

ropg avatar May 21 '20 08:05 ropg

Fixed the documentation in commit 71a6baf to add

Note that this uses a single variable internally to store when the time was last accessed, so your code can only poll this in one place.

ropg avatar May 21 '20 08:05 ropg

The library does not have a daemon running. The only thing that happens magically in the background is the ESP itself increasing the millisecond counter. ezTime is all just code that you call which then uses this counter to figure out what time it is. What that means is that if some other code is doing things at the the time second or minute changes, you will learn about it later.

@bobcroft, is that what you mean?

ropg avatar May 21 '20 08:05 ropg

Hi, thank you for your responses so far, to be absolutely clear I was only using the minuteChanged() function in one place, in the main loop immediately after events(). I was only musing that maybe it had to be called multiple times, from your remarks the intent is that it is called once. Good, that's clear, however it still does not increment the display as I expected it to. Below is the code in my loop.

void loop()
{
  events();

  if (minuteChanged())
  {
    tft.setTextColor(TFT_MAGENTA, TFT_BLACK);
    tft.drawString( (myTZ.dateTime("H:i:s")), 0, row2, 6 );
  }
  if (secondChanged())

  {
    tft.setTextColor(TFT_MAGENTA, TFT_BLACK);
    tft.drawString( (myTZ.dateTime("s")), posnSec, row2, 6 );
  }

  if (millis() >= timerxs) stateloop();  // called every 100 mS

  mqttClient.loop();                   // process MQTT subscribed topics
  ArduinoOTA.handle();
  keeplive();
}

Could you clarify what 'learn about it later means' please.

In your last response you ask 'is that what I mean'? Yes, I think it is, or put another way - What happens if some other code is running at the point the minutes increment should occur? howdo I ensure the minute update is not missed?

bobcroft avatar May 21 '20 08:05 bobcroft

Hmmm, I'm just wondering about something... Do things get better if you drop the minuteChanged check and in secondChanged do a if (now() % 60)

See too many ways my code doesn't cut it all of a sudden. I may redo this to have separate vars for presenting minutes changed and seconds changed, it seems like I wrote this too much with only one too specific use case in mind. Thank you for reporting...

ropg avatar May 21 '20 09:05 ropg

Hi Rop, I'll try that later, i was wondering about doing something similar. There is so much I like about your library I want to stick with it. I'll keep you posted.

bobcroft avatar May 21 '20 10:05 bobcroft

I'll try to make it work for you, within the limitations of what ezTime is. With that I mean that on modern processors such as the ESP, one could do cooler things such as running one's own process. But that doesn't translate all the way down to the original Arduino that ezTime also has to work on.

ropg avatar May 21 '20 11:05 ropg

Hi Rop,

I did as you suggested and put the if (now() % 60) into the secondChanged() and the minute update has not failed in about 6 hours. I ran two separate rows of time on the TFT display one showing time using minuteChanged(), the second row showing time with the modified secondChanged(). I could see the minute change errors in row 1.

Its getting late I’ll feedback more tomorrow.

Bob

From: Rop Gonggrijp [email protected] Sent: 21 May 2020 10:31 To: ropg/ezTime [email protected] Cc: bobcroft [email protected]; Mention [email protected] Subject: Re: [ropg/ezTime] secondChanged/minuteChanged triggeres not always (#91)

Hmmm, I'm just wondering about something... Do things get better if you drop the minuteChanged check and in secondChanged do a if (now() % 60)

See too many ways my code doesn't cut it all of a sudden. I may redo this to have separate vars for presenting minutes changed and seconds changed, it seems like I wrote this too much with only one too specific use case in mind. Thank you for reporting...

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/ropg/ezTime/issues/91#issuecomment-631985802 , or unsubscribe https://github.com/notifications/unsubscribe-auth/AAVDXISVBVQTTNHHFCNPILTRSTYFNANCNFSM4NF7XUCQ .

bobcroft avatar May 21 '20 21:05 bobcroft

Just wanted to report, that I faced the same issue when checking secondChanged and minuteChanged in the same frame. I used the (now() % 60 == 0) workaround, since secondChanged always fired correctly and minuteChanged not even once. With the workaround it runs fine now. Not a big deal :) thanks for this lib

ellogwen avatar Nov 08 '21 16:11 ellogwen

I call secondChanged() only one place in loop(). it triggers very irregularly.

const int WX_CURRENT_SHORT_INTERVAL = 10; // WeatherBit has 500 requests per day limit ( 2 min 53 sec ) const int WX_CURRENT_LONG_INTERVAL = 60; // intervals are in minutes

void loop() { static bool shouldUpdateCurrent = true;

events();

if (secondChanged()) { DEBUG_PRINTLN(dateTime("H~:i~:s")); updateFrame(); }

// set intervals every current short interval int currentInterval = WX_CURRENT_SHORT_INTERVAL; if (minute() % WX_CURRENT_SHORT_INTERVAL == 0) { // long intervals from midnight to 7 am if (hour() < 7) { currentInterval = WX_CURRENT_LONG_INTERVAL; } // check if this interval needs current WX update if (minute() % currentInterval == 0) { if (shouldUpdateCurrent) { getWXcurrent(); shouldUpdateCurrent = false; } } else { shouldUpdateCurrent = true; } } } // loop()

Output: 17:33:51 17:33:52 17:33:55 17:33:58 17:34:00 17:34:01 17:34:02 17:34:03 17:34:06 17:34:09 17:34:14 17:34:16 17:34:17 17:34:18 17:34:25 17:34:26 17:34:29 17:34:32 17:34:34 17:34:35 17:34:36 17:34:42 17:34:43 17:34:45 17:34:46 17:34:47 17:34:49 17:34:52 17:34:53 17:34:54 17:34:58 17:34:59 17:35:00 17:35:01 17:35:02 17:35:04

W4KRL avatar Feb 19 '22 22:02 W4KRL

I am on ezTime 0.8.3 on a ESP32-C3. I do not set any #defines for ezTime in my project.

I call secondChanged() only in one place in loop(), which runs non-blocking. Mainly TickerTwo are called from loop.

secondChanged() actually triggers any time called.

I made a simple custom function, now it works perfectly:

int8_t wasSecond = -1; bool mySecondChanged() { if (second() != wasSecond) { wasSecond = second(); return true; } else { return false; } }

LeFish1 avatar Jan 16 '23 07:01 LeFish1

Tried it, but it doesn't compile.

void loop() { int8_t wasSecond = -1; bool mySecondChanged() events(); { if (second() != wasSecond) { wasSecond = second(); return true; } else { return false; } } }

heffnerm2 avatar Jan 16 '23 13:01 heffnerm2