From 94719be92826188b0f986e5e7541ae684bdb175e Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Sun, 10 Apr 2022 17:37:54 +0200 Subject: [PATCH] Implemented handling of WiFi settings --- include/Configuration.h | 14 ++++ include/WiFiSettings.h | 31 +++++++++ include/defaults.h | 15 ++++- src/Configuration.cpp | 7 ++ src/WiFiSettings.cpp | 144 ++++++++++++++++++++++++++++++++++++++++ src/main.cpp | 6 +- 6 files changed, 215 insertions(+), 2 deletions(-) create mode 100644 include/WiFiSettings.h create mode 100644 src/WiFiSettings.cpp diff --git a/include/Configuration.h b/include/Configuration.h index e3dd74f..1a1a24f 100644 --- a/include/Configuration.h +++ b/include/Configuration.h @@ -5,9 +5,23 @@ #define CONFIG_FILENAME "/config.bin" #define CONFIG_VERSION 0x00010000 // 0.1.0 +#define WIFI_MAX_SSID_STRLEN 31 +#define WIFI_MAX_PASSWORD_STRLEN 31 +#define WIFI_MAX_HOSTNAME_STRLEN 31 + struct CONFIG_T { uint32_t Cfg_Version; uint Cfg_SaveCount; + + char WiFi_Ssid[WIFI_MAX_SSID_STRLEN + 1]; + char WiFi_Password[WIFI_MAX_PASSWORD_STRLEN + 1]; + byte WiFi_Ip[4]; + byte WiFi_Netmask[4]; + byte WiFi_Gateway[4]; + byte WiFi_Dns1[4]; + byte WiFi_Dns2[4]; + bool WiFi_Dhcp; + char WiFi_Hostname[WIFI_MAX_HOSTNAME_STRLEN + 1]; }; class ConfigurationClass { diff --git a/include/WiFiSettings.h b/include/WiFiSettings.h new file mode 100644 index 0000000..bbc3309 --- /dev/null +++ b/include/WiFiSettings.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +class WiFiSettingsClass { +public: + WiFiSettingsClass(); + void init(); + void loop(); + void applyConfig(); + void enableAdminMode(); + String getApName(); + +private: + void setHostname(); + void setStaticIp(); + void setupMode(); + bool adminEnabled = true; + bool forceDisconnection = false; + int adminTimeoutCounter = 0; + int connectTimeoutTimer = 0; + int connectRedoTimer = 0; + unsigned long lastTimerCall = 0; + const byte DNS_PORT = 53; + IPAddress apIp; + IPAddress apNetmask; + std::unique_ptr dnsServer; +}; + +extern WiFiSettingsClass WiFiSettings; \ No newline at end of file diff --git a/include/defaults.h b/include/defaults.h index a067eec..8635fa7 100644 --- a/include/defaults.h +++ b/include/defaults.h @@ -1,3 +1,16 @@ #pragma once -#define SERIAL_BAUDRATE 115200 \ No newline at end of file +#define SERIAL_BAUDRATE 115200 + +#define APP_HOSTNAME "OpenDTU-%06X" + +#define ACCESS_POINT_NAME "OpenDTU-" +#define ACCESS_POINT_PASSWORD "openDTU" + +#define ADMIN_TIMEOUT 180 +#define WIFI_RECONNECT_TIMEOUT 15 +#define WIFI_RECONNECT_REDO_TIMEOUT 600 + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" +#define WIFI_DHCP true \ No newline at end of file diff --git a/src/Configuration.cpp b/src/Configuration.cpp index 1efbf8d..e101016 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -1,4 +1,5 @@ #include "Configuration.h" +#include "defaults.h" #include CONFIG_T config; @@ -8,6 +9,12 @@ void ConfigurationClass::init() memset(&config, 0x0, sizeof(config)); config.Cfg_SaveCount = 0; config.Cfg_Version = CONFIG_VERSION; + + // WiFi Settings + strlcpy(config.WiFi_Ssid, WIFI_SSID, sizeof(config.WiFi_Ssid)); + strlcpy(config.WiFi_Password, WIFI_PASSWORD, sizeof(config.WiFi_Password)); + config.WiFi_Dhcp = WIFI_DHCP; + strlcpy(config.WiFi_Hostname, APP_HOSTNAME, sizeof(config.WiFi_Hostname)); } bool ConfigurationClass::write() diff --git a/src/WiFiSettings.cpp b/src/WiFiSettings.cpp new file mode 100644 index 0000000..7a7934f --- /dev/null +++ b/src/WiFiSettings.cpp @@ -0,0 +1,144 @@ +#include "WiFiSettings.h" +#include "Configuration.h" +#include "defaults.h" +#include + +WiFiSettingsClass::WiFiSettingsClass() + : apIp(172, 217, 28, 1) + , apNetmask(255, 255, 255, 0) +{ + dnsServer.reset(new DNSServer()); +} + +void WiFiSettingsClass::init() +{ + setupMode(); +} + +void WiFiSettingsClass::setupMode() +{ + if (adminEnabled) { + WiFi.mode(WIFI_AP_STA); + String ssidString = getApName(); + WiFi.softAPConfig(apIp, apIp, apNetmask); + WiFi.softAP((const char*)ssidString.c_str(), ACCESS_POINT_PASSWORD); + dnsServer->setErrorReplyCode(DNSReplyCode::NoError); + dnsServer->start(DNS_PORT, "*", WiFi.softAPIP()); + } else { + dnsServer->stop(); + WiFi.mode(WIFI_STA); + } +} + +void WiFiSettingsClass::enableAdminMode() +{ + adminEnabled = true; + adminTimeoutCounter = 0; + setupMode(); +} + +String WiFiSettingsClass::getApName() +{ + uint32_t chipId = 0; + for (int i = 0; i < 17; i += 8) { + chipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i; + } + return String(ACCESS_POINT_NAME + String(chipId)); +} + +void WiFiSettingsClass::loop() +{ + if (millis() - lastTimerCall > 1000) { + adminTimeoutCounter++; + connectTimeoutTimer++; + connectRedoTimer++; + lastTimerCall = millis(); + } + if (adminEnabled) { + // Don't disable the admin mode when WiFi is not available + if (WiFi.status() != WL_CONNECTED) { + adminTimeoutCounter = 0; + } + // If WiFi is connected to AP for more than ADMIN_TIMEOUT + // seconds, disable the internal Access Point + if (adminTimeoutCounter > ADMIN_TIMEOUT) { + adminEnabled = false; + Serial.println(F("Admin mode disabled")); + setupMode(); + } + // It's nearly not possible to use the internal AP if the + // WiFi is searching for an AP. So disable searching afer + // WIFI_RECONNECT_TIMEOUT and repeat after WIFI_RECONNECT_REDO_TIMEOUT + if (WiFi.status() == WL_CONNECTED) { + connectTimeoutTimer = 0; + connectRedoTimer = 0; + } else { + if (connectTimeoutTimer > WIFI_RECONNECT_TIMEOUT && !forceDisconnection) { + Serial.print(F("Disable search for AP... ")); + WiFi.mode(WIFI_AP); + Serial.println(F("done")); + connectRedoTimer = 0; + forceDisconnection = true; + } + if (connectRedoTimer > WIFI_RECONNECT_REDO_TIMEOUT && forceDisconnection) { + Serial.print(F("Enable search for AP... ")); + WiFi.mode(WIFI_AP_STA); + Serial.println(F("done")); + applyConfig(); + connectTimeoutTimer = 0; + forceDisconnection = false; + } + } + } + dnsServer->processNextRequest(); +} + +void WiFiSettingsClass::applyConfig() +{ + setHostname(); + if (!strcmp(Configuration.get().WiFi_Ssid, "")) { + return; + } + Serial.print(F("Configuring WiFi STA using ")); + if (strcmp(WiFi.SSID().c_str(), Configuration.get().WiFi_Ssid) || strcmp(WiFi.psk().c_str(), Configuration.get().WiFi_Password)) { + Serial.print(F("new credentials... ")); + WiFi.begin( + Configuration.get().WiFi_Ssid, + Configuration.get().WiFi_Password); + } else { + Serial.print(F("existing credentials... ")); + WiFi.begin(); + } + Serial.println("done"); + setStaticIp(); +} + +void WiFiSettingsClass::setHostname() +{ + Serial.print(F("Setting Hostname... ")); + if (strcmp(Configuration.get().WiFi_Hostname, "")) { + if (WiFi.hostname(Configuration.get().WiFi_Hostname)) { + Serial.println(F("done")); + } else { + Serial.println(F("failed")); + } + } else { + Serial.println(F("failed (Hostname empty)")); + } +} + +void WiFiSettingsClass::setStaticIp() +{ + if (!Configuration.get().WiFi_Dhcp) { + Serial.print(F("Configuring WiFi STA static IP... ")); + WiFi.config( + IPAddress(Configuration.get().WiFi_Ip), + IPAddress(Configuration.get().WiFi_Gateway), + IPAddress(Configuration.get().WiFi_Netmask), + IPAddress(Configuration.get().WiFi_Dns1), + IPAddress(Configuration.get().WiFi_Dns2)); + Serial.println(F("done")); + } +} + +WiFiSettingsClass WiFiSettings; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 754cd77..5f4ab90 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,5 @@ #include "Configuration.h" +#include "WiFiSettings.h" #include "defaults.h" #include #include @@ -39,9 +40,12 @@ void setup() // Initialize WiFi Serial.print(F("Initialize WiFi... ")); + WiFiSettings.init(); + Serial.println(F("done")); + WiFiSettings.applyConfig(); } void loop() { - // put your main code here, to run repeatedly: + WiFiSettings.loop(); } \ No newline at end of file