From bfd645d7a1fd4351988f951306910625317ba3dc Mon Sep 17 00:00:00 2001 From: Moritz Wirger Date: Mon, 14 Sep 2020 11:59:35 +0200 Subject: [PATCH 1/4] Use const String& to reduce IROM usage --- src/ESPUI.cpp | 20 ++++++++++---------- src/ESPUI.h | 22 +++++++++++----------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/ESPUI.cpp b/src/ESPUI.cpp index 858d291..497937e 100644 --- a/src/ESPUI.cpp +++ b/src/ESPUI.cpp @@ -500,7 +500,7 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp } } -uint16_t ESPUIClass::addControl(ControlType type, const char *label, String value, ControlColor color, uint16_t parentControl, +uint16_t ESPUIClass::addControl(ControlType type, const char *label, const String& value, ControlColor color, uint16_t parentControl, void (*callback)(Control *, int)) { Control *control = new Control(type, label, callback, value, color, parentControl); @@ -571,7 +571,7 @@ bool ESPUIClass::removeControl(uint16_t id, bool force_reload_ui) return false; } -uint16_t ESPUIClass::label(const char *label, ControlColor color, String value) { return addControl(ControlType::Label, label, value, color); } +uint16_t ESPUIClass::label(const char *label, ControlColor color, const String& value) { return addControl(ControlType::Label, label, value, color); } uint16_t ESPUIClass::graph(const char *label, ControlColor color) { return addControl(ControlType::Graph, label, "", color); } @@ -584,7 +584,7 @@ uint16_t ESPUIClass::slider(const char *label, void (*callback)(Control *, int), return sliderId; } -uint16_t ESPUIClass::button(const char *label, void (*callback)(Control *, int), ControlColor color, String value) +uint16_t ESPUIClass::button(const char *label, void (*callback)(Control *, int), ControlColor color, const String& value) { return addControl(ControlType::Button, label, value, color, Control::noParent, callback); } @@ -624,7 +624,7 @@ uint16_t ESPUIClass::accelerometer(const char *label, void (*callback)(Control * return addControl(ControlType::Accel, label, "", color, Control::noParent, callback); } -uint16_t ESPUIClass::text(const char *label, void (*callback)(Control *, int), ControlColor color, String value) +uint16_t ESPUIClass::text(const char *label, void (*callback)(Control *, int), ControlColor color, const String& value) { return addControl(ControlType::Text, label, value, color, Control::noParent, callback); } @@ -713,7 +713,7 @@ void ESPUIClass::updateControl(uint16_t id, int clientId) updateControl(control, clientId); } -void ESPUIClass::updateControlValue(Control *control, String value, int clientId) +void ESPUIClass::updateControlValue(Control *control, const String& value, int clientId) { if (!control) { @@ -724,7 +724,7 @@ void ESPUIClass::updateControlValue(Control *control, String value, int clientId updateControl(control, clientId); } -void ESPUIClass::updateControlValue(uint16_t id, String value, int clientId) +void ESPUIClass::updateControlValue(uint16_t id, const String& value, int clientId) { Control *control = getControl(id); @@ -740,9 +740,9 @@ void ESPUIClass::updateControlValue(uint16_t id, String value, int clientId) updateControlValue(control, value, clientId); } -void ESPUIClass::print(uint16_t id, String value) { updateControlValue(id, value); } +void ESPUIClass::print(uint16_t id, const String& value) { updateControlValue(id, value); } -void ESPUIClass::updateLabel(uint16_t id, String value) { updateControlValue(id, value); } +void ESPUIClass::updateLabel(uint16_t id, const String& value) { updateControlValue(id, value); } void ESPUIClass::updateSlider(uint16_t id, int nValue, int clientId) { updateControlValue(id, String(nValue), clientId); } @@ -750,9 +750,9 @@ void ESPUIClass::updateSwitcher(uint16_t id, bool nValue, int clientId) { update void ESPUIClass::updateNumber(uint16_t id, int number, int clientId) { updateControlValue(id, String(number), clientId); } -void ESPUIClass::updateText(uint16_t id, String text, int clientId) { updateControlValue(id, text, clientId); } +void ESPUIClass::updateText(uint16_t id, const String& text, int clientId) { updateControlValue(id, text, clientId); } -void ESPUIClass::updateSelect(uint16_t id, String text, int clientId) { updateControlValue(id, text, clientId); } +void ESPUIClass::updateSelect(uint16_t id, const String& text, int clientId) { updateControlValue(id, text, clientId); } void ESPUIClass::updateGauge(uint16_t id, int number, int clientId) { updateControlValue(id, String(number), clientId); } diff --git a/src/ESPUI.h b/src/ESPUI.h index a491330..0487439 100644 --- a/src/ESPUI.h +++ b/src/ESPUI.h @@ -140,7 +140,7 @@ public: static constexpr uint16_t noParent = 0xffff; - Control(ControlType type, const char *label, void (*callback)(Control *, int), String value, ControlColor color, + Control(ControlType type, const char *label, void (*callback)(Control *, int), const String& value, ControlColor color, uint16_t parentControl = Control::noParent) : type(type), label(label), callback(callback), value(value), color(color), parentControl(parentControl), next(nullptr) { @@ -206,11 +206,11 @@ public: void prepareFileSystem(); // Initially preps the filesystem and loads a lot of stuff into SPIFFS void list(); // Lists SPIFFS directory - uint16_t addControl(ControlType type, const char *label, String value = String(""), ControlColor color = ControlColor::Turquoise, uint16_t parentControl = Control::noParent, void (*callback)(Control *, int) = nullptr); + uint16_t addControl(ControlType type, const char *label, const String& value = String(""), ControlColor color = ControlColor::Turquoise, uint16_t parentControl = Control::noParent, void (*callback)(Control *, int) = nullptr); bool removeControl(uint16_t id, bool force_reload_ui = false); // create Elements - uint16_t button(const char *label, void (*callback)(Control *, int), ControlColor color, String value = ""); // Create Event Button + uint16_t button(const char *label, void (*callback)(Control *, int), ControlColor color, const String& value = ""); // Create Event Button uint16_t switcher(const char *label, void (*callback)(Control *, int), ControlColor color, bool startState = false); // Create Toggle Button uint16_t pad(const char *label, void (*callback)(Control *, int), ControlColor color); // Create Pad Control uint16_t padWithCenter(const char *label, void (*callback)(Control *, int), ControlColor color); // Create Pad Control with Centerbutton @@ -219,10 +219,10 @@ public: int max = 100); // Create Slider Control uint16_t number(const char *label, void (*callback)(Control *, int), ControlColor color, int value, int min = 0, int max = 100); // Create a Number Input Control - uint16_t text(const char *label, void (*callback)(Control *, int), ControlColor color, String value = ""); // Create a Text Input Control + uint16_t text(const char *label, void (*callback)(Control *, int), ControlColor color, const String& value = ""); // Create a Text Input Control // Output only - uint16_t label(const char *label, ControlColor color, String value = ""); // Create Label + uint16_t label(const char *label, ControlColor color, const String& value = ""); // Create Label uint16_t graph(const char *label, ControlColor color); // Create Graph display uint16_t gauge(const char *label, ControlColor color, int value, int min = 0, int max = 100); // Create Gauge display @@ -234,19 +234,19 @@ public: Control *getControl(uint16_t id); // Update Elements - void updateControlValue(uint16_t id, String value, int clientId = -1); - void updateControlValue(Control *control, String value, int clientId = -1); + void updateControlValue(uint16_t id, const String& value, int clientId = -1); + void updateControlValue(Control *control, const String& value, int clientId = -1); void updateControl(uint16_t id, int clientId = -1); void updateControl(Control *control, int clientId = -1); - void print(uint16_t id, String value); - void updateLabel(uint16_t id, String value); + void print(uint16_t id, const String& value); + void updateLabel(uint16_t id, const String& value); void updateSwitcher(uint16_t id, bool nValue, int clientId = -1); void updateSlider(uint16_t id, int nValue, int clientId = -1); void updateNumber(uint16_t id, int nValue, int clientId = -1); - void updateText(uint16_t id, String nValue, int clientId = -1); - void updateSelect(uint16_t id, String nValue, int clientId = -1); + void updateText(uint16_t id, const String& nValue, int clientId = -1); + void updateSelect(uint16_t id, const String& nValue, int clientId = -1); void updateGauge(uint16_t id, int number, int clientId); void clearGraph(uint16_t id, int clientId = -1); From db4164f6217206f34355d20522a494841a7f17b6 Mon Sep 17 00:00:00 2001 From: Moritz Wirger Date: Mon, 14 Sep 2020 12:10:45 +0200 Subject: [PATCH 2/4] Reduce heap usage by using F and PSTR --- src/ESPUI.cpp | 122 +++++++++++++++++++++++++------------------------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/src/ESPUI.cpp b/src/ESPUI.cpp index 497937e..1f5f018 100644 --- a/src/ESPUI.cpp +++ b/src/ESPUI.cpp @@ -22,7 +22,7 @@ void listDir(const char *dirname, uint8_t levels) { if (ESPUI.verbosity) { - Serial.printf("Listing directory: %s\n", dirname); + Serial.printf_P(F("Listing directory: %s\n"), dirname); } File root = LittleFS.open(dirname); @@ -31,7 +31,7 @@ void listDir(const char *dirname, uint8_t levels) { if (ESPUI.verbosity) { - Serial.println("Failed to open directory"); + Serial.println(F("Failed to open directory")); } return; @@ -41,7 +41,7 @@ void listDir(const char *dirname, uint8_t levels) { if (ESPUI.verbosity) { - Serial.println("Not a directory"); + Serial.println(F("Not a directory")); } return; @@ -55,7 +55,7 @@ void listDir(const char *dirname, uint8_t levels) { if (ESPUI.verbosity) { - Serial.print(" DIR : "); + Serial.print(F(" DIR : ")); Serial.println(file.name()); } @@ -68,9 +68,9 @@ void listDir(const char *dirname, uint8_t levels) { if (ESPUI.verbosity) { - Serial.print(" FILE: "); + Serial.print(F(" FILE: ")); Serial.print(file.name()); - Serial.print(" SIZE: "); + Serial.print(F(" SIZE: ")); Serial.println(file.size()); } } @@ -83,16 +83,16 @@ void listDir(const char *dirname, uint8_t levels) void listDir(const char *dirname, uint8_t levels) { // ignoring levels for esp8266 - Serial.printf("Listing directory: %s\n", dirname); + Serial.printf_P(PSTR("Listing directory: %s\n"), dirname); String str = ""; Dir dir = LittleFS.openDir("/"); while (dir.next()) { - Serial.print(" FILE: "); + Serial.print(F(" FILE: ")); Serial.print(dir.fileName()); - Serial.print(" SIZE: "); + Serial.print(F(" SIZE: ")); Serial.println(dir.fileSize()); } } @@ -103,7 +103,7 @@ void ESPUIClass::list() { if (!LittleFS.begin()) { - Serial.println("SPIFFS Mount Failed"); + Serial.println(F("SPIFFS Mount Failed")); return; } @@ -134,7 +134,7 @@ void deleteFile(const char *path) { if (ESPUI.verbosity) { - Serial.printf("File: %s does not exist, not deleting\n", path); + Serial.printf_P(PSTR("File: %s does not exist, not deleting\n"), path); } return; @@ -142,21 +142,21 @@ void deleteFile(const char *path) if (ESPUI.verbosity) { - Serial.printf("Deleting file: %s\n", path); + Serial.printf_P(PSTR("Deleting file: %s\n"), path); } if (LittleFS.remove(path)) { if (ESPUI.verbosity) { - Serial.println("File deleted"); + Serial.println(F("File deleted")); } } else { if (ESPUI.verbosity) { - Serial.println("Delete failed"); + Serial.println(F("Delete failed")); } } } @@ -165,7 +165,7 @@ void writeFile(const char *path, const char *data) { if (ESPUI.verbosity) { - Serial.printf("Writing file: %s\n", path); + Serial.printf_P(PSTR("Writing file: %s\n"), path); } File file = LittleFS.open(path, FILE_WRITE); @@ -174,7 +174,7 @@ void writeFile(const char *path, const char *data) { if (ESPUI.verbosity) { - Serial.println("Failed to open file for writing"); + Serial.println(F("Failed to open file for writing")); } return; @@ -186,14 +186,14 @@ void writeFile(const char *path, const char *data) { if (ESPUI.verbosity) { - Serial.println("File written"); + Serial.println(F("File written")); } } else { if (ESPUI.verbosity) { - Serial.println("Write failed"); + Serial.println(F("Write failed")); } } @@ -203,14 +203,14 @@ void writeFile(const char *path, const char *data) { if (ESPUI.verbosity) { - Serial.println("File written"); + Serial.println(F("File written")); } } else { if (ESPUI.verbosity) { - Serial.println("Write failed"); + Serial.println(F("Write failed")); } } @@ -226,7 +226,7 @@ void ESPUIClass::prepareFileSystem() if (this->verbosity) { - Serial.println("About to prepare filesystem..."); + Serial.println(F("About to prepare filesystem...")); } #if defined(ESP32) @@ -236,7 +236,7 @@ void ESPUIClass::prepareFileSystem() { if (this->verbosity) { - Serial.println("SPIFFS Mount Failed"); + Serial.println(F("SPIFFS Mount Failed")); } return; @@ -245,7 +245,7 @@ void ESPUIClass::prepareFileSystem() if (this->verbosity) { listDir("/", 1); - Serial.println("SPIFFS Mount ESP32 Done"); + Serial.println(F("SPIFFS Mount ESP32 Done")); } #else @@ -254,7 +254,7 @@ void ESPUIClass::prepareFileSystem() if (this->verbosity) { - Serial.println("SPIFFS Mount ESP8266 Done"); + Serial.println(F("SPIFFS Mount ESP8266 Done")); } #endif @@ -272,7 +272,7 @@ void ESPUIClass::prepareFileSystem() if (this->verbosity) { - Serial.println("Cleanup done"); + Serial.println(F("Cleanup done")); } // Now write @@ -290,7 +290,7 @@ void ESPUIClass::prepareFileSystem() if (this->verbosity) { - Serial.println("Done Initializing filesystem :-)"); + Serial.println(F("Done Initializing filesystem :-)")); } #if defined(ESP32) @@ -314,7 +314,7 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp { if (ESPUI.verbosity) { - Serial.printf("Disconnected!\n"); + Serial.print(F("Disconnected!\n")); } break; @@ -324,7 +324,7 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp { if (ESPUI.verbosity) { - Serial.printf("Received PONG!\n"); + Serial.print(F("Received PONG!\n")); } break; @@ -334,7 +334,7 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp { if (ESPUI.verbosity) { - Serial.printf("WebSocket Error!\n"); + Serial.print(F("WebSocket Error!\n")); } break; @@ -344,7 +344,7 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp { if (ESPUI.verbosity) { - Serial.print("Connected: "); + Serial.print(F("Connected: ")); Serial.println(client->id()); } @@ -352,7 +352,7 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp if (ESPUI.verbosity) { - Serial.println("JSON Data Sent to Client!"); + Serial.println(F("JSON Data Sent to Client!")); } } break; @@ -371,9 +371,9 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp if (ESPUI.verbosity >= Verbosity::VerboseJSON) { - Serial.print("WS rec: "); + Serial.print(F("WS rec: ")); Serial.println(msg); - Serial.print("WS recognised ID: "); + Serial.print(F("WS recognised ID: ")); Serial.println(id); } @@ -383,7 +383,7 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp { if (ESPUI.verbosity) { - Serial.print("No control found for ID "); + Serial.print(F("No control found for ID ")); Serial.println(id); } @@ -394,92 +394,92 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp { if (ESPUI.verbosity) { - Serial.print("No callback found for ID "); + Serial.print(F("No callback found for ID ")); Serial.println(id); } return; } - if (msg.startsWith("bdown:")) + if (msg.startsWith(F("bdown:"))) { c->callback(c, B_DOWN); } - else if (msg.startsWith("bup:")) + else if (msg.startsWith(F("bup:"))) { c->callback(c, B_UP); } - else if (msg.startsWith("pfdown:")) + else if (msg.startsWith(F("pfdown:"))) { c->callback(c, P_FOR_DOWN); } - else if (msg.startsWith("pfup:")) + else if (msg.startsWith(F("pfup:"))) { c->callback(c, P_FOR_UP); } - else if (msg.startsWith("pldown:")) + else if (msg.startsWith(F("pldown:"))) { c->callback(c, P_LEFT_DOWN); } - else if (msg.startsWith("plup:")) + else if (msg.startsWith(F("plup:"))) { c->callback(c, P_LEFT_UP); } - else if (msg.startsWith("prdown:")) + else if (msg.startsWith(F("prdown:"))) { c->callback(c, P_RIGHT_DOWN); } - else if (msg.startsWith("prup:")) + else if (msg.startsWith(F("prup:"))) { c->callback(c, P_RIGHT_UP); } - else if (msg.startsWith("pbdown:")) + else if (msg.startsWith(F("pbdown:"))) { c->callback(c, P_BACK_DOWN); } - else if (msg.startsWith("pbup:")) + else if (msg.startsWith(F("pbup:"))) { c->callback(c, P_BACK_UP); } - else if (msg.startsWith("pcdown:")) + else if (msg.startsWith(F("pcdown:"))) { c->callback(c, P_CENTER_DOWN); } - else if (msg.startsWith("pcup:")) + else if (msg.startsWith(F("pcup:"))) { c->callback(c, P_CENTER_UP); } - else if (msg.startsWith("sactive:")) + else if (msg.startsWith(F("sactive:"))) { c->value = "1"; ESPUI.updateControl(c, client->id()); c->callback(c, S_ACTIVE); } - else if (msg.startsWith("sinactive:")) + else if (msg.startsWith(F("sinactive:"))) { c->value = "0"; ESPUI.updateControl(c, client->id()); c->callback(c, S_INACTIVE); } - else if (msg.startsWith("slvalue:")) + else if (msg.startsWith(F("slvalue:"))) { c->value = msg.substring(msg.indexOf(':') + 1, msg.lastIndexOf(':')); ESPUI.updateControl(c, client->id()); c->callback(c, SL_VALUE); } - else if (msg.startsWith("nvalue:")) + else if (msg.startsWith(F("nvalue:"))) { c->value = msg.substring(msg.indexOf(':') + 1, msg.lastIndexOf(':')); ESPUI.updateControl(c, client->id()); c->callback(c, N_VALUE); } - else if (msg.startsWith("tvalue:")) + else if (msg.startsWith(F("tvalue:"))) { c->value = msg.substring(msg.indexOf(':') + 1, msg.lastIndexOf(':')); ESPUI.updateControl(c, client->id()); c->callback(c, T_VALUE); } - else if (msg.startsWith("svalue:")) + else if (msg.startsWith(F("svalue:"))) { c->value = msg.substring(msg.indexOf(':') + 1, msg.lastIndexOf(':')); ESPUI.updateControl(c, client->id()); @@ -489,7 +489,7 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp { if (ESPUI.verbosity) { - Serial.println("Malformated message from the websocket"); + Serial.println(F("Malformated message from the websocket")); } } } @@ -672,7 +672,7 @@ void ESPUIClass::updateControl(Control *control, int clientId) { if (this->verbosity >= Verbosity::VerboseJSON) { - Serial.println("TextAll"); + Serial.println(F("TextAll")); } this->ws->textAll(json); return; @@ -705,7 +705,7 @@ void ESPUIClass::updateControl(uint16_t id, int clientId) { if (this->verbosity) { - Serial.println(String("Error: There is no control with ID ") + String(id)); + Serial.printf_P(PSTR("Error: There is no control with ID %d"), id); } return; } @@ -732,7 +732,7 @@ void ESPUIClass::updateControlValue(uint16_t id, const String& value, int client { if (this->verbosity) { - Serial.println(String("Error: There is no control with ID ") + String(id)); + Serial.printf_P(PSTR("Error: There is no control with ID %d"), id); } return; } @@ -918,7 +918,7 @@ void ESPUIClass::beginSPIFFS(const char *_title, const char *username, const cha { if (ESPUI.verbosity) { - Serial.println("SPIFFS Mount Failed, PLEASE CHECK THE README ON HOW TO PREPARE YOUR ESP!!!!!!!"); + Serial.println(F("SPIFFS Mount Failed, PLEASE CHECK THE README ON HOW TO PREPARE YOUR ESP!!!!!!!")); } return; @@ -933,7 +933,7 @@ void ESPUIClass::beginSPIFFS(const char *_title, const char *username, const cha { if (ESPUI.verbosity) { - Serial.println("Please read the README!!!!!!!, Make sure to ESPUI.prepareFileSystem() once in an empty sketch"); + Serial.println(F("Please read the README!!!!!!!, Make sure to ESPUI.prepareFileSystem() once in an empty sketch")); } return; @@ -971,7 +971,7 @@ void ESPUIClass::beginSPIFFS(const char *_title, const char *username, const cha if (this->verbosity) { - Serial.println("UI Initialized"); + Serial.println(F("UI Initialized")); } } @@ -1107,7 +1107,7 @@ void ESPUIClass::begin(const char *_title, const char *username, const char *pas if (this->verbosity) { - Serial.println("UI Initialized"); + Serial.println(F("UI Initialized")); } } From 1e5ee117c539e1db1fee27eff339b4983b2cc046 Mon Sep 17 00:00:00 2001 From: Moritz Wirger Date: Mon, 28 Sep 2020 10:40:31 +0200 Subject: [PATCH 3/4] Use DEBUG_ESPUI to en/disable debug code from being compiled Include clang-format file for formatting code and format code --- .clang-format | 58 ++ src/ESPUI.cpp | 1859 ++++++++++++++++++++++++++----------------------- src/ESPUI.h | 298 ++++---- 3 files changed, 1216 insertions(+), 999 deletions(-) create mode 100755 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100755 index 0000000..792a92e --- /dev/null +++ b/.clang-format @@ -0,0 +1,58 @@ +--- +# Based on Webkit style +BasedOnStyle: Webkit +IndentWidth: 4 +ColumnLimit: 120 +--- +Language: Cpp +Standard: Cpp11 +# Pointers aligned to the left +DerivePointerAlignment: false +PointerAlignment: Left +AccessModifierOffset: -4 +AllowShortFunctionsOnASingleLine: Inline +AlwaysBreakTemplateDeclarations: true +BreakBeforeBraces: Custom +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: true + BeforeElse: true + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false +BreakConstructorInitializers: BeforeColon +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +Cpp11BracedListStyle: true +FixNamespaceComments: true +IncludeBlocks: Regroup +IncludeCategories: + # C++ standard headers (no .h) + - Regex: '<[[:alnum:]_-]+>' + Priority: 1 + # Extenal libraries (with .h) + - Regex: '<[[:alnum:]_./-]+>' + Priority: 2 + # Headers from same folder + - Regex: '"[[:alnum:]_.-]+"' + Priority: 3 + # Headers from other folders + - Regex: '"[[:alnum:]_/.-]+"' + Priority: 4 +IndentCaseLabels: false +NamespaceIndentation: All +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterTemplateKeyword: true +SpacesInAngles: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +UseTab: Never \ No newline at end of file diff --git a/src/ESPUI.cpp b/src/ESPUI.cpp index 1f5f018..f054727 100644 --- a/src/ESPUI.cpp +++ b/src/ESPUI.cpp @@ -1,813 +1,920 @@ -#include "ESPUI.h" - -#include "dataIndexHTML.h" - -#include "dataNormalizeCSS.h" -#include "dataStyleCSS.h" - -#include "dataControlsJS.h" -#include "dataGraphJS.h" -#include "dataSliderJS.h" -#include "dataTabbedcontentJS.h" -#include "dataZeptoJS.h" +#include #include -#include + +#include "ESPUI.h" +#include "dataControlsJS.h" +#include "dataGraphJS.h" +#include "dataIndexHTML.h" +#include "dataNormalizeCSS.h" +#include "dataSliderJS.h" +#include "dataStyleCSS.h" +#include "dataTabbedcontentJS.h" +#include "dataZeptoJS.h" uint16_t Control::idCounter = 0; // ################# Spiffs functions #if defined(ESP32) -void listDir(const char *dirname, uint8_t levels) +void listDir(const char* dirname, uint8_t levels) { - if (ESPUI.verbosity) - { - Serial.printf_P(F("Listing directory: %s\n"), dirname); - } - - File root = LittleFS.open(dirname); - - if (!root) - { +#if defined(DEBUG_ESPUI) if (ESPUI.verbosity) { - Serial.println(F("Failed to open directory")); + Serial.printf_P(F("Listing directory: %s\n"), dirname); } +#endif - return; - } + File root = LittleFS.open(dirname); - if (!root.isDirectory()) - { - if (ESPUI.verbosity) + if (!root) { - Serial.println(F("Not a directory")); +#if defined(DEBUG_ESPUI) + if (ESPUI.verbosity) + { + Serial.println(F("Failed to open directory")); + } +#endif + + return; } - return; - } - - File file = root.openNextFile(); - - while (file) - { - if (file.isDirectory()) + if (!root.isDirectory()) { - if (ESPUI.verbosity) - { - Serial.print(F(" DIR : ")); - Serial.println(file.name()); - } +#if defined(DEBUG_ESPUI) + if (ESPUI.verbosity) + { + Serial.println(F("Not a directory")); + } +#endif - if (levels) - { - listDir(file.name(), levels - 1); - } + return; } - else + + File file = root.openNextFile(); + + while (file) { - if (ESPUI.verbosity) - { - Serial.print(F(" FILE: ")); - Serial.print(file.name()); - Serial.print(F(" SIZE: ")); - Serial.println(file.size()); - } - } + if (file.isDirectory()) + { +#if defined(DEBUG_ESPUI) + if (ESPUI.verbosity) + { + Serial.print(F(" DIR : ")); + Serial.println(file.name()); + } +#endif - file = root.openNextFile(); - } + if (levels) + { + listDir(file.name(), levels - 1); + } + } + else + { +#if defined(DEBUG_ESPUI) + if (ESPUI.verbosity) + { + Serial.print(F(" FILE: ")); + Serial.print(file.name()); + Serial.print(F(" SIZE: ")); + Serial.println(file.size()); + } +#endif + } + + file = root.openNextFile(); + } } #else -void listDir(const char *dirname, uint8_t levels) +void listDir(const char* dirname, uint8_t levels) { - // ignoring levels for esp8266 - Serial.printf_P(PSTR("Listing directory: %s\n"), dirname); + // ignoring levels for esp8266 + Serial.printf_P(PSTR("Listing directory: %s\n"), dirname); - String str = ""; - Dir dir = LittleFS.openDir("/"); + String str = ""; + Dir dir = LittleFS.openDir("/"); - while (dir.next()) - { - Serial.print(F(" FILE: ")); - Serial.print(dir.fileName()); - Serial.print(F(" SIZE: ")); - Serial.println(dir.fileSize()); - } + while (dir.next()) + { + Serial.print(F(" FILE: ")); + Serial.print(dir.fileName()); + Serial.print(F(" SIZE: ")); + Serial.println(dir.fileSize()); + } } #endif void ESPUIClass::list() { - if (!LittleFS.begin()) - { - Serial.println(F("SPIFFS Mount Failed")); - return; - } + if (!LittleFS.begin()) + { + Serial.println(F("SPIFFS Mount Failed")); + return; + } - listDir("/", 1); + listDir("/", 1); #if defined(ESP32) - Serial.println(LittleFS.totalBytes()); - Serial.println(LittleFS.usedBytes()); + Serial.println(LittleFS.totalBytes()); + Serial.println(LittleFS.usedBytes()); #else - FSInfo fs_info; - LittleFS.info(fs_info); + FSInfo fs_info; + LittleFS.info(fs_info); - Serial.println(fs_info.totalBytes); - Serial.println(fs_info.usedBytes); + Serial.println(fs_info.totalBytes); + Serial.println(fs_info.usedBytes); #endif } -void deleteFile(const char *path) +void deleteFile(const char* path) { - if (ESPUI.verbosity) - { - Serial.print(LittleFS.exists(path)); - } - - if (!LittleFS.exists(path)) - { +#if defined(DEBUG_ESPUI) if (ESPUI.verbosity) { - Serial.printf_P(PSTR("File: %s does not exist, not deleting\n"), path); + Serial.print(LittleFS.exists(path)); + } +#endif + + if (!LittleFS.exists(path)) + { +#if defined(DEBUG_ESPUI) + if (ESPUI.verbosity) + { + Serial.printf_P(PSTR("File: %s does not exist, not deleting\n"), path); + } +#endif + + return; } - return; - } - - if (ESPUI.verbosity) - { - Serial.printf_P(PSTR("Deleting file: %s\n"), path); - } - - if (LittleFS.remove(path)) - { +#if defined(DEBUG_ESPUI) if (ESPUI.verbosity) { - Serial.println(F("File deleted")); + Serial.printf_P(PSTR("Deleting file: %s\n"), path); } - } - else - { - if (ESPUI.verbosity) +#endif + + if (LittleFS.remove(path)) { - Serial.println(F("Delete failed")); +#if defined(DEBUG_ESPUI) + if (ESPUI.verbosity) + { + Serial.println(F("File deleted")); + } +#endif + } + else + { +#if defined(DEBUG_ESPUI) + if (ESPUI.verbosity) + { + Serial.println(F("Delete failed")); + } +#endif } - } } -void writeFile(const char *path, const char *data) +void writeFile(const char* path, const char* data) { - if (ESPUI.verbosity) - { - Serial.printf_P(PSTR("Writing file: %s\n"), path); - } - - File file = LittleFS.open(path, FILE_WRITE); - - if (!file) - { +#if defined(DEBUG_ESPUI) if (ESPUI.verbosity) { - Serial.println(F("Failed to open file for writing")); + Serial.printf_P(PSTR("Writing file: %s\n"), path); } +#endif - return; - } + File file = LittleFS.open(path, FILE_WRITE); + + if (!file) + { +#if defined(DEBUG_ESPUI) + if (ESPUI.verbosity) + { + Serial.println(F("Failed to open file for writing")); + } +#endif + + return; + } #if defined(ESP32) - if (file.print(data)) - { - if (ESPUI.verbosity) + if (file.print(data)) { - Serial.println(F("File written")); +#if defined(DEBUG_ESPUI) + if (ESPUI.verbosity) + { + Serial.println(F("File written")); + } +#endif } - } - else - { - if (ESPUI.verbosity) + else { - Serial.println(F("Write failed")); +#if defined(DEBUG_ESPUI) + if (ESPUI.verbosity) + { + Serial.println(F("Write failed")); + } +#endif } - } #else - if (file.print(FPSTR(data))) - { - if (ESPUI.verbosity) + if (file.print(FPSTR(data))) { - Serial.println(F("File written")); +#if defined(DEBUG_ESPUI) + if (ESPUI.verbosity) + { + Serial.println(F("File written")); + } +#endif } - } - else - { - if (ESPUI.verbosity) + else { - Serial.println(F("Write failed")); +#if defined(DEBUG_ESPUI) + if (ESPUI.verbosity) + { + Serial.println(F("Write failed")); + } +#endif } - } #endif - file.close(); + file.close(); } // end Spiffs functions void ESPUIClass::prepareFileSystem() { - // this function should only be used once + // this function should only be used once - if (this->verbosity) - { - Serial.println(F("About to prepare filesystem...")); - } - -#if defined(ESP32) - LittleFS.format(); - - if (!LittleFS.begin(true)) - { +#if defined(DEBUG_ESPUI) if (this->verbosity) { - Serial.println(F("SPIFFS Mount Failed")); + Serial.println(F("About to prepare filesystem...")); + } +#endif + +#if defined(ESP32) + LittleFS.format(); + + if (!LittleFS.begin(true)) + { +#if defined(DEBUG_ESPUI) + if (this->verbosity) + { + Serial.println(F("SPIFFS Mount Failed")); + } +#endif + + return; } - return; - } - - if (this->verbosity) - { - listDir("/", 1); - Serial.println(F("SPIFFS Mount ESP32 Done")); - } +#if defined(DEBUG_ESPUI) + if (this->verbosity) + { + listDir("/", 1); + Serial.println(F("SPIFFS Mount ESP32 Done")); + } +#endif #else - LittleFS.format(); - LittleFS.begin(); + LittleFS.format(); + LittleFS.begin(); - if (this->verbosity) - { - Serial.println(F("SPIFFS Mount ESP8266 Done")); - } +#if defined(DEBUG_ESPUI) + if (this->verbosity) + { + Serial.println(F("SPIFFS Mount ESP8266 Done")); + } +#endif #endif - deleteFile("/index.htm"); + deleteFile("/index.htm"); - deleteFile("/css/style.css"); - deleteFile("/css/normalize.css"); + deleteFile("/css/style.css"); + deleteFile("/css/normalize.css"); - deleteFile("/js/zepto.min.js"); - deleteFile("/js/controls.js"); - deleteFile("/js/slider.js"); - deleteFile("/js/graph.js"); - deleteFile("/js/tabbedcontent.js"); + deleteFile("/js/zepto.min.js"); + deleteFile("/js/controls.js"); + deleteFile("/js/slider.js"); + deleteFile("/js/graph.js"); + deleteFile("/js/tabbedcontent.js"); - if (this->verbosity) - { - Serial.println(F("Cleanup done")); - } +#if defined(DEBUG_ESPUI) + if (this->verbosity) + { + Serial.println(F("Cleanup done")); + } +#endif - // Now write - writeFile("/index.htm", HTML_INDEX); + // Now write + writeFile("/index.htm", HTML_INDEX); - writeFile("/css/style.css", CSS_STYLE); - writeFile("/css/normalize.css", CSS_NORMALIZE); + writeFile("/css/style.css", CSS_STYLE); + writeFile("/css/normalize.css", CSS_NORMALIZE); - writeFile("/js/zepto.min.js", JS_ZEPTO); - writeFile("/js/controls.js", JS_CONTROLS); - writeFile("/js/slider.js", JS_SLIDER); - writeFile("/js/graph.js", JS_GRAPH); + writeFile("/js/zepto.min.js", JS_ZEPTO); + writeFile("/js/controls.js", JS_CONTROLS); + writeFile("/js/slider.js", JS_SLIDER); + writeFile("/js/graph.js", JS_GRAPH); - writeFile("/js/tabbedcontent.js", JS_TABBEDCONTENT); + writeFile("/js/tabbedcontent.js", JS_TABBEDCONTENT); - if (this->verbosity) - { - Serial.println(F("Done Initializing filesystem :-)")); - } +#if defined(DEBUG_ESPUI) + if (this->verbosity) + { + Serial.println(F("Done Initializing filesystem :-)")); + } +#endif #if defined(ESP32) - if (this->verbosity) - { - listDir("/", 1); - } +#if defined(DEBUG_ESPUI) + if (this->verbosity) + { + listDir("/", 1); + } +#endif #endif - LittleFS.end(); + LittleFS.end(); } // Handle Websockets Communication -void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) +void onWsEvent( + AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len) { - switch (type) - { - case WS_EVT_DISCONNECT: - { - if (ESPUI.verbosity) + switch (type) { - Serial.print(F("Disconnected!\n")); + case WS_EVT_DISCONNECT: + { +#if defined(DEBUG_ESPUI) + if (ESPUI.verbosity) + { + Serial.print(F("Disconnected!\n")); + } +#endif + + break; } + case WS_EVT_PONG: + { +#if defined(DEBUG_ESPUI) + if (ESPUI.verbosity) + { + Serial.print(F("Received PONG!\n")); + } +#endif + + break; + } + + case WS_EVT_ERROR: + { +#if defined(DEBUG_ESPUI) + if (ESPUI.verbosity) + { + Serial.print(F("WebSocket Error!\n")); + } +#endif + + break; + } + + case WS_EVT_CONNECT: + { +#if defined(DEBUG_ESPUI) + if (ESPUI.verbosity) + { + Serial.print(F("Connected: ")); + Serial.println(client->id()); + } +#endif + + ESPUI.jsonDom(client); + +#if defined(DEBUG_ESPUI) + if (ESPUI.verbosity) + { + Serial.println(F("JSON Data Sent to Client!")); + } +#endif + } break; - } - case WS_EVT_PONG: - { - if (ESPUI.verbosity) + case WS_EVT_DATA: { - Serial.print(F("Received PONG!\n")); - } + String msg = ""; + msg.reserve(len + 1); + for (size_t i = 0; i < len; i++) + { + msg += (char)data[i]; + } + + uint16_t id = msg.substring(msg.lastIndexOf(':') + 1).toInt(); + +#if defined(DEBUG_ESPUI) + if (ESPUI.verbosity >= Verbosity::VerboseJSON) + { + Serial.print(F("WS rec: ")); + Serial.println(msg); + Serial.print(F("WS recognised ID: ")); + Serial.println(id); + } +#endif + + Control* c = ESPUI.getControl(id); + + if (c == nullptr) + { +#if defined(DEBUG_ESPUI) + if (ESPUI.verbosity) + { + Serial.print(F("No control found for ID ")); + Serial.println(id); + } +#endif + + return; + } + + if (c->callback == nullptr) + { +#if defined(DEBUG_ESPUI) + if (ESPUI.verbosity) + { + Serial.print(F("No callback found for ID ")); + Serial.println(id); + } +#endif + + return; + } + + if (msg.startsWith(F("bdown:"))) + { + c->callback(c, B_DOWN); + } + else if (msg.startsWith(F("bup:"))) + { + c->callback(c, B_UP); + } + else if (msg.startsWith(F("pfdown:"))) + { + c->callback(c, P_FOR_DOWN); + } + else if (msg.startsWith(F("pfup:"))) + { + c->callback(c, P_FOR_UP); + } + else if (msg.startsWith(F("pldown:"))) + { + c->callback(c, P_LEFT_DOWN); + } + else if (msg.startsWith(F("plup:"))) + { + c->callback(c, P_LEFT_UP); + } + else if (msg.startsWith(F("prdown:"))) + { + c->callback(c, P_RIGHT_DOWN); + } + else if (msg.startsWith(F("prup:"))) + { + c->callback(c, P_RIGHT_UP); + } + else if (msg.startsWith(F("pbdown:"))) + { + c->callback(c, P_BACK_DOWN); + } + else if (msg.startsWith(F("pbup:"))) + { + c->callback(c, P_BACK_UP); + } + else if (msg.startsWith(F("pcdown:"))) + { + c->callback(c, P_CENTER_DOWN); + } + else if (msg.startsWith(F("pcup:"))) + { + c->callback(c, P_CENTER_UP); + } + else if (msg.startsWith(F("sactive:"))) + { + c->value = "1"; + ESPUI.updateControl(c, client->id()); + c->callback(c, S_ACTIVE); + } + else if (msg.startsWith(F("sinactive:"))) + { + c->value = "0"; + ESPUI.updateControl(c, client->id()); + c->callback(c, S_INACTIVE); + } + else if (msg.startsWith(F("slvalue:"))) + { + c->value = msg.substring(msg.indexOf(':') + 1, msg.lastIndexOf(':')); + ESPUI.updateControl(c, client->id()); + c->callback(c, SL_VALUE); + } + else if (msg.startsWith(F("nvalue:"))) + { + c->value = msg.substring(msg.indexOf(':') + 1, msg.lastIndexOf(':')); + ESPUI.updateControl(c, client->id()); + c->callback(c, N_VALUE); + } + else if (msg.startsWith(F("tvalue:"))) + { + c->value = msg.substring(msg.indexOf(':') + 1, msg.lastIndexOf(':')); + ESPUI.updateControl(c, client->id()); + c->callback(c, T_VALUE); + } + else if (msg.startsWith(F("svalue:"))) + { + c->value = msg.substring(msg.indexOf(':') + 1, msg.lastIndexOf(':')); + ESPUI.updateControl(c, client->id()); + c->callback(c, S_VALUE); + } + else + { +#if defined(DEBUG_ESPUI) + if (ESPUI.verbosity) + { + Serial.println(F("Malformated message from the websocket")); + } +#endif + } + } break; - } - case WS_EVT_ERROR: - { - if (ESPUI.verbosity) - { - Serial.print(F("WebSocket Error!\n")); + default: + break; } +} - break; - } +uint16_t ESPUIClass::addControl(ControlType type, const char* label, const String& value, ControlColor color, + uint16_t parentControl, void (*callback)(Control*, int)) +{ + Control* control = new Control(type, label, callback, value, color, parentControl); - case WS_EVT_CONNECT: - { - if (ESPUI.verbosity) + if (this->controls == nullptr) { - Serial.print(F("Connected: ")); - Serial.println(client->id()); - } - - ESPUI.jsonDom(client); - - if (ESPUI.verbosity) - { - Serial.println(F("JSON Data Sent to Client!")); - } - } - break; - - case WS_EVT_DATA: - { - String msg = ""; - msg.reserve(len + 1); - - for (size_t i = 0; i < len; i++) - { - msg += (char)data[i]; - } - - uint16_t id = msg.substring(msg.lastIndexOf(':') + 1).toInt(); - - if (ESPUI.verbosity >= Verbosity::VerboseJSON) - { - Serial.print(F("WS rec: ")); - Serial.println(msg); - Serial.print(F("WS recognised ID: ")); - Serial.println(id); - } - - Control *c = ESPUI.getControl(id); - - if (c == nullptr) - { - if (ESPUI.verbosity) - { - Serial.print(F("No control found for ID ")); - Serial.println(id); - } - - return; - } - - if (c->callback == nullptr) - { - if (ESPUI.verbosity) - { - Serial.print(F("No callback found for ID ")); - Serial.println(id); - } - - return; - } - - if (msg.startsWith(F("bdown:"))) - { - c->callback(c, B_DOWN); - } - else if (msg.startsWith(F("bup:"))) - { - c->callback(c, B_UP); - } - else if (msg.startsWith(F("pfdown:"))) - { - c->callback(c, P_FOR_DOWN); - } - else if (msg.startsWith(F("pfup:"))) - { - c->callback(c, P_FOR_UP); - } - else if (msg.startsWith(F("pldown:"))) - { - c->callback(c, P_LEFT_DOWN); - } - else if (msg.startsWith(F("plup:"))) - { - c->callback(c, P_LEFT_UP); - } - else if (msg.startsWith(F("prdown:"))) - { - c->callback(c, P_RIGHT_DOWN); - } - else if (msg.startsWith(F("prup:"))) - { - c->callback(c, P_RIGHT_UP); - } - else if (msg.startsWith(F("pbdown:"))) - { - c->callback(c, P_BACK_DOWN); - } - else if (msg.startsWith(F("pbup:"))) - { - c->callback(c, P_BACK_UP); - } - else if (msg.startsWith(F("pcdown:"))) - { - c->callback(c, P_CENTER_DOWN); - } - else if (msg.startsWith(F("pcup:"))) - { - c->callback(c, P_CENTER_UP); - } - else if (msg.startsWith(F("sactive:"))) - { - c->value = "1"; - ESPUI.updateControl(c, client->id()); - c->callback(c, S_ACTIVE); - } - else if (msg.startsWith(F("sinactive:"))) - { - c->value = "0"; - ESPUI.updateControl(c, client->id()); - c->callback(c, S_INACTIVE); - } - else if (msg.startsWith(F("slvalue:"))) - { - c->value = msg.substring(msg.indexOf(':') + 1, msg.lastIndexOf(':')); - ESPUI.updateControl(c, client->id()); - c->callback(c, SL_VALUE); - } - else if (msg.startsWith(F("nvalue:"))) - { - c->value = msg.substring(msg.indexOf(':') + 1, msg.lastIndexOf(':')); - ESPUI.updateControl(c, client->id()); - c->callback(c, N_VALUE); - } - else if (msg.startsWith(F("tvalue:"))) - { - c->value = msg.substring(msg.indexOf(':') + 1, msg.lastIndexOf(':')); - ESPUI.updateControl(c, client->id()); - c->callback(c, T_VALUE); - } - else if (msg.startsWith(F("svalue:"))) - { - c->value = msg.substring(msg.indexOf(':') + 1, msg.lastIndexOf(':')); - ESPUI.updateControl(c, client->id()); - c->callback(c, S_VALUE); + this->controls = control; } else { - if (ESPUI.verbosity) - { - Serial.println(F("Malformated message from the websocket")); - } - } - } - break; + Control* iterator = this->controls; - default: - break; - } -} + while (iterator->next != nullptr) + { + iterator = iterator->next; + } -uint16_t ESPUIClass::addControl(ControlType type, const char *label, const String& value, ControlColor color, uint16_t parentControl, - void (*callback)(Control *, int)) -{ - Control *control = new Control(type, label, callback, value, color, parentControl); - - if (this->controls == nullptr) - { - this->controls = control; - } - else - { - Control *iterator = this->controls; - - while (iterator->next != nullptr) - { - iterator = iterator->next; + iterator->next = control; } - iterator->next = control; - } - - return control->id; + return control->id; } bool ESPUIClass::removeControl(uint16_t id, bool force_reload_ui) { - if (nullptr == this->controls) + if (nullptr == this->controls) + return false; + + Control* it = this->controls; + + if (id == it->id) + { + this->controls = it->next; + delete it; + if (force_reload_ui) + { + jsonReload(); + } + else + { + jsonDom(); + } + return true; + } + + Control* it_next = it->next; + while (nullptr != it_next && id != it_next->id) + { + it = it_next; + it_next = it_next->next; + } + + if (nullptr != it_next) + { + it->next = it_next->next; + delete it_next; + if (force_reload_ui) + { + jsonReload(); + } + else + { + jsonDom(); // resends to all + } + return true; + } + return false; +} - Control *it = this->controls; +uint16_t ESPUIClass::label(const char* label, ControlColor color, const String& value) +{ + return addControl(ControlType::Label, label, value, color); +} - if (id == it->id) - { - this->controls = it->next; - delete it; - if (force_reload_ui) +uint16_t ESPUIClass::graph(const char* label, ControlColor color) +{ + return addControl(ControlType::Graph, label, "", color); +} + +uint16_t ESPUIClass::slider( + const char* label, void (*callback)(Control*, int), ControlColor color, int value, int min, int max) +{ + uint16_t sliderId = addControl(ControlType::Slider, label, String(value), color, Control::noParent, callback); + addControl(ControlType::Min, label, String(min), ControlColor::None, sliderId); + addControl(ControlType::Max, label, String(max), ControlColor::None, sliderId); + + return sliderId; +} + +uint16_t ESPUIClass::button(const char* label, void (*callback)(Control*, int), ControlColor color, const String& value) +{ + return addControl(ControlType::Button, label, value, color, Control::noParent, callback); +} + +uint16_t ESPUIClass::switcher(const char* label, void (*callback)(Control*, int), ControlColor color, bool startState) +{ + return addControl(ControlType::Switcher, label, startState ? "1" : "0", color, Control::noParent, callback); +} + +uint16_t ESPUIClass::pad(const char* label, void (*callback)(Control*, int), ControlColor color) +{ + return addControl(ControlType::Pad, label, "", color, Control::noParent, callback); +} +uint16_t ESPUIClass::padWithCenter(const char* label, void (*callback)(Control*, int), ControlColor color) +{ + return addControl(ControlType::PadWithCenter, label, "", color, Control::noParent, callback); +} + +uint16_t ESPUIClass::number( + const char* label, void (*callback)(Control*, int), ControlColor color, int number, int min, int max) +{ + uint16_t numberId = addControl(ControlType::Number, label, String(number), color, Control::noParent, callback); + addControl(ControlType::Min, label, String(min), ControlColor::None, numberId); + addControl(ControlType::Max, label, String(max), ControlColor::None, numberId); + return numberId; +} + +uint16_t ESPUIClass::gauge(const char* label, ControlColor color, int number, int min, int max) +{ + uint16_t numberId = addControl(ControlType::Gauge, label, String(number), color, Control::noParent); + addControl(ControlType::Min, label, String(min), ControlColor::None, numberId); + addControl(ControlType::Max, label, String(max), ControlColor::None, numberId); + return numberId; +} + +uint16_t ESPUIClass::accelerometer(const char* label, void (*callback)(Control*, int), ControlColor color) +{ + return addControl(ControlType::Accel, label, "", color, Control::noParent, callback); +} + +uint16_t ESPUIClass::text(const char* label, void (*callback)(Control*, int), ControlColor color, const String& value) +{ + return addControl(ControlType::Text, label, value, color, Control::noParent, callback); +} + +Control* ESPUIClass::getControl(uint16_t id) +{ + Control* control = this->controls; + + while (control != nullptr) { - jsonReload(); - } - else - { - jsonDom(); - } - return true; - } + if (control->id == id) + { + return control; + } - Control *it_next = it->next; - while (nullptr != it_next && id != it_next->id) - { - it = it_next; - it_next = it_next->next; - } - - if (nullptr != it_next) - { - it->next = it_next->next; - delete it_next; - if (force_reload_ui) - { - jsonReload(); - } - else - { - jsonDom(); // resends to all - } - return true; - } - - return false; -} - -uint16_t ESPUIClass::label(const char *label, ControlColor color, const String& value) { return addControl(ControlType::Label, label, value, color); } - -uint16_t ESPUIClass::graph(const char *label, ControlColor color) { return addControl(ControlType::Graph, label, "", color); } - -uint16_t ESPUIClass::slider(const char *label, void (*callback)(Control *, int), ControlColor color, int value, int min, int max) -{ - uint16_t sliderId = addControl(ControlType::Slider, label, String(value), color, Control::noParent, callback); - addControl(ControlType::Min, label, String(min), ControlColor::None, sliderId); - addControl(ControlType::Max, label, String(max), ControlColor::None, sliderId); - - return sliderId; -} - -uint16_t ESPUIClass::button(const char *label, void (*callback)(Control *, int), ControlColor color, const String& value) -{ - return addControl(ControlType::Button, label, value, color, Control::noParent, callback); -} - -uint16_t ESPUIClass::switcher(const char *label, void (*callback)(Control *, int), ControlColor color, bool startState) -{ - return addControl(ControlType::Switcher, label, startState ? "1" : "0", color, Control::noParent, callback); -} - -uint16_t ESPUIClass::pad(const char *label, void (*callback)(Control *, int), ControlColor color) -{ - return addControl(ControlType::Pad, label, "", color, Control::noParent, callback); -} -uint16_t ESPUIClass::padWithCenter(const char *label, void (*callback)(Control *, int), ControlColor color) -{ - return addControl(ControlType::PadWithCenter, label, "", color, Control::noParent, callback); -} - -uint16_t ESPUIClass::number(const char *label, void (*callback)(Control *, int), ControlColor color, int number, int min, int max) -{ - uint16_t numberId = addControl(ControlType::Number, label, String(number), color, Control::noParent, callback); - addControl(ControlType::Min, label, String(min), ControlColor::None, numberId); - addControl(ControlType::Max, label, String(max), ControlColor::None, numberId); - return numberId; -} - -uint16_t ESPUIClass::gauge(const char *label, ControlColor color, int number, int min, int max) -{ - uint16_t numberId = addControl(ControlType::Gauge, label, String(number), color, Control::noParent); - addControl(ControlType::Min, label, String(min), ControlColor::None, numberId); - addControl(ControlType::Max, label, String(max), ControlColor::None, numberId); - return numberId; -} - -uint16_t ESPUIClass::accelerometer(const char *label, void (*callback)(Control *, int), ControlColor color) -{ - return addControl(ControlType::Accel, label, "", color, Control::noParent, callback); -} - -uint16_t ESPUIClass::text(const char *label, void (*callback)(Control *, int), ControlColor color, const String& value) -{ - return addControl(ControlType::Text, label, value, color, Control::noParent, callback); -} - -Control *ESPUIClass::getControl(uint16_t id) -{ - Control *control = this->controls; - - while (control != nullptr) - { - if (control->id == id) - { - return control; + control = control->next; } - control = control->next; - } - - return nullptr; + return nullptr; } -void ESPUIClass::updateControl(Control *control, int clientId) +void ESPUIClass::updateControl(Control* control, int clientId) { - if (!control) - { - return; - } + if (!control) + { + return; + } - String json; - DynamicJsonDocument document(jsonUpdateDocumentSize); - JsonObject root = document.to(); + String json; + DynamicJsonDocument document(jsonUpdateDocumentSize); + JsonObject root = document.to(); - root["type"] = (int)control->type + ControlType::UpdateOffset; - root["value"] = control->value; - root["id"] = control->id; - root["color"] = (int)control->color; - serializeJson(document, json); + root["type"] = (int)control->type + ControlType::UpdateOffset; + root["value"] = control->value; + root["id"] = control->id; + root["color"] = (int)control->color; + serializeJson(document, json); - if (this->verbosity >= Verbosity::VerboseJSON) - { - Serial.println(json); - } - - if (clientId < 0) - { +#if defined(DEBUG_ESPUI) if (this->verbosity >= Verbosity::VerboseJSON) { - Serial.println(F("TextAll")); + Serial.println(json); } - this->ws->textAll(json); - return; - } - // This is a hacky workaround because ESPAsyncWebServer does not have a - // function like this and it's clients array is private - int tryId = 0; +#endif - for (int count = 0; count < this->ws->count();) - { - if (this->ws->hasClient(tryId)) + if (clientId < 0) { - if (clientId != tryId) - { - this->ws->client(tryId)->text(json); - } - - count++; +#if defined(DEBUG_ESPUI) + if (this->verbosity >= Verbosity::VerboseJSON) + { + Serial.println(F("TextAll")); + } +#endif + this->ws->textAll(json); + return; } + // This is a hacky workaround because ESPAsyncWebServer does not have a + // function like this and it's clients array is private + int tryId = 0; - tryId++; - } + for (int count = 0; count < this->ws->count();) + { + if (this->ws->hasClient(tryId)) + { + if (clientId != tryId) + { + this->ws->client(tryId)->text(json); + } + + count++; + } + + tryId++; + } } void ESPUIClass::updateControl(uint16_t id, int clientId) { - Control *control = getControl(id); + Control* control = getControl(id); - if (!control) - { - if (this->verbosity) + if (!control) { - Serial.printf_P(PSTR("Error: There is no control with ID %d"), id); +#if defined(DEBUG_ESPUI) + if (this->verbosity) + { + Serial.printf_P(PSTR("Error: There is no control with ID %d"), id); + } +#endif + return; } - return; - } - updateControl(control, clientId); + updateControl(control, clientId); } -void ESPUIClass::updateControlValue(Control *control, const String& value, int clientId) +void ESPUIClass::updateControlValue(Control* control, const String& value, int clientId) { - if (!control) - { - return; - } + if (!control) + { + return; + } - control->value = value; - updateControl(control, clientId); + control->value = value; + updateControl(control, clientId); } void ESPUIClass::updateControlValue(uint16_t id, const String& value, int clientId) { - Control *control = getControl(id); + Control* control = getControl(id); - if (!control) - { - if (this->verbosity) + if (!control) { - Serial.printf_P(PSTR("Error: There is no control with ID %d"), id); +#if defined(DEBUG_ESPUI) + if (this->verbosity) + { + Serial.printf_P(PSTR("Error: There is no control with ID %d"), id); + } +#endif + return; } - return; - } - updateControlValue(control, value, clientId); + updateControlValue(control, value, clientId); } -void ESPUIClass::print(uint16_t id, const String& value) { updateControlValue(id, value); } +void ESPUIClass::print(uint16_t id, const String& value) +{ + updateControlValue(id, value); +} -void ESPUIClass::updateLabel(uint16_t id, const String& value) { updateControlValue(id, value); } +void ESPUIClass::updateLabel(uint16_t id, const String& value) +{ + updateControlValue(id, value); +} -void ESPUIClass::updateSlider(uint16_t id, int nValue, int clientId) { updateControlValue(id, String(nValue), clientId); } +void ESPUIClass::updateSlider(uint16_t id, int nValue, int clientId) +{ + updateControlValue(id, String(nValue), clientId); +} -void ESPUIClass::updateSwitcher(uint16_t id, bool nValue, int clientId) { updateControlValue(id, String(nValue ? "1" : "0"), clientId); } +void ESPUIClass::updateSwitcher(uint16_t id, bool nValue, int clientId) +{ + updateControlValue(id, String(nValue ? "1" : "0"), clientId); +} -void ESPUIClass::updateNumber(uint16_t id, int number, int clientId) { updateControlValue(id, String(number), clientId); } +void ESPUIClass::updateNumber(uint16_t id, int number, int clientId) +{ + updateControlValue(id, String(number), clientId); +} -void ESPUIClass::updateText(uint16_t id, const String& text, int clientId) { updateControlValue(id, text, clientId); } +void ESPUIClass::updateText(uint16_t id, const String& text, int clientId) +{ + updateControlValue(id, text, clientId); +} -void ESPUIClass::updateSelect(uint16_t id, const String& text, int clientId) { updateControlValue(id, text, clientId); } +void ESPUIClass::updateSelect(uint16_t id, const String& text, int clientId) +{ + updateControlValue(id, text, clientId); +} -void ESPUIClass::updateGauge(uint16_t id, int number, int clientId) { updateControlValue(id, String(number), clientId); } +void ESPUIClass::updateGauge(uint16_t id, int number, int clientId) +{ + updateControlValue(id, String(number), clientId); +} void ESPUIClass::clearGraph(uint16_t id, int clientId) {} void ESPUIClass::addGraphPoint(uint16_t id, int nValue, int clientId) { - Control *control = getControl(id); - if (!control) - { - return; - } - - String json; - DynamicJsonDocument document(jsonUpdateDocumentSize); - JsonObject root = document.to(); - - root["type"] = (int)ControlType::GraphPoint; - root["value"] = nValue; - root["id"] = control->id; - serializeJson(document, json); - - if (this->verbosity >= Verbosity::VerboseJSON) - { - Serial.println(json); - } - - if (clientId < 0) - { - this->ws->textAll(json); - return; - } - // This is a hacky workaround because ESPAsyncWebServer does not have a - // function like this and it's clients array is private - int tryId = 0; - - for (int count = 0; count < this->ws->count();) - { - if (this->ws->hasClient(tryId)) + Control* control = getControl(id); + if (!control) { - if (clientId != tryId) - { - this->ws->client(tryId)->text(json); - - if (this->verbosity >= Verbosity::VerboseJSON) - { - Serial.println(json); - } - } - - count++; + return; } - tryId++; - } + String json; + DynamicJsonDocument document(jsonUpdateDocumentSize); + JsonObject root = document.to(); + + root["type"] = (int)ControlType::GraphPoint; + root["value"] = nValue; + root["id"] = control->id; + serializeJson(document, json); + +#if defined(DEBUG_ESPUI) + if (this->verbosity >= Verbosity::VerboseJSON) + { + Serial.println(json); + } +#endif + + if (clientId < 0) + { + this->ws->textAll(json); + return; + } + // This is a hacky workaround because ESPAsyncWebServer does not have a + // function like this and it's clients array is private + int tryId = 0; + + for (int count = 0; count < this->ws->count();) + { + if (this->ws->hasClient(tryId)) + { + if (clientId != tryId) + { + this->ws->client(tryId)->text(json); + +#if defined(DEBUG_ESPUI) + if (this->verbosity >= Verbosity::VerboseJSON) + { + Serial.println(json); + } +#endif + } + + count++; + } + + tryId++; + } } /* Convert & Transfer Arduino elements to JSON elements @@ -815,302 +922,328 @@ Initially this function used to send the control element data individually. Due to a change in the ESPAsyncWebserver library this had top be changed to be sent as one blob at the beginning. Therefore a new type is used as well */ -void ESPUIClass::jsonDom(AsyncWebSocketClient *client) +void ESPUIClass::jsonDom(AsyncWebSocketClient* client) { - String json; - DynamicJsonDocument document(jsonInitialDocumentSize); - document["type"] = (int)UI_INITIAL_GUI; - document["sliderContinuous"] = sliderContinuous; - JsonArray items = document.createNestedArray("controls"); + String json; + DynamicJsonDocument document(jsonInitialDocumentSize); + document["type"] = (int)UI_INITIAL_GUI; + document["sliderContinuous"] = sliderContinuous; + JsonArray items = document.createNestedArray("controls"); - Control *control = this->controls; + Control* control = this->controls; - JsonObject titleItem = items.createNestedObject(); - titleItem["type"] = (int)UI_TITLE; - titleItem["label"] = ui_title; + JsonObject titleItem = items.createNestedObject(); + titleItem["type"] = (int)UI_TITLE; + titleItem["label"] = ui_title; - while (control != nullptr) - { - JsonObject item = items.createNestedObject(); - - item["id"] = String(control->id); - item["type"] = (int)control->type; - item["label"] = control->label; - item["value"] = String(control->value); - item["color"] = (int)control->color; - - if (control->parentControl != Control::noParent) + while (control != nullptr) { - item["parentControl"] = String(control->parentControl); + JsonObject item = items.createNestedObject(); + + item["id"] = String(control->id); + item["type"] = (int)control->type; + item["label"] = control->label; + item["value"] = String(control->value); + item["color"] = (int)control->color; + + if (control->parentControl != Control::noParent) + { + item["parentControl"] = String(control->parentControl); + } + + // special case for selects: to preselect an option, you have to add + // "selected" to