diff --git a/.travis.yml b/.travis.yml index e4d141e..8ee77d1 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.1 + - arduino --install-library PubSubClient,PageBuilder:1.2.0 - 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 5b661b7..6560b48 100644 --- a/keywords.txt +++ b/keywords.txt @@ -9,6 +9,7 @@ AutoConnectButton KEYWORD1 AutoConnectCheckbox KEYWORD1 AutoConnectElement KEYWORD1 AutoConnectInput KEYWORD1 +AutoConnectRadio KEYWORD1 AutoConnectSelect KEYWORD1 AutoConnectSubmit KEYWORD1 AutoConnectText KEYWORD1 @@ -54,6 +55,7 @@ ACButton PREPROCESSOR ACCheckbox PREPROCESSOR ACElement PREPROCESSOR ACInput PREPROCESSOR +ACRadio PREPROCESSOR ACSelect PREPROCESSOR ACSubmit PREPROCESSOR ACText PREPROCESSOR diff --git a/library.json b/library.json index 9d5cfbb..1a8d7c7 100644 --- a/library.json +++ b/library.json @@ -12,7 +12,7 @@ [ { "name": "PageBuilder", - "version": ">=1.1.0" + "version": ">=1.2.0" } ], "frameworks": "arduino", diff --git a/src/AutoConnect.cpp b/src/AutoConnect.cpp index 13fd9e0..ab887ed 100644 --- a/src/AutoConnect.cpp +++ b/src/AutoConnect.cpp @@ -310,6 +310,7 @@ void AutoConnect::_startWebServer() { _webServer->onNotFound(std::bind(&AutoConnect::_handleNotFound, this)); // here, Prepare PageBuilders for captive portal _responsePage = new PageBuilder(); + _responsePage->chunked(PB_ByteStream); _responsePage->exitCanHandle(std::bind(&AutoConnect::_classifyHandle, this, std::placeholders::_1, std::placeholders::_2)); _responsePage->insert(*_webServer); @@ -538,10 +539,11 @@ String AutoConnect::_induceConnect(PageArgument& args) { // Read from EEPROM AutoConnectCredential credential(_apConfig.boundaryOffset); struct station_config entry; - AC_DBG("Load credential:%s\n", args.arg(AUTOCONNECT_PARAMID_CRED).c_str()); +// AC_DBG("Load credential:%s\n", args.arg(AUTOCONNECT_PARAMID_CRED).c_str()); credential.load(args.arg(AUTOCONNECT_PARAMID_CRED).c_str(), &entry); strncpy(reinterpret_cast(_credential.ssid), reinterpret_cast(entry.ssid), sizeof(_credential.ssid)); strncpy(reinterpret_cast(_credential.password), reinterpret_cast(entry.password), sizeof(_credential.password)); + AC_DBG("Credential loaded:%s %s\n", _credential.ssid, _credential.password); } else { // Credential had by the post parameter. diff --git a/src/AutoConnectAux.cpp b/src/AutoConnectAux.cpp index 7b1ed15..c74399c 100644 --- a/src/AutoConnectAux.cpp +++ b/src/AutoConnectAux.cpp @@ -282,50 +282,43 @@ AutoConnectElement* AutoConnectAux::_createElement(const JsonObject& json) { * Constructs an AutoConnectAux instance by reading all the * AutoConnectElements of the specified URI from the elements defined JSON. * @param in AutoConnectAux element data which is described by JSON. - * @param uri AutoConnectAux uri to be loaded. * @return true The element collection successfully loaded. * @return false Invalid JSON data occurred. */ -bool AutoConnectAux::load(const char* in, const String uri) { - DynamicJsonBuffer jsonBuffer; +bool AutoConnectAux::load(const char* in) { +// DynamicJsonBuffer jsonBuffer(); + const size_t bufferSize = 2*JSON_ARRAY_SIZE(2) + 3*JSON_ARRAY_SIZE(3) + JSON_ARRAY_SIZE(9) + JSON_OBJECT_SIZE(1) + 2*JSON_OBJECT_SIZE(3) + 9*JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(6) + 1080; + DynamicJsonBuffer jsonBuffer(bufferSize); JsonObject& jb = jsonBuffer.parseObject(in); - return _load(jb, uri); + return _load(jb); } -bool AutoConnectAux::load(const __FlashStringHelper* in, const String uri) { - DynamicJsonBuffer jsonBuffer; +bool AutoConnectAux::load(const __FlashStringHelper* in) { +// DynamicJsonBuffer jsonBuffer(); + const size_t bufferSize = 2*JSON_ARRAY_SIZE(2) + 3*JSON_ARRAY_SIZE(3) + JSON_ARRAY_SIZE(9) + JSON_OBJECT_SIZE(1) + 2*JSON_OBJECT_SIZE(3) + 9*JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(6) + 1080; + DynamicJsonBuffer jsonBuffer(bufferSize); JsonObject& jb = jsonBuffer.parseObject(in); - return _load(jb, uri); + return _load(jb); } -bool AutoConnectAux::load(Stream& in, const String uri) { - DynamicJsonBuffer jsonBuffer; +bool AutoConnectAux::load(Stream& in) { +// DynamicJsonBuffer jsonBuffer(); + const size_t bufferSize = 2*JSON_ARRAY_SIZE(2) + 3*JSON_ARRAY_SIZE(3) + JSON_ARRAY_SIZE(9) + JSON_OBJECT_SIZE(1) + 2*JSON_OBJECT_SIZE(3) + 9*JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(6) + 1080; + DynamicJsonBuffer jsonBuffer(bufferSize); JsonObject& jb = jsonBuffer.parseObject(in); - return _load(jb, uri); + return _load(jb); } -bool AutoConnectAux::_load(JsonObject& jb, const String uri) { - bool rc = jb.success(); - if (rc) { - JsonArray& aux = jb[AUTOCONNECT_JSON_KEY_AUX]; - if ((rc = aux.success())) { - rc = false; - for (JsonObject& page : aux) { - const String j_uri = page.get(F(AUTOCONNECT_JSON_KEY_URI)); - if (uri == j_uri) { - AC_DBG("Loading %s\n", j_uri.c_str()); - _title = page.get(F(AUTOCONNECT_JSON_KEY_TITLE)); - _menu = page.get(F(AUTOCONNECT_JSON_KEY_MENU)); - _uriStr = j_uri; - setUri(_uriStr.c_str()); - (void)_loadElement(jb, "*"); - rc = true; - break; - } - } - } - } - return rc; +bool AutoConnectAux::_load(JsonObject& jb) { + if (!jb.success()) + return false; + + _title = jb.get(F(AUTOCONNECT_JSON_KEY_TITLE)); + _uriStr = jb.get(F(AUTOCONNECT_JSON_KEY_URI)); + _uri = _uriStr.c_str(); + _menu = jb.get(F(AUTOCONNECT_JSON_KEY_MENU)); + (void)_loadElement(jb, "*"); + return true; } /** @@ -333,7 +326,7 @@ bool AutoConnectAux::_load(JsonObject& jb, const String uri) { * described by JSON. Usually, the Stream is specified a storm file of * SD or SPIFFS. The Stream must be opened before invoking the function. * @param in Reference of the Stream which contains the parameter - * file described by JSON. + * data described by JSON. * @param name The element name to be loaded. '*'specifies that all * elements are to be loaded. * @return A reference of loaded AutoConnectElement instance. @@ -363,41 +356,31 @@ AutoConnectElement& AutoConnectAux::_loadElement(JsonObject& jb, const String na if (!jb.success()) return _nullElement(); - JsonArray& aux = jb[AUTOCONNECT_JSON_KEY_AUX]; - if (!aux.success()) - return _nullElement(); - - for (JsonObject& page : aux) { - if (page[AUTOCONNECT_JSON_KEY_URI].as() == String(uri())) { - JsonArray& element = page[AUTOCONNECT_JSON_KEY_ELEMENT]; - for (JsonObject& elm : element) { - String elmName = elm.get(F(AUTOCONNECT_JSON_KEY_NAME)); - if (wc || name.equalsIgnoreCase(elmName)) { - // The specified element is defined in the JSON stream. - // Loads from JSON object. - const String inType = elm[AUTOCONNECT_JSON_KEY_TYPE].as(); - auxElm = _getElement(elmName); - // The element is not created yet, create new one. - if (!auxElm) { - if ((auxElm = _createElement(elm))) { - AC_DBG("%s<%d> of %s created\n", elmName.c_str(), (int)(auxElm->typeOf()), uri()); - add(*auxElm); // Insert to AutoConnect - } - else { - AC_DBG("%s unknown element type\n", elmName.c_str()); - continue; - } - } - if (auxElm->loadElement(elm)) { - AC_DBG("%s<%d> of %s loaded\n", auxElm->name.c_str(), (int)auxElm->typeOf(), uri()); - } - else { - // Element type mismatch - AC_DBG("Type of %s element mismatched\n", elmName.c_str()); - continue; - } + JsonArray& elements = jb[AUTOCONNECT_JSON_KEY_ELEMENT]; + for (JsonObject& element : elements) { + String elmName = element.get(F(AUTOCONNECT_JSON_KEY_NAME)); + if (wc || name.equalsIgnoreCase(elmName)) { + // The specified element is defined in the JSON stream. + // Loads from JSON object. + auxElm = _getElement(elmName); + // The element is not created yet, create new one. + if (!auxElm) { + if ((auxElm = _createElement(element))) { + AC_DBG("%s<%d> of %s created\n", elmName.c_str(), (int)(auxElm->typeOf()), uri()); + add(*auxElm); // Insert to AutoConnect + } + else { + AC_DBG("%s unknown element type\n", elmName.c_str()); + continue; } } + if (auxElm->loadElement(element)) + AC_DBG("%s<%d> of %s loaded\n", auxElm->name.c_str(), (int)auxElm->typeOf(), uri()); + else { + // Element type mismatch + AC_DBG("Type of %s element mismatched\n", elmName.c_str()); + continue; + } } } return auxElm ? *auxElm : _nullElement(); @@ -416,12 +399,12 @@ size_t AutoConnectAux::saveElement(Stream& out, const AutoConnectElement& elemen if (!jb.success()) return 0; - JsonArray& aux = jb[AUTOCONNECT_JSON_KEY_AUX]; + JsonArray& aux = jb["aux"]; if (!aux.success()) return 0; for (JsonObject& page : aux) { - if (page["uri"].as() == String(uri())) { + if (page["aux"].as() == String(uri())) { JsonArray& element_j = page[AUTOCONNECT_JSON_KEY_ELEMENT]; for (JsonObject& elm : element_j) { if (elm[AUTOCONNECT_JSON_KEY_NAME].as() == element.name) { diff --git a/src/AutoConnectAux.h b/src/AutoConnectAux.h index eb95364..e935688 100644 --- a/src/AutoConnectAux.h +++ b/src/AutoConnectAux.h @@ -60,9 +60,9 @@ class AutoConnectAux : public PageBuilder { void on(const AuxHandlerFunctionT handler, const AutoConnectExitOrder_t order = AC_EXIT_AHEAD) { _handler = handler; _order = order; } /**< Set user handler */ #ifdef AUTOCONNECT_USE_JSON - bool load(const char* in, const String uri); - bool load(const __FlashStringHelper* in, const String uri); - bool load(Stream& in, const String uri); + bool load(const char* in); + bool load(const __FlashStringHelper* in); + bool load(Stream& in); AutoConnectElement& loadElement(const char* in, const String name = "*"); AutoConnectElement& loadElement(const __FlashStringHelper* in, const String name = "*"); AutoConnectElement& loadElement(Stream& in, const String name = "*"); @@ -78,7 +78,7 @@ class AutoConnectAux : public PageBuilder { const String _injectMenu(PageArgument& args); #ifdef AUTOCONNECT_USE_JSON - bool _load(JsonObject& in, const String uri); + bool _load(JsonObject& in); AutoConnectElement& _loadElement(JsonObject& in, const String name); AutoConnectElement* _createElement(const JsonObject& json); AutoConnectElement* _getElement(const String name); diff --git a/src/AutoConnectElementBasis.h b/src/AutoConnectElementBasis.h index f26cf26..37d66ed 100644 --- a/src/AutoConnectElementBasis.h +++ b/src/AutoConnectElementBasis.h @@ -48,7 +48,7 @@ class AutoConnectElementBasis { String name; /**< Element name */ String value; /**< Element value */ -protected: + protected: ACElement_t _type; /**< Element type identifier */ }; @@ -119,17 +119,17 @@ class AutoConnectInputBasis : virtual public AutoConnectElementBasis { */ class AutoConnectRadioBasis : virtual public AutoConnectElementBasis { public: - explicit AutoConnectRadioBasis(const char* name = "", std::vector values = {}, const char* label = "", const ACArrange_t order = AC_Vertical, const uint8_t checked = 0) : AutoConnectElementBasis(name, ""), _values(values), label(label), order(order), checked(checked) { + explicit AutoConnectRadioBasis(const char* name = "", std::vector values = {}, const char* label = "", const ACArrange_t order = AC_Vertical, const uint8_t checked = 0) : AutoConnectElementBasis(name, ""), label(label), order(order), checked(checked), _values(values) { _type = AC_Radio; } virtual ~AutoConnectRadioBasis() {} const String toHTML(void) const; - void option(const String value) { _values.push_back(value); } + void add(const String value) { _values.push_back(value); } void empty(void) { _values.clear(); } String label; /**< A label for a subsequent radio buttons */ ACArrange_t order; /**< layout order */ - uint8_t checked; /**< Index of check marked item */ + uint8_t checked; /**< Index of check marked item */ protected: std::vector _values; /**< Items in a group */ @@ -145,12 +145,12 @@ class AutoConnectRadioBasis : virtual public AutoConnectElementBasis { */ class AutoConnectSelectBasis : virtual public AutoConnectElementBasis { public: - explicit AutoConnectSelectBasis(const char* name = "", std::vector options = {}, const char* label = "") : AutoConnectElementBasis(name, ""), label(String(label)), _options(options) { + explicit AutoConnectSelectBasis(const char* name = "", std::vector options = {}, const char* label = "") : AutoConnectElementBasis(name, ""), label(String(label)), _options(options) { _type = AC_Select; } virtual ~AutoConnectSelectBasis() {} const String toHTML(void) const; - void option(const String value) { _options.push_back(value); } + void add(const String option) { _options.push_back(option); } void empty(void) { _options.clear(); } String label; /**< A label for a subsequent input box */ diff --git a/src/AutoConnectElementBasisImpl.h b/src/AutoConnectElementBasisImpl.h index c550516..1a3d171 100644 --- a/src/AutoConnectElementBasisImpl.h +++ b/src/AutoConnectElementBasisImpl.h @@ -69,15 +69,17 @@ const String AutoConnectInputBasis::toHTML(void) const { const String AutoConnectRadioBasis::toHTML(void) const { String html = String(); - if (label.length()) - html = String(FPSTR("")); - if (order == AC_Vertical) - html += String("
"); + if (label.length()) { + html = label; + if (order == AC_Vertical) + html += String("
"); + } for (std::size_t n = 0; n < _values.size(); n++) { - html += String(FPSTR("") + _values[n]; + html += String(FPSTR(">")); if (order == AC_Vertical) html += String("
"); } @@ -96,14 +98,14 @@ const String AutoConnectSelectBasis::toHTML(void) const { String html = String(); if (label.length()) - html = String(FPSTR("")); - html += String(FPSTR(""); std::size_t n = _options.size(); if (n) { for (std::size_t n = 0; n < _options.size(); n++) html += String(FPSTR("")); } - html += String(FPSTR("
")); + html += String(FPSTR("")); return html; } diff --git a/src/AutoConnectElementJson.h b/src/AutoConnectElementJson.h index d2eb3fd..075c49c 100644 --- a/src/AutoConnectElementJson.h +++ b/src/AutoConnectElementJson.h @@ -15,7 +15,6 @@ #define AUTOCONNECT_JSON_KEY_ACTION "action" #define AUTOCONNECT_JSON_KEY_ARRANGE "arrange" -#define AUTOCONNECT_JSON_KEY_AUX "aux" #define AUTOCONNECT_JSON_KEY_CHECKED "checked" #define AUTOCONNECT_JSON_KEY_ELEMENT "element" #define AUTOCONNECT_JSON_KEY_HORIZONTAL "horizontal" @@ -28,7 +27,7 @@ #define AUTOCONNECT_JSON_KEY_TYPE "type" #define AUTOCONNECT_JSON_KEY_URI "uri" #define AUTOCONNECT_JSON_KEY_VALUE "value" -#define AUTOCONNECT_JSON_KEY_VERTICAL "vertival" +#define AUTOCONNECT_JSON_KEY_VERTICAL "vertical" #define AUTOCONNECT_JSON_TYPE_ACBUTTON "ACButton" #define AUTOCONNECT_JSON_TYPE_ACCHECKBOX "ACCheckBox" #define AUTOCONNECT_JSON_TYPE_ACELEMENT "ACElement" diff --git a/src/AutoConnectElementJsonImpl.h b/src/AutoConnectElementJsonImpl.h index afc83e7..4c15dd6 100644 --- a/src/AutoConnectElementJsonImpl.h +++ b/src/AutoConnectElementJsonImpl.h @@ -105,7 +105,7 @@ bool AutoConnectRadioJson::loadElement(const JsonObject& json) { empty(); JsonArray& optionArray = json[AUTOCONNECT_JSON_KEY_VALUE]; for (auto value : optionArray) - option(value.as()); + add(value.as()); return true; } return false; @@ -125,7 +125,7 @@ bool AutoConnectSelectJson::loadElement(const JsonObject& json) { empty(); JsonArray& optionArray = json[AUTOCONNECT_JSON_KEY_OPTION]; for (auto value : optionArray) - option(value.as()); + add(value.as()); return true; } return false;