diff --git a/main/User_config.h b/main/User_config.h index f48e4fd73c..50e9aa6c20 100644 --- a/main/User_config.h +++ b/main/User_config.h @@ -380,6 +380,13 @@ int lowpowermode = DEFAULT_LOW_POWER_MODE; #ifndef ota_port # define ota_port 8266 #endif +// timeout for OTA activities +// OTA upload with no activity in this period is considered inactive +// As long as OTA upload is considered "active", we avoid rebooting e.g. +// in case of failures connecting to MQTT +#ifndef ota_timeout_millis +# define ota_timeout_millis 30000 +#endif /*-------------DEFINE PINs FOR STATUS LEDs----------------*/ #ifndef LED_SEND_RECEIVE diff --git a/main/main.ino b/main/main.ino index ac3595b7ea..7d2995fb4a 100644 --- a/main/main.ino +++ b/main/main.ino @@ -188,6 +188,7 @@ bool disc = true; // Auto discovery with Home Assistant convention #endif unsigned long timer_led_measures = 0; static void* eClient = nullptr; +static unsigned long last_ota_activity_millis = 0; #if defined(ESP8266) || defined(ESP32) static bool mqtt_secure = MQTT_SECURE_DEFAULT; static uint8_t mqtt_ss_index = MQTT_SECURE_SELF_SIGNED_INDEX_DEFAULT; @@ -509,6 +510,18 @@ bool cmpToMainTopic(const char* topicOri, const char* toAdd) { return true; } +void delayWithOTA(long waitMillis) { +#if defined(ESP8266) || defined(ESP32) + long waitStep = 100; + for (long waitedMillis = 0; waitedMillis < waitMillis; waitedMillis += waitStep) { + ArduinoOTA.handle(); + delay(waitStep); + } +#else + delay(waitMillis); +#endif +} + void connectMQTT() { #ifndef ESPWifiManualSetup # if defined(ESP8266) || defined(ESP32) @@ -564,10 +577,25 @@ void connectMQTT() { Log.warning(F("failed, ssl error code=%d" CR), ((WiFiClientSecure*)eClient)->getLastSSLError()); #endif digitalWrite(LED_ERROR, LED_ERROR_ON); - delay(2000); + delayWithOTA(2000); digitalWrite(LED_ERROR, !LED_ERROR_ON); - delay(5000); + delayWithOTA(5000); if (failure_number_mqtt > maxRetryWatchDog) { + unsigned long millis_since_last_ota; + while ( + // When + // ...incomplete OTA in progress + (last_ota_activity_millis != 0) + // ...AND last OTA activity fairly recently + && ((millis_since_last_ota = millis() - last_ota_activity_millis) < ota_timeout_millis)) { + // ... We consider that OTA might be still active, and we sleep for a while, and giving + // OTA chance to proceed (ArduinoOTA.handle()) + Log.warning(F("OTA might be still active (activity %d ms ago)" CR), millis_since_last_ota); +#if defined(ESP8266) || defined(ESP32) + ArduinoOTA.handle(); +#endif + delay(100); + } watchdogReboot(1); } } @@ -875,6 +903,7 @@ void setOTA() { Log.trace(F("Start OTA, lock other functions" CR)); digitalWrite(LED_SEND_RECEIVE, LED_SEND_RECEIVE_ON); digitalWrite(LED_ERROR, LED_ERROR_ON); + last_ota_activity_millis = millis(); # if defined(ZgatewayBT) && defined(ESP32) stopProcessing(); # endif @@ -882,6 +911,7 @@ void setOTA() { }); ArduinoOTA.onEnd([]() { Log.trace(F("\nOTA done" CR)); + last_ota_activity_millis = 0; digitalWrite(LED_SEND_RECEIVE, !LED_SEND_RECEIVE_ON); digitalWrite(LED_ERROR, !LED_ERROR_ON); # if defined(ZgatewayBT) && defined(ESP32) @@ -891,8 +921,10 @@ void setOTA() { }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { Log.trace(F("Progress: %u%%\r" CR), (progress / (total / 100))); + last_ota_activity_millis = millis(); }); ArduinoOTA.onError([](ota_error_t error) { + last_ota_activity_millis = millis(); digitalWrite(LED_SEND_RECEIVE, !LED_SEND_RECEIVE_ON); digitalWrite(LED_ERROR, !LED_ERROR_ON); # if defined(ZgatewayBT) && defined(ESP32)