You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
588 lines
21 KiB
588 lines
21 KiB
/**
|
|
* AutoConnectUpdate class implementation.
|
|
* @file AutoConnectUpdate.cpp
|
|
* @author hieromon@gmail.com
|
|
* @version 1.0.2
|
|
* @date 2019-09-18
|
|
* @copyright MIT license.
|
|
*/
|
|
|
|
#include "AutoConnectDefs.h"
|
|
|
|
#ifdef AUTOCONNECT_USE_UPDATE
|
|
|
|
#include <functional>
|
|
#include <type_traits>
|
|
#include "AutoConnectUpdate.h"
|
|
#include "AutoConnectUpdatePage.h"
|
|
#include "AutoConnectJsonDefs.h"
|
|
|
|
/**
|
|
* The AutoConnectUpdateAct class inherits from the HTTPupdate class. The
|
|
* update server corresponding to this class needs a simple script
|
|
* based on an HTTP server. It is somewhat different from the advanced
|
|
* updater script offered by Arduino core of ESP8266.
|
|
* The equipment required for the update server for the
|
|
* AutoConnectUpdateAct class is as follows:
|
|
*
|
|
* The catalog script:
|
|
* The update server URI /catalog is a script process that responds to
|
|
* queries from the AutoConnectUpdateAct class. The catalog script accepts
|
|
* the queries such as '/catalog?op=list&path='.
|
|
* - op:
|
|
* An op parameter specifies the query operation. In the current
|
|
* version, available query operation is a list only.
|
|
* - list:
|
|
* The query operation list responds with a list of available sketch
|
|
* binaries. The response of list is a directory list of file paths
|
|
* on the server specified by the path parameter and describes as a
|
|
* JSON document. Its JSON document is an array of JSON objects with
|
|
* the name and the type keys. For example, it is the following
|
|
* description:
|
|
* [
|
|
* {
|
|
* "name": "somefoler",
|
|
* "type": "directory"
|
|
* },
|
|
* {
|
|
* "name": "update.ino",
|
|
* "type": "file"
|
|
* },
|
|
* {
|
|
* "name": "update.bin",
|
|
* "type": "bin"
|
|
* }
|
|
* ]
|
|
* - name:
|
|
* Name of file entry on the path.
|
|
* - type:
|
|
* The type of the file. It defines either directory, file or bin.
|
|
* The bin means that the file is a sketch binary, and the
|
|
* AutoConnectUpdateAct class recognizes only files type bin as
|
|
* available update files.
|
|
* - path:
|
|
* A path parameter specifies the path on the server storing
|
|
* available sketch binaries.
|
|
*
|
|
* Access to the path on the server:
|
|
* It should have access to the bin file. The update server needs to
|
|
* send a bin file with a content type of application/octet-stream via
|
|
* HTTP and also needs to attach an MD5 hash value to the x-MD5 header.
|
|
*/
|
|
|
|
/**
|
|
* The following two templates absorb callbacks that are enabled/disabled
|
|
* by the Update library version in the core.
|
|
* The old UpdateClass of the ESP8266/ESP32 arduino core does not have
|
|
* the onProgress function for registering callbacks. These templates
|
|
* avoid the onProgress calls on older library versions.
|
|
* In versions where the update function callback is disabled, the
|
|
* dialog on the client browser does not show the progress of the update.
|
|
*/
|
|
#if defined(ARDUINO_ARCH_ESP8266)
|
|
using UpdateVariedClass = UpdaterClass;
|
|
#elif defined(ARDUINO_ARCH_ESP32)
|
|
using UpdateVariedClass = UpdateClass;
|
|
#endif
|
|
|
|
namespace AutoConnectUtil {
|
|
AC_HAS_FUNC(onProgress);
|
|
|
|
template<typename T>
|
|
typename std::enable_if<AutoConnectUtil::has_func_onProgress<T>::value, AutoConnectUpdateAct::AC_UPDATEDIALOG_t>::type onProgress(T& updater, UpdateVariedClass::THandlerFunction_Progress fn) {
|
|
updater.onProgress(fn);
|
|
AC_DBG("Updater keeps callback\n");
|
|
return AutoConnectUpdateAct::UPDATEDIALOG_METER;
|
|
}
|
|
|
|
template<typename T>
|
|
typename std::enable_if<!AutoConnectUtil::has_func_onProgress<T>::value, AutoConnectUpdateAct::AC_UPDATEDIALOG_t>::type onProgress(T& updater, UpdateVariedClass::THandlerFunction_Progress fn) {
|
|
(void)(updater);
|
|
(void)(fn);
|
|
return AutoConnectUpdateAct::UPDATEDIALOG_LOADER;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Definitions of notification commands to synchronize update processing
|
|
* with the Web client.
|
|
*/
|
|
#define UPDATE_NOTIFY_START "#s"
|
|
#define UPDATE_NOTIFY_PROGRESS "#p"
|
|
#define UPDATE_NOTIFY_END "#e"
|
|
#define UPDATE_NOTIFY_REBOOT "#r"
|
|
|
|
/**
|
|
* A destructor. Release the update processing dialogue page generated
|
|
* as AutoConnectAux.
|
|
*/
|
|
AutoConnectUpdateAct::~AutoConnectUpdateAct() {
|
|
_auxCatalog.reset(nullptr);
|
|
_auxProgress.reset(nullptr);
|
|
_auxResult.reset(nullptr);
|
|
}
|
|
|
|
/**
|
|
* Attach the AutoConnectUpdateAct to the AutoConnect which constitutes
|
|
* the bedrock of the update process. This function creates dialog pages
|
|
* for update operation as an instance of AutoConnectAux and joins to
|
|
* the AutoConnect which is the bedrock of the process.
|
|
* @param portal A reference of AutoConnect
|
|
*/
|
|
void AutoConnectUpdateAct::attach(AutoConnect& portal) {
|
|
AutoConnectAux* updatePage;
|
|
|
|
updatePage = new AutoConnectAux(String(FPSTR(_pageCatalog.uri)), String(FPSTR(_pageCatalog.title)), _pageCatalog.menu);
|
|
_buildAux(updatePage, &_pageCatalog, lengthOf(_elmCatalog));
|
|
_auxCatalog.reset(updatePage);
|
|
|
|
updatePage = new AutoConnectAux(String(FPSTR(_pageProgress.uri)), String(FPSTR(_pageProgress.title)), _pageProgress.menu);
|
|
_buildAux(updatePage, &_pageProgress, lengthOf(_elmProgress));
|
|
_auxProgress.reset(updatePage);
|
|
|
|
updatePage = new AutoConnectAux(String(FPSTR(_pageResult.uri)), String(FPSTR(_pageResult.title)), _pageResult.menu);
|
|
_buildAux(updatePage, &_pageResult, lengthOf(_elmResult));
|
|
_auxResult.reset(updatePage);
|
|
|
|
_auxCatalog->on(std::bind(&AutoConnectUpdateAct::_onCatalog, this, std::placeholders::_1, std::placeholders::_2), AC_EXIT_AHEAD);
|
|
_auxProgress->on(std::bind(&AutoConnectUpdateAct::_onUpdate, this, std::placeholders::_1, std::placeholders::_2), AC_EXIT_AHEAD);
|
|
_auxResult->on(std::bind(&AutoConnectUpdateAct::_onResult, this, std::placeholders::_1, std::placeholders::_2), AC_EXIT_AHEAD);
|
|
|
|
portal.join(*_auxCatalog.get());
|
|
portal.join(*_auxProgress.get());
|
|
portal.join(*_auxResult.get());
|
|
|
|
// Register the callback to inform the update progress
|
|
_dialog = AutoConnectUtil::onProgress<UpdateVariedClass>(Update, std::bind(&AutoConnectUpdateAct::_inProgress, this, std::placeholders::_1, std::placeholders::_2));
|
|
// Adjust the client dialog pattern according to the callback validity
|
|
// of the UpdateClass.
|
|
AutoConnectElement* loader = _auxProgress->getElement(String(F("loader")));
|
|
AutoConnectElement* progress_meter = _auxProgress->getElement(String(F("progress_meter")));
|
|
AutoConnectElement* progress_loader = _auxProgress->getElement(String(F("progress_loader")));
|
|
AutoConnectElement* enable_loader = _auxProgress->getElement(String(F("enable_loader")));
|
|
AutoConnectElement* inprogress_meter = _auxProgress->getElement(String(F("inprogress_meter")));
|
|
switch (_dialog) {
|
|
case UPDATEDIALOG_LOADER:
|
|
progress_meter->enable =false;
|
|
inprogress_meter->enable = false;
|
|
break;
|
|
case UPDATEDIALOG_METER:
|
|
loader->enable = false;
|
|
progress_loader->enable =false;
|
|
enable_loader->enable =false;
|
|
break;
|
|
}
|
|
|
|
// Attach this to the AutoConnectUpdateAct
|
|
portal._update.reset(this);
|
|
AC_DBG("AutoConnectUpdate attached\n");
|
|
if (WiFi.status() == WL_CONNECTED)
|
|
enable();
|
|
|
|
// Attach the update progress monitoring handler
|
|
_webServer = &(portal.host());
|
|
_webServer->on(String(F(AUTOCONNECT_URI_UPDATE_PROGRESS)), HTTP_ANY, std::bind(&AutoConnectUpdateAct::_progress, this));
|
|
|
|
// Reset the update progress status
|
|
_status = UPDATE_IDLE;
|
|
}
|
|
|
|
/**
|
|
* Detach the update item from the current AutoConnect menu.
|
|
* AutoConnectUpdateAct still active.
|
|
*/
|
|
void AutoConnectUpdateAct::disable(const bool activate) {
|
|
_enable = activate;
|
|
if (_auxCatalog) {
|
|
_auxCatalog->menu(false);
|
|
AC_DBG("AutoConnectUpdate disabled\n");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Make AutoConnectUpdateAct class available by incorporating the update
|
|
* function into the menu.
|
|
*/
|
|
void AutoConnectUpdateAct::enable(void) {
|
|
_enable = true;
|
|
_status = UPDATE_IDLE;
|
|
if (_auxCatalog) {
|
|
_auxCatalog->menu(WiFi.status() == WL_CONNECTED);
|
|
AC_DBG("AutoConnectUpdate enabled\n");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* An entry point of the process loop as AutoConnect::handleClient.
|
|
* The handleClient function of the AutoConnect that later accompanied
|
|
* the AutoConnectUpdate class will invoke this entry.
|
|
* This entry point will be called from the process loop of handleClient
|
|
* function only if the class is associated with the AutoConnect class.
|
|
*/
|
|
void AutoConnectUpdateAct::handleUpdate(void) {
|
|
// Activate the update menu conditional with WiFi connected.
|
|
if (!isEnabled() && _enable) {
|
|
if (WiFi.status() == WL_CONNECTED)
|
|
enable();
|
|
}
|
|
|
|
if (isEnabled()) {
|
|
if (WiFi.status() == WL_CONNECTED) {
|
|
// Evaluate the processing status of AutoConnectUpdateAct and
|
|
// execute it accordingly. It is only this process point that
|
|
// requests update processing.
|
|
if (_status == UPDATE_START) {
|
|
_status = UPDATE_PROGRESS;
|
|
update();
|
|
}
|
|
else if (_status == UPDATE_RESET) {
|
|
AC_DBG("Restart on %s updated...\n", _binName.c_str());
|
|
ESP.restart();
|
|
}
|
|
}
|
|
// If WiFi is not connected, disables the update menu.
|
|
// However, the AutoConnectUpdateAct class stills active.
|
|
else
|
|
disable(_enable);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Run the update function of HTTPUpdate that is the base class and
|
|
* fetch the result.
|
|
* @return AC_UPDATESTATUS_t
|
|
*/
|
|
AC_UPDATESTATUS_t AutoConnectUpdateAct::update(void) {
|
|
// Start update
|
|
String uriBin = uri + '/' + _binName;
|
|
if (_binName.length()) {
|
|
WiFiClient wifiClient;
|
|
AC_DBG("%s:%d/%s update in progress...", host.c_str(), port, uriBin.c_str());
|
|
t_httpUpdate_return ret = HTTPUpdateClass::update(wifiClient, host, port, uriBin);
|
|
switch (ret) {
|
|
case HTTP_UPDATE_FAILED:
|
|
_status = UPDATE_FAIL;
|
|
AC_DBG_DUMB(" %s\n", getLastErrorString().c_str());
|
|
AC_DBG("update returns HTTP_UPDATE_FAILED\n");
|
|
break;
|
|
case HTTP_UPDATE_NO_UPDATES:
|
|
_status = UPDATE_IDLE;
|
|
AC_DBG_DUMB(" No available update\n");
|
|
break;
|
|
case HTTP_UPDATE_OK:
|
|
_status = UPDATE_SUCCESS;
|
|
AC_DBG_DUMB(" completed\n");
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
AC_DBG("An update has not specified");
|
|
_status = UPDATE_NOAVAIL;
|
|
}
|
|
return _status;
|
|
}
|
|
|
|
/**
|
|
* Create the update operation pages using a predefined page structure
|
|
* with two structures as ACPage_t and ACElementProp_t which describe
|
|
* for AutoConnectAux configuration.
|
|
* This function receives instantiated AutoConnectAux, instantiates
|
|
* defined AutoConnectElements by ACPage_t, and configures it into
|
|
* received AutoConnectAux.
|
|
* @param aux An instantiated AutoConnectAux that will configure according to ACPage_t.
|
|
* @param page Pre-defined ACPage_t
|
|
* @param elementNum Number of AutoConnectElements to configure.
|
|
*/
|
|
void AutoConnectUpdateAct::_buildAux(AutoConnectAux* aux, const AutoConnectUpdateAct::ACPage_t* page, const size_t elementNum) {
|
|
for (size_t n = 0; n < elementNum; n++) {
|
|
if (page->element[n].type == AC_Element) {
|
|
AutoConnectElement* element = new AutoConnectElement;
|
|
element->name = String(FPSTR(page->element[n].name));
|
|
if (page->element[n].value)
|
|
element->value = String(FPSTR(page->element[n].value));
|
|
aux->add(reinterpret_cast<AutoConnectElement&>(*element));
|
|
}
|
|
else if (page->element[n].type == AC_Radio) {
|
|
AutoConnectRadio* element = new AutoConnectRadio;
|
|
element->name = String(FPSTR(page->element[n].name));
|
|
aux->add(reinterpret_cast<AutoConnectElement&>(*element));
|
|
}
|
|
else if (page->element[n].type == AC_Submit) {
|
|
AutoConnectSubmit* element = new AutoConnectSubmit;
|
|
element->name = String(FPSTR(page->element[n].name));
|
|
if (page->element[n].value)
|
|
element->value = String(FPSTR(page->element[n].value));
|
|
if (page->element[n].peculiar)
|
|
element->uri = String(FPSTR(page->element[n].peculiar));
|
|
aux->add(reinterpret_cast<AutoConnectElement&>(*element));
|
|
}
|
|
else if (page->element[n].type == AC_Text) {
|
|
AutoConnectText* element = new AutoConnectText;
|
|
element->name = String(FPSTR(page->element[n].name));
|
|
if (page->element[n].value)
|
|
element->value = String(FPSTR(page->element[n].value));
|
|
if (page->element[n].peculiar)
|
|
element->format = String(FPSTR(page->element[n].peculiar));
|
|
aux->add(reinterpret_cast<AutoConnectText&>(*element));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* An update callback function in HTTPUpdate::update.
|
|
* This callback handler acts as an HTTPUpdate::update callback and
|
|
* sends the updated amount over the web socket to advance the progress
|
|
* of the progress meter displayed in the browser.
|
|
* @param amount Already transferred size.
|
|
* @param size Total size of the binary to update.
|
|
*/
|
|
void AutoConnectUpdateAct::_inProgress(size_t amount, size_t size) {
|
|
_amount = amount;
|
|
_binSize = size;
|
|
_webServer->handleClient();
|
|
}
|
|
|
|
/**
|
|
* AUTOCONNECT_URI_UPDATE page handler.
|
|
* It queries the update server for cataloged sketch binary and
|
|
* displays the result on the page as an available updater list.
|
|
* The update execution button held by this page will be enabled only
|
|
* when there are any available updaters.
|
|
* @param catalog A reference of the AutoConnectAux as AUTOCONNECT_URI_UPDATE
|
|
* @param args A reference of the PageArgument of the PageBuilder
|
|
* @return Additional string to the page but it always null.
|
|
*/
|
|
String AutoConnectUpdateAct::_onCatalog(AutoConnectAux& catalog, PageArgument& args) {
|
|
AC_UNUSED(args);
|
|
WiFiClient wifiClient;
|
|
HTTPClient httpClient;
|
|
|
|
// Reallocate available firmwares list.
|
|
_binName = String("");
|
|
AutoConnectText& caption = catalog.getElement<AutoConnectText>(String(F("caption")));
|
|
AutoConnectRadio& firmwares = catalog.getElement<AutoConnectRadio>(String(F("firmwares")));
|
|
AutoConnectSubmit& submit = catalog.getElement<AutoConnectSubmit>(String(F("update")));
|
|
firmwares.empty();
|
|
firmwares.tags.clear();
|
|
submit.enable = false;
|
|
|
|
String qs = String(F(AUTOCONNECT_UPDATE_CATALOG)) + '?' + String(F("op=list&path=")) + uri;
|
|
AC_DBG("Query %s:%d%s\n", host.c_str(), port, qs.c_str());
|
|
|
|
// Throw a query to the update server and parse the response JSON
|
|
// document. After that, display the bin type file name contained in
|
|
// its JSON document as available updaters to the page.
|
|
if (httpClient.begin(wifiClient, host, port, qs)) {
|
|
int responseCode = httpClient.GET();
|
|
if (responseCode == HTTP_CODE_OK) {
|
|
|
|
// JsonVariant jb;
|
|
bool parse;
|
|
char beginOfList[] = "[";
|
|
char endOfEntry[] = ",";
|
|
char endOfList[] = "]";
|
|
WiFiClient& 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<AUTOCONNECT_UPDATE_CATALOG_JSONBUFFER_SIZE> jb;
|
|
|
|
#if ARDUINOJSON_VERSION_MAJOR<=5
|
|
ArduinoJsonObject json = jb.parseObject(responseBody);
|
|
parse = json.success();
|
|
#else
|
|
DeserializationError err = deserializeJson(jb, responseBody);
|
|
ArduinoJsonObject json = jb.as<JsonObject>();
|
|
parse = (err == DeserializationError::Ok);
|
|
#endif
|
|
if (parse) {
|
|
#ifdef AC_DEBUG
|
|
AC_DBG_DUMB("\n");
|
|
ARDUINOJSON_PRINT(json, 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<String>().equalsIgnoreCase("bin")) {
|
|
firmwares.add(json[F("name")].as<String>());
|
|
String attr = String(F("<span>")) + json[F("date")].as<String>() + String(F("</span><span>")) + json[F("time")].as<String>().substring(0, 5) + String(F("</span><span>")) + String(json[F("size")].as<int>()) + String(F("</span>"));
|
|
firmwares.tags.push_back(attr);
|
|
}
|
|
}
|
|
else {
|
|
#if ARDUINOJSON_VERSION_MAJOR<=5
|
|
String errCaption = String(F("JSON parse error"));
|
|
#else
|
|
String errCaption = String(err.c_str());
|
|
#endif
|
|
caption.value = String(F("Invalid catalog list:")) + errCaption;
|
|
AC_DBG("JSON:%s\n", errCaption.c_str());
|
|
break;
|
|
}
|
|
} while (responseBody.findUntil(endOfEntry, endOfList));
|
|
|
|
AC_DBG_DUMB("\n");
|
|
if (parse) {
|
|
if (firmwares.size()) {
|
|
caption.value = String(F("<h4>Available firmwares</h4>"));
|
|
submit.enable = true;
|
|
}
|
|
else
|
|
caption.value = String(F("<h4>No available firmwares</h4>"));
|
|
}
|
|
}
|
|
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 {
|
|
caption.value = String(F("http failed connect to ")) + host + String(':') + String(port);
|
|
AC_DBG("%s\n", caption.value.c_str());
|
|
}
|
|
|
|
_status = UPDATE_IDLE;
|
|
return String("");
|
|
}
|
|
|
|
/**
|
|
* AUTOCONNECT_URI_UPDATE_ACT page handler
|
|
* Only display a dialog indicating that the update is in progress.
|
|
* @param progress A reference of the AutoConnectAux as AUTOCONNECT_URI_UPDATE_ACT
|
|
* @param args A reference of the PageArgument of the PageBuilder
|
|
* @return Additional string to the page but it always null.
|
|
*/
|
|
String AutoConnectUpdateAct::_onUpdate(AutoConnectAux& progress, PageArgument& args) {
|
|
AC_UNUSED(args);
|
|
|
|
// Constructs the dialog page.
|
|
AutoConnectElement* binName = progress.getElement(String(F("binname")));
|
|
_binName = _auxCatalog->getElement<AutoConnectRadio>(String(F("firmwares"))).value();
|
|
binName->value = _binName;
|
|
AutoConnectElement* url = progress.getElement(String("url"));
|
|
url->value = host + ':' + port;
|
|
return String("");
|
|
}
|
|
|
|
/**
|
|
* AUTOCONNECT_URI_UPDATE_RESULT page handler
|
|
* Display the result of the update function of HTTPUpdate class.
|
|
* @param result A reference of the AutoConnectAux as AUTOCONNECT_URI_UPDATE_RESULT
|
|
* @param args A reference of the PageArgument of the PageBuilder
|
|
* @return Additional string to the page but it always null.
|
|
*/
|
|
String AutoConnectUpdateAct::_onResult(AutoConnectAux& result, PageArgument& args) {
|
|
AC_UNUSED(args);
|
|
String resForm;
|
|
String resColor;
|
|
bool restart = false;
|
|
|
|
switch (_status) {
|
|
case UPDATE_SUCCESS:
|
|
resForm = String(F(" sucessfully updated. restart..."));
|
|
resColor = String(F("blue"));
|
|
restart = true;
|
|
break;
|
|
case UPDATE_FAIL:
|
|
resForm = String(F(" failed."));
|
|
resForm += String(F("<br>")) + getLastErrorString();
|
|
resColor = String(F("red"));
|
|
break;
|
|
default:
|
|
resForm = String(F("<br>No available update."));
|
|
resColor = String(F("red"));
|
|
break;
|
|
}
|
|
AutoConnectText& resultElm = result.getElement<AutoConnectText>(String(F("status")));
|
|
resultElm.value = _binName + resForm;
|
|
resultElm.style = String(F("font-size:120%;color:")) + resColor;
|
|
result.getElement<AutoConnectElement>(String(F("restart"))).enable = restart;
|
|
|
|
return String("");
|
|
}
|
|
|
|
/**
|
|
* A handler for notifying the client of the progress of update processing.
|
|
* This handler specifies the URI behavior defined as THndlerFunc of
|
|
* ESP8266 WebServer (WebServer for ESP32).
|
|
* Usually, that URI is /_ac/update_progress and will return the
|
|
* processed amount of update processing to the client.
|
|
*/
|
|
void AutoConnectUpdateAct::_progress(void) {
|
|
String reqOperation = "op";
|
|
String reqOperand;
|
|
String payload = String("");
|
|
int httpCode;
|
|
static const char reply_msg_op[] PROGMEM = "invalid operation";
|
|
static const char reply_msg_seq[] PROGMEM = "invalid sequence";
|
|
static const char reply_msg_inv[] PROGMEM = "invalid request";
|
|
static const char* content_type = "text/plain";
|
|
|
|
switch (_webServer->method()) {
|
|
|
|
case HTTP_POST:
|
|
reqOperand = _webServer->arg(reqOperation);
|
|
switch (_status) {
|
|
case UPDATE_IDLE:
|
|
if (reqOperand == String(UPDATE_NOTIFY_START)) {
|
|
httpCode = 200;
|
|
_status = UPDATE_START;
|
|
}
|
|
else {
|
|
payload = String(FPSTR(reply_msg_seq));
|
|
httpCode = 500;
|
|
}
|
|
break;
|
|
case UPDATE_SUCCESS:
|
|
if (reqOperand == String(UPDATE_NOTIFY_REBOOT)) {
|
|
_status = UPDATE_RESET;
|
|
httpCode = 200;
|
|
}
|
|
else {
|
|
payload = String(FPSTR(reply_msg_seq));
|
|
httpCode = 500;
|
|
}
|
|
break;
|
|
default:
|
|
payload = String(FPSTR(reply_msg_op));
|
|
httpCode = 500;
|
|
}
|
|
break;
|
|
|
|
case HTTP_GET:
|
|
switch (_status) {
|
|
case UPDATE_PROGRESS:
|
|
payload = String(UPDATE_NOTIFY_PROGRESS) + ',' + String(_amount) + ':' + String(_binSize);
|
|
httpCode = 200;
|
|
break;
|
|
case UPDATE_IDLE:
|
|
case UPDATE_SUCCESS:
|
|
case UPDATE_NOAVAIL:
|
|
case UPDATE_FAIL:
|
|
payload = String(UPDATE_NOTIFY_END);
|
|
httpCode = 200;
|
|
break;
|
|
default:
|
|
payload = String(FPSTR(reply_msg_seq));
|
|
httpCode = 500;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
httpCode = 500;
|
|
payload = String(FPSTR(reply_msg_inv));
|
|
}
|
|
|
|
_webServer->send(httpCode, content_type, payload);
|
|
}
|
|
|
|
#endif // !AUTOCONNECT_USE_UPDATE
|
|
|