From cbeb0a19a8ae232202dfa93c5e4c284b2ddcc40e Mon Sep 17 00:00:00 2001 From: Jonathan Giles Date: Tue, 10 Dec 2024 10:54:20 +1300 Subject: [PATCH 01/33] Early work to externalise the webui --- data/www/config.htm | 57 +++ data/www/favicon.ico | Bin 0 -> 15406 bytes data/www/fota.htm | 55 +++ data/www/index.htm | 77 ++++ data/www/json.htm | 135 ++++++ data/www/reboot.htm | 13 + data/www/styles.css | 24 + lib/MultiBlinker/MultiBlinker.cpp | 34 +- lib/MultiBlinker/MultiBlinker.h | 5 +- lib/WebUI/WebUI.cpp | 198 ++++---- lib/WebUI/WebUI.h | 722 +++++++++++++++--------------- platformio.ini | 3 + src/main.cpp | 21 +- 13 files changed, 853 insertions(+), 491 deletions(-) create mode 100644 data/www/config.htm create mode 100644 data/www/favicon.ico create mode 100644 data/www/fota.htm create mode 100644 data/www/index.htm create mode 100644 data/www/json.htm create mode 100644 data/www/reboot.htm create mode 100644 data/www/styles.css diff --git a/data/www/config.htm b/data/www/config.htm new file mode 100644 index 0000000..394a5bc --- /dev/null +++ b/data/www/config.htm @@ -0,0 +1,57 @@ + + + + + + +Configuration + + +

Configuration

+
+ + + + + + + +
Spa Name:
MQTT Server:
MQTT Port:
MQTT Username:
MQTT Password:
Poll Frequency (seconds):
+ +
+
+ + + + \ No newline at end of file diff --git a/data/www/favicon.ico b/data/www/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..a4b599785f45860cc1dc65686fa9996820387560 GIT binary patch literal 15406 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 + + + + + +Firmware Update + + +

Firmware Update

+ +
+ + +
+
progress: 0%
+
+ + + \ No newline at end of file diff --git a/data/www/index.htm b/data/www/index.htm new file mode 100644 index 0000000..f64c0f9 --- /dev/null +++ b/data/www/index.htm @@ -0,0 +1,77 @@ + + + + + + + + + +

ESP32 Spa Controller

+ + + + + + + + + +
Spa status:Loading...
Spa temperature:Loading...
Set Temperature: +
Spa controller:Loading...
Spa serial number:Loading...
Spa interface initialised:Loading...
MQTT status:Loading...
Build:)TODO - NOT EXTERNALISED YET
+

Spa JSON HTML

+

Spa JSON

+

Spa Response

+

Send Current Time to Spa

+

Configuration

+

Firmware Update

+

Wi-Fi Manager

+

Reboot ESP

+ + \ No newline at end of file diff --git a/data/www/json.htm b/data/www/json.htm new file mode 100644 index 0000000..1add878 --- /dev/null +++ b/data/www/json.htm @@ -0,0 +1,135 @@ + + + + + + + +JSON Data Table + + +

JSON Data Table

+ + + + + + +
+ + + \ No newline at end of file diff --git a/data/www/reboot.htm b/data/www/reboot.htm new file mode 100644 index 0000000..2ed3fa5 --- /dev/null +++ b/data/www/reboot.htm @@ -0,0 +1,13 @@ + + + + + + + +Rebooting + + +

Rebooting ESP...

