From fee1dc25d6f18ee8bb654df7598cac3ae9d61210 Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Wed, 9 Apr 2025 15:49:34 +0700 Subject: [PATCH 01/13] Improve reconnection of CE network option Restart system if it already too long Bump airgradient-client: Improve ensureClientConnection --- src/Libraries/airgradient-client | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Libraries/airgradient-client b/src/Libraries/airgradient-client index d24b3696..bf8c1258 160000 --- a/src/Libraries/airgradient-client +++ b/src/Libraries/airgradient-client @@ -1 +1 @@ -Subproject commit d24b369604becb54eacf899997e8b39d3d2bf4f8 +Subproject commit bf8c1258e6b96fd285a5e56f11520d0931883e3a From 34d7c93e14330bc403f4caa2ccda52c581a19696 Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Wed, 9 Apr 2025 15:51:54 +0700 Subject: [PATCH 02/13] Improve reconnection of CE network option Restart system if it already too long --- examples/OneOpenAir/OneOpenAir.ino | 56 +++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino index c31a7877..2ea8ed46 100644 --- a/examples/OneOpenAir/OneOpenAir.ino +++ b/examples/OneOpenAir/OneOpenAir.ino @@ -37,6 +37,7 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License #include "Arduino.h" #include "EEPROM.h" #include "ESPmDNS.h" +#include "Libraries/airgradient-client/src/common.h" #include "LocalServer.h" #include "MqttClient.h" #include "OpenMetrics.h" @@ -1514,6 +1515,9 @@ void networkingTask(void *args) { measurementSchedule.update(); } + // Default value is 0, indicate its not started yet + uint32_t startTimeClientNotReady = 0; + // Reset scheduler configSchedule.update(); transmissionSchedule.update(); @@ -1529,14 +1533,56 @@ void networkingTask(void *args) { } else if (networkOption == UseCellular) { if (agClient->isClientReady() == false) { - Serial.println("Cellular client not ready, ensuring connection..."); + // Start time if value still default + if (startTimeClientNotReady == 0) { + startTimeClientNotReady = millis(); + } + + // TODO: Need to handle if millis is overflow (back to 0) + + // Enable at command debug agSerial->setDebug(true); - if (agClient->ensureClientConnection() == false) { - Serial.println("Cellular client connection not ready, retry in 5s..."); - delay(5000); + + // If in 2 hours still not ready, then restart esp + if ((millis() - startTimeClientNotReady) > (2 * 60 * 60000)) { + Serial.println("CLIENT NOT READY TAKING TOO LONG! Rebooting ..."); + int i = 3; + while (i != 0) { + if (ag->isOne()) { + String tmp = "Reboot in " + String(i); + oledDisplay.setText("CE error", "too long", tmp.c_str()); + } else { + Serial.println("Rebooting... " + String(i)); + } + i = i - 1; + delay(1000); + } + oledDisplay.setBrightness(0); + esp_restart(); + } + + // Starting from 1 hour since its not ready, power cycling the module + bool resetModule = true; + if ((millis() - startTimeClientNotReady) > (60 * 60000)) { + Serial.println("Power cycling module"); + cell->powerOff(); + delay(2000); + cell->powerOn(); + delay(10000); + resetModule = false; // No need to reset module anymore + } + + // Attempt to reconnect + Serial.println("Cellular client not ready, ensuring connection..."); + if (agClient->ensureClientConnection(resetModule) == false) { + Serial.println("Cellular client connection not ready, retry in 30s..."); + delay(30000); // before retry, wait for 30s continue; } - agSerial->setDebug(false); + + // Client is ready + startTimeClientNotReady = 0; // reset to default + agSerial->setDebug(false); // disable at command debug } } From 1c6bc3ec55ebc518bfe942b1abddf898b5387f4c Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Wed, 9 Apr 2025 22:48:21 +0700 Subject: [PATCH 03/13] Bump airgradient-client fix esp8266 compile --- src/Libraries/airgradient-client | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Libraries/airgradient-client b/src/Libraries/airgradient-client index bf8c1258..d91e4deb 160000 --- a/src/Libraries/airgradient-client +++ b/src/Libraries/airgradient-client @@ -1 +1 @@ -Subproject commit bf8c1258e6b96fd285a5e56f11520d0931883e3a +Subproject commit d91e4debe831659a658a4ed00d5f0a43d80848b2 From 52d3dc03f1fe1bf39a657ce826505b46ec5d0701 Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Wed, 9 Apr 2025 23:46:03 +0700 Subject: [PATCH 04/13] Redundant check if cellular client not ready for 2 hours Check calls happen in both task --- examples/OneOpenAir/OneOpenAir.ino | 59 +++++++++++++++++++----------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino index 2ea8ed46..f767a753 100644 --- a/examples/OneOpenAir/OneOpenAir.ino +++ b/examples/OneOpenAir/OneOpenAir.ino @@ -120,6 +120,9 @@ static bool ledBarButtonTest = false; static String fwNewVersion; static int lastCellSignalQuality = 99; // CSQ +// Default value is 0, indicate its not started yet +uint32_t startTimeClientNotReady = 0; + SemaphoreHandle_t mutexMeasurementCycleQueue; static std::vector measurementCycleQueue; @@ -147,6 +150,7 @@ static void displayExecuteOta(AirgradientOTA::OtaResult result, String msg, int static int calculateMaxPeriod(int updateInterval); static void setMeasurementMaxPeriod(); static void newMeasurementCycle(); +static void checkCellularClientNotReady(); static void networkSignalCheck(); static void networkingTask(void *args); @@ -299,6 +303,12 @@ void setup() { } void loop() { + if (networkOption == UseCellular) { + // Check if cellular client not ready until certain time + // Redundant check in both task to make sure its executed + checkCellularClientNotReady(); + } + // Schedule to feed external watchdog watchdogFeedSchedule.run(); @@ -1494,6 +1504,30 @@ void networkSignalCheck() { } } +/** +* If in 2 hours still not ready, then restart esp +*/ +void checkCellularClientNotReady() { + if (startTimeClientNotReady > 0 && + (millis() - startTimeClientNotReady) > (2 * 60 * 60000)) { + // Give up wait + Serial.println("CLIENT NOT READY TAKING TOO LONG! Rebooting ..."); + int i = 3; + while (i != 0) { + if (ag->isOne()) { + String tmp = "Reboot in " + String(i); + oledDisplay.setText("CE error", "too long", tmp.c_str()); + } else { + Serial.println("Rebooting... " + String(i)); + } + i = i - 1; + delay(1000); + } + oledDisplay.setBrightness(0); + esp_restart(); + } +} + void networkingTask(void *args) { // OTA check on boot #ifdef ESP8266 @@ -1515,9 +1549,6 @@ void networkingTask(void *args) { measurementSchedule.update(); } - // Default value is 0, indicate its not started yet - uint32_t startTimeClientNotReady = 0; - // Reset scheduler configSchedule.update(); transmissionSchedule.update(); @@ -1543,24 +1574,10 @@ void networkingTask(void *args) { // Enable at command debug agSerial->setDebug(true); - // If in 2 hours still not ready, then restart esp - if ((millis() - startTimeClientNotReady) > (2 * 60 * 60000)) { - Serial.println("CLIENT NOT READY TAKING TOO LONG! Rebooting ..."); - int i = 3; - while (i != 0) { - if (ag->isOne()) { - String tmp = "Reboot in " + String(i); - oledDisplay.setText("CE error", "too long", tmp.c_str()); - } else { - Serial.println("Rebooting... " + String(i)); - } - i = i - 1; - delay(1000); - } - oledDisplay.setBrightness(0); - esp_restart(); - } - + // Check if cellular client not ready until certain time + // Redundant check in both task to make sure its executed + checkCellularClientNotReady(); + // Starting from 1 hour since its not ready, power cycling the module bool resetModule = true; if ((millis() - startTimeClientNotReady) > (60 * 60000)) { From 040cb79a4d3be45ac6728d2bdfa807312500921e Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Thu, 10 Apr 2025 00:27:44 +0700 Subject: [PATCH 05/13] Transmit measures only if queue size is 1 or divisible by 3 --- examples/OneOpenAir/OneOpenAir.ino | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino index f767a753..db908b39 100644 --- a/examples/OneOpenAir/OneOpenAir.ino +++ b/examples/OneOpenAir/OneOpenAir.ino @@ -76,6 +76,7 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License #define DISPLAY_DELAY_SHOW_CONTENT_MS 2000 /** ms */ #define FIRMWARE_CHECK_FOR_UPDATE_MS (60 * 60 * 1000) /** ms */ +#define MEASUREMENT_TRANSMIT_CYCLE 3 #define MAXIMUM_MEASUREMENT_CYCLE_QUEUE 80 #define RESERVED_MEASUREMENT_CYCLE_CAPACITY 10 @@ -1364,6 +1365,13 @@ void postUsingCellular() { return; } + // Check queue size if its ready to transmit + // It is ready if size is 1 or divisible by 3 + if (queueSize != 1 && (queueSize % MEASUREMENT_TRANSMIT_CYCLE) > 0) { + Serial.printf("Not ready to transmit, queue size are %d\n", queueSize); + return; + } + // Build payload include all measurements from queue std::string payload; payload += std::to_string(CELLULAR_MEASUREMENT_INTERVAL / 1000); // Convert to seconds From 18a710ffc24e0926d2d8d75e9750faf4685dddc0 Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Thu, 10 Apr 2025 02:06:11 +0700 Subject: [PATCH 06/13] Make sure transmit cycle not too long to wait divisible by 3 --- examples/OneOpenAir/OneOpenAir.ino | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino index db908b39..cf770662 100644 --- a/examples/OneOpenAir/OneOpenAir.ino +++ b/examples/OneOpenAir/OneOpenAir.ino @@ -66,7 +66,7 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License #define WIFI_TRANSMISSION_INTERVAL 1 * 60000 /** ms */ #define CELLULAR_SERVER_CONFIG_SYNC_INTERVAL 30 * 60000 /** ms */ #define CELLULAR_MEASUREMENT_INTERVAL 3 * 60000 /** ms */ -#define CELLULAR_TRANSMISSION_INTERVAL 9 * 60000 /** ms */ +#define CELLULAR_TRANSMISSION_INTERVAL 3 * 60000 /** ms */ #define MQTT_SYNC_INTERVAL 60000 /** ms */ #define SENSOR_CO2_CALIB_COUNTDOWN_MAX 5 /** sec */ #define SENSOR_TVOC_UPDATE_INTERVAL 1000 /** ms */ @@ -1353,7 +1353,10 @@ void postUsingWifi() { Serial.printf("Free heap: %u\n", ESP.getFreeHeap()); } -void postUsingCellular() { +/** +* forcePost to force post without checking transmit cycle +*/ +void postUsingCellular(bool forcePost) { // Aquire queue mutex to get queue size xSemaphoreTake(mutexMeasurementCycleQueue, portMAX_DELAY); @@ -1366,9 +1369,10 @@ void postUsingCellular() { } // Check queue size if its ready to transmit - // It is ready if size is 1 or divisible by 3 - if (queueSize != 1 && (queueSize % MEASUREMENT_TRANSMIT_CYCLE) > 0) { + // It is ready if size is divisible by 3 + if (!forcePost && (queueSize % MEASUREMENT_TRANSMIT_CYCLE) > 0) { Serial.printf("Not ready to transmit, queue size are %d\n", queueSize); + xSemaphoreGive(mutexMeasurementCycleQueue); return; } @@ -1413,7 +1417,7 @@ void sendDataToServer(void) { if (networkOption == UseWifi) { postUsingWifi(); } else if (networkOption == UseCellular) { - postUsingCellular(); + postUsingCellular(false); } } @@ -1553,7 +1557,7 @@ void networkingTask(void *args) { delay(20000); networkSignalCheck(); newMeasurementCycle(); - sendDataToServer(); + postUsingCellular(true); measurementSchedule.update(); } From 423eb4808fae40c82f2b3ab19ef07d43335dd55a Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Thu, 10 Apr 2025 02:14:34 +0700 Subject: [PATCH 07/13] Change airgradient-client to latest main --- src/Libraries/airgradient-client | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Libraries/airgradient-client b/src/Libraries/airgradient-client index d91e4deb..c552adc6 160000 --- a/src/Libraries/airgradient-client +++ b/src/Libraries/airgradient-client @@ -1 +1 @@ -Subproject commit d91e4debe831659a658a4ed00d5f0a43d80848b2 +Subproject commit c552adc6efbaaa80f309b665c9e8c2c0b37401a5 From 673d564ddb28ee8e6c70198e9f95bf289c43d00f Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Thu, 10 Apr 2025 12:45:18 +0700 Subject: [PATCH 08/13] Fix based on feedback --- examples/OneOpenAir/OneOpenAir.ino | 39 +++++++++++++++--------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino index cf770662..644b7fdb 100644 --- a/examples/OneOpenAir/OneOpenAir.ino +++ b/examples/OneOpenAir/OneOpenAir.ino @@ -104,7 +104,7 @@ static OpenMetrics openMetrics(measurements, configuration, wifiConnector); static LocalServer localServer(Serial, openMetrics, measurements, configuration, wifiConnector); static AgSerial *agSerial; -static CellularModule *cell; +static CellularModule *cellularModule; static AirgradientClient *agClient; enum NetworkOption { @@ -122,7 +122,7 @@ static String fwNewVersion; static int lastCellSignalQuality = 99; // CSQ // Default value is 0, indicate its not started yet -uint32_t startTimeClientNotReady = 0; +uint32_t agCeClientProblemDetectedTime = 0; SemaphoreHandle_t mutexMeasurementCycleQueue; static std::vector measurementCycleQueue; @@ -554,7 +554,7 @@ void checkForFirmwareUpdate(void) { if (networkOption == UseWifi) { agOta = new AirgradientOTAWifi; } else { - agOta = new AirgradientOTACellular(cell); + agOta = new AirgradientOTACellular(cellularModule); } // Indicate main task that ota is performing @@ -938,8 +938,8 @@ void initializeNetwork() { if (agSerial->open()) { Serial.println("Cellular module found"); // Initialize cellular module and use cellular as agClient - cell = new CellularModuleA7672XX(agSerial, GPIO_POWER_MODULE_PIN); - agClient = new AirgradientCellularClient(cell); + cellularModule = new CellularModuleA7672XX(agSerial, GPIO_POWER_MODULE_PIN); + agClient = new AirgradientCellularClient(cellularModule); networkOption = UseCellular; } else { Serial.println("Cellular module not available, using wifi"); @@ -1496,7 +1496,7 @@ void networkSignalCheck() { if (networkOption == UseWifi) { Serial.printf("WiFi RSSI %d\n", wifiConnector.RSSI()); } else if (networkOption == UseCellular) { - auto result = cell->retrieveSignal(); + auto result = cellularModule->retrieveSignal(); if (result.status != CellReturnStatus::Ok) { agClient->setClientReady(false); lastCellSignalQuality = 99; @@ -1520,14 +1520,14 @@ void networkSignalCheck() { * If in 2 hours still not ready, then restart esp */ void checkCellularClientNotReady() { - if (startTimeClientNotReady > 0 && - (millis() - startTimeClientNotReady) > (2 * 60 * 60000)) { + if (agCeClientProblemDetectedTime > 0 && + (millis() - agCeClientProblemDetectedTime) > (2 * 60 * 60000)) { // Give up wait - Serial.println("CLIENT NOT READY TAKING TOO LONG! Rebooting ..."); + Serial.println("Rebooting because CE client issues for 2 hours detected"); int i = 3; while (i != 0) { if (ag->isOne()) { - String tmp = "Reboot in " + String(i); + String tmp = "Rebooting in " + String(i); oledDisplay.setText("CE error", "too long", tmp.c_str()); } else { Serial.println("Rebooting... " + String(i)); @@ -1577,8 +1577,8 @@ void networkingTask(void *args) { else if (networkOption == UseCellular) { if (agClient->isClientReady() == false) { // Start time if value still default - if (startTimeClientNotReady == 0) { - startTimeClientNotReady = millis(); + if (agCeClientProblemDetectedTime == 0) { + agCeClientProblemDetectedTime = millis(); } // TODO: Need to handle if millis is overflow (back to 0) @@ -1590,15 +1590,16 @@ void networkingTask(void *args) { // Redundant check in both task to make sure its executed checkCellularClientNotReady(); - // Starting from 1 hour since its not ready, power cycling the module + // Power cycling cellular module due to network issues for more than 1 hour bool resetModule = true; - if ((millis() - startTimeClientNotReady) > (60 * 60000)) { + if ((millis() - agCeClientProblemDetectedTime) > (60 * 60000)) { Serial.println("Power cycling module"); - cell->powerOff(); + cellularModule->powerOff(); delay(2000); - cell->powerOn(); + cellularModule->powerOn(); delay(10000); - resetModule = false; // No need to reset module anymore + // no need to reset module when calling ensureClientConnection() + resetModule = false; } // Attempt to reconnect @@ -1610,7 +1611,7 @@ void networkingTask(void *args) { } // Client is ready - startTimeClientNotReady = 0; // reset to default + agCeClientProblemDetectedTime = 0; // reset to default agSerial->setDebug(false); // disable at command debug } } @@ -1643,7 +1644,7 @@ void newMeasurementCycle() { // Get current measures auto mc = measurements.getMeasures(); - mc.signal = cell->csqToDbm(lastCellSignalQuality); // convert to RSSI + mc.signal = cellularModule->csqToDbm(lastCellSignalQuality); // convert to RSSI measurementCycleQueue.push_back(mc); Serial.println("New measurement cycle added to queue"); From 3c8a65a3298081aeb37a9195ea252b219ccce996 Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Thu, 10 Apr 2025 14:58:11 +0700 Subject: [PATCH 09/13] Use esp_timer_get_time for timer of ce client not ready --- examples/OneOpenAir/OneOpenAir.ino | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino index 644b7fdb..db1e4d48 100644 --- a/examples/OneOpenAir/OneOpenAir.ino +++ b/examples/OneOpenAir/OneOpenAir.ino @@ -26,7 +26,6 @@ https://forum.airgradient.com/ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License */ - #include "AgConfigure.h" #include "AgSchedule.h" #include "AgStateMachine.h" @@ -46,6 +45,7 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License #include #include #include +#include #include #include "Libraries/airgradient-client/src/agSerial.h" @@ -75,6 +75,8 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License #define SENSOR_TEMP_HUM_UPDATE_INTERVAL 6000 /** ms */ #define DISPLAY_DELAY_SHOW_CONTENT_MS 2000 /** ms */ #define FIRMWARE_CHECK_FOR_UPDATE_MS (60 * 60 * 1000) /** ms */ +#define TIME_TO_START_POWER_CYCLE_CELLULAR_MODULE (1 * 60) /** minutes */ +#define TIMEOUT_WAIT_FOR_CELLULAR_MODULE_READY (2 * 60) /** minutes */ #define MEASUREMENT_TRANSMIT_CYCLE 3 #define MAXIMUM_MEASUREMENT_CYCLE_QUEUE 80 @@ -90,6 +92,8 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License #define GPIO_EXPANSION_CARD_POWER 4 #define GPIO_IIC_RESET 3 +#define MICROS_TO_MINUTES() ((uint32_t)(esp_timer_get_time() / 1000 / 1000 / 60)) + static MqttClient mqttClient(Serial); static TaskHandle_t mqttTask = NULL; static Configuration configuration(Serial); @@ -122,6 +126,7 @@ static String fwNewVersion; static int lastCellSignalQuality = 99; // CSQ // Default value is 0, indicate its not started yet +// In minutes uint32_t agCeClientProblemDetectedTime = 0; SemaphoreHandle_t mutexMeasurementCycleQueue; @@ -1521,14 +1526,15 @@ void networkSignalCheck() { */ void checkCellularClientNotReady() { if (agCeClientProblemDetectedTime > 0 && - (millis() - agCeClientProblemDetectedTime) > (2 * 60 * 60000)) { + (MICROS_TO_MINUTES() - agCeClientProblemDetectedTime) > + TIMEOUT_WAIT_FOR_CELLULAR_MODULE_READY) { // Give up wait Serial.println("Rebooting because CE client issues for 2 hours detected"); int i = 3; while (i != 0) { if (ag->isOne()) { String tmp = "Rebooting in " + String(i); - oledDisplay.setText("CE error", "too long", tmp.c_str()); + oledDisplay.setText("CE error", "since 1h", tmp.c_str()); } else { Serial.println("Rebooting... " + String(i)); } @@ -1565,6 +1571,9 @@ void networkingTask(void *args) { configSchedule.update(); transmissionSchedule.update(); + + uint32_t startTime = millis(); + while (1) { // Handle reconnection based on mode if (networkOption == UseWifi) { @@ -1578,11 +1587,9 @@ void networkingTask(void *args) { if (agClient->isClientReady() == false) { // Start time if value still default if (agCeClientProblemDetectedTime == 0) { - agCeClientProblemDetectedTime = millis(); + agCeClientProblemDetectedTime = MICROS_TO_MINUTES(); } - // TODO: Need to handle if millis is overflow (back to 0) - // Enable at command debug agSerial->setDebug(true); @@ -1592,14 +1599,16 @@ void networkingTask(void *args) { // Power cycling cellular module due to network issues for more than 1 hour bool resetModule = true; - if ((millis() - agCeClientProblemDetectedTime) > (60 * 60000)) { - Serial.println("Power cycling module"); + if ((MICROS_TO_MINUTES() - agCeClientProblemDetectedTime) > + TIME_TO_START_POWER_CYCLE_CELLULAR_MODULE) { + Serial.println("The CE client hasn't recovered in more than 1 hour, " + "performing a power cycle"); cellularModule->powerOff(); delay(2000); cellularModule->powerOn(); delay(10000); // no need to reset module when calling ensureClientConnection() - resetModule = false; + resetModule = false; } // Attempt to reconnect From 44879927483ed5278a7b9ac3505105ff8b5806f5 Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Thu, 10 Apr 2025 14:58:51 +0700 Subject: [PATCH 10/13] Remove unnecessary code --- examples/OneOpenAir/OneOpenAir.ino | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino index db1e4d48..0d92cbb3 100644 --- a/examples/OneOpenAir/OneOpenAir.ino +++ b/examples/OneOpenAir/OneOpenAir.ino @@ -1571,9 +1571,6 @@ void networkingTask(void *args) { configSchedule.update(); transmissionSchedule.update(); - - uint32_t startTime = millis(); - while (1) { // Handle reconnection based on mode if (networkOption == UseWifi) { From 83504c862857edc0f1e3424fd198dca8ece4b4d0 Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Thu, 10 Apr 2025 19:05:28 +0700 Subject: [PATCH 11/13] Bump libs to latest --- src/Libraries/airgradient-client | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Libraries/airgradient-client b/src/Libraries/airgradient-client index c552adc6..a4ac1493 160000 --- a/src/Libraries/airgradient-client +++ b/src/Libraries/airgradient-client @@ -1 +1 @@ -Subproject commit c552adc6efbaaa80f309b665c9e8c2c0b37401a5 +Subproject commit a4ac14936e91bca7a660536293f2e52297798875 From 0b1c901a76b205750d824d6ae03b72ed5600be50 Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Fri, 11 Apr 2025 13:41:07 +0700 Subject: [PATCH 12/13] Rename cellularModule object name to cellularCard Rename checkCellularClientNotReady to restartIfCeClientIssueOverTwoHours --- examples/OneOpenAir/OneOpenAir.ino | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino index 0d92cbb3..df5c7861 100644 --- a/examples/OneOpenAir/OneOpenAir.ino +++ b/examples/OneOpenAir/OneOpenAir.ino @@ -108,7 +108,7 @@ static OpenMetrics openMetrics(measurements, configuration, wifiConnector); static LocalServer localServer(Serial, openMetrics, measurements, configuration, wifiConnector); static AgSerial *agSerial; -static CellularModule *cellularModule; +static CellularModule *cellularCard; static AirgradientClient *agClient; enum NetworkOption { @@ -156,7 +156,7 @@ static void displayExecuteOta(AirgradientOTA::OtaResult result, String msg, int static int calculateMaxPeriod(int updateInterval); static void setMeasurementMaxPeriod(); static void newMeasurementCycle(); -static void checkCellularClientNotReady(); +static void restartIfCeClientIssueOverTwoHours(); static void networkSignalCheck(); static void networkingTask(void *args); @@ -312,7 +312,7 @@ void loop() { if (networkOption == UseCellular) { // Check if cellular client not ready until certain time // Redundant check in both task to make sure its executed - checkCellularClientNotReady(); + restartIfCeClientIssueOverTwoHours(); } // Schedule to feed external watchdog @@ -559,7 +559,7 @@ void checkForFirmwareUpdate(void) { if (networkOption == UseWifi) { agOta = new AirgradientOTAWifi; } else { - agOta = new AirgradientOTACellular(cellularModule); + agOta = new AirgradientOTACellular(cellularCard); } // Indicate main task that ota is performing @@ -943,8 +943,8 @@ void initializeNetwork() { if (agSerial->open()) { Serial.println("Cellular module found"); // Initialize cellular module and use cellular as agClient - cellularModule = new CellularModuleA7672XX(agSerial, GPIO_POWER_MODULE_PIN); - agClient = new AirgradientCellularClient(cellularModule); + cellularCard = new CellularModuleA7672XX(agSerial, GPIO_POWER_MODULE_PIN); + agClient = new AirgradientCellularClient(cellularCard); networkOption = UseCellular; } else { Serial.println("Cellular module not available, using wifi"); @@ -1501,7 +1501,7 @@ void networkSignalCheck() { if (networkOption == UseWifi) { Serial.printf("WiFi RSSI %d\n", wifiConnector.RSSI()); } else if (networkOption == UseCellular) { - auto result = cellularModule->retrieveSignal(); + auto result = cellularCard->retrieveSignal(); if (result.status != CellReturnStatus::Ok) { agClient->setClientReady(false); lastCellSignalQuality = 99; @@ -1522,9 +1522,9 @@ void networkSignalCheck() { } /** -* If in 2 hours still not ready, then restart esp +* If in 2 hours cellular client still not ready, then restart system */ -void checkCellularClientNotReady() { +void restartIfCeClientIssueOverTwoHours() { if (agCeClientProblemDetectedTime > 0 && (MICROS_TO_MINUTES() - agCeClientProblemDetectedTime) > TIMEOUT_WAIT_FOR_CELLULAR_MODULE_READY) { @@ -1534,7 +1534,7 @@ void checkCellularClientNotReady() { while (i != 0) { if (ag->isOne()) { String tmp = "Rebooting in " + String(i); - oledDisplay.setText("CE error", "since 1h", tmp.c_str()); + oledDisplay.setText("CE error", "since 2h", tmp.c_str()); } else { Serial.println("Rebooting... " + String(i)); } @@ -1592,7 +1592,7 @@ void networkingTask(void *args) { // Check if cellular client not ready until certain time // Redundant check in both task to make sure its executed - checkCellularClientNotReady(); + restartIfCeClientIssueOverTwoHours(); // Power cycling cellular module due to network issues for more than 1 hour bool resetModule = true; @@ -1600,9 +1600,9 @@ void networkingTask(void *args) { TIME_TO_START_POWER_CYCLE_CELLULAR_MODULE) { Serial.println("The CE client hasn't recovered in more than 1 hour, " "performing a power cycle"); - cellularModule->powerOff(); + cellularCard->powerOff(); delay(2000); - cellularModule->powerOn(); + cellularCard->powerOn(); delay(10000); // no need to reset module when calling ensureClientConnection() resetModule = false; @@ -1650,7 +1650,7 @@ void newMeasurementCycle() { // Get current measures auto mc = measurements.getMeasures(); - mc.signal = cellularModule->csqToDbm(lastCellSignalQuality); // convert to RSSI + mc.signal = cellularCard->csqToDbm(lastCellSignalQuality); // convert to RSSI measurementCycleQueue.push_back(mc); Serial.println("New measurement cycle added to queue"); From c6846c818adc692a97bfe096630fd739df222f3d Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Fri, 11 Apr 2025 15:46:21 +0700 Subject: [PATCH 13/13] Rename MICROS_TO_MINUTES() to follow convention --- examples/OneOpenAir/OneOpenAir.ino | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino index df5c7861..94ccac76 100644 --- a/examples/OneOpenAir/OneOpenAir.ino +++ b/examples/OneOpenAir/OneOpenAir.ino @@ -92,7 +92,7 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License #define GPIO_EXPANSION_CARD_POWER 4 #define GPIO_IIC_RESET 3 -#define MICROS_TO_MINUTES() ((uint32_t)(esp_timer_get_time() / 1000 / 1000 / 60)) +#define MINUTES() ((uint32_t)(esp_timer_get_time() / 1000 / 1000 / 60)) static MqttClient mqttClient(Serial); static TaskHandle_t mqttTask = NULL; @@ -1526,7 +1526,7 @@ void networkSignalCheck() { */ void restartIfCeClientIssueOverTwoHours() { if (agCeClientProblemDetectedTime > 0 && - (MICROS_TO_MINUTES() - agCeClientProblemDetectedTime) > + (MINUTES() - agCeClientProblemDetectedTime) > TIMEOUT_WAIT_FOR_CELLULAR_MODULE_READY) { // Give up wait Serial.println("Rebooting because CE client issues for 2 hours detected"); @@ -1584,7 +1584,7 @@ void networkingTask(void *args) { if (agClient->isClientReady() == false) { // Start time if value still default if (agCeClientProblemDetectedTime == 0) { - agCeClientProblemDetectedTime = MICROS_TO_MINUTES(); + agCeClientProblemDetectedTime = MINUTES(); } // Enable at command debug @@ -1596,7 +1596,7 @@ void networkingTask(void *args) { // Power cycling cellular module due to network issues for more than 1 hour bool resetModule = true; - if ((MICROS_TO_MINUTES() - agCeClientProblemDetectedTime) > + if ((MINUTES() - agCeClientProblemDetectedTime) > TIME_TO_START_POWER_CYCLE_CELLULAR_MODULE) { Serial.println("The CE client hasn't recovered in more than 1 hour, " "performing a power cycle");