1
0
mirror of https://github.com/s00500/ESPUI.git synced 2024-11-22 04:00:55 +00:00

Aligned with latest main branch

This commit is contained in:
Martin 2023-09-09 16:52:28 -04:00
parent 136b182813
commit 7e3de1c14f
5 changed files with 349 additions and 245 deletions

View File

@ -13,6 +13,58 @@
#include "dataTabbedcontentJS.h" #include "dataTabbedcontentJS.h"
#include "dataZeptoJS.h" #include "dataZeptoJS.h"
#if ESP8266
#include <umm_malloc/umm_heap_select.h>
#endif
static String heapInfo(const __FlashStringHelper* mode)
{
String result;
#if ESP8266
uint32_t hfree;
uint16_t hmax;
uint8_t hfrag;
result.reserve(128);
#ifdef UMM_HEAP_IRAM
// here esp8266 is configurerd to use an extra 16KB (i)ram
{
HeapSelectIram useInstructionRamHere;
ESP.getHeapStats(&hfree, &hmax, &hfrag);
}
result += F("IRAM: free: ");
result += hfree;
result += F(" max: ");
result += hmax;
result += F(" frag: ");
result += hfrag;
result += "%\n";
#endif // !UMM_HEAP_IRAM
{
HeapSelectDram useRegularRamHere;
ESP.getHeapStats(&hfree, &hmax, &hfrag);
}
result += F("DRAM: free: ");
result += hfree;
result += F(" max: ");
result += hmax;
result += F(" frag: ");
result += hfrag;
result += "%\n";
#else // !ESP8266
result += ESP.getFreeHeap();
result += ' ';
#endif // !ESP8266
result += mode;
return result;
}
// ################# LITTLEFS functions // ################# LITTLEFS functions
#if defined(ESP32) #if defined(ESP32)
void listDir(const char* dirname, uint8_t levels) void listDir(const char* dirname, uint8_t levels)
@ -517,11 +569,11 @@ void ESPUIClass::prepareFileSystem(bool format)
#else #else
LittleFS.end(); LittleFS.end();
#endif #endif
} }
// Handle Websockets Communication // Handle Websockets Communication
void ESPUIClass::onWsEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len) 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)); // Serial.println(String("ESPUIClass::OnWsEvent: type: ") + String(type));
RemoveToBeDeletedControls(); RemoveToBeDeletedControls();
@ -572,12 +624,14 @@ uint16_t ESPUIClass::addControl(ControlType type, const char* label, const Strin
return addControl(type, label, value, color, Control::noParent); return addControl(type, label, value, color, Control::noParent);
} }
uint16_t ESPUIClass::addControl(ControlType type, const char* label, const String& value, ControlColor color, uint16_t parentControl) uint16_t ESPUIClass::addControl(
ControlType type, const char* label, const String& value, ControlColor color, uint16_t parentControl)
{ {
return addControl(type, label, value, color, parentControl, nullptr); return addControl(type, label, value, color, parentControl, nullptr);
} }
uint16_t ESPUIClass::addControl(ControlType type, const char* label, const String& value, ControlColor color, uint16_t parentControl, void (*callback)(Control*, int)) uint16_t ESPUIClass::addControl(ControlType type, const char* label, const String& value, ControlColor color,
uint16_t parentControl, void (*callback)(Control*, int))
{ {
uint16_t id = addControl(type, label, value, color, parentControl, nullptr, nullptr); uint16_t id = addControl(type, label, value, color, parentControl, nullptr, nullptr);
// set the original style callback // set the original style callback
@ -585,7 +639,8 @@ uint16_t ESPUIClass::addControl(ControlType type, const char* label, const Strin
return id; return id;
} }
uint16_t ESPUIClass::addControl(ControlType type, const char* label, const String& value, ControlColor color, uint16_t parentControl, void (*callback)(Control*, int, void *), void * UserData) uint16_t ESPUIClass::addControl(ControlType type, const char* label, const String& value, ControlColor color,
uint16_t parentControl, void (*callback)(Control*, int, void*), void* UserData)
{ {
#ifdef ESP32 #ifdef ESP32
xSemaphoreTake(ControlsSemaphore, portMAX_DELAY); xSemaphoreTake(ControlsSemaphore, portMAX_DELAY);
@ -697,16 +752,19 @@ uint16_t ESPUIClass::graph(const char* label, ControlColor color)
return addControl(ControlType::Graph, label, "", color); return addControl(ControlType::Graph, label, "", color);
} }
uint16_t ESPUIClass::slider(const char* label, void (*callback)(Control*, int), ControlColor color, int value, int min, int max) uint16_t ESPUIClass::slider(
const char* label, void (*callback)(Control*, int), ControlColor color, int value, int min, int max)
{ {
uint16_t id = slider(label, nullptr, color, value, min, max, nullptr); uint16_t id = slider(label, nullptr, color, value, min, max, nullptr);
getControl(id)->callback = callback; getControl(id)->callback = callback;
return id; return id;
} }
uint16_t ESPUIClass::slider(const char* label, void (*callback)(Control*, int, void*), ControlColor color, int value, int min, int max, void* userData) uint16_t ESPUIClass::slider(const char* label, void (*callback)(Control*, int, void*), ControlColor color, int value,
int min, int max, void* userData)
{ {
uint16_t sliderId = addControl(ControlType::Slider, label, String(value), color, Control::noParent, callback, userData); uint16_t sliderId
= addControl(ControlType::Slider, label, String(value), color, Control::noParent, callback, userData);
addControl(ControlType::Min, label, String(min), ControlColor::None, sliderId); addControl(ControlType::Min, label, String(min), ControlColor::None, sliderId);
addControl(ControlType::Max, label, String(max), ControlColor::None, sliderId); addControl(ControlType::Max, label, String(max), ControlColor::None, sliderId);
@ -718,7 +776,8 @@ uint16_t ESPUIClass::button(const char* label, void (*callback)(Control*, int),
return addControl(ControlType::Button, label, value, color, Control::noParent, callback); return addControl(ControlType::Button, label, value, color, Control::noParent, callback);
} }
uint16_t ESPUIClass::button(const char* label, void (*callback)(Control*, int, void*), ControlColor color, const String& value, void* UserData) uint16_t ESPUIClass::button(
const char* label, void (*callback)(Control*, int, void*), ControlColor color, const String& value, void* UserData)
{ {
return addControl(ControlType::Button, label, value, color, Control::noParent, callback, UserData); return addControl(ControlType::Button, label, value, color, Control::noParent, callback, UserData);
} }
@ -728,9 +787,11 @@ uint16_t ESPUIClass::switcher(const char* label, void (*callback)(Control*, int)
return addControl(ControlType::Switcher, label, startState ? "1" : "0", color, Control::noParent, callback); return addControl(ControlType::Switcher, label, startState ? "1" : "0", color, Control::noParent, callback);
} }
uint16_t ESPUIClass::switcher(const char* label, void (*callback)(Control*, int, void*), ControlColor color, bool startState, void* UserData) uint16_t ESPUIClass::switcher(
const char* label, void (*callback)(Control*, int, void*), ControlColor color, bool startState, void* UserData)
{ {
return addControl(ControlType::Switcher, label, startState ? "1" : "0", color, Control::noParent, callback, UserData); return addControl(
ControlType::Switcher, label, startState ? "1" : "0", color, Control::noParent, callback, UserData);
} }
uint16_t ESPUIClass::pad(const char* label, void (*callback)(Control*, int), ControlColor color) uint16_t ESPUIClass::pad(const char* label, void (*callback)(Control*, int), ControlColor color)
@ -748,12 +809,14 @@ uint16_t ESPUIClass::padWithCenter(const char* label, void (*callback)(Control*,
return addControl(ControlType::PadWithCenter, label, "", color, Control::noParent, callback); return addControl(ControlType::PadWithCenter, label, "", color, Control::noParent, callback);
} }
uint16_t ESPUIClass::padWithCenter(const char* label, void (*callback)(Control*, int, void*), ControlColor color, void* UserData) uint16_t ESPUIClass::padWithCenter(
const char* label, void (*callback)(Control*, int, void*), ControlColor color, void* UserData)
{ {
return addControl(ControlType::PadWithCenter, label, "", color, Control::noParent, callback, UserData); return addControl(ControlType::PadWithCenter, label, "", color, Control::noParent, callback, UserData);
} }
uint16_t ESPUIClass::number(const char* label, void (*callback)(Control*, int), ControlColor color, int number, int min, int max) uint16_t ESPUIClass::number(
const char* label, void (*callback)(Control*, int), ControlColor color, int number, int min, int max)
{ {
uint16_t numberId = addControl(ControlType::Number, label, String(number), color, Control::noParent, callback); uint16_t numberId = addControl(ControlType::Number, label, String(number), color, Control::noParent, callback);
addControl(ControlType::Min, label, String(min), ControlColor::None, numberId); addControl(ControlType::Min, label, String(min), ControlColor::None, numberId);
@ -761,9 +824,11 @@ uint16_t ESPUIClass::number(const char* label, void (*callback)(Control*, int),
return numberId; return numberId;
} }
uint16_t ESPUIClass::number(const char* label, void (*callback)(Control*, int, void*), ControlColor color, int number, int min, int max, void* UserData) uint16_t ESPUIClass::number(const char* label, void (*callback)(Control*, int, void*), ControlColor color, int number,
int min, int max, void* UserData)
{ {
uint16_t numberId = addControl(ControlType::Number, label, String(number), color, Control::noParent, callback, UserData); uint16_t numberId
= addControl(ControlType::Number, label, String(number), color, Control::noParent, callback, UserData);
addControl(ControlType::Min, label, String(min), ControlColor::None, numberId); addControl(ControlType::Min, label, String(min), ControlColor::None, numberId);
addControl(ControlType::Max, label, String(max), ControlColor::None, numberId); addControl(ControlType::Max, label, String(max), ControlColor::None, numberId);
return numberId; return numberId;
@ -777,7 +842,8 @@ uint16_t ESPUIClass::gauge(const char* label, ControlColor color, int number, in
return numberId; return numberId;
} }
uint16_t ESPUIClass::separator(const char* label) { uint16_t ESPUIClass::separator(const char* label)
{
return addControl(ControlType::Separator, label, "", ControlColor::Alizarin, Control::noParent, nullptr); return addControl(ControlType::Separator, label, "", ControlColor::Alizarin, Control::noParent, nullptr);
} }
@ -786,7 +852,8 @@ uint16_t ESPUIClass::accelerometer(const char* label, void (*callback)(Control*,
return addControl(ControlType::Accel, label, "", color, Control::noParent, callback); return addControl(ControlType::Accel, label, "", color, Control::noParent, callback);
} }
uint16_t ESPUIClass::accelerometer(const char* label, void (*callback)(Control*, int, void*), ControlColor color, void* UserData) uint16_t ESPUIClass::accelerometer(
const char* label, void (*callback)(Control*, int, void*), ControlColor color, void* UserData)
{ {
return addControl(ControlType::Accel, label, "", color, Control::noParent, callback, UserData); return addControl(ControlType::Accel, label, "", color, Control::noParent, callback, UserData);
} }
@ -796,7 +863,8 @@ uint16_t ESPUIClass::text(const char* label, void (*callback)(Control*, int), Co
return addControl(ControlType::Text, label, value, color, Control::noParent, callback); return addControl(ControlType::Text, label, value, color, Control::noParent, callback);
} }
uint16_t ESPUIClass::text(const char* label, void (*callback)(Control*, int, void*), ControlColor color, const String& value, void* UserData) uint16_t ESPUIClass::text(
const char* label, void (*callback)(Control*, int, void*), ControlColor color, const String& value, void* UserData)
{ {
return addControl(ControlType::Text, label, value, color, Control::noParent, callback, UserData); return addControl(ControlType::Text, label, value, color, Control::noParent, callback, UserData);
} }
@ -887,7 +955,8 @@ void ESPUIClass::setPanelWide(uint16_t id, bool wide)
} }
} }
void ESPUIClass::setEnabled(uint16_t id, bool enabled, int clientId) { void ESPUIClass::setEnabled(uint16_t id, bool enabled, int clientId)
{
Control* control = getControl(id); Control* control = getControl(id);
if (control) if (control)
{ {
@ -897,7 +966,8 @@ void ESPUIClass::setEnabled(uint16_t id, bool enabled, int clientId) {
} }
} }
void ESPUIClass::setVertical(uint16_t id, bool vert) { void ESPUIClass::setVertical(uint16_t id, bool vert)
{
Control* control = getControl(id); Control* control = getControl(id);
if (control) if (control)
{ {
@ -973,7 +1043,8 @@ void ESPUIClass::updateControlLabel(Control* control, const char * value, int cl
updateControl(control, clientId); updateControl(control, clientId);
} }
void ESPUIClass::updateVisibility(uint16_t id, bool visibility, int clientId) { void ESPUIClass::updateVisibility(uint16_t id, bool visibility, int clientId)
{
Control* control = getControl(id); Control* control = getControl(id);
if (control) if (control)
{ {
@ -992,7 +1063,8 @@ void ESPUIClass::updateLabel(uint16_t id, const String& value)
updateControlValue(id, value); updateControlValue(id, value);
} }
void ESPUIClass::updateButton(uint16_t id, const String& value) { void ESPUIClass::updateButton(uint16_t id, const String& value)
{
updateControlValue(id, value); updateControlValue(id, value);
} }
@ -1031,7 +1103,8 @@ void ESPUIClass::updateTime(uint16_t id, int clientId)
updateControl(id, clientId); updateControl(id, clientId);
} }
void ESPUIClass::clearGraph(uint16_t id, int clientId) { void ESPUIClass::clearGraph(uint16_t id, int clientId)
{
do // once do // once
{ {
Control* control = getControl(id); Control* control = getControl(id);
@ -1218,10 +1291,8 @@ void ESPUIClass::beginLITTLEFS(const char* _title, const char* username, const c
return; return;
} }
ws->onEvent([](AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len) ws->onEvent([](AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data,
{ size_t len) { ESPUI.onWsEvent(server, client, type, arg, data, len); });
ESPUI.onWsEvent(server, client, type, arg, data, len);
});
server->addHandler(ws); server->addHandler(ws);
if (basicAuth) if (basicAuth)
@ -1260,7 +1331,7 @@ void ESPUIClass::beginLITTLEFS(const char* _title, const char* username, const c
return request->requestAuthentication(); return request->requestAuthentication();
} }
request->send(200, "text/plain", String(ESP.getFreeHeap()) + " In LITTLEFS mode"); request->send(200, "text/plain", heapInfo(F("In LITTLEFS mode")));
}); });
server->onNotFound([this](AsyncWebServerRequest* request) { server->onNotFound([this](AsyncWebServerRequest* request) {
@ -1303,10 +1374,8 @@ void ESPUIClass::begin(const char* _title, const char* username, const char* pas
server = new AsyncWebServer(port); server = new AsyncWebServer(port);
ws = new AsyncWebSocket("/ws"); ws = new AsyncWebSocket("/ws");
ws->onEvent([](AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len) ws->onEvent([](AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data,
{ size_t len) { ESPUI.onWsEvent(server, client, type, arg, data, len); });
ESPUI.onWsEvent(server, client, type, arg, data, len);
});
server->addHandler(ws); server->addHandler(ws);
@ -1418,7 +1487,7 @@ void ESPUIClass::begin(const char* _title, const char* username, const char* pas
return request->requestAuthentication(); return request->requestAuthentication();
} }
request->send(200, "text/plain", String(ESP.getFreeHeap()) + " In Memorymode"); request->send(200, "text/plain", heapInfo(F("In Memorymode")));
}); });
server->onNotFound([this](AsyncWebServerRequest* request) { server->onNotFound([this](AsyncWebServerRequest* request) {

View File

@ -89,18 +89,20 @@ class ESPUIClass
public: public:
ESPUIClass() ESPUIClass()
{ {
verbosity = Verbosity::Quiet;
jsonUpdateDocumentSize = 2000;
jsonInitialDocumentSize = 8000;
sliderContinuous = false;
#ifdef ESP32 #ifdef ESP32
ControlsSemaphore = xSemaphoreCreateMutex(); ControlsSemaphore = xSemaphoreCreateMutex();
xSemaphoreGive(ControlsSemaphore); xSemaphoreGive(ControlsSemaphore);
#endif // def ESP32 #endif // def ESP32
} }
unsigned int jsonUpdateDocumentSize; unsigned int jsonUpdateDocumentSize = 2000;
unsigned int jsonInitialDocumentSize; #ifdef ESP8266
bool sliderContinuous; unsigned int jsonInitialDocumentSize = 2000;
unsigned int jsonChunkNumberMax = 5;
#else
unsigned int jsonInitialDocumentSize = 8000;
unsigned int jsonChunkNumberMax = 0;
#endif
bool sliderContinuous = false;
void onWsEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len); void onWsEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len);
bool captivePortal = true; bool captivePortal = true;
@ -205,7 +207,7 @@ public:
void jsonReload(); void jsonReload();
void jsonDom(uint16_t startidx, AsyncWebSocketClient* client = nullptr, bool Updating = false); void jsonDom(uint16_t startidx, AsyncWebSocketClient* client = nullptr, bool Updating = false);
Verbosity verbosity; Verbosity verbosity = Verbosity::Quiet;
protected: protected:
friend class ESPUIclient; friend class ESPUIclient;

View File

@ -2,6 +2,42 @@
#include "ESPUIclient.h" #include "ESPUIclient.h"
#include "ESPUIcontrol.h" #include "ESPUIcontrol.h"
// JSONSlave:
// helper to process exact JSON serialization size
// it takes ~2ms on esp8266 and avoid large String reallocation which is really worth the cost
class JSONSlave: public Print
{
public:
size_t write (uint8_t c) override { counter++; return 1; }
size_t write (const uint8_t* buf, size_t count) override { counter += count; return count; }
size_t get_counter () { return counter; }
static size_t serializedSize (JsonDocument& doc)
{
JSONSlave counter;
serializeJson(doc, counter);
return counter.get_counter();
}
static size_t serialize (JsonDocument& doc, String& str)
{
size_t s = serializedSize(doc) + 10; // 10 is paranoid
str.reserve(s);
serializeJson(doc, str);
return s;
}
static String toString (JsonDocument& doc)
{
String str;
serialize(doc, str);
return str;
}
protected:
size_t counter = 0;
};
ESPUIclient::ESPUIclient(AsyncWebSocketClient * _client): ESPUIclient::ESPUIclient(AsyncWebSocketClient * _client):
client(_client) client(_client)
{ {
@ -201,7 +237,7 @@ void ESPUIclient::onWsEvent(AwsEventType type, void* arg, uint8_t* data, size_t
{ {
if(!emptyString.equals(value)) if(!emptyString.equals(value))
{ {
Serial.println(String(F("ESPUIclient::OnWsEvent:WS_EVT_DATA:uifragmentok:ProcessAck:value: '")) + value + "'"); // Serial.println(String(F("ESPUIclient::OnWsEvent:WS_EVT_DATA:uifragmentok:ProcessAck:value: '")) + value + "'");
pCurrentFsmState->ProcessAck(uint16_t(-1), value); pCurrentFsmState->ProcessAck(uint16_t(-1), value);
} }
else else
@ -377,7 +413,7 @@ uint32_t ESPUIclient::prepareJSONChunk(uint16_t startindex,
elementcount++; elementcount++;
control->MarshalControl(item, InUpdateMode, DataOffset); control->MarshalControl(item, InUpdateMode, DataOffset);
if (rootDoc.overflowed()) if (rootDoc.overflowed() || (ESPUI.jsonChunkNumberMax > 0 && (elementcount % ESPUI.jsonChunkNumberMax) == 0))
{ {
// String("prepareJSONChunk: too much data in the message. Remove the last entry"); // String("prepareJSONChunk: too much data in the message. Remove the last entry");
if (1 == elementcount) if (1 == elementcount)
@ -393,6 +429,7 @@ uint32_t ESPUIclient::prepareJSONChunk(uint16_t startindex,
{ {
// Serial.println(String("prepareJSONChunk: Defering control: ") + String(control->id)); // Serial.println(String("prepareJSONChunk: Defering control: ") + String(control->id));
// Serial.println(String("prepareJSONChunk: elementcount: ") + String(elementcount)); // Serial.println(String("prepareJSONChunk: elementcount: ") + String(elementcount));
items.remove(elementcount); items.remove(elementcount);
--elementcount; --elementcount;
} }
@ -478,9 +515,8 @@ bool ESPUIclient::SendControlsToClient(uint16_t startidx, ClientUpdateType_t Tra
if (ESPUI.verbosity >= Verbosity::VerboseJSON) if (ESPUI.verbosity >= Verbosity::VerboseJSON)
{ {
Serial.println(F("ESPUIclient:SendControlsToClient: Sending elements --------->")); Serial.println(F("ESPUIclient:SendControlsToClient: Sending elements --------->"));
String json; serializeJson(document, Serial);
serializeJson(document, json); Serial.println();
Serial.println(json);
} }
#endif #endif
@ -525,10 +561,7 @@ bool ESPUIclient::SendJsonDocToWebSocket(DynamicJsonDocument& document)
break; break;
} }
String json; String json = JSONSlave::toString(document);
json.reserve(document.size() / 2);
json.clear();
serializeJson(document, json);
#if defined(DEBUG_ESPUI) #if defined(DEBUG_ESPUI)
if (ESPUI.verbosity >= Verbosity::VerboseJSON) if (ESPUI.verbosity >= Verbosity::VerboseJSON)

View File

@ -2,7 +2,6 @@
#include <Arduino.h> #include <Arduino.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <ESPUIClient.h>
enum ControlType : uint8_t enum ControlType : uint8_t
{ {
@ -30,8 +29,9 @@ enum ControlType : uint8_t
Accel, Accel,
Separator, Separator,
Time, Time,
Fragment,
Fragment,
Password = 99,
UpdateOffset = 100, UpdateOffset = 100,
}; };
@ -84,7 +84,7 @@ public:
void SendCallback(int type); void SendCallback(int type);
bool HasCallback() { return ((nullptr != callback) || (nullptr != extendedCallback)); } bool HasCallback() { return ((nullptr != callback) || (nullptr != extendedCallback)); }
void MarshalControl(ArduinoJson::JsonObject& item, bool refresh, uint32_t StartingOffset); void MarshalControl(ArduinoJson::JsonObject& item, bool refresh);
void MarshalErrorMessage(ArduinoJson::JsonObject& item); void MarshalErrorMessage(ArduinoJson::JsonObject& item);
bool ToBeDeleted() { return (ControlSyncState_t::deleted == ControlSyncState); } bool ToBeDeleted() { return (ControlSyncState_t::deleted == ControlSyncState); }
void DeleteControl(); void DeleteControl();