+ + \ No newline at end of file diff --git a/data/www/styles.css b/data/www/styles.css new file mode 100644 index 0000000..feb0ce0 --- /dev/null +++ b/data/www/styles.css @@ -0,0 +1,24 @@ +input[type=file]::file-selector-button, input[type="submit"], a, button { + padding: 7px 15px; + border: none; + background: #007BFF; + color: white; + text-decoration: none; + border-radius: 5px; + margin-top: 5px; + display: inline-block; + font-size: 16px; + font-family: Arial, sans-serif; + cursor: pointer; + text-align: center; +} +input[type=file]::file-selector-button:hover, input[type="submit"]:hover, a:hover, button:hover { + background-color: #0056b3; +} +table, td, th { + border: 1px solid; + padding: 5px; +} +table { + border-collapse: collapse; +} \ No newline at end of file diff --git a/lib/MultiBlinker/MultiBlinker.cpp b/lib/MultiBlinker/MultiBlinker.cpp index 084e89a..e2fe3bf 100644 --- a/lib/MultiBlinker/MultiBlinker.cpp +++ b/lib/MultiBlinker/MultiBlinker.cpp @@ -2,23 +2,23 @@ // Define the on/off times for each state (-1 to 15) const LEDPattern LED_PATTERNS[17] = { - {2000, 2000}, //KNIGHT_RIDER - {UINT_MAX, 0}, // STATE_NONE: Always off - {100, 100}, // STATE_WIFI_NOT_CONNECTED - {0, 0}, // Reserved - {0, 0}, // Reserved - {500, 500}, // STATE_MQTT_NOT_CONNECTED - {0, 0}, // Reserved - {0, 0}, // Reserved - {0, 0}, // Reserved - {0, 0}, // Reserved - {0, 0}, // Reserved - {0, 0}, // Reserved - {0, 0}, // Reserved - {0, 0}, // Reserved - {0, 0}, // Reserved - {0, 0}, // Reserved - {0, UINT_MAX} // STATE_STARTED_WIFI_AP: Always on + {2000, 2000}, //KNIGHT_RIDER + {UINT_MAX, 0}, // STATE_NONE: Always off + {100, 100}, // STATE_WIFI_NOT_CONNECTED + {1000, 1000}, // STATE_WAITING_FOR_SPA + {0, 0}, // Reserved + {500, 500}, // STATE_MQTT_NOT_CONNECTED + {0, 0}, // Reserved + {0, 0}, // Reserved + {0, 0}, // Reserved + {0, 0}, // Reserved + {0, 0}, // Reserved + {0, 0}, // Reserved + {0, 0}, // Reserved + {0, 0}, // Reserved + {0, 0}, // Reserved + {0, 0}, // Reserved + {0, UINT_MAX} // STATE_STARTED_WIFI_AP: Always on }; MultiBlinker::MultiBlinker(int led1, int led2, int led3, int led4) { diff --git a/lib/MultiBlinker/MultiBlinker.h b/lib/MultiBlinker/MultiBlinker.h index bf93774..56710e8 100644 --- a/lib/MultiBlinker/MultiBlinker.h +++ b/lib/MultiBlinker/MultiBlinker.h @@ -19,8 +19,9 @@ extern RemoteDebug Debug; const int KNIGHT_RIDER = -1; // Knight Rider animation or 2000ms blink const int STATE_NONE = 0; // ON: (nothing) const int STATE_STARTED_WIFI_AP = 15; // ON: ALL or solid on -const int STATE_WIFI_NOT_CONNECTED = 1; // ON: 4 or 100ms blink -const int STATE_MQTT_NOT_CONNECTED = 4; // ON: 2 or 500ms blink +const int STATE_WIFI_NOT_CONNECTED = 1; // ON: LED 4 or 100ms blink +const int STATE_WAITING_FOR_SPA = 2; // ON: LED 3 or 1000ms blink +const int STATE_MQTT_NOT_CONNECTED = 4; // ON: LED 2 or 500ms blink const int MULTI_BLINKER_INTERVAL = 100; diff --git a/lib/WebUI/WebUI.cpp b/lib/WebUI/WebUI.cpp index 754b208..f56c74e 100644 --- a/lib/WebUI/WebUI.cpp +++ b/lib/WebUI/WebUI.cpp @@ -14,105 +14,89 @@ const char * WebUI::getError() { return Update.errorString(); } - void WebUI::begin() { - - server.reset(new WebServer(80)); - - server->on("/", HTTP_GET, [&]() { - debugD("uri: %s", server->uri().c_str()); - server->sendHeader("Connection", "close"); - server->send(200, "text/html", WebUI::indexPageTemplate); - }); - - server->on("/json", HTTP_GET, [&]() { - debugD("uri: %s", server->uri().c_str()); - server->sendHeader("Connection", "close"); + server.on("/json", HTTP_GET, [&](AsyncWebServerRequest *request) { + debugD("uri: %s", request->url().c_str()); String json; + AsyncWebServerResponse *response; if (generateStatusJson(*_spa, *_mqttClient, json, true)) { - server->send(200, "text/json", json.c_str()); + response = request->beginResponse(200, "application/json", json); } else { - server->send(200, "text/text", "Error generating json"); + response = request->beginResponse(200, "text/plain", "Error generating json"); } + response->addHeader("Connection", "close"); + request->send(response); }); - server->on("/reboot", HTTP_GET, [&]() { - debugD("uri: %s", server->uri().c_str()); - server->send(200, "text/html", WebUI::rebootPage); + server.on("/reboot", HTTP_GET, [&](AsyncWebServerRequest *request) { + debugD("uri: %s", request->url().c_str()); + request->send(LittleFS, "/www/reboot.htm"); debugD("Rebooting..."); delay(200); - server->client().stop(); ESP.restart(); }); - server->on("/styles.css", HTTP_GET, [&]() { - debugD("uri: %s", server->uri().c_str()); - server->send(200, "text/css", WebUI::styleSheet); + server.on("/fota", HTTP_GET, [&](AsyncWebServerRequest *request) { + debugD("uri: %s", request->url().c_str()); + request->send(LittleFS, "/www/fota.htm"); }); - server->on("/fota", HTTP_GET, [&]() { - debugD("uri: %s", server->uri().c_str()); - server->sendHeader("Connection", "close"); - server->send(200, "text/html", WebUI::fotaPage); + server.on("/config", HTTP_GET, [&](AsyncWebServerRequest *request) { + debugD("uri: %s", request->url().c_str()); + request->send(LittleFS, "/www/config.htm"); }); - server->on("/fota", HTTP_POST, [&]() { - debugD("uri: %s", server->uri().c_str()); + server.on("/fota", HTTP_POST, [this](AsyncWebServerRequest *request) { + debugD("uri: %s", request->url().c_str()); if (Update.hasError()) { - server->sendHeader("Connection", "close"); - server->send(200, F("text/plain"), String(F("Update error: ")) + String(getError())); + AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", String("Update error: ") + String(this->getError())); + response->addHeader("Connection", "close"); + request->send(response); } else { - server->client().setNoDelay(true); - server->sendHeader("Connection", "close"); - server->send(200, "text/plain", "OK"); + request->client()->setNoDelay(true); + AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", "OK"); + response->addHeader("Connection", "close"); + request->send(response); debugD("Rebooting..."); delay(100); - server->client().stop(); + request->client()->stop(); ESP.restart(); } - }, [&]() { - debugD("uri: %s", server->uri().c_str()); - HTTPUpload& upload = server->upload(); - if (upload.status == UPLOAD_FILE_START) { - debugD("Update: %s", upload.filename.c_str()); - if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size - debugD("Update Error: %s",getError()); + }, [this](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) { + if (index == 0) { + debugD("Update: %s", filename.c_str()); + if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { // start with max available size + debugD("Update Error: %s", this->getError()); } - } else if (upload.status == UPLOAD_FILE_WRITE) { - /* flashing firmware to ESP*/ - if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) { - debugD("Update Error: %s",getError()); - } - } else if (upload.status == UPLOAD_FILE_END) { - if (Update.end(true)) { //true to set the size to the current progress - debugD("Update Success: %u\n", upload.totalSize); + } + if (Update.write(data, len) != len) { + debugD("Update Error: %s", this->getError()); + } + if (final) { + if (Update.end(true)) { // true to set the size to the current progress + debugD("Update Success: %u\n", index + len); } else { - debugD("Update Error: %s",getError()); + debugD("Update Error: %s", this->getError()); } } }); - server->on("/config", HTTP_GET, [&]() { - debugD("uri: %s", server->uri().c_str()); - server->sendHeader("Connection", "close"); - server->send(200, "text/html", WebUI::configPageTemplate); - }); - - server->on("/config", HTTP_POST, [&]() { - debugD("uri: %s", server->uri().c_str()); - if (server->hasArg("spaName")) _config->SpaName.setValue(server->arg("spaName")); - if (server->hasArg("mqttServer")) _config->MqttServer.setValue(server->arg("mqttServer")); - if (server->hasArg("mqttPort")) _config->MqttPort.setValue(server->arg("mqttPort").toInt()); - if (server->hasArg("mqttUsername")) _config->MqttUsername.setValue(server->arg("mqttUsername")); - if (server->hasArg("mqttPassword")) _config->MqttPassword.setValue(server->arg("mqttPassword")); - if (server->hasArg("updateFrequency")) _config->UpdateFrequency.setValue(server->arg("updateFrequency").toInt()); + server.on("/config", HTTP_POST, [this](AsyncWebServerRequest *request) { + debugD("uri: %s", request->url().c_str()); + if (request->hasParam("spaName", true)) _config->SpaName.setValue(request->getParam("spaName", true)->value()); + if (request->hasParam("mqttServer", true)) _config->MqttServer.setValue(request->getParam("mqttServer", true)->value()); + if (request->hasParam("mqttPort", true)) _config->MqttPort.setValue(request->getParam("mqttPort", true)->value().toInt()); + if (request->hasParam("mqttUsername", true)) _config->MqttUsername.setValue(request->getParam("mqttUsername", true)->value()); + if (request->hasParam("mqttPassword", true)) _config->MqttPassword.setValue(request->getParam("mqttPassword", true)->value()); + if (request->hasParam("updateFrequency", true)) _config->UpdateFrequency.setValue(request->getParam("updateFrequency", true)->value().toInt()); _config->writeConfigFile(); - server->sendHeader("Connection", "close"); - server->send(200, "text/plain", "Updated"); + AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", "Updated"); + response->addHeader("Connection", "close"); + request->send(response); }); - server->on("/json/config", HTTP_GET, [&]() { - debugD("uri: %s", server->uri().c_str()); + server.on("/json/config", HTTP_GET, [this](AsyncWebServerRequest *request) { + debugD("uri: %s", request->url().c_str()); String configJson = "{"; configJson += "\"spaName\":\"" + _config->SpaName.getValue() + "\","; configJson += "\"mqttServer\":\"" + _config->MqttServer.getValue() + "\","; @@ -121,54 +105,62 @@ void WebUI::begin() { configJson += "\"mqttPassword\":\"" + _config->MqttPassword.getValue() + "\","; configJson += "\"updateFrequency\":" + String(_config->UpdateFrequency.getValue()); configJson += "}"; - server->send(200, "application/json", configJson); + AsyncWebServerResponse *response = request->beginResponse(200, "application/json", configJson); + response->addHeader("Connection", "close"); + request->send(response); }); - server->on("/set", HTTP_POST, [&]() { - //In theory with minor modification, we can reuse mqttCallback here - //for (uint8_t i = 0; i < server->args(); i++) updateSpaSetting("set/" + server->argName(0), server->arg(0)); - if (server->hasArg("temperatures_setPoint")) { - float newTemperature = server->arg("temperatures_setPoint").toFloat(); - _spa->setSTMP(int(newTemperature*10)); - server->send(200, "text/plain", "Temperature updated"); - } - else if (server->hasArg("status_datetime")) { - String p = server->arg("status_datetime"); + // Handle /set endpoint (POST) + server.on("/set", HTTP_POST, [this](AsyncWebServerRequest *request) { + // In theory with minor modification, we can reuse mqttCallback here + // for (uint8_t i = 0; i < request->params(); i++) updateSpaSetting("set/" + request->getParam(i)->name(), request->getParam(i)->value()); + if (request->hasParam("temperatures_setPoint", true)) { + float newTemperature = request->getParam("temperatures_setPoint", true)->value().toFloat(); + _spa->setSTMP(int(newTemperature * 10)); + AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", "Temperature updated"); + response->addHeader("Connection", "close"); + request->send(response); + } else if (request->hasParam("status_datetime", true)) { + String p = request->getParam("status_datetime", true)->value(); tmElements_t tm; - tm.Year=CalendarYrToTm(p.substring(0,4).toInt()); - tm.Month=p.substring(5,7).toInt(); - tm.Day=p.substring(8,10).toInt(); - tm.Hour=p.substring(11,13).toInt(); - tm.Minute=p.substring(14,16).toInt(); - tm.Second=p.substring(17).toInt(); + tm.Year = CalendarYrToTm(p.substring(0, 4).toInt()); + tm.Month = p.substring(5, 7).toInt(); + tm.Day = p.substring(8, 10).toInt(); + tm.Hour = p.substring(11, 13).toInt(); + tm.Minute = p.substring(14, 16).toInt(); + tm.Second = p.substring(17).toInt(); _spa->setSpaTime(makeTime(tm)); - server->send(200, "text/plain", "Date/Time updated"); - } - else { - server->send(400, "text/plain", "Invalid temperature value"); + AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", "Date/Time updated"); + response->addHeader("Connection", "close"); + request->send(response); + } else { + AsyncWebServerResponse *response = request->beginResponse(400, "text/plain", "Invalid temperature value"); + response->addHeader("Connection", "close"); + request->send(response); } }); - server->on("/wifi-manager", HTTP_GET, [&]() { - debugD("uri: %s", server->uri().c_str()); - server->sendHeader("Connection", "close"); - server->send(200, "text/plain", "WiFi Manager launching, connect to ESP WiFi..."); + // Handle /wifi-manager endpoint (GET) + server.on("/wifi-manager", HTTP_GET, [this](AsyncWebServerRequest *request) { + debugD("uri: %s", request->url().c_str()); + AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", "WiFi Manager launching, connect to ESP WiFi..."); + response->addHeader("Connection", "close"); + request->send(response); if (_wifiManagerCallback != nullptr) { _wifiManagerCallback(); } }); - server->on("/json.html", HTTP_GET, [&]() { - debugD("uri: %s", server->uri().c_str()); - server->sendHeader("Connection", "close"); - server->send(200, "text/html", WebUI::jsonHTMLTemplate); + server.on("/status", HTTP_GET, [this](AsyncWebServerRequest *request) { + debugD("uri: %s", request->url().c_str()); + AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", _spa->statusResponse.getValue()); + response->addHeader("Connection", "close"); + request->send(response); }); - server->on("/status", HTTP_GET, [&]() { - debugD("uri: %s", server->uri().c_str()); - server->sendHeader("Connection", "close"); - server->send(200, "text/plain", _spa->statusResponse.getValue()); - }); + // Returns web site rendering of the current station state, + // served from the data/../www directory of this project. + server.serveStatic("/", LittleFS, "/www/"); - server->begin(); + server.begin(); initialised = true; } \ No newline at end of file diff --git a/lib/WebUI/WebUI.h b/lib/WebUI/WebUI.h index d2a5105..1cf03eb 100644 --- a/lib/WebUI/WebUI.h +++ b/lib/WebUI/WebUI.h @@ -3,7 +3,8 @@ #include -#include +// #include +#include "ESPAsyncWebServer.h" #include #include "SpaInterface.h" @@ -11,15 +12,15 @@ #include "Config.h" #include "MQTTClientWrapper.h" -//define stringify function -#define xstr(a) str(a) -#define str(a) #a +// //define stringify function +// #define xstr(a) str(a) +// #define str(a) #a extern RemoteDebug Debug; class WebUI { public: - std::unique_ptr server; + // std::unique_ptr server_old; WebUI(SpaInterface *spa, Config *config, MQTTClientWrapper *mqttClient); /// @brief Set the function to be called when properties have been updated. @@ -29,6 +30,7 @@ class WebUI { bool initialised = false; private: + AsyncWebServer server{80}; SpaInterface *_spa; Config *_config; MQTTClientWrapper *_mqttClient; @@ -36,378 +38,378 @@ class WebUI { const char* getError(); -static constexpr const char *indexPageTemplate PROGMEM = -R"( - - - - - - - - -

ESP32 Spa Controller

- - - - - - - - - -
Spa status:Loading...
Spa temperature:Loading...
Set Temperature: -
Spa controller:Loading...
Spa serial number:Loading...
Spa interface initialised:Loading...
MQTT status:Loading...
Build:)" xstr(BUILD_INFO) R"(
-

Spa JSON HTML

-

Spa JSON

-

Spa Response

-

Send Current Time to Spa

-

Configuration

-

Firmware Update

-

Wi-Fi Manager

-

Reboot ESP

- -)"; +// static constexpr const char *indexPageTemplate PROGMEM = +// R"( +// +// +// +// +// +// +// +// +//

ESP32 Spa Controller

+// +// +// +// +// +// +// +// +// +//
Spa status:Loading...
Spa temperature:Loading...
Set Temperature: +//
Spa controller:Loading...
Spa serial number:Loading...
Spa interface initialised:Loading...
MQTT status:Loading...
Build:)" xstr(BUILD_INFO) R"(
+//

Spa JSON HTML

+//

Spa JSON

+//

Spa Response

+//

Send Current Time to Spa

+//

Configuration

+//

Firmware Update

+//

Wi-Fi Manager

+//

Reboot ESP

+// +// )"; -static constexpr const char *fotaPage PROGMEM = -R"( - - - - - -Firmware Update - - -

Firmware Update

- -
- - -
-
progress: 0%
-
- - -)"; +// static constexpr const char *fotaPage PROGMEM = +// R"( +// +// +// +// +// +// Firmware Update +// +// +//

Firmware Update

+// +//
+// +// +//
+//
progress: 0%
+//
+// +// +// )"; -static constexpr const char *styleSheet PROGMEM = -R"( -input[type=file]::file-selector-button, input[type="submit"], a, button { - padding: 7px 15px; - border: none; - background: #007BFF; - color: white; - text-decoration: none; - border-radius: 5px; - margin-top: 5px; - display: inline-block; - font-size: 16px; - font-family: Arial, sans-serif; - cursor: pointer; - text-align: center; -} -input[type=file]::file-selector-button:hover, input[type="submit"]:hover, a:hover, button:hover { - background-color: #0056b3; -} -table, td, th { - border: 1px solid; - padding: 5px; -} -table { - border-collapse: collapse; -})"; +// static constexpr const char *styleSheet PROGMEM = +// R"( +// input[type=file]::file-selector-button, input[type="submit"], a, button { +// padding: 7px 15px; +// border: none; +// background: #007BFF; +// color: white; +// text-decoration: none; +// border-radius: 5px; +// margin-top: 5px; +// display: inline-block; +// font-size: 16px; +// font-family: Arial, sans-serif; +// cursor: pointer; +// text-align: center; +// } +// input[type=file]::file-selector-button:hover, input[type="submit"]:hover, a:hover, button:hover { +// background-color: #0056b3; +// } +// table, td, th { +// border: 1px solid; +// padding: 5px; +// } +// table { +// border-collapse: collapse; +// })"; -static constexpr const char *rebootPage PROGMEM = -R"( - - - - - - -Rebooting - - -

Rebooting ESP...

- -)"; +// static constexpr const char *rebootPage PROGMEM = +// R"( +// +// +// +// +// +// +// Rebooting +// +// +//

Rebooting ESP...

+// +// )"; -static constexpr const char *configPageTemplate PROGMEM = -R"( - - - - - -Configuration - - -

Configuration

-
- - - - - - - -
Spa Name:
MQTT Server:
MQTT Port:
MQTT Username:
MQTT Password:
Poll Frequency (seconds):
- -
-
- - - -)"; +// static constexpr const char *configPageTemplate PROGMEM = +// R"( +// +// +// +// +// +// Configuration +// +// +//

Configuration

+//
+// +// +// +// +// +// +// +//
Spa Name:
MQTT Server:
MQTT Port:
MQTT Username:
MQTT Password:
Poll Frequency (seconds):
+// +//
+//
+// +// +// +// )"; -static constexpr const char *jsonHTMLTemplate PROGMEM = -R"( - - - - - - -JSON Data Table - - -

JSON Data Table

- - - - - - -
- - -)"; +// // Fetch data on page load +// window.onload = fetchDataAndPopulateTable; +// +// +// )"; }; diff --git a/platformio.ini b/platformio.ini index d0cdf7a..e192e9f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -10,11 +10,13 @@ [platformio] default_envs = esp32dev, spa-control-pcb +; data_dir = {$PROJECT_DIR}/data [env:spa-base] framework = arduino monitor_speed = 115200 lib_ldf_mode = deep +board_build.filesystem = littlefs lib_deps = https://github.com/ktos/RemoteDebug.git@^3.0.7 tzapu/WiFiManager@^2.0.17 @@ -22,6 +24,7 @@ lib_deps = bblanchon/ArduinoJson@^7.1.0 links2004/WebSockets@^2.3.6 paulstoffregen/Time@^1.6.1 + https://github.com/me-no-dev/ESPAsyncWebServer.git extra_scripts = pre:get_version.py post:merge-bin.py diff --git a/src/main.cpp b/src/main.cpp index 62523ad..678c5e1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -62,9 +62,9 @@ void WMsaveConfigCallback(){ } void startWiFiManager(){ - if (ui.initialised) { - ui.server->stop(); - } + // if (ui.initialised) { + // ui.server_old->stop(); + // } WiFiManager wm; WiFiManagerParameter custom_spa_name("spa_name", "Spa Name", config.SpaName.getValue().c_str(), 40); @@ -618,9 +618,9 @@ void loop() { mqttClient.loop(); Debug.handle(); - if (ui.initialised) { - ui.server->handleClient(); - } + // if (ui.initialised) { + // ui.server_old->handleClient(); + // } if (updateMqtt) { debugD("Changing MQTT settings..."); @@ -643,9 +643,13 @@ void loop() { delayedStart = !(bootTime + 10000 < millis()); } else { - si.loop(); + // quiet down the log for now + // si.loop(); - if (si.isInitialised()) { + if (!si.isInitialised()) { + // set status lights to indicate we are waiting for spa connection before we proceed + blinker.setState(STATE_WAITING_FOR_SPA); + } else { if ( spaSerialNumber=="" ) { debugI("Initialising..."); @@ -690,7 +694,6 @@ void loop() { mqttPublishStatus(); si.statusResponse.setCallback(mqttPublishStatusString); - } // all systems are go! Start the knight rider animation loop From dd79abf3883e04bf6967fc2bea896a9b4ff9835d Mon Sep 17 00:00:00 2001 From: Jonathan Giles Date: Tue, 10 Dec 2024 10:55:34 +1300 Subject: [PATCH 02/33] Let the spa interface make noise again --- src/main.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 678c5e1..a61cc78 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -642,9 +642,7 @@ void loop() { if (delayedStart) { delayedStart = !(bootTime + 10000 < millis()); } else { - - // quiet down the log for now - // si.loop(); + si.loop(); if (!si.isInitialised()) { // set status lights to indicate we are waiting for spa connection before we proceed From ae630101313cf5d469755756b7bf3a724a35650b Mon Sep 17 00:00:00 2001 From: Jonathan Giles Date: Tue, 10 Dec 2024 11:04:15 +1300 Subject: [PATCH 03/33] Delete the old content from WebUI.h as it has all be externalised --- lib/WebUI/WebUI.h | 374 ---------------------------------------------- 1 file changed, 374 deletions(-) diff --git a/lib/WebUI/WebUI.h b/lib/WebUI/WebUI.h index 1cf03eb..4673f4b 100644 --- a/lib/WebUI/WebUI.h +++ b/lib/WebUI/WebUI.h @@ -37,380 +37,6 @@ class WebUI { void (*_wifiManagerCallback)() = nullptr; const char* getError(); - -// static constexpr const char *indexPageTemplate PROGMEM = -// R"( -// -// -// -// -// -// -// -// -//

