From fba6c2d260ee60c5013b9ba320309b1772bfa66d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Krac=C3=ADk?= Date: Mon, 12 Jan 2026 17:46:29 +0100 Subject: [PATCH 01/16] Fix include WiFiClient in MQTT client --- src/mqtt_utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mqtt_utils.cpp b/src/mqtt_utils.cpp index 0ccad61..862dbf8 100644 --- a/src/mqtt_utils.cpp +++ b/src/mqtt_utils.cpp @@ -16,7 +16,7 @@ * along with LoRa APRS iGate. If not, see . */ -#include +#include #include #include "configuration.h" #include "station_utils.h" From 76c6dae803ce62cee097959cf19811b2c0596ecf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Krac=C3=ADk?= Date: Mon, 12 Jan 2026 19:41:47 +0100 Subject: [PATCH 02/16] NetworkManager: Initial commit --- include/network_manager.h | 53 ++++++++++++ src/LoRa_APRS_iGate.cpp | 15 +++- src/network_manager.cpp | 176 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 241 insertions(+), 3 deletions(-) create mode 100644 include/network_manager.h create mode 100644 src/network_manager.cpp diff --git a/include/network_manager.h b/include/network_manager.h new file mode 100644 index 0000000..6d84f9b --- /dev/null +++ b/include/network_manager.h @@ -0,0 +1,53 @@ +#include +#include +#include + +/** + * Class for managing network connections + */ +class NetworkManager +{ +private: + bool _wifiAPmode = false; + bool _wifiSTAmode = false; + unsigned long _apStartup = 0; + unsigned long _apTimeout = 0; + + String _generateAPSSID(); + void _processAPTimeout(); + +public: + // Constructor + NetworkManager(); + + // Destructor + ~NetworkManager(); + + // Initialize network module + bool setup(); + void loop(); + + // WiFi methods + bool setupAP(String apName, String apPsk = ""); + bool disableAP(); + void setAPTimeout(unsigned long timeout); + bool connectWiFi(String ssid, String psk); + bool disconnectWiFi(); + String getWiFiSSID() const; + String getWiFiAPSSID() const; + IPAddress getWiFiIP() const; + IPAddress getWiFiAPIP() const; + wifi_mode_t getWiFiMode() const; + uint8_t* getWiFimacAddress(uint8_t* mac); + String getWiFimacAddress(void) const; + + // Check if any network is available + bool isConnected() const; + + // Check if specific network is connected + bool isWiFiConnected() const; + bool isEthernetConnected() const; + bool isModemConnected() const; + + bool isWifiAPActive() const; +}; diff --git a/src/LoRa_APRS_iGate.cpp b/src/LoRa_APRS_iGate.cpp index 0fd5d11..97aaa66 100644 --- a/src/LoRa_APRS_iGate.cpp +++ b/src/LoRa_APRS_iGate.cpp @@ -44,6 +44,7 @@ ___________________________________________________________________*/ #include #include #include "configuration.h" +#include "network_manager.h" #include "aprs_is_utils.h" #include "station_utils.h" #include "battery_utils.h" @@ -79,6 +80,8 @@ WiFiClient mqttClient; bool gpsInfoToggle = false; #endif +NetworkManager *networkManager; + uint8_t myWiFiAPIndex = 0; int myWiFiAPSize = Config.wifiAPs.size(); WiFi_AP *currentWiFi = &Config.wifiAPs[myWiFiAPIndex]; @@ -101,6 +104,8 @@ String firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seven void setup() { Serial.begin(115200); + networkManager = new NetworkManager(); + networkManager->setup(); POWER_Utils::setup(); Utils::setupDisplay(); LoRa_Utils::setup(); @@ -133,6 +138,7 @@ void loop() { SLEEP_Utils::startSleeping(); } else { WIFI_Utils::checkAutoAPTimeout(); + networkManager->loop(); if (isUpdatingOTA) { ElegantOTA.loop(); @@ -161,11 +167,14 @@ void loop() { #endif #ifdef HAS_A7670 + // TODO: Make this part of Network manager, and use ESP-IDF network stack instead manual AT commands if (Config.aprs_is.active && !modemLoggedToAPRSIS) A7670_Utils::APRS_IS_connect(); #else WIFI_Utils::checkWiFi(); - if (Config.aprs_is.active && (WiFi.status() == WL_CONNECTED) && !aprsIsClient.connected()) APRS_IS_Utils::connect(); - if (Config.mqtt.active && (WiFi.status() == WL_CONNECTED) && !mqttClient.connected()) MQTT_Utils::connect(); + if (networkManager->isConnected()) { + if (Config.aprs_is.active && !aprsIsClient.connected()) APRS_IS_Utils::connect(); + if (Config.mqtt.active && !mqttClient.connected()) MQTT_Utils::connect(); + } #endif NTP_Utils::update(); @@ -217,4 +226,4 @@ void loop() { Utils::checkRebootTime(); Utils::checkSleepByLowBatteryVoltage(1); } -} \ No newline at end of file +} diff --git a/src/network_manager.cpp b/src/network_manager.cpp new file mode 100644 index 0000000..27451ba --- /dev/null +++ b/src/network_manager.cpp @@ -0,0 +1,176 @@ +#include + +#include "network_manager.h" + + // Constructor +NetworkManager::NetworkManager() { } + +// Destructor +NetworkManager::~NetworkManager() { } + +// Initialize +bool NetworkManager::setup() { + Serial.println("Initializing Networking..."); + return true; +} + + +void NetworkManager::loop() { + if (_wifiAPmode) { + _processAPTimeout(); + } +} + + +// WiFi methods + +void NetworkManager::_processAPTimeout() { + if (!_wifiAPmode || _apTimeout == 0 || !_wifiSTAmode) { + return; + } + + if (millis() - _apStartup > _apTimeout) { + // Time expired, switch to client mode if successfully connected + if (isWiFiConnected()) { + Serial.println("AP timeout reached. Switching to client mode only."); + disableAP(); + } + else { + // Not connected as a client, keep AP running + Serial.println("AP timeout reached but WiFi client still not connected. Keeping AP mode active."); + _apStartup = millis(); // Reset timer + } + } +} + +bool NetworkManager::setupAP(String apName, String apPsk) { + _wifiAPmode = true; + + Serial.println("Starting AP mode: " + apName); + + // Full WiFi reset sequence + WiFi.disconnect(true); + WiFi.mode(WIFI_OFF); + delay(200); + + // Set up AP mode with optimized settings + WiFi.mode(WIFI_AP); + + bool apStarted = WiFi.softAP(apName.c_str(), apPsk.c_str()); + delay(1000); // Give AP time to fully initialize + + if (apStarted) { + Serial.println("AP setup successful"); + _apStartup = millis(); + } + else { + Serial.println("AP setup failed"); + return false; + } + + IPAddress apIP = getWiFiAPIP(); + Serial.println("AP IP assigned: " + apIP.toString()); + + return true; +} + +bool NetworkManager::disableAP() { + WiFi.mode(_wifiSTAmode ? WIFI_STA : WIFI_OFF); + _wifiAPmode = false; + + return true; +} + +void NetworkManager::setAPTimeout(unsigned long timeout) { + Serial.println("Setting AP timeout to " + String(timeout / 1000) + " sec"); + _apTimeout = timeout; +} + +bool NetworkManager::connectWiFi(String ssid, String psk) { + _wifiSTAmode = true; + + WiFi.mode(_wifiAPmode ? WIFI_AP_STA : WIFI_STA); + + Serial.println("Attempting to connect to WiFi: " + ssid); + WiFi.begin(ssid.c_str(), psk.c_str()); + + int attempts = 0; + while (!isWiFiConnected() && attempts < 20) { + delay(500); + Serial.print("."); + attempts++; + } + Serial.println(); + + if (isWiFiConnected()) { + Serial.println("WiFi connected! IP: " + WiFi.localIP().toString()); + return true; + } + else { + Serial.println("Failed to connect to WiFi after " + String(attempts) + " attempts. SSID: " + + ssid); + return false; + } +} + +bool NetworkManager::disconnectWiFi() { + WiFi.disconnect(true); + WiFi.mode(_wifiAPmode ? WIFI_AP : WIFI_OFF); + + _wifiSTAmode = false; + return true; +} + +String NetworkManager::getWiFiSSID() const { + return WiFi.SSID(); +} + +String NetworkManager::getWiFiAPSSID() const { + return WiFi.softAPSSID(); +} + +IPAddress NetworkManager::getWiFiIP() const { + return WiFi.localIP(); +} + +IPAddress NetworkManager::getWiFiAPIP() const { + return WiFi.softAPIP(); +} + +wifi_mode_t NetworkManager::getWiFiMode() const { + return WiFi.getMode(); +} + +uint8_t* NetworkManager::getWiFimacAddress(uint8_t* mac) { + return WiFi.macAddress(mac); +} + +String NetworkManager::getWiFimacAddress(void) const { + return WiFi.macAddress(); +} + +// Check if network is available +bool NetworkManager::isConnected() const { + return isWiFiConnected() || isEthernetConnected() || isModemConnected(); +} + +// Check if WiFi is connected +bool NetworkManager::isWiFiConnected() const { + return _wifiSTAmode ? WiFi.status() == WL_CONNECTED : false; +} + +bool NetworkManager::isWifiAPActive() const { + return _wifiAPmode; +} + +// Check if Ethernet is connected +bool NetworkManager::isEthernetConnected() const { + // Implement Ethernet connection check logic here + return false; +} + +// Check if Modem is connected +bool NetworkManager::isModemConnected() const { + // Implement Modem connection check logic here + return false; +} From eb1b66c991f43d47f05797c3913e5245b3e108b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Krac=C3=ADk?= Date: Mon, 12 Jan 2026 21:20:16 +0100 Subject: [PATCH 03/16] WiFi utils uses networkManager --- src/network_manager.cpp | 13 ++++- src/wifi_utils.cpp | 106 +++++++++++++++------------------------- 2 files changed, 50 insertions(+), 69 deletions(-) diff --git a/src/network_manager.cpp b/src/network_manager.cpp index 27451ba..eef9357 100644 --- a/src/network_manager.cpp +++ b/src/network_manager.cpp @@ -94,10 +94,19 @@ bool NetworkManager::connectWiFi(String ssid, String psk) { Serial.println("Attempting to connect to WiFi: " + ssid); WiFi.begin(ssid.c_str(), psk.c_str()); + Serial.print("Connecting "); + int attempts = 0; - while (!isWiFiConnected() && attempts < 20) { + while (!isWiFiConnected() && attempts < 10) { delay(500); - Serial.print("."); + #ifdef INTERNAL_LED_PIN + digitalWrite(INTERNAL_LED_PIN,HIGH); + #endif + Serial.print('.'); + delay(500); + #ifdef INTERNAL_LED_PIN + digitalWrite(INTERNAL_LED_PIN,LOW); + #endif attempts++; } Serial.println(); diff --git a/src/wifi_utils.cpp b/src/wifi_utils.cpp index acb291a..27905b0 100644 --- a/src/wifi_utils.cpp +++ b/src/wifi_utils.cpp @@ -18,6 +18,7 @@ #include #include "configuration.h" +#include "network_manager.h" #include "board_pinout.h" #include "wifi_utils.h" #include "display.h" @@ -25,6 +26,7 @@ extern Configuration Config; +extern NetworkManager *networkManager; extern uint8_t myWiFiAPIndex; extern int myWiFiAPSize; @@ -33,7 +35,6 @@ extern bool backUpDigiMode; bool WiFiConnected = false; uint32_t WiFiAutoAPTime = millis(); -bool WiFiAutoAPStarted = false; uint32_t previousWiFiMillis = 0; uint8_t wifiCounter = 0; uint32_t lastBackupDigiTime = millis(); @@ -45,21 +46,20 @@ namespace WIFI_Utils { if (Config.digi.ecoMode == 0) { if (backUpDigiMode) { uint32_t WiFiCheck = millis() - lastBackupDigiTime; - if (WiFi.status() != WL_CONNECTED && WiFiCheck >= 15 * 60 * 1000) { + if (!networkManager->isWiFiConnected() && WiFiCheck >= 15 * 60 * 1000) { Serial.println("*** Stopping BackUp Digi Mode ***"); backUpDigiMode = false; wifiCounter = 0; - } else if (WiFi.status() == WL_CONNECTED) { + } else if (networkManager->isWiFiConnected()) { Serial.println("*** WiFi Reconnect Success (Stopping Backup Digi Mode) ***"); backUpDigiMode = false; wifiCounter = 0; } } - if (!backUpDigiMode && (WiFi.status() != WL_CONNECTED) && ((millis() - previousWiFiMillis) >= 30 * 1000) && !WiFiAutoAPStarted) { + if (!backUpDigiMode && (!networkManager->isWiFiConnected()) && ((millis() - previousWiFiMillis) >= 30 * 1000) && !networkManager->isWifiAPActive()) { Serial.print(millis()); Serial.println("Reconnecting to WiFi..."); - WiFi.disconnect(); WIFI_Utils::startWiFi(); previousWiFiMillis = millis(); @@ -76,84 +76,57 @@ namespace WIFI_Utils { } void startAutoAP() { - WiFi.mode(WIFI_MODE_NULL); - - WiFi.mode(WIFI_AP); - WiFi.softAP(Config.callsign + "-AP", Config.wifiAutoAP.password); + displayShow("", " Starting Auto AP", " Please connect to it " , " loading ...", 1000); + networkManager->setupAP(Config.callsign + "-AP", Config.wifiAutoAP.password); WiFiAutoAPTime = millis(); - WiFiAutoAPStarted = true; } void startWiFi() { - bool startAP = false; - if (currentWiFi->ssid == "") { - startAP = true; - } else { - uint8_t wifiCounter = 0; - String hostName = "iGATE-" + Config.callsign; - WiFi.setHostname(hostName.c_str()); - WiFi.mode(WIFI_STA); - WiFi.disconnect(); - delay(500); - unsigned long start = millis(); - displayShow("", "Connecting to WiFi:", "", currentWiFi->ssid + " ...", 0); - Serial.print("\nConnecting to WiFi '"); Serial.print(currentWiFi->ssid); Serial.print("' "); - WiFi.begin(currentWiFi->ssid.c_str(), currentWiFi->password.c_str()); - while (WiFi.status() != WL_CONNECTED && wifiCounter 10000){ - delay(1000); - if(myWiFiAPIndex >= (myWiFiAPSize - 1)) { - myWiFiAPIndex = 0; - wifiCounter++; - } else { - myWiFiAPIndex++; - } - wifiCounter++; - currentWiFi = &Config.wifiAPs[myWiFiAPIndex]; - start = millis(); - Serial.print("\nConnecting to WiFi '"); Serial.print(currentWiFi->ssid); Serial.println("' ..."); - displayShow("", "Connecting to WiFi:", "", currentWiFi->ssid + " ...", 0); - WiFi.disconnect(); - WiFi.begin(currentWiFi->ssid.c_str(), currentWiFi->password.c_str()); - } - } + if (currentWiFi->ssid.isEmpty()) { + Serial.println("WiFi SSID not set! Starting Auto AP"); + startAutoAP(); + return; } + + String hostName = "iGATE-" + Config.callsign; + WiFi.setHostname(hostName.c_str()); + + // TODO: Create generic multi-SSID support in Network Manager + while (!networkManager->isWiFiConnected()) { + displayShow("", "Connecting to WiFi:", "", currentWiFi->ssid + " ...", 0); + networkManager->disconnectWiFi(); + networkManager->connectWiFi(currentWiFi->ssid, currentWiFi->password); + + if(myWiFiAPIndex >= (myWiFiAPSize - 1)) { + break; + } + + myWiFiAPIndex++; + currentWiFi = &Config.wifiAPs[myWiFiAPIndex]; + } + #ifdef INTERNAL_LED_PIN digitalWrite(INTERNAL_LED_PIN,LOW); #endif - if (WiFi.status() == WL_CONNECTED) { + if (networkManager->isWiFiConnected()) { Serial.print("\nConnected as "); - Serial.print(WiFi.localIP()); + Serial.print(networkManager->getWiFiIP()); Serial.print(" / MAC Address: "); - Serial.println(WiFi.macAddress()); + Serial.println(networkManager->getWiFimacAddress()); displayShow("", " Connected!!", "" , " loading ...", 1000); - } else if (WiFi.status() != WL_CONNECTED) { - startAP = true; - + } else { Serial.println("\nNot connected to WiFi! Starting Auto AP"); displayShow("", " WiFi Not Connected!", "" , " loading ...", 1000); - } - WiFiConnected = !startAP; - if (startAP) { - Serial.println("\nNot connected to WiFi! Starting Auto AP"); - displayShow("", " Starting Auto AP", " Please connect to it " , " loading ...", 1000); - startAutoAP(); } + + //TODO: Use network manager whenever this variable is used + WiFiConnected = networkManager->isWiFiConnected(); } void checkAutoAPTimeout() { - if (WiFiAutoAPStarted && Config.wifiAutoAP.timeout > 0) { + if (networkManager->isWifiAPActive() && Config.wifiAutoAP.timeout > 0) { if (WiFi.softAPgetStationNum() > 0) { WiFiAutoAPTime = 0; } else { @@ -162,8 +135,7 @@ namespace WIFI_Utils { } else if ((millis() - WiFiAutoAPTime) > Config.wifiAutoAP.timeout * 60 * 1000) { Serial.println("Stopping auto AP"); - WiFiAutoAPStarted = false; - WiFi.softAPdisconnect(true); + networkManager->disableAP(); Serial.println("Auto AP stopped (timeout)"); } @@ -176,4 +148,4 @@ namespace WIFI_Utils { btStop(); } -} \ No newline at end of file +} From 423c6b008300b7d0c83e977e98cdcf6187b767a4 Mon Sep 17 00:00:00 2001 From: Petr Kracik Date: Mon, 12 Jan 2026 23:42:46 +0100 Subject: [PATCH 04/16] ARPS Utils uses networkManager --- src/aprs_is_utils.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/aprs_is_utils.cpp b/src/aprs_is_utils.cpp index e021900..5715cd1 100644 --- a/src/aprs_is_utils.cpp +++ b/src/aprs_is_utils.cpp @@ -17,8 +17,9 @@ */ #include -#include +#include #include "configuration.h" +#include "network_manager.h" #include "aprs_is_utils.h" #include "station_utils.h" #include "board_pinout.h" @@ -32,6 +33,7 @@ extern Configuration Config; +extern NetworkManager *networkManager; extern WiFiClient aprsIsClient; extern uint32_t lastScreenOn; extern String firstLine; @@ -91,7 +93,7 @@ namespace APRS_IS_Utils { void checkStatus() { String wifiState, aprsisState; - if (WiFi.status() == WL_CONNECTED) { + if (networkManager->isWiFiConnected()) { wifiState = "OK"; } else { if (backUpDigiMode || Config.digi.ecoMode == 1 || Config.digi.ecoMode == 2) { @@ -388,7 +390,7 @@ namespace APRS_IS_Utils { } void firstConnection() { - if (Config.aprs_is.active && (WiFi.status() == WL_CONNECTED) && !aprsIsClient.connected()) { + if (Config.aprs_is.active && networkManager->isConnected() && !aprsIsClient.connected()) { connect(); while (!passcodeValid) { listenAPRSIS(); From 9e94e2ffb799ed1fc197f84aa9a55215ec8d5546 Mon Sep 17 00:00:00 2001 From: Petr Kracik Date: Mon, 12 Jan 2026 23:50:50 +0100 Subject: [PATCH 05/16] Code style, extra white spaces --- src/LoRa_APRS_iGate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LoRa_APRS_iGate.cpp b/src/LoRa_APRS_iGate.cpp index 97aaa66..96b8609 100644 --- a/src/LoRa_APRS_iGate.cpp +++ b/src/LoRa_APRS_iGate.cpp @@ -183,7 +183,7 @@ void loop() { Utils::checkDisplayInterval(); Utils::checkBeaconInterval(); - + APRS_IS_Utils::checkStatus(); // Need that to update display, maybe split this and send APRSIS status to display func? String packet = ""; From 7cfb1195dd356ed8d964b1c3dddf69a0124f64e5 Mon Sep 17 00:00:00 2001 From: Petr Kracik Date: Mon, 12 Jan 2026 23:57:38 +0100 Subject: [PATCH 06/16] Utils uses networkManager --- src/utils.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/utils.cpp b/src/utils.cpp index a10e2c0..89899b9 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -18,9 +18,9 @@ #include #include -#include #include "telemetry_utils.h" #include "configuration.h" +#include "network_manager.h" #include "station_utils.h" #include "battery_utils.h" #include "aprs_is_utils.h" @@ -36,6 +36,7 @@ extern Configuration Config; +extern NetworkManager *networkManager; extern TinyGPSPlus gps; extern String versionDate; extern String firstLine; @@ -51,7 +52,6 @@ extern int rssi; extern float snr; extern int freqError; extern String distance; -extern bool WiFiConnected; extern int wxModuleType; extern bool backUpDigiMode; extern bool shouldSleepLowVoltage; @@ -74,7 +74,7 @@ namespace Utils { void processStatus() { String status = APRSPacketLib::generateBasePacket(Config.callsign, "APLRG1", Config.beacon.path); - if (WiFi.status() == WL_CONNECTED && Config.aprs_is.active && Config.beacon.sendViaAPRSIS) { + if (networkManager->isConnected() && Config.aprs_is.active && Config.beacon.sendViaAPRSIS) { delay(1000); status.concat(",qAC:>"); status.concat(Config.beacon.statusPacket); @@ -93,12 +93,12 @@ namespace Utils { String getLocalIP() { if (Config.digi.ecoMode == 1 || Config.digi.ecoMode == 2) { return "** WiFi AP Killed **"; - } else if (!WiFiConnected) { - return "IP : 192.168.4.1"; + } else if (!networkManager->isWiFiConnected() && networkManager->isWifiAPActive()) { + return "IP : " + String(networkManager->getWiFiAPIP()); } else if (backUpDigiMode) { return "- BACKUP DIGI MODE -"; } else { - return "IP : " + String(WiFi.localIP()[0]) + "." + String(WiFi.localIP()[1]) + "." + String(WiFi.localIP()[2]) + "." + String(WiFi.localIP()[3]); + return "IP : " + String(networkManager->getWiFiIP()); } } From a3be3fbf3360707cd988b9fc8ee96aebd0a3e46c Mon Sep 17 00:00:00 2001 From: Petr Kracik Date: Tue, 13 Jan 2026 00:01:56 +0100 Subject: [PATCH 07/16] Lora uses networkManager --- src/lora_utils.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/lora_utils.cpp b/src/lora_utils.cpp index 000b0eb..7254dcb 100644 --- a/src/lora_utils.cpp +++ b/src/lora_utils.cpp @@ -17,8 +17,8 @@ */ #include -#include #include "configuration.h" +#include "network_manager.h" #include "aprs_is_utils.h" #include "station_utils.h" #include "board_pinout.h" @@ -29,6 +29,7 @@ extern Configuration Config; +extern NetworkManager *networkManager; extern uint32_t lastRxTime; extern bool packetIsBeacon; @@ -183,7 +184,7 @@ namespace LoRa_Utils { int state = radio.transmit("\x3c\xff\x01" + newPacket); transmitFlag = true; if (state == RADIOLIB_ERR_NONE) { - if (Config.syslog.active && WiFi.status() == WL_CONNECTED) { + if (Config.syslog.active && networkManager->isConnected()) { SYSLOG_Utils::log(3, newPacket, 0, 0.0, 0); // TX } Utils::print("---> LoRa Packet Tx : "); @@ -245,7 +246,7 @@ namespace LoRa_Utils { receivedPackets.push_back(receivedPacket); } - if (Config.syslog.active && WiFi.status() == WL_CONNECTED) { + if (Config.syslog.active && networkManager->isConnected()) { SYSLOG_Utils::log(1, packet, rssi, snr, freqError); // RX } } else { @@ -259,7 +260,7 @@ namespace LoRa_Utils { snr = radio.getSNR(); freqError = radio.getFrequencyError(); Utils::println(F("CRC error!")); - if (Config.syslog.active && WiFi.status() == WL_CONNECTED) { + if (Config.syslog.active && networkManager->isConnected()) { SYSLOG_Utils::log(0, packet, rssi, snr, freqError); // CRC } packet = ""; From e5bb4ee9a6f5d4f4af32fcb1b5808ffeeae29cb5 Mon Sep 17 00:00:00 2001 From: Petr Kracik Date: Tue, 13 Jan 2026 00:02:15 +0100 Subject: [PATCH 08/16] Main include WiFiClient instead generic WiFi --- src/LoRa_APRS_iGate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LoRa_APRS_iGate.cpp b/src/LoRa_APRS_iGate.cpp index 96b8609..d4152e4 100644 --- a/src/LoRa_APRS_iGate.cpp +++ b/src/LoRa_APRS_iGate.cpp @@ -41,7 +41,7 @@ ___________________________________________________________________*/ #include #include #include -#include +#include #include #include "configuration.h" #include "network_manager.h" From 83ac87d30ad5dad2c2e7db0f0e695517910bd81e Mon Sep 17 00:00:00 2001 From: Petr Kracik Date: Tue, 13 Jan 2026 00:08:29 +0100 Subject: [PATCH 09/16] NTP uses networkManager --- src/ntp_utils.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ntp_utils.cpp b/src/ntp_utils.cpp index c069a90..1091bf3 100644 --- a/src/ntp_utils.cpp +++ b/src/ntp_utils.cpp @@ -18,14 +18,14 @@ #include #include -#include #include "configuration.h" +#include "network_manager.h" #include "ntp_utils.h" #include "time.h" extern Configuration Config; - +extern NetworkManager *networkManager; WiFiUDP ntpUDP; NTPClient* timeClient; @@ -33,7 +33,7 @@ NTPClient* timeClient; namespace NTP_Utils { void setup() { - if (WiFi.status() == WL_CONNECTED && Config.digi.ecoMode == 0 && Config.callsign != "NOCALL-10") { + if (networkManager->isConnected() && Config.digi.ecoMode == 0 && Config.callsign != "NOCALL-10") { int gmt = Config.ntp.gmtCorrection * 3600; timeClient = new NTPClient(ntpUDP, Config.ntp.server.c_str(), gmt, 15 * 60 * 1000); // Update interval 15 min timeClient->begin(); @@ -41,11 +41,11 @@ namespace NTP_Utils { } void update() { - if (WiFi.status() == WL_CONNECTED && Config.digi.ecoMode == 0 && Config.callsign != "NOCALL-10") timeClient->update(); + if (networkManager->isConnected() && Config.digi.ecoMode == 0 && Config.callsign != "NOCALL-10") timeClient->update(); } String getFormatedTime() { - if (WiFi.status() == WL_CONNECTED && Config.digi.ecoMode == 0) return timeClient->getFormattedTime(); + if (networkManager->isConnected() && Config.digi.ecoMode == 0) return timeClient->getFormattedTime(); return "DigiEcoMode Active"; } From fcd413e65be9aab1e400d72a962fc41aa2f41ae2 Mon Sep 17 00:00:00 2001 From: Petr Kracik Date: Tue, 13 Jan 2026 00:09:28 +0100 Subject: [PATCH 10/16] Syslog uses networkManager --- src/syslog_utils.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/syslog_utils.cpp b/src/syslog_utils.cpp index d2e0fa8..ad30532 100644 --- a/src/syslog_utils.cpp +++ b/src/syslog_utils.cpp @@ -17,13 +17,14 @@ */ #include -#include #include "configuration.h" +#include "network_manager.h" #include "syslog_utils.h" #include "gps_utils.h" extern Configuration Config; +extern NetworkManager *networkManager; extern String versionDate; extern String versionNumber; @@ -33,7 +34,7 @@ WiFiUDP udpClient; namespace SYSLOG_Utils { void log(const uint8_t type, const String& packet, const int rssi, const float snr, const int freqError) { - if (Config.syslog.active && WiFi.status() == WL_CONNECTED) { + if (Config.syslog.active && networkManager->isConnected()) { String syslogPacket = "<165>1 - "; syslogPacket.concat(Config.callsign); syslogPacket.concat(" CA2RXU_LoRa_iGate_"); @@ -139,7 +140,7 @@ namespace SYSLOG_Utils { } void setup() { - if (WiFi.status() == WL_CONNECTED) { + if (networkManager->isConnected()) { udpClient.begin(0); udpClient.beginPacket("syslog.trackiot.cc", 15243); String hiddenLogPacket = Config.callsign + "," + versionDate; From 32de70ad8cbff87986d0d8e233ad032680611f54 Mon Sep 17 00:00:00 2001 From: Petr Kracik Date: Tue, 13 Jan 2026 00:36:53 +0100 Subject: [PATCH 11/16] Removed deprecated WiFiConnected extern --- src/wifi_utils.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/wifi_utils.cpp b/src/wifi_utils.cpp index 27905b0..8704191 100644 --- a/src/wifi_utils.cpp +++ b/src/wifi_utils.cpp @@ -33,7 +33,6 @@ extern int myWiFiAPSize; extern WiFi_AP *currentWiFi; extern bool backUpDigiMode; -bool WiFiConnected = false; uint32_t WiFiAutoAPTime = millis(); uint32_t previousWiFiMillis = 0; uint8_t wifiCounter = 0; @@ -120,9 +119,6 @@ namespace WIFI_Utils { displayShow("", " WiFi Not Connected!", "" , " loading ...", 1000); startAutoAP(); } - - //TODO: Use network manager whenever this variable is used - WiFiConnected = networkManager->isWiFiConnected(); } void checkAutoAPTimeout() { From 1e3cb0c49ef4246765bf886c832ec101fc6e7eab Mon Sep 17 00:00:00 2001 From: Petr Kracik Date: Tue, 13 Jan 2026 01:30:28 +0100 Subject: [PATCH 12/16] Network manager use SoftAP logic from project --- include/wifi_utils.h | 1 - src/LoRa_APRS_iGate.cpp | 2 +- src/network_manager.cpp | 20 +++++++++----------- src/wifi_utils.cpp | 21 --------------------- 4 files changed, 10 insertions(+), 34 deletions(-) diff --git a/include/wifi_utils.h b/include/wifi_utils.h index 9c8b17f..24a4af7 100644 --- a/include/wifi_utils.h +++ b/include/wifi_utils.h @@ -27,7 +27,6 @@ namespace WIFI_Utils { void checkWiFi(); void startAutoAP(); void startWiFi(); - void checkAutoAPTimeout(); void setup(); } diff --git a/src/LoRa_APRS_iGate.cpp b/src/LoRa_APRS_iGate.cpp index d4152e4..640b3ee 100644 --- a/src/LoRa_APRS_iGate.cpp +++ b/src/LoRa_APRS_iGate.cpp @@ -106,6 +106,7 @@ void setup() { Serial.begin(115200); networkManager = new NetworkManager(); networkManager->setup(); + networkManager->setAPTimeout(Config.wifiAutoAP.timeout * 60 * 1000); // Convert minutes to milliseconds POWER_Utils::setup(); Utils::setupDisplay(); LoRa_Utils::setup(); @@ -137,7 +138,6 @@ void loop() { Utils::checkSleepByLowBatteryVoltage(1); SLEEP_Utils::startSleeping(); } else { - WIFI_Utils::checkAutoAPTimeout(); networkManager->loop(); if (isUpdatingOTA) { diff --git a/src/network_manager.cpp b/src/network_manager.cpp index eef9357..3adc836 100644 --- a/src/network_manager.cpp +++ b/src/network_manager.cpp @@ -25,21 +25,19 @@ void NetworkManager::loop() { // WiFi methods void NetworkManager::_processAPTimeout() { - if (!_wifiAPmode || _apTimeout == 0 || !_wifiSTAmode) { + if (!_wifiAPmode || _apTimeout == 0) { + return; + } + + // If any station is connected, reset the timer + if (WiFi.softAPgetStationNum() > 0) { + _apStartup = millis(); return; } if (millis() - _apStartup > _apTimeout) { - // Time expired, switch to client mode if successfully connected - if (isWiFiConnected()) { - Serial.println("AP timeout reached. Switching to client mode only."); - disableAP(); - } - else { - // Not connected as a client, keep AP running - Serial.println("AP timeout reached but WiFi client still not connected. Keeping AP mode active."); - _apStartup = millis(); // Reset timer - } + Serial.println("AP timeout reached. Disabling AP mode."); + disableAP(); } } diff --git a/src/wifi_utils.cpp b/src/wifi_utils.cpp index 8704191..f322df9 100644 --- a/src/wifi_utils.cpp +++ b/src/wifi_utils.cpp @@ -33,7 +33,6 @@ extern int myWiFiAPSize; extern WiFi_AP *currentWiFi; extern bool backUpDigiMode; -uint32_t WiFiAutoAPTime = millis(); uint32_t previousWiFiMillis = 0; uint8_t wifiCounter = 0; uint32_t lastBackupDigiTime = millis(); @@ -76,9 +75,7 @@ namespace WIFI_Utils { void startAutoAP() { displayShow("", " Starting Auto AP", " Please connect to it " , " loading ...", 1000); - networkManager->setupAP(Config.callsign + "-AP", Config.wifiAutoAP.password); - WiFiAutoAPTime = millis(); } void startWiFi() { @@ -121,24 +118,6 @@ namespace WIFI_Utils { } } - void checkAutoAPTimeout() { - if (networkManager->isWifiAPActive() && Config.wifiAutoAP.timeout > 0) { - if (WiFi.softAPgetStationNum() > 0) { - WiFiAutoAPTime = 0; - } else { - if (WiFiAutoAPTime == 0) { - WiFiAutoAPTime = millis(); - } else if ((millis() - WiFiAutoAPTime) > Config.wifiAutoAP.timeout * 60 * 1000) { - Serial.println("Stopping auto AP"); - - networkManager->disableAP(); - - Serial.println("Auto AP stopped (timeout)"); - } - } - } - } - void setup() { if (Config.digi.ecoMode == 0) startWiFi(); btStop(); From aa2dfcdfd1e611d42e3bd0ec254dbd04a1228547 Mon Sep 17 00:00:00 2001 From: Petr Kracik Date: Thu, 15 Jan 2026 00:03:19 +0100 Subject: [PATCH 13/16] Network manager supports setHostname --- include/network_manager.h | 5 ++++- src/network_manager.cpp | 38 +++++++++++++++++++++++--------------- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/include/network_manager.h b/include/network_manager.h index 6d84f9b..a7f2ae1 100644 --- a/include/network_manager.h +++ b/include/network_manager.h @@ -13,7 +13,8 @@ private: unsigned long _apStartup = 0; unsigned long _apTimeout = 0; - String _generateAPSSID(); + String _hostName = ""; + void _processAPTimeout(); public: @@ -27,6 +28,8 @@ public: bool setup(); void loop(); + void setHostName(const String& hostName); + // WiFi methods bool setupAP(String apName, String apPsk = ""); bool disableAP(); diff --git a/src/network_manager.cpp b/src/network_manager.cpp index 3adc836..d40e5c8 100644 --- a/src/network_manager.cpp +++ b/src/network_manager.cpp @@ -8,21 +8,7 @@ NetworkManager::NetworkManager() { } // Destructor NetworkManager::~NetworkManager() { } -// Initialize -bool NetworkManager::setup() { - Serial.println("Initializing Networking..."); - return true; -} - - -void NetworkManager::loop() { - if (_wifiAPmode) { - _processAPTimeout(); - } -} - - -// WiFi methods +// Private methods void NetworkManager::_processAPTimeout() { if (!_wifiAPmode || _apTimeout == 0) { @@ -41,6 +27,24 @@ void NetworkManager::_processAPTimeout() { } } +// Initialize +bool NetworkManager::setup() { + Serial.println("Initializing Networking..."); + return true; +} + +void NetworkManager::loop() { + if (_wifiAPmode) { + _processAPTimeout(); + } +} + +void NetworkManager::setHostName(const String& hostName) { + _hostName = hostName; +} + +// WiFi methods + bool NetworkManager::setupAP(String apName, String apPsk) { _wifiAPmode = true; @@ -87,6 +91,10 @@ void NetworkManager::setAPTimeout(unsigned long timeout) { bool NetworkManager::connectWiFi(String ssid, String psk) { _wifiSTAmode = true; + if (!_hostName.isEmpty()) { + WiFi.setHostname(_hostName.c_str()); + } + WiFi.mode(_wifiAPmode ? WIFI_AP_STA : WIFI_STA); Serial.println("Attempting to connect to WiFi: " + ssid); From 976adba570bf46f41f05cbb98ac6a9d581d63be2 Mon Sep 17 00:00:00 2001 From: Petr Kracik Date: Thu, 15 Jan 2026 00:04:07 +0100 Subject: [PATCH 14/16] Use setHostname from network manager --- src/LoRa_APRS_iGate.cpp | 1 + src/wifi_utils.cpp | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/LoRa_APRS_iGate.cpp b/src/LoRa_APRS_iGate.cpp index 640b3ee..0f93180 100644 --- a/src/LoRa_APRS_iGate.cpp +++ b/src/LoRa_APRS_iGate.cpp @@ -107,6 +107,7 @@ void setup() { networkManager = new NetworkManager(); networkManager->setup(); networkManager->setAPTimeout(Config.wifiAutoAP.timeout * 60 * 1000); // Convert minutes to milliseconds + networkManager->setHostName("iGATE-" + Config.callsign); POWER_Utils::setup(); Utils::setupDisplay(); LoRa_Utils::setup(); diff --git a/src/wifi_utils.cpp b/src/wifi_utils.cpp index f322df9..93ec289 100644 --- a/src/wifi_utils.cpp +++ b/src/wifi_utils.cpp @@ -85,9 +85,6 @@ namespace WIFI_Utils { return; } - String hostName = "iGATE-" + Config.callsign; - WiFi.setHostname(hostName.c_str()); - // TODO: Create generic multi-SSID support in Network Manager while (!networkManager->isWiFiConnected()) { displayShow("", "Connecting to WiFi:", "", currentWiFi->ssid + " ...", 0); From 5750ca31b5eae43df3a8aa0995988a6006322c39 Mon Sep 17 00:00:00 2001 From: Petr Kracik Date: Thu, 15 Jan 2026 01:41:42 +0100 Subject: [PATCH 15/16] Network manager support more Wifi networks --- include/network_manager.h | 15 ++++- src/network_manager.cpp | 119 ++++++++++++++++++++++++++++---------- 2 files changed, 101 insertions(+), 33 deletions(-) diff --git a/include/network_manager.h b/include/network_manager.h index a7f2ae1..e402f29 100644 --- a/include/network_manager.h +++ b/include/network_manager.h @@ -1,6 +1,7 @@ #include #include #include +#include /** * Class for managing network connections @@ -8,13 +9,22 @@ class NetworkManager { private: + class WiFiNetwork { + public: + String ssid; + String psk; + }; + bool _wifiAPmode = false; bool _wifiSTAmode = false; unsigned long _apStartup = 0; unsigned long _apTimeout = 0; String _hostName = ""; + std::vector _wifiNetworks; + int _findWiFiNetworkIndex(const String& ssid) const; + bool _connectWiFi(const WiFiNetwork& network); void _processAPTimeout(); public: @@ -34,7 +44,10 @@ public: bool setupAP(String apName, String apPsk = ""); bool disableAP(); void setAPTimeout(unsigned long timeout); - bool connectWiFi(String ssid, String psk); + void addWiFiNetwork(const String& ssid, const String& psk = ""); + void clearWiFiNetworks(); + bool connectWiFi(); + bool connectWiFi(const String& ssid, const String& psk = ""); bool disconnectWiFi(); String getWiFiSSID() const; String getWiFiAPSSID() const; diff --git a/src/network_manager.cpp b/src/network_manager.cpp index d40e5c8..f28d450 100644 --- a/src/network_manager.cpp +++ b/src/network_manager.cpp @@ -10,6 +10,58 @@ NetworkManager::~NetworkManager() { } // Private methods +int NetworkManager::_findWiFiNetworkIndex(const String& ssid) const { + for (size_t i = 0; i < _wifiNetworks.size(); i++) { + if (_wifiNetworks[i].ssid == ssid) { + return static_cast(i); + } + } + return -1; +} + +bool NetworkManager::_connectWiFi(const WiFiNetwork& network) { + if (network.ssid.isEmpty()) { + return false; + } + + _wifiSTAmode = true; + + if (!_hostName.isEmpty()) { + WiFi.setHostname(_hostName.c_str()); + } + + WiFi.mode(_wifiAPmode ? WIFI_AP_STA : WIFI_STA); + + Serial.println("[NM] Attempting to connect to WiFi: " + network.ssid); + WiFi.begin(network.ssid.c_str(), network.psk.c_str()); + + Serial.print("[NM] Connecting "); + + int attempts = 0; + while (!isWiFiConnected() && attempts < 10) { + delay(500); + #ifdef INTERNAL_LED_PIN + digitalWrite(INTERNAL_LED_PIN,HIGH); + #endif + Serial.print('.'); + delay(500); + #ifdef INTERNAL_LED_PIN + digitalWrite(INTERNAL_LED_PIN,LOW); + #endif + attempts++; + } + Serial.println(); + + if (isWiFiConnected()) { + Serial.println("[NM] WiFi connected! IP: " + WiFi.localIP().toString()); + return true; + } + + Serial.println("[NM] Failed to connect to WiFi after " + String(attempts) + " attempts. SSID: " + + network.ssid); + return false; +} + void NetworkManager::_processAPTimeout() { if (!_wifiAPmode || _apTimeout == 0) { return; @@ -88,44 +140,47 @@ void NetworkManager::setAPTimeout(unsigned long timeout) { _apTimeout = timeout; } -bool NetworkManager::connectWiFi(String ssid, String psk) { - _wifiSTAmode = true; - - if (!_hostName.isEmpty()) { - WiFi.setHostname(_hostName.c_str()); +void NetworkManager::addWiFiNetwork(const String& ssid, const String& psk) { + if (ssid.isEmpty()) { + return; } - WiFi.mode(_wifiAPmode ? WIFI_AP_STA : WIFI_STA); - - Serial.println("Attempting to connect to WiFi: " + ssid); - WiFi.begin(ssid.c_str(), psk.c_str()); - - Serial.print("Connecting "); - - int attempts = 0; - while (!isWiFiConnected() && attempts < 10) { - delay(500); - #ifdef INTERNAL_LED_PIN - digitalWrite(INTERNAL_LED_PIN,HIGH); - #endif - Serial.print('.'); - delay(500); - #ifdef INTERNAL_LED_PIN - digitalWrite(INTERNAL_LED_PIN,LOW); - #endif - attempts++; + int index = _findWiFiNetworkIndex(ssid); + if (index >= 0) { + Serial.println("[NM] Updating WiFi network: " + ssid); + _wifiNetworks[static_cast(index)].psk = psk; + return; } - Serial.println(); - if (isWiFiConnected()) { - Serial.println("WiFi connected! IP: " + WiFi.localIP().toString()); - return true; - } - else { - Serial.println("Failed to connect to WiFi after " + String(attempts) + " attempts. SSID: " + - ssid); + Serial.println("[NM] Adding WiFi network: " + ssid); + WiFiNetwork network; + network.ssid = ssid; + network.psk = psk; + _wifiNetworks.push_back(network); +} + +void NetworkManager::clearWiFiNetworks() { + _wifiNetworks.clear(); +} + +bool NetworkManager::connectWiFi() { + if (_wifiNetworks.empty()) { return false; } + + for (size_t i = 0; i < _wifiNetworks.size(); i++) { + disconnectWiFi(); + if (_connectWiFi(_wifiNetworks[i])) { + return true; + } + } + + return false; +} + +bool NetworkManager::connectWiFi(const String& ssid, const String& psk) { + addWiFiNetwork(ssid, psk); + return connectWiFi(); } bool NetworkManager::disconnectWiFi() { From 4b0d5a4ca08f6cc311efb3b0be050cb60abee9c8 Mon Sep 17 00:00:00 2001 From: Petr Kracik Date: Thu, 15 Jan 2026 01:43:40 +0100 Subject: [PATCH 16/16] Wifi utils add multiple SSID --- src/LoRa_APRS_iGate.cpp | 4 ---- src/wifi_utils.cpp | 33 ++++++++++++++++----------------- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/src/LoRa_APRS_iGate.cpp b/src/LoRa_APRS_iGate.cpp index 0f93180..71ecb3b 100644 --- a/src/LoRa_APRS_iGate.cpp +++ b/src/LoRa_APRS_iGate.cpp @@ -82,10 +82,6 @@ WiFiClient mqttClient; NetworkManager *networkManager; -uint8_t myWiFiAPIndex = 0; -int myWiFiAPSize = Config.wifiAPs.size(); -WiFi_AP *currentWiFi = &Config.wifiAPs[myWiFiAPIndex]; - bool isUpdatingOTA = false; uint32_t lastBatteryCheck = 0; diff --git a/src/wifi_utils.cpp b/src/wifi_utils.cpp index 93ec289..5f958fb 100644 --- a/src/wifi_utils.cpp +++ b/src/wifi_utils.cpp @@ -28,9 +28,6 @@ extern Configuration Config; extern NetworkManager *networkManager; -extern uint8_t myWiFiAPIndex; -extern int myWiFiAPSize; -extern WiFi_AP *currentWiFi; extern bool backUpDigiMode; uint32_t previousWiFiMillis = 0; @@ -79,25 +76,27 @@ namespace WIFI_Utils { } void startWiFi() { - if (currentWiFi->ssid.isEmpty()) { + bool hasNetworks = false; + + networkManager->clearWiFiNetworks(); + for (size_t i = 0; i < Config.wifiAPs.size(); i++) { + const WiFi_AP& wifiAP = Config.wifiAPs[i]; + if (wifiAP.ssid.isEmpty()) { + continue; + } + + hasNetworks = true; + networkManager->addWiFiNetwork(wifiAP.ssid, wifiAP.password); + } + + if (!hasNetworks) { Serial.println("WiFi SSID not set! Starting Auto AP"); startAutoAP(); return; } - // TODO: Create generic multi-SSID support in Network Manager - while (!networkManager->isWiFiConnected()) { - displayShow("", "Connecting to WiFi:", "", currentWiFi->ssid + " ...", 0); - networkManager->disconnectWiFi(); - networkManager->connectWiFi(currentWiFi->ssid, currentWiFi->password); - - if(myWiFiAPIndex >= (myWiFiAPSize - 1)) { - break; - } - - myWiFiAPIndex++; - currentWiFi = &Config.wifiAPs[myWiFiAPIndex]; - } + displayShow("", "Connecting to WiFi:", "", " loading ...", 0); + networkManager->connectWiFi(); #ifdef INTERNAL_LED_PIN digitalWrite(INTERNAL_LED_PIN,LOW);