Change to the progress meter

pull/123/head
Hieromon Ikasamo 6 years ago
parent ee5abff99f
commit 07331d630e
  1. 5
      src/AutoConnectDefs.h
  2. 56
      src/AutoConnectUpdate.cpp
  3. 14
      src/AutoConnectUpdate.h
  4. 10
      src/AutoConnectUpdatePage.h

@ -192,6 +192,11 @@
#define AUTOCONNECT_UPDATE_CATALOG_JSONBUFFER_SIZE 2048
#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)

@ -74,6 +74,7 @@ AutoConnectUpdate::~AutoConnectUpdate() {
_progress.reset(nullptr);
_result.reset(nullptr);
_WiFiClient.reset(nullptr);
_ws.reset(nullptr);
}
/**
@ -98,8 +99,8 @@ void AutoConnectUpdate::attach(AutoConnect& portal) {
_buildAux(updatePage, &_auxResult, lengthOf(_elmResult));
_result.reset(updatePage);
_catalog->on(std::bind(&AutoConnectUpdate::_onCatalog, 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);
_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);
portal.join(*_catalog.get());
portal.join(*_progress.get());
@ -180,6 +181,11 @@ void AutoConnectUpdate::handleUpdate(void) {
* @return AC_UPDATESTATUS_t
*/
AC_UPDATESTATUS_t AutoConnectUpdate::update(void) {
// Crawl queued requests.
if (_ws)
_ws->loop();
// Start update
String uriBin = uri + '/' + _binName;
if (_binName.length()) {
AC_DBG("%s:%d/%s update in progress...", host.c_str(), port, uriBin.c_str());
@ -203,6 +209,12 @@ AC_UPDATESTATUS_t AutoConnectUpdate::update(void) {
break;
}
_WiFiClient.reset(nullptr);
// Request the client to close the WebSocket.
if (_ws) {
String cmdClose = String("#e");
_ws->sendTXT(_wsClient, cmdClose);
_ws->loop();
}
}
else {
AC_DBG("An update has not specified");
@ -362,9 +374,27 @@ String AutoConnectUpdate::_onCatalog(AutoConnectAux& catalog, PageArgument& args
*/
String AutoConnectUpdate::_onUpdate(AutoConnectAux& progress, PageArgument& args) {
AC_UNUSED(args);
AutoConnectText& flash = progress.getElement<AutoConnectText>(String(F("flash")));
// launch the WebSocket server
WebSocketsServer* ws = new WebSocketsServer(AUTOCONNECT_WEBSOCKETPORT);
if (ws) {
ws->begin();
ws->onEvent(std::bind(&AutoConnectUpdate::_wsEvent, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
}
else {
AC_DBG("WebSocketsServer allocation failed\n");
}
_ws.reset(ws);
// Constructs the dialog page.
AutoConnectText& binName = progress.getElement<AutoConnectText>(String(F("binname")));
_binName = _catalog->getElement<AutoConnectRadio>(String(F("firmwares"))).value();
flash.value = _binName;
binName.value = _binName;
AutoConnectText& url = progress.getElement<AutoConnectText>(String("url"));
url.value = host + ':' + port;
AutoConnectElement& inprogress = progress.getElement<AutoConnectElement>(String(F("inprogress")));
String js = inprogress.value;
js.replace(String(F("#wsserver#")), WiFi.localIP().toString() + ':' + AUTOCONNECT_WEBSOCKETPORT);
inprogress.value = js;
_status = UPDATE_START;
return String("");
}
@ -406,3 +436,23 @@ String AutoConnectUpdate::_onResult(AutoConnectAux& result, PageArgument& args)
_status = UPDATE_RESET;
return String("");
}
void AutoConnectUpdate::_inProgress(size_t amount, size_t size) {
if (_ws) {
_amount = amount;
_binSize = size;
String payload = "#p," + String(_amount) + ':' + String(_binSize);
_ws->sendTXT(_wsClient, payload);
_ws->loop();
}
}
void AutoConnectUpdate::_wsEvent(uint8_t client, WStype_t event, uint8_t* payload, size_t length) {
AC_DBG("WS event(%d)\n", event);
if (event == WStype_CONNECTED)
_wsClient = client;
else if (event == WStype_DISCONNECTED) {
if (client == _wsClient)
_ws.reset(nullptr);
}
}

@ -40,6 +40,7 @@ using HTTPUpdateClass = ESP8266HTTPUpdate;
#include <HTTPUpdate.h>
using HTTPUpdateClass = HTTPUpdate;
#endif
#include <WebSocketsServer.h>
#include "AutoConnectDefs.h"
#if defined(AUTOCONNECT_USE_UPDATE)
#ifndef AUTOCONNECT_USE_JSON
@ -115,25 +116,22 @@ class AutoConnectUpdate : public HTTPUpdateClass {
String _onUpdate(AutoConnectAux& update, PageArgument& args);
String _onResult(AutoConnectAux& result, PageArgument& args);
size_t _insertCatalog(AutoConnectRadio& radio, JsonVariant & responseBody);
#ifdef ARDUINO_ARCH_ESP32
void _inProgress(size_t amount, size_t size) {
_amount = amount;
_binSize = size;
AC_DBG_DUMB(".");
}
#endif
void _wsEvent(uint8_t client, WStype_t event, uint8_t* payload, size_t length);
void _inProgress(size_t amount, size_t size);
std::unique_ptr<AutoConnectAux> _catalog; /**< A catalog page for internally generated update binaries */
std::unique_ptr<AutoConnectAux> _progress; /**< An update in-progress page */
std::unique_ptr<AutoConnectAux> _result; /**< A update result page */
std::unique_ptr<WebSocketsServer> _ws; /**< Reports the update progress measure */
uint8_t _wsClient; /**< WebSocket client id */
size_t _amount; /**< Received amound bytes */
size_t _binSize; /**< Updater binary size */
private:
AC_UPDATESTATUS_t _status;
String _binName; /**< .bin name to update */
unsigned long _period; /**< Duration of WiFiClient holding */
unsigned long _period; /**< Duration of WiFiClient holding for the connection with the update server */
std::unique_ptr<WiFiClient> _WiFiClient; /**< Provide to HTTPUpdate class */
static const ACPage_t _auxCatalog PROGMEM;

@ -25,10 +25,12 @@ const AutoConnectUpdate::ACPage_t AutoConnectUpdate::_auxCatalog PROGMEM = {
// Define the AUTOCONNECT_URI_UPDATE_ACT page to display during the
// update process.
const AutoConnectUpdate::ACElementProp_t AutoConnectUpdate::_elmProgress[] PROGMEM = {
{ AC_Element, "spinner", "<style>.loader {border:2px solid #f3f3f3;border-radius:50%;border-top:2px solid #555;width:12px;height:12px;-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg)}}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}</style>", nullptr },
{ AC_Text, "caption", "Update start...", "<div style=\"font-size:120%%;font-weight:bold\">%s</div>" },
{ AC_Text, "flash", nullptr, "<div style=\"margin-top:18px\">%s<span style=\"display:inline-block;vertical-align:middle;margin-left:7px\"><div class=\"loader\"></div></span></div>" },
{ AC_Element, "inprogress", "<script type=\"text/javascript\">setTimeout(\"location.href='" AUTOCONNECT_URI_UPDATE_RESULT "'\",1000*15);</script>", nullptr }
{ AC_Element, "caption", "<div style=\"display:inline-block\"", nullptr },
{ AC_Text, "binname", nullptr, "%s&ensp;from&ensp;" },
{ AC_Text, "url", nullptr, "%s</div>" },
{ AC_Element, "progress", "<div id=\"progress\">Updating...&ensp;<meter min=\"0\"></meter></div>", nullptr },
{ AC_Text, "status", nullptr, nullptr },
{ AC_Element, "inprogress", "<script type='text/javascript'>var ws;window.onload=function(){ws=new WebSocket('ws://'+'#wsserver#');ws.onopen=function(e){ws.onmessage=function(e){var pl=e.data.split(',');if(pl[0]=='#p'){var iv=pl[1].split(':');var pb=document.getElementById('progress').getElementsByTagName('meter');pb[0].setAttribute('value',iv[0]);pb[0].setAttribute('max',iv[1]);}else if(pl[0]=='#e'){location.href='" AUTOCONNECT_URI_UPDATE_RESULT "';}};ws.onclose=function(e){console.log('WS close('+e.code+') '+e.reason);};};ws.onerror=function(e){console.log(e);document.getElementById('status').textContent='Connection failed.';};};window.onbeforeunload=function(){ws.close();};</script>", nullptr }
};
const AutoConnectUpdate::ACPage_t AutoConnectUpdate::_auxProgress PROGMEM = {
AUTOCONNECT_URI_UPDATE_ACT, "Update", false, AutoConnectUpdate::_elmProgress

Loading…
Cancel
Save