ESP32 Spa Controller

-// -// -// -// -// -// -// -// -// -//
Spa status:Loading...
Spa temperature:Loading...
Set Temperature: -//
Spa controller:Loading...
Spa serial number:Loading...
Spa interface initialised:Loading...
MQTT status:Loading...
Build:)" xstr(BUILD_INFO) R"(
-//

Spa JSON HTML

-//

Spa JSON

-//

Spa Response

-//

Send Current Time to Spa

-//

Configuration

-//

Firmware Update

-//

Wi-Fi Manager

-//

Reboot ESP

-// -// )"; - -// static constexpr const char *fotaPage PROGMEM = -// R"( -// -// -// -// -// -// Firmware Update -// -// -//

Firmware Update

-// -//
-// -// -//
-//
progress: 0%
-//
-// -// -// )"; - -// static constexpr const char *styleSheet PROGMEM = -// R"( -// input[type=file]::file-selector-button, input[type="submit"], a, button { -// padding: 7px 15px; -// border: none; -// background: #007BFF; -// color: white; -// text-decoration: none; -// border-radius: 5px; -// margin-top: 5px; -// display: inline-block; -// font-size: 16px; -// font-family: Arial, sans-serif; -// cursor: pointer; -// text-align: center; -// } -// input[type=file]::file-selector-button:hover, input[type="submit"]:hover, a:hover, button:hover { -// background-color: #0056b3; -// } -// table, td, th { -// border: 1px solid; -// padding: 5px; -// } -// table { -// border-collapse: collapse; -// })"; - -// static constexpr const char *rebootPage PROGMEM = -// R"( -// -// -// -// -// -// -// Rebooting -// -// -//

Rebooting ESP...

-// -// )"; - -// static constexpr const char *configPageTemplate PROGMEM = -// R"( -// -// -// -// -// -// Configuration -// -// -//

Configuration

-//
-// -// -// -// -// -// -// -//
Spa Name:
MQTT Server:
MQTT Port:
MQTT Username:
MQTT Password:
Poll Frequency (seconds):
-// -//
-//
-// -// -// -// )"; - -// static constexpr const char *jsonHTMLTemplate PROGMEM = -// R"( -// -// -// -// -// -// -// JSON Data Table -// -// -//

JSON Data Table

-// -// -// -// -// -// -//
-// -// -// )"; - }; #endif // WEBUI_H From d7884fa1384b3b505aac682dd93bf5a819d0b246 Mon Sep 17 00:00:00 2001 From: Jonathan Giles Date: Tue, 10 Dec 2024 11:09:23 +1300 Subject: [PATCH 04/33] minor cleanups --- lib/WebUI/WebUI.cpp | 3 +-- lib/WebUI/WebUI.h | 6 ------ 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/lib/WebUI/WebUI.cpp b/lib/WebUI/WebUI.cpp index f56c74e..fc3f625 100644 --- a/lib/WebUI/WebUI.cpp +++ b/lib/WebUI/WebUI.cpp @@ -156,8 +156,7 @@ void WebUI::begin() { request->send(response); }); - // Returns web site rendering of the current station state, - // served from the data/../www directory of this project. + // As a fallback we try to load from /www any requested URL server.serveStatic("/", LittleFS, "/www/"); server.begin(); diff --git a/lib/WebUI/WebUI.h b/lib/WebUI/WebUI.h index 4673f4b..685063c 100644 --- a/lib/WebUI/WebUI.h +++ b/lib/WebUI/WebUI.h @@ -3,7 +3,6 @@ #include -// #include #include "ESPAsyncWebServer.h" #include @@ -12,15 +11,10 @@ #include "Config.h" #include "MQTTClientWrapper.h" -// //define stringify function -// #define xstr(a) str(a) -// #define str(a) #a - extern RemoteDebug Debug; class WebUI { public: - // std::unique_ptr server_old; WebUI(SpaInterface *spa, Config *config, MQTTClientWrapper *mqttClient); /// @brief Set the function to be called when properties have been updated. From 4059a892ef19384adb9526e0baa78f6a0235980d Mon Sep 17 00:00:00 2001 From: Jonathan Giles Date: Tue, 10 Dec 2024 11:10:07 +1300 Subject: [PATCH 05/33] remove bad character --- data/www/index.htm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/www/index.htm b/data/www/index.htm index f64c0f9..e951c5a 100644 --- a/data/www/index.htm +++ b/data/www/index.htm @@ -63,7 +63,7 @@

ESP32 Spa Controller

Spa serial number:Loading... Spa interface initialised:Loading... MQTT status:Loading... -Build:)TODO - NOT EXTERNALISED YET +Build:TODO - NOT EXTERNALISED YET

Spa JSON HTML

Spa JSON

