diff --git a/src/AutoConnectElementBasis.h b/src/AutoConnectElementBasis.h index a7f92e5..85b876d 100644 --- a/src/AutoConnectElementBasis.h +++ b/src/AutoConnectElementBasis.h @@ -180,6 +180,7 @@ class AutoConnectRadioBasis : virtual public AutoConnectElementBasis { String label; /**< A label for a subsequent radio buttons */ ACArrange_t order; /**< layout order */ uint8_t checked; /**< Index of check marked item */ + std::vector tags; /**< For private API: Tag of each value */ protected: std::vector _values; /**< Items in a group */ diff --git a/src/AutoConnectElementBasisImpl.h b/src/AutoConnectElementBasisImpl.h index da0d393..01b12ca 100644 --- a/src/AutoConnectElementBasisImpl.h +++ b/src/AutoConnectElementBasisImpl.h @@ -196,6 +196,8 @@ const String AutoConnectRadioBasis::toHTML(void) const { if (n == checked) html += String(F(" checked")); html += String(F(">")); + if (n <= tags.size()) + html += tags[n - 1]; if (order == AC_Vertical) html += String(F("
")); } diff --git a/src/AutoConnectUpdate.cpp b/src/AutoConnectUpdate.cpp index b8deff3..fa6b219 100644 --- a/src/AutoConnectUpdate.cpp +++ b/src/AutoConnectUpdate.cpp @@ -132,6 +132,7 @@ void AutoConnectUpdate::attach(AutoConnect& portal) { updatePage = new AutoConnectAux(String(FPSTR(_auxResult.uri)), String(FPSTR(_auxResult.title)), _auxResult.menu); _buildAux(updatePage, &_auxResult, lengthOf(_elmResult)); _result.reset(updatePage); + _result->chunk = PB_ByteStream; _catalog->on(std::bind(&AutoConnectUpdate::_onCatalog, this, std::placeholders::_1, std::placeholders::_2), AC_EXIT_AHEAD); _progress->on(std::bind(&AutoConnectUpdate::_onUpdate, this, std::placeholders::_1, std::placeholders::_2), AC_EXIT_AHEAD); _result->on(std::bind(&AutoConnectUpdate::_onResult, this, std::placeholders::_1, std::placeholders::_2), AC_EXIT_AHEAD); @@ -330,22 +331,6 @@ void AutoConnectUpdate::_buildAux(AutoConnectAux* aux, const AutoConnectUpdate:: } } -/** - * Register only bin type file name as available sketch binary to - * AutoConnectRadio value based on the response from the update server. - * @param radio A reference to AutoConnectRadio - * @param responseBody JSON variant of a JSON document responded from the Update server - * @return Number of available sketch binaries - */ -size_t AutoConnectUpdate::_insertCatalog(AutoConnectRadio& radio, JsonVariant& responseBody) { - ArduinoJsonArray firmwares = responseBody.as(); - radio.empty(firmwares.size()); - for (ArduinoJsonObject entry : firmwares) - if (entry[F("type")] == "bin") - radio.add(entry[F("name")].as()); - return firmwares.size(); -} - /** * AUTOCONNECT_URI_UPDATE page handler. * It queries the update server for cataloged sketch binary and @@ -370,6 +355,7 @@ String AutoConnectUpdate::_onCatalog(AutoConnectAux& catalog, PageArgument& args AutoConnectRadio& firmwares = catalog.getElement(String(F("firmwares"))); AutoConnectSubmit& submit = catalog.getElement(String(F("update"))); firmwares.empty(); + firmwares.tags.clear(); submit.enable = false; _binName = String(""); @@ -383,45 +369,74 @@ String AutoConnectUpdate::_onCatalog(AutoConnectAux& catalog, PageArgument& args int responseCode = httpClient.GET(); if (responseCode == HTTP_CODE_OK) { - // The size of the JSON buffer is a fixed. It can be a problem - // when parsing with ArduinoJson V6. If memory insufficient has - // occurred during the parsing, increase this buffer size. - ArduinoJsonBuffer json(AUTOCONNECT_UPDATE_CATALOG_JSONBUFFER_SIZE); - JsonVariant jb; - bool parse; + bool parse; + char beginOfList[] = "["; + char endOfEntry[] = ","; + char endOfList[] = "]"; Stream& responseBody = httpClient.getStream(); + + // Read partially and repeatedly the responded http stream that is + // including the JSON array to reduce the buffer size for parsing + // of the firmware catalog list. + AC_DBG("Update server responded:"); + responseBody.find(beginOfList); + do { + // The size of the JSON buffer is a fixed. It can be a problem + // when parsing with ArduinoJson V6. If memory insufficient has + // occurred during the parsing, increase this buffer size. + ArduinoJsonStaticBuffer jb; + #if ARDUINOJSON_VERSION_MAJOR<=5 - jb = json.parse(responseBody); - parse = jb.success(); + ArduinoJsonObject json = jb.parseObject(responseBody); + parse = jb.success(); #else - DeserializationError err = deserializeJson(json, responseBody); - parse = !(err == true); - if (parse) - jb = json.as(); + DeserializationError err = deserializeJson(jb, responseBody); + ArduinoJsonObject json = jb.as(); + parse = (err == DeserializationError::Ok); +#endif + if (parse) { +#ifdef AC_DEBUG + AC_DBG_DUMB("\n"); + ARDUINOJSON_PRINT(jb, AC_DEBUG_PORT); #endif + // Register only bin type file name as available sketch binary to + // AutoConnectRadio value based on the response from the update server. + firmwares.order = AC_Horizontal; + if (json["type"].as().equalsIgnoreCase("bin")) { + firmwares.add(json[F("name")].as()); + String attr = String(F("")) + json[F("date")].as() + String(F("")) + json[F("time")].as().substring(0, 5) + String(F("")) + String(json[F("size")].as()) + String(F("")); + firmwares.tags.push_back(attr); + } + } + else { + caption.value = String(F("Invalid catalog list:")) + String(err.c_str()); + AC_DBG("JSON:%s\n", err.c_str()); + break; + } + } while (responseBody.findUntil(endOfEntry, endOfList)); + + AC_DBG_DUMB("\n"); if (parse) { - caption.value = String(F("

Available firmwares

")); - JsonVariant firmwareList = json.as(); - if (_insertCatalog(firmwares, firmwareList) > 0) + if (firmwares.size()) { + caption.value = String(F("

Available firmwares

")); submit.enable = true; + } + else + caption.value = String(F("

No available firmwares

")); } - else - caption.value = String(F("Invalid catalog list:")) + String(err.c_str()); -#if defined(AC_DEBUG) - AC_DBG("Update server responds catalog list\n"); - ARDUINOJSON_PRINT(jb, AC_DEBUG_PORT); - AC_DBG_DUMB("\n"); -#endif } else { caption.value = String(F("Update server responds (")) + String(responseCode) + String("):"); caption.value += HTTPClient::errorToString(responseCode); + AC_DBG("%s\n", caption.value.c_str()); } httpClient.end(); } - else + else { caption.value = String(F("http failed connect to ")) + host + String(':') + String(port); + AC_DBG("%s\n", caption.value.c_str()); + } return String(""); } diff --git a/src/AutoConnectUpdate.h b/src/AutoConnectUpdate.h index 679dc1d..060ab13 100644 --- a/src/AutoConnectUpdate.h +++ b/src/AutoConnectUpdate.h @@ -121,7 +121,6 @@ class AutoConnectUpdate : public HTTPUpdateClass { String _onCatalog(AutoConnectAux& catalog, PageArgument& args); String _onUpdate(AutoConnectAux& update, PageArgument& args); String _onResult(AutoConnectAux& result, PageArgument& args); - size_t _insertCatalog(AutoConnectRadio& radio, JsonVariant & responseBody); void _wsEvent(uint8_t client, WStype_t event, uint8_t* payload, size_t length); void _inProgress(size_t amount, size_t size); diff --git a/src/AutoConnectUpdatePage.h b/src/AutoConnectUpdatePage.h index d93eaa9..361c908 100644 --- a/src/AutoConnectUpdatePage.h +++ b/src/AutoConnectUpdatePage.h @@ -14,8 +14,11 @@ // Define the AUTOCONNECT_URI_UPDATE page to select the sketch binary // for update and order update execution. const AutoConnectUpdate::ACElementProp_t AutoConnectUpdate::_elmCatalog[] PROGMEM = { + { AC_Element, "binSty", "", nullptr }, { AC_Text, "caption", nullptr, nullptr }, + { AC_Element, "c1", "
", nullptr }, { AC_Radio, "firmwares", nullptr, nullptr }, + { AC_Element, "c1", "
", nullptr }, { AC_Submit, "update", "UPDATE", AUTOCONNECT_URI_UPDATE_ACT } }; const AutoConnectUpdate::ACPage_t AutoConnectUpdate::_auxCatalog PROGMEM = {