Created
October 17, 2020 21:02
-
-
Save marcelstoer/914ff2ac58a42a957dfa071c9c5c8acd to your computer and use it in GitHub Desktop.
ESP32 WiFi Manager based on ESPAsync_WiFiManager
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/**************************************************************************************************/ | |
/* */ | |
/* Adaptation and simplification of the blue-print sketch at */ | |
/* https://github.com/khoih-prog/ESPAsync_WiFiManager/tree/master/examples/Async_ConfigOnSwitch */ | |
/* */ | |
/**************************************************************************************************/ | |
#include <esp_wifi.h> | |
#include <WiFi.h> | |
#include <WiFiClient.h> | |
#include <WiFiMulti.h> | |
#include <SPIFFS.h> | |
WiFiMulti wifiMulti; | |
FS* filesystem = &SPIFFS; | |
#define FileFS SPIFFS | |
#define FS_Name "SPIFFS" | |
const char* configPortalPassword = CONFIG_PORTAL_AP_PASSWORD; | |
String Router_SSID; | |
String Router_Pass; | |
#define SSID_MAX_LEN 32 | |
// WPA2 calls for 8-63 ASCII printable characters | |
#define PASSWORD_MIN_LEN 8 | |
#define PASSWORD_MAX_LEN 63 | |
typedef struct { | |
char wifi_ssid[SSID_MAX_LEN]; | |
char wifi_pw [PASSWORD_MAX_LEN]; | |
} WiFi_Credentials; | |
typedef struct { | |
String wifi_ssid; | |
String wifi_pw; | |
} WiFi_Credentials_String; | |
// store at most that many access point information (multi-WiFi) | |
#define NUM_WIFI_CREDENTIALS 2 | |
typedef struct { | |
WiFi_Credentials WiFi_Creds [NUM_WIFI_CREDENTIALS]; | |
} WM_Config; | |
WM_Config WM_config; | |
#define CONFIG_FILENAME F("/wifi_cred.dat") | |
// Indicates whether ESP has WiFi credentials saved from previous session, or double reset detected | |
bool initialConfig = false; | |
#include <ESPAsync_WiFiManager.h> | |
AsyncWebServer webServer(80); | |
DNSServer dnsServer; | |
/*****************************************************************************/ | |
/* Function declaration */ | |
/*****************************************************************************/ | |
// pseudo-public | |
void checkWifiStatus(void); | |
void initWifiManager(String deviceId); | |
void startConfigPortal(String deviceId); | |
// pseudo-private | |
void check_WiFi(void); | |
void loadConfigData(void); | |
void saveConfigData(void); | |
uint8_t connectMultiWiFi(void); | |
bool wifiCredentialsValid(uint8_t index); | |
void processConfigPortalUserData(ESPAsync_WiFiManager *ESPAsync_wifiManager); | |
/*****************************************************************************/ | |
/* Functions */ | |
/*****************************************************************************/ | |
void initWifiManager(String deviceId) { | |
log_i("Starting Async_ConfigOnSwitch using '%s' on %s.", FS_Name, ARDUINO_BOARD); | |
if (!FileFS.begin(true)) { | |
log_w("'%s' failed! AutoFormatting.", FS_Name); | |
} | |
unsigned long startedAt = millis(); | |
ESPAsync_WiFiManager ESPAsync_wifiManager(&webServer, &dnsServer); | |
ESPAsync_wifiManager.setDebugOutput(true); | |
ESPAsync_wifiManager.setMinimumSignalQuality(-1); | |
// 0 => random channel from 1-13 | |
ESPAsync_wifiManager.setConfigPortalChannel(0); | |
// We can't use WiFi.SSID() in ESP32 as it's only valid after connected. | |
// SSID and Password stored in ESP32 wifi_ap_record_t and wifi_config_t are also cleared in reboot | |
// Have to create a new function to store in EEPROM/SPIFFS for this purpose | |
Router_SSID = ESPAsync_wifiManager.WiFi_SSID(); | |
Router_Pass = ESPAsync_wifiManager.WiFi_Pass(); | |
// Remove this line if you do not want to see WiFi password printed | |
log_i("Stored: SSID = %s, Pass = %s.", Router_SSID, Router_Pass); | |
String configPortalSsid = CONFIG_PORTAL_AP_NAME_PREFIX + deviceId; | |
if ((Router_SSID != "") && (Router_Pass != "")) { | |
LOGERROR3(F("* Add SSID = "), Router_SSID, F(", PW = "), Router_Pass); | |
wifiMulti.addAP(Router_SSID.c_str(), Router_Pass.c_str()); | |
ESPAsync_wifiManager.setConfigPortalTimeout(120); // If no access point name has been previously entered disable timeout. | |
log_i("Got stored Credentials. Timeout 120s for Config Portal"); | |
} else { | |
log_i("Open Config Portal without Timeout: No stored Credentials."); | |
initialConfig = true; | |
} | |
if (initialConfig) { | |
log_i("Starting configuration portal."); | |
// sets timeout in seconds until configuration portal gets turned off. | |
// If not specified device will remain in configuration mode until | |
// switched off via webserver or device is restarted. | |
ESPAsync_wifiManager.setConfigPortalTimeout(600); | |
// Starts an access point | |
if (!ESPAsync_wifiManager.startConfigPortal((const char *)configPortalSsid.c_str(), configPortalPassword)) { | |
log_i("Not connected to WiFi but continuing anyway."); | |
} else { | |
log_i("WiFi connected...yeey :)"); | |
} | |
// Stored for later usage, from v1.1.0, but clear first | |
memset(&WM_config, 0, sizeof(WM_config)); | |
processConfigPortalUserData(&ESPAsync_wifiManager); | |
saveConfigData(); | |
} | |
startedAt = millis(); | |
if (!initialConfig) { | |
// Load stored data, the addAP ready for MultiWiFi reconnection | |
loadConfigData(); | |
for (uint8_t i = 0; i < NUM_WIFI_CREDENTIALS; i++) { | |
if (wifiCredentialsValid(i)) { | |
LOGERROR3(F("* Add SSID = "), WM_config.WiFi_Creds[i].wifi_ssid, F(", PW = "), WM_config.WiFi_Creds[i].wifi_pw); | |
wifiMulti.addAP(WM_config.WiFi_Creds[i].wifi_ssid, WM_config.WiFi_Creds[i].wifi_pw); | |
} | |
} | |
if (WiFi.status() != WL_CONNECTED) { | |
connectMultiWiFi(); | |
} | |
} | |
log_i("After waiting %d secs more in initWifiManager(), connection result is ", ((float)(millis() - startedAt) / 1000L)); | |
if (WiFi.status() == WL_CONNECTED) { | |
log_i("connected. Local IP: %s", WiFi.localIP().toString()); | |
} else { | |
log_i("%s", String(ESPAsync_wifiManager.getStatus(WiFi.status()))); | |
} | |
} | |
void startConfigPortal(String deviceId){ | |
log_i("Configuration portal requested."); | |
//Local intialization. Once its business is done, there is no need to keep it around | |
ESPAsync_WiFiManager ESPAsync_wifiManager(&webServer, &dnsServer); | |
ESPAsync_wifiManager.setMinimumSignalQuality(-1); | |
// From v1.0.10 only | |
// Set config portal channel, default = 1. Use 0 => random channel from 1-13 | |
ESPAsync_wifiManager.setConfigPortalChannel(0); | |
// ESPAsync_wifiManager.setCORSHeader("Access-Control-Allow-Origin: *"); | |
//Check if there is stored WiFi router/password credentials. | |
//If not found, device will remain in configuration mode until switched off via webserver. | |
log_i("Opening configuration portal. "); | |
Router_SSID = ESPAsync_wifiManager.WiFi_SSID(); | |
Router_Pass = ESPAsync_wifiManager.WiFi_Pass(); | |
// From v1.1.0, Don't permit NULL password | |
if ((Router_SSID != "") && (Router_Pass != "")) { | |
ESPAsync_wifiManager.setConfigPortalTimeout(120); // If no access point name has been previously entered disable timeout. | |
log_i("Got stored Credentials. Timeout 120s"); | |
} else { | |
log_i("No stored Credentials. No timeout"); | |
} | |
String configPortalSsid = CONFIG_PORTAL_AP_NAME_PREFIX + deviceId; | |
//Starts an access point | |
//and goes into a blocking loop awaiting configuration | |
if (!ESPAsync_wifiManager.startConfigPortal((const char *)configPortalSsid.c_str(), configPortalPassword)) { | |
log_i("Not connected to WiFi but continuing anyway."); | |
} else { | |
// if you get here you have connected to the WiFi | |
log_i("connected...yeey :)"); | |
log_i("Local IP: %s", WiFi.localIP().toString()); | |
} | |
// Only clear then save data if CP entered and with new valid Credentials | |
// No CP => stored getSSID() = "" | |
if ( String(ESPAsync_wifiManager.getSSID(0)) != "" && String(ESPAsync_wifiManager.getSSID(1)) != "" ) { | |
// Stored for later usage, from v1.1.0, but clear first | |
memset(&WM_config, 0, sizeof(WM_config)); | |
processConfigPortalUserData(&ESPAsync_wifiManager); | |
saveConfigData(); | |
} | |
} | |
void check_WiFi(void) { | |
if ((WiFi.status() != WL_CONNECTED)) { | |
log_i("WiFi lost. Call connectMultiWiFi in loop"); | |
connectMultiWiFi(); | |
} | |
} | |
void checkWifiStatus(void) { | |
static ulong checkwifi_timeout = 0; | |
static ulong current_millis; | |
#define WIFICHECK_INTERVAL 1000L | |
current_millis = millis(); | |
// Check WiFi every WIFICHECK_INTERVAL (1) seconds. | |
if ((current_millis > checkwifi_timeout) || (checkwifi_timeout == 0)) { | |
check_WiFi(); | |
checkwifi_timeout = current_millis + WIFICHECK_INTERVAL; | |
} | |
} | |
void loadConfigData(void) { | |
File file = FileFS.open(CONFIG_FILENAME, "r"); | |
LOGERROR(F("LoadWiFiCfgFile ")); | |
if (file) { | |
file.readBytes((char *)&WM_config, sizeof(WM_config)); | |
file.close(); | |
LOGERROR(F("OK")); | |
} else { | |
LOGERROR(F("failed")); | |
} | |
} | |
void saveConfigData(void) { | |
File file = FileFS.open(CONFIG_FILENAME, "w"); | |
LOGERROR(F("Save WiFi config file ")); | |
if (file) { | |
file.write((uint8_t *)&WM_config, sizeof(WM_config)); | |
file.close(); | |
LOGERROR(F("OK")); | |
} else { | |
LOGERROR(F("failed")); | |
} | |
} | |
uint8_t connectMultiWiFi(void) { | |
// For ESP32, this better be 0 to shorten the connect time | |
#define WIFI_MULTI_1ST_CONNECT_WAITING_MS 0 | |
#define WIFI_MULTI_CONNECT_WAITING_MS 100L | |
uint8_t status; | |
LOGERROR(F("ConnectMultiWiFi with :")); | |
if ((Router_SSID != "") && (Router_Pass != "")) { | |
LOGERROR3(F("* Flash-stored Router_SSID = "), Router_SSID, | |
F(", Router_Pass = "), Router_Pass); | |
} | |
for (uint8_t i = 0; i < NUM_WIFI_CREDENTIALS; i++) { | |
if (wifiCredentialsValid(i)) { | |
LOGERROR3(F("* Additional SSID = "), WM_config.WiFi_Creds[i].wifi_ssid, | |
F(", PW = "), WM_config.WiFi_Creds[i].wifi_pw); | |
} | |
} | |
LOGERROR(F("Connecting MultiWifi...")); | |
WiFi.mode(WIFI_STA); | |
int i = 0; | |
status = wifiMulti.run(); | |
delay(WIFI_MULTI_1ST_CONNECT_WAITING_MS); | |
while ((i++ < 20) && (status != WL_CONNECTED)) { | |
status = wifiMulti.run(); | |
if (status == WL_CONNECTED) { | |
break; | |
} else { | |
delay(WIFI_MULTI_CONNECT_WAITING_MS); | |
} | |
} | |
if (status == WL_CONNECTED) { | |
LOGERROR1(F("WiFi connected after time: "), i); | |
LOGERROR3(F("SSID:"), WiFi.SSID(), F(",RSSI="), WiFi.RSSI()); | |
LOGERROR3(F("Channel:"), WiFi.channel(), F(",IP address:"), WiFi.localIP()); | |
} else { | |
LOGERROR(F("WiFi not connected")); | |
} | |
return status; | |
} | |
// Don't permit NULL SSID and password length < PASSWORD_MIN_LEN (8) | |
bool wifiCredentialsValid(uint8_t index) { | |
return (String(WM_config.WiFi_Creds[index].wifi_ssid) != "") && | |
(strlen(WM_config.WiFi_Creds[index].wifi_pw) >= PASSWORD_MIN_LEN); | |
} | |
void processConfigPortalUserData(ESPAsync_WiFiManager *ESPAsync_wifiManager) { | |
for (uint8_t i = 0; i < NUM_WIFI_CREDENTIALS; i++) { | |
String tempSSID = ESPAsync_wifiManager->getSSID(i); | |
String tempPW = ESPAsync_wifiManager->getPW(i); | |
if (strlen(tempSSID.c_str()) < sizeof(WM_config.WiFi_Creds[i].wifi_ssid) - 1) { | |
strcpy(WM_config.WiFi_Creds[i].wifi_ssid, tempSSID.c_str()); | |
} else { | |
strncpy(WM_config.WiFi_Creds[i].wifi_ssid, tempSSID.c_str(), sizeof(WM_config.WiFi_Creds[i].wifi_ssid) - 1); | |
} | |
if (strlen(tempPW.c_str()) < sizeof(WM_config.WiFi_Creds[i].wifi_pw) - 1) { | |
strcpy(WM_config.WiFi_Creds[i].wifi_pw, tempPW.c_str()); | |
} else { | |
strncpy(WM_config.WiFi_Creds[i].wifi_pw, tempPW.c_str(), sizeof(WM_config.WiFi_Creds[i].wifi_pw) - 1); | |
} | |
if (wifiCredentialsValid(i)) { | |
LOGERROR3(F("* Add SSID = "), WM_config.WiFi_Creds[i].wifi_ssid, F(", PW = "), WM_config.WiFi_Creds[i].wifi_pw ); | |
wifiMulti.addAP(WM_config.WiFi_Creds[i].wifi_ssid, WM_config.WiFi_Creds[i].wifi_pw); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment