From 40cb4cf8e041d425703cd48e9b35f64e87fccc56 Mon Sep 17 00:00:00 2001 From: Hieromon Ikasamo Date: Tue, 25 Jun 2019 15:23:24 +0900 Subject: [PATCH] AutoConnectUpdate-rc2 Abolished WebSocket in-process notification for update progress notification. Its method consumes too much memory on the ESP8266. Replace with Ajax. --- src/AutoConnectDefs.h | 35 +++-- src/AutoConnectUpdate.cpp | 283 +++++++++++++++++++----------------- src/AutoConnectUpdate.h | 66 +++++---- src/AutoConnectUpdatePage.h | 23 ++- 4 files changed, 223 insertions(+), 184 deletions(-) diff --git a/src/AutoConnectDefs.h b/src/AutoConnectDefs.h index b6e502e..b4d97df 100644 --- a/src/AutoConnectDefs.h +++ b/src/AutoConnectDefs.h @@ -90,8 +90,9 @@ #define AUTOCONNECT_URI_SUCCESS AUTOCONNECT_URI "/success" #define AUTOCONNECT_URI_FAIL AUTOCONNECT_URI "/fail" #define AUTOCONNECT_URI_UPDATE AUTOCONNECT_URI "/update" -#define AUTOCONNECT_URI_UPDATE_ACT AUTOCONNECT_URI "/update_act" -#define AUTOCONNECT_URI_UPDATE_RESULT AUTOCONNECT_URI "/update_result" +#define AUTOCONNECT_URI_UPDATE_ACT AUTOCONNECT_URI "/update_act" +#define AUTOCONNECT_URI_UPDATE_PROGRESS AUTOCONNECT_URI "/update_progress" +#define AUTOCONNECT_URI_UPDATE_RESULT AUTOCONNECT_URI "/update_result" // Time-out limitation when AutoConnect::begin [ms] #ifndef AUTOCONNECT_TIMEOUT @@ -138,7 +139,7 @@ #define AUTOCONNECT_SSIDPAGEUNIT_LINES 5 #endif // !AUTOCONNECT_SSIDPAGEUNIT_LINES -// SPI transfer speed for SD +// SPI transfer speed for SD [Hz] #ifndef AUTOCONNECT_SD_SPEED #define AUTOCONNECT_SD_SPEED 4000000 #endif // !AUTOCONNECT_SD_SPEED @@ -154,20 +155,39 @@ #define AUTOCONNECT_JSONPSRAM_SIZE (16* 1024) #endif // !AUTOCONNECT_JSONPSRAM_SIZE -// Available HTTP port number for the update +// Available HTTP port number for the update [ms] #ifndef AUTOCONNECT_UPDATE_PORT #define AUTOCONNECT_UPDATE_PORT 8000 #endif // !AUTOCONNECT_UPDATE_PORT -// HTTP client timeout limitation for the update +// HTTP client timeout limitation for the update [ms] #ifndef AUTOCONNECT_UPDATE_TIMEOUT #define AUTOCONNECT_UPDATE_TIMEOUT 8000 #endif // !AUTOCONNECT_UPDATE_TIMEOUT +// Maximum wait time until transitioning AutoConnectUpdate dialog page [ms] #ifndef AUTOCONNECT_UPDATE_DURATION #define AUTOCONNECT_UPDATE_DURATION 180000 #endif // !AUTOCONNECT_UPDATE_DURATION +// Interval time of progress status periodical inquiry [ms] +#ifndef AUTOCONNECT_UPDATE_INTERVAL +#define AUTOCONNECT_UPDATE_INTERVAL 400 +#endif // !AUTOCONNECT_UPDATE_INTERVAL + +// Wait timer for rebooting after updated +#ifndef AUTOCONNECT_UPDATE_WAITFORREBOOT +#define AUTOCONNECT_UPDATE_WAITFORREBOOT 9000 +#endif // !AUTOCONNECT_UPDATE_WAITFORREBOOT + +// A signal value that the board dependent LED turns on. +// As a typical example, the ON signal of built-in LED such as the +// NodeMCU is LOW and the HIGH for the NodeMCU-32S as another example. +#ifndef AUTOCONNECT_UPDATE_LEDON +// #define AUTOCONNECT_UPDATE_LEDON HIGH +#define AUTOCONNECT_UPDATE_LEDON LOW +#endif // !AUTOCONNECT_UPDATE_LEDON + // URIs of the behaviors owned by the update server #ifndef AUTOCONNECT_UPDATE_CATALOG #define AUTOCONNECT_UPDATE_CATALOG "/_catalog" @@ -179,11 +199,6 @@ #define AUTOCONNECT_UPDATE_CATALOG_JSONBUFFER_SIZE 256 #endif // !AUTOCONNECT_UPDATE_CATALOG_JSONBUFFER_SIZE -// Default WebSocket port for the update progress measur -#ifndef AUTOCONNECT_WEBSOCKETPORT -#define AUTOCONNECT_WEBSOCKETPORT 81 -#endif // !AUTOCONNECT_WEBSOCKETPORT - // Explicitly avoiding unused warning with token handler of PageBuilder #define AC_UNUSED(expr) do { (void)(expr); } while (0) diff --git a/src/AutoConnectUpdate.cpp b/src/AutoConnectUpdate.cpp index 18e74b7..6058d09 100644 --- a/src/AutoConnectUpdate.cpp +++ b/src/AutoConnectUpdate.cpp @@ -30,7 +30,7 @@ * queries from the AutoConnectUpdateAct class. The catalog script accepts * the queries such as '/catalog?op=list&path='. * - op: - * An op parameter speicies the query operation. In the current + * 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 @@ -90,15 +90,9 @@ AC_HAS_FUNC(onProgress); template typename std::enable_if::value, AutoConnectUpdateAct::AC_UPDATEDIALOG_t>::type onProgress(T& updater, UpdateVariedClass::THandlerFunction_Progress fn) { -#if defined(ARDUINO_ARCH_ESP32) || (defined(ARDUINO_ARCH_ESP8266) && (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)) updater.onProgress(fn); AC_DBG("Updater keeps callback\n"); return AutoConnectUpdateAct::UPDATEDIALOG_METER; -#else - (void)(updater); - (void)(fn); - return AutoConnectUpdateAct::UPDATEDIALOG_LOADER; -#endif } template @@ -109,15 +103,23 @@ typename std::enable_if::value, AutoCon } } +/** + * 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() { - _catalog.reset(nullptr); - _progress.reset(nullptr); - _result.reset(nullptr); - _ws.reset(nullptr); + _auxCatalog.reset(nullptr); + _auxProgress.reset(nullptr); + _auxResult.reset(nullptr); } /** @@ -130,44 +132,35 @@ AutoConnectUpdateAct::~AutoConnectUpdateAct() { void AutoConnectUpdateAct::attach(AutoConnect& portal) { AutoConnectAux* updatePage; - updatePage = new AutoConnectAux(String(FPSTR(_auxCatalog.uri)), String(FPSTR(_auxCatalog.title)), _auxCatalog.menu); - _buildAux(updatePage, &_auxCatalog, lengthOf(_elmCatalog)); - _catalog.reset(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(_auxProgress.uri)), String(FPSTR(_auxProgress.title)), _auxProgress.menu); - _buildAux(updatePage, &_auxProgress, lengthOf(_elmProgress)); - _progress.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(_auxResult.uri)), String(FPSTR(_auxResult.title)), _auxResult.menu); - _buildAux(updatePage, &_auxResult, lengthOf(_elmResult)); - _result.reset(updatePage); + updatePage = new AutoConnectAux(String(FPSTR(_pageResult.uri)), String(FPSTR(_pageResult.title)), _pageResult.menu); + _buildAux(updatePage, &_pageResult, lengthOf(_elmResult)); + _auxResult.reset(updatePage); - _catalog->on(std::bind(&AutoConnectUpdateAct::_onCatalog, this, std::placeholders::_1, std::placeholders::_2), AC_EXIT_AHEAD); - _progress->on(std::bind(&AutoConnectUpdateAct::_onUpdate, this, std::placeholders::_1, std::placeholders::_2), AC_EXIT_AHEAD); - _result->on(std::bind(&AutoConnectUpdateAct::_onResult, this, std::placeholders::_1, std::placeholders::_2), AC_EXIT_AHEAD); + _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(*_catalog.get()); - portal.join(*_progress.get()); - portal.join(*_result.get()); - - _status = UPDATE_IDLE; - - // Attach this to the AutoConnectUpdateAct - portal._update.reset(this); - AC_DBG("AutoConnectUpdate attached\n"); - if (WiFi.status() == WL_CONNECTED) - enable(); + portal.join(*_auxCatalog.get()); + portal.join(*_auxProgress.get()); + portal.join(*_auxResult.get()); // Register the callback to inform the update progress _dialog = AutoConnectUtil::onProgress(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 = _progress->getElement(String(F("loader"))); - AutoConnectElement* enable_loader = _progress->getElement(String(F("enable_loader"))); - AutoConnectElement* progress_meter = _progress->getElement(String(F("progress_meter"))); - AutoConnectElement* inprogress_meter = _progress->getElement(String(F("inprogress_meter"))); - AutoConnectElement* progress_loader = _progress->getElement(String(F("progress_loader"))); - AutoConnectElement* inprogress_loader = _progress->getElement(String(F("inprogress_loader"))); + 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; @@ -175,11 +168,23 @@ void AutoConnectUpdateAct::attach(AutoConnect& portal) { break; case UPDATEDIALOG_METER: loader->enable = false; - enable_loader->enable =false; progress_loader->enable =false; - inprogress_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; } /** @@ -188,8 +193,8 @@ void AutoConnectUpdateAct::attach(AutoConnect& portal) { */ void AutoConnectUpdateAct::disable(const bool activate) { _enable = activate; - if (_catalog) { - _catalog->menu(false); + if (_auxCatalog) { + _auxCatalog->menu(false); AC_DBG("AutoConnectUpdate disabled\n"); } } @@ -201,12 +206,19 @@ void AutoConnectUpdateAct::disable(const bool activate) { void AutoConnectUpdateAct::enable(void) { _enable = true; _status = UPDATE_IDLE; - if (_catalog) { - _catalog->menu(WiFi.status() == WL_CONNECTED); + 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 (!isEnable() && _enable) { @@ -220,21 +232,8 @@ void AutoConnectUpdateAct::handleUpdate(void) { // execute it accordingly. It is only this process point that // requests update processing. if (_status == UPDATE_START) { - AC_DBG("Waiting for WS connection\n"); - unsigned long tm = millis(); - while (!_wsConnected) { - if (millis() - tm > AUTOCONNECT_TIMEOUT) { - AC_DBG("WebSocket client connection timeout, update ignored\n"); - break; - } - _ws->loop(); // Crawl the connection request. - yield(); - } - // Launch the update - if (_wsConnected) - update(); - else - _status = UPDATE_IDLE; + _status = UPDATE_PROGRESS; + update(); } else if (_status == UPDATE_RESET) { AC_DBG("Restart on %s updated...\n", _binName.c_str()); @@ -257,13 +256,9 @@ AC_UPDATESTATUS_t AutoConnectUpdateAct::update(void) { // Start update String uriBin = uri + '/' + _binName; if (_binName.length()) { - AC_DBG("%s:%d/%s update in progress...", host.c_str(), port, uriBin.c_str()); -#if defined(ARDUINO_ARCH_ESP8266) - t_httpUpdate_return ret = HTTPUpdateClass::update(host, port, uriBin); -#elif defined(ARDUINO_ARCH_ESP32) 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); -#endif switch (ret) { case HTTP_UPDATE_FAILED: _status = UPDATE_FAIL; @@ -279,8 +274,6 @@ AC_UPDATESTATUS_t AutoConnectUpdateAct::update(void) { AC_DBG_DUMB(" completed\n"); break; } - // Request the client to close the WebSocket. - _ws->sendTXT(_wsClient, "#e"); } else { AC_DBG("An update has not specified"); @@ -335,6 +328,20 @@ void AutoConnectUpdateAct::_buildAux(AutoConnectAux* aux, const AutoConnectUpdat } } +/** + * 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 @@ -347,7 +354,8 @@ void AutoConnectUpdateAct::_buildAux(AutoConnectAux* aux, const AutoConnectUpdat */ String AutoConnectUpdateAct::_onCatalog(AutoConnectAux& catalog, PageArgument& args) { AC_UNUSED(args); - HTTPClient httpClient; + WiFiClient wifiClient; + HTTPClient httpClient; // Reallocate available firmwares list. _binName = String(""); @@ -364,11 +372,11 @@ String AutoConnectUpdateAct::_onCatalog(AutoConnectAux& catalog, PageArgument& a // 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(host, port, qs)) { + if (httpClient.begin(wifiClient, host, port, qs)) { int responseCode = httpClient.GET(); if (responseCode == HTTP_CODE_OK) { - JsonVariant jb; + // JsonVariant jb; bool parse; char beginOfList[] = "["; char endOfEntry[] = ","; @@ -437,6 +445,7 @@ String AutoConnectUpdateAct::_onCatalog(AutoConnectAux& catalog, PageArgument& a AC_DBG("%s\n", caption.value.c_str()); } + _status = UPDATE_IDLE; return String(""); } @@ -449,26 +458,13 @@ String AutoConnectUpdateAct::_onCatalog(AutoConnectAux& catalog, PageArgument& a */ String AutoConnectUpdateAct::_onUpdate(AutoConnectAux& progress, PageArgument& args) { AC_UNUSED(args); - // launch the WebSocket server - _ws.reset(new WebSocketsServer(AUTOCONNECT_WEBSOCKETPORT)); - if (_ws) { - _ws->begin(); - _ws->onEvent(std::bind(&AutoConnectUpdateAct::_wsEvent, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); - } - else - AC_DBG("WebSocketsServer allocation failed\n"); // Constructs the dialog page. AutoConnectElement* binName = progress.getElement(String(F("binname"))); - _binName = _catalog->getElement(String(F("firmwares"))).value(); + _binName = _auxCatalog->getElement(String(F("firmwares"))).value(); binName->value = _binName; AutoConnectElement* url = progress.getElement(String("url")); url->value = host + ':' + port; - AutoConnectElement* wsurl = progress.getElement(String(F("wsurl"))); - wsurl->value = "ws://" + WiFi.localIP().toString() + ':' + AUTOCONNECT_WEBSOCKETPORT; - AC_DBG("Cast WS %s\n", wsurl->value.c_str()); - _wsConnected = false; - _status = UPDATE_START; return String(""); } @@ -485,19 +481,6 @@ String AutoConnectUpdateAct::_onResult(AutoConnectAux& result, PageArgument& arg String resColor; bool restart = false; - if (_ws) { - _ws->loop(); - while (_wsConnected) { - IPAddress ipAny; - if (_ws->remoteIP(_wsClient) == ipAny) - _wsConnected = false; - else - _ws->close(); - yield(); - } - _ws.reset(nullptr); - } - switch (_status) { case UPDATE_SUCCESS: resForm = String(F(" sucessfully updated. restart...")); @@ -518,48 +501,84 @@ String AutoConnectUpdateAct::_onResult(AutoConnectAux& result, PageArgument& arg resultElm.value = _binName + resForm; resultElm.style = String(F("font-size:120%;color:")) + resColor; result.getElement(String(F("restart"))).enable = restart; - if (restart) - _status = UPDATE_RESET; return String(""); } /** - * 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. + * 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::_inProgress(size_t amount, size_t size) { - if (_ws) { - _amount = amount; - _binSize = size; - String payload = "#p," + String(_amount) + ':' + String(_binSize); - _ws->sendTXT(_wsClient, payload); - } -} +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: + if (_webServer->hasArg(reqOperation)) { + reqOperand = _webServer->arg(reqOperation); + if (reqOperand == String(UPDATE_NOTIFY_START)) { + if (_status == UPDATE_IDLE) { + httpCode = 200; + _status = UPDATE_START; + } + else { + payload = String(FPSTR(reply_msg_seq)); + httpCode = 500; + } + } + else if (reqOperand == String(UPDATE_NOTIFY_REBOOT)) { + if (_status == UPDATE_SUCCESS) { + _status = UPDATE_RESET; + httpCode = 200; + } + else { + payload = String(FPSTR(reply_msg_seq)); + httpCode = 500; + } + } + } + else { + payload = String(FPSTR(reply_msg_op)); + httpCode = 500; + } + break; -/** - * An event handler of WebSocket which should be opened to monitor - * update progress. AutoConnectUpdate will send #s to start the update - * progress notification to the client when the WebSocket client - * connected. This has the meaning of ACK. - * @param client WS client number of WebSocketsServer - * @param event Event id - * @param payload Payload content - * @param length payload length - */ -void AutoConnectUpdateAct::_wsEvent(uint8_t client, WStype_t event, uint8_t* payload, size_t length) { - AC_DBG("WS client:%d event(%d)\n", client, event); - if (event == WStype_CONNECTED) { - _wsConnected = true; - _wsClient = client; - _ws->sendTXT(_wsClient, "#s"); + 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)); } - else if (event == WStype_DISCONNECTED) - _wsConnected = false; + + _webServer->send(httpCode, content_type, payload); } #endif // !AUTOCONNECT_USE_UPDATE diff --git a/src/AutoConnectUpdate.h b/src/AutoConnectUpdate.h index 8ddae2e..2aef52a 100644 --- a/src/AutoConnectUpdate.h +++ b/src/AutoConnectUpdate.h @@ -45,7 +45,7 @@ using HTTPUpdateClass = ESP8266HTTPUpdate; #include using HTTPUpdateClass = HTTPUpdate; #endif -#include +// #include // Quote the true AutoConnectUpdate class according to AUTOCONNECT_USE_UPDATE. #define AutoConnectUpdate AutoConnectUpdateAct #else // !AUTOCONNECT_USE_UPDATE! @@ -54,10 +54,10 @@ using HTTPUpdateClass = HTTPUpdate; #include "AutoConnect.h" // Support LED flashing only the board with built-in LED. -#ifdef LED_BUILTIN -#define UPDATE_SETLED(s) do {setLedPin(LED_BUILTIN, s);} while(0) +#if defined(BUILTIN_LED) || defined(LED_BUILTIN) +#define AC_SETLED(s) do {setLedPin(LED_BUILTIN, s);} while(0) #else -#define UPDATE_SETLED(s) do {} while(0) +#define AC_SETLED(s) do {} while(0) #endif // Indicate an update process loop @@ -65,6 +65,7 @@ typedef enum AC_UPDATESTATUS { UPDATE_RESET, /**< Update process ended, need to reset */ UPDATE_IDLE, /**< Update process has not started */ UPDATE_START, /**< Update process has been started */ + UPDATE_PROGRESS, /**< Update process has been started */ UPDATE_SUCCESS, /**< Update successfully completed */ UPDATE_NOAVAIL, /**< No available update */ UPDATE_FAIL /**< Update fails */ @@ -72,18 +73,20 @@ typedef enum AC_UPDATESTATUS { class AutoConnectUpdateVoid { public: - explicit AutoConnectUpdateVoid(const String& host = String(""), const uint16_t port = AUTOCONNECT_UPDATE_PORT, const String& uri = String("."), const int timeout = AUTOCONNECT_UPDATE_TIMEOUT) { + explicit AutoConnectUpdateVoid(const String& host = String(""), const uint16_t port = AUTOCONNECT_UPDATE_PORT, const String& uri = String("."), const int timeout = AUTOCONNECT_UPDATE_TIMEOUT, const uint8_t ledOn = LOW) { AC_UNUSED(host); AC_UNUSED(port); AC_UNUSED(uri); AC_UNUSED(timeout); + AC_UNUSED(ledOn); } - AutoConnectUpdateVoid(AutoConnect& portal, const String& host = String(""), const uint16_t port = AUTOCONNECT_UPDATE_PORT, const String& uri = String("."), const int timeout = AUTOCONNECT_UPDATE_TIMEOUT) { + AutoConnectUpdateVoid(AutoConnect& portal, const String& host = String(""), const uint16_t port = AUTOCONNECT_UPDATE_PORT, const String& uri = String("."), const int timeout = AUTOCONNECT_UPDATE_TIMEOUT, const uint8_t ledOn = LOW) { AC_UNUSED(portal); AC_UNUSED(host); AC_UNUSED(port); AC_UNUSED(uri); AC_UNUSED(timeout); + AC_UNUSED(ledOn); } virtual ~AutoConnectUpdateVoid() {} virtual void attach(AutoConnect& portal) { AC_UNUSED(portal); } @@ -99,14 +102,14 @@ class AutoConnectUpdateVoid { class AutoConnectUpdateAct : public AutoConnectUpdateVoid, public HTTPUpdateClass { public: - explicit AutoConnectUpdateAct(const String& host = String(""), const uint16_t port = AUTOCONNECT_UPDATE_PORT, const String& uri = String("."), const int timeout = AUTOCONNECT_UPDATE_TIMEOUT) - : HTTPUpdateClass(timeout), host(host), port(port), uri(uri), _wsClient(0), _wsConnected(false), _amount(0), _binSize(0), _enable(false), _dialog(UPDATEDIALOG_LOADER), _status(UPDATE_IDLE), _binName(String()) { - UPDATE_SETLED(LOW); /**< LED blinking during the update that is the default. */ + explicit AutoConnectUpdateAct(const String& host = String(""), const uint16_t port = AUTOCONNECT_UPDATE_PORT, const String& uri = String("."), const int timeout = AUTOCONNECT_UPDATE_TIMEOUT, const uint8_t ledOn = AUTOCONNECT_UPDATE_LEDON) + : HTTPUpdateClass(timeout), host(host), port(port), uri(uri), _amount(0), _binSize(0), _enable(false), _dialog(UPDATEDIALOG_LOADER), _status(UPDATE_IDLE), _binName(String()), _webServer(nullptr) { + AC_SETLED(ledOn); /**< LED blinking during the update that is the default. */ rebootOnUpdate(false); /**< Default reboot mode */ } - AutoConnectUpdateAct(AutoConnect& portal, const String& host = String(""), const uint16_t port = AUTOCONNECT_UPDATE_PORT, const String& uri = String("."), const int timeout = AUTOCONNECT_UPDATE_TIMEOUT) - : HTTPUpdateClass(timeout), host(host), port(port), uri(uri), _wsClient(0), _wsConnected(false), _amount(0), _binSize(0), _enable(false), _dialog(UPDATEDIALOG_LOADER), _status(UPDATE_IDLE), _binName(String()) { - UPDATE_SETLED(LOW); + AutoConnectUpdateAct(AutoConnect& portal, const String& host = String(""), const uint16_t port = AUTOCONNECT_UPDATE_PORT, const String& uri = String("."), const int timeout = AUTOCONNECT_UPDATE_TIMEOUT, const uint8_t ledOn = AUTOCONNECT_UPDATE_LEDON) + : HTTPUpdateClass(timeout), host(host), port(port), uri(uri), _amount(0), _binSize(0), _enable(false), _dialog(UPDATEDIALOG_LOADER), _status(UPDATE_IDLE), _binName(String()), _webServer(nullptr) { + AC_SETLED(ledOn); rebootOnUpdate(false); attach(portal); } @@ -115,7 +118,7 @@ class AutoConnectUpdateAct : public AutoConnectUpdateVoid, public HTTPUpdateClas void enable(void) override; /**< Enable the AutoConnectUpdateAct */ void disable(const bool activte = false) override; /**< Disable the AutoConnectUpdateAct */ void handleUpdate(void) override; /**< Behaves the update process */ - bool isEnable(void) override { return _catalog ? _catalog->isMenu() : false; } /**< Returns current updater effectiveness */ + bool isEnable(void) override { return _auxCatalog ? _auxCatalog->isMenu() : false; } /**< Returns current updater effectiveness */ AC_UPDATESTATUS_t status(void) override { return _status; } /**< reports the current update behavior status */ AC_UPDATESTATUS_t update(void) override; /**< behaves update */ @@ -152,33 +155,38 @@ class AutoConnectUpdateAct : public AutoConnectUpdateVoid, public HTTPUpdateClas String _onCatalog(AutoConnectAux& catalog, PageArgument& args); String _onUpdate(AutoConnectAux& update, PageArgument& args); String _onResult(AutoConnectAux& result, PageArgument& args); - void _wsEvent(uint8_t client, WStype_t event, uint8_t* payload, size_t length); void _inProgress(size_t amount, size_t size); /**< UpdateClass::THandlerFunction_Progress */ - std::unique_ptr _catalog; /**< A catalog page for internally generated update binaries */ - std::unique_ptr _progress; /**< An update in-progress page */ - std::unique_ptr _result; /**< A update result page */ + std::unique_ptr _auxCatalog; /**< A catalog page for internally generated update binaries */ + std::unique_ptr _auxProgress; /**< An update in-progress page */ + std::unique_ptr _auxResult; /**< A update result page */ - std::unique_ptr _ws; /**< Reports the update progress measure */ - uint8_t _wsClient; /**< WebSocket client id */ - bool _wsConnected; /**< WebSocket connection status */ - size_t _amount; /**< Received amount bytes */ - size_t _binSize; /**< Updater binary size */ + size_t _amount; /**< Received amount bytes */ + size_t _binSize; /**< Updater binary size */ private: - bool _enable; /**< Validation status of the Update class */ - AC_UPDATEDIALOG_t _dialog; /**< The type of updating dialog displayed on the client */ - AC_UPDATESTATUS_t _status; /**< Status of update processing during the cycle of receiving a request */ - String _binName; /**< .bin name to update */ + void _progress(void); /**< A Handler that returns progress status to the web client */ - static const ACPage_t _auxCatalog PROGMEM; + bool _enable; /**< Validation status of the Update class */ + AC_UPDATEDIALOG_t _dialog; /**< The type of updating dialog displayed on the client */ + AC_UPDATESTATUS_t _status; /**< Status of update processing during the cycle of receiving a request */ + String _binName; /**< .bin name to update */ + WebServerClass* _webServer; /**< Hosted WebServer for XMLHttpRequest */ + + static const ACPage_t _pageCatalog PROGMEM; static const ACElementProp_t _elmCatalog[] PROGMEM; - static const ACPage_t _auxProgress PROGMEM; + static const ACPage_t _pageProgress PROGMEM; static const ACElementProp_t _elmProgress[] PROGMEM; - static const ACPage_t _auxResult PROGMEM; + static const ACPage_t _pageResult PROGMEM; static const ACElementProp_t _elmResult[] PROGMEM; + +#if defined(ARDUINO_ARCH_ESP8266) + friend class ESP8266WebServer; +#elif defined(ARDUINO_ARCH_ESP32) + friend class WebServer; +#endif }; #endif // !AUTOCONNECT_USE_UPDATE diff --git a/src/AutoConnectUpdatePage.h b/src/AutoConnectUpdatePage.h index d4aff16..d9754f1 100644 --- a/src/AutoConnectUpdatePage.h +++ b/src/AutoConnectUpdatePage.h @@ -21,7 +21,7 @@ const AutoConnectUpdateAct::ACElementProp_t AutoConnectUpdateAct::_elmCatalog[] { AC_Element, "c1", "", nullptr }, { AC_Submit, "update", "UPDATE", AUTOCONNECT_URI_UPDATE_ACT } }; -const AutoConnectUpdateAct::ACPage_t AutoConnectUpdateAct::_auxCatalog PROGMEM = { +const AutoConnectUpdateAct::ACPage_t AutoConnectUpdateAct::_pageCatalog PROGMEM = { AUTOCONNECT_URI_UPDATE, "Update", false, AutoConnectUpdateAct::_elmCatalog }; @@ -36,27 +36,24 @@ const AutoConnectUpdateAct::ACElementProp_t AutoConnectUpdateAct::_elmProgress[] { AC_Element, "c3", "
Updating...", nullptr }, { AC_Element, "progress_meter", "", nullptr }, { AC_Element, "progress_loader", "
", nullptr }, - { AC_Element, "c4", "
", nullptr }, + { AC_Element, "c4", "", nullptr }, { AC_Text, "status", nullptr, nullptr }, - { AC_Element, "c5", "", nullptr } + { AC_Element, "c5", "", nullptr } }; -const AutoConnectUpdateAct::ACPage_t AutoConnectUpdateAct::_auxProgress PROGMEM = { +const AutoConnectUpdateAct::ACPage_t AutoConnectUpdateAct::_pageProgress PROGMEM = { AUTOCONNECT_URI_UPDATE_ACT, "Update", false, AutoConnectUpdateAct::_elmProgress }; // Definition of the AUTOCONNECT_URI_UPDATE_RESULT page to notify update results const AutoConnectUpdateAct::ACElementProp_t AutoConnectUpdateAct::_elmResult[] PROGMEM = { { AC_Text, "status", nullptr, nullptr }, - { AC_Element, "restart", "", nullptr } + { AC_Element, "restart", "", nullptr } }; -const AutoConnectUpdateAct::ACPage_t AutoConnectUpdateAct::_auxResult PROGMEM = { +const AutoConnectUpdateAct::ACPage_t AutoConnectUpdateAct::_pageResult PROGMEM = { AUTOCONNECT_URI_UPDATE_RESULT, "Update", false, AutoConnectUpdateAct::_elmResult };