diff --git a/.gitignore b/.gitignore index 72ed49c..73c54ec 100644 --- a/.gitignore +++ b/.gitignore @@ -9,5 +9,4 @@ img/ *.sln *.vcxproj *.vcxproj.filters -.pioenvs -.piolibdeps +*.vcxitems diff --git a/README.md b/README.md index 94cc84f..ca4ab49 100644 --- a/README.md +++ b/README.md @@ -91,8 +91,10 @@ Full documentation is available on https://Hieromon.github.io/AutoConnect, some ### [0.9.7] Dec. 11, 2018 - Supports AutoConnect menu extention by user sketch with **AutoConnectAux** implementation that attached **AutoConnectElement**. +- Improved the WiFi connection sequence at the first WiFi.begin. Even if **AutoConnectConfig::autoReconnect** is disabled when SSID and PSK are not specified, it will use the information of the last established access point. The autoReconnect option will achieve trying the connect after a previous connection failed. - Supports loading and saving of user-defined parameters with JSON format. -- Supports AutoConnectConfig::immediateStart option, to start the portal immediately without first trying WiFi.begin. +- Supports **AutoConnectConfig::immediateStart** option, to start the portal immediately without first trying WiFi.begin. +- Improved boot uri after reset. **AutoConnectConfig::bootUri** can be specified either /_ac or HOME path as the uri to be accessed after invoking Reset from AutoConnect menu. - Improved source code placement of predefined macros. Defined common macros have been moved to ```AutoConnectDefs.h```. ### [0.9.6] Sept. 27, 2018 diff --git a/src/AutoConnect.cpp b/src/AutoConnect.cpp index 5757afd..54f123a 100644 --- a/src/AutoConnect.cpp +++ b/src/AutoConnect.cpp @@ -91,7 +91,6 @@ bool AutoConnect::begin(const char* ssid, const char* passphrase, unsigned long // Start WiFi connection with station mode. WiFi.softAPdisconnect(true); WiFi.enableAP(false); - _disconnectWiFi(false); WiFi.mode(WIFI_STA); delay(100); @@ -124,8 +123,10 @@ bool AutoConnect::begin(const char* ssid, const char* passphrase, unsigned long // Try to connect by STA immediately. if (ssid == nullptr && passphrase == nullptr) WiFi.begin(); - else + else { + _disconnectWiFi(false); WiFi.begin(ssid, passphrase); + } AC_DBG("WiFi.begin(%s%s%s)\n", ssid == nullptr ? "" : ssid, passphrase == nullptr ? "" : ",", passphrase == nullptr ? "" : passphrase); cs = _waitForConnect(_portalTimeout) == WL_CONNECTED; } @@ -284,25 +285,27 @@ WebServerClass& AutoConnect::host() { * @param aux A reference to AutoConnectAux that made up * the auxiliary page to be added. */ -void AutoConnect::join(AutoConnectAux& aux) { +bool AutoConnect::join(AutoConnectAux& aux) { if (_aux) _aux->_concat(aux); else _aux.reset(&aux); aux._join(*this); AC_DBG("%s on hands\n", aux.uri()); + return true; } /** -* 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) { + * Append auxiliary pages made up with AutoConnectAux. + * @param aux A vector of reference to AutoConnectAux that made up + * the auxiliary page to be added. + */ +bool AutoConnect::join(std::vector> aux) { for (std::size_t n = 0; n < aux.size(); n++) { AutoConnectAux& addon = aux[n].get(); join(addon); } + return true; } /** diff --git a/src/AutoConnect.h b/src/AutoConnect.h index ba6a353..742131c 100644 --- a/src/AutoConnect.h +++ b/src/AutoConnect.h @@ -39,6 +39,11 @@ typedef enum AC_SAVECREDENTIAL { AC_SAVECREDENTIAL_AUTO } AC_SAVECREDENTIAL_t; +typedef enum AC_URIONBOOT { + AC_URIONBOOT_ROOT, + AC_URIONBOOT_HOME +} AC_URIONBOOT_t; + class AutoConnectConfig { public: /** @@ -55,6 +60,7 @@ class AutoConnectConfig { channel(AUTOCONNECT_AP_CH), hidden(0), autoSave(AC_SAVECREDENTIAL_AUTO), + bootUri(AC_URIONBOOT_ROOT), boundaryOffset(AC_IDENTIFIER_OFFSET), uptime(AUTOCONNECT_STARTUPTIME), autoRise(true), @@ -79,6 +85,7 @@ class AutoConnectConfig { channel(channel), hidden(0), autoSave(AC_SAVECREDENTIAL_AUTO), + bootUri(AC_URIONBOOT_ROOT), boundaryOffset(AC_IDENTIFIER_OFFSET), uptime(AUTOCONNECT_STARTUPTIME), autoRise(true), @@ -103,6 +110,7 @@ class AutoConnectConfig { channel = o.channel; hidden = o.hidden; autoSave = o.autoSave; + bootUri = o.bootUri; boundaryOffset = o.boundaryOffset; uptime = o.uptime; autoRise = o.autoRise; @@ -126,6 +134,7 @@ class AutoConnectConfig { uint8_t channel; /**< SoftAP used wifi channel */ uint8_t hidden; /**< SoftAP SSID hidden */ AC_SAVECREDENTIAL_t autoSave; /**< Auto save credential */ + AC_URIONBOOT_t bootUri; /**< An uri invoking after reset */ uint16_t boundaryOffset; /**< The save storage offset of EEPROM */ int uptime; /**< Length of start up time */ bool autoRise; /**< Automatic starting the captive portal */ @@ -154,8 +163,16 @@ class AutoConnect { void handleClient(); void handleRequest(); WebServerClass& host(); - void join(AutoConnectAux& aux); - void join(std::vector> aux); + bool join(AutoConnectAux& aux); + bool join(std::vector> aux); + + /** For AutoConnectAux described in JSON */ +#ifdef AUTOCONNECT_USE_JSON + bool join(const char* aux); + bool join(const __FlashStringHelper* aux); + bool join(Stream& aux, size_t bufferSize = AUTOCONNECT_JSON_BUFFER_SIZE); + bool _load(JsonVariant& aux); +#endif typedef std::function DetectExit_ft; void onDetect(DetectExit_ft fn); @@ -283,6 +300,7 @@ class AutoConnect { String _token_HIDDEN_COUNT(PageArgument& args); String _token_OPEN_SSID(PageArgument& args); String _token_UPTIME(PageArgument& args); + String _token_BOOTURI(PageArgument& args); #if defined(ARDUINO_ARCH_ESP8266) friend class ESP8266WebServer; diff --git a/src/AutoConnectAux.cpp b/src/AutoConnectAux.cpp index 9b5c4ec..6d0b309 100644 --- a/src/AutoConnectAux.cpp +++ b/src/AutoConnectAux.cpp @@ -234,6 +234,98 @@ const String AutoConnectAux::_injectMenu(PageArgument& args) { #ifdef AUTOCONNECT_USE_JSON +/** + * Static storage for JSON buffer size calculation. + */ +int16_t AutoConnectAux::_jbSize; /**< JSON dynamic buffer size */ +uint16_t AutoConnectAux::_jbByte; /**< Byte count for calculation of JSON buffer */ +uint8_t AutoConnectAux::_jbObject; /**< Object count for calculation of JSON buffer */ +uint8_t AutoConnectAux::_jbArray; /**< Array count for calculation of JSON buffer */ +uint8_t AutoConnectAux::_jbNest; /**< JSON array nest count */ +uint8_t AutoConnectAux::_kStack[AUTOCONENCT_JSONOBJECTTREE_MAXDEPTH]; /**< JSON array counter stack */ +uint8_t AutoConnectAux::_nStack[AUTOCONENCT_JSONOBJECTTREE_MAXDEPTH]; /**< JSON object counter stack */ +int8_t AutoConnectAux::_kp; /**< Stack pointer for JSON array counter */ +int8_t AutoConnectAux::_np; /**< Stack pointer for JSON object counter */ +bool AutoConnectAux::_jbOpen; /**< JSON object paring status */ +bool AutoConnectAux::_jbLiteral; /**< JSON object lexical status */ + +/** + * Load AutoConnectAux page from JSON description stored in the sketch. + * This function can load AutoConnectAux for multiple AUX pages written + * in JSON and is registered in AutoConnect. + * @param aux JSON description to be load. + * @return true Successfully loaded. + */ +bool AutoConnect::join(const char* aux) { + const size_t bufferSize = AutoConnectAux::_calcJsonBufferSize(aux); + DynamicJsonBuffer jsonBuffer(bufferSize); + JsonVariant jv = jsonBuffer.parse(aux); + return _load(jv); +} + +/** + * Load AutoConnectAux page from JSON description stored in PROGMEM. + * This function can load AutoConnectAux for multiple AUX pages written + * in JSON and is registered in AutoConnect. + * @param aux JSON description to be load. + * @return true Successfully loaded. + */ +bool AutoConnect::join(const __FlashStringHelper* aux) { + const size_t bufferSize = AutoConnectAux::_calcJsonBufferSize(aux); + DynamicJsonBuffer jsonBuffer(bufferSize); + JsonVariant jv = jsonBuffer.parse(aux); + return _load(jv); +} + +/** +* Load AutoConnectAux page from JSON description from the stream. +* This function can load AutoConnectAux for multiple AUX pages written +* in JSON and is registered in AutoConnect. +* @param aux Stream for read AutoConnectAux elements. +* @return true Successfully loaded. +*/ +bool AutoConnect::join(Stream& aux, size_t bufferSize) { + DynamicJsonBuffer jsonBuffer(bufferSize); + JsonVariant jv = jsonBuffer.parse(aux); + return _load(jv); +} + +/** + * Load AutoConnectAux page from JSON object. + * @param aux A JsonVariant object that stores each element of AutoConnectAuxl. + * @return true Successfully loaded. + */ +bool AutoConnect::_load(JsonVariant& aux) { + bool rc = true; + if (aux.success()) { + if (aux.is()) { + JsonArray& jb = aux.as(); + for (JsonObject& auxJson : jb) { + AutoConnectAux* newAux = new AutoConnectAux; + if (newAux->_load(auxJson)) + join(*newAux); + else { + delete newAux; + rc = false; + break; + } + } + } + else { + JsonObject& jb = aux.as(); + AutoConnectAux* newAux = new AutoConnectAux; + if (newAux->_load(jb)) + join(*newAux); + else { + delete newAux; + rc = false; + } + } + } + else + return rc; +} + /** * Create an instance from the AutoConnectElement of the JSON object. * @param json A reference of JSON diff --git a/src/AutoConnectAux.h b/src/AutoConnectAux.h index a024249..6132f50 100644 --- a/src/AutoConnectAux.h +++ b/src/AutoConnectAux.h @@ -101,23 +101,23 @@ class AutoConnectAux : public PageBuilder { friend class AutoConnect; private: - size_t _calcJsonBufferSize(const char* in); /**< Calculate JSON buffer size for constant character array */ - size_t _calcJsonBufferSize(const __FlashStringHelper* in); /**< Calculate JSON buffer size for pgm_data */ - void _initJsonBufferSize(void); /**< Initialize the stacks for JSON Dynamic buffer size calculation */ - void _accJsonBufferSize(const char c); /**< Accumulate JSON Dynamic buffer size */ - size_t _resultJsonBufferSize(void); /**< Retrieve accumulated result value */ - - int16_t _jbSize; /**< JSON dynamic buffer size */ - uint16_t _jbByte; /**< Byte count for calculation of JSON buffer */ - uint8_t _jbObject; /**< Object count for calculation of JSON buffer */ - uint8_t _jbArray; /**< Array count for calculation of JSON buffer */ - uint8_t _jbNest; /**< JSON array nest count */ - uint8_t _kStack[AUTOCONENCT_JSONOBJECTTREE_MAXDEPTH]; /**< JSON array counter stack */ - uint8_t _nStack[AUTOCONENCT_JSONOBJECTTREE_MAXDEPTH]; /**< JSON object counter stack */ - int8_t _kp; /**< Stack pointer for JSON array counter */ - int8_t _np; /**< Stack pointer for JSON object counter */ - bool _jbOpen; /**< JSON object paring status */ - bool _jbLiteral; /**< JSON object lexical status */ + static size_t _calcJsonBufferSize(const char* in); /**< Calculate JSON buffer size for constant character array */ + static size_t _calcJsonBufferSize(const __FlashStringHelper* in); /**< Calculate JSON buffer size for pgm_data */ + static void _initJsonBufferSize(void); /**< Initialize the stacks for JSON Dynamic buffer size calculation */ + static void _accJsonBufferSize(const char c); /**< Accumulate JSON Dynamic buffer size */ + static size_t _resultJsonBufferSize(void); /**< Retrieve accumulated result value */ + + static int16_t _jbSize; /**< JSON dynamic buffer size */ + static uint16_t _jbByte; /**< Byte count for calculation of JSON buffer */ + static uint8_t _jbObject; /**< Object count for calculation of JSON buffer */ + static uint8_t _jbArray; /**< Array count for calculation of JSON buffer */ + static uint8_t _jbNest; /**< JSON array nest count */ + static uint8_t _kStack[AUTOCONENCT_JSONOBJECTTREE_MAXDEPTH]; /**< JSON array counter stack */ + static uint8_t _nStack[AUTOCONENCT_JSONOBJECTTREE_MAXDEPTH]; /**< JSON object counter stack */ + static int8_t _kp; /**< Stack pointer for JSON array counter */ + static int8_t _np; /**< Stack pointer for JSON object counter */ + static bool _jbOpen; /**< JSON object paring status */ + static bool _jbLiteral; /**< JSON object lexical status */ }; #endif // _AUTOCONNECTAUX_H_ \ No newline at end of file diff --git a/src/AutoConnectPage.cpp b/src/AutoConnectPage.cpp index 680e179..6d16108 100644 --- a/src/AutoConnectPage.cpp +++ b/src/AutoConnectPage.cpp @@ -511,7 +511,7 @@ const char AutoConnect::_PAGE_404[] PROGMEM = { /**< The page that started the reset. */ const char AutoConnect::_PAGE_RESETTING[] PROGMEM = { "{{HEAD}}" - "" + "" "AutoConnect resetting" "" "" @@ -1081,6 +1081,17 @@ String AutoConnect::_token_UPTIME(PageArgument& args) { return String(_apConfig.uptime); } +String AutoConnect::_token_BOOTURI(PageArgument& args) { + AC_UNUSED(args); + if (_apConfig.bootUri == AC_URIONBOOT_ROOT) + return String(AUTOCONNECT_URI); + else if (_apConfig.bootUri == AC_URIONBOOT_HOME) + return _apConfig.homeUri.length() > 0 ? _apConfig.homeUri : String("/"); + else + return ""; +} + + /** * This function dynamically build up the response pages that conform to * the requested URI. A PageBuilder instance is stored in _rensponsePage @@ -1178,6 +1189,7 @@ PageElement* AutoConnect::_setupPage(String uri) { // Setup /auto/reset elm->setMold(_PAGE_RESETTING); elm->addToken(PSTR("HEAD"), std::bind(&AutoConnect::_token_HEAD, this, std::placeholders::_1)); + elm->addToken(PSTR("BOOTURI"), std::bind(&AutoConnect::_token_BOOTURI, this, std::placeholders::_1)); elm->addToken(PSTR("UPTIME"), std::bind(&AutoConnect::_token_UPTIME, this, std::placeholders::_1)); elm->addToken(PSTR("RESET"), std::bind(&AutoConnect::_induceReset, this, std::placeholders::_1));