From 5710cc0a72531a89444af8f4616d50371719a581 Mon Sep 17 00:00:00 2001 From: Jonathan Giles Date: Wed, 11 Dec 2024 13:28:41 +1300 Subject: [PATCH 06/33] Beginning work on updated webUI --- .gitignore | 1 + data/www/espa.js | 77 +++++++++ data/www/images/heart.svg | 11 ++ data/www/images/logo_eSpa_02_320px.png | Bin 0 -> 114846 bytes data/www/index.htm | 231 +++++++++++++++++-------- data/www/json.htm | 135 --------------- data/www/styles.css | 34 +++- 7 files changed, 282 insertions(+), 207 deletions(-) create mode 100644 data/www/espa.js create mode 100644 data/www/images/heart.svg create mode 100644 data/www/images/logo_eSpa_02_320px.png delete mode 100644 data/www/json.htm diff --git a/.gitignore b/.gitignore index beaaf8a..8293886 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ .vscode/launch.json .vscode/ipch .vscode/extensions.json +.DS_Store diff --git a/data/www/espa.js b/data/www/espa.js new file mode 100644 index 0000000..df21ced --- /dev/null +++ b/data/www/espa.js @@ -0,0 +1,77 @@ +function confirmAction(url) { + if (confirm('Are you sure?')) { + window.location.href = url; + } +} + +function fetchStatus() { + fetch('/json') + .then(response => response.json()) + .then(value_json => { + document.getElementById('temperatures_water').innerText = value_json.temperatures.water + "\u00B0C"; + document.getElementById('temperatures_setPoint').value = value_json.temperatures.setPoint; + document.getElementById('status_state').innerText = value_json.status.state; + document.getElementById('status_controller').innerText = value_json.status.controller; + document.getElementById('status_serial').innerText = value_json.status.serial; + document.getElementById('status_siInitialised').innerText = value_json.status.siInitialised; + document.getElementById('status_mqtt').innerText = value_json.status.mqtt; + }) + .catch(error => console.error('Error fetching status:', error)); +} + +function updateTempSetPoint() { + const temperatures_setPoint = document.getElementById('temperatures_setPoint').value; + fetch('/set', { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: 'temperatures_setPoint=' + temperatures_setPoint + }) + .then(response => response.text()) + .then(result => console.log(result)) + .catch(error => console.error('Error setting temperature:', error)); +} + +function sendCurrentTime() { + const status_datetime = new Date(Date() + " UTC").toISOString().slice(0, 19).replace("T", " "); + fetch('/set', { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: 'status_datetime=' + status_datetime + }) + .then(response => response.text()) + .then(result => console.log(result)) + .catch(error => console.error('Error setting temperature:', error)); +} + +window.onload = function() { + fetchStatus(); + setInterval(fetchStatus, 10000); +} + +// Modal dialog content population +$(document).ready(function() { + $('#jsonLink').click(function(event) { + event.preventDefault(); + fetch('/json').then(response => response.json()).then(data => { + $('#infoModalTitle').html("Spa JSON"); + $('#infoModalBody').html('
' + JSON.stringify(data, null, 2) + '
'); + $('#infoModal').modal('show'); + }).catch(error => console.error('Error fetching JSON:', error)); + }); + $('#statusLink').click(function(event) { + event.preventDefault(); + fetch('/status').then(response => response.json()).then(data => { + $('#infoModalTitle').html("Spa Status"); + $('#infoModalBody').html('
' + data + '
'); + $('#infoModal').modal('show'); + }).catch(error => console.error('Error fetching status:', error)); + }); + // $('#configLink').click(function(event) { + // event.preventDefault(); + // fetch('/status').then(response => response.json()).then(data => { + // $('#infoModalTitle').html("Spa Status"); + // $('#infoModalBody').html('
' + data + '
'); + // $('#infoModal').modal('show'); + // }).catch(error => console.error('Error fetching status:', error)); + // }); +}); \ No newline at end of file diff --git a/data/www/images/heart.svg b/data/www/images/heart.svg new file mode 100644 index 0000000..43bda91 --- /dev/null +++ b/data/www/images/heart.svg @@ -0,0 +1,11 @@ + +Created with Fabric.js 1.7.22 + + + + + + + + + \ No newline at end of file diff --git a/data/www/images/logo_eSpa_02_320px.png b/data/www/images/logo_eSpa_02_320px.png new file mode 100644 index 0000000000000000000000000000000000000000..1f329f3e6eddef30e853769113d077d168ad3f95 GIT binary patch literal 114846 zcmd421yEhhvM`E!aDoQexVt;SodkE;8w<|H6I_B@f($#;tM*#6db(%Yrl+S@xVoy`3p5fm7#Nrr3i8r#U|?V+{#+Ljn{3Il_V_veCzNy{LDfkC6U(bR?NswfLtINGzBfgQ~uY@YT`05lAYh`6Vd znZ-K@l+qkxW#b?UI&N+UQQCk-K{~uD94bz)A=WnX-Y$^0-m01w-tQ~~!60!lN)b;X z0D(OOYDVd4Z|C4Dg> zcq#b>**N)lcm+9FD7iSeIM_M4*f|7QIXQ)R`Gt6RDF68b0n}W;mO^i&W&cSFcoGF! zL!nMW?Cc&M9&8@mY>qBg?3{vvg6tez>|9)|00gV6mjl$ylhwhM`d=8NA+8oKHcn6* zM+eG37|qNb-Jqf%V5EOd!QSa_v<|NSWD~$Jc26@Wc1|{qKU4Y#pwqw6|6c%s7XTpl z-+*9?zY#jQx!C<Xh#kZp;sA98U^)MW1=y*g@;CVZg7#nZ?d|`Dc7@8g14I8O z6aGtRS4}S`2>Tm|tD~EX1w_Ujph*3%8Ms2mY=|AX!T_}`tKtR10_uGWtK4Y&S& z{Ws5?gkHNq%%Biy;1UG^qUHgF%*x55$;BbjA(p_*zo> zk796BvQo;rm^pM6nc28fGRV3>94xFE|9Zo~#lyx0G%BmSrPPD~&5VEHQgH;^SbF^@ zg1nj>oI)JjLfjn8e{MMb2?}T{*bHj+zXb-QE2Qq?2zIl8xQK#)Cnq~cC?_AAHQ0s{ z_~YPWW_U*qd2F*qt1#{y|SgMM%NH6>8>S0a1_^1pyOh zv#|jSK?FH1_{{;e0%qKT{~C>&iw$7+ zW_JIM_0Ool07i2@bBGxSCpRltkPplX;pE|E73AQtWaWc!@tIo+@L7O4!63^2p!?d< z&d~+nJs@W8KUN2D0cr!agZ$HkCGDX9ytA|UV@pDIW)4;W4_LtvOEWh+C`e4r+!g{A zVgF;Db~XU)KkokO#{O@}{$VUa@;0teM;EVuqI?T+{tx8;un!?Ki$At53UW1bhXCXJ ztI_7a;Qs$?o`3cCu!aCA|JGtasW^nV1ckVG{-soZfw?+bLOsk}Ad*&qr2gdt)&FHW zlw4eFoRkbYHV$A%4_82G|LSC64KM@(_+EAp`~Ty~@IZLX`OVEZSs{Xaf~0+ z_{~|tfY0UN zIn22@`GBR$lEVVR${`2{Nr2PRf|UczWx)^TG2^!6=KBAOkp8!m`JXwj|IU2=lTZFX zXFmUM9)Gz7_W$fL{(6@FOD$yoDB3^PM4|u6JN!=#3RonC08jk4Z~njMMgOAj`2W@$ z|1p7oO#I)Xoqsg}A=IDSzhgJx;qT}V;sCfE7a+C^&$#V|fvtmAke1Z+%s9w&%fQ>d z>S^c38==$lAS6>%LjV4~U`c6lanZ;jy2*9lq2AkZaWTZZWTo<(K|*x%(68gzS)-Q` ztSq1J*LUfM=zb|LRap&tjR=n5FuBjAtIPyn2E+CtqWP0iRvf$Xt-w^@8NcknAcFN- zu1;#Zgnc7Hb^bq z_`v5g{7(rSlGNSj{L_Ll`H89PJ%qV?<1z`-(N4O+h2SYuJXi-Qam4_Q4($%2Y}jHM z>c)1a3kkF3cMrBn&hV@f)RizdsJc^PPCB6A;K~ zse=*qG}Q4CYmbfMwKTOPH8j<=CO=PWXi^7MNlXH(Y}Ob;Uv@snR9p<- zou9jQjU?ZVTkM|^kAnakBw5j_j1(nH?Hxp(X&h!;@u6a3H|_#AmjM(3`f)Zy4Rh)l zXq;@dVs+{LsuZmR90BH%VM?X>teB`+sG&umP-HJxF>S%IH@17Zb16ilAcY+&o$%PD z3-f^T9_s<-fon3_?#D7ZFl#?Nf({;24^tl=9rw&^2DDwxG%!d(B#S0fHE)3HR_1nw zjBmW32Sx@GvO%~J4;lGkIr8JEGCngsnz}b;*8GPxu(qUf5MA!P@TSQOrcwC#hT`@z zp3(ZZNz71ZU`S-+LDbj&eC`_&F;#(kT}<%@(==fNdAbA|bJV~9Y*>>xbxLIhd^$1| zJhV_0Bq?broF6$Tr@8=75d-~=E4skHdn`uxacG?xdaDR-aBpBzhUm~w{V>xFSDs(& z_#gUb-Ww+d)GqComL`0p|0tbHv#y`fVaK`NSNB%KNL5lpEaWF5&*b#kt-)q^+=;%6S4am7$w9$6kTTC%8>>$_902hRnu1yz3XWWxH1ppkXz z6)fDy9vF_aDBYTGDZdJN8z-keR9K9%bW`}N`Ktv~jOI?KpYZq4!9CoAkZ<37?#)1Fd2iHrNd#Y~0#(}w=A}$; zd46n4V4ZNLx!s8A+YZw`3{{51JR5VsbNhere;jo=)Q(gZdQF2%ONJ4jn5?Agz;~)k zCW$X_w(&Zp@~6N+=>P*GbC2b)R9FlKF|J~uv`9(WSLwL(vv65+`48RM#Y`n&G(qY- zCept5K^!YD-^s2izFbq>x%VLW{3!$U`Jt7Q4h1fk#=I`Ac%%YyFf+C@mPqxQ1}CRz zP)5mu*?#ENci!5Gv2g_*IsSknN*KL5mTJ4-Q#j_RPS9m$j26rm#FogU<_1(hcso!> zJMt9*=7A5p;S}6sxrIm)b<@AIQh7a^{ervaYrqVLl5?Y_5&kP=2qjDrt zu+1dWNjUVP?KmNzi9$P-G#&>>_QRo9ELrWJO#CwB)^j0Hj|)mG@PVMa-4zRsf_^H- z`PddltfW%6FM%h9ZUc@x1dk6Ja3mFo)J_~uG;<3}$D?ZAl71iMIfBQ`3+vj_GOuUi zo$=(jy?@A;?lDz`>vbz&$H?x06dADfGnx6pcKGPn*wU~F0ls3ys@LB3>i8j^ERrHg z5?Wf)8XeYLT+Uxn?P{hpLA|op?;NbgT4-5r+&Iy<*$Nx0LZoRzr_88@djsG!DYc4OEaI(2e-rU;jEazulrjBP>(WkX-l*Z5@5=pcs``CSjt9~SgmQ}0g9v!PM2jN73hmrk}FNxU}5q2{<%%CO{*b;lt79Cm3~bD z_Y`b0oFlF0#+bJ+SGD})GqLVmZGD8hHJm!)C_ZG-A1J#v#t_p&c7Qow+SBrGd0%^_ zy(6*1(Qii8{s+JXm}kQSgp7c#t#bdT#(GbdnBGG~1lzr@Gmw#2vzB-GJ&v5AAUPaj zt{V&3ChumA`-Q&FefH&*6FmpgURD`uamoAaR{I&U6(>n-1bjWJ9V{I6Ae2D=S#!(Y z%sQ+3O!prIdypq~^qZ~71FWG6Xwbbgm%3WqAotplpdZueO}@sz|M08ea*;)GBIWJsOYLqmiG--%vOl`5LKSk0rM2cq+8KkVfo%PPe2&~ z0z8R_8oN+y%n-d}Po1#+koE)}r;9Ya_r(pan2>if5=-kP!}Z<1)Ks5e2!qoX^aq`g zQ7dhFJcXvUMSv@;y*NE565xVm%;Fcq}HBd88%bK)Cer{a`>WlT6=e`d& zN0Aga4|%iiuQy}Av)a%x^QSL7keMQ0Hz1{ixR)&;iNMhKUR$Jd*!>v>mh5-0teVkD z9i&ll$s_lxgpb`soW3++uly+I54oaGEqXwp6|^RsGk)rbwGJUa0=pI-BAocA$Ek7C zrrNWYEmOFd&ERN65hl_k?H&vw*x1 zM2Fdo+7+dO(BSNZn=02;)cxG->eKaoTdnh@5g{d2i?$d++huVG5g5 zpq5``Gs8O|4IlcnZ;#A`JwpJ|um0@p(E3I*%oqXMg{BSHvC(99Z`dTx*ncsaalSt6 zA_AS0=ptwvH8P-iY%9)DLMd-H*sOyNj*R>ukT0NBO0#}> zZQu4-c2eP>a^C&GZ4{&MkcWU-+YpCPrF;waLrc35pF2KL6+4!bI_Scr6AoV*7S@aa zjc>n-6&68~MmpHI-Xr^rb_J_)B*#ZWfA#0KF@5H+y1qt>%Z4Y$3B`)tiarljsLBis zFyj}mX`QH@CRf<+33PN;aa=Q7+c&a%|icRpf zu)D>^@zn3OU=V}Fqfly@ur($GdB9Yl1WF1;!P5$LnBV_dCRWg(icn!j^; z>{j>UmE{>`qSx*2^vzz4BQ`?7_!%yZ0*P|4K_27i19Ahd%9$VDZ}@Z+r$=YOw5jRk zS-Ta>on4m%#rzrXJNzqQJ9hVl4?a;uJ6FPhaQz~F@{?)L%f9HkDC)d;caEAy^n*g- zJ&L-aZZPJn=%K+I+tums_3l7`6c0gsmlRSxz-3EXO3dqkP!NNgK}A@lOQxXj5pcLH z2?GSW^Rr4=#C6N=BnFPcsUzZd3DaNv(jCQ~$ulL@6!gZwPcjNc+&j7s3_yrrPu0^i}LuT=EIQi)KX*VAkfNTIzf9 zCc@b(yQWN0`COj-qV547`Unsgv5;XVQ52H`_cgci`#UY)M|aG+1v?jX z7i0v>v7^;@qo1tHVT_5g^3IDKTl15Y?LcYm0GZq3+a#psjv%TCP%1Q3 zTZdFOG2p{hN+)Ks+WOS?(nkBUZ)#nL%Eo6xiyAAcL6>J+w~q6UC2Ox>(Jm*?r|qiU zazp-%h~F{?4NvTM6EF4C=M?A?$lSI#MIIhnGrWJC=8rR`8M4A39X*rqy=1iU_W$7J zZ}*^Ys+ZJ1GAK99VCcC85pn8j6{xn?j4r1p4qrJwkmV(cFJ;1h_mzsBkQZBe&;8At zPjZ_n-ffQu2C4!(JX;S}=ma5~uU%%5lMG*&*fR1Erx}%Xk#r5uhy=bc6QOP+)X0dt%$pmpC}e{*i1&kSO5Rp$g?T5XSR zAxu}N=Q03W0lk+tAb#;MKVv9t^HD2a?7}UANz1)plASQ(&)c9yb7m)Y{mj!6i3xA= z!e_6C|x5mI>g0iC7BvX)eNRYxntNZ1DIkrx{OzHFZYZ9rI`G*6C?rQTlO6d$0C6px5uIB_bA89RS?CNp~ z2ETQ|9;!uM`@r)wr4#X12MCilg}gg%4b2^wntRDc{d8~oYuH+4WrS>Q?DjcG<>kt; zM!0rRqt!FvV}F0<;i7y(U%VCB5NFXVRT&4w%p5k{)8MU8I~eZb(uhv$j-yJmo~Q`L zG<;kk=#G2>4Ouh>Lmb9uqUSvuj>-oCEE*}tY?`ON>{6x>uiJ-~8-DWUeMXmoNGhCO z(&*C}yldBo?dVAC5F~=`&PHtHMh|ZMTNAy8OO) zhfk;qhFe3|t%)zbT(jw5$tK1JT`$Jk7piTghJD%oX=U>B_=UQ*o{)f*Mwqs0J(j+T z_qi5&?}677~UgUV9>+?3Ir(tIP{6jK_g_(KuFvEo|oZ7{Ke;u|f3Ow}KD zReAh78eC}AEP2!W{Z#3dR8m}7WMc1hu`A_YF8SVyN;$CeuFI{MG<+IBA6^-i+?b9H z8hU9N5}2<^5X2BznhUL?PSP=NT=&im`w~ck60emqDChWLUY|Awt0^Ire+)c1t}Yu{(-LtNGwv3FWVc&kgoW<=-?(PbNjI~e?QBJ zH$uO==ko6ep5`VBUR_W-r;zb@r)dzl1-Z1}8RZYGp-F{ftBKrVn0z?nRZ%iPL6qvN zj>@0NxsbX2rl+kqsFYH@m~`MXV;og%r%TmpX-`B~@jm4GMF`6vkZ(ZynZvAme!pOBO4>n^t)R}lg;5;VPeO@*7AB>PPUwB+uXJt-A2V{|dgR9&&SE(V zDY!m;n_C*DlF$24TGWDOJR>8~P--lY^L5w8r1seO%z)bR(~m5lgSI1t23R$Gg#?tF zAcPR?M0%CAT^)+et<;*Eox_p7p+UV{F!AU(*!^`4(!~Dr;4>)@igDnu=J`UO2@_~= zBk7##-MAd~q=(zjSPE4#BA9mzr)EPZlL_nE)U^mSa7zZhZWJ}THayNX>zzDS5WV7a zId^4bWef)6YH9FnaS^H0gdefdt1aK-AGck>7G?N>!d|&xXQd=NF|@dIEuH*s?Lv~# zh=bzRB2G0(Ib?aR68kCEX1$-xkKJBoaJ}gUm9c{Mlm{=HXGHgX6h`NurU`hF;jfS z3)t;g?NB523-&X5@T2d*^Y6VEx5hC>wMvczzfrOmTwhD9+WW?H#TPIT3VG;~`1xAP z81eYS16A@D*B7PV)OicZ>!;P!tOy19NMjN}nytofWv*^>zNXuS1wA-ZpER{DK%Xuz zphAMjf!yi@pRIYCETxE$6dqO^l98JqDBhoOVl7`HDES!#gZbh!*E?)^sV_di-*poL z{N=LWBc4g?wV-3$4I98)xcj48!nWX83CafJ?JoZSAgs)dXK?>Y?BWvF6O;Q!#Z`yl zqj3m4t2TJ0(K@&&&#ct#Yl9X7EG@S5H2tFK*(1_tzr za(r=qqirl%e8g%Ruv3=YHZqczcYP0Bu@~vbiN+1V3#BeBe9X^nhh_*GD=p{4l&Olj zeea5cNn{lsE<RLS98sN4%n^$vfG~E*1*w|XRz710jgoBgxLlLBYEh}4T74S2VF*R5HQ-c`( zM!Yow!DnN=9Q~r#SbbmTQdok0W(w-Gqr*kRLzU$)`1OvaBN~-J9h|C6qAGN) z+m`uAz3g}P3c|a|jLss0q6{fOcz$NTd6xJ8+(Bwx&YmqQ__`CjO_jcxoF~Z7*bi3b zN-C|jtdH2MtE^3oAwtpDSZvXlp8xTjFN%)(ii|Y#F!R^lHe!ayWR5%%JZr~kI755) zy5`9{w5fwIP1Q$+|pf+|6qKOeGk*O+|JM!V%Va{jwxgN9iBhu>Z$Zwgh=o_|NorM!Ye^rOJb^O}1 zj$qL9GK!Pc3PA_##ng!+)D21vvu)@@PM-zEaK_~kG~g5X(ac4Y`BBSiHOA+-pt&(9 z?UdRkwb|byRxk=(O~Bi%)`S)(pOeG}2UE{whoJcM#KDZl_LEgoinqE(vQ52+)cbEDh?>=UJSyCdEQf_vE2H}KQH7w1(ud> zY;ROG*rQ?%d6O9^P|3nJHDzYFZvI?w-u$UtUS`J3)4y&Jgp(%R6xS@Q;Vp#omAT5$ z192;rFb|4@YgM9|Np%9tDq%(Xb`P6&g@iF|S?5oqNyw{El-9b0U7z z4l!S(Nh&>i6RHe7JR?4}W3L2R4_W#@MZ_SyicFhvpSBUX8i!ZT5(tO1s(c+Nq#!Sj zqt(CNP5**=9|WY_Sxc^Ns8Q0CzZ(8zW+p-=1tokW3C~XG^gPq}i0D;3MkJIN?_S6c;4RG?LL1VZ%ZU&fa$!J`-A#?c zH{TTIpoQ3JN_Re0&tU(`ln>b0Sn!jE1ozGD1x{q*+5vYD`ZN@Z~1= z*%fo2aYYtN=D~}6I!bE~m+b6(hCEc@Wg~iqN#1@C$_y@=R;s8;PGl4P+)UB>N+~Io z&I%oll)XxKTtWI13Xr%ROO0Y^gK1Jo*QmUYSs=i~HQ6on0g!gZ&aX)lpe>x|ML zXg&5~q5gwGV?L83OkW!598& z=UHl80f_f=L4D^NzOe4Y@lALHTD1LL%`~ZR-Zy2LQNx?vRPcEKWW~2+<(!w$&nsNNVzsfPM z$JHJW^hu3DiwdTN_4J@Z%*d$;XHa)oSi4MT-d3)d)%Z zh$DQgh@VW#$eygO#@>9;2+td$75ut=xnjzkI%WIaTt1CLgHh{E9_+CAI)*V_xgyEtvI_{Fnlz^cE+d+M0$-4LrgUvW6DL9 zouF8Ndh;6Ip4P7(&CeKHIyQ^;JQ+8-JC2LXTm!Z#e4P<+6GAK7(VkHlac{J;!etx9 zh_aQ(AAMUAf^pHQqbY)P--eS!<}skz4;}U~?Ax`X2l@~0TMk$nINvCQt=JsFguRl) z56|>N?4Mqi`o%2G^i`sA{yPt09!{sZEDNhF@NDBi=l#nD?3)tQRu?h6g=tG4wJ~ae z)sucwHX-m-X%ntR_EI6?qpStXd0l0%YV+w%RHDy=<5xKyQ(7}p5fhLD8@#C!*ikIL``PCZ8qoYr{=+l<2uJmm~KrjbN=^DPPy#Nh@@lj#2{&PxJ8H zI8`h8qKW-{gJcD(%DHd4EH9-3IAmcbojiXo>rQtTGg0P*g5ue3X`EGl~FC0bvaY-C{&I3!Pmo%!w|lcim_o zan6rQzlH^DP#qulu~Z}QDNb9Gk{LM826m8WXJ?#dG?EDt4Dz7(Nqyn+U}-J|V@dL# z5E&kJd#XWO8RLbIBrgK`5yHFUJaqM%Fu1r%G(!)_gbN6Mc5g-(NmPpgdo)pRAar!0 zga4qNou*7BV8`H(uz`hk^^Fln23w}DulQ6TF#ojz9jAfvjGSHzMhd1gNAgh( zMvr!N$2v^VgQuRWI*In^+!CZ?ClnlvG5Hsvyoe#UBEG%r8~B^+eR@ zvCjl>Ekq4v&q4W#Czp5O!PJJ(37HJ1i?IfC2dQ^BFVwZl(DhUuFlU93?T_4j@9qdm z2wC&W8sTH-U(=AiinFa2w!=@te`8=G)0N`g;~*BA_QQN(%s4lm;GOGclycp$>SM8x znBTQ){+T(~@(9)WtR05WVZg#H=DxWg1Cx}Qn4%o%Zfv`B-w2S*uKxLHsJOfggu5gl z1l^DHh5Po6ak`-sEbZK+-t2>ITdEPX>Xuxpq187aW#b@oxFcJsANN{AaUhb@jKpxM zc6ij`J)u{lprPBP_^jnUW6SM$Gs}%VPNw}L%uckoghUK||BaMx4a+3&WaR|8uv16; zy(#~!jdT5F?WN(gFC|>RbZM+EPu1JR{+lBG6F?&8cM9|4hR~%(eEdz<`Cr2QVDK55 zYwft?i)&ax>&2a?-!~?d9ZI8V1h6ExmqMc57S0Y0K6J>3RamT@mieh5J0IS zY9g$UY*u%ZpSrA${S>SW=);NtWJPnA zqz`73;|=CUqrcHlZJM9C8zj8@MMZ>Bc15?aVxVNSYM+TiKiua`-8Wp9C@XP>-2eWZ z`p#w|^yZ!k=)AX2p)S;fZOb%9iZRKfndcxOC!a~PdX0>-`{ST;-QBKvosUJoGT5t~ zCELb^8`cC{CW+HvNb|QQhvg539y`7?TpygHlrZ=0Ec=u zNA>f7Ye6dGXNM8WjLA}^XJYaYap!JUTMmJUm1TLTbYkiy0aha`y-`J}NW738U;6B^=yiL1UL{5+(&JWxVuoDB{#Q)E^oYMqr2>>s^*QI3_%kjuoBdE@{b z^)K#_@R15<@z|`TB9!Kuau9KtfnJmN2^8yn2;_irB56oS<}_9jXlW@FyxG{=R@c{) zV&T3hiPL)OLHfoV0V>gqfV62}ExBQ_sHHUCd}rQ0+R6Ez`$^f7QpAH=KWk-^ROAn@ zw;4`&ze)JwW*!=)u*i~o96)8=aFhtII5nuVpb9@1`v> z>U_b!5FzQ9-B27Cl|hxMO#KzD$jB2{5YfxiTV$t{S-$<@e-OqE;0Rm{-8;qk;)Pz!Wv*9JSXwRA#|3zwz-)To!$XF{%pJ5d6lh~g-Gt_z zk}YajXz%55Y}8#VtdO^`v)6+34;=F`BC(1u!%J)#tquv{mpa9D^Y-7Hg;UOlM!?%! z*cV~NrDgfmO&Qh#d@T1>IYkEhK`av+HkQ5ih36-J$5ew^GIHNryn~U73=QAc^qn{zM zNKWn3U;eDmH}(zswOtdhs1!Fu*R;iEd5nj-)&YN2z&uma^Wjxeq5OU$jwJR@wAak_ zN~`B{ZLGE7f;7aQpoG1h*88kc_o$7yqy;G1k%*Q~#?nRXw3F%^eyuew{VbR`*-T+( zU0hJq8g>?6OXmE83L$|iI+I_DAhxtLXuFM%s2cRvnqeg~cDcw)fqRO&^t91CRlo}l zGZWrVh@)jnp0p!azb;6zra85&$Dy-TZMlyw< zJ|>vq@eq%1388{_v>Z1)*e!S)&-jwozEBn$8w2S=_|V_C=oJUK8%Mv~7plu1;hl4r zk_>^gW3jZMkRqd=#n=%LKRt5$vRZR{(BsuodYpLow^WaWs96TGMTwp%rH7_@Z014U zuf^b2lk3(G0beGEvfaPj35#9yoTQEnIbQwKS_E$4VGD20uf1)@u!vPO zmUrto)=*wfvu+~tyOG6=4+}EDX6UW9me9?r(}(5zIUcibElm{mSE(*V?#m; zqbyVW4`Qgx0;k+teT{)K?&Ivu=@4-8OS7+~!C*MACy+W=Q&NH>6?;%oK7Sm_W-mFu zFR)oXA^3QZ7+#onbGJn_9lRRFT0T-oqmY|dpJ-2~vKrcKOKrF0-ON(dFYxUBVDB$qN`W6N?AY<6hJD_e4>Sv{8Y{msHG zm=Kii*p#_N%Q_idT3~ZzjwyPG((^m2u(tk%S;`x;$>ql?Gi;f7OC9EQ64^fVlG|7q#3c&;3~{hQfkR?(>> zrOl(nD1h5g^Jf_ps6PCZ7Lnq%EZTCpTwn67;>XlsVRr7Pt{CAICpwXQvLE8`xeVhQ zwgoxWSw3IVe(wIm1JDypZ3Zcv_)_*Q)9BqDOZhi*7XNrXt^lO^t1R`97MAEd&~q!@ z3Dq_5na~Dq4$|2@cXy{5$}6OHFG0FxVDglomReKa^fMH@ERo>VzUBH;jA|++FoJdX zLybISTUTAyk_{u5Y^j*p!+MXrBUp=6LG;4u5*!~{26>wG85xGx&zRYAcN<=AJvYTA z^=M}-vf)+P#+?;%!|V4IzUH%Qknih==C77t+Vz19KC>m7ChHHdR#{x`gql|>UREt zX-KD^W}aB5Kohy5#~i=h{)Z7Z-l2(b9pKB=S!(A&1XnW0^}D^ zX3Jy41%HM&80%=l;ax`bUUoc{2i7spr2R3vLi{-SN>&mkrtrP) zu+TMr2F^BG|5;Z^v`Wz*({->MtTJ%A@8WklI!#`2^8qS|NtFX@#y+La@t-;UCiR2B zO~Ni`e_jB}^g1Oz$_xB>as3N?z1uu`VE<~aB^*W;4BUmAK-iWpqdENQRJsBHwr?1grYU!h$lIHRlMW$iAVG zoYqEo1$yVFp=76nQ#tI9VJLEZF=X=;TI$mWHjpCwLf1j~>C+KzOWYGg=Z%?rMErve z4{Ps0zcSFJ*u!VklMg%^ZxJ*oanx3h-Cf6637t=(K3HGWVm1WsqXmum3-6f$#hg_$ zHE|!r@`vcN=WSgz+mW^K8SxPGxooa>+?;KbqH(-MePvcdbU&%#I+H-}+}N9N5hj(< z93oq6IK%x1{{_FC)F9c0)fNeZfhHk1ENCU~=a0MOj?|^`wGb!4-M}jTsLywsbsDR?d_<=M<6>-4_h+6}Y5* zHG4~OQ-19{5mIl;u><6180PSmP*12T7kfzi@7606{jqY~oJdmyJZhmX2Z+6{KQwwr zaSwFgh4hx14pomfI1w*q>Mv1>vOyF1UROf$pdNvgaoSq8Q1AEEzX&A7k$8;6A}Kja zV;_Fsrr{!d@~0@td1>>5h^wZ(*S5y?2O17LQeJ>27jOOtU7fyaWivC_@`iN6FYi;o zv6NXDO4{JeAMk|8)1CFok|7o|Fj!sHFFRc#@~`c>yfJ($34E2H$Pi32#YBnl6}9Sn zTvX}Vtk0LzMICXMsj}qiYjW_4OOo>8f2=tFjqah|rwu}C%2CoiS{yaZ{yQToEGO!$?Et|=31K-37XgRluwI7` z!Q*#KP$47n07rC@kl()N>>=$S*et9Jp_|C^9zIL5DndddPt5WZrNj(bAdA+ZN6*ufZ7NM&JOW_yLNJ#;d^&VvzGuaOC zqrnbTD@#g>VUBf%aI^oZpx%?68sqWcyr=MhStsqW8CQ87+%$f#-t*STuz$qWZ*yUt z4Jgp$iJ}Ov$wRjSq2`eQfn@RIF7~4Fn{z@C3LJ0V-f4q~q3;|4(Nozr1(5hp{0hlD zf8qiN`LbDNhBO~Fe(_s=#;DF!*U*Z|?E_R4_)^8?%*6>jKSp}7FSgrzY-OUU6**w= z&GOIIpVxurMczJ9&8)S{1!jf@|6w^MjfRvqm_-|%whol^o&W5Mhp~D8LqUVLAvl5Y z+pIei)8LHx{?M%3$SWXkJhpiR``aE<*XS^8HH;D^KY_7{T6I|XUfDa7e93c{)VL;X9j++4x1jq0c=5!o+H=qJ9}F2n1{5uPhXlU24il zy#ekb`JNp1&Q|}|Aflv1(F9JUEb3h#kVeCp_+7h`=kHHDC{@x(q&Cni^V|}3ZG7uL z(4@E^>fkaMA#j%8^>IK$Q^x4HZ(aR2a0DK<7{I=_oy2UJ1E;06`JF{icIu|e(05H^ z1E}Vn)q80i-OCXEb8N&&{%ovB;rW8ut5%C4;>U~RMcFCz&zhP^6Z@Cn+zyEK3X3aY zH1Kb?y|`~rLh2d6eeE{qoLHI*AG0={!!)Rw;xka^&J8^A>ose@!~o(`6D46B!VD zCoV4(KKz@FX^*LK^JyO&`^2+#|I_PH$a6(uEzdi|`?Yd3G&^Qk{s_hcW$^p5$XoJFvx zn8W)USy`>ve6LrobUHnEqXm>G8@knv=P^EdXXkLXbWuNMC#5zw6y85=1brgK@GrD9 zC@fx}l6X`V&Ym|Tsj6Y4x*Xfa=bIeka^zGKyC4G!6Fw(VwuR!8%V_ku3t;0kT>Sca z^H3XGOu`@N$)fu1t?)dsy$pNh!C_#}jf(!#yjwmWZ_ceM>wXqXOAE-Xwiqv?9eKCQ zmzNgL*t=s0iRzfRP#=ptGR2&km-bHLogu5kQ?Ug4YZXyfRO4$^Y!^BDt>y=fZ1nh) zTlP3KkIl`u{pQ51#V;4<|K3oH0vix=PB_-kfLdQeD2dO=#+qxU$(kn@4U$2t|4OKV ztwSlLkZ^MQo+vW1adYXN;A#iAwc~DfZsB_;@C|%+QoB6(rb62POHfh}ivlirJz?Hh z$I!Kjl7>4K>+tUvpmtxBz=nl+Ev+Hk2Wpo}e8f*;UnM79Zhl{`eq%rb(w(^(Qkt4V zO+u;jB43VT$jf4@vM)!Rgnd$lt;Eo`S%Gw^27hUiadKGPU{?sgakrSyfkIe?YwKXy z@7_c%tJK{SDCd2mV->+>{3$Yu@WI0E$}4!F5|6azpoJK7{hcFia|_1#xBYl5@o;4W zWJH33U$uIcG?|L(d=%q4Atzh&Kq$`0bJKMBYuhw1x zWXn}h68nG?a*>15$5owc%0&zW0)6iseS%pA@d*gcJ36es_;wZ@f9MDML>^=IYN-+oIg z`y*|ed-Lp8VTbj3t=HGC{Xz=4Q;WlvFV-8c%9$H>@|iyd=jm4edQ9@+Juz81$$8be z+G~;%vtzv?0E2KC++ZLixZAQm<2Ws9b6SgO5YP~%ENMnATcg1o`0=N@Ppkj;E7=)R z1jL_nS4_7 z)gZqO@xp&en2?yPB9fKwrhx8S@r4-qu+xHlX$1EEK&hxAQW{hxxlu1>)#)Dq)bNza z__I(GY<2M^CR^2GNl9qj@Miv?iqJ>@<%s}2_IAL;w@xq*>y?}$^?M<66=!$)N z??l?gb{T;q8ppUO`l=Ka0VB5ZmMbnc(M!+L>Q|a@gmBx15F!3$vi%7xkiB3$ z^c^xmEx`ka59Sx&3&fDC2i`QV{R5+7G{9zBu21FugcS0*@{2P#4e+o+&9%suOrHyD zYDi6Jr2a3C&M`dBu8YEr+MqET+qP}nR@2y4W7{?x+qP{qP9{lX<9puk=lq$O>%l(f z?6vN--=E?K3mv9;{-XH4nIR-Yp$8s6eI+EE-Lo;P!E-&ni&Pi{R^*$_zeW};1b);X z)^PTaSI(c`q>?Q3<|muIE_zRY=8C#myEhz|oN}6}6$4@c3XB934fV}D`2_(-3XUmr z!PmFZi45dF7=VS*gd(P-w$)$LbZIa3-KBjAO6~1w1DBo$WT{(~tr|7k`Bft}6X4ng zj7BV&3t*|i~>_ZJNpDGR!q5YExt2q4EVaWuoLtk%5cCb-sxM zSC?#Ih?%JFfv2Pci6whODteto;CPu@UFaj1QZ98QBu+ZtK+bkTw_ZkDnbx4 zS@>qZZiN-i4;CXdm&2x@WX2r*fB%m9mLV&rgk`K~WR4ifYAAEI{{s^J9tsPs{a5_M2^K(;X^4W#nh2#wA#vdE3Y!AH8Y=%#nlVIpv zYhNnFo<=>`-;|FuSZt&4dx2Og#Fq=`DJCW6BJeP(H~fJX3_BP-qNgMZ;O<_GDL-!K zsV1%};h@~>pdKV<0=9sFLw65&gNG7QMUGy%D6=o1+qla5;1kt8@l?@?C~_x{4G3rS z!c@}~>e~X53qehtHItT`oND>)wGlObPbp3@9a#P$Q{oF-b0XZ?=9#A|>D)fd$xDY= zQJ!dOVrWq3YX}iCuw(4ziKJ4oEuoXz>tNQ_Wo14-s-kkV#Myla?ns=QAajNWs1Cv# z5$dr`)rj>zHTHzOI$dsv1pfkyjRZ}XZ=8v1{tTD<0~`W<7EGv-Lt|qTe@|Fq2;~FZ z&mU8AX(vq0%#_m9dRGLzCjfuy_?rR7?k&Lfco3%2CB`#ld{0VBW;ENN<9ZtmET^k1 z8CYOre6MBKgvVIVVQ%j(Cd%irVZUa>6G4Lm$Mwju$)*+qAq^dlDH$EA8fqMC zHec|hYO^97c)t?3H!PoI`~pg(Gm=~yySAW!Ki<0ZkF}}LX7fL+6QZS5C=%q0knq?K z$R;HH*m35JaXu{UccxNau2>c|vlkyv{YzQ2wbqw>tp80ASmh@$ zI1)ADCaMrOdoK{TN0mbH##2;U3@48Yf3yr~{wK)xCx8Pjor^BKR?jWUh<2q>J4%g; z0AUBMx@E1YJc-j&qP0co{Gkw$V9Y`#{D`1mW2R*nEpK1Yp!#wG=l4Y~Ped6rmC%9< z=85l4G)@D!&k-=D4JPZw8_Rkzyd|GVMXBlJgW1W%@QnN1zc_#Y!9(jAUMs!Dk zg*JpR94!@HNj*-cZb>$LO4v*a3}EIV!G-kQp9HeJue7{hhEi3JYvQgt#3fIlpG1ID zi)gQP)1LFHhb#I7KWg+W%>)(;b3k8MS|&s}nt0%Edq!DKETI-<0zmJa%P0Av06^(0 z+H3&Pa2ow9S?Ngk8{f44a13@G_%q-84al48Si{C6J7(qICuUn4*OM@jvpU?ZZ-#tr{L!MF4Lk}FTYbITUQ1Fewn3aN?X8IC}C zV*;pV07T+9Kd+_P_KyX`g3E1v?=D~OE`Gq|2Ef{~p8GJke`2v^b;DJ7>N5b5ea!i* zs$|y-`;T6Wi2`XffXg367d!aa0jwODu;8aH0s(^1S_z}|TID!eauI42v6+l@K>I7- z5K9S#F(cZ#VL%lvX{UIKG9q9qC3wnoKcv$3a4r*{5TJ|JUo3Sm^|`%to!9?xT2arf zsFR%B1LEl_^Dj$w95GUq!%kHCqv92VLf#hZZ0S2RG+A>JWdW@sWmQw=&99pTu=6An z&J)aTp(2|<5R{7-ewE}^#?W!}?u#nY6h?k0iAwgp)F7kF})9l z0#{C>)oUudPUH87Z}(c;nkuHcQOgGOQ-E`e>)z$5Sj~!(mZFe@5%ORAG-NgS^TrWp zZ#{bFq2STTl!VrIe#ktC^oaL`mg$TRydU$J2rKig5tP3Y-uPTWzaEWG-O0^ z45%MhK3{XaFe02t^UID!Z)HR?{MnMIw<%8#|5OJ@tPZ>d5~nA`EN)=N&4Cu2;ts!% zJ-FJ6lxg%u%qxGm%}xavU;vfw1!3}Rq%idk@?EGPzEymj8&9p6>QYNO{JijtygZoU`+Tffo9D6ktC$9&_Zi-auKhD(WGX}KE(H5j8HBl1~@_YGu5dntW*sN zvV#4Y7=^MegIQgJLm_48cXSaC-qG^!+(IKnBY3?lxxO;ADZQ#m3VYR|fURsHT!Lh^ z{*J8UrI2o6zMzB1GoEEk7ZqLJ)0gL-voK$gqV5IjUgj;*a!+5 z8oJ>`GjeP-rDy>q>>-qy_w|Jaujfi48mnr)Lh-MQ%fA59xi^Fw`$O{q%TSzjki&yZ zH3mD_cV;VG&y}t`mY<@gJ4BOooR33bboE%Gh8c?yD_%0F{RNx4V*J@=T30#}F1+i5 zUd!u3{JlsD(yLuCrF`iW2@Pt^NFw3;V6HD%aWS5r54?10WL;)-KW&;4^Z1uOstDnH zvRp*|_n;v-Y~YZ-h|;lQUvH{5Y|3uLc)|w9l}LoPJm@R;6=LMF;alvMD<;~3Q~!q- z{Ga2S7eS1~9Nt_~K0`+4Hs@=ceedYVbHYKCb zQ*wV+s~zTgzsvcL)fPw8_q}!5ko4j@;oMrHR;!NR9rGo-nPO{RUdx3`##e6;hoM{K zH=AFy)9-Rq?9j2k>eq8gZfprQY$2sEJx{uH0$A>DF;6HT=<-2*Wiao)Pe&A#_4RL9Rew!~3LK;>rGZp|1(dTY4E^UP z78^F9-8oRr?lWfY9tdcV{=-X+YW_mN>k=wAN%+zG^v9XOL7d7*djGZJa!j^kMmHxP)t8!^bM zsU}2GK)HEp``c%==6z?*`q=zu*=LGb``P8x&ONKk^uFy{MiguAe9YoBpGPkRGv-nV_$|7{^k8ZuX@jth6Z+={~Y zg(&jB2AJ}{1WZ0U#Yw|T5h2~Xw_Rm4l+)6dn#G~hPB7m?HFe&vd3nE0{{&p}H7bha z@sf%;2GW2T_2`o`c3i2c^L6g$=JTQ-=jSTP7f$CLK6TCGf{jb#k4>n>7|T45OJngU ztGwO>g$-(y0u3ms1dB)K`iW&8`@7T7>w}9}6}D!hD|Z4xmBdT!Qg~a!4@q$Eu1`du zUu6L@-AoG4a`+f)Ma4fLDzc)C5H|7!>(0w{itPz2fr?(V$R7BzDhF{+=f?kp)3MbayOWS6EQwxH`?CITP=P9%FgtYt7-0`(5cirJ}oSN!t z=@13s2D)(_XWy_o@P|XQJXntb-Xq`(&??Pte35ZA(|Y~AO+nK~Y*B9k<`;KE3l~AS z%eg10?VpDg&<@VDrJT)1cn|kZaz{JXbiZQb?Sh8==Wi*G{?nt(=tE|WuRLv!!=a4n(I+x z_e(hUST5q#ZAau8zB;n+gG{aK+>ERBt@|bEQMq+A7p^=lB>Q5;q}UYK1Gou~0`i{Q z!qS$Nr`Djo02YSh!4(7k8{AJ^hwA0y*7_t>@yP1%fZkL)KWQfuxJLmm z%x5T%r?(!&uWw3mq%eT%jhkjj>u1g|&-hy`x7eI+wWeW^Qi|MrGJ>N>u@WnDHbvfzFpts4i3m5(6zr204_0rG$lB5 zHyDTSSjx8%LbrC>HmCC@@6YguNZ7UJMljtcsU|t?cOhPHb`Z=fYQ+>(&{|vOmlj4w zWJoiYfB#L7nYzQ0czwSgLR(D~2L9VHu3}G`zWYH}p68qwXlO0dT75!TIqiP`@PEkg zg9OW%W$p&M$n#qF;=E2sOlLQOmGR095%sO8P|ngD1lm87p?2P~Yh~KReDWw5sCK-s zlswCHHFY@&N~>dsq}I&FTMplx7fO)$KCG1mK4i5-=;#C(cBj1vjvi>L4_dyMH0Xmlz!rUr`j{#OiyT z5UvIp_DKZnvh_p%AWC+tOk10$oeBHSl$kk! zl-W44j`sZ*e(dJEXl{hGeKa+-72d{8eibIL$-szQK(R8L3{tY@H)8ShmIrS4RclvS zgtV;?0=n8^5_)n$-t6BwQAL2!7UU_BLIKVJQ_9jMarJm*<|JnI!ZPFo`d##{tQm2? z0UJU>g>;*|gr#DK{37e>1++OFCAA~D$SeVFT&(tn!-=!2lCtuoUhLK|h@oqW;-9y; zmlXxS9g^C#A!GU|!=y<^cB#W|{A>N;6P>-dt|*BTX}N+j4aK(xi=!+j2IG&%9%TVv zQeT5FTqKE^xgDJ{8`$z`#5C^2`qP{sQ{fLJhRsLT=6T@?kR?nIiTBMrE+kmJ4SU6z zrTt@TxYt{j_wx^2&#T|gQ0>c=s!cr#cj|={4tKvoZ)f2jP4E^NIU)9aQ`}NFECBxT zN{STFWE*x{T?VpsMKp$)TwRBCk8`(s;!&|f~dS~E%nzs(Ek1_G;c!AV&i zqa`?ib#McDf~IcM7e0PKfoT6BK~Jea*5GY0YadfdS9uaS6u%$n$htqw9jCvqad7$w z{Q>gUipj7Xq0I-5+O()8ZdzWtz{;&xzTZQ91c#%+xoN z!^*&hL#|Be&0%9orA?CGjP+YH5&bl^F@XG?)oG3E$pa&jrApm3U0Ub&xp}D%sniQR zKt}VN-?6^@W~C~q!{Wm~77QM`;`n~HQBv_xyjGqktnKe8MO;wPi4;lvMJz$Inv$NP z=a6UKt%2T-fm)hoBdk)Qhs=UKlk;E~BCT$xnw7z-7)TzJWe%nrkvEfrQZq|79i82? z#nY@22xS^cn_^qp98CS^D>Rknsms@erh&oYafadjvW>ZpSY^if&h48(>Nuu$tfHki zeXGzdtmE`8uYd#V3wlihW)Gz@M}116ZEKv*!xpN-Adg{mHKyuGcpK+S(Lmb!bqj4q zOIifF-d~E}5X*M^ppa-e{|<=I0M{-6Hx-pScuW7e$H-&hg24B8&6;gtd#MjdTo@gj z5W95fujWy1dvC7P?UtR7S5ljmqSV8aG(%65=Z$!}Z>UvEncF%wy|$Anr>`nl+v*RS zyWeyiae2F1Q1E`fw#ImC4y$gqUDx9?U9*O$`h*n9>nQxD6;DM^WgJPB$>K0^eO~+e z5LJZ}EpS1w+H>#9vtoaJHaoYxC`6u3o-SWVeDwscp{$%YwYKTlxAwMwl1NomF?f7G zx4kH3qXv(xF6aLaGfLh76FL{1^(IKK#qtDJ2Z zd-LhTt?f$%?1`cmALU<4;S}`1IYD0`{2QbMO(5MUS$g5}QqXQzWkGQ&ZLaX85syW5 zZw?(F@_nBpBMMC`vh_Wt!~Jj$vkXg1h7yekJKXW2Diu|R{6DMbD9xx|X=wtf6d!=K>7^cBzt|LYT+@3Rp-MrFD)^}u%MdEdb=9c6VbX)_xrt`O@0 zM~mRndqpNqS6`cEQ9r7rFn{8S*3ND)aAyx6?Vs)ZAeDJ3%F0%**WfQVaE^8HVhXcE zh&$6pr~PKMF90lcu?6W3_9a3Zwy8Iu!2Wfzqj6Y3?3p#H`sZRRauk-1f{zUzw=)nK zf^rS7lDmebs3ynNQPHf-BVZ0EEyI(Zdu+^WFJQX%&5Fm)XDX3-XG%y>Euow>2KQUC z%i$oih@CHxw3*J&KrCsW{JAaQDn+3LD%-t2&fOp5`IM9LK~I+o#Z-eW+>uVYpKH=b;5QB?*0!E9; zL>-Fj_C;a)+OA@Fxo{jpx{ZP)mui#rVBGX}*8u1F*{h10TZ#?PwuCWU0I9K?uu%5+&MF*6Ce*?&A za-{fpng&)%<;t3Av1+x(?g!DI|oDv7&{8jhnIfdKhY= zl-5*a7zv4lR9`2i&gf@uu`KM}Xm#QwbiU&pDh z)ez?(7N>rs-VchyT5pLEzjyCi0bm$u2+sjKQ)y;5d1K@ z|LSAiHDy|2-9l#2b<0Jh~0z7=R+ALBk_rHF??`rxXX|xEJAd*20LzTl(5R=fm&!xIClr= z$N3qPgZmEK9v2YXUhg90wp_mQMPm`HVyP^7_S@CN=pL#$_j{8El zQ4a!|SYP}_-lAr&Q%%n#{AVY;RSHzcfcQj!I0EmrAwB0KZk7^-Yo$q-pTYl`Md|to z2QfYGtG*Fhy;aGHdUhb9v0x6XqJZ#}6cF$alZydF@c$adx+O8Uv$L01NYeb*b)S92 zr*ejh{U@iGzvBz$31c%qI-@K7y?$@suh+2|njr6@zWYfgh+3)OY+QEpdHv%FoK`&k z8gCHtz0HG5n~9T9+?cXUUzOBS3^|o{0mzNPfV6zo9R!O}QLEKf+QJ7CGXlnf&Jhz6 za|6Ld{0J757yky3KZO-p|Y~Uex;0*X_FiL z1+I@f6X-$kjHOaaGz@e@3|ZdW{##zxe?1N@E-H#z;`e3Rrm={{Rd{S1-vD~e*zAX~ z5|MB-M3i{di9oh^w5SpiT%G>N7me z8CY#ZA^_Oek?PhOMmY}lrQBODa=hH%wo4sMH-PO#zQ;C7^OgyBs(}|%PEo2or*t!$ z*Rwd}@+tQPVxt;{29lhF$HVjI&9)Um-EK>8kqT85IV#YU*V`E|P($OjWw`az^UoUJ z9i1|tsA@6H6?rfmxoDv%5IuGA3c2e|6b+9Nr0|+tjaGR4$WqvO&pLZK>jR4~ofTCL zLB|RFLcv1mhzc)Jw`P;&`1d+2jMR9n+hXm7C?iZsOGC&=ib%f&vywC+{T(kP@KJ&Z z+rEh9F0$(La_x+d9(Hy*Twnq#{`HEZ}sAX2241q`-tCKUn+2(uaY0_(T;wd zqVmyedwCjeTHHzCik>dg)x}y0j=B1qYW@;@fBlm;Y(j~rH`+r-$nxqnZ{Q2@7n&^j zaI~QJzb4;i?y=L{((z5Kp6k#L*DB>yyV1}R1y*(jfmGVQ2!S7_e*=a9(>PGs0w{MK zywY~+!ruD5BN|{~%!Qx4eIX$?xAlh?V~%n;^hX60x^V#$c42qOT?av8ddHW6?N7mV zYh2;n@$j?j#OF&1WjjBA!U?Q1t6v7o;*P(9!{LDl9W`hj0=zxVK{rpZbol=tGCj?d`0o?s#_bs?5Ow{bR=jGc!By?T)s)-wnNXCy4NNn+#2m zc1`~O-rGqaO62-{*NI*aFzcEEn#o_TEutdkVb3I%YpsPyV%A~j34Fz0_7#}U>scJ# zN}G4b6^ymSX=_9;FG;TlouIi8fE0HzGqI=~#sEb}3nz{<>JM!BKNIR?QUw!haz;{M z9B)?S(Nlo^!#Qu^v4c%s@8DvLJ)un)9#PD#@UUV>FnjXCH_YsuL7~S}BHHB?qb7zLS#w)i6yY^OdxVINR zF>y|9Du5pWf?&KonwYv|Da#WdKeu+rf67P(j!vz)Rym%QOfP0{TVwhb!bT|QvJ(Xo ztaPF6g?EfCE_R*+UHOdi@Hy3BZ#ms9ZftZh8s|3$Qjv)ki*hrBgDBqVne;d;+}J!w zk|Lo@9up{t2gBr~LV4}YS*F@Y_oW7ZOYM&BL4h2#YoiXV9Xcyi94L*NLJBpBQy}vH z;QO1w9()Qb=dE4UT8UE-9;+^vE%+t`7Gj3MzuPCu^2&op8iEDvv6>rtgp5?pn^C}E^N(%a*nYsvReG&KCh;V{AvQ+ z{Je+8rI@Yp(baafH{=J%GmTWLA9PJ5O-yzuwz#rfP=FF6adLh!UyxHED5u00nUQLL zq;&k(;kE3C07_FsXo_Z3*9>Fs{)LBPfxaBaV=;yic9^lMl&=nREflr~Oc{K22C^t>Go#sl!UlOCmz`=&8$Ow=U zbKr_MP1>;Q$!yX0#msHMj2sA=G7_m-$uD6k1IN1eL@7rDirP%9f%ixzL)S$92>z%N z1)g{cTjb>>emnRUuEStH8XAWE&IRHEw;ff9HBQVP@%MzHF(;TjG>kae;;Z{sr39*y z%SQNAeK-ClbhgH}jTP=^1{!AbhIAA!rtQ{PM1iLugYM7hqhWQ=c28)ieh9Ouh(AD# z2apaJWBqN(MGfeTWMHx;sOa{3aOh7eQQ*rnCl;;jYmq%yU4T_oP+aJ~KCYR-M0wW+oDaMV2f@Evwc)*f~n{d=+5^ zy!!ML!c##?jU3GmFUZF?y-sdSMvLy+S#+RFgvwnh53ZAw_ot`q8DN?KK*O9;^dVbp zA69~z>zYhjVXpf62!y+Q<#``9u_HhLu?j!28A}Mw`A+Y;W%l!d^NMEM=RwYroj|0$ zFmv@6rXlY>S6BI<=n0gDUmv+l`ZSJxh#sm`uz6e8R);NTE z@iLsHzZak3L?W4~N-*C@f;7f&RnUU#_ms8UwYgqb;jTQuRbwm278a#j2Buxzwg)qL z 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

)7u_Z+<AJ+zhNCJ%y7mtYl#gHuYd<5H03goSQ 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

