mirror of
https://github.com/s00500/ESPUI.git
synced 2025-07-05 07:50:19 +00:00
Merge 2e79f99247
into aa9a62bbdf
This commit is contained in:
228
src/ESPUI.cpp
228
src/ESPUI.cpp
@ -5,7 +5,11 @@
|
||||
#include <ESPAsyncWebServer.h>
|
||||
|
||||
#include "dataControlsJS.h"
|
||||
|
||||
#ifndef ESPU_DISABLE_GRAPH
|
||||
#include "dataGraphJS.h"
|
||||
#endif
|
||||
|
||||
#include "dataIndexHTML.h"
|
||||
#include "dataNormalizeCSS.h"
|
||||
#include "dataSliderJS.h"
|
||||
@ -17,6 +21,14 @@
|
||||
#include <umm_malloc/umm_heap_select.h>
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG) && defined(ESPU_DEBUG)
|
||||
#define ESPU_DBG(arg) Serial.print(arg)
|
||||
#define ESPU_DBGL(arg) Serial.println(arg)
|
||||
#else
|
||||
#define ESPU_DBG(arg)
|
||||
#define ESPU_DBGL(arg)
|
||||
#endif
|
||||
|
||||
static String heapInfo(const __FlashStringHelper* mode)
|
||||
{
|
||||
String result;
|
||||
@ -72,7 +84,7 @@ void listDir(const char* dirname, uint8_t levels)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.printf_P(PSTR("Listing directory: %s\n"), dirname);
|
||||
ESPU_DBGf_P(PSTR("Listing directory: %s\n"), dirname);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -91,7 +103,7 @@ void listDir(const char* dirname, uint8_t levels)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.println(F("Failed to open directory"));
|
||||
ESPU_DBGL(F("Failed to open directory"));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -103,7 +115,7 @@ void listDir(const char* dirname, uint8_t levels)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.println(F("Not a directory"));
|
||||
ESPU_DBGL(F("Not a directory"));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -119,8 +131,8 @@ void listDir(const char* dirname, uint8_t levels)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.print(F(" DIR : "));
|
||||
Serial.println(file.name());
|
||||
ESPU_DBG(F(" DIR : "));
|
||||
ESPU_DBGL(file.name());
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -138,10 +150,10 @@ void listDir(const char* dirname, uint8_t levels)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.print(F(" FILE: "));
|
||||
Serial.print(file.name());
|
||||
Serial.print(F(" SIZE: "));
|
||||
Serial.println(file.size());
|
||||
ESPU_DBG(F(" FILE: "));
|
||||
ESPU_DBG(file.name());
|
||||
ESPU_DBG(F(" SIZE: "));
|
||||
ESPU_DBGL(file.size());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -156,7 +168,7 @@ void listDir(const char* dirname, uint8_t levels)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.printf_P(PSTR("Listing directory: %s\n"), dirname);
|
||||
ESPU_DBGf_P(PSTR("Listing directory: %s\n"), dirname);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -169,8 +181,8 @@ void listDir(const char* dirname, uint8_t levels)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.print(F(" DIR : "));
|
||||
Serial.println(dir.fileName());
|
||||
ESPU_DBG(F(" DIR : "));
|
||||
ESPU_DBGL(dir.fileName());
|
||||
}
|
||||
#endif
|
||||
if (levels)
|
||||
@ -185,10 +197,10 @@ void listDir(const char* dirname, uint8_t levels)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.print(F(" FILE: "));
|
||||
Serial.print(dir.fileName());
|
||||
Serial.print(F(" SIZE: "));
|
||||
Serial.println(dir.fileSize());
|
||||
ESPU_DBG(F(" FILE: "));
|
||||
ESPU_DBG(dir.fileName());
|
||||
ESPU_DBG(F(" SIZE: "));
|
||||
ESPU_DBGL(dir.fileSize());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -206,13 +218,13 @@ void ESPUIClass::list()
|
||||
if (!LITTLEFS.begin())
|
||||
#endif
|
||||
{
|
||||
Serial.println(F("LITTLEFS Mount Failed"));
|
||||
ESPU_DBGL(F("LITTLEFS Mount Failed"));
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (!LittleFS.begin())
|
||||
{
|
||||
Serial.println(F("LittleFS Mount Failed"));
|
||||
ESPU_DBG(F("LittleFS Mount Failed"));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@ -220,27 +232,27 @@ void ESPUIClass::list()
|
||||
listDir("/", 1);
|
||||
#if defined(ESP32)
|
||||
|
||||
Serial.print(F("Total KB: "));
|
||||
ESPU_DBG(F("Total KB: "));
|
||||
#if (ESP_IDF_VERSION_MAJOR == 4 && ESP_IDF_VERSION_MINOR >= 4) || ESP_IDF_VERSION_MAJOR > 4
|
||||
Serial.println(LittleFS.totalBytes() / 1024);
|
||||
ESPU_DBGL(LittleFS.totalBytes() / 1024);
|
||||
#else
|
||||
Serial.println(LITTLEFS.totalBytes() / 1024);
|
||||
ESPU_DBGL(LITTLEFS.totalBytes() / 1024);
|
||||
#endif
|
||||
Serial.print(F("Used KB: "));
|
||||
ESPU_DBG(F("Used KB: "));
|
||||
#if (ESP_IDF_VERSION_MAJOR == 4 && ESP_IDF_VERSION_MINOR >= 4) || ESP_IDF_VERSION_MAJOR > 4
|
||||
Serial.println(LittleFS.usedBytes() / 1024);
|
||||
ESPU_DBGL(LittleFS.usedBytes() / 1024);
|
||||
#else
|
||||
Serial.println(LITTLEFS.usedBytes() / 1024);
|
||||
ESPU_DBGL(LITTLEFS.usedBytes() / 1024);
|
||||
#endif
|
||||
|
||||
#else
|
||||
FSInfo fs_info;
|
||||
LittleFS.info(fs_info);
|
||||
|
||||
Serial.print(F("Total KB: "));
|
||||
Serial.println(fs_info.totalBytes / 1024);
|
||||
Serial.print(F("Used KB: "));
|
||||
Serial.println(fs_info.usedBytes / 1024);
|
||||
ESPU_DBG(F("Total KB: "));
|
||||
ESPU_DBGL(fs_info.totalBytes / 1024);
|
||||
ESPU_DBG(F("Used KB: "));
|
||||
ESPU_DBGL(fs_info.usedBytes / 1024);
|
||||
|
||||
#endif
|
||||
}
|
||||
@ -261,7 +273,7 @@ void deleteFile(const char* path)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.printf_P(PSTR("File: %s does not exist, not deleting\n"), path);
|
||||
ESPU_DBGf_P(PSTR("File: %s does not exist, not deleting\n"), path);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -271,7 +283,7 @@ void deleteFile(const char* path)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.printf_P(PSTR("Deleting file: %s\n"), path);
|
||||
ESPU_DBGf_P(PSTR("Deleting file: %s\n"), path);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -289,7 +301,7 @@ void deleteFile(const char* path)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.println(F("File deleted"));
|
||||
ESPU_DBGL(F("File deleted"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -298,7 +310,7 @@ void deleteFile(const char* path)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.println(F("Delete failed"));
|
||||
ESPU_DBGL(F("Delete failed"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -309,7 +321,7 @@ void writeFile(const char* path, const char* data)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.printf_P(PSTR("Writing file: %s\n"), path);
|
||||
ESPU_DBGf_P(PSTR("Writing file: %s\n"), path);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -327,7 +339,7 @@ void writeFile(const char* path, const char* data)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.println(F("Failed to open file for writing"));
|
||||
ESPU_DBGL(F("Failed to open file for writing"));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -341,7 +353,7 @@ void writeFile(const char* path, const char* data)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.println(F("File written"));
|
||||
ESPU_DBGL(F("File written"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -350,7 +362,7 @@ void writeFile(const char* path, const char* data)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.println(F("Write failed"));
|
||||
ESPU_DBGL(F("Write failed"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -362,7 +374,7 @@ void writeFile(const char* path, const char* data)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.println(F("File written"));
|
||||
ESPU_DBGL(F("File written"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -371,7 +383,7 @@ void writeFile(const char* path, const char* data)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.println(F("Write failed"));
|
||||
ESPU_DBGL(F("Write failed"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -389,7 +401,7 @@ void ESPUIClass::prepareFileSystem(bool format)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (verbosity)
|
||||
{
|
||||
Serial.println(F("About to prepare filesystem..."));
|
||||
ESPU_DBGL(F("About to prepare filesystem..."));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -409,7 +421,7 @@ void ESPUIClass::prepareFileSystem(bool format)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (verbosity)
|
||||
{
|
||||
Serial.println(F("LittleFS Format Failed"));
|
||||
ESPU_DBGL(F("LittleFS Format Failed"));
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
@ -425,7 +437,7 @@ void ESPUIClass::prepareFileSystem(bool format)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (verbosity)
|
||||
{
|
||||
Serial.println(F("LittleFS Formatted"));
|
||||
ESPU_DBGL(F("LittleFS Formatted"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -434,7 +446,7 @@ void ESPUIClass::prepareFileSystem(bool format)
|
||||
if (verbosity)
|
||||
{
|
||||
listDir("/", 1);
|
||||
Serial.println(F("LittleFS Mount ESP32 Done"));
|
||||
ESPU_DBGL(F("LittleFS Mount ESP32 Done"));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -447,7 +459,7 @@ void ESPUIClass::prepareFileSystem(bool format)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (verbosity)
|
||||
{
|
||||
Serial.println(F("LittleFS Formatted"));
|
||||
ESPU_DBGL(F("LittleFS Formatted"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -456,7 +468,7 @@ void ESPUIClass::prepareFileSystem(bool format)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (verbosity)
|
||||
{
|
||||
Serial.println(F("LittleFS Mount Failed"));
|
||||
ESPU_DBGL(F("LittleFS Mount Failed"));
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
@ -468,7 +480,7 @@ void ESPUIClass::prepareFileSystem(bool format)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (verbosity)
|
||||
{
|
||||
Serial.println(F("LittleFS Formatted"));
|
||||
ESPU_DBGL(F("LittleFS Formatted"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -477,7 +489,7 @@ void ESPUIClass::prepareFileSystem(bool format)
|
||||
if (verbosity)
|
||||
{
|
||||
listDir("/", 1);
|
||||
Serial.println(F("LittleFS Mount ESP8266 Done"));
|
||||
ESPU_DBGL(F("LittleFS Mount ESP8266 Done"));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -491,13 +503,15 @@ void ESPUIClass::prepareFileSystem(bool format)
|
||||
deleteFile("/js/zepto.min.js");
|
||||
deleteFile("/js/controls.js");
|
||||
deleteFile("/js/slider.js");
|
||||
#ifndef ESPU_DISABLE_GRAPH
|
||||
deleteFile("/js/graph.js");
|
||||
#endif
|
||||
deleteFile("/js/tabbedcontent.js");
|
||||
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (verbosity)
|
||||
{
|
||||
Serial.println(F("Cleanup done"));
|
||||
ESPU_DBGL(F("Cleanup done"));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -512,8 +526,9 @@ void ESPUIClass::prepareFileSystem(bool format)
|
||||
writeFile("/js/zepto.min.js", JS_ZEPTO);
|
||||
writeFile("/js/controls.js", JS_CONTROLS);
|
||||
writeFile("/js/slider.js", JS_SLIDER);
|
||||
#ifndef ESPU_DISABLE_GRAPH
|
||||
writeFile("/js/graph.js", JS_GRAPH);
|
||||
|
||||
#endif
|
||||
writeFile("/js/tabbedcontent.js", JS_TABBEDCONTENT);
|
||||
#else
|
||||
writeFile("/index.htm", HTML_INDEX);
|
||||
@ -524,8 +539,9 @@ void ESPUIClass::prepareFileSystem(bool format)
|
||||
writeFile("/js/zepto.min.js", JS_ZEPTO);
|
||||
writeFile("/js/controls.js", JS_CONTROLS);
|
||||
writeFile("/js/slider.js", JS_SLIDER);
|
||||
#ifndef ESPU_DISABLE_GRAPH
|
||||
writeFile("/js/graph.js", JS_GRAPH);
|
||||
|
||||
#endif
|
||||
writeFile("/js/tabbedcontent.js", JS_TABBEDCONTENT);
|
||||
#endif
|
||||
#else
|
||||
@ -537,15 +553,16 @@ void ESPUIClass::prepareFileSystem(bool format)
|
||||
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);
|
||||
|
||||
#ifndef ESPU_DISABLE_GRAPH
|
||||
writeFile("/js/graph.js", JS_GRAPH);
|
||||
#endif
|
||||
writeFile("/js/tabbedcontent.js", JS_TABBEDCONTENT);
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (verbosity)
|
||||
{
|
||||
Serial.println(F("Done Initializing filesystem :-)"));
|
||||
ESPU_DBGL(F("Done Initializing filesystem :-)"));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -575,7 +592,7 @@ void ESPUIClass::prepareFileSystem(bool format)
|
||||
void ESPUIClass::onWsEvent(
|
||||
AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len)
|
||||
{
|
||||
// Serial.println(String("ESPUIClass::OnWsEvent: type: ") + String(type));
|
||||
// ESPU_DBGL(String("ESPUIClass::OnWsEvent: type: ") + String(type));
|
||||
RemoveToBeDeletedControls();
|
||||
|
||||
if (WS_EVT_DISCONNECT == type)
|
||||
@ -583,13 +600,13 @@ void ESPUIClass::onWsEvent(
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (verbosity)
|
||||
{
|
||||
Serial.println(F("WS_EVT_DISCONNECT"));
|
||||
ESPU_DBGL(F("WS_EVT_DISCONNECT"));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (MapOfClients.end() != MapOfClients.find(client->id()))
|
||||
{
|
||||
// Serial.println("Delete client.");
|
||||
// ESPU_DBGL("Delete client.");
|
||||
delete MapOfClients[client->id()];
|
||||
MapOfClients.erase(client->id());
|
||||
}
|
||||
@ -598,13 +615,13 @@ void ESPUIClass::onWsEvent(
|
||||
{
|
||||
if (MapOfClients.end() == MapOfClients.find(client->id()))
|
||||
{
|
||||
// Serial.println("ESPUIClass::OnWsEvent:Create new client.");
|
||||
// ESPU_DBGL("ESPUIClass::OnWsEvent:Create new client.");
|
||||
MapOfClients[client->id()] = new ESPUIclient(client);
|
||||
}
|
||||
|
||||
if(MapOfClients[client->id()]->onWsEvent(type, arg, data, len))
|
||||
{
|
||||
// Serial.println("ESPUIClass::OnWsEvent:notify the clients that they need to be updated.");
|
||||
// ESPU_DBGL("ESPUIClass::OnWsEvent:notify the clients that they need to be updated.");
|
||||
NotifyClients(ESPUIclient::UpdateNeeded);
|
||||
}
|
||||
}
|
||||
@ -630,7 +647,19 @@ uint16_t ESPUIClass::addControl(ControlType type, const char* label, const Strin
|
||||
uint16_t ESPUIClass::addControl(
|
||||
ControlType type, const char* label, const String& value, ControlColor color, uint16_t parentControl)
|
||||
{
|
||||
return addControl(type, label, value, color, parentControl, new Control(type, label, nullptr, value, color, true, parentControl));
|
||||
Control * ctrl = new Control(type, label, nullptr, value, color, true, parentControl);
|
||||
if (auto_update_values && ctrl)
|
||||
ctrl->auto_update_value = true;
|
||||
return addControl(ctrl);
|
||||
}
|
||||
|
||||
uint16_t ESPUIClass::addControl(
|
||||
ControlType type, const __FlashStringHelper* label, const String& value, ControlColor color, uint16_t parentControl)
|
||||
{
|
||||
Control* ctrl = new Control(type, label, nullptr, value, color, true, parentControl);
|
||||
if (auto_update_values && ctrl)
|
||||
ctrl->auto_update_value = true;
|
||||
return addControl(ctrl);
|
||||
}
|
||||
|
||||
uint16_t ESPUIClass::addControl(ControlType type, const char* label, const String& value, ControlColor color,
|
||||
@ -642,8 +671,16 @@ uint16_t ESPUIClass::addControl(ControlType type, const char* label, const Strin
|
||||
return id;
|
||||
}
|
||||
|
||||
uint16_t ESPUIClass::addControl(
|
||||
ControlType type, const char* label, const String& value, ControlColor color, uint16_t parentControl, Control* control)
|
||||
uint16_t ESPUIClass::addControl(ControlType type, const __FlashStringHelper* label, const String& value, ControlColor color,
|
||||
uint16_t parentControl, std::function<void(Control*, int)> callback)
|
||||
{
|
||||
uint16_t id = addControl(type, label, value, color, parentControl);
|
||||
// set the original style callback
|
||||
getControl(id)->callback = callback;
|
||||
return id;
|
||||
}
|
||||
|
||||
uint16_t ESPUIClass::addControl(Control* control)
|
||||
{
|
||||
#ifdef ESP32
|
||||
xSemaphoreTake(ControlsSemaphore, portMAX_DELAY);
|
||||
@ -699,7 +736,7 @@ bool ESPUIClass::removeControl(uint16_t id, bool force_rebuild_ui)
|
||||
#ifdef DEBUG_ESPUI
|
||||
else
|
||||
{
|
||||
// Serial.println(String("Could not Remove Control ") + String(id));
|
||||
// ESPU_DBGL(String("Could not Remove Control ") + String(id));
|
||||
}
|
||||
#endif // def DEBUG_ESPUI
|
||||
|
||||
@ -768,6 +805,10 @@ uint16_t ESPUIClass::button(const char* label, std::function<void(Control*, int)
|
||||
return addControl(ControlType::Button, label, value, color, Control::noParent, callback);
|
||||
}
|
||||
|
||||
uint16_t ESPUIClass::button(const __FlashStringHelper* label, const __FlashStringHelper* text, std::function<void(Control*, int)> callback, uint16_t parentControl, ControlColor color){
|
||||
return addControl(ControlType::Button, label, text, color, parentControl, callback);
|
||||
}
|
||||
|
||||
uint16_t ESPUIClass::switcher(const char* label, std::function<void(Control*, int)> callback, ControlColor color, bool startState)
|
||||
{
|
||||
return addControl(ControlType::Switcher, label, startState ? "1" : "0", color, Control::noParent, callback);
|
||||
@ -853,7 +894,7 @@ Control* ESPUIClass::getControlNoLock(uint16_t id)
|
||||
|
||||
void ESPUIClass::updateControl(Control* control, int)
|
||||
{
|
||||
if (!control)
|
||||
if (!control || !ws)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -916,7 +957,7 @@ void ESPUIClass::setEnabled(uint16_t id, bool enabled, int clientId)
|
||||
Control* control = getControl(id);
|
||||
if (control)
|
||||
{
|
||||
// Serial.println(String("CreateAllowed: id: ") + String(clientId) + " State: " + String(enabled));
|
||||
// ESPU_DBGL(String("CreateAllowed: id: ") + String(clientId) + " State: " + String(enabled));
|
||||
control->enabled = enabled;
|
||||
updateControl(control, clientId);
|
||||
}
|
||||
@ -940,7 +981,7 @@ void ESPUIClass::updateControl(uint16_t id, int clientId)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (verbosity)
|
||||
{
|
||||
Serial.printf_P(PSTR("Error: Update Control: There is no control with ID %d\n"), id);
|
||||
ESPU_DBGf_P(PSTR("Error: Update Control: There is no control with ID %d\n"), id);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
@ -969,7 +1010,7 @@ void ESPUIClass::updateControlValue(uint16_t id, const String& value, int client
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (verbosity)
|
||||
{
|
||||
Serial.printf_P(PSTR("Error: updateControlValue Control: There is no control with ID %d\n"), id);
|
||||
ESPU_DBGf_P(PSTR("Error: updateControlValue Control: There is no control with ID %d\n"), id);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
@ -990,12 +1031,30 @@ void ESPUIClass::updateControlLabel(Control* control, const char* value, int cli
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (verbosity)
|
||||
{
|
||||
Serial.printf_P(PSTR("Error: updateControlLabel Control: There is no control with the requested ID \n"));
|
||||
ESPU_DBGf_P(PSTR("Error: updateControlLabel Control: There is no control with the requested ID \n"));
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
control->label = value;
|
||||
control->label_r = value;
|
||||
control->lablel_is_in_flash = 0;
|
||||
updateControl(control, clientId);
|
||||
}
|
||||
|
||||
void ESPUIClass::updateControlLabel(Control* control, const __FlashStringHelper* value, int clientId)
|
||||
{
|
||||
if (!control)
|
||||
{
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (verbosity)
|
||||
{
|
||||
ESPU_DBGf_P(PSTR("Error: updateControlLabel Control: There is no control with the requested ID \n"));
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
control->label_f = value;
|
||||
control->lablel_is_in_flash = 1;
|
||||
updateControl(control, clientId);
|
||||
}
|
||||
|
||||
@ -1103,11 +1162,11 @@ void ESPUIClass::addGraphPoint(uint16_t id, int nValue, int clientId)
|
||||
} while (false);
|
||||
}
|
||||
|
||||
bool ESPUIClass::SendJsonDocToWebSocket(ArduinoJson::DynamicJsonDocument& document, uint16_t clientId)
|
||||
bool ESPUIClass::SendJsonDocToWebSocket(ArduinoJson::DynamicJsonDocument& document, int clientId)
|
||||
{
|
||||
bool Response = false;
|
||||
|
||||
if (0 > clientId)
|
||||
if (clientId >= 0)
|
||||
{
|
||||
if (MapOfClients.end() != MapOfClients.find(clientId))
|
||||
{
|
||||
@ -1143,7 +1202,7 @@ void ESPUIClass::jsonReload()
|
||||
{
|
||||
for (auto& CurrentClient : MapOfClients)
|
||||
{
|
||||
// Serial.println("Requesting Reload");
|
||||
// ESPU_DBGL("Requesting Reload");
|
||||
CurrentClient.second->NotifyClient(ClientUpdateType_t::ReloadNeeded);
|
||||
}
|
||||
}
|
||||
@ -1186,7 +1245,7 @@ void ESPUIClass::beginLITTLEFS(const char* _title, const char* username, const c
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (verbosity)
|
||||
{
|
||||
Serial.println(F("LITTLEFS Mount Failed, PLEASE CHECK THE README ON HOW TO "
|
||||
ESPU_DBGL(F("LITTLEFS Mount Failed, PLEASE CHECK THE README ON HOW TO "
|
||||
"PREPARE YOUR ESP!!!!!!!"));
|
||||
}
|
||||
#endif
|
||||
@ -1215,7 +1274,7 @@ void ESPUIClass::beginLITTLEFS(const char* _title, const char* username, const c
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (verbosity)
|
||||
{
|
||||
Serial.println(F("Please read the README!!!!!!!, Make sure to "
|
||||
ESPU_DBGL(F("Please read the README!!!!!!!, Make sure to "
|
||||
"prepareFileSystem() once in an empty sketch"));
|
||||
}
|
||||
#endif
|
||||
@ -1282,7 +1341,7 @@ void ESPUIClass::beginLITTLEFS(const char* _title, const char* username, const c
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (verbosity)
|
||||
{
|
||||
Serial.println(F("UI Initialized"));
|
||||
ESPU_DBGL(F("UI Initialized"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -1362,17 +1421,18 @@ void ESPUIClass::begin(const char* _title, const char* username, const char* pas
|
||||
request->send(response);
|
||||
});
|
||||
|
||||
#ifndef ESPU_DISABLE_GRAPH
|
||||
server->on("/js/graph.js", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||
if (ESPUI.basicAuth && !request->authenticate(ESPUI.basicAuthUsername, ESPUI.basicAuthPassword))
|
||||
{
|
||||
return request->requestAuthentication();
|
||||
}
|
||||
|
||||
AsyncWebServerResponse* response
|
||||
= request->beginResponse_P(200, "application/javascript", JS_GRAPH_GZIP, sizeof(JS_GRAPH_GZIP));
|
||||
response->addHeader("Content-Encoding", "gzip");
|
||||
request->send(response);
|
||||
});
|
||||
#endif
|
||||
|
||||
server->on("/js/tabbedcontent.js", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||
if (ESPUI.basicAuth && !request->authenticate(ESPUI.basicAuthUsername, ESPUI.basicAuthPassword))
|
||||
@ -1432,13 +1492,17 @@ void ESPUIClass::begin(const char* _title, const char* username, const char* pas
|
||||
request->send(404);
|
||||
}
|
||||
});
|
||||
|
||||
if (onCreateServerCallback) {
|
||||
onCreateServerCallback(server);
|
||||
}
|
||||
|
||||
server->begin();
|
||||
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (verbosity)
|
||||
{
|
||||
Serial.println(F("UI Initialized"));
|
||||
ESPU_DBGL(F("UI Initialized"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -1448,4 +1512,18 @@ void ESPUIClass::setVerbosity(Verbosity v)
|
||||
verbosity = v;
|
||||
}
|
||||
|
||||
void ESPUIClass::Alert(const char * message,alert_type_t alert_type, int clientId)
|
||||
{
|
||||
if (!message && !strlen(message))
|
||||
return;
|
||||
|
||||
DynamicJsonDocument document(jsonUpdateDocumentSize);
|
||||
JsonObject root = document.to<JsonObject>();
|
||||
|
||||
root[F("type")] = (int)MessageTypes::AlertInfo + (int)alert_type;
|
||||
root[F("value")] = message;
|
||||
|
||||
SendJsonDocToWebSocket(document, clientId);
|
||||
}
|
||||
|
||||
ESPUIClass ESPUI;
|
||||
|
54
src/ESPUI.h
54
src/ESPUI.h
@ -28,9 +28,7 @@
|
||||
|
||||
#else
|
||||
|
||||
#include <ArduinoOTA.h>
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266mDNS.h>
|
||||
#include <ESPAsyncTCP.h>
|
||||
#include <Hash.h>
|
||||
|
||||
@ -47,6 +45,10 @@ enum MessageTypes : uint8_t
|
||||
ExtendGUI = 210,
|
||||
UpdateGui = 220,
|
||||
ExtendedUpdateGui = 230,
|
||||
AlertInfo = 240,
|
||||
AlertWarning,
|
||||
AlertError,
|
||||
AllertSuccess
|
||||
};
|
||||
|
||||
#define UI_INITIAL_GUI MessageTypes::InitialGui
|
||||
@ -105,8 +107,16 @@ public:
|
||||
bool sliderContinuous = false;
|
||||
void onWsEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len);
|
||||
bool captivePortal = true;
|
||||
bool auto_update_values = false;
|
||||
|
||||
void setVerbosity(Verbosity verbosity);
|
||||
|
||||
typedef std::function<void(AsyncWebServer*)> onCreateServerCallback_t;
|
||||
void onCreateServerCallbackSet(onCreateServerCallback_t callback)
|
||||
{
|
||||
onCreateServerCallback = callback;
|
||||
}
|
||||
|
||||
void begin(const char* _title, const char* username = nullptr, const char* password = nullptr,
|
||||
uint16_t port = 80); // Setup server and page in Memorymode
|
||||
void beginSPIFFS(const char* _title, const char* username = nullptr, const char* password = nullptr,
|
||||
@ -122,13 +132,18 @@ public:
|
||||
uint16_t addControl(ControlType type, const char* label, const String& value);
|
||||
uint16_t addControl(ControlType type, const char* label, const String& value, ControlColor color);
|
||||
uint16_t addControl(ControlType type, const char* label, const String& value, ControlColor color, uint16_t parentControl);
|
||||
uint16_t addControl(ControlType type, const __FlashStringHelper* label, const String& value, ControlColor color, uint16_t parentControl);
|
||||
uint16_t addControl(ControlType type, const char* label, const String& value, ControlColor color, uint16_t parentControl, std::function<void(Control*, int)> callback);
|
||||
uint16_t addControl(ControlType type, const __FlashStringHelper * label, const String& value, ControlColor color, uint16_t parentControl, std::function<void(Control*, int)> callback);
|
||||
|
||||
bool removeControl(uint16_t id, bool force_rebuild_ui = false);
|
||||
|
||||
// create Elements
|
||||
// Create Event Button
|
||||
uint16_t button(const char* label, std::function<void(Control*, int)> callback, ControlColor color, const String& value = "");
|
||||
uint16_t button(const __FlashStringHelper* label, const __FlashStringHelper* value,
|
||||
std::function<void(Control*, int)> callback, uint16_t parentControl = Control::noParent, ControlColor color = ControlColor::Dark);
|
||||
|
||||
uint16_t switcher(const char* label, std::function<void(Control*, int)> callback, ControlColor color, bool startState = false); // Create Toggle Button
|
||||
uint16_t pad(const char* label, std::function<void(Control*, int)> callback, ControlColor color); // Create Pad Control
|
||||
uint16_t padWithCenter(const char* label, std::function<void(Control*, int)> callback, ControlColor color); // Create Pad Control with Centerbutton
|
||||
@ -158,6 +173,7 @@ public:
|
||||
|
||||
void updateControlLabel(uint16_t control, const char * value, int clientId = -1);
|
||||
void updateControlLabel(Control* control, const char * value, int clientId = -1);
|
||||
void updateControlLabel(Control* control, const __FlashStringHelper* value, int clientId = -1);
|
||||
|
||||
void updateControl(uint16_t id, int clientId = -1);
|
||||
void updateControl(Control* control, int clientId = -1);
|
||||
@ -186,8 +202,31 @@ public:
|
||||
|
||||
void updateVisibility(uint16_t id, bool visibility, int clientId = -1);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ALERT_INFO = 0,
|
||||
ALERT_WARNING,
|
||||
ALERT_ERROR,
|
||||
ALERT_SUCCESS
|
||||
} alert_type_t;
|
||||
|
||||
void Alert(const char* message, alert_type_t alert_type = ALERT_INFO, int clientId = -1);
|
||||
void AlertInfo(const char* message) { Alert(message); }
|
||||
void AlertWarning(const char* message){ Alert(message, ALERT_WARNING); }
|
||||
void AlertError(const char* message){ Alert(message, ALERT_ERROR); }
|
||||
void AlertSuccess(const char* message){ Alert(message, ALERT_SUCCESS); }
|
||||
void AlertInfo(String& message) { AlertInfo(message.c_str()); }
|
||||
void AlertWarning(String& message){ AlertWarning(message.c_str()); }
|
||||
void AlertError(String& message){ AlertError(message.c_str()); }
|
||||
void AlertSuccess(String& message){ AlertSuccess(message.c_str()); }
|
||||
void AlertInfo(const __FlashStringHelper * message) { AlertInfo(String(message).c_str()); }
|
||||
void AlertWarning(const __FlashStringHelper * message){ AlertWarning(String(message).c_str()); }
|
||||
void AlertError(const __FlashStringHelper * message){ AlertError(String(message).c_str()); }
|
||||
void AlertSuccess(const __FlashStringHelper * message){ AlertSuccess(String(message).c_str()); }
|
||||
|
||||
// Variables
|
||||
const char* ui_title = "ESPUI"; // Store UI Title and Header Name
|
||||
|
||||
Control* controls = nullptr;
|
||||
void jsonReload();
|
||||
void jsonDom(uint16_t startidx, AsyncWebSocketClient* client = nullptr, bool Updating = false);
|
||||
@ -231,6 +270,9 @@ public:
|
||||
{
|
||||
return accelerometer(label, [callback, userData](Control* sender, int type){ callback(sender, type, userData); }, color);
|
||||
}
|
||||
|
||||
AsyncWebServer* WebServer() {return server;}
|
||||
AsyncWebSocket* WebSocket() {return ws;}
|
||||
|
||||
AsyncWebServer* WebServer() {return server;}
|
||||
AsyncWebSocket* WebSocket() {return ws;}
|
||||
@ -247,19 +289,21 @@ protected:
|
||||
|
||||
AsyncWebServer* server;
|
||||
AsyncWebSocket* ws;
|
||||
|
||||
|
||||
|
||||
onCreateServerCallback_t onCreateServerCallback = nullptr;
|
||||
const char* basicAuthUsername = nullptr;
|
||||
const char* basicAuthPassword = nullptr;
|
||||
bool basicAuth = true;
|
||||
uint16_t controlCount = 0;
|
||||
|
||||
uint16_t addControl(ControlType type, const char* label, const String& value, ControlColor color, uint16_t parentControl, Control* control);
|
||||
uint16_t addControl(Control* control);
|
||||
|
||||
#define ClientUpdateType_t ESPUIclient::ClientUpdateType_t
|
||||
void NotifyClients(ClientUpdateType_t newState);
|
||||
void NotifyClient(uint32_t WsClientId, ClientUpdateType_t newState);
|
||||
|
||||
bool SendJsonDocToWebSocket(ArduinoJson::DynamicJsonDocument& document, uint16_t clientId);
|
||||
bool SendJsonDocToWebSocket(ArduinoJson::DynamicJsonDocument& document, int clientId);
|
||||
|
||||
std::map<uint32_t, ESPUIclient*> MapOfClients;
|
||||
|
||||
|
@ -2,6 +2,15 @@
|
||||
#include "ESPUIclient.h"
|
||||
#include "ESPUIcontrol.h"
|
||||
|
||||
#if defined(DEBUG) && defined(ESPU_DEBUG)
|
||||
#define ESPU_DBG(arg) Serial.print(arg)
|
||||
#define ESPU_DBGL(arg) Serial.println(arg)
|
||||
#else
|
||||
#define ESPU_DBG(arg)
|
||||
#define ESPU_DBGL(arg)
|
||||
#endif
|
||||
|
||||
|
||||
// JSONSlave:
|
||||
// helper to process exact JSON serialization size
|
||||
// it takes ~2ms on esp8266 and avoid large String reallocation which is really worth the cost
|
||||
@ -100,7 +109,7 @@ bool ESPUIclient::SendClientNotification(ClientUpdateType_t value)
|
||||
{
|
||||
if(!CanSend())
|
||||
{
|
||||
// Serial.println(F("ESPUIclient::SendClientNotification:CannotSend"));
|
||||
// ESPU_DBGL(F("ESPUIclient::SendClientNotification:CannotSend"));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -108,13 +117,13 @@ bool ESPUIclient::SendClientNotification(ClientUpdateType_t value)
|
||||
FillInHeader(document);
|
||||
if(ClientUpdateType_t::ReloadNeeded == value)
|
||||
{
|
||||
// Serial.println(F("ESPUIclient::SendClientNotification:set type to reload"));
|
||||
// ESPU_DBGL(F("ESPUIclient::SendClientNotification:set type to reload"));
|
||||
document["type"] = int(UI_RELOAD);
|
||||
}
|
||||
// dont send any controls
|
||||
|
||||
Response = SendJsonDocToWebSocket(document);
|
||||
// Serial.println(String("ESPUIclient::SendClientNotification:NotificationSent:Response: ") + String(Response));
|
||||
// ESPU_DBGL(String("ESPUIclient::SendClientNotification:NotificationSent:Response: ") + String(Response));
|
||||
|
||||
} while (false);
|
||||
return Response;
|
||||
@ -130,7 +139,7 @@ void ESPUIclient::NotifyClient(ClientUpdateType_t newState)
|
||||
bool ESPUIclient::onWsEvent(AwsEventType type, void* arg, uint8_t* data, size_t len)
|
||||
{
|
||||
bool Response = false;
|
||||
// Serial.println(String("ESPUIclient::OnWsEvent: type: ") + String(type));
|
||||
// ESPU_DBGL(String("ESPUIclient::OnWsEvent: type: ") + String(type));
|
||||
|
||||
switch (type)
|
||||
{
|
||||
@ -139,7 +148,7 @@ bool ESPUIclient::onWsEvent(AwsEventType type, void* arg, uint8_t* data, size_t
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.println(F("ESPUIclient::OnWsEvent:WS_EVT_PONG"));
|
||||
ESPU_DBGL(F("ESPUIclient::OnWsEvent:WS_EVT_PONG"));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
@ -150,7 +159,7 @@ bool ESPUIclient::onWsEvent(AwsEventType type, void* arg, uint8_t* data, size_t
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.println(F("ESPUIclient::OnWsEvent:WS_EVT_ERROR"));
|
||||
ESPU_DBGL(F("ESPUIclient::OnWsEvent:WS_EVT_ERROR"));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
@ -161,19 +170,19 @@ bool ESPUIclient::onWsEvent(AwsEventType type, void* arg, uint8_t* data, size_t
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.println(F("ESPUIclient::OnWsEvent:WS_EVT_CONNECT"));
|
||||
Serial.println(client->id());
|
||||
ESPU_DBGL(F("ESPUIclient::OnWsEvent:WS_EVT_CONNECT"));
|
||||
ESPU_DBGL(client->id());
|
||||
}
|
||||
#endif
|
||||
|
||||
// Serial.println("ESPUIclient:onWsEvent:WS_EVT_CONNECT: Call NotifyClient: RebuildNeeded");
|
||||
// ESPU_DBGL("ESPUIclient:onWsEvent:WS_EVT_CONNECT: Call NotifyClient: RebuildNeeded");
|
||||
NotifyClient(ClientUpdateType_t::RebuildNeeded);
|
||||
break;
|
||||
}
|
||||
|
||||
case WS_EVT_DATA:
|
||||
{
|
||||
// Serial.println(F("ESPUIclient::OnWsEvent:WS_EVT_DATA"));
|
||||
// ESPU_DBGL(F("ESPUIclient::OnWsEvent:WS_EVT_DATA"));
|
||||
String msg = "";
|
||||
msg.reserve(len + 1);
|
||||
|
||||
@ -189,50 +198,50 @@ bool ESPUIclient::onWsEvent(AwsEventType type, void* arg, uint8_t* data, size_t
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity >= Verbosity::VerboseJSON)
|
||||
{
|
||||
Serial.println(String(F(" WS msg: ")) + msg);
|
||||
Serial.println(String(F(" WS cmd: ")) + cmd);
|
||||
Serial.println(String(F(" WS id: ")) + String(id));
|
||||
Serial.println(String(F("WS value: ")) + String(value));
|
||||
ESPU_DBGL(String(F(" WS msg: ")) + msg);
|
||||
ESPU_DBGL(String(F(" WS cmd: ")) + cmd);
|
||||
ESPU_DBGL(String(F(" WS id: ")) + String(id));
|
||||
ESPU_DBGL(String(F("WS value: ")) + String(value));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cmd.equals(F("uiok")))
|
||||
{
|
||||
|
||||
// Serial.println(String(F("ESPUIclient::OnWsEvent:WS_EVT_DATA:uiok:ProcessAck:")) + pCurrentFsmState->GetStateName());
|
||||
// ESPU_DBGL(String(F("ESPUIclient::OnWsEvent:WS_EVT_DATA:uiok:ProcessAck:")) + pCurrentFsmState->GetStateName());
|
||||
pCurrentFsmState->ProcessAck(id, emptyString);
|
||||
break;
|
||||
}
|
||||
|
||||
if (cmd.equals(F("uifragmentok")))
|
||||
{
|
||||
// Serial.println(String(F("ESPUIclient::OnWsEvent:WS_EVT_DATA:uiok:uifragmentok:")) + pCurrentFsmState->GetStateName() + ":ProcessAck");
|
||||
// ESPU_DBGL(String(F("ESPUIclient::OnWsEvent:WS_EVT_DATA:uiok:uifragmentok:")) + pCurrentFsmState->GetStateName() + ":ProcessAck");
|
||||
if(!emptyString.equals(value))
|
||||
{
|
||||
// Serial.println(String(F("ESPUIclient::OnWsEvent:WS_EVT_DATA:uiok:uifragmentok:")) + pCurrentFsmState->GetStateName() + ":ProcessAck:value:'" + value + "'");
|
||||
// ESPU_DBGL(String(F("ESPUIclient::OnWsEvent:WS_EVT_DATA:uiok:uifragmentok:")) + pCurrentFsmState->GetStateName() + ":ProcessAck:value:'" + value + "'");
|
||||
pCurrentFsmState->ProcessAck(uint16_t(-1), value);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("ERROR:ESPUIclient::OnWsEvent:WS_EVT_DATA:uifragmentok:ProcessAck:Fragment Header is missing"));
|
||||
ESPU_DBGL(F("ERROR:ESPUIclient::OnWsEvent:WS_EVT_DATA:uifragmentok:ProcessAck:Fragment Header is missing"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (cmd.equals(F("uiuok")))
|
||||
{
|
||||
// Serial.println(F("WS_EVT_DATA: uiuok. Unlock new async notifications"));
|
||||
// ESPU_DBGL(F("WS_EVT_DATA: uiuok. Unlock new async notifications"));
|
||||
break;
|
||||
}
|
||||
|
||||
// Serial.println(F("WS_EVT_DATA:Process Control"));
|
||||
// ESPU_DBGL(F("WS_EVT_DATA:Process Control"));
|
||||
Control* control = ESPUI.getControl(id);
|
||||
if (nullptr == control)
|
||||
{
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.println(String(F("No control found for ID ")) + String(id));
|
||||
ESPU_DBGL(String(F("No control found for ID ")) + String(id));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
@ -245,7 +254,7 @@ bool ESPUIclient::onWsEvent(AwsEventType type, void* arg, uint8_t* data, size_t
|
||||
|
||||
default:
|
||||
{
|
||||
// Serial.println(F("ESPUIclient::OnWsEvent:default"));
|
||||
// ESPU_DBGL(F("ESPUIclient::OnWsEvent:default"));
|
||||
break;
|
||||
}
|
||||
} // end switch
|
||||
@ -267,7 +276,7 @@ uint32_t ESPUIclient::prepareJSONChunk(uint16_t startindex,
|
||||
xSemaphoreTake(ESPUI.ControlsSemaphore, portMAX_DELAY);
|
||||
#endif // def ESP32
|
||||
|
||||
// Serial.println(String("prepareJSONChunk: Start. InUpdateMode: ") + String(InUpdateMode));
|
||||
// ESPU_DBGL(String("prepareJSONChunk: Start. InUpdateMode: ") + String(InUpdateMode));
|
||||
int elementcount = 0;
|
||||
|
||||
do // once
|
||||
@ -281,10 +290,10 @@ uint32_t ESPUIclient::prepareJSONChunk(uint16_t startindex,
|
||||
|
||||
if(!emptyString.equals(FragmentRequestString))
|
||||
{
|
||||
// Serial.println(F("prepareJSONChunk:Fragmentation:Got Header (1)"));
|
||||
// Serial.println(String("prepareJSONChunk:startindex: ") + String(startindex));
|
||||
// Serial.println(String("prepareJSONChunk:currentIndex: ") + String(currentIndex));
|
||||
// Serial.println(String("prepareJSONChunk:FragmentRequestString: '") + FragmentRequestString + "'");
|
||||
// ESPU_DBGL(F("prepareJSONChunk:Fragmentation:Got Header (1)"));
|
||||
// ESPU_DBGL(String("prepareJSONChunk:startindex: ") + String(startindex));
|
||||
// ESPU_DBGL(String("prepareJSONChunk:currentIndex: ") + String(currentIndex));
|
||||
// ESPU_DBGL(String("prepareJSONChunk:FragmentRequestString: '") + FragmentRequestString + "'");
|
||||
|
||||
// this is actually a fragment or directed update request
|
||||
// parse the string we got from the UI and try to update that specific
|
||||
@ -292,38 +301,38 @@ uint32_t ESPUIclient::prepareJSONChunk(uint16_t startindex,
|
||||
DynamicJsonDocument FragmentRequest(FragmentRequestString.length() * 3);
|
||||
if(0 >= FragmentRequest.capacity())
|
||||
{
|
||||
Serial.println(F("ERROR:prepareJSONChunk:Fragmentation:Could not allocate memory for a fragmentation request. Skipping Response"));
|
||||
ESPU_DBGL(F("ERROR:prepareJSONChunk:Fragmentation:Could not allocate memory for a fragmentation request. Skipping Response"));
|
||||
break;
|
||||
}
|
||||
size_t FragmentRequestStartOffset = FragmentRequestString.indexOf("{");
|
||||
DeserializationError error = deserializeJson(FragmentRequest, FragmentRequestString.substring(FragmentRequestStartOffset));
|
||||
if(DeserializationError::Ok != error)
|
||||
{
|
||||
Serial.println(F("ERROR:prepareJSONChunk:Fragmentation:Could not extract json from the fragment request"));
|
||||
ESPU_DBGL(F("ERROR:prepareJSONChunk:Fragmentation:Could not extract json from the fragment request"));
|
||||
break;
|
||||
}
|
||||
|
||||
if(!FragmentRequest.containsKey(F("id")))
|
||||
{
|
||||
Serial.println(F("ERROR:prepareJSONChunk:Fragmentation:Request does not contain a control ID"));
|
||||
ESPU_DBGL(F("ERROR:prepareJSONChunk:Fragmentation:Request does not contain a control ID"));
|
||||
break;
|
||||
}
|
||||
uint16_t ControlId = uint16_t(FragmentRequest[F("id")]);
|
||||
|
||||
if(!FragmentRequest.containsKey(F("offset")))
|
||||
{
|
||||
Serial.println(F("ERROR:prepareJSONChunk:Fragmentation:Request does not contain a starting offset"));
|
||||
ESPU_DBGL(F("ERROR:prepareJSONChunk:Fragmentation:Request does not contain a starting offset"));
|
||||
break;
|
||||
}
|
||||
DataOffset = uint16_t(FragmentRequest[F("offset")]);
|
||||
control = ESPUI.getControlNoLock(ControlId);
|
||||
if(nullptr == control)
|
||||
{
|
||||
Serial.println(String(F("ERROR:prepareJSONChunk:Fragmentation:Requested control: ")) + String(ControlId) + F(" does not exist"));
|
||||
ESPU_DBGL(String(F("ERROR:prepareJSONChunk:Fragmentation:Requested control: ")) + String(ControlId) + F(" does not exist"));
|
||||
break;
|
||||
}
|
||||
|
||||
// Serial.println(F("prepareJSONChunk:Fragmentation:disable the control search operation"));
|
||||
// ESPU_DBGL(F("prepareJSONChunk:Fragmentation:disable the control search operation"));
|
||||
currentIndex = 1;
|
||||
startindex = 0;
|
||||
SingleControl = true;
|
||||
@ -355,7 +364,7 @@ uint32_t ESPUIclient::prepareJSONChunk(uint16_t startindex,
|
||||
// any controls left to be processed?
|
||||
if(nullptr == control)
|
||||
{
|
||||
// Serial.println("prepareJSONChunk: No controls to process");
|
||||
// ESPU_DBGL("prepareJSONChunk: No controls to process");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -367,7 +376,7 @@ uint32_t ESPUIclient::prepareJSONChunk(uint16_t startindex,
|
||||
// skip deleted controls or controls that have not been updated
|
||||
if (control->ToBeDeleted() && !SingleControl)
|
||||
{
|
||||
// Serial.println(String("prepareJSONChunk: Ignoring Deleted control: ") + String(control->id));
|
||||
// ESPU_DBGL(String("prepareJSONChunk: Ignoring Deleted control: ") + String(control->id));
|
||||
control = control->next;
|
||||
continue;
|
||||
}
|
||||
@ -395,8 +404,8 @@ uint32_t ESPUIclient::prepareJSONChunk(uint16_t startindex,
|
||||
// String("prepareJSONChunk: too much data in the message. Remove the last entry");
|
||||
if (1 == elementcount)
|
||||
{
|
||||
Serial.println(String(F("ERROR: prepareJSONChunk: Control ")) + String(control->id) + F(" is too large to be sent to the browser."));
|
||||
// Serial.println(String(F("ERROR: prepareJSONChunk: value: ")) + control->value);
|
||||
ESPU_DBGL(String(F("ERROR: prepareJSONChunk: Control ")) + String(control->id) + F(" is too large to be sent to the browser."));
|
||||
// ESPU_DBGL(String(F("ERROR: prepareJSONChunk: value: ")) + control->value);
|
||||
rootDoc.clear();
|
||||
item = items.createNestedObject();
|
||||
control->MarshalErrorMessage(item);
|
||||
@ -404,8 +413,8 @@ uint32_t ESPUIclient::prepareJSONChunk(uint16_t startindex,
|
||||
}
|
||||
else
|
||||
{
|
||||
// Serial.println(String("prepareJSONChunk: Defering control: ") + String(control->id));
|
||||
// Serial.println(String("prepareJSONChunk: elementcount: ") + String(elementcount));
|
||||
// ESPU_DBGL(String("prepareJSONChunk: Defering control: ") + String(control->id));
|
||||
// ESPU_DBGL(String("prepareJSONChunk: elementcount: ") + String(elementcount));
|
||||
|
||||
items.remove(elementcount);
|
||||
--elementcount;
|
||||
@ -415,7 +424,7 @@ uint32_t ESPUIclient::prepareJSONChunk(uint16_t startindex,
|
||||
}
|
||||
else if (SingleControl)
|
||||
{
|
||||
// Serial.println("prepareJSONChunk: exit loop");
|
||||
// ESPU_DBGL("prepareJSONChunk: exit loop");
|
||||
control = nullptr;
|
||||
}
|
||||
else
|
||||
@ -430,7 +439,7 @@ uint32_t ESPUIclient::prepareJSONChunk(uint16_t startindex,
|
||||
xSemaphoreGive(ESPUI.ControlsSemaphore);
|
||||
#endif // def ESP32
|
||||
|
||||
// Serial.println(String("prepareJSONChunk: elementcount: ") + String(elementcount));
|
||||
// ESPU_DBGL(String("prepareJSONChunk: elementcount: ") + String(elementcount));
|
||||
return elementcount;
|
||||
}
|
||||
|
||||
@ -457,18 +466,18 @@ etc.
|
||||
bool ESPUIclient::SendControlsToClient(uint16_t startidx, ClientUpdateType_t TransferMode, String FragmentRequest)
|
||||
{
|
||||
bool Response = false;
|
||||
// Serial.println(String("ESPUIclient:SendControlsToClient:startidx: ") + String(startidx));
|
||||
// ESPU_DBGL(String("ESPUIclient:SendControlsToClient:startidx: ") + String(startidx));
|
||||
do // once
|
||||
{
|
||||
if(!CanSend())
|
||||
{
|
||||
// Serial.println("ESPUIclient:SendControlsToClient: Cannot Send to clients.");
|
||||
// ESPU_DBGL("ESPUIclient:SendControlsToClient: Cannot Send to clients.");
|
||||
break;
|
||||
}
|
||||
|
||||
else if ((startidx >= ESPUI.controlCount) && (emptyString.equals(FragmentRequest)))
|
||||
{
|
||||
// Serial.println(F("ERROR:ESPUIclient:SendControlsToClient: No more controls to send."));
|
||||
// ESPU_DBGL(F("ERROR:ESPUIclient:SendControlsToClient: No more controls to send."));
|
||||
Response = true;
|
||||
break;
|
||||
}
|
||||
@ -480,44 +489,44 @@ bool ESPUIclient::SendControlsToClient(uint16_t startidx, ClientUpdateType_t Tra
|
||||
|
||||
if(0 == startidx)
|
||||
{
|
||||
// Serial.println("ESPUIclient:SendControlsToClient: Tell client we are starting a transfer of controls.");
|
||||
// ESPU_DBGL("ESPUIclient:SendControlsToClient: Tell client we are starting a transfer of controls.");
|
||||
document["type"] = (ClientUpdateType_t::RebuildNeeded == TransferMode) ? UI_INITIAL_GUI : UI_EXTEND_GUI;
|
||||
CurrentSyncID = NextSyncID;
|
||||
NextSyncID = ESPUI.GetNextControlChangeId();
|
||||
}
|
||||
// Serial.println(String("ESPUIclient:SendControlsToClient:type: ") + String((uint32_t)document["type"]));
|
||||
// ESPU_DBGL(String("ESPUIclient:SendControlsToClient:type: ") + String((uint32_t)document["type"]));
|
||||
|
||||
// Serial.println("ESPUIclient:SendControlsToClient: Build Controls.");
|
||||
// ESPU_DBGL("ESPUIclient:SendControlsToClient: Build Controls.");
|
||||
if(prepareJSONChunk(startidx, document, ClientUpdateType_t::UpdateNeeded == TransferMode, FragmentRequest))
|
||||
{
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity >= Verbosity::VerboseJSON)
|
||||
{
|
||||
Serial.println(F("ESPUIclient:SendControlsToClient: Sending elements --------->"));
|
||||
ESPU_DBGL(F("ESPUIclient:SendControlsToClient: Sending elements --------->"));
|
||||
serializeJson(document, Serial);
|
||||
Serial.println();
|
||||
ESPU_DBGL();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Serial.println("ESPUIclient:SendControlsToClient: Send message.");
|
||||
// ESPU_DBGL("ESPUIclient:SendControlsToClient: Send message.");
|
||||
if(true == SendJsonDocToWebSocket(document))
|
||||
{
|
||||
// Serial.println("ESPUIclient:SendControlsToClient: Sent.");
|
||||
// ESPU_DBGL("ESPUIclient:SendControlsToClient: Sent.");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Serial.println("ESPUIclient:SendControlsToClient: Send failed.");
|
||||
// ESPU_DBGL("ESPUIclient:SendControlsToClient: Send failed.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Serial.println("ESPUIclient:SendControlsToClient: No elements to send.");
|
||||
// ESPU_DBGL("ESPUIclient:SendControlsToClient: No elements to send.");
|
||||
Response = true;
|
||||
}
|
||||
|
||||
} while(false);
|
||||
|
||||
// Serial.println(String("ESPUIclient:SendControlsToClient:Response: ") + String(Response));
|
||||
// ESPU_DBGL(String("ESPUIclient:SendControlsToClient:Response: ") + String(Response));
|
||||
return Response;
|
||||
}
|
||||
|
||||
@ -532,10 +541,10 @@ bool ESPUIclient::SendJsonDocToWebSocket(DynamicJsonDocument& document)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity >= Verbosity::VerboseJSON)
|
||||
{
|
||||
Serial.println(F("ESPUIclient::SendJsonDocToWebSocket: Cannot Send to client. Not sending websocket message"));
|
||||
ESPU_DBGL(F("ESPUIclient::SendJsonDocToWebSocket: Cannot Send to client. Not sending websocket message"));
|
||||
}
|
||||
#endif
|
||||
// Serial.println("ESPUIclient::SendJsonDocToWebSocket: Cannot Send to client. Not sending websocket message");
|
||||
// ESPU_DBGL("ESPUIclient::SendJsonDocToWebSocket: Cannot Send to client. Not sending websocket message");
|
||||
Response = false;
|
||||
break;
|
||||
}
|
||||
@ -545,17 +554,17 @@ bool ESPUIclient::SendJsonDocToWebSocket(DynamicJsonDocument& document)
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity >= Verbosity::VerboseJSON)
|
||||
{
|
||||
Serial.println(String(F("ESPUIclient::SendJsonDocToWebSocket: json: '")) + json + "'");
|
||||
ESPU_DBGL(String(F("ESPUIclient::SendJsonDocToWebSocket: json: '")) + json + "'");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity >= Verbosity::VerboseJSON)
|
||||
{
|
||||
Serial.println(F("ESPUIclient::SendJsonDocToWebSocket: client.text"));
|
||||
ESPU_DBGL(F("ESPUIclient::SendJsonDocToWebSocket: client.text"));
|
||||
}
|
||||
#endif
|
||||
// Serial.println(F("ESPUIclient::SendJsonDocToWebSocket: client.text"));
|
||||
// ESPU_DBGL(F("ESPUIclient::SendJsonDocToWebSocket: client.text"));
|
||||
client->text(json);
|
||||
|
||||
} while (false);
|
||||
|
@ -1,282 +1,302 @@
|
||||
#include "ESPUI.h"
|
||||
|
||||
static uint16_t idCounter = 0;
|
||||
static const String ControlError = "*** ESPUI ERROR: Could not transfer control ***";
|
||||
|
||||
Control::Control(ControlType type, const char* label, std::function<void(Control*, int)> callback,
|
||||
const String& value, ControlColor color, bool visible, uint16_t parentControl)
|
||||
: type(type),
|
||||
label(label),
|
||||
callback(callback),
|
||||
value(value),
|
||||
color(color),
|
||||
visible(visible),
|
||||
wide(false),
|
||||
vertical(false),
|
||||
enabled(true),
|
||||
parentControl(parentControl),
|
||||
next(nullptr)
|
||||
{
|
||||
id = ++idCounter;
|
||||
ControlChangeID = 1;
|
||||
}
|
||||
|
||||
Control::Control(const Control& Control)
|
||||
: type(Control.type),
|
||||
id(Control.id),
|
||||
label(Control.label),
|
||||
callback(Control.callback),
|
||||
value(Control.value),
|
||||
color(Control.color),
|
||||
visible(Control.visible),
|
||||
parentControl(Control.parentControl),
|
||||
next(Control.next),
|
||||
ControlChangeID(Control.ControlChangeID)
|
||||
{ }
|
||||
|
||||
void Control::SendCallback(int type)
|
||||
{
|
||||
if(callback)
|
||||
{
|
||||
callback(this, type);
|
||||
}
|
||||
}
|
||||
|
||||
void Control::DeleteControl()
|
||||
{
|
||||
_ToBeDeleted = true;
|
||||
callback = nullptr;
|
||||
}
|
||||
|
||||
void Control::MarshalControl(JsonObject & _item, bool refresh, uint32_t StartingOffset)
|
||||
{
|
||||
JsonObject & item = _item;
|
||||
uint32_t length = value.length();
|
||||
uint32_t maxLength = uint32_t(double(ESPUI.jsonInitialDocumentSize) * 0.75);
|
||||
if((length > maxLength) || StartingOffset)
|
||||
{
|
||||
/*
|
||||
Serial.println(String("MarshalControl:Start Fragment Processing"));
|
||||
Serial.println(String("MarshalControl:id: ") + String(id));
|
||||
Serial.println(String("MarshalControl:length: ") + String(length));
|
||||
Serial.println(String("MarshalControl:StartingOffset: ") + String(StartingOffset));
|
||||
Serial.println(String("MarshalControl:maxLength: ") + String(maxLength));
|
||||
|
||||
if(0 == StartingOffset)
|
||||
{
|
||||
Serial.println(String("MarshalControl: New control to fragement. ID: ") + String(id));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(String("MarshalControl: Next fragement. ID: ") + String(id));
|
||||
}
|
||||
*/
|
||||
|
||||
// indicate that no additional controls should be sent
|
||||
_item[F("type")] = uint32_t(ControlType::Fragment);
|
||||
_item[F("id")] = id;
|
||||
|
||||
length = min((length - StartingOffset), maxLength);
|
||||
// Serial.println(String("MarshalControl:Final length: ") + String(length));
|
||||
|
||||
_item[F("offset")] = StartingOffset;
|
||||
_item[F("length")] = length;
|
||||
_item[F("total")] = value.length();
|
||||
item = _item.createNestedObject(F("control"));
|
||||
}
|
||||
|
||||
item[F("id")] = id;
|
||||
ControlType TempType = (ControlType::Password == type) ? ControlType::Text : type;
|
||||
if(refresh)
|
||||
{
|
||||
item[F("type")] = uint32_t(TempType) + uint32_t(ControlType::UpdateOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
item[F("type")] = uint32_t(TempType);
|
||||
}
|
||||
|
||||
item[F("label")] = label;
|
||||
item[F ("value")] = (ControlType::Password == type) ? F ("--------") : value.substring(StartingOffset, length + StartingOffset);
|
||||
item[F("visible")] = visible;
|
||||
item[F("color")] = (int)color;
|
||||
item[F("enabled")] = enabled;
|
||||
|
||||
if (!panelStyle.isEmpty()) {item[F("panelStyle")] = panelStyle;}
|
||||
if (!elementStyle.isEmpty()) {item[F("elementStyle")] = elementStyle;}
|
||||
if (!inputType.isEmpty()) {item[F("inputType")] = inputType;}
|
||||
if (wide == true) {item[F("wide")] = true;}
|
||||
if (vertical == true) {item[F("vertical")] = true;}
|
||||
if (parentControl != Control::noParent)
|
||||
{
|
||||
item[F("parentControl")] = String(parentControl);
|
||||
}
|
||||
|
||||
// special case for selects: to preselect an option, you have to add
|
||||
// "selected" to <option>
|
||||
if (ControlType::Option == type)
|
||||
{
|
||||
Control* ParentControl = ESPUI.getControlNoLock(parentControl);
|
||||
if (nullptr == ParentControl)
|
||||
{
|
||||
item[F("selected")] = emptyString;
|
||||
}
|
||||
else if (ParentControl->value == value)
|
||||
{
|
||||
item[F("selected")] = F("selected");
|
||||
}
|
||||
else
|
||||
{
|
||||
item[F("selected")] = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Control::MarshalErrorMessage(JsonObject & item)
|
||||
{
|
||||
item[F("id")] = id;
|
||||
item[F("type")] = uint32_t(ControlType::Label);
|
||||
item[F("label")] = ControlError.c_str();
|
||||
item[F("value")] = ControlError;
|
||||
item[F("visible")] = true;
|
||||
item[F("color")] = (int)ControlColor::Carrot;
|
||||
item[F("enabled")] = true;
|
||||
|
||||
if (parentControl != Control::noParent)
|
||||
{
|
||||
item[F("parentControl")] = String(parentControl);
|
||||
}
|
||||
}
|
||||
|
||||
void Control::onWsEvent(String & cmd, String& data)
|
||||
{
|
||||
do // once
|
||||
{
|
||||
// Serial.println(String(F("Control::onWsEvent")));
|
||||
SetControlChangedId(ESPUI.GetNextControlChangeId());
|
||||
if (!HasCallback())
|
||||
{
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.println(String(F("Control::onWsEvent:No callback found for ID ")) + String(id));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
// Serial.println("Control::onWsEvent:Generating callback");
|
||||
if (cmd.equals(F("bdown")))
|
||||
{
|
||||
SendCallback(B_DOWN);
|
||||
break;
|
||||
}
|
||||
|
||||
if (cmd.equals(F("bup")))
|
||||
{
|
||||
SendCallback(B_UP);
|
||||
break;
|
||||
}
|
||||
|
||||
if (cmd.equals(F("pfdown")))
|
||||
{
|
||||
SendCallback(P_FOR_DOWN);
|
||||
break;
|
||||
}
|
||||
|
||||
if (cmd.equals(F("pfup")))
|
||||
{
|
||||
SendCallback(P_FOR_UP);
|
||||
break;
|
||||
}
|
||||
|
||||
if (cmd.equals(F("pldown")))
|
||||
{
|
||||
SendCallback(P_LEFT_DOWN);
|
||||
break;
|
||||
}
|
||||
|
||||
else if (cmd.equals(F("plup")))
|
||||
{
|
||||
SendCallback(P_LEFT_UP);
|
||||
}
|
||||
else if (cmd.equals(F("prdown")))
|
||||
{
|
||||
SendCallback(P_RIGHT_DOWN);
|
||||
}
|
||||
else if (cmd.equals(F("prup")))
|
||||
{
|
||||
SendCallback(P_RIGHT_UP);
|
||||
}
|
||||
else if (cmd.equals(F("pbdown")))
|
||||
{
|
||||
SendCallback(P_BACK_DOWN);
|
||||
}
|
||||
else if (cmd.equals(F("pbup")))
|
||||
{
|
||||
SendCallback(P_BACK_UP);
|
||||
}
|
||||
else if (cmd.equals(F("pcdown")))
|
||||
{
|
||||
SendCallback(P_CENTER_DOWN);
|
||||
}
|
||||
else if (cmd.equals(F("pcup")))
|
||||
{
|
||||
SendCallback(P_CENTER_UP);
|
||||
}
|
||||
else if (cmd.equals(F("sactive")))
|
||||
{
|
||||
value = "1";
|
||||
SendCallback(S_ACTIVE);
|
||||
}
|
||||
else if (cmd.equals(F("sinactive")))
|
||||
{
|
||||
value = "0";
|
||||
// updateControl(c, client->id());
|
||||
SendCallback(S_INACTIVE);
|
||||
}
|
||||
else if (cmd.equals(F("slvalue")))
|
||||
{
|
||||
value = data;
|
||||
// updateControl(c, client->id());
|
||||
SendCallback(SL_VALUE);
|
||||
}
|
||||
else if (cmd.equals(F("nvalue")))
|
||||
{
|
||||
value = data;
|
||||
// updateControl(c, client->id());
|
||||
SendCallback(N_VALUE);
|
||||
}
|
||||
else if (cmd.equals(F("tvalue")))
|
||||
{
|
||||
value = data;
|
||||
// updateControl(c, client->id());
|
||||
SendCallback(T_VALUE);
|
||||
}
|
||||
else if (cmd.equals(F("tabvalue")))
|
||||
{
|
||||
SendCallback(0);
|
||||
}
|
||||
else if (cmd.equals(F("svalue")))
|
||||
{
|
||||
value = data;
|
||||
// updateControl(c, client->id());
|
||||
SendCallback(S_VALUE);
|
||||
}
|
||||
else if (cmd.equals(F("time")))
|
||||
{
|
||||
value = data;
|
||||
// updateControl(c, client->id());
|
||||
SendCallback(TM_VALUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.println(F("Control::onWsEvent:Malformed message from the websocket"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} while (false);
|
||||
}
|
||||
#include "ESPUI.h"
|
||||
|
||||
static uint16_t idCounter = 0;
|
||||
static const String ControlError = "*** ESPUI ERROR: Could not transfer control ***";
|
||||
|
||||
Control::Control(ControlType type, const char* label, std::function<void(Control*, int)> callback, const String& value,
|
||||
ControlColor color, bool visible, uint16_t parentControl)
|
||||
: label_r(label),
|
||||
callback(callback),
|
||||
next(nullptr),
|
||||
value(value),
|
||||
type(type),
|
||||
color(color),
|
||||
parentControl(parentControl),
|
||||
options(CTRL_OPT_ENABLED),
|
||||
ControlChangeID(1)
|
||||
{
|
||||
this->visible = visible;
|
||||
id = ++idCounter;
|
||||
}
|
||||
|
||||
Control::Control(ControlType type, const __FlashStringHelper* label, std::function<void(Control*, int)> callback,
|
||||
const String& value, ControlColor color, bool visible, uint16_t parentControl)
|
||||
: label_f(label),
|
||||
callback(callback),
|
||||
next(nullptr),
|
||||
value(value),
|
||||
type(type),
|
||||
color(color),
|
||||
parentControl(parentControl),
|
||||
options(CTRL_OPT_ENABLED | CTRL_OPT_LABEL_IN_FLASH),
|
||||
ControlChangeID(1)
|
||||
{
|
||||
this->visible = visible;
|
||||
id = ++idCounter;
|
||||
}
|
||||
|
||||
Control::Control(const Control& Control)
|
||||
: label_r(Control.label_r),
|
||||
callback(Control.callback),
|
||||
next(Control.next),
|
||||
value(Control.value),
|
||||
type(Control.type),
|
||||
color(Control.color),
|
||||
id(Control.id),
|
||||
parentControl(Control.parentControl),
|
||||
visible(Control.visible),
|
||||
ControlChangeID(Control.ControlChangeID)
|
||||
{
|
||||
options = Control.options;
|
||||
if (lablel_is_in_flash)
|
||||
label_f = Control.label_f;
|
||||
}
|
||||
|
||||
void Control::SendCallback(int type)
|
||||
{
|
||||
if(callback)
|
||||
{
|
||||
callback(this, type);
|
||||
}
|
||||
}
|
||||
|
||||
void Control::DeleteControl()
|
||||
{
|
||||
_ToBeDeleted = true;
|
||||
callback = nullptr;
|
||||
}
|
||||
|
||||
void Control::MarshalControl(JsonObject & _item, bool refresh, uint32_t StartingOffset)
|
||||
{
|
||||
JsonObject & item = _item;
|
||||
uint32_t length = value.length();
|
||||
uint32_t maxLength = uint32_t(double(ESPUI.jsonInitialDocumentSize) * 0.75);
|
||||
if((length > maxLength) || StartingOffset)
|
||||
{
|
||||
/*
|
||||
Serial.println(String("MarshalControl:Start Fragment Processing"));
|
||||
Serial.println(String("MarshalControl:id: ") + String(id));
|
||||
Serial.println(String("MarshalControl:length: ") + String(length));
|
||||
Serial.println(String("MarshalControl:StartingOffset: ") + String(StartingOffset));
|
||||
Serial.println(String("MarshalControl:maxLength: ") + String(maxLength));
|
||||
|
||||
if(0 == StartingOffset)
|
||||
{
|
||||
Serial.println(String("MarshalControl: New control to fragement. ID: ") + String(id));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(String("MarshalControl: Next fragement. ID: ") + String(id));
|
||||
}
|
||||
*/
|
||||
|
||||
// indicate that no additional controls should be sent
|
||||
_item[F("type")] = uint32_t(ControlType::Fragment);
|
||||
_item[F("id")] = id;
|
||||
|
||||
length = min((length - StartingOffset), maxLength);
|
||||
// Serial.println(String("MarshalControl:Final length: ") + String(length));
|
||||
|
||||
_item[F("offset")] = StartingOffset;
|
||||
_item[F("length")] = length;
|
||||
_item[F("total")] = value.length();
|
||||
item = _item.createNestedObject(F("control"));
|
||||
}
|
||||
|
||||
item[F("id")] = id;
|
||||
ControlType TempType = (ControlType::Password == type) ? ControlType::Text : type;
|
||||
if(refresh)
|
||||
{
|
||||
item[F("type")] = uint32_t(TempType) + uint32_t(ControlType::UpdateOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
item[F("type")] = uint32_t(TempType);
|
||||
}
|
||||
|
||||
if (lablel_is_in_flash)
|
||||
item[F("label")] = label_f;
|
||||
else
|
||||
item[F("label")] = label_r;
|
||||
item[F ("value")] = (ControlType::Password == type) ? F ("--------") : value.substring(StartingOffset, length + StartingOffset);
|
||||
item[F("visible")] = visible;
|
||||
item[F("color")] = (int)color;
|
||||
item[F("enabled")] = enabled;
|
||||
|
||||
if (!panelStyle.isEmpty()) {item[F("panelStyle")] = panelStyle;}
|
||||
if (!elementStyle.isEmpty()) {item[F("elementStyle")] = elementStyle;}
|
||||
if (!inputType.isEmpty()) {item[F("inputType")] = inputType;}
|
||||
if (wide == true) {item[F("wide")] = true;}
|
||||
if (vertical == true) {item[F("vertical")] = true;}
|
||||
if (parentControl != Control::noParent)
|
||||
{
|
||||
item[F("parentControl")] = String(parentControl);
|
||||
}
|
||||
|
||||
// special case for selects: to preselect an option, you have to add
|
||||
// "selected" to <option>
|
||||
if (ControlType::Option == type)
|
||||
{
|
||||
Control* ParentControl = ESPUI.getControlNoLock(parentControl);
|
||||
if (nullptr == ParentControl)
|
||||
{
|
||||
item[F("selected")] = emptyString;
|
||||
}
|
||||
else if (ParentControl->value == value)
|
||||
{
|
||||
item[F("selected")] = F("selected");
|
||||
}
|
||||
else
|
||||
{
|
||||
item[F("selected")] = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Control::MarshalErrorMessage(JsonObject & item)
|
||||
{
|
||||
item[F("id")] = id;
|
||||
item[F("type")] = uint32_t(ControlType::Label);
|
||||
item[F("label")] = ControlError.c_str();
|
||||
item[F("value")] = ControlError;
|
||||
item[F("visible")] = true;
|
||||
item[F("color")] = (int)ControlColor::Carrot;
|
||||
item[F("enabled")] = true;
|
||||
|
||||
if (parentControl != Control::noParent)
|
||||
{
|
||||
item[F("parentControl")] = String(parentControl);
|
||||
}
|
||||
}
|
||||
|
||||
void Control::onWsEvent(String & cmd, String& data)
|
||||
{
|
||||
do // once
|
||||
{
|
||||
// Serial.println(String(F("Control::onWsEvent")));
|
||||
SetControlChangedId(ESPUI.GetNextControlChangeId());
|
||||
|
||||
int arg = 0;
|
||||
|
||||
if (cmd.equals(F("bdown")))
|
||||
{
|
||||
arg = B_DOWN;
|
||||
}
|
||||
else if (cmd.equals(F("bup")))
|
||||
{
|
||||
arg = B_UP;
|
||||
}
|
||||
else if (cmd.equals(F("pfdown")))
|
||||
{
|
||||
arg = P_FOR_DOWN;
|
||||
}
|
||||
else if (cmd.equals(F("pfup")))
|
||||
{
|
||||
arg = P_FOR_UP;
|
||||
}
|
||||
else if (cmd.equals(F("pldown")))
|
||||
{
|
||||
arg = P_LEFT_DOWN;
|
||||
}
|
||||
else if (cmd.equals(F("plup")))
|
||||
{
|
||||
arg = P_LEFT_UP;
|
||||
}
|
||||
else if (cmd.equals(F("prdown")))
|
||||
{
|
||||
arg = P_RIGHT_DOWN;
|
||||
}
|
||||
else if (cmd.equals(F("prup")))
|
||||
{
|
||||
arg = P_RIGHT_UP;
|
||||
}
|
||||
else if (cmd.equals(F("pbdown")))
|
||||
{
|
||||
arg = P_BACK_DOWN;
|
||||
}
|
||||
else if (cmd.equals(F("pbup")))
|
||||
{
|
||||
arg = P_BACK_UP;
|
||||
}
|
||||
else if (cmd.equals(F("pcdown")))
|
||||
{
|
||||
arg = P_CENTER_DOWN;
|
||||
}
|
||||
else if (cmd.equals(F("pcup")))
|
||||
{
|
||||
arg = P_CENTER_UP;
|
||||
}
|
||||
else if (cmd.equals(F("sactive")))
|
||||
{
|
||||
if (auto_update_value)
|
||||
value = "1";
|
||||
arg = S_ACTIVE;
|
||||
}
|
||||
else if (cmd.equals(F("sinactive")))
|
||||
{
|
||||
if (auto_update_value)
|
||||
value = "0";
|
||||
arg = S_INACTIVE;
|
||||
}
|
||||
else if (cmd.equals(F("slvalue")))
|
||||
{
|
||||
if (auto_update_value)
|
||||
value = data;
|
||||
arg = SL_VALUE;
|
||||
}
|
||||
else if (cmd.equals(F("nvalue")))
|
||||
{
|
||||
if (auto_update_value)
|
||||
value = data;
|
||||
arg = N_VALUE;
|
||||
}
|
||||
else if (cmd.equals(F("tvalue")))
|
||||
{
|
||||
if (auto_update_value)
|
||||
value = data;
|
||||
arg = T_VALUE;
|
||||
}
|
||||
else if (cmd.equals(F("tabvalue")))
|
||||
{
|
||||
arg = 0;
|
||||
}
|
||||
else if (cmd.equals(F("svalue")))
|
||||
{
|
||||
if (auto_update_value)
|
||||
value = data;
|
||||
arg = S_VALUE;
|
||||
}
|
||||
else if (cmd.equals(F("time")))
|
||||
{
|
||||
if (auto_update_value)
|
||||
value = data;
|
||||
arg = TM_VALUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.println(F("Control::onWsEvent:Malformed message from the websocket"));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
if (!HasCallback())
|
||||
{
|
||||
#if defined(DEBUG_ESPUI)
|
||||
if (ESPUI.verbosity)
|
||||
{
|
||||
Serial.println(String(F("Control::onWsEvent:No callback found for ID ")) + String(id));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// Serial.println("Control::onWsEvent:Generating callback");
|
||||
SendCallback(arg);
|
||||
}
|
||||
|
||||
} while (false);
|
||||
}
|
||||
|
@ -1,126 +1,162 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <functional>
|
||||
|
||||
enum ControlType : uint8_t
|
||||
{
|
||||
// fixed Controls
|
||||
Title = 0,
|
||||
|
||||
// updatable Controls
|
||||
Pad,
|
||||
PadWithCenter,
|
||||
Button,
|
||||
Label,
|
||||
Switcher,
|
||||
Slider,
|
||||
Number,
|
||||
Text,
|
||||
Graph,
|
||||
GraphPoint,
|
||||
Tab,
|
||||
Select,
|
||||
Option,
|
||||
Min,
|
||||
Max,
|
||||
Step,
|
||||
Gauge,
|
||||
Accel,
|
||||
Separator,
|
||||
Time,
|
||||
|
||||
Fragment,
|
||||
Password = 99,
|
||||
UpdateOffset = 100,
|
||||
};
|
||||
|
||||
enum ControlColor : uint8_t
|
||||
{
|
||||
Turquoise,
|
||||
Emerald,
|
||||
Peterriver,
|
||||
Wetasphalt,
|
||||
Sunflower,
|
||||
Carrot,
|
||||
Alizarin,
|
||||
Dark,
|
||||
None = 0xFF
|
||||
};
|
||||
|
||||
class Control
|
||||
{
|
||||
public:
|
||||
ControlType type;
|
||||
uint16_t id; // just mirroring the id here for practical reasons
|
||||
const char* label;
|
||||
std::function<void(Control*, int)> callback;
|
||||
String value;
|
||||
ControlColor color;
|
||||
bool visible;
|
||||
bool wide;
|
||||
bool vertical;
|
||||
bool enabled;
|
||||
uint16_t parentControl;
|
||||
String panelStyle;
|
||||
String elementStyle;
|
||||
String inputType;
|
||||
Control* next;
|
||||
|
||||
static constexpr uint16_t noParent = 0xffff;
|
||||
|
||||
Control(ControlType type,
|
||||
const char* label,
|
||||
std::function<void(Control*, int)> callback,
|
||||
const String& value,
|
||||
ControlColor color,
|
||||
bool visible,
|
||||
uint16_t parentControl);
|
||||
|
||||
Control(const Control& Control);
|
||||
|
||||
void SendCallback(int type);
|
||||
bool HasCallback() { return (nullptr != callback); }
|
||||
void MarshalControl(ArduinoJson::JsonObject& item, bool refresh, uint32_t DataOffset);
|
||||
void MarshalErrorMessage(ArduinoJson::JsonObject& item);
|
||||
void DeleteControl();
|
||||
void onWsEvent(String& cmd, String& data);
|
||||
inline bool ToBeDeleted() { return _ToBeDeleted; }
|
||||
inline bool NeedsSync(uint32_t lastControlChangeID) {return (false == _ToBeDeleted) && (lastControlChangeID < ControlChangeID);}
|
||||
void SetControlChangedId(uint32_t value) {ControlChangeID = value;}
|
||||
|
||||
private:
|
||||
bool _ToBeDeleted = false;
|
||||
uint32_t ControlChangeID = 0;
|
||||
};
|
||||
|
||||
#define UI_TITLE ControlType::Title
|
||||
#define UI_LABEL ControlType::Label
|
||||
#define UI_BUTTON ControlType::Button
|
||||
#define UI_SWITCHER ControlType::Switcher
|
||||
#define UI_PAD ControlType::Pad
|
||||
#define UI_CPAD ControlType::Cpad
|
||||
#define UI_SLIDER ControlType::Slider
|
||||
#define UI_NUMBER ControlType::Number
|
||||
#define UI_TEXT_INPUT ControlType::Text
|
||||
#define UI_GRAPH ControlType::Graph
|
||||
#define UI_ADD_GRAPH_POINT ControlType::GraphPoint
|
||||
|
||||
#define UPDATE_LABEL ControlType::UpdateLabel
|
||||
#define UPDATE_SWITCHER ControlType::UpdateSwitcher
|
||||
#define UPDATE_SLIDER ControlType::UpdateSlider
|
||||
#define UPDATE_NUMBER ControlType::UpdateNumber
|
||||
#define UPDATE_TEXT_INPUT ControlType::UpdateText
|
||||
#define CLEAR_GRAPH ControlType::ClearGraph
|
||||
|
||||
// Colors
|
||||
#define COLOR_TURQUOISE ControlColor::Turquoise
|
||||
#define COLOR_EMERALD ControlColor::Emerald
|
||||
#define COLOR_PETERRIVER ControlColor::Peterriver
|
||||
#define COLOR_WETASPHALT ControlColor::Wetasphalt
|
||||
#define COLOR_SUNFLOWER ControlColor::Sunflower
|
||||
#define COLOR_CARROT ControlColor::Carrot
|
||||
#define COLOR_ALIZARIN ControlColor::Alizarin
|
||||
#define COLOR_DARK ControlColor::Dark
|
||||
#define COLOR_NONE ControlColor::None
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <functional>
|
||||
|
||||
enum ControlType : uint8_t
|
||||
{
|
||||
// fixed Controls
|
||||
Title = 0,
|
||||
|
||||
// updatable Controls
|
||||
Pad,
|
||||
PadWithCenter,
|
||||
Button,
|
||||
Label,
|
||||
Switcher,
|
||||
Slider,
|
||||
Number,
|
||||
Text,
|
||||
Graph,
|
||||
GraphPoint,
|
||||
Tab,
|
||||
Select,
|
||||
Option,
|
||||
Min,
|
||||
Max,
|
||||
Step,
|
||||
Gauge,
|
||||
Accel,
|
||||
Separator,
|
||||
Time,
|
||||
|
||||
Fragment,
|
||||
Password = 99,
|
||||
UpdateOffset = 100,
|
||||
};
|
||||
|
||||
enum ControlColor : uint8_t
|
||||
{
|
||||
Turquoise,
|
||||
Emerald,
|
||||
Peterriver,
|
||||
Wetasphalt,
|
||||
Sunflower,
|
||||
Carrot,
|
||||
Alizarin,
|
||||
Dark,
|
||||
None = 0xFF
|
||||
};
|
||||
|
||||
#define CTRL_OPT_ENABLED 0x01
|
||||
#define CTRL_OPT_VISIBLE 0x02
|
||||
#define CTRL_OPT_LABEL_IN_FLASH 0x04
|
||||
#define CTRL_OPT_AUTO_UPDATE_VALUE 0x08
|
||||
#define CTRL_OPT_WIDE 0x10
|
||||
#define CTRL_OPT_VERTICAL 0x20
|
||||
|
||||
class Control
|
||||
{
|
||||
public:
|
||||
static constexpr uint16_t noParent = 0xffff;
|
||||
|
||||
// Pointers
|
||||
union
|
||||
{
|
||||
const char* label_r;
|
||||
const __FlashStringHelper* label_f;
|
||||
};
|
||||
std::function<void(Control*, int)> callback;
|
||||
Control* next;
|
||||
|
||||
// Strings
|
||||
String value;
|
||||
String panelStyle;
|
||||
String elementStyle;
|
||||
String inputType;
|
||||
|
||||
//enums
|
||||
ControlType type;
|
||||
ControlColor color;
|
||||
|
||||
// uint16_t
|
||||
uint16_t id; // just mirroring the id here for practical reasons
|
||||
uint16_t parentControl;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint16_t enabled : 1 ;
|
||||
uint16_t visible : 1;
|
||||
uint16_t lablel_is_in_flash : 1;
|
||||
uint16_t auto_update_value : 1;
|
||||
uint16_t wide : 1;
|
||||
uint16_t vertical : 1;
|
||||
};
|
||||
uint16_t options;
|
||||
};
|
||||
|
||||
Control(ControlType type,
|
||||
const char* label,
|
||||
std::function<void(Control*, int)> callback,
|
||||
const String& value,
|
||||
ControlColor color,
|
||||
bool visible,
|
||||
uint16_t parentControl);
|
||||
|
||||
Control(ControlType type,
|
||||
const __FlashStringHelper* label,
|
||||
std::function<void(Control*, int)> callback,
|
||||
const String& value,
|
||||
ControlColor color,
|
||||
bool visible,
|
||||
uint16_t parentControl);
|
||||
|
||||
Control(const Control& Control);
|
||||
|
||||
void SendCallback(int type);
|
||||
bool HasCallback() { return (nullptr != callback); }
|
||||
void MarshalControl(ArduinoJson::JsonObject& item, bool refresh, uint32_t DataOffset);
|
||||
void MarshalErrorMessage(ArduinoJson::JsonObject& item);
|
||||
void DeleteControl();
|
||||
void onWsEvent(String& cmd, String& data);
|
||||
inline bool ToBeDeleted() { return _ToBeDeleted; }
|
||||
inline bool NeedsSync(uint32_t lastControlChangeID) {return (false == _ToBeDeleted) && (lastControlChangeID < ControlChangeID);}
|
||||
void SetControlChangedId(uint32_t value) {ControlChangeID = value;}
|
||||
|
||||
private:
|
||||
bool _ToBeDeleted = false;
|
||||
uint32_t ControlChangeID;
|
||||
};
|
||||
|
||||
#define UI_TITLE ControlType::Title
|
||||
#define UI_LABEL ControlType::Label
|
||||
#define UI_BUTTON ControlType::Button
|
||||
#define UI_SWITCHER ControlType::Switcher
|
||||
#define UI_PAD ControlType::Pad
|
||||
#define UI_CPAD ControlType::Cpad
|
||||
#define UI_SLIDER ControlType::Slider
|
||||
#define UI_NUMBER ControlType::Number
|
||||
#define UI_TEXT_INPUT ControlType::Text
|
||||
#define UI_GRAPH ControlType::Graph
|
||||
#define UI_ADD_GRAPH_POINT ControlType::GraphPoint
|
||||
|
||||
#define UPDATE_LABEL ControlType::UpdateLabel
|
||||
#define UPDATE_SWITCHER ControlType::UpdateSwitcher
|
||||
#define UPDATE_SLIDER ControlType::UpdateSlider
|
||||
#define UPDATE_NUMBER ControlType::UpdateNumber
|
||||
#define UPDATE_TEXT_INPUT ControlType::UpdateText
|
||||
#define CLEAR_GRAPH ControlType::ClearGraph
|
||||
|
||||
// Colors
|
||||
#define COLOR_TURQUOISE ControlColor::Turquoise
|
||||
#define COLOR_EMERALD ControlColor::Emerald
|
||||
#define COLOR_PETERRIVER ControlColor::Peterriver
|
||||
#define COLOR_WETASPHALT ControlColor::Wetasphalt
|
||||
#define COLOR_SUNFLOWER ControlColor::Sunflower
|
||||
#define COLOR_CARROT ControlColor::Carrot
|
||||
#define COLOR_ALIZARIN ControlColor::Alizarin
|
||||
#define COLOR_DARK ControlColor::Dark
|
||||
#define COLOR_NONE ControlColor::None
|
||||
|
File diff suppressed because one or more lines are too long
@ -1,19 +1,19 @@
|
||||
const char JS_GRAPH[] PROGMEM = R"=====(
|
||||
function lineGraph(parent,xAccessor,yAccessor){const width=620;const height=420;const gutter=40;const pixelsPerTick=30;function numericTransformer(dataMin,dataMax,pxMin,pxMax){var dataDiff=dataMax-dataMin,pxDiff=pxMax-pxMin,dataRatio=pxDiff/dataDiff,coordRatio=dataDiff/pxDiff;return{toCoord:function(data){return(data-dataMin)*dataRatio+pxMin;},toData:function(coord){return(coord-pxMin)*coordRatio+dataMin;}};}
|
||||
function axisRenderer(orientation,transform){var axisGroup=document.createElementNS("http://www.w3.org/2000/svg","g");var axisPath=document.createElementNS("http://www.w3.org/2000/svg","path");axisGroup.setAttribute("class",orientation+"-axis");var xMin=gutter;var xMax=width-gutter;var yMin=height-gutter;var yMax=gutter;if(orientation==="x"){axisPath.setAttribute("d","M "+xMin+" "+yMin+" L "+xMax+" "+yMin);for(var i=xMin;i<=xMax;i++){if((i-xMin)%(pixelsPerTick*3)===0&&i!==xMin){var text=document.createElementNS("http://www.w3.org/2000/svg","text");text.innerHTML=new Date(Math.floor(transform(i))).toLocaleTimeString();text.setAttribute("x",i);text.setAttribute("y",yMin);text.setAttribute("dy","1em");axisGroup.appendChild(text);}}}else{axisPath.setAttribute("d","M "+xMin+" "+yMin+" L "+xMin+" "+yMax);for(var i=yMax;i<=yMin;i++){if((i-yMin)%pixelsPerTick===0&&i!==yMin){var tickGroup=document.createElementNS("http://www.w3.org/2000/svg","g");var gridLine=document.createElementNS("http://www.w3.org/2000/svg","path");text=document.createElementNS("http://www.w3.org/2000/svg","text");text.innerHTML=Math.floor(transform(i));text.setAttribute("x",xMin);text.setAttribute("y",i);text.setAttribute("dx","-.5em");text.setAttribute("dy",".3em");gridLine.setAttribute("d","M "+xMin+" "+i+" L "+xMax+" "+i);tickGroup.appendChild(gridLine);tickGroup.appendChild(text);axisGroup.appendChild(tickGroup);}}}
|
||||
axisGroup.appendChild(axisPath);parent.appendChild(axisGroup);}
|
||||
function lineRenderer(xAccessor,yAccessor,xTransform,yTransform){var line=document.createElementNS("http://www.w3.org/2000/svg","path");xAccessor.reset();yAccessor.reset();if(!xAccessor.hasNext()||!yAccessor.hasNext()){return;}
|
||||
var pathString="M "+xTransform(xAccessor.next())+" "+yTransform(yAccessor.next());while(xAccessor.hasNext()&&yAccessor.hasNext()){pathString+=" L "+
|
||||
xTransform(xAccessor.next())+
|
||||
" "+
|
||||
yTransform(yAccessor.next());}
|
||||
line.setAttribute("class","series");line.setAttribute("d",pathString);parent.appendChild(line);}
|
||||
function pointRenderer(xAccessor,yAccessor,xTransform,yTransform){var pointGroup=document.createElementNS("http://www.w3.org/2000/svg","g");pointGroup.setAttribute("class","data-points");xAccessor.reset();yAccessor.reset();if(!xAccessor.hasNext()||!yAccessor.hasNext()){return;}
|
||||
while(xAccessor.hasNext()&&yAccessor.hasNext()){var xDataValue=xAccessor.next();var x=xTransform(xDataValue);var yDataValue=yAccessor.next();var y=yTransform(yDataValue);var circle=document.createElementNS("http://www.w3.org/2000/svg","circle");circle.setAttribute("cx",x);circle.setAttribute("cy",y);circle.setAttribute("r","4");var text=document.createElementNS("http://www.w3.org/2000/svg","text");text.innerHTML=Math.floor(xDataValue)+" / "+Math.floor(yDataValue);text.setAttribute("x",x);text.setAttribute("y",y);text.setAttribute("dx","1em");text.setAttribute("dy","-.7em");pointGroup.appendChild(circle);pointGroup.appendChild(text);}
|
||||
parent.appendChild(pointGroup);}
|
||||
xTransform=numericTransformer(xAccessor.min(),xAccessor.max(),0+gutter,width-gutter);yTransform=numericTransformer(yAccessor.min(),yAccessor.max(),height-gutter,0+gutter);axisRenderer("x",xTransform.toData);axisRenderer("y",yTransform.toData);lineRenderer(xAccessor,yAccessor,xTransform.toCoord,yTransform.toCoord);pointRenderer(xAccessor,yAccessor,xTransform.toCoord,yTransform.toCoord);}
|
||||
function renderGraphSvg(dataArray,renderId){var figure=document.getElementById(renderId);while(figure.hasChildNodes()){figure.removeChild(figure.lastChild);}
|
||||
var svg=document.createElementNS("http://www.w3.org/2000/svg","svg");svg.setAttribute("viewBox","0 0 640 440");svg.setAttribute("preserveAspectRatio","xMidYMid meet");lineGraph(svg,(function(data,min,max){var i=0;return{hasNext:function(){return i<data.length;},next:function(){return data[i++].x;},reset:function(){i=0;},min:function(){return min;},max:function(){return max;}};})(dataArray,Math.min.apply(Math,dataArray.map(function(o){return o.x;})),Math.max.apply(Math,dataArray.map(function(o){return o.x;}))),(function(data,min,max){var i=0;return{hasNext:function(){return i<data.length;},next:function(){return data[i++].y;},reset:function(){i=0;},min:function(){return min;},max:function(){return max;}};})(dataArray,Math.min.apply(Math,dataArray.map(function(o){return o.y;})),Math.max.apply(Math,dataArray.map(function(o){return o.y;}))));figure.appendChild(svg);}
|
||||
)=====";
|
||||
|
||||
const uint8_t JS_GRAPH_GZIP[1280] PROGMEM = { 31,139,8,0,22,146,123,99,2,255,205,87,95,111,219,54,16,127,247,167,112,4,52,16,99,89,86,27,175,3,170,240,33,109,135,174,64,18,20,77,48,96,24,246,192,73,180,76,76,150,4,138,182,69,184,254,238,59,146,162,36,59,82,134,58,41,182,135,56,34,239,47,239,126,119,71,46,214,89,36,88,158,141,83,150,209,79,156,20,75,183,32,156,102,194,171,174,163,136,150,101,206,61,105,191,208,46,202,179,82,140,183,44,22,75,252,246,77,16,154,245,146,178,100,41,240,188,217,72,214,66,80,142,231,118,93,176,138,166,229,23,202,31,88,244,55,190,12,194,133,53,155,173,87,148,179,232,129,147,172,92,228,28,22,110,76,4,185,101,153,167,255,147,202,43,42,181,130,95,82,161,221,134,240,177,34,124,100,139,5,174,57,166,86,162,168,244,182,102,157,26,49,69,250,74,192,20,54,196,153,21,246,162,60,231,177,33,217,189,153,225,9,57,21,107,158,237,68,254,65,241,188,179,206,106,207,208,206,80,245,194,90,70,23,141,157,137,182,27,238,61,145,127,132,189,86,88,219,107,164,245,202,248,136,46,90,87,38,181,194,112,191,15,247,163,38,74,164,98,229,87,154,197,148,67,124,114,206,32,63,138,59,243,132,141,155,137,140,226,251,196,243,117,129,227,60,130,200,102,194,143,56,37,130,254,146,82,181,186,187,119,157,165,16,197,187,217,108,187,221,250,219,75,63,231,201,236,77,16,4,179,114,147,56,158,147,56,40,180,138,190,16,72,242,137,122,10,144,5,85,141,63,126,73,197,181,16,156,253,181,22,212,117,162,148,148,165,227,117,78,50,113,166,138,185,54,175,194,130,13,136,234,53,169,176,70,221,180,179,43,21,151,193,222,225,54,48,215,107,182,232,134,11,99,236,84,14,218,217,211,29,121,21,131,227,183,99,103,162,172,79,28,248,144,230,227,70,239,145,170,217,67,33,132,220,85,182,24,214,217,102,87,88,49,132,108,50,65,59,176,233,178,169,206,236,43,247,0,249,23,151,8,92,8,206,207,217,25,214,130,38,107,130,86,226,212,64,43,89,8,154,250,231,179,44,163,252,215,135,219,27,156,209,237,24,208,71,221,91,117,202,69,10,248,114,27,168,184,12,33,228,139,252,38,143,72,74,31,216,138,222,67,8,178,196,173,213,28,6,165,114,60,214,75,144,142,103,98,209,67,139,129,232,188,166,171,3,8,144,162,0,8,127,88,178,52,118,149,12,2,144,239,33,56,244,180,124,52,123,208,22,58,249,144,58,15,87,88,234,188,180,249,208,190,190,58,108,68,77,46,100,155,11,216,127,145,10,74,56,139,111,160,167,62,179,130,94,30,27,67,144,24,72,126,53,148,99,57,4,140,24,164,156,169,255,147,78,255,16,56,252,75,77,182,81,250,183,204,179,227,50,84,166,109,170,14,144,101,53,14,209,13,242,6,80,105,37,52,52,71,253,76,22,172,40,52,131,242,17,209,106,104,219,183,154,173,77,251,238,153,171,94,213,204,63,79,62,28,182,244,244,249,24,106,44,250,156,66,156,161,206,229,163,29,40,146,179,150,111,73,202,59,136,147,139,190,125,59,147,143,119,237,20,131,51,42,23,149,25,211,66,176,201,90,115,132,246,176,126,102,36,77,205,182,12,242,152,33,220,66,32,169,219,227,203,249,121,175,43,173,245,9,54,32,25,61,233,192,72,121,48,122,210,133,253,40,125,140,201,122,102,57,37,220,87,168,26,84,105,47,110,91,119,122,1,146,106,104,118,176,81,228,44,19,167,130,67,11,63,187,93,181,90,6,142,172,175,58,154,171,252,193,112,250,222,228,235,203,129,186,103,253,70,210,53,197,199,217,54,151,7,220,197,67,195,108,136,178,21,150,125,194,18,119,145,114,36,28,49,30,165,39,87,167,145,134,128,154,143,227,216,171,222,59,68,83,179,119,128,198,65,243,188,158,65,63,116,120,116,34,9,69,61,131,162,234,16,187,145,26,152,43,131,151,138,225,161,242,250,201,145,50,245,127,214,244,14,156,187,149,103,162,53,72,174,111,36,163,158,154,109,37,20,67,11,38,220,243,120,105,17,184,98,153,139,188,206,154,84,176,14,38,230,102,234,117,111,179,80,65,79,42,149,71,74,229,145,210,131,59,112,99,194,76,185,166,181,232,160,55,90,125,243,60,57,230,81,241,127,204,243,29,243,203,175,31,77,135,106,244,86,29,250,151,80,212,233,159,92,171,211,47,215,251,77,162,95,101,215,156,19,233,25,194,231,216,52,137,5,75,214,188,83,170,9,21,117,37,188,151,159,99,183,97,174,199,143,97,87,157,70,67,224,46,143,105,169,250,77,189,207,233,42,223,80,131,142,122,11,90,165,208,27,168,158,138,80,70,167,214,158,250,69,33,252,30,193,124,195,232,246,125,174,42,33,24,7,227,183,243,96,60,159,7,189,156,133,106,196,124,67,175,203,130,70,66,63,45,65,10,174,83,241,239,240,55,94,81,42,234,9,102,222,252,160,193,115,15,222,185,30,64,205,91,217,39,55,195,129,125,21,215,221,183,125,216,218,246,61,102,87,74,208,79,105,150,136,37,188,128,179,126,54,197,244,7,220,204,255,244,43,96,210,19,163,203,165,76,237,149,245,30,209,149,126,89,131,87,125,52,184,247,171,87,51,234,96,64,119,36,16,82,229,156,74,253,26,242,26,42,20,79,209,158,57,111,20,229,202,47,132,106,97,82,157,34,140,254,131,104,202,255,105,52,229,115,162,169,133,225,74,86,87,89,183,45,3,102,161,214,254,1,223,145,42,131,193,18,0,0 };
|
||||
const char JS_GRAPH[] PROGMEM = R"=====(
|
||||
function lineGraph(parent,xAccessor,yAccessor){const width=620;const height=420;const gutter=40;const pixelsPerTick=30;function numericTransformer(dataMin,dataMax,pxMin,pxMax){var dataDiff=dataMax-dataMin,pxDiff=pxMax-pxMin,dataRatio=pxDiff/dataDiff,coordRatio=dataDiff/pxDiff;return{toCoord:function(data){return(data-dataMin)*dataRatio+pxMin;},toData:function(coord){return(coord-pxMin)*coordRatio+dataMin;}};}
|
||||
function axisRenderer(orientation,transform){var axisGroup=document.createElementNS("http://www.w3.org/2000/svg","g");var axisPath=document.createElementNS("http://www.w3.org/2000/svg","path");axisGroup.setAttribute("class",orientation+"-axis");var xMin=gutter;var xMax=width-gutter;var yMin=height-gutter;var yMax=gutter;if(orientation==="x"){axisPath.setAttribute("d","M "+xMin+" "+yMin+" L "+xMax+" "+yMin);for(var i=xMin;i<=xMax;i++){if((i-xMin)%(pixelsPerTick*3)===0&&i!==xMin){var text=document.createElementNS("http://www.w3.org/2000/svg","text");text.innerHTML=new Date(Math.floor(transform(i))).toLocaleTimeString();text.setAttribute("x",i);text.setAttribute("y",yMin);text.setAttribute("dy","1em");axisGroup.appendChild(text);}}}else{axisPath.setAttribute("d","M "+xMin+" "+yMin+" L "+xMin+" "+yMax);for(var i=yMax;i<=yMin;i++){if((i-yMin)%pixelsPerTick===0&&i!==yMin){var tickGroup=document.createElementNS("http://www.w3.org/2000/svg","g");var gridLine=document.createElementNS("http://www.w3.org/2000/svg","path");text=document.createElementNS("http://www.w3.org/2000/svg","text");text.innerHTML=Math.floor(transform(i));text.setAttribute("x",xMin);text.setAttribute("y",i);text.setAttribute("dx","-.5em");text.setAttribute("dy",".3em");gridLine.setAttribute("d","M "+xMin+" "+i+" L "+xMax+" "+i);tickGroup.appendChild(gridLine);tickGroup.appendChild(text);axisGroup.appendChild(tickGroup);}}}
|
||||
axisGroup.appendChild(axisPath);parent.appendChild(axisGroup);}
|
||||
function lineRenderer(xAccessor,yAccessor,xTransform,yTransform){var line=document.createElementNS("http://www.w3.org/2000/svg","path");xAccessor.reset();yAccessor.reset();if(!xAccessor.hasNext()||!yAccessor.hasNext()){return;}
|
||||
var pathString="M "+xTransform(xAccessor.next())+" "+yTransform(yAccessor.next());while(xAccessor.hasNext()&&yAccessor.hasNext()){pathString+=" L "+
|
||||
xTransform(xAccessor.next())+
|
||||
" "+
|
||||
yTransform(yAccessor.next());}
|
||||
line.setAttribute("class","series");line.setAttribute("d",pathString);parent.appendChild(line);}
|
||||
function pointRenderer(xAccessor,yAccessor,xTransform,yTransform){var pointGroup=document.createElementNS("http://www.w3.org/2000/svg","g");pointGroup.setAttribute("class","data-points");xAccessor.reset();yAccessor.reset();if(!xAccessor.hasNext()||!yAccessor.hasNext()){return;}
|
||||
while(xAccessor.hasNext()&&yAccessor.hasNext()){var xDataValue=xAccessor.next();var x=xTransform(xDataValue);var yDataValue=yAccessor.next();var y=yTransform(yDataValue);var circle=document.createElementNS("http://www.w3.org/2000/svg","circle");circle.setAttribute("cx",x);circle.setAttribute("cy",y);circle.setAttribute("r","4");var text=document.createElementNS("http://www.w3.org/2000/svg","text");text.innerHTML=Math.floor(xDataValue)+" / "+Math.floor(yDataValue);text.setAttribute("x",x);text.setAttribute("y",y);text.setAttribute("dx","1em");text.setAttribute("dy","-.7em");pointGroup.appendChild(circle);pointGroup.appendChild(text);}
|
||||
parent.appendChild(pointGroup);}
|
||||
xTransform=numericTransformer(xAccessor.min(),xAccessor.max(),0+gutter,width-gutter);yTransform=numericTransformer(yAccessor.min(),yAccessor.max(),height-gutter,0+gutter);axisRenderer("x",xTransform.toData);axisRenderer("y",yTransform.toData);lineRenderer(xAccessor,yAccessor,xTransform.toCoord,yTransform.toCoord);pointRenderer(xAccessor,yAccessor,xTransform.toCoord,yTransform.toCoord);}
|
||||
function renderGraphSvg(dataArray,renderId){var figure=document.getElementById(renderId);while(figure.hasChildNodes()){figure.removeChild(figure.lastChild);}
|
||||
var svg=document.createElementNS("http://www.w3.org/2000/svg","svg");svg.setAttribute("viewBox","0 0 640 440");svg.setAttribute("preserveAspectRatio","xMidYMid meet");lineGraph(svg,(function(data,min,max){var i=0;return{hasNext:function(){return i<data.length;},next:function(){return data[i++].x;},reset:function(){i=0;},min:function(){return min;},max:function(){return max;}};})(dataArray,Math.min.apply(Math,dataArray.map(function(o){return o.x;})),Math.max.apply(Math,dataArray.map(function(o){return o.x;}))),(function(data,min,max){var i=0;return{hasNext:function(){return i<data.length;},next:function(){return data[i++].y;},reset:function(){i=0;},min:function(){return min;},max:function(){return max;}};})(dataArray,Math.min.apply(Math,dataArray.map(function(o){return o.y;})),Math.max.apply(Math,dataArray.map(function(o){return o.y;}))));figure.appendChild(svg);}
|
||||
)=====";
|
||||
|
||||
const uint8_t JS_GRAPH_GZIP[1280] PROGMEM = { 31,139,8,0,19,56,151,101,2,255,205,87,95,111,219,54,16,127,247,167,112,4,52,16,99,89,86,27,175,3,170,240,33,109,135,174,64,18,20,77,48,96,24,246,192,73,180,76,76,150,4,138,182,69,184,254,238,59,146,162,36,59,82,134,58,41,182,135,56,34,239,47,239,126,119,71,46,214,89,36,88,158,141,83,150,209,79,156,20,75,183,32,156,102,194,171,174,163,136,150,101,206,61,105,191,208,46,202,179,82,140,183,44,22,75,252,246,77,16,154,245,146,178,100,41,240,188,217,72,214,66,80,142,231,118,93,176,138,166,229,23,202,31,88,244,55,190,12,194,133,53,155,173,87,148,179,232,129,147,172,92,228,28,22,110,76,4,185,101,153,167,255,147,202,43,42,181,130,95,82,161,221,134,240,177,34,124,100,139,5,174,57,166,86,162,168,244,182,102,157,26,49,69,250,74,192,20,54,196,153,21,246,162,60,231,177,33,217,189,153,225,9,57,21,107,158,237,68,254,65,241,188,179,206,106,207,208,206,80,245,194,90,70,23,141,157,137,182,27,238,61,145,127,132,189,86,88,219,107,164,245,202,248,136,46,90,87,38,181,194,112,191,15,247,163,38,74,164,98,229,87,154,197,148,67,124,114,206,32,63,138,59,243,132,141,155,137,140,226,251,196,243,117,129,227,60,130,200,102,194,143,56,37,130,254,146,82,181,186,187,119,157,165,16,197,187,217,108,187,221,250,219,75,63,231,201,236,77,16,4,179,114,147,56,158,147,56,40,180,138,190,16,72,242,137,122,10,144,5,85,141,63,126,73,197,181,16,156,253,181,22,212,117,162,148,148,165,227,117,78,50,113,166,138,185,54,175,194,130,13,136,234,53,169,176,70,221,180,179,43,21,151,193,222,225,54,48,215,107,182,232,134,11,99,236,84,14,218,217,211,29,121,21,131,227,183,99,103,162,172,79,28,248,144,230,227,70,239,145,170,217,67,33,132,220,85,182,24,214,217,102,87,88,49,132,108,50,65,59,176,233,178,169,206,236,43,247,0,249,23,151,8,92,8,206,207,217,25,214,130,38,107,130,86,226,212,64,43,89,8,154,250,231,179,44,163,252,215,135,219,27,156,209,237,24,208,71,221,91,117,202,69,10,248,114,27,168,184,12,33,228,139,252,38,143,72,74,31,216,138,222,67,8,178,196,173,213,28,6,165,114,60,214,75,144,142,103,98,209,67,139,129,232,188,166,171,3,8,144,162,0,8,127,88,178,52,118,149,12,2,144,239,33,56,244,180,124,52,123,208,22,58,249,144,58,15,87,88,234,188,180,249,208,190,190,58,108,68,77,46,100,155,11,216,127,145,10,74,56,139,111,160,167,62,179,130,94,30,27,67,144,24,72,126,53,148,99,57,4,140,24,164,156,169,255,147,78,255,16,56,252,75,77,182,81,250,183,204,179,227,50,84,166,109,170,14,144,101,53,14,209,13,242,6,80,105,37,52,52,71,253,76,22,172,40,52,131,242,17,209,106,104,219,183,154,173,77,251,238,153,171,94,213,204,63,79,62,28,182,244,244,249,24,106,44,250,156,66,156,161,206,229,163,29,40,146,179,150,111,73,202,59,136,147,139,190,125,59,147,143,119,237,20,131,51,42,23,149,25,211,66,176,201,90,115,132,246,176,126,102,36,77,205,182,12,242,152,33,220,66,32,169,219,227,203,249,121,175,43,173,245,9,54,32,25,61,233,192,72,121,48,122,210,133,253,40,125,140,201,122,102,57,37,220,87,168,26,84,105,47,110,91,119,122,1,146,106,104,118,176,81,228,44,19,167,130,67,11,63,187,93,181,90,6,142,172,175,58,154,171,252,193,112,250,222,228,235,203,129,186,103,253,70,210,53,197,199,217,54,151,7,220,197,67,195,108,136,178,21,150,125,194,18,119,145,114,36,28,49,30,165,39,87,167,145,134,128,154,143,227,216,171,222,59,68,83,179,119,128,198,65,243,188,158,65,63,116,120,116,34,9,69,61,131,162,234,16,187,145,26,152,43,131,151,138,225,161,242,250,201,145,50,245,127,214,244,14,156,187,149,103,162,53,72,174,111,36,163,158,154,109,37,20,67,11,38,220,243,120,105,17,184,98,153,139,188,206,154,84,176,14,38,230,102,234,117,111,179,80,65,79,42,149,71,74,229,145,210,131,59,112,99,194,76,185,166,181,232,160,55,90,125,243,60,57,230,81,241,127,204,243,29,243,203,175,31,77,135,106,244,86,29,250,151,80,212,233,159,92,171,211,47,215,251,77,162,95,101,215,156,19,233,25,194,231,216,52,137,5,75,214,188,83,170,9,21,117,37,188,151,159,99,183,97,174,199,143,97,87,157,70,67,224,46,143,105,169,250,77,189,207,233,42,223,80,131,142,122,11,90,165,208,27,168,158,138,80,70,167,214,158,250,69,33,252,30,193,124,195,232,246,125,174,42,33,24,7,227,183,243,96,60,159,7,189,156,133,106,196,124,67,175,203,130,70,66,63,45,65,10,174,83,241,239,240,55,94,81,42,234,9,102,222,252,160,193,115,15,222,185,30,64,205,91,217,39,55,195,129,125,21,215,221,183,125,216,218,246,61,102,87,74,208,79,105,150,136,37,188,128,179,126,54,197,244,7,220,204,255,244,43,96,210,19,163,203,165,76,237,149,245,30,209,149,126,89,131,87,125,52,184,247,171,87,51,234,96,64,119,36,16,82,229,156,74,253,26,242,26,42,20,79,209,158,57,111,20,229,202,47,132,106,97,82,157,34,140,254,131,104,202,255,105,52,229,115,162,169,133,225,74,86,87,89,183,45,3,102,161,214,254,1,223,145,42,131,193,18,0,0 };
|
||||
|
@ -1,27 +1,5 @@
|
||||
// Old PNG File
|
||||
//const char HTML_INDEX[] PROGMEM = R"=====(
|
||||
//<!DOCTYPE html><html> <head><meta charset=utf-8><title>Control</title><meta name=viewport content="width=device-width, initial-scale=1"><link rel="shortcut icon" href=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAPFBMVEUAAACA1VWR21qQ2liR3FqR3FqS3VuR3VqR3VuR3VqO21mS21uS3FqS3FqS21uJ2GKQ21qR3FuR3FoAAAB/3Gu7AAAAEnRSTlMABoA3kPBwz8i5Kzioxg4NVcU3uEJHAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB+EFEhcEM+HpYwQAAABYSURBVBjThY/JDsAgCESt4lpX/v9jLQZJ6qF9t3khAyj1xXUKbQ4BVowDwqOYgExkkW4iY6lPaF06RqM8YItOuRbMaz6xjbsusDAW/drplBg47jP696cXE8bPA1eUDeK2AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTA1LTE4VDIzOjA0OjUxKzAyOjAwxE59ewAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNy0wNS0xOFQyMzowNDo1MSswMjowMLUTxccAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC><link rel=stylesheet href=/css/normalize.css><link rel=stylesheet href=/css/style.css><script src=/js/zepto.min.js></script><script src=/js/slider.js></script><script src=/js/graph.js></script><script src=/js/controls.js></script><script src=/js/tabbedcontent.js></script></head> <body onload=javascript:start();> <div> <h4> <div id=mainHeader>Control</div> <span id=conStatus class=label>Offline</span> </h4> </div> <hr> <div class=container> <div id=row class="row u-full-width"></div> <ul id=tabsnav class="navigation navigation-tabs u-full-width"></ul> <div id=tabscontent class="tabscontent u-full-width"></div> </div> </body> </html>
|
||||
//)=====";
|
||||
|
||||
// SVG Water Drop Icon
|
||||
//const char HTML_INDEX[] PROGMEM = R"=====(
|
||||
//<!DOCTYPE html><html> <head><meta charset=utf-8><title>Control</title><meta name=viewport content="width=device-width, initial-scale=1"><link rel="shortcut icon" href="data:image/svg+xml,%3Csvg data-name='Layer 1' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M504.08 256C504.08 119 393 7.92 256 7.92S7.92 119 7.92 256 119 504.08 256 504.08 504.08 393 504.08 256z' style='fill:%23009040'/%3E%3Cpath d='M289.15 157.48A306.25 306.25 0 0 1 256 84.69a306.22 306.22 0 0 1-33.14 72.8c-28.24 56.86-73.39 86.85-73.39 158.38 0 61.55 45 111.44 106.53 111.44 61.55 0 106.53-49.89 106.53-111.44.01-71.54-45.14-101.52-73.38-158.39z' style='fill:%2398c8f0'/%3E%3Cpath d='M289.15 157.48A306.25 306.25 0 0 1 256 84.69s-61.57 342.62 0 342.62c61.55 0 106.53-49.89 106.53-111.44.01-71.54-45.14-101.52-73.38-158.39z' style='fill:%23b0e0ff'/%3E%3Cpath d='M262.08 409.12c48.17 0 83.38-39 83.38-87.22.01-55.99-131.55 87.22-83.38 87.22z' style='fill:%23ffffff'/%3E%3C/svg%3E"><link rel=stylesheet href=/css/normalize.css><link rel=stylesheet href=/css/style.css><script src=/js/zepto.min.js></script><script src=/js/slider.js></script><script src=/js/graph.js></script><script src=/js/controls.js></script><script src=/js/tabbedcontent.js></script></head> <body onload=javascript:start();> <div> <h4> <div id=mainHeader>Control</div> <span id=conStatus class=label>Offline</span> </h4> </div> <hr> <div class=container> <div id=row class="row u-full-width"></div> <ul id=tabsnav class="navigation navigation-tabs u-full-width"></ul> <div id=tabscontent class="tabscontent u-full-width"></div> </div> </body> </html>
|
||||
//)=====";
|
||||
|
||||
// Apple icon only
|
||||
//const char HTML_INDEX[] PROGMEM = R"=====(
|
||||
//<!DOCTYPE html><html> <head><meta charset=utf-8><title>Control</title><meta name=viewport content="width=device-width, initial-scale=1"><link rel="apple-touch-icon" href=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALQAAAC0AQMAAAAHA5RxAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsIAAA7CARUoSoAAAAAGUExURYi/Sv///zEELvQAAAFGSURBVFjD7dUxbsUgEIRhLAqXPoKPskczRyNKkTJX4AiUFAhHr4g0kfZXslJKU36VwbOz6XZPT48//jqf4B/g7+Bv4JX8AjfwE/wA38Ez+AaeyC9wAz/BD/AdPINv4In8AjfwE/z44S19nx08g2/gifwCN/AT/ADfwTP4Bp7Ir3/y4Pfk4H2P4Hta8H8F85D/lDfK5+95tuC8BOdR59f8eV/m98M0v0+G+f3Tze+rZn6/VfP7sJjfn8ncvl3q0s9TXfp8qEv/d3XZF01d9ksV131UxHV/JXHZd0td9uNUl306wDt4A6/gBTz5vnTgxCf4AO/gDbyCF/Dk+wKf4AO8g7d/8h78nhm8L70PvmcN/q8ezAPlh/JG+cQ81+C89OA80vwu8Ju8gFfwBt7BB/gEX+A3eQGv4A28gw/wCb7Ab/L78cdf/gVoGRZWiw+tcgAAAABJRU5ErkJggg==><link rel=stylesheet href=/css/normalize.css><link rel=stylesheet href=/css/style.css><script src=/js/zepto.min.js></script><script src=/js/slider.js></script><script src=/js/graph.js></script><script src=/js/controls.js></script><script src=/js/tabbedcontent.js></script></head> <body onload=javascript:start();> <div> <h4> <div id=mainHeader>Control</div> <span id=conStatus class=label>Offline</span> </h4> </div> <hr> <div class=container> <div id=row class="row u-full-width"></div> <ul id=tabsnav class="navigation navigation-tabs u-full-width"></ul> <div id=tabscontent class="tabscontent u-full-width"></div> </div> </body> </html>
|
||||
//)=====";
|
||||
|
||||
// SVG Logo Only
|
||||
//const char HTML_INDEX[] PROGMEM = R"=====(
|
||||
//<!DOCTYPE html><html> <head><meta charset=utf-8><title>Control</title><meta name=viewport content="width=device-width, initial-scale=1"><link rel="shortcut icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 180 180'%3E%3Cpath d='M74 46v28h55v27l40-40l-40-40v27zM104 100v28h-55v27l-40-40l40-40v27z' fill='%2388BF4A' /%3E%3C/svg%3E"><link rel=stylesheet href=/css/normalize.css><link rel=stylesheet href=/css/style.css><script src=/js/zepto.min.js></script><script src=/js/slider.js></script><script src=/js/graph.js></script><script src=/js/controls.js></script><script src=/js/tabbedcontent.js></script></head> <body onload=javascript:start();> <div> <h4> <div id=mainHeader>Control</div> <span id=conStatus class=label>Offline</span> </h4> </div> <hr> <div class=container> <div id=row class="row u-full-width"></div> <ul id=tabsnav class="navigation navigation-tabs u-full-width"></ul> <div id=tabscontent class="tabscontent u-full-width"></div> </div> </body> </html>
|
||||
//)=====";
|
||||
|
||||
// SVG Logo & Apple icon
|
||||
const char HTML_INDEX[] PROGMEM = R"=====(
|
||||
<!DOCTYPE html><html><head><meta charset=utf-8><title>Control</title><meta name=viewport content="width=device-width, initial-scale=1"><link rel="shortcut icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 180 180'%3E%3Cpath d='M74 46v28h55v27l40-40l-40-40v27zM104 100v28h-55v27l-40-40l40-40v27z' fill='%2388BF4A' /%3E%3C/svg%3E"><link rel="apple-touch-icon" href=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALQAAAC0AQMAAAAHA5RxAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsIAAA7CARUoSoAAAAAGUExURYi/Sv///zEELvQAAAFGSURBVFjD7dUxbsUgEIRhLAqXPoKPskczRyNKkTJX4AiUFAhHr4g0kfZXslJKU36VwbOz6XZPT48//jqf4B/g7+Bv4JX8AjfwE/wA38Ez+AaeyC9wAz/BD/AdPINv4In8AjfwE/z44S19nx08g2/gifwCN/AT/ADfwTP4Bp7Ir3/y4Pfk4H2P4Hta8H8F85D/lDfK5+95tuC8BOdR59f8eV/m98M0v0+G+f3Tze+rZn6/VfP7sJjfn8ncvl3q0s9TXfp8qEv/d3XZF01d9ksV131UxHV/JXHZd0td9uNUl306wDt4A6/gBTz5vnTgxCf4AO/gDbyCF/Dk+wKf4AO8g7d/8h78nhm8L70PvmcN/q8ezAPlh/JG+cQ81+C89OA80vwu8Ju8gFfwBt7BB/gEX+A3eQGv4A28gw/wCb7Ab/L78cdf/gVoGRZWiw+tcgAAAABJRU5ErkJggg==><link rel=stylesheet href=/css/normalize.css><link rel=stylesheet href=/css/style.css><script src=/js/zepto.min.js></script><script src=/js/slider.js></script><script src=/js/graph.js></script><script src=/js/controls.js></script><script src=/js/tabbedcontent.js></script></head><body onload=javascript:start();><div><h4><div id=mainHeader>Control</div> <span id=conStatus class=label>Offline</span></h4></div><hr><div class=container><div id=row class="row u-full-width"></div><ul id=tabsnav class="navigation navigation-tabs u-full-width"></ul><div id=tabscontent class="tabscontent u-full-width"></div></div></body></html>
|
||||
<!DOCTYPE html><html> <head><meta charset=utf-8><title>Control</title><meta name=viewport content="width=device-width, initial-scale=1"><link rel="shortcut icon" href=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAPFBMVEUAAACA1VWR21qQ2liR3FqR3FqS3VuR3VqR3VuR3VqO21mS21uS3FqS3FqS21uJ2GKQ21qR3FuR3FoAAAB/3Gu7AAAAEnRSTlMABoA3kPBwz8i5Kzioxg4NVcU3uEJHAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB+EFEhcEM+HpYwQAAABYSURBVBjThY/JDsAgCESt4lpX/v9jLQZJ6qF9t3khAyj1xXUKbQ4BVowDwqOYgExkkW4iY6lPaF06RqM8YItOuRbMaz6xjbsusDAW/drplBg47jP696cXE8bPA1eUDeK2AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTA1LTE4VDIzOjA0OjUxKzAyOjAwxE59ewAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNy0wNS0xOFQyMzowNDo1MSswMjowMLUTxccAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC><link rel=stylesheet href=/css/normalize.css><link rel=stylesheet href=/css/style.css><script src=/js/zepto.min.js></script><script src=/js/slider.js></script><script src=/js/graph.js></script><script src=/js/controls.js></script><script src=/js/tabbedcontent.js></script></head> <body onload=javascript:start();> <div> <h4> <div id=mainHeader>Control</div> <span id=conStatus class=label>Offline</span> </h4> </div> <hr> <div class=container> <div id=row class="row u-full-width"></div> <ul id=tabsnav class="navigation navigation-tabs u-full-width"></ul> <div id=tabscontent class="tabscontent u-full-width"></div> </div> </body> </html>
|
||||
)=====";
|
||||
|
||||
|
||||
const uint8_t HTML_INDEX_GZIP[916] PROGMEM = { 31,139,8,0,210,8,51,99,2,255,133,148,235,115,162,58,20,192,255,21,174,159,238,157,221,22,95,181,237,174,56,19,20,108,85,68,64,240,241,45,64,42,193,240,40,9,162,254,245,155,128,157,238,157,189,211,235,12,201,201,57,191,243,200,17,206,240,175,137,57,94,239,86,154,20,177,132,140,134,245,42,13,35,4,195,209,48,65,12,74,65,4,11,138,152,82,178,183,187,167,209,144,97,70,208,104,156,165,172,200,200,80,110,142,13,153,194,4,41,39,140,170,60,43,152,20,112,4,165,76,105,85,56,100,145,18,162,19,14,208,93,125,248,46,225,20,51,12,201,29,13,32,65,74,167,53,26,18,156,30,165,2,17,165,69,35,238,30,148,76,194,60,68,75,138,10,244,166,132,144,193,31,56,129,7,36,231,233,225,167,15,41,26,244,191,99,79,53,237,170,61,159,30,50,192,127,75,199,141,52,247,192,37,85,28,129,53,6,134,216,179,133,245,188,22,130,58,13,213,181,171,1,176,152,174,198,242,57,82,45,174,28,171,177,163,207,150,220,58,152,113,223,195,43,87,174,68,188,49,24,240,53,20,158,102,46,162,14,18,190,232,189,113,80,18,237,73,196,91,233,170,225,105,110,205,118,188,141,221,237,188,91,93,130,237,158,254,46,30,167,231,149,118,207,227,114,179,155,221,78,226,116,59,165,83,219,248,195,229,89,119,58,183,184,31,231,57,163,139,188,170,220,155,150,143,34,190,150,218,206,154,24,64,205,64,239,184,82,171,235,19,126,152,95,113,118,62,244,151,94,224,246,74,109,246,82,223,116,51,91,216,109,11,96,224,134,78,173,32,149,163,147,171,232,73,167,2,96,18,6,170,133,177,143,106,91,216,118,220,142,174,126,211,116,45,10,52,227,219,75,190,171,68,35,212,157,227,218,170,167,198,235,104,39,207,38,20,28,198,154,195,250,36,223,202,167,231,120,97,237,103,131,119,253,153,245,142,17,184,196,157,243,214,157,251,86,95,245,178,106,82,189,155,187,131,118,62,30,55,125,188,27,144,21,212,219,3,251,221,120,218,189,50,179,180,125,3,94,7,231,216,167,37,157,128,141,28,22,57,81,15,253,199,120,53,120,30,4,91,237,201,95,129,14,114,39,104,222,21,213,205,182,182,190,121,177,143,187,173,77,204,100,121,217,111,244,246,222,2,23,99,162,245,22,107,208,89,172,181,190,55,121,189,154,49,104,155,177,123,158,95,193,133,203,213,89,123,120,70,149,248,43,188,182,237,69,237,253,148,251,173,115,230,119,237,124,159,30,129,17,131,243,242,210,174,150,78,251,108,234,214,197,184,102,213,114,146,117,12,135,86,70,156,85,198,194,93,159,131,64,148,176,15,53,111,23,234,203,211,62,181,123,187,237,140,128,151,176,23,94,30,114,63,97,215,93,87,175,246,206,195,41,72,144,255,24,87,176,110,169,70,244,245,209,41,173,100,60,254,237,77,166,236,66,16,141,16,98,205,75,44,7,148,202,105,86,36,144,224,43,186,231,167,255,131,107,101,3,210,160,192,57,147,104,17,40,114,76,229,43,202,89,118,159,224,244,62,230,70,185,177,254,65,81,130,67,84,124,137,28,10,152,71,95,18,65,243,173,211,47,33,6,125,31,133,183,111,254,223,164,92,15,19,105,232,103,225,69,202,82,146,193,80,137,225,9,54,246,31,148,193,130,253,253,207,79,78,132,248,36,102,79,191,17,37,28,42,9,196,233,11,119,71,197,231,200,105,40,154,195,84,16,60,165,195,32,43,169,20,16,72,169,66,160,143,200,200,124,123,227,157,69,188,8,142,113,90,174,131,222,92,163,226,150,160,241,16,69,243,52,168,248,76,91,100,213,205,216,18,98,121,247,86,18,210,204,46,62,170,110,97,74,34,80,126,113,154,194,143,88,45,46,226,3,100,56,75,165,79,241,78,64,127,68,41,201,103,66,1,220,154,247,17,233,119,213,127,23,240,177,137,198,214,119,172,103,247,47,103,53,186,226,210,5,0,0 };
|
||||
const uint8_t HTML_INDEX_GZIP[916] PROGMEM = { 31,139,8,0,19,56,151,101,2,255,133,148,235,115,162,58,20,192,255,21,174,159,238,157,221,22,95,181,237,174,56,19,20,108,85,68,64,240,241,45,64,42,193,240,40,9,162,254,245,155,128,157,238,157,189,211,235,12,201,201,57,191,243,200,17,206,240,175,137,57,94,239,86,154,20,177,132,140,134,245,42,13,35,4,195,209,48,65,12,74,65,4,11,138,152,82,178,183,187,167,209,144,97,70,208,104,156,165,172,200,200,80,110,142,13,153,194,4,41,39,140,170,60,43,152,20,112,4,165,76,105,85,56,100,145,18,162,19,14,208,93,125,248,46,225,20,51,12,201,29,13,32,65,74,167,53,26,18,156,30,165,2,17,165,69,35,238,30,148,76,194,60,68,75,138,10,244,166,132,144,193,31,56,129,7,36,231,233,225,167,15,41,26,244,191,99,79,53,237,170,61,159,30,50,192,127,75,199,141,52,247,192,37,85,28,129,53,6,134,216,179,133,245,188,22,130,58,13,213,181,171,1,176,152,174,198,242,57,82,45,174,28,171,177,163,207,150,220,58,152,113,223,195,43,87,174,68,188,49,24,240,53,20,158,102,46,162,14,18,190,232,189,113,80,18,237,73,196,91,233,170,225,105,110,205,118,188,141,221,237,188,91,93,130,237,158,254,46,30,167,231,149,118,207,227,114,179,155,221,78,226,116,59,165,83,219,248,195,229,89,119,58,183,184,31,231,57,163,139,188,170,220,155,150,143,34,190,150,218,206,154,24,64,205,64,239,184,82,171,235,19,126,152,95,113,118,62,244,151,94,224,246,74,109,246,82,223,116,51,91,216,109,11,96,224,134,78,173,32,149,163,147,171,232,73,167,2,96,18,6,170,133,177,143,106,91,216,118,220,142,174,126,211,116,45,10,52,227,219,75,190,171,68,35,212,157,227,218,170,167,198,235,104,39,207,38,20,28,198,154,195,250,36,223,202,167,231,120,97,237,103,131,119,253,153,245,142,17,184,196,157,243,214,157,251,86,95,245,178,106,82,189,155,187,131,118,62,30,55,125,188,27,144,21,212,219,3,251,221,120,218,189,50,179,180,125,3,94,7,231,216,167,37,157,128,141,28,22,57,81,15,253,199,120,53,120,30,4,91,237,201,95,129,14,114,39,104,222,21,213,205,182,182,190,121,177,143,187,173,77,204,100,121,217,111,244,246,222,2,23,99,162,245,22,107,208,89,172,181,190,55,121,189,154,49,104,155,177,123,158,95,193,133,203,213,89,123,120,70,149,248,43,188,182,237,69,237,253,148,251,173,115,230,119,237,124,159,30,129,17,131,243,242,210,174,150,78,251,108,234,214,197,184,102,213,114,146,117,12,135,86,70,156,85,198,194,93,159,131,64,148,176,15,53,111,23,234,203,211,62,181,123,187,237,140,128,151,176,23,94,30,114,63,97,215,93,87,175,246,206,195,41,72,144,255,24,87,176,110,169,70,244,245,209,41,173,100,60,254,237,77,166,236,66,16,141,16,98,205,75,44,7,148,202,105,86,36,144,224,43,186,231,167,255,131,107,101,3,210,160,192,57,147,104,17,40,114,76,229,43,202,89,118,159,224,244,62,230,70,185,177,254,65,81,130,67,84,124,137,28,10,152,71,95,18,65,243,173,211,47,33,6,125,31,133,183,111,254,223,164,92,15,19,105,232,103,225,69,202,82,146,193,80,137,225,9,54,246,31,148,193,130,253,253,207,79,78,132,248,36,102,79,191,17,37,28,42,9,196,233,11,119,71,197,231,200,105,40,154,195,84,16,60,165,195,32,43,169,20,16,72,169,66,160,143,200,200,124,123,227,157,69,188,8,142,113,90,174,131,222,92,163,226,150,160,241,16,69,243,52,168,248,76,91,100,213,205,216,18,98,121,247,86,18,210,204,46,62,170,110,97,74,34,80,126,113,154,194,143,88,45,46,226,3,100,56,75,165,79,241,78,64,127,68,41,201,103,66,1,220,154,247,17,233,119,213,127,23,240,177,137,198,214,119,172,103,247,47,103,53,186,226,210,5,0,0 };
|
||||
|
@ -1,5 +1,5 @@
|
||||
const char CSS_NORMALIZE[] PROGMEM = R"=====(
|
||||
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:visible}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}
|
||||
)=====";
|
||||
|
||||
const uint8_t CSS_NORMALIZE_GZIP[859] PROGMEM = { 31,139,8,0,53,140,123,99,2,255,149,84,237,110,163,58,16,125,149,168,171,74,187,146,137,104,247,163,87,70,247,73,162,252,24,236,1,124,227,47,217,38,77,22,241,238,59,6,66,147,54,93,233,254,2,6,123,230,204,57,103,166,75,70,15,141,179,169,104,192,40,125,230,17,108,44,34,6,213,84,133,137,69,194,83,42,162,250,141,5,200,255,250,152,248,83,89,62,86,197,43,214,7,149,238,255,29,107,39,207,131,129,208,42,203,203,17,66,82,66,35,131,168,36,50,137,9,148,142,172,81,173,0,159,148,179,249,181,15,200,26,231,18,6,214,33,200,252,104,131,235,61,51,160,44,51,104,123,102,225,200,34,138,233,70,236,13,165,63,15,82,69,175,225,204,107,237,196,97,132,94,42,199,4,216,35,68,230,131,107,3,198,200,142,84,213,173,39,149,213,202,98,49,93,168,142,152,161,129,46,64,171,214,242,26,34,230,191,115,34,110,93,250,186,19,196,76,112,58,238,191,173,41,172,179,88,117,168,218,46,81,119,187,78,73,137,118,207,18,26,250,157,240,230,220,8,67,13,226,144,123,177,178,16,78,187,192,83,32,134,61,4,180,105,4,14,212,209,145,200,225,157,35,56,131,235,83,134,144,105,171,235,176,75,42,105,220,15,181,11,196,73,81,187,148,156,225,79,254,180,145,244,138,114,172,89,36,120,182,157,21,124,157,65,213,78,203,81,54,118,14,198,116,214,200,85,162,30,197,216,61,45,65,146,140,63,163,169,22,149,182,191,94,208,108,202,145,62,15,87,136,249,151,166,41,171,25,246,151,178,44,199,104,64,235,171,20,255,144,218,177,39,20,189,191,138,190,252,124,172,38,154,47,44,85,222,69,149,149,227,1,137,35,106,248,83,238,115,166,228,60,47,182,63,209,228,220,195,210,117,177,125,206,17,101,218,133,14,226,40,30,219,73,38,30,200,59,223,134,204,96,163,221,43,63,170,168,106,141,227,236,172,139,21,159,168,197,31,165,63,141,93,24,10,227,126,19,159,167,12,88,217,150,103,157,73,144,28,170,62,9,175,146,123,74,185,150,130,62,185,81,56,114,246,161,150,228,58,100,17,140,191,153,40,227,172,35,193,5,178,245,173,122,35,139,80,141,117,79,45,90,166,172,239,19,115,62,205,222,39,70,200,239,44,207,24,185,5,134,89,7,101,59,26,206,52,101,88,63,214,97,155,51,125,100,98,169,48,167,28,166,177,157,124,216,184,96,102,167,46,39,58,218,7,155,9,200,46,157,61,254,251,48,199,31,246,236,58,72,147,133,233,93,140,180,50,138,130,195,101,57,128,247,8,84,68,32,159,147,84,162,15,145,90,240,78,17,173,97,41,185,163,129,1,194,40,247,215,197,215,224,176,92,146,216,64,175,211,114,137,243,73,193,198,137,62,22,202,90,218,24,211,189,143,241,213,45,149,7,41,179,168,229,56,29,29,174,45,106,137,7,208,227,117,63,162,67,113,32,225,223,183,14,180,28,30,242,76,174,46,89,199,243,244,190,198,114,199,246,166,198,240,176,39,116,11,55,19,180,34,122,101,139,107,241,63,61,79,123,225,246,252,176,0,159,252,119,35,3,113,46,186,251,50,100,221,27,133,90,86,127,243,255,229,226,255,26,143,187,24,222,240,207,145,66,100,24,250,94,203,159,94,145,40,92,128,188,60,238,117,52,89,119,106,137,12,121,145,58,47,200,232,180,146,155,168,52,77,194,58,30,155,103,255,38,209,246,59,237,147,205,246,215,243,244,120,201,203,69,99,139,86,222,115,204,58,132,183,131,127,153,213,143,251,55,101,247,94,22,55,77,174,6,31,145,95,94,170,229,71,94,6,75,1,201,82,55,188,21,252,3,26,45,63,124,152,7,0,0 };
|
||||
const char CSS_NORMALIZE[] PROGMEM = R"=====(
|
||||
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:visible}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}
|
||||
)=====";
|
||||
|
||||
const uint8_t CSS_NORMALIZE_GZIP[859] PROGMEM = { 31,139,8,0,19,56,151,101,2,255,149,84,237,110,163,58,16,125,149,168,171,74,187,146,137,104,247,163,87,70,247,73,162,252,24,236,1,124,227,47,217,38,77,22,241,238,59,6,66,147,54,93,233,254,2,6,123,230,204,57,103,166,75,70,15,141,179,169,104,192,40,125,230,17,108,44,34,6,213,84,133,137,69,194,83,42,162,250,141,5,200,255,250,152,248,83,89,62,86,197,43,214,7,149,238,255,29,107,39,207,131,129,208,42,203,203,17,66,82,66,35,131,168,36,50,137,9,148,142,172,81,173,0,159,148,179,249,181,15,200,26,231,18,6,214,33,200,252,104,131,235,61,51,160,44,51,104,123,102,225,200,34,138,233,70,236,13,165,63,15,82,69,175,225,204,107,237,196,97,132,94,42,199,4,216,35,68,230,131,107,3,198,200,142,84,213,173,39,149,213,202,98,49,93,168,142,152,161,129,46,64,171,214,242,26,34,230,191,115,34,110,93,250,186,19,196,76,112,58,238,191,173,41,172,179,88,117,168,218,46,81,119,187,78,73,137,118,207,18,26,250,157,240,230,220,8,67,13,226,144,123,177,178,16,78,187,192,83,32,134,61,4,180,105,4,14,212,209,145,200,225,157,35,56,131,235,83,134,144,105,171,235,176,75,42,105,220,15,181,11,196,73,81,187,148,156,225,79,254,180,145,244,138,114,172,89,36,120,182,157,21,124,157,65,213,78,203,81,54,118,14,198,116,214,200,85,162,30,197,216,61,45,65,146,140,63,163,169,22,149,182,191,94,208,108,202,145,62,15,87,136,249,151,166,41,171,25,246,151,178,44,199,104,64,235,171,20,255,144,218,177,39,20,189,191,138,190,252,124,172,38,154,47,44,85,222,69,149,149,227,1,137,35,106,248,83,238,115,166,228,60,47,182,63,209,228,220,195,210,117,177,125,206,17,101,218,133,14,226,40,30,219,73,38,30,200,59,223,134,204,96,163,221,43,63,170,168,106,141,227,236,172,139,21,159,168,197,31,165,63,141,93,24,10,227,126,19,159,167,12,88,217,150,103,157,73,144,28,170,62,9,175,146,123,74,185,150,130,62,185,81,56,114,246,161,150,228,58,100,17,140,191,153,40,227,172,35,193,5,178,245,173,122,35,139,80,141,117,79,45,90,166,172,239,19,115,62,205,222,39,70,200,239,44,207,24,185,5,134,89,7,101,59,26,206,52,101,88,63,214,97,155,51,125,100,98,169,48,167,28,166,177,157,124,216,184,96,102,167,46,39,58,218,7,155,9,200,46,157,61,254,251,48,199,31,246,236,58,72,147,133,233,93,140,180,50,138,130,195,101,57,128,247,8,84,68,32,159,147,84,162,15,145,90,240,78,17,173,97,41,185,163,129,1,194,40,247,215,197,215,224,176,92,146,216,64,175,211,114,137,243,73,193,198,137,62,22,202,90,218,24,211,189,143,241,213,45,149,7,41,179,168,229,56,29,29,174,45,106,137,7,208,227,117,63,162,67,113,32,225,223,183,14,180,28,30,242,76,174,46,89,199,243,244,190,198,114,199,246,166,198,240,176,39,116,11,55,19,180,34,122,101,139,107,241,63,61,79,123,225,246,252,176,0,159,252,119,35,3,113,46,186,251,50,100,221,27,133,90,86,127,243,255,229,226,255,26,143,187,24,222,240,207,145,66,100,24,250,94,203,159,94,145,40,92,128,188,60,238,117,52,89,119,106,137,12,121,145,58,47,200,232,180,146,155,168,52,77,194,58,30,155,103,255,38,209,246,59,237,147,205,246,215,243,244,120,201,203,69,99,139,86,222,115,204,58,132,183,131,127,153,213,143,251,55,101,247,94,22,55,77,174,6,31,145,95,94,170,229,71,94,6,75,1,201,82,55,188,21,252,3,26,45,63,124,152,7,0,0 };
|
||||
|
@ -12,4 +12,4 @@ function sliderDiscrete_tmplt(){var tmplt='<div class="slider">'+
|
||||
function slider_move(parents,newW,sliderW,send){var slider_new_val=parseInt(Math.round((newW/sliderW)*100));var slider_fill=parents.find(".slider-fill");var slider_handle=parents.find(".slider-handle");var range=parents.find('input[type="range"]');range.next().html(newW);slider_fill.css("width",slider_new_val+"%");slider_handle.css({left:slider_new_val+"%",transition:"none","-webkit-transition":"none","-moz-transition":"none",});range.val(slider_new_val);if(parents.find(".slider-handle span").text()!=slider_new_val){parents.find(".slider-handle span").text(slider_new_val);var number=parents.attr("id").substring(2);if(send)websock.send("slvalue:"+slider_new_val+":"+number);}}
|
||||
)=====";
|
||||
|
||||
const uint8_t JS_SLIDER_GZIP[881] PROGMEM = { 31,139,8,0,210,8,51,99,2,255,237,86,77,143,218,48,16,189,243,43,88,107,187,196,93,240,210,61,18,204,165,85,165,30,122,106,165,86,90,173,144,73,156,141,69,112,162,216,129,182,44,255,189,227,143,132,36,192,106,219,83,15,61,37,246,60,143,223,204,60,123,156,84,50,210,34,151,195,114,189,137,151,37,147,79,252,75,38,98,94,6,138,103,60,210,121,137,247,91,86,14,97,148,140,149,181,44,119,34,214,105,61,200,147,68,113,61,142,170,82,106,63,247,65,168,168,228,154,143,173,59,63,25,26,15,244,250,232,54,108,123,163,198,74,236,111,208,88,156,107,103,114,255,1,38,25,79,116,216,221,199,34,122,115,132,179,40,13,18,31,93,32,198,91,188,183,28,129,130,78,133,194,161,29,17,86,20,92,198,65,119,241,82,111,138,12,54,195,161,141,128,58,104,34,0,56,18,178,168,244,131,254,89,112,138,172,21,61,142,106,198,109,32,34,110,14,53,225,36,34,203,168,251,239,66,38,198,114,196,165,76,198,25,63,143,116,182,35,54,99,43,126,193,169,53,1,210,84,207,18,93,110,89,70,11,86,42,254,73,234,192,78,17,152,50,97,182,24,146,72,169,0,217,74,160,113,179,238,22,189,233,19,116,64,83,142,75,56,203,192,179,82,5,147,8,19,205,127,248,173,13,26,135,7,28,186,242,202,0,109,242,74,241,56,223,201,161,206,171,40,85,154,149,224,186,31,250,184,169,41,199,123,145,4,156,172,42,173,115,73,41,189,199,123,168,30,148,96,152,176,76,241,240,48,48,177,67,196,92,106,85,215,157,248,49,36,202,72,126,210,84,201,170,188,45,73,15,108,84,217,2,120,101,214,136,174,56,13,46,74,121,180,118,199,169,65,189,160,31,34,128,207,44,22,138,173,50,30,3,25,8,172,237,130,82,93,86,252,36,188,58,36,22,199,239,51,102,202,33,212,132,65,118,182,220,7,180,201,183,252,99,69,219,57,115,57,121,226,223,41,39,246,251,252,12,181,76,205,62,241,87,147,120,174,30,166,143,206,212,142,89,242,93,147,24,48,77,58,169,48,132,251,184,57,109,167,243,230,230,234,20,129,166,8,227,189,159,54,92,3,159,172,113,31,218,189,123,108,54,194,195,193,242,171,138,94,132,117,90,128,90,224,84,83,194,121,239,148,1,145,86,166,72,201,205,222,103,82,232,54,168,125,208,189,149,168,193,206,92,98,199,86,169,237,9,139,168,138,153,33,229,172,112,189,184,209,33,188,14,226,60,170,54,64,3,27,197,31,185,189,254,24,252,215,127,47,188,19,117,122,85,255,11,250,28,252,129,60,207,74,237,111,132,116,24,212,155,13,207,119,53,123,3,216,127,58,154,199,98,59,140,140,240,41,242,74,88,140,110,7,103,230,93,147,90,204,239,192,114,9,226,175,232,197,25,147,235,70,139,185,233,3,139,233,252,206,126,157,179,198,37,114,127,40,244,101,182,28,79,227,233,22,2,42,240,205,39,31,190,144,35,255,94,57,214,167,211,246,62,51,157,146,50,175,64,138,129,89,122,231,151,226,183,239,166,83,220,17,185,237,215,189,91,163,219,176,91,96,223,180,207,195,155,174,221,244,226,215,28,10,247,248,32,210,180,76,76,82,189,201,44,227,203,221,186,27,243,165,150,189,55,135,116,118,138,5,209,50,169,132,73,244,12,201,92,66,171,69,147,29,95,173,133,158,28,77,232,104,219,228,191,206,25,14,53,113,243,182,232,110,99,207,245,75,41,26,182,159,9,248,138,246,150,239,95,189,182,191,175,73,188,172,54,43,120,163,213,62,152,214,37,220,246,112,219,16,85,173,148,46,133,124,10,238,45,69,43,35,8,93,229,209,154,152,1,188,95,50,240,83,241,25,186,237,103,14,166,156,103,211,144,126,3,128,124,107,46,79,11,0,0 };
|
||||
const uint8_t JS_SLIDER_GZIP[881] PROGMEM = { 31,139,8,0,19,56,151,101,2,255,237,86,77,143,218,48,16,189,243,43,88,107,187,196,93,240,210,61,18,204,165,85,165,30,122,106,165,86,90,173,144,73,156,141,69,112,162,216,129,182,44,255,189,227,143,132,36,192,106,219,83,15,61,37,246,60,143,223,204,60,123,156,84,50,210,34,151,195,114,189,137,151,37,147,79,252,75,38,98,94,6,138,103,60,210,121,137,247,91,86,14,97,148,140,149,181,44,119,34,214,105,61,200,147,68,113,61,142,170,82,106,63,247,65,168,168,228,154,143,173,59,63,25,26,15,244,250,232,54,108,123,163,198,74,236,111,208,88,156,107,103,114,255,1,38,25,79,116,216,221,199,34,122,115,132,179,40,13,18,31,93,32,198,91,188,183,28,129,130,78,133,194,161,29,17,86,20,92,198,65,119,241,82,111,138,12,54,195,161,141,128,58,104,34,0,56,18,178,168,244,131,254,89,112,138,172,21,61,142,106,198,109,32,34,110,14,53,225,36,34,203,168,251,239,66,38,198,114,196,165,76,198,25,63,143,116,182,35,54,99,43,126,193,169,53,1,210,84,207,18,93,110,89,70,11,86,42,254,73,234,192,78,17,152,50,97,182,24,146,72,169,0,217,74,160,113,179,238,22,189,233,19,116,64,83,142,75,56,203,192,179,82,5,147,8,19,205,127,248,173,13,26,135,7,28,186,242,202,0,109,242,74,241,56,223,201,161,206,171,40,85,154,149,224,186,31,250,184,169,41,199,123,145,4,156,172,42,173,115,73,41,189,199,123,168,30,148,96,152,176,76,241,240,48,48,177,67,196,92,106,85,215,157,248,49,36,202,72,126,210,84,201,170,188,45,73,15,108,84,217,2,120,101,214,136,174,56,13,46,74,121,180,118,199,169,65,189,160,31,34,128,207,44,22,138,173,50,30,3,25,8,172,237,130,82,93,86,252,36,188,58,36,22,199,239,51,102,202,33,212,132,65,118,182,220,7,180,201,183,252,99,69,219,57,115,57,121,226,223,41,39,246,251,252,12,181,76,205,62,241,87,147,120,174,30,166,143,206,212,142,89,242,93,147,24,48,77,58,169,48,132,251,184,57,109,167,243,230,230,234,20,129,166,8,227,189,159,54,92,3,159,172,113,31,218,189,123,108,54,194,195,193,242,171,138,94,132,117,90,128,90,224,84,83,194,121,239,148,1,145,86,166,72,201,205,222,103,82,232,54,168,125,208,189,149,168,193,206,92,98,199,86,169,237,9,139,168,138,153,33,229,172,112,189,184,209,33,188,14,226,60,170,54,64,3,27,197,31,185,189,254,24,252,215,127,47,188,19,117,122,85,255,11,250,28,252,129,60,207,74,237,111,132,116,24,212,155,13,207,119,53,123,3,216,127,58,154,199,98,59,140,140,240,41,242,74,88,140,110,7,103,230,93,147,90,204,239,192,114,9,226,175,232,197,25,147,235,70,139,185,233,3,139,233,252,206,126,157,179,198,37,114,127,40,244,101,182,28,79,227,233,22,2,42,240,205,39,31,190,144,35,255,94,57,214,167,211,246,62,51,157,146,50,175,64,138,129,89,122,231,151,226,183,239,166,83,220,17,185,237,215,189,91,163,219,176,91,96,223,180,207,195,155,174,221,244,226,215,28,10,247,248,32,210,180,76,76,82,189,201,44,227,203,221,186,27,243,165,150,189,55,135,116,118,138,5,209,50,169,132,73,244,12,201,92,66,171,69,147,29,95,173,133,158,28,77,232,104,219,228,191,206,25,14,53,113,243,182,232,110,99,207,245,75,41,26,182,159,9,248,138,246,150,239,95,189,182,191,175,73,188,172,54,43,120,163,213,62,152,214,37,220,246,112,219,16,85,173,148,46,133,124,10,238,45,69,43,35,8,93,229,209,154,152,1,188,95,50,240,83,241,25,186,237,103,14,166,156,103,211,144,126,3,128,124,107,46,79,11,0,0 };
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user