diff --git a/.travis.yml b/.travis.yml index 7cd4f58..e4d141e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ before_install: - if [[ "$BOARD" =~ "esp32:esp32:" ]]; then arduino --install-boards esp32:esp32; fi - - arduino --install-library PubSubClient,PageBuilder:1.1.0 + - arduino --install-library PubSubClient,PageBuilder:1.1.1 - buildExampleSketch() { arduino --verbose-build --verify --board $BOARD $PWD/examples/$1/$1.ino; } install: - mkdir -p ~/Arduino/libraries diff --git a/keywords.txt b/keywords.txt index 5f5c370..541bddb 100644 --- a/keywords.txt +++ b/keywords.txt @@ -4,6 +4,11 @@ AutoConnect KEYWORD1 AutoConnectConfig KEYWORD1 AutoConnectCredential KEYWORD1 +AutoConnectAux KEYWORD1 +AutoConnectText KEYWORD1 +AutoConnectInput KEYWORD1 +AutoConnectButon KEYWORD1 +AutoConnectSubmit KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) @@ -17,6 +22,7 @@ handleClient KEYWORD2 handleRequest KEYWORD2 home KEYWORD2 host KEYWORD2 +join KEYWORD2 load KEYWORD2 onDetect KEYWORD2 onNotFound KEYWORD2 diff --git a/library.json b/library.json index 3bead03..9d5cfbb 100644 --- a/library.json +++ b/library.json @@ -21,6 +21,6 @@ "espressif8266", "espressif32" ], - "version": "0.9.6", + "version": "0.9.7", "license": "MIT" } diff --git a/library.properties b/library.properties index 6f42c98..b054290 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=AutoConnect -version=0.9.6 +version=0.9.7 author=Hieromon Ikasamo maintainer=Hieromon Ikasamo sentence=ESP8266/ESP32 WLAN configuration at runtime with web interface. diff --git a/src/AutoConnect.cpp b/src/AutoConnect.cpp index dc882eb..5c46d14 100644 --- a/src/AutoConnect.cpp +++ b/src/AutoConnect.cpp @@ -2,8 +2,8 @@ * AutoConnect class implementation. * @file AutoConnect.cpp * @author hieromon@gmail.com - * @version 0.9.6 - * @date 2018-09-27 + * @version 0.9.7 + * @date 2018-11-17 * @copyright MIT license. */ @@ -51,6 +51,7 @@ void AutoConnect::_initialize() { _menuTitle = String(AUTOCONNECT_MENU_TITLE); _portalTimeout = AUTOCONNECT_TIMEOUT; memset(&_credential, 0x00, sizeof(struct station_config)); + _aux.release(); } /** @@ -257,6 +258,34 @@ WebServerClass& AutoConnect::host() { return *_webServer; } +/** + * Append auxiliary pages made up with AutoConnectAux. + * @param aux A reference to AutoConnectAux that made up + * the auxiliary page to be added. + */ +void AutoConnect::join(AutoConnectAux& aux) { + if (_aux) { + AutoConnectAux* addon = _aux.get(); + addon->_append(aux); + } + else + _aux.reset(&aux); + aux._join(*this); + AC_DBG("%s contained\n", aux._uri); +} + +/** +* Append auxiliary pages made up with AutoConnectAux. +* @param aux A vector of reference to AutoConnectAux that made up +* the auxiliary page to be added. +*/ +void AutoConnect::join(std::vector> aux) { + for (std::size_t n = 0; n < aux.size(); n++) { + AutoConnectAux& addon = aux[n + 1].get(); + join(addon); + } +} + /** * Starts Web server for AutoConnect service. */ @@ -360,9 +389,9 @@ void AutoConnect::handleRequest() { _stopPortal(); _disconnectWiFi(true); AC_DBG("Disconnected\n"); - // Reset disconnection request, restore the menu title. + // Reset disconnection request //, restore the menu title. _rfDisconnect = false; - _menuTitle = String(AUTOCONNECT_MENU_TITLE); +// _menuTitle = String(AUTOCONNECT_MENU_TITLE); if (_apConfig.autoReset) { delay(1000); @@ -485,7 +514,6 @@ String AutoConnect::_induceReset(PageArgument& args) { */ String AutoConnect::_induceDisconnect(PageArgument& args) { _rfDisconnect = true; - _menuTitle = String("Disconnect"); return ""; } @@ -552,7 +580,7 @@ String AutoConnect::_invokeResult(PageArgument& args) { * a part of the handling of http request originated from handleClient. */ bool AutoConnect::_classifyHandle(HTTPMethod method, String uri) { - AC_DBG("%s%s\n", _webServer->hostHeader().c_str(), uri.c_str()); + AC_DBG("Host:%s, URI:%s\n", _webServer->hostHeader().c_str(), uri.c_str()); if (uri == _uri) { return true; // The response page already exists. } @@ -567,6 +595,12 @@ bool AutoConnect::_classifyHandle(HTTPMethod method, String uri) { if ((_currentPageElement = _setupPage(uri)) != nullptr) { _uri = String(uri); _responsePage->addElement(*_currentPageElement); + } else if (_aux) { + // Requested URL is not a normal page, exploring AUX pages + if ((_currentPageElement = _aux->_setupPage(uri)) != nullptr) { + _uri = String(uri); + _responsePage->addElement(*_currentPageElement); + } } _responsePage->setUri(_uri.c_str()); AC_DBG("Page[%s] allocated\n", _responsePage->uri()); diff --git a/src/AutoConnect.h b/src/AutoConnect.h index 909027e..1ba4b9f 100644 --- a/src/AutoConnect.h +++ b/src/AutoConnect.h @@ -2,8 +2,8 @@ * Declaration of AutoConnect class and accompanying AutoConnectConfig class. * @file AutoConnect.h * @author hieromon@gmail.com - * @version 0.9.5 - * @date 2018-08-27 + * @version 0.9.7 + * @date 2018-11-17 * @copyright MIT license. */ @@ -30,6 +30,7 @@ using WebServerClass = WebServer; #include #include "AutoConnectPage.h" #include "AutoConnectCredential.h" +#include "AutoConnectAux.h" // Uncomment the following AC_DEBUG to enable debug output. #define AC_DEBUG @@ -186,27 +187,29 @@ class AutoConnectConfig { return *this; } - IPAddress apip; /**< SoftAP IP address */ - IPAddress gateway; /**< SoftAP gateway address */ - IPAddress netmask; /**< SoftAP subnet mask */ - String apid; /**< SoftAP SSID */ - String psk; /**< SoftAP password */ - uint8_t channel; /**< SoftAP used wifi channel */ - uint8_t hidden; /**< SoftAP SSID hidden */ + IPAddress apip; /**< SoftAP IP address */ + IPAddress gateway; /**< SoftAP gateway address */ + IPAddress netmask; /**< SoftAP subnet mask */ + String apid; /**< SoftAP SSID */ + String psk; /**< SoftAP password */ + uint8_t channel; /**< SoftAP used wifi channel */ + uint8_t hidden; /**< SoftAP SSID hidden */ AC_SAVECREDENTIAL_t autoSave; /**< Auto save credential */ - uint16_t boundaryOffset; /**< The save storage offset of EEPROM */ - int uptime; /**< Length of start up time */ - bool autoRise; /**< Automatic starting the captive portal */ - bool autoReset; /**< Reset ESP8266 module automatically when WLAN disconnected. */ - bool autoReconnect; /**< Automatic reconnect with past SSID */ - String homeUri; /**< A URI of user site */ - IPAddress staip; /**< Station static IP address */ - IPAddress staGateway; /**< Station gateway address */ - IPAddress staNetmask; /**< Station subnet mask */ - IPAddress dns1; /**< Primary DNS server */ - IPAddress dns2; /**< Secondary DNS server */ + uint16_t boundaryOffset; /**< The save storage offset of EEPROM */ + int uptime; /**< Length of start up time */ + bool autoRise; /**< Automatic starting the captive portal */ + bool autoReset; /**< Reset ESP8266 module automatically when WLAN disconnected. */ + bool autoReconnect; /**< Automatic reconnect with past SSID */ + String homeUri; /**< A URI of user site */ + IPAddress staip; /**< Station static IP address */ + IPAddress staGateway; /**< Station gateway address */ + IPAddress staNetmask; /**< Station subnet mask */ + IPAddress dns1; /**< Primary DNS server */ + IPAddress dns2; /**< Secondary DNS server */ }; +class AutoConnectAux; + class AutoConnect { public: AutoConnect(); @@ -221,6 +224,8 @@ class AutoConnect { void handleClient(); void handleRequest(); WebServerClass& host(); + void join(AutoConnectAux& aux); + void join(std::vector> aux); typedef std::function DetectExit_ft; void onDetect(DetectExit_ft fn); @@ -262,28 +267,38 @@ class AutoConnect { DetectExit_ft _onDetectExit; WebServerClass::THandlerFunction _notFoundHandler; + /** Servers which works in concert. */ std::unique_ptr _webServer; - std::unique_ptr _dnsServer; - AC_WEBSERVER_TYPE _webServerAlloc; + std::unique_ptr _dnsServer; + AC_WEBSERVER_TYPE _webServerAlloc; + /** + * Dynamically hold one page of AutoConnect menu. + * Every time a GET/POST HTTP request occurs, an AutoConnect + * menu page corresponding to the URI is generated. + */ PageBuilder* _responsePage; PageElement* _currentPageElement; + + /** Extended pages made up with AutoConnectAux */ + std::unique_ptr _aux; - /** configurations */ + /** Saved configurations */ AutoConnectConfig _apConfig; struct station_config _credential; uint8_t _hiddenSSIDCount; unsigned long _portalTimeout; /** The control indicators */ - bool _rfConnect; /**< URI /connect requested */ - bool _rfDisconnect; /**< URI /disc requested */ - bool _rfReset; /**< URI /reset requested */ + bool _rfConnect; /**< URI /connect requested */ + bool _rfDisconnect; /**< URI /disc requested */ + bool _rfReset; /**< URI /reset requested */ - String _uri; - String _redirectURI; - IPAddress _currentHostIP; - String _menuTitle; + /** HTTP header information of the currently requested page. */ + String _uri; /**< Requested URI */ + String _redirectURI; /**< Redirect destination */ + IPAddress _currentHostIP; /**< host IP address */ + String _menuTitle; /**< Title string of the page */ /** PegeElements of AutoConnect site. */ static const char _CSS_BASE[] PROGMEM; @@ -294,7 +309,9 @@ class AutoConnect { static const char _CSS_TABLE[] PROGMEM; static const char _CSS_LUXBAR[] PROGMEM; static const char _ELM_HTML_HEAD[] PROGMEM; - static const char _ELM_MENU[] PROGMEM; + static const char _ELM_MENU_PRE[] PROGMEM; + static const char _ELM_MENU_AUX[] PROGMEM; + static const char _ELM_MENU_POST[] PROGMEM; static const char _PAGE_STAT[] PROGMEM; static const char _PAGE_CONFIGNEW[] PROGMEM; static const char _PAGE_OPENCREDT[] PROGMEM; @@ -313,7 +330,9 @@ class AutoConnect { String _token_CSS_TABLE(PageArgument& args); String _token_CSS_LUXBAR(PageArgument& args); String _token_HEAD(PageArgument& args); - String _token_MENU(PageArgument& args); + String _token_MENU_PRE(PageArgument& args); + String _token_MENU_AUX(PageArgument& args); + String _token_MENU_POST(PageArgument& args); String _token_ESTAB_SSID(PageArgument& args); String _token_WIFI_MODE(PageArgument& args); String _token_WIFI_STATUS(PageArgument& args); @@ -340,6 +359,7 @@ class AutoConnect { #elif defined(ARDUINO_ARCH_ESP32) friend class WebServer; #endif + friend class AutoConnectAux; }; #endif // _AUTOCONNECT_H_ diff --git a/src/AutoConnectAux.cpp b/src/AutoConnectAux.cpp new file mode 100644 index 0000000..857a35a --- /dev/null +++ b/src/AutoConnectAux.cpp @@ -0,0 +1,135 @@ +/** + * Implementation of AutoConnectAux class and subordinated AutoConnectElement class. + * @file AutoConnectAux.cpp + * @author hieromon@gmail.com + * @version 0.9.7 + * @date 2018-11-17 + * @copyright MIT license. + */ + +#include "AutoConnect.h" +#include "AutoConnectAux.h" + +const char AutoConnectAux::_PAGE_AUX[] PROGMEM = { + "{{HEAD}}" + "{{AUX_TITLE}}" + "" + "" + "" + "
" + "{{MENU_PRE}}" + "{{MENU_AUX}}" + "{{MENU_POST}}" + "
" + "
" + "
    " + "{{AUX_ELEMENT}}" + "
" + "
" + "
" + "
" + "" + "" + "" +}; + +/** + * Destructs container of AutoConnectElement and release a unique + * pointer of AutoConnect instance. + */ +AutoConnectAux::~AutoConnectAux() { + _addonElm.clear(); + _addonElm.swap(_addonElm); + if (_ac) + _ac.release(); +} + +void AutoConnectAux::add(AutoConnectElement& addon) { + _addonElm.push_back(addon); + AC_DBG("ELM:%s placed\n", addon.name().c_str()); +} + +void AutoConnectAux::add(AutoConnectElementVT addons) { + for (std::size_t n = 0; n < addons.size(); n++) + add(addons[n]); +} + +void AutoConnectAux::_append(AutoConnectAux& aux) { + if (_next) { + AutoConnectAux* next = _next.get(); + next->_append(aux); + } + else + _next.reset(&aux); +} + +void AutoConnectAux::_join(AutoConnect& ac) { + _ac.reset(&ac); + if (_next) { + AutoConnectAux *next = _next.get(); + next->_join(ac); + } +} + +const String AutoConnectAux::_insertElement(PageArgument& args) { + String body = String(); + + for (std::size_t n = 0; n < _addonElm.size(); n++) { + AutoConnectElement& addon = _addonElm[n]; + body += addon.toHTML(); + } + return body; +} + +PageElement* AutoConnectAux::_setupPage(String uri) { + PageElement* elm = nullptr; + + if (_ac) { + if (uri != String(_uri)) { + if (_next) { + elm = _next->_setupPage(uri); + } + } else { + AutoConnect* mother = _ac.get(); + elm = new PageElement(); + + // Overwrite the default menu title + mother->_menuTitle = _title; + + // Construct the auxiliary page + elm->setMold(_PAGE_AUX); + elm->addToken(PSTR("HEAD"), std::bind(&AutoConnect::_token_HEAD, mother, std::placeholders::_1)); + elm->addToken(PSTR("AUX_TITLE"), std::bind(&AutoConnectAux::_injectTitle, this, std::placeholders::_1)); + elm->addToken(PSTR("CSS_BASE"), std::bind(&AutoConnect::_token_CSS_BASE, mother, std::placeholders::_1)); + elm->addToken(PSTR("CSS_UL"), std::bind(&AutoConnect::_token_CSS_UL, mother, std::placeholders::_1)); + elm->addToken(PSTR("CSS_INPUT_BUTTON"), std::bind(&AutoConnect::_token_CSS_INPUT_BUTTON, mother, std::placeholders::_1)); + elm->addToken(PSTR("CSS_INPUT_TEXT"), std::bind(&AutoConnect::_token_CSS_INPUT_TEXT, mother, std::placeholders::_1)); + elm->addToken(PSTR("CSS_LUXBAR"), std::bind(&AutoConnect::_token_CSS_LUXBAR, mother, std::placeholders::_1)); + elm->addToken(PSTR("MENU_PRE"), std::bind(&AutoConnect::_token_MENU_PRE, mother, std::placeholders::_1)); + elm->addToken(PSTR("MENU_AUX"), std::bind(&AutoConnect::_token_MENU_AUX, mother, std::placeholders::_1)); + elm->addToken(PSTR("MENU_POST"), std::bind(&AutoConnect::_token_MENU_POST, mother, std::placeholders::_1)); + elm->addToken(PSTR("AUX_ELEMENT"), std::bind(&AutoConnectAux::_insertElement, this, std::placeholders::_1)); + } + } + return elm; +} + +const String AutoConnectAux::_injectMenu(PageArgument& args) { + String menuItem = String(FPSTR("
  • ") + _title + String(FPSTR("
  • ")); + if (_next) { + AutoConnectAux* next = _next.get(); + menuItem += next->_injectMenu(args); + } + return menuItem; +} diff --git a/src/AutoConnectAux.h b/src/AutoConnectAux.h new file mode 100644 index 0000000..df2a746 --- /dev/null +++ b/src/AutoConnectAux.h @@ -0,0 +1,156 @@ +/** + * Declaration of AutoConnectAux class and subordinated AutoConnectElement class. + * @file AutoConnectAux.h + * @author hieromon@gmail.com + * @version 0.9.7 + * @date 2018-11-17 + * @copyright MIT license. + */ + +#ifndef _AUTOCONNECTAUX_H_ +#define _AUTOCONNECTAUX_H_ + +#include +#include +#include +#include + +class AutoConnect; // Reference to avoid circular + +// Add-on element base class +class AutoConnectElement { + public: + explicit AutoConnectElement(const char* name = nullptr, const char* value = nullptr) : _name(String(name)), _value(String(value)) {} + virtual ~AutoConnectElement() {} + const String name(void) const { return _name; } /**< Element name */ + const String value(void) const { return _value; } /**< Element value */ + virtual const String toHTML(void) { return String(); }; /**< HTML code to be generated */ + + protected: + String _name; + String _value; +}; + +/** + * Text arrangement class, a part of AutoConnectAux element. + * @param + * @param name Text name string. + * @param value Text value string. + * @param style A string of style-code for decoration, optionally. + * An arrangement text would be placed with
    contains. A string + * of style-codes are given for '
    '. + */ +class AutoConnectText : public AutoConnectElement { + public: + explicit AutoConnectText(const char* name = nullptr, const char* value = nullptr, const char* style = nullptr) : AutoConnectElement(name, value), _style(String(style)) {} + ~AutoConnectText() {} + const String style(void) const { return _style; } /**< A modify of HTML 'style' code */ + const String toHTML(void) { + return String(FPSTR("
    ") + _value + String(FPSTR("
    ")); + } + + protected: + String _style; +}; + +/** + * Input-box arrangement class, a part of AutoConnectAux element. + * Place a optionally labeled input-box that can be added by user sketch. + * @param name Input-box name string. + * @param value Button value string. + * @param label A label string that follows Input-box, optionally. + * The label is placed in front of Input-box. + */ +class AutoConnectInput : public AutoConnectElement { + public: + explicit AutoConnectInput(const char* name = nullptr, const char* value = nullptr, const char* label = nullptr) : AutoConnectElement(name, value), _label(String(label)) {} + ~AutoConnectInput() {} + const String label(void) const { return _label; } + const String toHTML(void) { + return _label + String(FPSTR("
    "); + } + + protected: + String _label; +}; + +/** + * Button arrangement class, a part of AutoConnectAux element. + * Placed a labeled button that can be added by user sketch. + * @param name Button name string. + * @param value Button value string. + * @param action A sting of action code, it contains a simple JavaScript code. + */ +class AutoConnectButton : public AutoConnectElement { + public: + explicit AutoConnectButton(const char* name = nullptr, const char* value = nullptr, const String action = String()) : AutoConnectElement(name, value), _action(action) {} + const String action(void) const { return _action; } + const String toHTML(void) { + return String(FPSTR("")); + } + + protected: + String _action; +}; + +/** + * Submit button arrangement class, a part of AutoConnectAux element. + * Place a submit button with a label that can be added by user sketch. + * With the button behavior, the values of the elements contained in + * the form would be sent using the post method. + * @param name Button name string. + * @param value Sending value string. + * @param uri Sending uri string. + */ +class AutoConnectSubmit : public AutoConnectElement { + public: + explicit AutoConnectSubmit(const char* name = nullptr, const char* value = nullptr, const char* uri = nullptr) : AutoConnectElement(name, value), _uri(String(uri)) {} + const String uri(void) const { return _uri; } + const String toHTML(void) { + return String(FPSTR("")); + } + + protected: + String _uri; +}; + +// Manage placed AutoConnectElement with a vector +typedef std::vector> AutoConnectElementVT; + +/** + * A class that handles an auxiliary page with AutoConnectElement + * that placed on it by binding it to the AutoConnect menu. + * @param uri An uri string of this page. + * @param title A title string of this page. + * @param addons A set of AutoConnectElement vector. + */ +class AutoConnectAux : public PageBuilder { + public: + explicit AutoConnectAux(const char* uri = nullptr, const char* title = nullptr, const AutoConnectElementVT addons = AutoConnectElementVT()) : + _title(String(title)), _addonElm(addons) { setUri(uri); _next.release(); _ac.release(); } + ~AutoConnectAux(); + void add(AutoConnectElement& addon); /**< Add an element to the auxiliary page. */ + void add(AutoConnectElementVT addons); /**< Add the element set to the auxiliary page. */ + void setTitle(const char* title) { _title = String(title); } /**< Set a title of the auxiliary page. */ + + protected: + void _append(AutoConnectAux& aux); + void _join(AutoConnect& ac); + PageElement* _setupPage(String uri); + const String _insertElement(PageArgument& args); + const String _injectTitle(PageArgument& args) { return _title; } + const String _injectMenu(PageArgument& args); + + String _title; /**< A title of the page */ + + AutoConnectElementVT _addonElm; /**< A vector set of AutoConnectElements placed on this auxiliary page */ + std::unique_ptr _next; /**< Auxiliary pages chain list */ + std::unique_ptr _ac; /**< Hosted AutoConnect instance */ + + static const char _PAGE_AUX[] PROGMEM; /**< Auxiliary page template */ + + // Protected members can be used from AutoConnect which handles AutoConnectAux pages. + friend class AutoConnect; +}; + +#endif // _AUTOCONNECTAUX_H_ \ No newline at end of file diff --git a/src/AutoConnectPage.cpp b/src/AutoConnectPage.cpp index 4e3426e..aeb7085 100644 --- a/src/AutoConnectPage.cpp +++ b/src/AutoConnectPage.cpp @@ -2,8 +2,8 @@ * AutoConnect portal site web page implementation. * @file AutoConnectPage.h * @author hieromon@gmail.com - * @version 0.9.6 - * @date 2018-09-27 + * @version 0.9.7 + * @date 2018-11-17 * @copyright MIT license. */ @@ -104,6 +104,10 @@ const char AutoConnect::_CSS_UL[] PROGMEM = { "margin-right:10px;" "text-align:right;" "}" + "ul.noorder>input[type=\"checkbox\"]{" + "-moz-appearance: checkbox;" + "-webkit-appearance: checkbox;" + "}" }; /**< Image icon for inline expansion, the lock mark. */ @@ -448,7 +452,7 @@ const char AutoConnect::_ELM_HTML_HEAD[] PROGMEM = { }; /**< LuxBar menu element. */ -const char AutoConnect::_ELM_MENU[] PROGMEM = { +const char AutoConnect::_ELM_MENU_PRE[] PROGMEM = { "
    " "" "
    " @@ -459,6 +463,13 @@ const char AutoConnect::_ELM_MENU[] PROGMEM = { "" "
  • Configure new AP
  • " "
  • Open SSIDs
  • " +}; + +const char AutoConnect::_ELM_MENU_AUX[] PROGMEM = { + "{{AUX_MENU}}" +}; + +const char AutoConnect::_ELM_MENU_POST[] PROGMEM = { "
  • Disconnect
  • " "
  • Reset...
  • " "
  • HOME
  • " @@ -505,7 +516,9 @@ const char AutoConnect::_PAGE_STAT[] PROGMEM = { "" "" "
    " - "{{MENU}}" + "{{MENU_PRE}}" + "{{MENU_AUX}}" + "{{MENU_POST}}" "
    " "" "" @@ -588,7 +601,9 @@ const char AutoConnect::_PAGE_CONFIGNEW[] PROGMEM = { "" "" "
    " - "{{MENU}}" + "{{MENU_PRE}}" + "{{MENU_AUX}}" + "{{MENU_POST}}" "
    " "
    " "{{LIST_SSID}}" @@ -624,7 +639,9 @@ const char AutoConnect::_PAGE_OPENCREDT[] PROGMEM = { "" "" "
    " - "{{MENU}}" + "{{MENU_PRE}}" + "{{MENU_AUX}}" + "{{MENU_POST}}" "
    " "" "{{OPEN_SSID}}" @@ -647,7 +664,9 @@ const char AutoConnect::_PAGE_SUCCESS[] PROGMEM = { "" "" "
    " - "{{MENU}}" + "{{MENU_PRE}}" + "{{MENU_AUX}}" + "{{MENU_POST}}" "
    " "
    " "" @@ -697,7 +716,9 @@ const char AutoConnect::_PAGE_FAIL[] PROGMEM = { "" "" "
    " - "{{MENU}}" + "{{MENU_PRE}}" + "{{MENU_AUX}}" + "{{MENU_POST}}" "
    " "
    " "" @@ -775,13 +796,26 @@ String AutoConnect::_token_HEAD(PageArgument& args) { return String(_ELM_HTML_HEAD); } -String AutoConnect::_token_MENU(PageArgument& args) { - String currentMenu = String(_ELM_MENU); +String AutoConnect::_token_MENU_PRE(PageArgument& args) { + String currentMenu = String(_ELM_MENU_PRE); currentMenu.replace(String("MENU_TITLE"), _menuTitle); currentMenu.replace(String("HOME_URI"), _apConfig.homeUri); return currentMenu; } +String AutoConnect::_token_MENU_AUX(PageArgument& args) { + String menuItem; + if (_aux) { + AutoConnectAux* aux = _aux.get(); + menuItem = aux->_injectMenu(args); + } + return menuItem; +} + +String AutoConnect::_token_MENU_POST(PageArgument& args) { + return String(FPSTR(_ELM_MENU_POST)); +} + String AutoConnect::_token_CSS_LUXBAR(PageArgument& args) { return String(_CSS_LUXBAR); } @@ -819,11 +853,9 @@ String AutoConnect::_token_WIFI_STATUS(PageArgument& args) { } String AutoConnect::_token_STATION_STATUS(PageArgument& args) { - uint8_t st; const char* wlStatusSymbol; - -#if defined(ARDUINO_ARCH_ESP8266) static const char *wlStatusSymbols[] = { +#if defined(ARDUINO_ARCH_ESP8266) "IDLE", "CONNECTING", "WRONG_PASSWORD", @@ -831,7 +863,7 @@ String AutoConnect::_token_STATION_STATUS(PageArgument& args) { "CONNECT_FAIL", "GOT_IP" }; - st = wifi_station_get_connect_status(); + uint8_t st = wifi_station_get_connect_status(); switch (st) { case STATION_IDLE: wlStatusSymbol = wlStatusSymbols[0]; @@ -851,19 +883,17 @@ String AutoConnect::_token_STATION_STATUS(PageArgument& args) { case STATION_GOT_IP: wlStatusSymbol = wlStatusSymbols[5]; break; - } - #elif defined(ARDUINO_ARCH_ESP32) - static const char *wlStatusSymbols[] = { "IDLE", "NO_SSID_AVAIL", "SCAN_COMPLETED", "CONNECTED", "CONNECT_FAILED", "CONNECTION_LOST", - "DISCONNECTED" + "DISCONNECTED", + "NO_SHIELD" }; - st = WiFi.status(); + wl_status_t st = WiFi.status(); switch (st) { case WL_IDLE_STATUS: wlStatusSymbol = wlStatusSymbols[0]; @@ -886,9 +916,10 @@ String AutoConnect::_token_STATION_STATUS(PageArgument& args) { case WL_DISCONNECTED: wlStatusSymbol = wlStatusSymbols[6]; break; - } + default: + wlStatusSymbol = wlStatusSymbols[7]; #endif - + } return "(" + String(st) + ") " + String(wlStatusSymbol); } @@ -1016,6 +1047,9 @@ String AutoConnect::_token_UPTIME(PageArgument& args) { PageElement* AutoConnect::_setupPage(String uri) { PageElement *elm = new PageElement(); + // Restore menu title + _menuTitle = String(AUTOCONNECT_MENU_TITLE); + // Build the elements of current requested page. if (uri == String(AUTOCONNECT_URI)) { @@ -1025,7 +1059,9 @@ PageElement* AutoConnect::_setupPage(String uri) { elm->addToken(PSTR("CSS_BASE"), std::bind(&AutoConnect::_token_CSS_BASE, this, std::placeholders::_1)); elm->addToken(PSTR("CSS_TABLE"), std::bind(&AutoConnect::_token_CSS_TABLE, this, std::placeholders::_1)); elm->addToken(PSTR("CSS_LUXBAR"), std::bind(&AutoConnect::_token_CSS_LUXBAR, this, std::placeholders::_1)); - elm->addToken(PSTR("MENU"), std::bind(&AutoConnect::_token_MENU, this, std::placeholders::_1)); + elm->addToken(PSTR("MENU_PRE"), std::bind(&AutoConnect::_token_MENU_PRE, this, std::placeholders::_1)); + elm->addToken(PSTR("MENU_AUX"), std::bind(&AutoConnect::_token_MENU_AUX, this, std::placeholders::_1)); + elm->addToken(PSTR("MENU_POST"), std::bind(&AutoConnect::_token_MENU_POST, this, std::placeholders::_1)); elm->addToken(PSTR("ESTAB_SSID"), std::bind(&AutoConnect::_token_ESTAB_SSID, this, std::placeholders::_1)); elm->addToken(PSTR("WIFI_MODE"), std::bind(&AutoConnect::_token_WIFI_MODE, this, std::placeholders::_1)); elm->addToken(PSTR("WIFI_STATUS"), std::bind(&AutoConnect::_token_WIFI_STATUS, this, std::placeholders::_1)); @@ -1053,7 +1089,9 @@ PageElement* AutoConnect::_setupPage(String uri) { elm->addToken(PSTR("CSS_INPUT_BUTTON"), std::bind(&AutoConnect::_token_CSS_INPUT_BUTTON, this, std::placeholders::_1)); elm->addToken(PSTR("CSS_INPUT_TEXT"), std::bind(&AutoConnect::_token_CSS_INPUT_TEXT, this, std::placeholders::_1)); elm->addToken(PSTR("CSS_LUXBAR"), std::bind(&AutoConnect::_token_CSS_LUXBAR, this, std::placeholders::_1)); - elm->addToken(PSTR("MENU"), std::bind(&AutoConnect::_token_MENU, this, std::placeholders::_1)); + elm->addToken(PSTR("MENU_PRE"), std::bind(&AutoConnect::_token_MENU_PRE, this, std::placeholders::_1)); + elm->addToken(PSTR("MENU_AUX"), std::bind(&AutoConnect::_token_MENU_AUX, this, std::placeholders::_1)); + elm->addToken(PSTR("MENU_POST"), std::bind(&AutoConnect::_token_MENU_POST, this, std::placeholders::_1)); elm->addToken(PSTR("LIST_SSID"), std::bind(&AutoConnect::_token_LIST_SSID, this, std::placeholders::_1)); elm->addToken(PSTR("HIDDEN_COUNT"), std::bind(&AutoConnect::_token_HIDDEN_COUNT, this, std::placeholders::_1)); } @@ -1072,18 +1110,23 @@ PageElement* AutoConnect::_setupPage(String uri) { elm->addToken(PSTR("CSS_ICON_LOCK"), std::bind(&AutoConnect::_token_CSS_ICON_LOCK, this, std::placeholders::_1)); elm->addToken(PSTR("CSS_INPUT_BUTTON"), std::bind(&AutoConnect::_token_CSS_INPUT_BUTTON, this, std::placeholders::_1)); elm->addToken(PSTR("CSS_LUXBAR"), std::bind(&AutoConnect::_token_CSS_LUXBAR, this, std::placeholders::_1)); - elm->addToken(PSTR("MENU"), std::bind(&AutoConnect::_token_MENU, this, std::placeholders::_1)); + elm->addToken(PSTR("MENU_PRE"), std::bind(&AutoConnect::_token_MENU_PRE, this, std::placeholders::_1)); + elm->addToken(PSTR("MENU_AUX"), std::bind(&AutoConnect::_token_MENU_AUX, this, std::placeholders::_1)); + elm->addToken(PSTR("MENU_POST"), std::bind(&AutoConnect::_token_MENU_POST, this, std::placeholders::_1)); elm->addToken(PSTR("OPEN_SSID"), std::bind(&AutoConnect::_token_OPEN_SSID, this, std::placeholders::_1)); } else if (uri == String(AUTOCONNECT_URI_DISCON)) { // Setup /auto/disc + _menuTitle = String("Disconnect"); elm->setMold(_PAGE_DISCONN); elm->addToken(PSTR("DISCONNECT"), std::bind(&AutoConnect::_induceDisconnect, this, std::placeholders::_1)); elm->addToken(PSTR("HEAD"), std::bind(&AutoConnect::_token_HEAD, this, std::placeholders::_1)); elm->addToken(PSTR("CSS_BASE"), std::bind(&AutoConnect::_token_CSS_BASE, this, std::placeholders::_1)); elm->addToken(PSTR("CSS_LUXBAR"), std::bind(&AutoConnect::_token_CSS_LUXBAR, this, std::placeholders::_1)); - elm->addToken(PSTR("MENU"), std::bind(&AutoConnect::_token_MENU, this, std::placeholders::_1)); + elm->addToken(PSTR("MENU_PRE"), std::bind(&AutoConnect::_token_MENU_PRE, this, std::placeholders::_1)); + elm->addToken(PSTR("MENU_AUX"), std::bind(&AutoConnect::_token_MENU_AUX, this, std::placeholders::_1)); + elm->addToken(PSTR("MENU_POST"), std::bind(&AutoConnect::_token_MENU_POST, this, std::placeholders::_1)); } else if (uri == String(AUTOCONNECT_URI_RESET)) { @@ -1108,7 +1151,9 @@ PageElement* AutoConnect::_setupPage(String uri) { elm->addToken(PSTR("CSS_BASE"), std::bind(&AutoConnect::_token_CSS_BASE, this, std::placeholders::_1)); elm->addToken(PSTR("CSS_TABLE"), std::bind(&AutoConnect::_token_CSS_TABLE, this, std::placeholders::_1)); elm->addToken(PSTR("CSS_LUXBAR"), std::bind(&AutoConnect::_token_CSS_LUXBAR, this, std::placeholders::_1)); - elm->addToken(PSTR("MENU"), std::bind(&AutoConnect::_token_MENU, this, std::placeholders::_1)); + elm->addToken(PSTR("MENU_PRE"), std::bind(&AutoConnect::_token_MENU_PRE, this, std::placeholders::_1)); + elm->addToken(PSTR("MENU_AUX"), std::bind(&AutoConnect::_token_MENU_AUX, this, std::placeholders::_1)); + elm->addToken(PSTR("MENU_POST"), std::bind(&AutoConnect::_token_MENU_POST, this, std::placeholders::_1)); elm->addToken(PSTR("ESTAB_SSID"), std::bind(&AutoConnect::_token_ESTAB_SSID, this, std::placeholders::_1)); elm->addToken(PSTR("WIFI_MODE"), std::bind(&AutoConnect::_token_WIFI_MODE, this, std::placeholders::_1)); elm->addToken(PSTR("WIFI_STATUS"), std::bind(&AutoConnect::_token_WIFI_STATUS, this, std::placeholders::_1)); @@ -1126,7 +1171,9 @@ PageElement* AutoConnect::_setupPage(String uri) { elm->addToken(PSTR("CSS_BASE"), std::bind(&AutoConnect::_token_CSS_BASE, this, std::placeholders::_1)); elm->addToken(PSTR("CSS_TABLE"), std::bind(&AutoConnect::_token_CSS_TABLE, this, std::placeholders::_1)); elm->addToken(PSTR("CSS_LUXBAR"), std::bind(&AutoConnect::_token_CSS_LUXBAR, this, std::placeholders::_1)); - elm->addToken(PSTR("MENU"), std::bind(&AutoConnect::_token_MENU, this, std::placeholders::_1)); + elm->addToken(PSTR("MENU_PRE"), std::bind(&AutoConnect::_token_MENU_PRE, this, std::placeholders::_1)); + elm->addToken(PSTR("MENU_AUX"), std::bind(&AutoConnect::_token_MENU_AUX, this, std::placeholders::_1)); + elm->addToken(PSTR("MENU_POST"), std::bind(&AutoConnect::_token_MENU_POST, this, std::placeholders::_1)); elm->addToken(PSTR("STATION_STATUS"), std::bind(&AutoConnect::_token_STATION_STATUS, this, std::placeholders::_1)); } else {