Compare commits

..

1 Commits

Author SHA1 Message Date
Ricardo Guzman (Richonguzman)
e31dbbf91f testing1 2026-03-08 10:43:51 -03:00
18 changed files with 276 additions and 707 deletions

View File

@@ -32,7 +32,7 @@ lib_deps =
adafruit/Adafruit Si7021 Library @ 1.5.3 adafruit/Adafruit Si7021 Library @ 1.5.3
arduino-libraries/NTPClient @ 3.2.1 arduino-libraries/NTPClient @ 3.2.1
ayushsharma82/ElegantOTA @ 3.1.7 ayushsharma82/ElegantOTA @ 3.1.7
bblanchon/ArduinoJson @ 7.4.2 bblanchon/ArduinoJson @ 6.21.3
jgromes/RadioLib @ 7.6.0 jgromes/RadioLib @ 7.6.0
knolleary/PubSubClient @ 2.8 knolleary/PubSubClient @ 2.8
ESP32Async/AsyncTCP @ 3.4.10 ESP32Async/AsyncTCP @ 3.4.10

View File

@@ -1853,68 +1853,46 @@
</div> </div>
<div class="col-9"> <div class="col-9">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-6">
<div class="form-check form-switch"> <label
for="wifi.autoAP.password"
class="form-label"
>Password</label
>
<div class="input-group">
<input <input
type="checkbox" type="password"
name="wifi.autoAP.enabled" name="wifi.autoAP.password"
id="wifi.autoAP.enabled" id="wifi.autoAP.password"
class="form-check-input" class="form-control"
placeholder="1234567890"
required=""
/> />
<label
for="wifi.autoAP.enabled"
class="form-label"
>Enable Auto AP</label
>
<div class="form-text">
Create WiFi AP when no network is available
</div>
</div> </div>
</div> </div>
</div> <div class="col-6">
<div id="wifi-autoap-config" style="{{wifi.autoAP.enabled ? '' : 'display:none'}}"> <label
<div class="row mt-3"> for="wifi.autoAP.timeout"
<div class="col-6"> class="form-label"
<label >WiFiAP timeout (to search again)</label
for="wifi.autoAP.password" >
class="form-label" <div class="input-group">
>Password</label <input
type="number"
name="wifi.autoAP.timeout"
id="wifi.autoAP.timeout"
class="form-control"
placeholder="10"
required=""
step="1"
min="0"
/>
<span class="input-group-text"
>minutes</span
> >
<div class="input-group"> <div class="form-text">
<input Set to <strong>0</strong> if you don't
type="password" want WiFi AP to stop.
name="wifi.autoAP.password"
id="wifi.autoAP.password"
class="form-control"
placeholder="1234567890"
required=""
/>
</div>
</div>
<div class="col-6">
<label
for="wifi.autoAP.timeout"
class="form-label"
>WiFiAP timeout (to search again)</label
>
<div class="input-group">
<input
type="number"
name="wifi.autoAP.timeout"
id="wifi.autoAP.timeout"
class="form-control"
placeholder="10"
required=""
step="1"
min="0"
/>
<span class="input-group-text"
>minutes</span
>
<div class="form-text">
Set to <strong>0</strong> if you don't
want WiFi AP to stop.
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -237,10 +237,8 @@ function loadSettings(settings) {
RebootModeTime.disabled = !RebootModeCheckbox.check; RebootModeTime.disabled = !RebootModeCheckbox.check;
// WiFi Auto AP // WiFi Auto AP
document.getElementById("wifi.autoAP.enabled").checked = settings.wifi.autoAP.enabled;
document.getElementById("wifi.autoAP.password").value = settings.wifi.autoAP.password; document.getElementById("wifi.autoAP.password").value = settings.wifi.autoAP.password;
document.getElementById("wifi.autoAP.timeout").value = settings.wifi.autoAP.timeout; document.getElementById("wifi.autoAP.timeout").value = settings.wifi.autoAP.timeout;
toggleWiFiAutoAPFields();
// OTA // OTA
document.getElementById("ota.username").value = settings.ota.username; document.getElementById("ota.username").value = settings.ota.username;
@@ -434,18 +432,6 @@ WebadminCheckbox.addEventListener("change", function () {
WebadminPassword.disabled = !this.checked; WebadminPassword.disabled = !this.checked;
}); });
// WiFi Auto AP Switches
const WiFiAutoAPCheckbox = document.querySelector('input[name="wifi.autoAP.enabled"]');
WiFiAutoAPCheckbox.addEventListener("change", function () {
toggleWiFiAutoAPFields();
});
function toggleWiFiAutoAPFields() {
const isEnabled = WiFiAutoAPCheckbox.checked;
const autoAPConfig = document.getElementById('wifi-autoap-config');
if (autoAPConfig) autoAPConfig.style.display = isEnabled ? 'block' : 'none';
}
document.querySelector(".new button").addEventListener("click", function () { document.querySelector(".new button").addEventListener("click", function () {
const networksContainer = document.querySelector(".list-networks"); const networksContainer = document.querySelector(".list-networks");

View File

@@ -32,7 +32,6 @@ public:
class WiFi_Auto_AP { class WiFi_Auto_AP {
public: public:
bool enabled; // Enable Auto AP
String password; String password;
int timeout; int timeout;
}; };

View File

@@ -1,82 +0,0 @@
#include <Arduino.h>
#include <SPI.h>
#include <WiFi.h>
#include <ETH.h>
#include <vector>
/**
* Class for managing network connections
*/
class NetworkManager
{
private:
class WiFiNetwork {
public:
String ssid;
String psk;
};
bool _wifiAPmode = false;
bool _wifiSTAmode = false;
bool _ethernetMode = false;
bool _ethernetConnected = false;
unsigned long _apStartup = 0;
unsigned long _apTimeout = 0;
String _hostName = "";
std::vector<WiFiNetwork> _wifiNetworks;
int _findWiFiNetworkIndex(const String& ssid) const;
bool _connectWiFi(const WiFiNetwork& network);
void _processAPTimeout();
void _onNetworkEvent(arduino_event_id_t event, arduino_event_info_t /*info*/);
public:
// Constructor
NetworkManager();
// Destructor
~NetworkManager();
// Initialize network module
bool setup();
void loop();
void setHostName(const String& hostName);
// WiFi methods
bool setupAP(String apName, String apPsk = "");
bool disableAP();
void setAPTimeout(unsigned long timeout);
void addWiFiNetwork(const String& ssid, const String& psk = "");
void clearWiFiNetworks();
bool hasWiFiNetworks() const;
size_t getWiFiNetworkCount() const;
bool connectWiFi();
bool connectWiFi(const String& ssid, const 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;
// Ethernet methods
bool ethernetConnect(eth_phy_type_t type, uint8_t phy_addr, uint8_t mdc, uint8_t mdio, int power, eth_clock_mode_t clock_mode, bool use_mac_from_efuse = false);
bool setEthernetIP(const String& staticIP, const String& gateway, const String& subnet, const String& dns1, const String& dns2);
bool ethernetDisconnect();
IPAddress getEthernetIP() const;
String getEthernetMACAddress() 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;
};

View File

@@ -24,7 +24,7 @@
namespace NTP_Utils { namespace NTP_Utils {
bool setup(); void setup();
void update(); void update();
String getFormatedTime(); String getFormatedTime();

View File

@@ -27,6 +27,7 @@ namespace WIFI_Utils {
void checkWiFi(); void checkWiFi();
void startAutoAP(); void startAutoAP();
void startWiFi(); void startWiFi();
void checkAutoAPTimeout();
void setup(); void setup();
} }

View File

@@ -41,10 +41,9 @@ ___________________________________________________________________*/
#include <ElegantOTA.h> #include <ElegantOTA.h>
#include <TinyGPS++.h> #include <TinyGPS++.h>
#include <Arduino.h> #include <Arduino.h>
#include <WiFiClient.h> #include <WiFi.h>
#include <vector> #include <vector>
#include "configuration.h" #include "configuration.h"
#include "network_manager.h"
#include "aprs_is_utils.h" #include "aprs_is_utils.h"
#include "station_utils.h" #include "station_utils.h"
#include "battery_utils.h" #include "battery_utils.h"
@@ -68,8 +67,8 @@ ___________________________________________________________________*/
#endif #endif
String versionDate = "2026-03-11"; String versionDate = "2026-03-08";
String versionNumber = "3.2.107"; String versionNumber = "3.2.103";
Configuration Config; Configuration Config;
WiFiClient aprsIsClient; WiFiClient aprsIsClient;
WiFiClient mqttClient; WiFiClient mqttClient;
@@ -80,7 +79,9 @@ WiFiClient mqttClient;
bool gpsInfoToggle = false; bool gpsInfoToggle = false;
#endif #endif
NetworkManager *networkManager; uint8_t myWiFiAPIndex = 0;
int myWiFiAPSize = Config.wifiAPs.size();
WiFi_AP *currentWiFi = &Config.wifiAPs[myWiFiAPIndex];
bool isUpdatingOTA = false; bool isUpdatingOTA = false;
uint32_t lastBatteryCheck = 0; uint32_t lastBatteryCheck = 0;
@@ -101,12 +102,6 @@ String firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seven
void setup() { void setup() {
Serial.begin(115200); Serial.begin(115200);
Config.setup(); Config.setup();
networkManager = new NetworkManager();
networkManager->setup();
if (Config.wifiAutoAP.enabled) {
networkManager->setAPTimeout(Config.wifiAutoAP.timeout * 60 * 1000); // Convert minutes to milliseconds
}
networkManager->setHostName("iGATE-" + Config.callsign);
POWER_Utils::setup(); POWER_Utils::setup();
Utils::setupDisplay(); Utils::setupDisplay();
LoRa_Utils::setup(); LoRa_Utils::setup();
@@ -138,7 +133,7 @@ void loop() {
Utils::checkSleepByLowBatteryVoltage(1); Utils::checkSleepByLowBatteryVoltage(1);
SLEEP_Utils::startSleeping(); SLEEP_Utils::startSleeping();
} else { } else {
networkManager->loop(); WIFI_Utils::checkAutoAPTimeout();
if (isUpdatingOTA) { if (isUpdatingOTA) {
ElegantOTA.loop(); ElegantOTA.loop();
@@ -167,14 +162,11 @@ void loop() {
#endif #endif
#ifdef HAS_A7670 #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(); if (Config.aprs_is.active && !modemLoggedToAPRSIS) A7670_Utils::APRS_IS_connect();
#else #else
WIFI_Utils::checkWiFi(); WIFI_Utils::checkWiFi();
if (networkManager->isConnected()) { if (Config.aprs_is.active && (WiFi.status() == WL_CONNECTED) && !aprsIsClient.connected()) APRS_IS_Utils::connect();
if (Config.aprs_is.active && !aprsIsClient.connected()) APRS_IS_Utils::connect(); if (Config.mqtt.active && (WiFi.status() == WL_CONNECTED) && !mqttClient.connected()) MQTT_Utils::connect();
if (Config.mqtt.active && !mqttClient.connected()) MQTT_Utils::connect();
}
#endif #endif
NTP_Utils::update(); NTP_Utils::update();

View File

@@ -16,10 +16,9 @@
* along with LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>. * along with LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <APRSPacketLib.h> #include <APRSPacketLib.h>
#include <WiFiClient.h> #include <WiFi.h>
#include "configuration.h" #include "configuration.h"
#include "network_manager.h"
#include "aprs_is_utils.h" #include "aprs_is_utils.h"
#include "station_utils.h" #include "station_utils.h"
#include "board_pinout.h" #include "board_pinout.h"
@@ -33,7 +32,6 @@
extern Configuration Config; extern Configuration Config;
extern NetworkManager *networkManager;
extern WiFiClient aprsIsClient; extern WiFiClient aprsIsClient;
extern uint32_t lastScreenOn; extern uint32_t lastScreenOn;
extern String firstLine; extern String firstLine;
@@ -95,7 +93,7 @@ namespace APRS_IS_Utils {
void checkStatus() { void checkStatus() {
String wifiState, aprsisState; String wifiState, aprsisState;
if (networkManager->isWiFiConnected()) { if (WiFi.status() == WL_CONNECTED) {
wifiState = "OK"; wifiState = "OK";
} else { } else {
if (backupDigiMode || Config.digi.ecoMode == 1 || Config.digi.ecoMode == 2) { if (backupDigiMode || Config.digi.ecoMode == 1 || Config.digi.ecoMode == 2) {
@@ -410,7 +408,7 @@ namespace APRS_IS_Utils {
} }
void firstConnection() { void firstConnection() {
if (Config.aprs_is.active && networkManager->isConnected() && !aprsIsClient.connected()) { if (Config.aprs_is.active && (WiFi.status() == WL_CONNECTED) && !aprsIsClient.connected()) {
connect(); connect();
while (!passcodeValid) { while (!passcodeValid) {
listenAPRSIS(); listenAPRSIS();
@@ -418,4 +416,4 @@ namespace APRS_IS_Utils {
} }
} }
} }

View File

@@ -26,10 +26,29 @@
bool shouldSleepStop = true; bool shouldSleepStop = true;
void Configuration::setup() {
if (!SPIFFS.begin(false)) {
Serial.println("SPIFFS Mount Failed");
return;
} else {
Serial.println("SPIFFS Mounted");
}
bool exists = SPIFFS.exists("/igate_conf.json");
if (!exists) {
setDefaultValues();
writeFile();
delay(1000);
ESP.restart();
}
readFile();
}
bool Configuration::writeFile() { bool Configuration::writeFile() {
Serial.println("Saving configuration..."); Serial.println("Saving configuration...");
JsonDocument data; StaticJsonDocument<3584> data;
File configFile = SPIFFS.open("/igate_conf.json", "w"); File configFile = SPIFFS.open("/igate_conf.json", "w");
if (!configFile) { if (!configFile) {
@@ -47,7 +66,6 @@ bool Configuration::writeFile() {
data["other"]["startupDelay"] = startupDelay; data["other"]["startupDelay"] = startupDelay;
data["wifi"]["autoAP"]["enabled"] = wifiAutoAP.enabled;
data["wifi"]["autoAP"]["password"] = wifiAutoAP.password; data["wifi"]["autoAP"]["password"] = wifiAutoAP.password;
data["wifi"]["autoAP"]["timeout"] = wifiAutoAP.timeout; data["wifi"]["autoAP"]["timeout"] = wifiAutoAP.timeout;
@@ -196,7 +214,8 @@ bool Configuration::readFile() {
if (configFile) { if (configFile) {
bool needsRewrite = false; bool needsRewrite = false;
JsonDocument data; StaticJsonDocument<3584> data;
DeserializationError error = deserializeJson(data, configFile); DeserializationError error = deserializeJson(data, configFile);
if (error) { if (error) {
Serial.println("Failed to read file, using default configuration"); Serial.println("Failed to read file, using default configuration");
@@ -211,28 +230,26 @@ bool Configuration::readFile() {
wifiAPs.push_back(wifiap); wifiAPs.push_back(wifiap);
} }
if (data["other"]["startupDelay"].isNull()) needsRewrite = true; if (!data["other"].containsKey("startupDelay")) needsRewrite = true;
startupDelay = data["other"]["startupDelay"] | 0; startupDelay = data["other"]["startupDelay"] | 0;
if (data["wifi"]["autoAP"]["enabled"].isNull() || if (!data["wifi"]["autoAP"].containsKey("password") ||
data["wifi"]["autoAP"]["password"].isNull() || !data["wifi"]["autoAP"].containsKey("timeout")) needsRewrite = true;
data["wifi"]["autoAP"]["timeout"].isNull()) needsRewrite = true;
wifiAutoAP.enabled = data["wifi"]["autoAP"]["enabled"] | true;
wifiAutoAP.password = data["wifi"]["autoAP"]["password"] | "1234567890"; wifiAutoAP.password = data["wifi"]["autoAP"]["password"] | "1234567890";
wifiAutoAP.timeout = data["wifi"]["autoAP"]["timeout"] | 10; wifiAutoAP.timeout = data["wifi"]["autoAP"]["timeout"] | 10;
if (data["callsign"].isNull()) needsRewrite = true; if (!data.containsKey("callsign")) needsRewrite = true;
callsign = data["callsign"] | "NOCALL-10"; callsign = data["callsign"] | "NOCALL-10";
if (data["tacticalCallsign"].isNull()) needsRewrite = true; if (!data.containsKey("tacticalCallsign")) needsRewrite = true;
tacticalCallsign = data["tacticalCallsign"] | ""; tacticalCallsign = data["tacticalCallsign"] | "";
if (data["aprs_is"]["active"].isNull() || if (!data["aprs_is"].containsKey("active") ||
data["aprs_is"]["passcode"].isNull() || !data["aprs_is"].containsKey("passcode") ||
data["aprs_is"]["server"].isNull() || !data["aprs_is"].containsKey("server") ||
data["aprs_is"]["port"].isNull() || !data["aprs_is"].containsKey("port") ||
data["aprs_is"]["filter"].isNull() || !data["aprs_is"].containsKey("filter") ||
data["aprs_is"]["messagesToRF"].isNull() || !data["aprs_is"].containsKey("messagesToRF") ||
data["aprs_is"]["objectsToRF"].isNull()) needsRewrite = true; !data["aprs_is"].containsKey("objectsToRF")) needsRewrite = true;
aprs_is.active = data["aprs_is"]["active"] | false; aprs_is.active = data["aprs_is"]["active"] | false;
aprs_is.passcode = data["aprs_is"]["passcode"] | "XYZWV"; aprs_is.passcode = data["aprs_is"]["passcode"] | "XYZWV";
aprs_is.server = data["aprs_is"]["server"] | "rotate.aprs2.net"; aprs_is.server = data["aprs_is"]["server"] | "rotate.aprs2.net";
@@ -241,20 +258,20 @@ bool Configuration::readFile() {
aprs_is.messagesToRF = data["aprs_is"]["messagesToRF"] | false; aprs_is.messagesToRF = data["aprs_is"]["messagesToRF"] | false;
aprs_is.objectsToRF = data["aprs_is"]["objectsToRF"] | false; aprs_is.objectsToRF = data["aprs_is"]["objectsToRF"] | false;
if (data["beacon"]["latitude"].isNull() || if (!data["beacon"].containsKey("latitude") ||
data["beacon"]["longitude"].isNull() || !data["beacon"].containsKey("longitude") ||
data["beacon"]["comment"].isNull() || !data["beacon"].containsKey("comment") ||
data["beacon"]["interval"].isNull() || !data["beacon"].containsKey("interval") ||
data["beacon"]["overlay"].isNull() || !data["beacon"].containsKey("overlay") ||
data["beacon"]["symbol"].isNull() || !data["beacon"].containsKey("symbol") ||
data["beacon"]["path"].isNull() || !data["beacon"].containsKey("path") ||
data["beacon"]["sendViaAPRSIS"].isNull() || !data["beacon"].containsKey("sendViaAPRSIS") ||
data["beacon"]["sendViaRF"].isNull() || !data["beacon"].containsKey("sendViaRF") ||
data["beacon"]["beaconFreq"].isNull() || !data["beacon"].containsKey("beaconFreq") ||
data["beacon"]["statusActive"].isNull() || !data["beacon"].containsKey("statusActive") ||
data["beacon"]["statusPacket"].isNull() || !data["beacon"].containsKey("statusPacket") ||
data["beacon"]["gpsActive"].isNull() || !data["beacon"].containsKey("gpsActive") ||
data["beacon"]["ambiguityLevel"].isNull()) needsRewrite = true; !data["beacon"].containsKey("ambiguityLevel")) needsRewrite = true;
beacon.latitude = data["beacon"]["latitude"] | 0.0; beacon.latitude = data["beacon"]["latitude"] | 0.0;
beacon.longitude = data["beacon"]["longitude"] | 0.0; beacon.longitude = data["beacon"]["longitude"] | 0.0;
beacon.comment = data["beacon"]["comment"] | "LoRa APRS"; beacon.comment = data["beacon"]["comment"] | "LoRa APRS";
@@ -270,15 +287,15 @@ bool Configuration::readFile() {
beacon.gpsActive = data["beacon"]["gpsActive"] | false; beacon.gpsActive = data["beacon"]["gpsActive"] | false;
beacon.ambiguityLevel = data["beacon"]["ambiguityLevel"] | 0; beacon.ambiguityLevel = data["beacon"]["ambiguityLevel"] | 0;
if (data["personalNote"].isNull()) needsRewrite = true; if (!data.containsKey("personalNote")) needsRewrite = true;
personalNote = data["personalNote"] | "personal note here"; personalNote = data["personalNote"] | "personal note here";
if (data["blacklist"].isNull()) needsRewrite = true; if (!data.containsKey("blacklist")) needsRewrite = true;
blacklist = data["blacklist"] | "station callsign"; blacklist = data["blacklist"] | "station callsign";
if (data["digi"]["mode"].isNull() || if (!data["digi"].containsKey("mode") ||
data["digi"]["ecoMode"].isNull() || !data["digi"].containsKey("ecoMode") ||
data["digi"]["backupDigiMode"].isNull()) needsRewrite = true; !data["digi"].containsKey("backupDigiMode")) needsRewrite = true;
digi.mode = data["digi"]["mode"] | 0; digi.mode = data["digi"]["mode"] | 0;
digi.ecoMode = data["digi"]["ecoMode"] | 0; digi.ecoMode = data["digi"]["ecoMode"] | 0;
if (digi.ecoMode == 1) shouldSleepStop = false; if (digi.ecoMode == 1) shouldSleepStop = false;
@@ -288,17 +305,17 @@ bool Configuration::readFile() {
digi.backupDigiMode = data["digi"]["backupDigiMode"] | false; digi.backupDigiMode = data["digi"]["backupDigiMode"] | false;
if (data["lora"]["rxActive"].isNull() || if (!data["lora"].containsKey("rxActive") ||
data["lora"]["rxFreq"].isNull() || !data["lora"].containsKey("rxFreq") ||
data["lora"]["rxSpreadingFactor"].isNull() || !data["lora"].containsKey("rxSpreadingFactor") ||
data["lora"]["rxCodingRate4"].isNull() || !data["lora"].containsKey("rxCodingRate4") ||
data["lora"]["rxSignalBandwidth"].isNull() || !data["lora"].containsKey("rxSignalBandwidth") ||
data["lora"]["txActive"].isNull() || !data["lora"].containsKey("txActive") ||
data["lora"]["txFreq"].isNull() || !data["lora"].containsKey("txFreq") ||
data["lora"]["txSpreadingFactor"].isNull() || !data["lora"].containsKey("txSpreadingFactor") ||
data["lora"]["txCodingRate4"].isNull() || !data["lora"].containsKey("txCodingRate4") ||
data["lora"]["txSignalBandwidth"].isNull() || !data["lora"].containsKey("txSignalBandwidth") ||
data["lora"]["power"].isNull()) needsRewrite = true; !data["lora"].containsKey("power")) needsRewrite = true;
loramodule.rxActive = data["lora"]["rxActive"] | true; loramodule.rxActive = data["lora"]["rxActive"] | true;
loramodule.rxFreq = data["lora"]["rxFreq"] | 433775000; loramodule.rxFreq = data["lora"]["rxFreq"] | 433775000;
loramodule.rxSpreadingFactor = data["lora"]["rxSpreadingFactor"] | 12; loramodule.rxSpreadingFactor = data["lora"]["rxSpreadingFactor"] | 12;
@@ -311,9 +328,9 @@ bool Configuration::readFile() {
loramodule.txSignalBandwidth = data["lora"]["txSignalBandwidth"] | 125000; loramodule.txSignalBandwidth = data["lora"]["txSignalBandwidth"] | 125000;
loramodule.power = data["lora"]["power"] | 20; loramodule.power = data["lora"]["power"] | 20;
if (data["display"]["alwaysOn"].isNull() || if (!data["display"].containsKey("alwaysOn") ||
data["display"]["timeout"].isNull() || !data["display"].containsKey("timeout") ||
data["display"]["turn180"].isNull()) needsRewrite = true; !data["display"].containsKey("turn180")) needsRewrite = true;
#ifdef HAS_EPAPER #ifdef HAS_EPAPER
display.alwaysOn = true; display.alwaysOn = true;
#else #else
@@ -322,17 +339,17 @@ bool Configuration::readFile() {
display.timeout = data["display"]["timeout"] | 4; display.timeout = data["display"]["timeout"] | 4;
display.turn180 = data["display"]["turn180"] | false; display.turn180 = data["display"]["turn180"] | false;
if (data["battery"]["sendInternalVoltage"].isNull() || if (!data["battery"].containsKey("sendInternalVoltage") ||
data["battery"]["monitorInternalVoltage"].isNull() || !data["battery"].containsKey("monitorInternalVoltage") ||
data["battery"]["internalSleepVoltage"].isNull() || !data["battery"].containsKey("internalSleepVoltage") ||
data["battery"]["sendExternalVoltage"].isNull() || !data["battery"].containsKey("sendExternalVoltage") ||
data["battery"]["monitorExternalVoltage"].isNull() || !data["battery"].containsKey("monitorExternalVoltage") ||
data["battery"]["externalSleepVoltage"].isNull() || !data["battery"].containsKey("externalSleepVoltage") ||
data["battery"]["useExternalI2CSensor"].isNull() || !data["battery"].containsKey("useExternalI2CSensor") ||
data["battery"]["voltageDividerR1"].isNull() || !data["battery"].containsKey("voltageDividerR1") ||
data["battery"]["voltageDividerR2"].isNull() || !data["battery"].containsKey("voltageDividerR2") ||
data["battery"]["externalVoltagePin"].isNull() || !data["battery"].containsKey("externalVoltagePin") ||
data["battery"]["sendVoltageAsTelemetry"].isNull()) needsRewrite = true; !data["battery"].containsKey("sendVoltageAsTelemetry")) needsRewrite = true;
battery.sendInternalVoltage = data["battery"]["sendInternalVoltage"] | false; battery.sendInternalVoltage = data["battery"]["sendInternalVoltage"] | false;
battery.monitorInternalVoltage = data["battery"]["monitorInternalVoltage"] | false; battery.monitorInternalVoltage = data["battery"]["monitorInternalVoltage"] | false;
battery.internalSleepVoltage = data["battery"]["internalSleepVoltage"] | 2.9; battery.internalSleepVoltage = data["battery"]["internalSleepVoltage"] | 2.9;
@@ -345,38 +362,38 @@ bool Configuration::readFile() {
battery.externalVoltagePin = data["battery"]["externalVoltagePin"] | 34; battery.externalVoltagePin = data["battery"]["externalVoltagePin"] | 34;
battery.sendVoltageAsTelemetry = data["battery"]["sendVoltageAsTelemetry"] | false; battery.sendVoltageAsTelemetry = data["battery"]["sendVoltageAsTelemetry"] | false;
if (data["wxsensor"]["active"].isNull() || if (!data["wxsensor"].containsKey("active") ||
data["wxsensor"]["heightCorrection"].isNull() || !data["wxsensor"].containsKey("heightCorrection") ||
data["wxsensor"]["temperatureCorrection"].isNull()) needsRewrite = true; !data["wxsensor"].containsKey("temperatureCorrection")) needsRewrite = true;
wxsensor.active = data["wxsensor"]["active"] | false; wxsensor.active = data["wxsensor"]["active"] | false;
wxsensor.heightCorrection = data["wxsensor"]["heightCorrection"] | 0; wxsensor.heightCorrection = data["wxsensor"]["heightCorrection"] | 0;
wxsensor.temperatureCorrection = data["wxsensor"]["temperatureCorrection"] | 0.0; wxsensor.temperatureCorrection = data["wxsensor"]["temperatureCorrection"] | 0.0;
if (data["syslog"]["active"].isNull() || if (!data["syslog"].containsKey("active") ||
data["syslog"]["server"].isNull() || !data["syslog"].containsKey("server") ||
data["syslog"]["port"].isNull() || !data["syslog"].containsKey("port") ||
data["syslog"]["logBeaconOverTCPIP"].isNull()) needsRewrite = true; !data["syslog"].containsKey("logBeaconOverTCPIP")) needsRewrite = true;
syslog.active = data["syslog"]["active"] | false; syslog.active = data["syslog"]["active"] | false;
syslog.server = data["syslog"]["server"] | "lora.link9.net"; syslog.server = data["syslog"]["server"] | "lora.link9.net";
syslog.port = data["syslog"]["port"] | 1514; syslog.port = data["syslog"]["port"] | 1514;
syslog.logBeaconOverTCPIP = data["syslog"]["logBeaconOverTCPIP"] | false; syslog.logBeaconOverTCPIP = data["syslog"]["logBeaconOverTCPIP"] | false;
if (data["tnc"]["enableServer"].isNull() || if (!data["tnc"].containsKey("enableServer") ||
data["tnc"]["enableSerial"].isNull() || !data["tnc"].containsKey("enableSerial") ||
data["tnc"]["acceptOwn"].isNull() || !data["tnc"].containsKey("acceptOwn") ||
data["tnc"]["aprsBridgeActive"].isNull()) needsRewrite = true; !data["tnc"].containsKey("aprsBridgeActive")) needsRewrite = true;
tnc.enableServer = data["tnc"]["enableServer"] | false; tnc.enableServer = data["tnc"]["enableServer"] | false;
tnc.enableSerial = data["tnc"]["enableSerial"] | false; tnc.enableSerial = data["tnc"]["enableSerial"] | false;
tnc.acceptOwn = data["tnc"]["acceptOwn"] | false; tnc.acceptOwn = data["tnc"]["acceptOwn"] | false;
tnc.aprsBridgeActive = data["tnc"]["aprsBridgeActive"] | false; tnc.aprsBridgeActive = data["tnc"]["aprsBridgeActive"] | false;
if (data["mqtt"]["active"].isNull() || if (!data["mqtt"].containsKey("active") ||
data["mqtt"]["server"].isNull() || !data["mqtt"].containsKey("server") ||
data["mqtt"]["topic"].isNull() || !data["mqtt"].containsKey("topic") ||
data["mqtt"]["username"].isNull() || !data["mqtt"].containsKey("username") ||
data["mqtt"]["password"].isNull() || !data["mqtt"].containsKey("password") ||
data["mqtt"]["port"].isNull() || !data["mqtt"].containsKey("port") ||
data["mqtt"]["beaconOverMqtt"].isNull()) needsRewrite = true; !data["mqtt"].containsKey("beaconOverMqtt")) needsRewrite = true;
mqtt.active = data["mqtt"]["active"] | false; mqtt.active = data["mqtt"]["active"] | false;
mqtt.server = data["mqtt"]["server"] | ""; mqtt.server = data["mqtt"]["server"] | "";
mqtt.topic = data["mqtt"]["topic"] | "aprs-igate"; mqtt.topic = data["mqtt"]["topic"] | "aprs-igate";
@@ -385,34 +402,34 @@ bool Configuration::readFile() {
mqtt.port = data["mqtt"]["port"] | 1883; mqtt.port = data["mqtt"]["port"] | 1883;
mqtt.beaconOverMqtt = data["mqtt"]["beaconOverMqtt"] | false; mqtt.beaconOverMqtt = data["mqtt"]["beaconOverMqtt"] | false;
if (data["ota"]["username"].isNull() || if (!data["ota"].containsKey("username") ||
data["ota"]["password"].isNull()) needsRewrite = true; !data["ota"].containsKey("password")) needsRewrite = true;
ota.username = data["ota"]["username"] | ""; ota.username = data["ota"]["username"] | "";
ota.password = data["ota"]["password"] | ""; ota.password = data["ota"]["password"] | "";
if (data["webadmin"]["active"].isNull() || if (!data["webadmin"].containsKey("active") ||
data["webadmin"]["username"].isNull() || !data["webadmin"].containsKey("username") ||
data["webadmin"]["password"].isNull()) needsRewrite = true; !data["webadmin"].containsKey("password")) needsRewrite = true;
webadmin.active = data["webadmin"]["active"] | false; webadmin.active = data["webadmin"]["active"] | false;
webadmin.username = data["webadmin"]["username"] | "admin"; webadmin.username = data["webadmin"]["username"] | "admin";
webadmin.password = data["webadmin"]["password"] | ""; webadmin.password = data["webadmin"]["password"] | "";
if (data["remoteManagement"]["managers"].isNull() || if (!data["remoteManagement"].containsKey("managers") ||
data["remoteManagement"]["rfOnly"].isNull()) needsRewrite = true; !data["remoteManagement"].containsKey("rfOnly")) needsRewrite = true;
remoteManagement.managers = data["remoteManagement"]["managers"] | ""; remoteManagement.managers = data["remoteManagement"]["managers"] | "";
remoteManagement.rfOnly = data["remoteManagement"]["rfOnly"] | true; remoteManagement.rfOnly = data["remoteManagement"]["rfOnly"] | true;
if (data["ntp"]["server"].isNull() || if (!data["ntp"].containsKey("server") ||
data["ntp"]["gmtCorrection"].isNull()) needsRewrite = true; !data["ntp"].containsKey("gmtCorrection")) needsRewrite = true;
ntp.server = data["ntp"]["server"] | "pool.ntp.org"; ntp.server = data["ntp"]["server"] | "pool.ntp.org";
ntp.gmtCorrection = data["ntp"]["gmtCorrection"] | 0.0; ntp.gmtCorrection = data["ntp"]["gmtCorrection"] | 0.0;
if (data["other"]["rebootMode"].isNull() || if (!data["other"].containsKey("rebootMode") ||
data["other"]["rebootModeTime"].isNull()) needsRewrite = true; !data["other"].containsKey("rebootModeTime")) needsRewrite = true;
rebootMode = data["other"]["rebootMode"] | false; rebootMode = data["other"]["rebootMode"] | false;
rebootModeTime = data["other"]["rebootModeTime"] | 6; rebootModeTime = data["other"]["rebootModeTime"] | 6;
if (data["other"]["rememberStationTime"].isNull()) needsRewrite = true; if (!data["other"].containsKey("rememberStationTime")) needsRewrite = true;
rememberStationTime = data["other"]["rememberStationTime"] | 30; rememberStationTime = data["other"]["rememberStationTime"] | 30;
if (wifiAPs.size() == 0) { // If we don't have any WiFi's from config we need to add "empty" SSID for AUTO AP if (wifiAPs.size() == 0) { // If we don't have any WiFi's from config we need to add "empty" SSID for AUTO AP
@@ -448,7 +465,6 @@ void Configuration::setDefaultValues() {
startupDelay = 0; startupDelay = 0;
wifiAutoAP.enabled = true;
wifiAutoAP.password = "1234567890"; wifiAutoAP.password = "1234567890";
wifiAutoAP.timeout = 10; wifiAutoAP.timeout = 10;
@@ -560,23 +576,4 @@ void Configuration::setDefaultValues() {
rememberStationTime = 30; rememberStationTime = 30;
Serial.println("New Data Created... All is Written!"); Serial.println("New Data Created... All is Written!");
}
void Configuration::setup() {
if (!SPIFFS.begin(false)) {
Serial.println("SPIFFS Mount Failed");
return;
} else {
Serial.println("SPIFFS Mounted");
}
bool exists = SPIFFS.exists("/igate_conf.json");
if (!exists) {
setDefaultValues();
writeFile();
delay(1000);
ESP.restart();
}
readFile();
} }

View File

@@ -17,8 +17,8 @@
*/ */
#include <RadioLib.h> #include <RadioLib.h>
#include <WiFi.h>
#include "configuration.h" #include "configuration.h"
#include "network_manager.h"
#include "aprs_is_utils.h" #include "aprs_is_utils.h"
#include "station_utils.h" #include "station_utils.h"
#include "board_pinout.h" #include "board_pinout.h"
@@ -29,7 +29,6 @@
extern Configuration Config; extern Configuration Config;
extern NetworkManager *networkManager;
extern uint32_t lastRxTime; extern uint32_t lastRxTime;
extern bool packetIsBeacon; extern bool packetIsBeacon;
@@ -182,7 +181,7 @@ namespace LoRa_Utils {
int state = radio.transmit("\x3c\xff\x01" + newPacket); int state = radio.transmit("\x3c\xff\x01" + newPacket);
transmitFlag = true; transmitFlag = true;
if (state == RADIOLIB_ERR_NONE) { if (state == RADIOLIB_ERR_NONE) {
if (Config.syslog.active && networkManager->isConnected()) { if (Config.syslog.active && WiFi.status() == WL_CONNECTED) {
SYSLOG_Utils::log(3, newPacket, 0, 0.0, 0); // TX SYSLOG_Utils::log(3, newPacket, 0, 0.0, 0); // TX
} }
Utils::print("---> LoRa Packet Tx : "); Utils::print("---> LoRa Packet Tx : ");
@@ -244,7 +243,7 @@ namespace LoRa_Utils {
receivedPackets.push_back(receivedPacket); receivedPackets.push_back(receivedPacket);
} }
if (Config.syslog.active && networkManager->isConnected()) { if (Config.syslog.active && WiFi.status() == WL_CONNECTED) {
SYSLOG_Utils::log(1, packet, rssi, snr, freqError); // RX SYSLOG_Utils::log(1, packet, rssi, snr, freqError); // RX
} }
} else { } else {
@@ -258,7 +257,7 @@ namespace LoRa_Utils {
snr = radio.getSNR(); snr = radio.getSNR();
freqError = radio.getFrequencyError(); freqError = radio.getFrequencyError();
Utils::println(F("CRC error!")); Utils::println(F("CRC error!"));
if (Config.syslog.active && networkManager->isConnected()) { if (Config.syslog.active && WiFi.status() == WL_CONNECTED) {
SYSLOG_Utils::log(0, packet, rssi, snr, freqError); // CRC SYSLOG_Utils::log(0, packet, rssi, snr, freqError); // CRC
} }
packet = ""; packet = "";

View File

@@ -16,7 +16,7 @@
* along with LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>. * along with LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <WiFiClient.h> #include <WiFiClientSecure.h>
#include <PubSubClient.h> #include <PubSubClient.h>
#include "configuration.h" #include "configuration.h"
#include "station_utils.h" #include "station_utils.h"

View File

@@ -1,333 +0,0 @@
#include <Arduino.h>
#include "network_manager.h"
// Constructor
NetworkManager::NetworkManager() { }
// Destructor
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<int>(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()) 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;
}
// If any station is connected, reset the timer
if (WiFi.softAPgetStationNum() > 0) {
_apStartup = millis();
return;
}
if (millis() - _apStartup > _apTimeout) {
Serial.println("[NM] AP timeout reached. Disabling AP mode.");
disableAP();
}
}
void NetworkManager::_onNetworkEvent(arduino_event_id_t event, arduino_event_info_t /*info*/) {
switch (event) {
case ARDUINO_EVENT_ETH_START:
Serial.println("[NM] ETH Started");
if (!_hostName.isEmpty()) {
Serial.println("[NM] ETH Setting Hostname: " + _hostName);
ETH.setHostname(_hostName.c_str());
}
break;
case ARDUINO_EVENT_ETH_CONNECTED:
Serial.println("[NM] ETH Connected");
break;
case ARDUINO_EVENT_ETH_GOT_IP:
Serial.println("[NM] ETH Got IP");
_ethernetConnected = true;
break;
case ARDUINO_EVENT_ETH_DISCONNECTED:
Serial.println("[NM] ETH Disconnected");
_ethernetConnected = false;
break;
case ARDUINO_EVENT_ETH_STOP:
Serial.println("[NM] ETH Stopped");
_ethernetConnected = false;
break;
default:
break;
}
}
// Initialize
bool NetworkManager::setup() {
Serial.println("[NM] Initializing Networking...");
WiFi.onEvent(
[this](arduino_event_id_t event, arduino_event_info_t info) {
_onNetworkEvent(event, info);
});
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;
Serial.println("[NM] 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("[NM] AP setup successful");
_apStartup = millis();
}
else {
Serial.println("[NM] AP setup failed");
return false;
}
IPAddress apIP = getWiFiAPIP();
Serial.println("[NM] 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("[NM] Setting AP timeout to " + String(timeout / 1000) + " sec");
_apTimeout = timeout;
}
void NetworkManager::addWiFiNetwork(const String& ssid, const String& psk) {
if (ssid.isEmpty()) {
return;
}
int index = _findWiFiNetworkIndex(ssid);
if (index >= 0) {
Serial.println("[NM] Updating WiFi network: " + ssid);
_wifiNetworks[static_cast<size_t>(index)].psk = psk;
return;
}
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::hasWiFiNetworks() const {
return !_wifiNetworks.empty();
}
size_t NetworkManager::getWiFiNetworkCount() const {
return _wifiNetworks.size();
}
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() {
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();
}
// Ethernet methods
bool NetworkManager::ethernetConnect(eth_phy_type_t type, uint8_t phy_addr, uint8_t mdc, uint8_t mdio, int power, eth_clock_mode_t clock_mode, bool use_mac_from_efuse) {
_ethernetMode = true;
Serial.println("[NM] Setting up Ethernet...");
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
// SDK 5.x (Arduino SDK 3.x)
#pragma message("Compiling ETH init: SDK 5.x (Arduino core 3.x)")
return ETH.begin(type, phy_addr, mdc, mdio, power, clock_mode, use_mac_from_efuse);
#else
// SDK 4.x (Arduino SDK 2.x)
#pragma message("Compiling ETH init: SDK 4.x (Arduino core 2.x)")
return ETH.begin(phy_addr, power, mdc, mdio, type, clock_mode, use_mac_from_efuse);
#endif
}
bool NetworkManager::setEthernetIP(const String& staticIP, const String& gateway, const String& subnet, const String& dns1, const String& dns2) {
if (staticIP.isEmpty()) {
return false;
}
IPAddress ip, gw, sn, d1, d2;
if (!ip.fromString(staticIP) || !gw.fromString(gateway) || !sn.fromString(subnet)) {
Serial.println("[NM] Invalid static IP configuration");
return false;
}
if (!dns1.isEmpty() && d1.fromString(dns1)) {
if (!dns2.isEmpty() && d2.fromString(dns2)) {
ETH.config(ip, gw, sn, d1, d2);
} else {
ETH.config(ip, gw, sn, d1);
}
} else {
ETH.config(ip, gw, sn);
}
Serial.println("[NM] Ethernet static IP: " + staticIP);
return true;
}
IPAddress NetworkManager::getEthernetIP() const {
return ETH.localIP();
}
String NetworkManager::getEthernetMACAddress() const {
return ETH.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 {
return _ethernetMode && _ethernetConnected && ETH.linkUp();
}
// Check if Modem is connected
bool NetworkManager::isModemConnected() const {
// Implement Modem connection check logic here
return false;
}

View File

@@ -18,49 +18,35 @@
#include <NTPClient.h> #include <NTPClient.h>
#include <WiFiUdp.h> #include <WiFiUdp.h>
#include <WiFi.h>
#include "configuration.h" #include "configuration.h"
#include "network_manager.h"
#include "ntp_utils.h" #include "ntp_utils.h"
#include "time.h" #include "time.h"
extern Configuration Config; extern Configuration Config;
extern NetworkManager *networkManager;
WiFiUDP ntpUDP; WiFiUDP ntpUDP;
NTPClient* timeClient = nullptr; NTPClient* timeClient;
namespace NTP_Utils { namespace NTP_Utils {
bool setup() { void setup() {
if (networkManager->isConnected() && Config.digi.ecoMode == 0 && Config.callsign != "NOCALL-10") { if (WiFi.status() == WL_CONNECTED && Config.digi.ecoMode == 0 && Config.callsign != "NOCALL-10") {
int gmt = Config.ntp.gmtCorrection * 3600; int gmt = Config.ntp.gmtCorrection * 3600;
Serial.println("[NTP] Setting up, TZ offset: " + String(gmt) + " Server: " + Config.ntp.server);
timeClient = new NTPClient(ntpUDP, Config.ntp.server.c_str(), gmt, 15 * 60 * 1000); // Update interval 15 min timeClient = new NTPClient(ntpUDP, Config.ntp.server.c_str(), gmt, 15 * 60 * 1000); // Update interval 15 min
timeClient->begin(); timeClient->begin();
return true;
} }
return false;
} }
void update() { void update() {
if (!networkManager->isConnected() || Config.digi.ecoMode != 0 || Config.callsign == "NOCALL-10") { if (WiFi.status() == WL_CONNECTED && Config.digi.ecoMode == 0 && Config.callsign != "NOCALL-10") timeClient->update();
return;
}
if (timeClient == nullptr) {
if (!setup()) {
return;
}
}
timeClient->update();
} }
String getFormatedTime() { String getFormatedTime() {
if (networkManager->isConnected() && Config.digi.ecoMode == 0 && timeClient != nullptr) { if (WiFi.status() == WL_CONNECTED && Config.digi.ecoMode == 0) return timeClient->getFormattedTime();
return timeClient->getFormattedTime();
}
return "DigiEcoMode Active"; return "DigiEcoMode Active";
} }
} }

View File

@@ -17,14 +17,13 @@
*/ */
#include <WiFiUdp.h> #include <WiFiUdp.h>
#include <WiFi.h>
#include "configuration.h" #include "configuration.h"
#include "network_manager.h"
#include "syslog_utils.h" #include "syslog_utils.h"
#include "gps_utils.h" #include "gps_utils.h"
extern Configuration Config; extern Configuration Config;
extern NetworkManager *networkManager;
extern String versionDate; extern String versionDate;
extern String versionNumber; extern String versionNumber;
@@ -34,7 +33,7 @@ WiFiUDP udpClient;
namespace SYSLOG_Utils { namespace SYSLOG_Utils {
void log(const uint8_t type, const String& packet, const int rssi, const float snr, const int freqError) { void log(const uint8_t type, const String& packet, const int rssi, const float snr, const int freqError) {
if (Config.syslog.active && networkManager->isConnected()) { if (Config.syslog.active && WiFi.status() == WL_CONNECTED) {
String syslogPacket = "<165>1 - "; String syslogPacket = "<165>1 - ";
syslogPacket.concat(Config.callsign); syslogPacket.concat(Config.callsign);
syslogPacket.concat(" CA2RXU_LoRa_iGate_"); syslogPacket.concat(" CA2RXU_LoRa_iGate_");
@@ -141,7 +140,7 @@ namespace SYSLOG_Utils {
} }
void setup() { void setup() {
if (networkManager->isConnected()) { if (WiFi.status() == WL_CONNECTED) {
udpClient.begin(0); udpClient.begin(0);
if (Config.syslog.active) Serial.println("init : Syslog Server ... done! (at " + Config.syslog.server + ")"); if (Config.syslog.active) Serial.println("init : Syslog Server ... done! (at " + Config.syslog.server + ")");
} }

View File

@@ -18,9 +18,9 @@
#include <APRSPacketLib.h> #include <APRSPacketLib.h>
#include <TinyGPS++.h> #include <TinyGPS++.h>
#include <WiFi.h>
#include "telemetry_utils.h" #include "telemetry_utils.h"
#include "configuration.h" #include "configuration.h"
#include "network_manager.h"
#include "station_utils.h" #include "station_utils.h"
#include "battery_utils.h" #include "battery_utils.h"
#include "aprs_is_utils.h" #include "aprs_is_utils.h"
@@ -37,7 +37,6 @@
#define DAY_MS (24UL * 60UL * 60UL * 1000UL) #define DAY_MS (24UL * 60UL * 60UL * 1000UL)
extern Configuration Config; extern Configuration Config;
extern NetworkManager *networkManager;
extern TinyGPSPlus gps; extern TinyGPSPlus gps;
extern String versionDate; extern String versionDate;
extern String firstLine; extern String firstLine;
@@ -53,6 +52,7 @@ extern int rssi;
extern float snr; extern float snr;
extern int freqError; extern int freqError;
extern String distance; extern String distance;
extern bool WiFiConnected;
extern int wxModuleType; extern int wxModuleType;
extern bool backupDigiMode; extern bool backupDigiMode;
extern bool shouldSleepLowVoltage; extern bool shouldSleepLowVoltage;
@@ -75,7 +75,7 @@ String secondaryBeaconPacket;
namespace Utils { namespace Utils {
void processStatus() { void processStatus() {
bool sendOverAPRSIS = Config.beacon.sendViaAPRSIS && Config.aprs_is.active && networkManager->isConnected(); bool sendOverAPRSIS = Config.beacon.sendViaAPRSIS && Config.aprs_is.active && WiFi.status() == WL_CONNECTED;
bool sendOverRF = !Config.beacon.sendViaAPRSIS && Config.beacon.sendViaRF; bool sendOverRF = !Config.beacon.sendViaAPRSIS && Config.beacon.sendViaRF;
if (!sendOverAPRSIS && !sendOverRF) { if (!sendOverAPRSIS && !sendOverRF) {
@@ -104,14 +104,12 @@ namespace Utils {
String getLocalIP() { String getLocalIP() {
if (Config.digi.ecoMode == 1 || Config.digi.ecoMode == 2) { if (Config.digi.ecoMode == 1 || Config.digi.ecoMode == 2) {
return "** WiFi AP Killed **"; return "** WiFi AP Killed **";
} else if (networkManager->isEthernetConnected()) { } else if (!WiFiConnected) {
return "LAN: " + networkManager->getEthernetIP().toString(); return "IP : 192.168.4.1";
} else if (!networkManager->isWiFiConnected() && networkManager->isWifiAPActive()) {
return "IP : " + networkManager->getWiFiAPIP().toString();
} else if (backupDigiMode) { } else if (backupDigiMode) {
return "- BACKUP DIGI MODE -"; return "- BACKUP DIGI MODE -";
} else { } else {
return "IP : " + networkManager->getWiFiIP().toString(); return "IP : " + String(WiFi.localIP()[0]) + "." + String(WiFi.localIP()[1]) + "." + String(WiFi.localIP()[2]) + "." + String(WiFi.localIP()[3]);
} }
} }
@@ -483,4 +481,4 @@ namespace Utils {
} }
} }
} }

View File

@@ -161,7 +161,7 @@ namespace WEB_Utils {
Config.callsign = getParamStringSafe("callsign", Config.callsign); Config.callsign = getParamStringSafe("callsign", Config.callsign);
Config.tacticalCallsign = getParamStringSafe("tacticalCallsign", Config.tacticalCallsign); Config.tacticalCallsign = getParamStringSafe("tacticalCallsign", Config.tacticalCallsign);
Config.wifiAutoAP.enabled = request->hasParam("wifi.autoAP.enabled", true);
Config.wifiAutoAP.password = getParamStringSafe("wifi.autoAP.password", Config.wifiAutoAP.password); Config.wifiAutoAP.password = getParamStringSafe("wifi.autoAP.password", Config.wifiAutoAP.password);
Config.wifiAutoAP.timeout = getParamIntSafe("wifi.autoAP.timeout", Config.wifiAutoAP.timeout); Config.wifiAutoAP.timeout = getParamIntSafe("wifi.autoAP.timeout", Config.wifiAutoAP.timeout);

View File

@@ -18,7 +18,6 @@
#include <WiFi.h> #include <WiFi.h>
#include "configuration.h" #include "configuration.h"
#include "network_manager.h"
#include "board_pinout.h" #include "board_pinout.h"
#include "wifi_utils.h" #include "wifi_utils.h"
#include "display.h" #include "display.h"
@@ -26,11 +25,16 @@
extern Configuration Config; extern Configuration Config;
extern NetworkManager *networkManager;
extern uint8_t myWiFiAPIndex;
extern int myWiFiAPSize;
extern WiFi_AP *currentWiFi;
extern bool backupDigiMode; extern bool backupDigiMode;
extern uint32_t lastServerCheck; extern uint32_t lastServerCheck;
bool WiFiConnected = false;
uint32_t WiFiAutoAPTime = millis();
bool WiFiAutoAPStarted = false;
uint8_t wifiCounter = 0; uint8_t wifiCounter = 0;
uint32_t lastBackupDigiTime = millis(); uint32_t lastBackupDigiTime = millis();
uint32_t lastWiFiCheck = 0; uint32_t lastWiFiCheck = 0;
@@ -40,35 +44,32 @@ namespace WIFI_Utils {
void checkWiFi() { void checkWiFi() {
if (Config.digi.ecoMode != 0) return; if (Config.digi.ecoMode != 0) return;
if (!networkManager->hasWiFiNetworks()) {
return;
}
uint32_t currentTime = millis(); uint32_t currentTime = millis();
if (backupDigiMode) { if (backupDigiMode) {
if (!networkManager->isWiFiConnected() && ((currentTime - lastBackupDigiTime) >= 15 * 60 * 1000)) { if (WiFi.status() != WL_CONNECTED && ((currentTime - lastBackupDigiTime) >= 15 * 60 * 1000)) {
Serial.println("*** Stopping BackUp Digi Mode ***"); Serial.println("*** Stopping BackUp Digi Mode ***");
backupDigiMode = false; backupDigiMode = false;
wifiCounter = 0; wifiCounter = 0;
} else if (networkManager->isWiFiConnected()) { } else if (WiFi.status() == WL_CONNECTED) {
Serial.println("*** WiFi Reconnect Success (Stopping Backup Digi Mode) ***"); Serial.println("*** WiFi Reconnect Success (Stopping Backup Digi Mode) ***");
backupDigiMode = false; backupDigiMode = false;
wifiCounter = 0; wifiCounter = 0;
} }
} }
if (!backupDigiMode && ((currentTime - lastWiFiCheck) >= 30 * 1000) && !networkManager->isWifiAPActive()) { if (!backupDigiMode && ((currentTime - lastWiFiCheck) >= 30 * 1000) && !WiFiAutoAPStarted) {
lastWiFiCheck = currentTime; lastWiFiCheck = currentTime;
if (networkManager->isWiFiConnected()) { if (WiFi.status() == WL_CONNECTED) {
if (Config.digi.backupDigiMode && (currentTime - lastServerCheck > 30 * 1000)) { if (Config.digi.backupDigiMode && (currentTime - lastServerCheck > 30 * 1000)) {
Serial.println("*** Server Connection LOST → Backup Digi Mode ***"); Serial.println("*** Server Connection LOST → Backup Digi Mode ***");
backupDigiMode = true; backupDigiMode = true;
WiFi.disconnect();
lastBackupDigiTime = currentTime; lastBackupDigiTime = currentTime;
} }
} else { } else {
Serial.println("Reconnecting to WiFi..."); Serial.println("Reconnecting to WiFi...");
WiFi.disconnect();
WIFI_Utils::startWiFi(); WIFI_Utils::startWiFi();
if (Config.digi.backupDigiMode) wifiCounter++; if (Config.digi.backupDigiMode) wifiCounter++;
@@ -82,47 +83,97 @@ namespace WIFI_Utils {
} }
void startAutoAP() { void startAutoAP() {
displayShow("", " Starting Auto AP", " Please connect to it " , " loading ...", 1000); WiFi.mode(WIFI_MODE_NULL);
networkManager->setupAP(Config.callsign + "-AP", Config.wifiAutoAP.password);
WiFi.mode(WIFI_AP);
WiFi.softAP(Config.callsign + "-AP", Config.wifiAutoAP.password);
WiFiAutoAPTime = millis();
WiFiAutoAPStarted = true;
} }
void startWiFi() { void startWiFi() {
networkManager->clearWiFiNetworks(); bool startAP = false;
for (size_t i = 0; i < Config.wifiAPs.size(); i++) { if (currentWiFi->ssid == "") {
const WiFi_AP& wifiAP = Config.wifiAPs[i]; startAP = true;
if (wifiAP.ssid.isEmpty()) continue; } else {
networkManager->addWiFiNetwork(wifiAP.ssid, wifiAP.password); uint8_t wifiCounter = 0;
} String hostName = "iGATE-" + Config.callsign;
WiFi.setHostname(hostName.c_str());
if (!networkManager->hasWiFiNetworks()) { WiFi.mode(WIFI_STA);
Serial.println("WiFi SSID not set!"); WiFi.disconnect();
if (Config.wifiAutoAP.enabled) { delay(500);
Serial.println("Starting AP fallback..."); unsigned long start = millis();
startAutoAP(); 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 < myWiFiAPSize) {
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
if ((millis() - start) > 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());
}
} }
return;
} }
displayShow("", "Connecting to WiFi:", "", " loading ...", 0);
networkManager->connectWiFi();
#ifdef INTERNAL_LED_PIN #ifdef INTERNAL_LED_PIN
digitalWrite(INTERNAL_LED_PIN, LOW); digitalWrite(INTERNAL_LED_PIN, LOW);
#endif #endif
if (networkManager->isWiFiConnected()) { if (WiFi.status() == WL_CONNECTED) {
Serial.print("[WiFi] Connected as "); Serial.print("\nConnected as ");
Serial.print(networkManager->getWiFiIP()); Serial.print(WiFi.localIP());
Serial.print(" / MAC Address: "); Serial.print(" / MAC Address: ");
Serial.println(networkManager->getWiFimacAddress()); Serial.println(WiFi.macAddress());
displayShow("", " Connected!!", "" , " loading ...", 1000); displayShow("", " Connected!!", "" , " loading ...", 1000);
} else { } else {
Serial.println("[WiFi] Not connected to WiFi!"); startAP = true;
if (Config.wifiAutoAP.enabled) {
Serial.println("Starting AP fallback..."); Serial.println("\nNot connected to WiFi! Starting Auto AP");
displayShow("", " WiFi Not Connected!", "" , " loading ...", 1000); displayShow("", " WiFi Not Connected!", "" , " loading ...", 1000);
startAutoAP(); }
WiFiConnected = !startAP;
if (startAP) {
Serial.println("\nNot connected to WiFi! Starting Auto AP");
displayShow("", " Starting Auto AP", " Please connect to it " , " loading ...", 1000);
startAutoAP();
}
}
void checkAutoAPTimeout() {
if (WiFiAutoAPStarted && Config.wifiAutoAP.timeout > 0) {
if (WiFi.softAPgetStationNum() > 0) {
WiFiAutoAPTime = 0;
} else { } else {
displayShow("", " WiFi Not Connected!", "" , " loading ...", 1000); if (WiFiAutoAPTime == 0) {
WiFiAutoAPTime = millis();
} else if ((millis() - WiFiAutoAPTime) > Config.wifiAutoAP.timeout * 60 * 1000) {
Serial.println("Stopping auto AP");
WiFiAutoAPStarted = false;
WiFi.softAPdisconnect(true);
Serial.println("Auto AP stopped (timeout)");
}
} }
} }
} }
@@ -132,4 +183,4 @@ namespace WIFI_Utils {
btStop(); btStop();
} }
} }