diff --git a/README.md b/README.md
index 4af1c17..a055cee 100644
--- a/README.md
+++ b/README.md
@@ -182,6 +182,12 @@ void loop() {
```
See example for a more complex version. [OnDemandConfigPortal](https://github.com/tzapu/WiFiManager/tree/master/examples/OnDemandConfigPortal)
+#### Exiting from the Configuration Portal
+Normally, once entered, the configuration portal will continue to loop until WiFi credentials have been successfully entered or a timeout is reached.
+If you'd prefer to exit without joining a WiFi network, say becuase you're going to put the ESP into AP mode, then press the "Exit" button
+on the main webpage.
+If started via `autoConnect` or `startConfigPortal` then it will return `false (portalAbortResult)`
+
#### Custom Parameters
You can use WiFiManager to collect more parameters than just SSID and password.
This could be helpful for configuring stuff like MQTT host and port, [blynk](http://www.blynk.cc) or [emoncms](http://emoncms.org) tokens, just to name a few.
@@ -189,18 +195,18 @@ This could be helpful for configuring stuff like MQTT host and port, [blynk](htt
Usage scenario would be:
- load values from somewhere (EEPROM/FS) or generate some defaults
- add the custom parameters to WiFiManager using
- ```cpp
+```cpp
// id/name, placeholder/prompt, default, length
WiFiManagerParameter custom_mqtt_server("server", "mqtt server", mqtt_server, 40);
wifiManager.addParameter(&custom_mqtt_server);
- ```
+```
- if connection to AP fails, configuration portal starts and you can set /change the values (or use on demand configuration portal)
- once configuration is done and connection is established [save config callback]() is called
- once WiFiManager returns control to your application, read and save the new values using the `WiFiManagerParameter` object.
- ```cpp
+```cpp
mqtt_server = custom_mqtt_server.getValue();
- ```
+```
This feature is a lot more involved than all the others, so here are some examples to fully show how it is done.
You should also take a look at adding custom HTML to your form.
diff --git a/WiFiManager.cpp b/WiFiManager.cpp
index e2c1fb2..90fba72 100644
--- a/WiFiManager.cpp
+++ b/WiFiManager.cpp
@@ -11,6 +11,7 @@
**************************************************************/
#include "WiFiManager.h"
+#include "strings_en.h"
// PARAMETERS
@@ -51,6 +52,12 @@ void WiFiManagerParameter::init(const char *id, const char *placeholder, const c
_customHTML = custom;
}
+WiFiManagerParameter::~WiFiManagerParameter() {
+ if (_value != NULL) {
+ delete[] _value;
+ }
+}
+
const char* WiFiManagerParameter::getValue() {
return _value;
}
@@ -70,19 +77,35 @@ const char* WiFiManagerParameter::getCustomHTML() {
return _customHTML;
}
-void WiFiManager::addParameter(WiFiManagerParameter *p) {
- if(_paramsCount + 1 > WIFI_MANAGER_MAX_PARAMS)
- {
- //Max parameters exceeded!
- DEBUG_WM("WIFI_MANAGER_MAX_PARAMS exceeded, increase number (in WiFiManager.h) before adding more parameters!");
- DEBUG_WM("Skipping parameter with ID:");
- DEBUG_WM(p->getID());
- return;
+bool WiFiManager::addParameter(WiFiManagerParameter *p) {
+
+ // check param id is valid
+ for (int i = 0; i < strlen(p->getID()); i++){
+ if(!isAlphaNumeric(p->getID()[i])){
+ DEBUG_WM("[ERROR] parameter IDs can only contain alpha numeric chars");
+ return false;
+ }
+ }
+
+ if(_paramsCount == _max_params){
+ // resize the params array by increment of WIFI_MANAGER_MAX_PARAMS
+ _max_params += WIFI_MANAGER_MAX_PARAMS;
+ DEBUG_WM(F("Updated _max_params:"),_max_params);
+ WiFiManagerParameter** new_params = (WiFiManagerParameter**)realloc(_params, _max_params * sizeof(WiFiManagerParameter*));
+ DEBUG_WM(WIFI_MANAGER_MAX_PARAMS);
+ DEBUG_WM(_paramsCount);
+ DEBUG_WM(_max_params);
+ if (new_params != NULL) {
+ _params = new_params;
+ } else {
+ DEBUG_WM("[ERROR] failed to realloc params, size not increased!");
+ return false;
+ }
}
_params[_paramsCount] = p;
_paramsCount++;
- DEBUG_WM("Adding parameter");
- DEBUG_WM(p->getID());
+ DEBUG_WM("Added Parameter:",p->getID());
+ return true;
}
// constructors
@@ -94,12 +117,22 @@ WiFiManager::WiFiManager():_debugPort(Serial) {
if(_debug) debugPlatformInfo();
_usermode = WiFi.getMode();
WiFi.persistent(false); // disable persistent so scannetworks and mode switching do not cause overwrites
+
+ //parameters
+ _max_params = WIFI_MANAGER_MAX_PARAMS;
+ _params = (WiFiManagerParameter**)malloc(_max_params * sizeof(WiFiManagerParameter*));
}
// destructor
WiFiManager::~WiFiManager() {
if(_userpersistent) WiFi.persistent(true); // reenable persistent, there is no getter we rely on _userpersistent
if(_usermode != WIFI_OFF) WiFi.mode(_usermode);
+
+ // parameters
+ if (_params != NULL){
+ DEBUG_WM(F("freeing allocated params!"));
+ free(_params);
+ }
DEBUG_WM(F("unloading"));
}
@@ -110,7 +143,6 @@ boolean WiFiManager::autoConnect() {
}
boolean WiFiManager::autoConnect(char const *apName, char const *apPassword) {
- DEBUG_WM(F(""));
DEBUG_WM(F("AutoConnect"));
// attempt to connect using saved settings, on fail fallback to AP config portal
@@ -122,8 +154,7 @@ boolean WiFiManager::autoConnect(char const *apName, char const *apPassword) {
// if already connected, or try stored connect
if (WiFi.status() == WL_CONNECTED || connectWifi("", "") == WL_CONNECTED) {
//connected
- DEBUG_WM(F("IP Address:"));
- DEBUG_WM(WiFi.localIP());
+ DEBUG_WM(F("IP Address:"),WiFi.localIP());
return true;
}
// not connected start configportal
@@ -132,12 +163,11 @@ boolean WiFiManager::autoConnect(char const *apName, char const *apPassword) {
// CONFIG PORTAL
bool WiFiManager::startAP(){
- DEBUG_WM(F("Configuring access point with with SSID of ... "));
- DEBUG_WM(_apName);
+ DEBUG_WM(F("StartAP with SSID of"),_apName);
// setup optional soft AP static ip config
if (_ap_static_ip) {
- DEBUG_WM(F("Custom AP IP/GW/Subnet"));
+ DEBUG_WM(F("Custom AP IP/GW/Subnet:"));
WiFi.softAPConfig(_ap_static_ip, _ap_static_gw, _ap_static_sn);
}
@@ -145,7 +175,6 @@ bool WiFiManager::startAP(){
// start soft AP with password or anonymous
if (_apPassword != "") {
- Serial.println((String)_apPassword.c_str());
ret = WiFi.softAP(_apName.c_str(), _apPassword.c_str());//password option
} else {
DEBUG_WM(F("AP has anonymous access"));
@@ -154,11 +183,10 @@ bool WiFiManager::startAP(){
debugSoftAPConfig();
- if(!ret) DEBUG_WM("There was an error starting the AP"); // @bug startAP returns unreliable success status
+ if(!ret) DEBUG_WM("[ERROR] There was a problem starting the AP"); // @bug startAP returns unreliable success status
delay(500); // slight delay to make sure we get an AP IP
- DEBUG_WM(F("AP IP address: "));
- DEBUG_WM(WiFi.softAPIP());
+ DEBUG_WM(F("AP IP address:"),WiFi.softAPIP());
// do AP callback if set
if ( _apcallback != NULL) {
@@ -406,9 +434,8 @@ int WiFiManager::connectWifi(String ssid, String pass) {
// Setup static IP config if provided
if (_sta_static_ip) {
- DEBUG_WM(F("Custom STA IP/GW/Subnet"));
WiFi.config(_sta_static_ip, _sta_static_gw, _sta_static_sn);
- DEBUG_WM(WiFi.localIP());
+ DEBUG_WM(F("Custom STA IP/GW/Subnet:"),WiFi.localIP());
}
// make sure sta is on before `begin` so it does not call enablesta->mode while persistent is ON ( which would save WM AP state to eeprom !)
@@ -435,8 +462,7 @@ int WiFiManager::connectWifi(String ssid, String pass) {
}
uint8_t connRes = waitforconx ? waitForConnectResult() : WL_NO_SSID_AVAIL;
- DEBUG_WM ("Connection result: ");
- DEBUG_WM ( getWLStatusString(connRes) );
+ DEBUG_WM ("Connection result:",getWLStatusString(connRes));
// do WPS, if WPS options enabled and not connected and no password was supplied
// @todo this seems like wrong place for this, is it a fallback or option?
@@ -535,35 +561,36 @@ void WiFiManager::setBreakAfterConfig(boolean shouldBreak) {
_shouldBreakAfterConfig = shouldBreak;
}
+String WiFiManager::getHTTPHead(String title){
+ String page;
+ page += FPSTR(HTTP_HEAD);
+ page.replace("{v}", title);
+ page += FPSTR(HTTP_SCRIPT);
+ page += FPSTR(HTTP_STYLE);
+ page += _customHeadElement;
+ page += FPSTR(HTTP_HEAD_END);
+ return page;
+}
+
/**
* HTTPD CALLBACK root or redirect to captive portal
*/
void WiFiManager::handleRoot() {
DEBUG_WM(F("<- HTTP Root"));
- if (captivePortal()) { // If captive portal redirect instead of displaying the page.
- return;
- }
+ if (captivePortal()) return; // If captive portal redirect instead of displaying the page
- String page = FPSTR(HTTP_HEAD);
- page.replace("{v}", "Options");
- page += FPSTR(HTTP_SCRIPT);
- page += FPSTR(HTTP_STYLE);
- page += _customHeadElement;
- page += FPSTR(HTTP_HEAD_END);
- page += "