From 09bd36cb9a394d3df6b3a07bd01c3b46e5924afb Mon Sep 17 00:00:00 2001 From: Gavin Wang Date: Thu, 15 Jun 2023 02:48:47 +0800 Subject: [PATCH] Create Pio project --- .gitignore | 7 ++ README.md | 5 +- platformio.ini | 17 ++++ src/config/user_config.cpp | 129 ++++++++++++++++++++++++++ src/config/user_config.h | 31 +++++++ src/entity/config.h | 23 +++++ src/entity/index.h | 17 ++++ src/main.cpp | 173 +++++++++++++++++++++++++++++++++++ src/services/wifiService.cpp | 92 +++++++++++++++++++ src/services/wifiService.h | 30 ++++++ test/test.html | 122 ++++++++++++++++++++++++ 11 files changed, 644 insertions(+), 2 deletions(-) create mode 100644 platformio.ini create mode 100644 src/config/user_config.cpp create mode 100644 src/config/user_config.h create mode 100644 src/entity/config.h create mode 100644 src/entity/index.h create mode 100644 src/main.cpp create mode 100644 src/services/wifiService.cpp create mode 100644 src/services/wifiService.h create mode 100644 test/test.html diff --git a/.gitignore b/.gitignore index c6127b3..8056b14 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch # Prerequisites *.d @@ -50,3 +55,5 @@ modules.order Module.symvers Mkfile.old dkms.conf +cmake-build-debug/ +cmake-build-esp8285/ diff --git a/README.md b/README.md index 52af0ec..30d9507 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ -# esp8266_ddns -DDNS for Esp8266 +# DDNS for Esp8266 + +## diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..12f014b --- /dev/null +++ b/platformio.ini @@ -0,0 +1,17 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:esp8285] +platform = espressif8266 +board = esp01_1m +framework = arduino +monitor_speed = 115200 +upload_resetmethod = nodemcu +lib_deps = bblanchon/ArduinoJson@^6.21.3 diff --git a/src/config/user_config.cpp b/src/config/user_config.cpp new file mode 100644 index 0000000..8495545 --- /dev/null +++ b/src/config/user_config.cpp @@ -0,0 +1,129 @@ +// +// Created by Gavin Wang on 6/23/23. +// + +#include +#include "user_config.h" +#include + +const String CONFIG_FILE = "/config.txt"; + + +/** + * Save param userConfig to local file system. + * @param userConfig user configuration + */ +void UserConfigService::saveConfigToFS(UserConfig *userConfig) { + File configFile = LittleFS.open(CONFIG_FILE, "w"); + if (!configFile) { + Serial.println("Failed to open userConfig file for writing"); + return; + } + DynamicJsonDocument doc(1024); + doc["wifi_ssid"] = userConfig->wifi_ssid.c_str(); + doc["wifi_password"] = userConfig->wifi_password.c_str(); + doc["ddns_hostname"] = userConfig->ddns_hostname.c_str(); + doc["ddns_domain"] = userConfig->ddns_domain.c_str(); + doc["ddns_password"] = userConfig->ddns_password.c_str(); + doc["ddns_url"] = userConfig->ddns_url.c_str(); + doc["ip_service_url"] = userConfig->ip_service_url.c_str(); + doc["refresh_timeout"] = userConfig->refresh_timeout.c_str(); + + String jsonStr; + serializeJson(doc, jsonStr); + configFile.println(jsonStr); + + configFile.close(); +} + +/** + * Delete config from file system. + */ +void UserConfigService::deleteConfigFromFS() { + bool result = LittleFS.remove(CONFIG_FILE); + if (!result) { + Serial.println("Failed to open config file for writing"); + return; + } +} + +/** + * Check UserConfig correctly. + * @param config user input + * @return is correctly + */ +bool UserConfigService::checkConfigProperties(UserConfig *config) { + + if (config->wifi_ssid == "") { + Serial.println("wifi_ssid:" + config->wifi_ssid); + return false; + } + if (config->wifi_password == "") { + Serial.println("wifi_password:" + config->wifi_password); + return false; + } + if (config->ddns_domain == "") { + Serial.println("ddns_domain:" + config->ddns_domain); + return false; + } + if (config->ddns_url == "") { + Serial.println("ddns_url:" + config->ddns_url); + return false; + } + if (config->ip_service_url == "") { + Serial.println("ip_service_url:" + config->ip_service_url); + return false; + } + + if (config->refresh_timeout == "0") { + Serial.println("refresh_timeout:" + config->refresh_timeout); + return false; + } + + return true; +} + +/** + * Reading user setting from file system. + * @return + */ +bool UserConfigService::readConfig() { + bool isFileExists = LittleFS.exists(CONFIG_FILE); + Serial.printf("readConfig: %d", isFileExists); + if (isFileExists) { + File configFile = LittleFS.open(CONFIG_FILE, "r"); + if (configFile) { + + DynamicJsonDocument doc(1024); + deserializeJson(doc, configFile.readStringUntil('\n').c_str()); + Serial.println("configFile: exist"); + + this->config.wifi_ssid = doc["wifi_ssid"].as(); + this->config.wifi_password = doc["wifi_password"].as(); + this->config.ddns_hostname = doc["ddns_hostname"].as(); + this->config.ddns_domain = doc["ddns_domain"].as(); + this->config.ddns_password = doc["ddns_password"].as(); + this->config.ddns_url = doc["ddns_url"].as(); + this->config.ip_service_url = doc["ip_service_url"].as(); + this->config.refresh_timeout = doc["refresh_timeout"].as(); + + Serial.printf("local configFile: %s \n%s \n%s \n%s \n%s \n%s", + this->config.wifi_ssid.c_str(), + this->config.wifi_password.c_str(), this->config.ddns_hostname.c_str(), this->config.ddns_domain.c_str(), + this->config.ddns_password.c_str(), this->config.ddns_url.c_str()); + + configFile.close(); + + return true; + } else { + Serial.println("configFile: isn't exist"); + } + } + return false; +} + +UserConfig UserConfigService::getUserConfig() { + return this->config; +} + + diff --git a/src/config/user_config.h b/src/config/user_config.h new file mode 100644 index 0000000..dc09dae --- /dev/null +++ b/src/config/user_config.h @@ -0,0 +1,31 @@ +// +// Created by Gavin Wang on 6/23/23. +// + +#ifndef ESP8266_DDNS_USER_CONFIG_H +#define ESP8266_DDNS_USER_CONFIG_H + +#include +#include "entity/config.h" + +class UserConfigService { +private: + UserConfig config; + +public: + UserConfigService() = default; + + UserConfig getUserConfig(); + + bool readConfig(); + + static void deleteConfigFromFS(); + + static void saveConfigToFS(UserConfig *userConfig); + + static bool checkConfigProperties(UserConfig *config); + +}; + + +#endif //ESP8266_DDNS_USER_CONFIG_H diff --git a/src/entity/config.h b/src/entity/config.h new file mode 100644 index 0000000..585b3d6 --- /dev/null +++ b/src/entity/config.h @@ -0,0 +1,23 @@ +// +// Created by Gavin Wang on 30/6/23. +// + +#ifndef ESP8266_DDNS_CONFIG_H +#define ESP8266_DDNS_CONFIG_H + +#include + +class UserConfig { +public: + String wifi_ssid; + String wifi_password; + String ddns_hostname; + String ddns_domain; + String ddns_password; + String ddns_url; + String ip_service_url; + String refresh_timeout; +}; + + +#endif //ESP8266_DDNS_CONFIG_H diff --git a/src/entity/index.h b/src/entity/index.h new file mode 100644 index 0000000..4a33e15 --- /dev/null +++ b/src/entity/index.h @@ -0,0 +1,17 @@ +// +// Created by Gavin Wang on 6/23/23. +// + +#ifndef ESP8266_DDNS_INDEX_H +#define ESP8266_DDNS_INDEX_H + +#include + +class Index { + +public: + const String PAGE = R"(Wifi Settings