LYd;zhO3Zdv-)j1W=ZOt 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 B+wuSa literal 0 HcmV?d00001 diff --git a/data/www/index.htm b/data/www/index.htm index e951c5a..ae1f8b9 100644 --- a/data/www/index.htm +++ b/data/www/index.htm @@ -1,77 +1,168 @@ + - - - - + + + + + + + eSpa + -

ESP32 Spa Controller

- - - - - - - - - -
Spa status:Loading...
Spa temperature:Loading...
Set Temperature: -
Spa controller:Loading...
Spa serial number:Loading...
Spa interface initialised:Loading...
MQTT status:Loading...
Build:TODO - NOT EXTERNALISED YET
-
-

Spa JSON

-

Spa Response

-

Send Current Time to Spa

-

Configuration

-

Firmware Update

-

Wi-Fi Manager

-

Reboot ESP

+ + +
+ + +
+
+

Status

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Spa status:Loading...
Spa temperature:Loading...
Set Temperature: + +
Spa controller:Loading...
Spa serial number:Loading...
Spa interface initialised:Loading...
MQTT status:Loading...
Build:TODO - NOT EXTERNALISED YET
+ + + + + + +
+
+ + + +

Built with heart by the eSpa Team

+
+
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/data/www/json.htm b/data/www/json.htm deleted file mode 100644 index 1add878..0000000 --- a/data/www/json.htm +++ /dev/null @@ -1,135 +0,0 @@ - - - - - - - -JSON Data Table - - -

