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

Merge pull request #241 from d-a-v/membreathe

reduce memory footprint
This commit is contained in:
Lukas Bachschwell 2023-08-01 13:00:52 +02:00 committed by GitHub
commit 372157b980
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 189 additions and 25 deletions

View File

@ -495,7 +495,7 @@ ESPUI includes a range of advanced features that can customise your UIs.
### Dynamic Visibility ### Dynamic Visibility
Cotrols can be made visible or invisible at runtime with the `updateVisibility()` function. Controls can be made visible or invisible at runtime with the `updateVisibility()` function.
``` ```
ESPUI.updateVisibility(controlId, false); ESPUI.updateVisibility(controlId, false);

View File

@ -26,8 +26,18 @@
#include <WiFi.h> #include <WiFi.h>
#include <ESPmDNS.h> #include <ESPmDNS.h>
#else #else
// esp8266
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <ESP8266mDNS.h> #include <ESP8266mDNS.h>
#include <umm_malloc/umm_heap_select.h>
#ifndef MMU_IRAM_HEAP
#warning Try MMU option '2nd heap shared' in 'tools' IDE menu (cf. https://arduino-esp8266.readthedocs.io/en/latest/mmu.html#option-summary)
#warning use decorators: { HeapSelectIram doAllocationsInIRAM; ESPUI.addControl(...) ... } (cf. https://arduino-esp8266.readthedocs.io/en/latest/mmu.html#how-to-select-heap)
#warning then check http://<ip>/heap
#endif // MMU_IRAM_HEAP
#ifndef DEBUG_ESP_OOM
#error on ESP8266 and ESPUI, you must define OOM debug option when developping
#endif
#endif #endif
//Settings //Settings
@ -62,6 +72,11 @@ volatile bool updates = false;
// This is the main function which builds our GUI // This is the main function which builds our GUI
void setUpUI() { void setUpUI() {
#ifdef ESP8266
{ HeapSelectIram doAllocationsInIRAM;
#endif
//Turn off verbose debugging //Turn off verbose debugging
ESPUI.setVerbosity(Verbosity::Quiet); ESPUI.setVerbosity(Verbosity::Quiet);
@ -274,6 +289,11 @@ void setUpUI() {
//Finally, start up the UI. //Finally, start up the UI.
//This should only be called once we are connected to WiFi. //This should only be called once we are connected to WiFi.
ESPUI.begin(HOSTNAME); ESPUI.begin(HOSTNAME);
#ifdef ESP8266
} // HeapSelectIram
#endif
} }
//This callback generates and applies inline styles to a bunch of controls to change their colour. //This callback generates and applies inline styles to a bunch of controls to change their colour.

View File

@ -0,0 +1 @@
// placeholder

View File

@ -8,7 +8,17 @@ DNSServer dnsServer;
#if defined(ESP32) #if defined(ESP32)
#include <WiFi.h> #include <WiFi.h>
#else #else
// esp8266
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <umm_malloc/umm_heap_select.h>
#ifndef MMU_IRAM_HEAP
#warning Try MMU option '2nd heap shared' in 'tools' IDE menu (cf. https://arduino-esp8266.readthedocs.io/en/latest/mmu.html#option-summary)
#warning use decorators: { HeapSelectIram doAllocationsInIRAM; ESPUI.addControl(...) ... } (cf. https://arduino-esp8266.readthedocs.io/en/latest/mmu.html#how-to-select-heap)
#warning then check http://<ip>/heap
#endif // MMU_IRAM_HEAP
#ifndef DEBUG_ESP_OOM
#error on ESP8266 and ESPUI, you must define OOM debug option when developping
#endif
#endif #endif
const char* ssid = "ESPUI"; const char* ssid = "ESPUI";
@ -235,6 +245,10 @@ void setup(void)
Serial.print("IP address: "); Serial.print("IP address: ");
Serial.println(WiFi.getMode() == WIFI_AP ? WiFi.softAPIP() : WiFi.localIP()); Serial.println(WiFi.getMode() == WIFI_AP ? WiFi.softAPIP() : WiFi.localIP());
#ifdef ESP8266
{ HeapSelectIram doAllocationsInIRAM;
#endif
status = ESPUI.addControl(ControlType::Label, "Status:", "Stop", ControlColor::Turquoise); status = ESPUI.addControl(ControlType::Label, "Status:", "Stop", ControlColor::Turquoise);
uint16_t select1 = ESPUI.addControl( uint16_t select1 = ESPUI.addControl(
@ -281,6 +295,10 @@ void setup(void)
*/ */
ESPUI.begin("ESPUI Control"); ESPUI.begin("ESPUI Control");
#ifdef ESP8266
} // HeapSelectIram
#endif
} }
void loop(void) void loop(void)

View File

@ -8,7 +8,17 @@ DNSServer dnsServer;
#if defined(ESP32) #if defined(ESP32)
#include <WiFi.h> #include <WiFi.h>
#else #else
// esp8266
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <umm_malloc/umm_heap_select.h>
#ifndef MMU_IRAM_HEAP
#warning Try MMU option '2nd heap shared' in 'tools' IDE menu (cf. https://arduino-esp8266.readthedocs.io/en/latest/mmu.html#option-summary)
#warning use decorators: { HeapSelectIram doAllocationsInIRAM; ESPUI.addControl(...) ... } (cf. https://arduino-esp8266.readthedocs.io/en/latest/mmu.html#how-to-select-heap)
#warning then check http://<ip>/heap
#endif // MMU_IRAM_HEAP
#ifndef DEBUG_ESP_OOM
#error on ESP8266 and ESPUI, you must define OOM debug option when developping
#endif
#endif #endif
const char* ssid = "ESPUI"; const char* ssid = "ESPUI";
@ -225,6 +235,10 @@ void setup(void)
Serial.print("IP address: "); Serial.print("IP address: ");
Serial.println(WiFi.getMode() == WIFI_AP ? WiFi.softAPIP() : WiFi.localIP()); Serial.println(WiFi.getMode() == WIFI_AP ? WiFi.softAPIP() : WiFi.localIP());
#ifdef ESP8266
{ HeapSelectIram doAllocationsInIRAM;
#endif
statusLabelId = ESPUI.label("Status:", ControlColor::Turquoise, "Stop"); statusLabelId = ESPUI.label("Status:", ControlColor::Turquoise, "Stop");
millisLabelId = ESPUI.label("Millis:", ControlColor::Emerald, "0"); millisLabelId = ESPUI.label("Millis:", ControlColor::Emerald, "0");
ESPUI.button("Push Button", &buttonCallback, ControlColor::Peterriver, "Press"); ESPUI.button("Push Button", &buttonCallback, ControlColor::Peterriver, "Press");
@ -257,6 +271,10 @@ void setup(void)
* password, for example begin("ESPUI Control", "username", "password") * password, for example begin("ESPUI Control", "username", "password")
*/ */
ESPUI.begin("ESPUI Control"); ESPUI.begin("ESPUI Control");
#ifdef ESP8266
} // HeapSelectIram
#endif
} }
void loop(void) void loop(void)

