[SERIAL] Add Serial Heartbeat ack (#2073)
And enable to launch the loop when offline: false and serial communication layer is activated Co-authored-by: Florian <1technophile@users.noreply.github.com>
This commit is contained in:
1 parent
3187ed6154
commit
88e09092d6
3 files changed
+50
-30
No files matched your search
+30
-8
@@ -39,6 +39,15 @@ SoftwareSerial SERIALSoftSerial(SERIAL_RX_GPIO, SERIAL_TX_GPIO); // RX, TX
|
|||||||
Stream* SERIALStream = NULL;
|
Stream* SERIALStream = NULL;
|
||||||
//unsigned long msgCount = 0;
|
//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() {
|
void setupSERIAL() {
|
||||||
//Initalize serial port
|
//Initalize serial port
|
||||||
# ifdef SERIAL_UART // Hardware serial
|
# ifdef SERIAL_UART // Hardware serial
|
||||||
@@ -135,17 +144,30 @@ void sendHeartbeat() {
|
|||||||
SERIALStream->flush();
|
SERIALStream->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long lastHeartbeatSent = 0;
|
void sendHeartbeatAck() {
|
||||||
const unsigned long heartbeatInterval = 5000; // 5 seconds
|
SERIALStream->print(SERIALPre);
|
||||||
bool isOverflow = false;
|
SERIALStream->print("{\"type\":\"heartbeat_ack\"}");
|
||||||
|
SERIALStream->print(SERIALPost);
|
||||||
|
SERIALStream->flush();
|
||||||
|
Log.notice(F("Sent heartbeat ack" CR));
|
||||||
|
}
|
||||||
|
|
||||||
void SERIALtoX() {
|
void SERIALtoX() {
|
||||||
static String buffer = ""; // Static buffer to store incomplete messages
|
static String buffer = ""; // Static buffer to store incomplete messages
|
||||||
|
|
||||||
unsigned long currentTime = millis();
|
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) {
|
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();
|
sendHeartbeat();
|
||||||
lastHeartbeatSent = currentTime;
|
lastHeartbeatSent = currentTime;
|
||||||
}
|
}
|
||||||
@@ -171,6 +193,9 @@ void SERIALtoX() {
|
|||||||
// Check if this is a heartbeat message
|
// Check if this is a heartbeat message
|
||||||
if (SERIALdata.containsKey("type") && strcmp(SERIALdata["type"], "heartbeat") == 0) {
|
if (SERIALdata.containsKey("type") && strcmp(SERIALdata["type"], "heartbeat") == 0) {
|
||||||
handleHeartbeat();
|
handleHeartbeat();
|
||||||
|
} else if (SERIALdata.containsKey("type") && strcmp(SERIALdata["type"], "heartbeat_ack") == 0) {
|
||||||
|
lastHeartbeatAckReceived = currentTime;
|
||||||
|
Log.notice(F("Heartbeat ack received" CR));
|
||||||
} else {
|
} else {
|
||||||
// Process normal messages
|
// Process normal messages
|
||||||
Log.notice(F("SERIAL msg received: %s" CR), jsonString.c_str());
|
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
|
# endif
|
||||||
|
|
||||||
bool receiverReady = false;
|
|
||||||
unsigned long lastHeartbeatReceived = 0;
|
|
||||||
const unsigned long heartbeatTimeout = 6000; // 5 seconds
|
|
||||||
|
|
||||||
bool XtoSERIAL(const char* topicOri, JsonObject& SERIALdata) {
|
bool XtoSERIAL(const char* topicOri, JsonObject& SERIALdata) {
|
||||||
bool res = false;
|
bool res = false;
|
||||||
unsigned long currentTime = millis();
|
unsigned long currentTime = millis();
|
||||||
@@ -300,5 +321,6 @@ void handleHeartbeat() {
|
|||||||
receiverReady = true;
|
receiverReady = true;
|
||||||
lastHeartbeatReceived = millis();
|
lastHeartbeatReceived = millis();
|
||||||
Log.trace(F("Heartbeat received. Receiver is ready." CR));
|
Log.trace(F("Heartbeat received. Receiver is ready." CR));
|
||||||
|
sendHeartbeatAck();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -72,7 +72,7 @@ void MeasureGPIOInput() {
|
|||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
Log.notice(F("Erasing ESP Config, restarting" CR));
|
Log.notice(F("Erasing ESP Config, restarting" CR));
|
||||||
setupwifi(true);
|
setupWiFiManager(true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
resetTime = 0;
|
resetTime = 0;
|
||||||
|
|||||||
+19
-21
@@ -1391,14 +1391,14 @@ void setup() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(ESPWifiManualSetup)
|
#if defined(ESPWifiManualSetup)
|
||||||
setup_wifi();
|
setupWiFiFromBuild();
|
||||||
#else
|
#else
|
||||||
if (loadConfigFromFlash()) {
|
if (loadConfigFromFlash()) {
|
||||||
Log.notice(F("Config loaded from flash" CR));
|
Log.notice(F("Config loaded from flash" CR));
|
||||||
# ifdef ESP32_ETHERNET
|
# ifdef ESP32_ETHERNET
|
||||||
setup_ethernet_esp32();
|
setup_ethernet_esp32();
|
||||||
# endif
|
# endif
|
||||||
if (!failSafeMode && !ethConnected) setupwifi(false);
|
if (!failSafeMode && !ethConnected) setupWiFiManager(false);
|
||||||
} else {
|
} else {
|
||||||
# ifdef ESP32_ETHERNET
|
# ifdef ESP32_ETHERNET
|
||||||
setup_ethernet_esp32();
|
setup_ethernet_esp32();
|
||||||
@@ -1411,7 +1411,7 @@ void setup() {
|
|||||||
|
|
||||||
Log.notice(F("No config in flash, launching wifi manager" CR));
|
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
|
// 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
|
#endif
|
||||||
@@ -1785,7 +1785,7 @@ void ESPRestart(byte reason) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(ESPWifiManualSetup)
|
#if defined(ESPWifiManualSetup)
|
||||||
void setup_wifi() {
|
void setupWiFiFromBuild() {
|
||||||
WiFi.mode(WIFI_STA);
|
WiFi.mode(WIFI_STA);
|
||||||
wifiMulti.addAP(wifi_ssid, wifi_password);
|
wifiMulti.addAP(wifi_ssid, wifi_password);
|
||||||
Log.trace(F("Connecting to %s" CR), wifi_ssid);
|
Log.trace(F("Connecting to %s" CR), wifi_ssid);
|
||||||
@@ -1877,7 +1877,7 @@ void blockingWaitForReset() {
|
|||||||
Log.trace(F("mounted file system" CR));
|
Log.trace(F("mounted file system" CR));
|
||||||
if (SPIFFS.exists("/config.json")) {
|
if (SPIFFS.exists("/config.json")) {
|
||||||
Log.notice(F("Erasing ESP Config, restarting" CR));
|
Log.notice(F("Erasing ESP Config, restarting" CR));
|
||||||
setupwifi(true);
|
setupWiFiManager(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delay(30000);
|
delay(30000);
|
||||||
@@ -1885,7 +1885,7 @@ void blockingWaitForReset() {
|
|||||||
Log.notice(F("Going into failsafe mode without peripherals" CR));
|
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
|
// Failsafe mode enable to connect to Wifi or change the firmware without the peripherals setup
|
||||||
failSafeMode = true;
|
failSafeMode = true;
|
||||||
setupwifi(false);
|
setupWiFiManager(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2165,7 +2165,7 @@ bool loadConfigFromFlash() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupwifi(bool reset_settings) {
|
void setupWiFiManager(bool reset_settings) {
|
||||||
delay(10);
|
delay(10);
|
||||||
WiFi.mode(WIFI_STA);
|
WiFi.mode(WIFI_STA);
|
||||||
|
|
||||||
@@ -2290,8 +2290,8 @@ void setupwifi(bool reset_settings) {
|
|||||||
# ifdef USE_BLUFI
|
# ifdef USE_BLUFI
|
||||||
shouldRestart = shouldRestart && !isStaConnecting();
|
shouldRestart = shouldRestart && !isStaConnecting();
|
||||||
# endif
|
# endif
|
||||||
// Restart/sleep only if not connected
|
// Restart/sleep only if not connected and not serial communication mode
|
||||||
if (shouldRestart) {
|
if (shouldRestart && !SYSConfig.serial) {
|
||||||
# ifdef DEEP_SLEEP_IN_US
|
# ifdef DEEP_SLEEP_IN_US
|
||||||
sleep();
|
sleep();
|
||||||
# endif
|
# endif
|
||||||
@@ -2475,23 +2475,21 @@ void loop() {
|
|||||||
mqttSetupPending = false;
|
mqttSetupPending = false;
|
||||||
}
|
}
|
||||||
// When online the MQTT connection callback release the processes
|
// When online the MQTT connection callback release the processes
|
||||||
} else { // Offline mode
|
}
|
||||||
if (firstStart) {
|
if (firstStart) {
|
||||||
#ifdef ZgatewaySERIAL
|
#ifdef ZgatewaySERIAL
|
||||||
if (SYSConfig.serial && isSerialReady()) {
|
if (SYSConfig.serial && isSerialReady()) {
|
||||||
# ifdef ZgatewayBT
|
# ifdef ZgatewayBT
|
||||||
BTProcessLock = !BTConfig.enabled;
|
BTProcessLock = !BTConfig.enabled;
|
||||||
# endif
|
# endif
|
||||||
ProcessLock = false;
|
|
||||||
firstStart = false;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
ProcessLock = false;
|
ProcessLock = false;
|
||||||
firstStart = false;
|
firstStart = false;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
ProcessLock = false;
|
||||||
|
firstStart = false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
|
|
||||||
#ifdef ZgatewaySERIAL // Serial is a module and a communication layer so it's always processed
|
#ifdef ZgatewaySERIAL // Serial is a module and a communication layer so it's always processed
|
||||||
@@ -2529,7 +2527,7 @@ void loop() {
|
|||||||
SYSConfig.discovery = false;
|
SYSConfig.discovery = false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
} else if (!SYSConfig.offline) { // disconnected from network
|
} else if (!SYSConfig.offline && !SYSConfig.serial) { // disconnected from network
|
||||||
Log.warning(F("Network disconnected" CR));
|
Log.warning(F("Network disconnected" CR));
|
||||||
gatewayState = GatewayState::NTWK_DISCONNECTED;
|
gatewayState = GatewayState::NTWK_DISCONNECTED;
|
||||||
if (!wifi_reconnect_bypass()) {
|
if (!wifi_reconnect_bypass()) {
|
||||||
@@ -3332,7 +3330,7 @@ void XtoSYS(const char* topicOri, JsonObject& SYSdata) { // json object decoding
|
|||||||
ESPRestart(5);
|
ESPRestart(5);
|
||||||
} else if (strstr(cmd, eraseCmd) != NULL) { //erase and restart
|
} else if (strstr(cmd, eraseCmd) != NULL) { //erase and restart
|
||||||
#ifndef ESPWifiManualSetup
|
#ifndef ESPWifiManualSetup
|
||||||
setupwifi(true);
|
setupWiFiManager(true);
|
||||||
#endif
|
#endif
|
||||||
} else if (strstr(cmd, statusCmd) != NULL) { //erase and restart
|
} else if (strstr(cmd, statusCmd) != NULL) { //erase and restart
|
||||||
publishState = true;
|
publishState = true;
|
||||||
|
|||||||
Reference in new issue
Block a user