JSON Data Table

- - - - - - -
- - - \ No newline at end of file diff --git a/data/www/styles.css b/data/www/styles.css index feb0ce0..f693df9 100644 --- a/data/www/styles.css +++ b/data/www/styles.css @@ -1,4 +1,4 @@ -input[type=file]::file-selector-button, input[type="submit"], a, button { +/* input[type=file]::file-selector-button, input[type="submit"], a, button { padding: 7px 15px; border: none; background: #007BFF; @@ -21,4 +21,34 @@ table, td, th { } table { border-collapse: collapse; -} \ No newline at end of file +} */ + +h1, h2, h3 { + text-align: left; + font-weight: 300; + padding-top: 20px; + display: flex; + align-items: center; +} + +.footer { + font-size: 10px; + text-align: center; +} + +.navbar-dark .navbar-nav .nav-link { + color: white; +} + +.modal-content { + border: none; +} + +.modal-header { + background-color: #0069d9; + color: white; +} + +.modal-header .modal-title { + font-weight: 400; +} From bb679d0668fa711b37582e9206f7b013f7902592 Mon Sep 17 00:00:00 2001 From: Jonathan Giles Date: Wed, 11 Dec 2024 14:56:13 +1300 Subject: [PATCH 07/33] Minor improvements - getting rid of the config page, but untested! --- data/www/config.htm | 57 -------------------------------------- data/www/espa.js | 67 +++++++++++++++++++++++++++++++++++++++------ data/www/index.htm | 28 ++++++++++++++----- 3 files changed, 79 insertions(+), 73 deletions(-) delete mode 100644 data/www/config.htm diff --git a/data/www/config.htm b/data/www/config.htm deleted file mode 100644 index 394a5bc..0000000 --- a/data/www/config.htm +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - -Configuration - - -

Configuration

-
- - - - - - - -
Spa Name:
MQTT Server:
MQTT Port:
MQTT Username:
MQTT Password:
Poll Frequency (seconds):
- -
-
- - - - \ No newline at end of file diff --git a/data/www/espa.js b/data/www/espa.js index df21ced..da981b6 100644 --- a/data/www/espa.js +++ b/data/www/espa.js @@ -48,8 +48,28 @@ window.onload = function() { setInterval(fetchStatus, 10000); } +// Retrieving and updating the configured settings, so they can be displayed in the modal popup +function loadConfig() { + $('#configErrorAlert').hide(); + fetch('/json/config') + .then(response => response.json()) + .then(data => { + document.getElementById('spaName').value = data.spaName; + document.getElementById('mqttServer').value = data.mqttServer; + document.getElementById('mqttPort').value = data.mqttPort; + document.getElementById('mqttUsername').value = data.mqttUsername; + document.getElementById('mqttPassword').value = data.mqttPassword; + document.getElementById('updateFrequency').value = data.updateFrequency; + }) + .catch(error => { + console.error('Error loading config:', error); + $('#configErrorAlert').show(); // Show the alert if there's an error + }); +} + // Modal dialog content population $(document).ready(function() { + // JSON dump modal $('#jsonLink').click(function(event) { event.preventDefault(); fetch('/json').then(response => response.json()).then(data => { @@ -58,6 +78,8 @@ $(document).ready(function() { $('#infoModal').modal('show'); }).catch(error => console.error('Error fetching JSON:', error)); }); + + // spa status modal $('#statusLink').click(function(event) { event.preventDefault(); fetch('/status').then(response => response.json()).then(data => { @@ -66,12 +88,39 @@ $(document).ready(function() { $('#infoModal').modal('show'); }).catch(error => console.error('Error fetching status:', error)); }); - // $('#configLink').click(function(event) { - // event.preventDefault(); - // fetch('/status').then(response => response.json()).then(data => { - // $('#infoModalTitle').html("Spa Status"); - // $('#infoModalBody').html('
' + data + '
'); - // $('#infoModal').modal('show'); - // }).catch(error => console.error('Error fetching status:', error)); - // }); -}); \ No newline at end of file + + // configuration settings modal + $('#configLink').click(function(event) { + event.preventDefault(); + $('#configModal').modal('show'); + }); + // Load configuration when the config modal is shown + $('#configModal').on('shown.bs.modal', function() { + loadConfig(); + }); + // Handle form submission when the save button is clicked + $('#saveConfigButton').click(function() { + submitConfigForm(); + }); + function submitConfigForm() { + $.ajax({ + url: '/config', + type: 'POST', + data: $('#config_form').serialize(), + success: function() { + // $('#msg').html('

Configuration updated successfully!

'); + loadConfig(); + setTimeout(function() { $('#msg').html(''); }, 3000); + $('#configModal').modal('hide'); + }, + error: function() { + $('#configErrorAlert').text('Error updating configuration. Please try again.').show(); + } + }); + } + + $('#config_form').submit(function(e) { + e.preventDefault(); + submitConfigForm(); + }); +}); diff --git a/data/www/index.htm b/data/www/index.htm index ae1f8b9..8204fcb 100644 --- a/data/www/index.htm +++ b/data/www/index.htm @@ -33,7 +33,7 @@ Config - + - + From 5279bf5dce24fd2b2f0ce08c1d8fa8f54c3d75c0 Mon Sep 17 00:00:00 2001 From: lucas_nz <606314+lucasnz@users.noreply.github.com> Date: Wed, 11 Dec 2024 19:14:35 +1300 Subject: [PATCH 08/33] Minor webui tweaks --- data/www/espa.js | 3 +++ data/www/index.htm | 13 +++++++++++-- lib/SpaUtils/SpaUtils.cpp | 6 ++++++ lib/SpaUtils/SpaUtils.h | 4 ++++ src/main.cpp | 3 --- 5 files changed, 24 insertions(+), 5 deletions(-) diff --git a/data/www/espa.js b/data/www/espa.js index da981b6..f7f65ed 100644 --- a/data/www/espa.js +++ b/data/www/espa.js @@ -12,9 +12,12 @@ function fetchStatus() { document.getElementById('temperatures_setPoint').value = value_json.temperatures.setPoint; document.getElementById('status_state').innerText = value_json.status.state; document.getElementById('status_controller').innerText = value_json.status.controller; + document.getElementById('status_firmware').innerText = value_json.status.firmware; document.getElementById('status_serial').innerText = value_json.status.serial; document.getElementById('status_siInitialised').innerText = value_json.status.siInitialised; document.getElementById('status_mqtt').innerText = value_json.status.mqtt; + document.getElementById('espa_model').innerText = value_json.eSpa.model; + document.getElementById('espa_build').innerText = value_json.eSpa.update.installed_version; }) .catch(error => console.error('Error fetching status:', error)); } diff --git a/data/www/index.htm b/data/www/index.htm index 8204fcb..d13c3e3 100644 --- a/data/www/index.htm +++ b/data/www/index.htm @@ -87,6 +87,11 @@

Status

Spa controller: Loading... + + Spa controller firmware: + Loading... + + Spa serial number: Loading... @@ -100,8 +105,12 @@

Status

Loading... - Build: - TODO - NOT EXTERNALISED YET + eSpa Model: + Loading... + + + eSpa Build: + Loading... - - @@ -236,16 +236,11 @@ -
+

Spa JSON HTML