diff --git a/main/ZgatewaySERIAL.ino b/main/ZgatewaySERIAL.ino index 1114c3cd..9e31991f 100644 --- a/main/ZgatewaySERIAL.ino +++ b/main/ZgatewaySERIAL.ino @@ -39,6 +39,15 @@ SoftwareSerial SERIALSoftSerial(SERIAL_RX_GPIO, SERIAL_TX_GPIO); // RX, TX Stream* SERIALStream = NULL; //unsigned long msgCount = 0; +bool receiverReady = false; +unsigned long lastHeartbeatReceived = 0; +unsigned long lastHeartbeatAckReceived = 0; +unsigned long lastHeartbeatSent = 0; +const unsigned long heartbeatTimeout = 15000; // 15 seconds timeout for ack +const unsigned long maxHeartbeatInterval = 60000; // Maximum interval of 1 minute +unsigned long heartbeatInterval = 5000; // 5 seconds +bool isOverflow = false; + void setupSERIAL() { //Initalize serial port # ifdef SERIAL_UART // Hardware serial @@ -135,17 +144,30 @@ void sendHeartbeat() { SERIALStream->flush(); } -unsigned long lastHeartbeatSent = 0; -const unsigned long heartbeatInterval = 5000; // 5 seconds -bool isOverflow = false; +void sendHeartbeatAck() { + SERIALStream->print(SERIALPre); + SERIALStream->print("{\"type\":\"heartbeat_ack\"}"); + SERIALStream->print(SERIALPost); + SERIALStream->flush(); + Log.notice(F("Sent heartbeat ack" CR)); +} void SERIALtoX() { static String buffer = ""; // Static buffer to store incomplete messages unsigned long currentTime = millis(); - // Send heartbeat if it's time and we don't have an overflow + // Check if it's time to send a heartbeat and we're not in overflow if (!isOverflow && currentTime - lastHeartbeatSent > heartbeatInterval) { + // Check if we received an ack for the last heartbeat + if (currentTime - lastHeartbeatAckReceived > heartbeatTimeout) { + // No ack received, increase the interval (with a maximum limit) + heartbeatInterval = min(heartbeatInterval * 2, maxHeartbeatInterval); + Log.warning(F("No heartbeat ack received. Increasing interval to %lu ms" CR), heartbeatInterval); + } else { + // Ack received, reset the interval + heartbeatInterval = 5000; + } sendHeartbeat(); lastHeartbeatSent = currentTime; } @@ -171,6 +193,9 @@ void SERIALtoX() { // Check if this is a heartbeat message if (SERIALdata.containsKey("type") && strcmp(SERIALdata["type"], "heartbeat") == 0) { handleHeartbeat(); + } else if (SERIALdata.containsKey("type") && strcmp(SERIALdata["type"], "heartbeat_ack") == 0) { + lastHeartbeatAckReceived = currentTime; + Log.notice(F("Heartbeat ack received" CR)); } else { // Process normal messages Log.notice(F("SERIAL msg received: %s" CR), jsonString.c_str()); @@ -247,10 +272,6 @@ void sendMQTTfromNestedJson(JsonVariant obj, char* topic, int level, int maxLeve } # endif -bool receiverReady = false; -unsigned long lastHeartbeatReceived = 0; -const unsigned long heartbeatTimeout = 6000; // 5 seconds - bool XtoSERIAL(const char* topicOri, JsonObject& SERIALdata) { bool res = false; unsigned long currentTime = millis(); @@ -300,5 +321,6 @@ void handleHeartbeat() { receiverReady = true; lastHeartbeatReceived = millis(); Log.trace(F("Heartbeat received. Receiver is ready." CR)); + sendHeartbeatAck(); } #endif \ No newline at end of file diff --git a/main/ZsensorGPIOInput.ino b/main/ZsensorGPIOInput.ino index 8d8cfefb..f35b545b 100644 --- a/main/ZsensorGPIOInput.ino +++ b/main/ZsensorGPIOInput.ino @@ -72,7 +72,7 @@ void MeasureGPIOInput() { } # endif Log.notice(F("Erasing ESP Config, restarting" CR)); - setupwifi(true); + setupWiFiManager(true); } } else { resetTime = 0; diff --git a/main/main.ino b/main/main.ino index 66c21c2c..3403f5ee 100644 --- a/main/main.ino +++ b/main/main.ino @@ -1391,14 +1391,14 @@ void setup() { #endif #if defined(ESPWifiManualSetup) - setup_wifi(); + setupWiFiFromBuild(); #else if (loadConfigFromFlash()) { Log.notice(F("Config loaded from flash" CR)); # ifdef ESP32_ETHERNET setup_ethernet_esp32(); # endif - if (!failSafeMode && !ethConnected) setupwifi(false); + if (!failSafeMode && !ethConnected) setupWiFiManager(false); } else { # ifdef ESP32_ETHERNET setup_ethernet_esp32(); @@ -1411,7 +1411,7 @@ void setup() { Log.notice(F("No config in flash, launching wifi manager" CR)); // In failSafeMode we don't want to setup wifi manager as it has already been done before - if (!failSafeMode) setupwifi(false); + if (!failSafeMode) setupWiFiManager(false); } #endif @@ -1785,7 +1785,7 @@ void ESPRestart(byte reason) { } #if defined(ESPWifiManualSetup) -void setup_wifi() { +void setupWiFiFromBuild() { WiFi.mode(WIFI_STA); wifiMulti.addAP(wifi_ssid, wifi_password); Log.trace(F("Connecting to %s" CR), wifi_ssid); @@ -1877,7 +1877,7 @@ void blockingWaitForReset() { Log.trace(F("mounted file system" CR)); if (SPIFFS.exists("/config.json")) { Log.notice(F("Erasing ESP Config, restarting" CR)); - setupwifi(true); + setupWiFiManager(true); } } delay(30000); @@ -1885,7 +1885,7 @@ void blockingWaitForReset() { Log.notice(F("Going into failsafe mode without peripherals" CR)); // Failsafe mode enable to connect to Wifi or change the firmware without the peripherals setup failSafeMode = true; - setupwifi(false); + setupWiFiManager(false); } } } @@ -2165,7 +2165,7 @@ bool loadConfigFromFlash() { return result; } -void setupwifi(bool reset_settings) { +void setupWiFiManager(bool reset_settings) { delay(10); WiFi.mode(WIFI_STA); @@ -2290,8 +2290,8 @@ void setupwifi(bool reset_settings) { # ifdef USE_BLUFI shouldRestart = shouldRestart && !isStaConnecting(); # endif - // Restart/sleep only if not connected - if (shouldRestart) { + // Restart/sleep only if not connected and not serial communication mode + if (shouldRestart && !SYSConfig.serial) { # ifdef DEEP_SLEEP_IN_US sleep(); # endif @@ -2475,23 +2475,21 @@ void loop() { mqttSetupPending = false; } // When online the MQTT connection callback release the processes - } else { // Offline mode - if (firstStart) { + } + if (firstStart) { #ifdef ZgatewaySERIAL - if (SYSConfig.serial && isSerialReady()) { + if (SYSConfig.serial && isSerialReady()) { # ifdef ZgatewayBT - BTProcessLock = !BTConfig.enabled; + BTProcessLock = !BTConfig.enabled; # endif - ProcessLock = false; - firstStart = false; - } -#else ProcessLock = false; firstStart = false; -#endif } +#else + ProcessLock = false; + firstStart = false; +#endif } - unsigned long now = millis(); #ifdef ZgatewaySERIAL // Serial is a module and a communication layer so it's always processed @@ -2529,7 +2527,7 @@ void loop() { SYSConfig.discovery = false; #endif } - } else if (!SYSConfig.offline) { // disconnected from network + } else if (!SYSConfig.offline && !SYSConfig.serial) { // disconnected from network Log.warning(F("Network disconnected" CR)); gatewayState = GatewayState::NTWK_DISCONNECTED; if (!wifi_reconnect_bypass()) { @@ -3332,7 +3330,7 @@ void XtoSYS(const char* topicOri, JsonObject& SYSdata) { // json object decoding ESPRestart(5); } else if (strstr(cmd, eraseCmd) != NULL) { //erase and restart #ifndef ESPWifiManualSetup - setupwifi(true); + setupWiFiManager(true); #endif } else if (strstr(cmd, statusCmd) != NULL) { //erase and restart publishState = true;