Skip to content

Instantly share code, notes, and snippets.

@marcelstoer
Created October 17, 2020 21:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marcelstoer/914ff2ac58a42a957dfa071c9c5c8acd to your computer and use it in GitHub Desktop.
Save marcelstoer/914ff2ac58a42a957dfa071c9c5c8acd to your computer and use it in GitHub Desktop.
ESP32 WiFi Manager based on ESPAsync_WiFiManager
/**************************************************************************************************/
/* */
/* 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