xoseperez / espurna

Home automation firmware for ESP8266-based devices
http://tinkerman.cat
GNU General Public License v3.0
2.99k stars 636 forks source link

Random delay during boot process before initializing wifi #2364

Open ghost opened 4 years ago

ghost commented 4 years ago

Scenario:

Proposed mitigation:

Proposed implementation:

diff --git a/code/espurna/main.cpp b/code/espurna/main.cpp
index d7bb1583..67e3c7ef 100644
--- a/code/espurna/main.cpp
+++ b/code/espurna/main.cpp
@@ -152,6 +152,12 @@ void setup() {
     // Show welcome message and system configuration
     info(true);

+    // powercut, and 30 nodes connecting simultaneously to same AP is not a good idea
+    // connect, or any other kind of regular event earch X seconds (data publishing, mdns)
+    // side effect with SYSTEM_CHECK_TIME???? Increase SYSTEM_CHECK_TIME to 120000?
+    uint rndDelay = secureRandom(0, getSetting("bootDelayMax",10));
+    delay(rndDelay*1000);
+
     wifiSetup();
     #if OTA_ARDUINOOTA_SUPPORT
         arduinoOtaSetup();
mcspr commented 4 years ago

The patch above is a bad idea, actually. delay() implies we don't get to execute anything below it, and must wait 1...10 seconds until it is done spinning system timer and doing nothing. So... no buttons, no relays boot sequence, nothing.

One option is to use JustWifi and the existing reconnect timeout that is configured through the setReconnectTimeout(ms): https://github.com/mcspr/justwifi/blob/083c9df266847d39112f852c21ea4935bed4abeb/src/JustWifi.cpp#L481 Meaning, if the wifiSetup() does this at the end:

jw.setReconnectTimeout(secureRandom(0, 10000));
jw.resetReconnectTimeout();

Instead of immediately trying to connect, it would wait for the time that secureRandom had generated.Perhaps this also would imply we never use the static WIFI_RECONNECT_INTERVAL as well and simply use the randomized value. Note that softAP fallback is enabled in the meantime, but this could be easily turned off via WIFI_AP_MODE.

edit: This does not handle connected->disconnected->reconnect chain though, only initial disconnected->connect. Current justwifi data enums contain MESSAGE_DISCONNECTED, but the only place that happens is jw.disconnect() when it is either manually called or after scanning had started (meaning, we already try to connect and setting timeout then would not work). And since the library only checks for the WL_CONNECTED status, we don't actually know if we were connected before that or not.

SDK does track the connection status, which Arduino Core exposes through the WiFiEventHandler 'tasks', which accept some callable to be used something like WiFi.onStationModeDisconnected([](WiFiEventStationModeDisconnected info) { ... the block from above ... }. Need to check it out.