View File

@ -8,7 +8,17 @@ DNSServer dnsServer;
#if defined(ESP32) #if defined(ESP32)
#include <WiFi.h> #include <WiFi.h>
#else #else
// esp8266
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <umm_malloc/umm_heap_select.h>
#ifndef MMU_IRAM_HEAP
#warning Try MMU option '2nd heap shared' in 'tools' IDE menu (cf. https://arduino-esp8266.readthedocs.io/en/latest/mmu.html#option-summary)
#warning use decorators: { HeapSelectIram doAllocationsInIRAM; ESPUI.addControl(...) ... } (cf. https://arduino-esp8266.readthedocs.io/en/latest/mmu.html#how-to-select-heap)
#warning then check http://<ip>/heap
#endif // MMU_IRAM_HEAP
#ifndef DEBUG_ESP_OOM
#error on ESP8266 and ESPUI, you must define OOM debug option when developping
#endif
#endif #endif
const char* ssid = "ESPUI"; const char* ssid = "ESPUI";
@ -233,6 +243,10 @@ void setup(void)
Serial.print("IP address: "); Serial.print("IP address: ");
Serial.println(WiFi.getMode() == WIFI_AP ? WiFi.softAPIP() : WiFi.localIP()); Serial.println(WiFi.getMode() == WIFI_AP ? WiFi.softAPIP() : WiFi.localIP());
#ifdef ESP8266
{ HeapSelectIram doAllocationsInIRAM;
#endif
uint16_t tab1 = ESPUI.addControl(ControlType::Tab, "Settings 1", "Settings 1"); uint16_t tab1 = ESPUI.addControl(ControlType::Tab, "Settings 1", "Settings 1");
uint16_t tab2 = ESPUI.addControl(ControlType::Tab, "Settings 2", "Settings 2"); uint16_t tab2 = ESPUI.addControl(ControlType::Tab, "Settings 2", "Settings 2");
uint16_t tab3 = ESPUI.addControl(ControlType::Tab, "Settings 3", "Settings 3"); uint16_t tab3 = ESPUI.addControl(ControlType::Tab, "Settings 3", "Settings 3");
@ -279,6 +293,10 @@ void setup(void)
*/ */
ESPUI.begin("ESPUI Control"); ESPUI.begin("ESPUI Control");
#ifdef ESP8266
} // HeapSelectIram
#endif
} }
void loop(void) void loop(void)

