esp8266 / Arduino

ESP8266 core for Arduino
GNU Lesser General Public License v2.1
16.05k stars 13.33k forks source link

WiFi messes up SimpleTimer #2295

Closed Gorkde closed 8 years ago

Gorkde commented 8 years ago

ESP8266 12-F V2.3.0

Once The Timers are defined before WiFi connection the Timers are messed up at the beginning. As soon as I put them below they work.

This wouldn't be that bad except when WiFi disconnects and reconnects randomly for some reason I assume this will probably happen again and can cause multiple problems (server flooding in my case).

unbenannt

#include <SimpleTimer.h>
#include <ESP8266WiFi.h>

#define WLANname "XXX"
#define WLANpw "XXX"
#define authToken "XXX"

// Timer definieren
SimpleTimer Timer;

// Timer ID's initialisieren
int Timer_A_ID = 0;
int Timer_B_ID = 0;
int Timer_C_ID = 0;

unsigned long TESTmillis1 = 0;
unsigned long TESTmillis2 = 0;
unsigned long TESTmillis3 = 0;

void setup()
{
  Serial.begin(115200);
  delay (200);

  Timer_A_ID = Timer.setInterval(1000L, Test1);
  Timer_B_ID = Timer.setInterval(1000L, Test2);
  Timer_C_ID = Timer.setInterval(1000L, Test3);

  WiFi.begin(WLANname, WLANpw);
  while (WiFi.status() != WL_CONNECTED) {yield();}

  TESTmillis1 = millis();
  TESTmillis2 = millis();
  TESTmillis3 = millis();

  Serial.println("\nSTART");
}

void loop()
{
  Timer.run();
}

void Test1()
{
  Serial.println("Timer - 1");
  Serial.println((millis() - TESTmillis1));
  TESTmillis1 = millis();
}

void Test2()
{
  Serial.println("Timer - 2");
  Serial.println((millis() - TESTmillis2));
  TESTmillis2 = millis();
}

void Test3()
{
  Serial.println("Timer - 3");
  Serial.println((millis() - TESTmillis3));
  TESTmillis3 = millis();
}
pieman64 commented 8 years ago

Please indicate why you need to start Timers before WiFi. Do a Google search for Ticker and see if you get the same results.

Gorkde commented 8 years ago

I don't need to but

A) This should be working B) If there's a problem for the first connect I assume this will also happen after a random disconnect and reconnect later (as I already wrote above)

pieman64 commented 8 years ago

Maybe you should speak to Espressif if you don't like their implementation of WiFi.

For your Blynk server you can code a WiFi disconnect as:

1) Reset device or 2) Stop Timers and restart when WiFi reconnects.

No problems.

Gorkde commented 8 years ago

I don't know if this is caused by the library or whatever I did'nt wrote it! I'm just reporting a problem that's what this page is for!

For what I think the Hardware won't change timer values.

Gorkde commented 8 years ago

Just checked...

Random disconnects (for example caused by the router getting offline later online again) do not cause this problem (automatic reconnect by esp without anoter WiFi.begin).

Neither while loosing connection nor while esp reconnects.

So this can't be caused by espressif's WiFi implementation. Then it would for sure happen at any connect.

unbenannt

Gorkde commented 8 years ago

Did another test....

When the connection is automatically reconnected by ESP the timer stays intact. But once the connection is reestablished by code the timers get messed up.

Therefore there must be a problem in the ESP or SimpleTimer code.

blynk

SteveToulouse commented 8 years ago

Could you try putting these lines

TESTmillis1 = millis(); TESTmillis2 = millis(); TESTmillis3 = millis();

before the wifi.begin while loop? Setting the timer interval will record the value of millis(), so there could be a rather big difference between what is stored in the timer and what is in your variables used to print the elapsed time.

If the while loop takes more than one second, the timers expire immediately on first call to timer.run. If it takes even longer, the timers will fire more frequently than expected until they "catch up" to the real millis counter because simpletimer::run doesn't record the actual millis() when a timer expires but it records previousmillis + interval value.

So if wifi.begin loop takes 3 seconds, the timers will "fire" 3 or 4 times before catching up (the first ones in 0 or a small number of millis, and the last one at (realmillis - timer accumulated millis) ).

You could also try setting the timers to 4000L without moving the code around, see what happens.

Note: all that explanation supposes you are using https://github.com/infomaniac50/SimpleTimer/blob/master/SimpleTimer.cpp or something which works in the same way.

Gorkde commented 8 years ago

Yes that's the one I use but I did download the one that's linked on the Arduino page.

That must be the reason and it's really no problem for the first connect since I could avoid that by defining timers after the connection. The problems begins once the connection is lost lateron and reestablished by Software (blynk in my case). Then the function will be executed multiple times in a short period.

Is there any way to avoid that?

SteveToulouse commented 8 years ago

I haven't really thought it through completely. If the disconnect/reconnect takes less than the timer interval, I don't think you'll see a problem in any case. But one way to be sure would be to modify the code of simpletimer::run so that instead of (line 70)

prev_millis[i] += delays[i];

you do

prev_millis[i] = elapsed();

This will change the way simpletimer works completely, and it will only run a timer callback once for each expiry, even if many periods have elapsed since the last call to 'run'. Whether that's acceptable depends on the logic of your sketch and also on what else you may want to do with simpletimers.

SteveToulouse commented 8 years ago

A workaround could be to check elapsed millis just after calling simpletimer::run and if it's greater than, say, twice the timer interval, call simpletimer::restartTimer (which records current millis() in the timer => the timer immediatly catches up to "real time").

You could even put restartTimer in the timer callback function, which is probably an even cleaner solution and avoids having to change the library...

Gorkde commented 8 years ago

The restart won't work if the connection is lost after that. The best way would be to add an option to the timer library to select behavior of the timers.

I'll probably write my own timer then.

Gorkde commented 8 years ago

Just for others to know:

I had this problem mess up my timed action while reconnecting to Blynk server.

1) When WiFi / Blynk connects by command the timers get messed up 2) ESP will reconnect automatically without command. Then Timers don't get messed up 3) A solution I found and tested working would be to encase Blynk.run() in a check if WiFi has been reconnected automatically like this:

if (WiFi.status() == WL_CONNECTED) { Blynk.run(); }

Btw. this would also avoid other timed actions to get delayed by Blynk reconnection

Just checked you don't need to do this for Blynk.virtualWrite since it doesn't reconnect when disconnected.

SteveToulouse commented 8 years ago

OK, doing your own timer would make it clear what is being done. However, I'm not sure why you say the call to restartTimer in the callback function won't work for you needs; it has exactly the same effect as changing line 70 of the run method = it remembers current millis() value as the start of the next interval.

Gorkde commented 8 years ago

Ok, thinking again, it would work but I decided writing my own which I did finish already. This also makes my code much smoother.