Settings

WiFi and DDNS Configuration






)"; +}; + + +#endif //ESP8266_DDNS_INDEX_H diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..8fc3af9 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,173 @@ +#include + +#include +#include +#include +#include "config/user_config.h" +#include "services/wifiService.h" + +const uint16_t CONFIG_TIMEOUT = 60 * 1000; +const char *ntpServer = "pool.ntp.org"; +const long gmtOffsetSec = 8 * 3600; +const int daylightOffsetSec = 0; +int refreshTimeout; + +String oldIP = ""; +int errorTime = 0; + +UserConfig userConfig; +UserConfigService *userConfigService; +bool hasUserconfig = false; + + +ESP8266WiFiClass WiFi; + +String url; + +void initUrlFromUserConfig(); + +void sendToDDNSServer(String url); + +String getIpFromIpServer(); + +void printTime(); + +void setup() { + Serial.begin(115200); + LittleFS.begin(); + userConfigService = new UserConfigService(); + Serial.printf("userConfigService is null: %d", userConfigService == nullptr); + // if user config can be read + hasUserconfig = userConfigService->readConfig(); + Serial.printf("readConfig %d", hasUserconfig); + if (hasUserconfig) { + // Set to AP mode , connect to WI-FI + Serial.println("Config file exist"); + WiFi.mode(WIFI_STA); + userConfig = userConfigService->getUserConfig(); + WiFi.begin(userConfig.wifi_ssid.c_str(), userConfig.wifi_password); + Serial.printf("SSID: %s \tPassword: %s", userConfig.wifi_ssid.c_str(), + userConfig.wifi_password.c_str()); + Serial.print("\nConnecting to WiFi."); + uint32_t configStartTime = millis(); + + // Init refresh timeout + refreshTimeout = userConfig.refresh_timeout.toInt(); + + // waiting connect status + while (WifiService::isWifiNotConnect(WiFi) && millis() - configStartTime < CONFIG_TIMEOUT) { + delay(1000); + Serial.print("."); + } + if (WifiService::isWifiConnect(WiFi)) { + // if successful ,it will go loop func + Serial.println("\nConnecting Wifi Successful."); + initUrlFromUserConfig(); + configTime(gmtOffsetSec, daylightOffsetSec, ntpServer); + + } else { + // If failed + Serial.println("\nFailed to connect WiFi. Starting AP mode."); + // Delete config + UserConfigService::deleteConfigFromFS(); + // Turn station mode on + WifiService::startAccessPoint(WiFi); + } + } else { + // If it didn't find user config file + Serial.println("\nDidn't find user config file."); + // Turn station mode on + WifiService::startAccessPoint(WiFi); + } + +} + + +void loop() { + if (WifiService::isWifiConnect(WiFi)) { + errorTime = 0; + + printTime(); + String publicIP = getIpFromIpServer(); + if (publicIP != "") { + publicIP.trim(); + Serial.printf("\nPublic IP address: %s", publicIP.c_str()); + if (publicIP != oldIP) { + oldIP = publicIP; + // if oldIP is not similarly between current IP, update DDNS + String urlTmp = url; + urlTmp.replace("$PUBLIC_IP", String(publicIP.c_str())); + Serial.printf("Address: %s", urlTmp.c_str()); + sendToDDNSServer(urlTmp); + + } else { + Serial.print("IP not Update."); + } + // Sleep and restart loop + // Get refresh timeout from user config + delay(refreshTimeout * 60 * 1000); + } + + } else { + if (hasUserconfig) { + errorTime++; + if (errorTime > 3) { + EspClass::restart(); + } + Serial.printf("Wifi connect error %d times.", errorTime); + delay(refreshTimeout * 60 * 1000); + } + WifiService::handleClient(); + } +} + + +void initUrlFromUserConfig() { + url = userConfig.ddns_url; + url.replace("$DDNS_DOMAIN", userConfig.ddns_domain); + if (userConfig.ddns_hostname != "") { + url.replace("$DDNS_HOSTNAME", userConfig.ddns_hostname); + } + if (userConfig.ddns_password != "") { + url.replace("$DDNS_PASSWORD", userConfig.ddns_password); + } + + Serial.printf("Init url: %s", url.c_str()); +} + +String getIpFromIpServer() { + String result = ""; + // Get IP from WI-FI IP address + HTTPClient ipServerHttp; + WiFiClient ipSercerWifiClient; + ipServerHttp.begin(ipSercerWifiClient, userConfig.ip_service_url); + int httpCode = ipServerHttp.GET(); + + Serial.printf("\n IP server connect status: %d", httpCode); + if (httpCode == HTTP_CODE_OK) { + result = ipServerHttp.getString(); + } + + return result; +} + +void sendToDDNSServer(String url) { + // send message to DDNS server + HTTPClient ddnsServerHttp; + WiFiClient ddnsSercerWifiClient; + ddnsServerHttp.begin(ddnsSercerWifiClient, url.c_str()); + int httpCode = ddnsServerHttp.GET(); + + // get result + String response = ddnsServerHttp.getString(); + Serial.printf("\n HTTP Code: %d\nHttp response is: %s ", httpCode, response.c_str()); + +} + +void printTime() { + struct tm timeInfo{}; + if (getLocalTime(&timeInfo)) { + Serial.printf("\n%d-%d-%d %d:%d:%d", timeInfo.tm_year, timeInfo.tm_mon, timeInfo.tm_mday, + timeInfo.tm_hour, timeInfo.tm_min, timeInfo.tm_sec); + } +} \ No newline at end of file diff --git a/src/services/wifiService.cpp b/src/services/wifiService.cpp new file mode 100644 index 0000000..6358f74 --- /dev/null +++ b/src/services/wifiService.cpp @@ -0,0 +1,92 @@ +// +// Created by Gavin Wang on 6/23/23. +// + +#include +#include "wifiService.h" +#include "entity/index.h" +#include "config/user_config.h" +#include +#include + +const String AP_SSID = "HomingBeacon"; +const String AP_PASSWORD = "12345678"; + +ESP8266WebServer server(80); + +WifiService::WifiService() = default; + +/** + * Handle user configuration page. + */ +void handleUserConfigurationPage() { + server.send(200, "text/html", (new Index())->PAGE); +} + +/** + * Save user input to driver file system + */ +void handleSetInfoSave() { + UserConfig *userConfigInp = new UserConfig(); + userConfigInp->wifi_ssid = server.arg("wifi_ssid"); + userConfigInp->wifi_password = server.arg("wifi_password"); + userConfigInp->ddns_hostname = server.arg("ddns_hostname"); + userConfigInp->ddns_domain = server.arg("ddns_domain"); + userConfigInp->ddns_password = server.arg("ddns_password"); + userConfigInp->ddns_url = server.arg("ddns_url"); + userConfigInp->ip_service_url = server.arg("ip_service_url"); + userConfigInp->refresh_timeout = server.arg("refresh_timeout"); + + //check user input legally + if (UserConfigService::checkConfigProperties(userConfigInp)) { + Serial.printf("configFile: %s \n%s \n%s \n%s \n%s \n%s", userConfigInp->wifi_ssid.c_str(), + userConfigInp->wifi_password.c_str(), userConfigInp->ddns_hostname.c_str(), + userConfigInp->ddns_domain.c_str(), + userConfigInp->ddns_password.c_str(), userConfigInp->ddns_url.c_str()); + + + UserConfigService::saveConfigToFS(userConfigInp); + server.send(200, "text/plain", "Configuration saved. Restarting..."); + + } else { + server.send(200, "text/plain", "Configuration is incorrect. Restarting..."); + } + delete (userConfigInp); + delay(2000); + EspClass::restart(); +} + +/** + * Check driver whether send data to server. + */ +void WifiService::handleClient() { + server.handleClient(); +} + +/** + * Set driver to AP mode , receive data from user setting page. + */ +void WifiService::startAccessPoint(ESP8266WiFiClass wifi) { + wifi.mode(WIFI_AP); + wifi.softAP(AP_SSID, AP_PASSWORD); + + Serial.println("AP IP address: " + WiFi.softAPIP().toString()); + + server.on("/", handleUserConfigurationPage); + server.on("/set_info", handleSetInfoSave); + + server.begin(); + +} + +/** + * @return Wifi stsaatus + */ +bool WifiService::isWifiConnect(ESP8266WiFiClass wifiClass) { + return wifiClass.status() == WL_CONNECTED; +} + +bool WifiService::isWifiNotConnect(ESP8266WiFiClass wifiClass) { + return !isWifiConnect(wifiClass); +} + diff --git a/src/services/wifiService.h b/src/services/wifiService.h new file mode 100644 index 0000000..d64ae03 --- /dev/null +++ b/src/services/wifiService.h @@ -0,0 +1,30 @@ +// +// Created by Gavin Wang on 6/23/23. +// + +#ifndef ESP8266_DDNS_WIFI_SERVICE_H +#define ESP8266_DDNS_WIFI_SERVICE_H + + +#include +#include +#include "config/user_config.h" + +class WifiService { + +public: + + + WifiService(); + + static void handleClient(); + + static void startAccessPoint(ESP8266WiFiClass wifiClass); + + static bool isWifiConnect(ESP8266WiFiClass wifiClass); + + static bool isWifiNotConnect(ESP8266WiFiClass wifiClass); + +}; + +#endif //ESP8266_DDNS_WIFI_SERVICE_H diff --git a/test/test.html b/test/test.html new file mode 100644 index 0000000..d8362b3 --- /dev/null +++ b/test/test.html @@ -0,0 +1,122 @@ + + + + + + Wifi Settings + + +
+
+

Settings

+
+ WiFi and DDNS Configuration + + +
+ +
+
+
+
+
+ +
+ + +
+ +
+
+
+ +