View File

@ -13,6 +13,61 @@
#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)
{
#if ESP8266
uint32_t hfree;
uint32_t hmax;
uint8_t hfrag;
String result;
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)
@ -1260,7 +1315,8 @@ 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) {
@ -1418,7 +1474,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

@ -87,20 +87,25 @@ enum Verbosity : uint8_t
class ESPUIClass class ESPUIClass
{ {
public: public:
#ifdef ESP32
ESPUIClass() ESPUIClass()
{ {
verbosity = Verbosity::Quiet;
jsonUpdateDocumentSize = 2000;
jsonInitialDocumentSize = 8000;
sliderContinuous = false;
#ifdef ESP32
ControlsSemaphore = xSemaphoreCreateMutex(); ControlsSemaphore = xSemaphoreCreateMutex();
xSemaphoreGive(ControlsSemaphore); xSemaphoreGive(ControlsSemaphore);
#endif // def ESP32
} }
unsigned int jsonUpdateDocumentSize; SemaphoreHandle_t ControlsSemaphore = NULL;
unsigned int jsonInitialDocumentSize; #endif // def ESP32
bool sliderContinuous;
unsigned int jsonUpdateDocumentSize = 2000;
#ifdef ESP8266
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,17 +210,13 @@ 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;
AsyncWebServer* server; AsyncWebServer* server;
protected: protected:
friend class ESPUIclient; friend class ESPUIclient;
friend class ESPUIcontrol; friend class ESPUIcontrol;
#ifdef ESP32
SemaphoreHandle_t ControlsSemaphore = NULL;
#endif // def ESP32
void RemoveToBeDeletedControls(); void RemoveToBeDeletedControls();
AsyncWebSocket* ws; AsyncWebSocket* ws;

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)
{ {
@ -309,7 +345,7 @@ uint32_t ESPUIclient::prepareJSONChunk(uint16_t startindex,
elementcount++; elementcount++;
control->MarshalControl(item, InUpdateMode); control->MarshalControl(item, InUpdateMode);
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)
@ -407,9 +443,8 @@ bool ESPUIclient::SendControlsToClient(uint16_t startidx,
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
@ -454,10 +489,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)