mirror of
https://github.com/s00500/ESPUI.git
synced 2024-11-24 02:10:55 +00:00
Merge pull request #307 from MartinMueller2003/master
This commit is contained in:
commit
2d023cce6d
15
data/js/controls.js
vendored
15
data/js/controls.js
vendored
@ -225,7 +225,7 @@ function handleVisibilityChange() {
|
|||||||
function start() {
|
function start() {
|
||||||
let location = window.location.hostname;
|
let location = window.location.hostname;
|
||||||
let port = window.location.port;
|
let port = window.location.port;
|
||||||
// let location = "192.168.10.219";
|
// let location = "192.168.10.198";
|
||||||
// let port = "";
|
// let port = "";
|
||||||
|
|
||||||
document.addEventListener("visibilitychange", handleVisibilityChange, false);
|
document.addEventListener("visibilitychange", handleVisibilityChange, false);
|
||||||
@ -655,6 +655,7 @@ function start() {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case UI_FRAGMENT:
|
case UI_FRAGMENT:
|
||||||
|
// console.info("Starting Fragment Processing");
|
||||||
let FragmentLen = data.length;
|
let FragmentLen = data.length;
|
||||||
let FragementOffset = data.offset;
|
let FragementOffset = data.offset;
|
||||||
let NextFragmentOffset = FragementOffset + FragmentLen;
|
let NextFragmentOffset = FragementOffset + FragmentLen;
|
||||||
@ -671,6 +672,7 @@ function start() {
|
|||||||
if (!data.hasOwnProperty('control'))
|
if (!data.hasOwnProperty('control'))
|
||||||
{
|
{
|
||||||
console.error("UI_FRAGMENT:Missing control record, skipping control");
|
console.error("UI_FRAGMENT:Missing control record, skipping control");
|
||||||
|
// console.info("Done Fragment Processing");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let control = data.control;
|
let control = data.control;
|
||||||
@ -686,7 +688,8 @@ function start() {
|
|||||||
StartFragmentAssemblyTimer(control.id);
|
StartFragmentAssemblyTimer(control.id);
|
||||||
let TotalRequest = JSON.stringify({ 'id' : control.id, 'offset' : NextFragmentOffset });
|
let TotalRequest = JSON.stringify({ 'id' : control.id, 'offset' : NextFragmentOffset });
|
||||||
websock.send("uifragmentok:" + 0 + ": " + TotalRequest + ":");
|
websock.send("uifragmentok:" + 0 + ": " + TotalRequest + ":");
|
||||||
// console.info("asked for fragment 2");
|
// console.info("asked for fragment " + TotalRequest);
|
||||||
|
// console.info("Done Fragment Processing");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -698,7 +701,8 @@ function start() {
|
|||||||
StartFragmentAssemblyTimer(control.id);
|
StartFragmentAssemblyTimer(control.id);
|
||||||
let TotalRequest = JSON.stringify({ 'id' : control.id, 'offset' : 0 });
|
let TotalRequest = JSON.stringify({ 'id' : control.id, 'offset' : 0 });
|
||||||
websock.send("uifragmentok:" + 0 + ": " + TotalRequest + ":");
|
websock.send("uifragmentok:" + 0 + ": " + TotalRequest + ":");
|
||||||
// console.info("asked for fragment 1");
|
// console.info("asked for fragment " + TotalRequest);
|
||||||
|
// console.info("Done Fragment Processing");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -709,7 +713,8 @@ function start() {
|
|||||||
StartFragmentAssemblyTimer(control.id);
|
StartFragmentAssemblyTimer(control.id);
|
||||||
let TotalRequest = JSON.stringify({ 'id' : control.id, 'offset' : controlAssemblyArray[control.id].length + controlAssemblyArray[control.id].offset });
|
let TotalRequest = JSON.stringify({ 'id' : control.id, 'offset' : controlAssemblyArray[control.id].length + controlAssemblyArray[control.id].offset });
|
||||||
websock.send("uifragmentok:" + 0 + ": " + TotalRequest + ":");
|
websock.send("uifragmentok:" + 0 + ": " + TotalRequest + ":");
|
||||||
// console.info("asked for the expected fragment");
|
// console.info("asked for the expected fragment: " + TotalRequest);
|
||||||
|
// console.info("Done Fragment Processing");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -733,7 +738,9 @@ function start() {
|
|||||||
StartFragmentAssemblyTimer(control.id);
|
StartFragmentAssemblyTimer(control.id);
|
||||||
let TotalRequest = JSON.stringify({ 'id' : control.id, 'offset' : NextFragmentOffset});
|
let TotalRequest = JSON.stringify({ 'id' : control.id, 'offset' : NextFragmentOffset});
|
||||||
websock.send("uifragmentok:" + 0 + ": " + TotalRequest + ":");
|
websock.send("uifragmentok:" + 0 + ": " + TotalRequest + ":");
|
||||||
|
// console.info("asked for the next fragment: " + TotalRequest);
|
||||||
}
|
}
|
||||||
|
// console.info("Done Fragment Processing");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -17,7 +17,8 @@ framework = arduino
|
|||||||
board_build.filesystem = littlefs
|
board_build.filesystem = littlefs
|
||||||
lib_extra_dirs = ../../
|
lib_extra_dirs = ../../
|
||||||
lib_deps =
|
lib_deps =
|
||||||
bblanchon/ArduinoJson @ ^6.18.5
|
; bblanchon/ArduinoJson @ ^6.18.5
|
||||||
|
bblanchon/ArduinoJson @ ^7.0.4
|
||||||
https://github.com/bmedici/ESPAsyncWebServer ; Use a fork of the library that has a bugfix for the compile.... https://github.com/esphome/ESPAsyncWebServer/pull/17
|
https://github.com/bmedici/ESPAsyncWebServer ; Use a fork of the library that has a bugfix for the compile.... https://github.com/esphome/ESPAsyncWebServer/pull/17
|
||||||
|
|
||||||
lib_ignore =
|
lib_ignore =
|
||||||
@ -41,11 +42,12 @@ platform = espressif32
|
|||||||
board = esp32dev
|
board = esp32dev
|
||||||
monitor_filters = esp32_exception_decoder
|
monitor_filters = esp32_exception_decoder
|
||||||
board_build.flash_mode = dout
|
board_build.flash_mode = dout
|
||||||
;build_flags =
|
build_flags =
|
||||||
; -D DEBUG_ESPUI
|
; -D DEBUG_ESPUI
|
||||||
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
me-no-dev/AsyncTCP
|
me-no-dev/AsyncTCP
|
||||||
upload_port = COM9
|
upload_port = COM6
|
||||||
monitor_port = COM9
|
monitor_port = COM6
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
|
@ -11,17 +11,23 @@ DNSServer dnsServer;
|
|||||||
#include <ESP8266WiFi.h>
|
#include <ESP8266WiFi.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const char* ssid = "ESPUI";
|
const char* ssid = "YourNetworkName";
|
||||||
const char* password = "espui";
|
const char* password = "YourNetworkPassphrase";
|
||||||
|
|
||||||
const char* hostname = "espui";
|
const char* hostname = "espui";
|
||||||
|
|
||||||
String DisplayTestFileName = "/FileName.txt";
|
String DisplayTestFileName = "/FileName.txt";
|
||||||
|
int fileDisplayId = Control::noParent;
|
||||||
|
|
||||||
int statusLabelId = Control::noParent;
|
int statusLabelId = Control::noParent;
|
||||||
|
|
||||||
|
#ifdef TEST_GRAPH
|
||||||
int graphId = Control::noParent;
|
int graphId = Control::noParent;
|
||||||
|
#endif // def TEST_GRAPH
|
||||||
int millisLabelId = Control::noParent;
|
int millisLabelId = Control::noParent;
|
||||||
int testSwitchId = Control::noParent;
|
int testSwitchId = Control::noParent;
|
||||||
int fileDisplayId = Control::noParent;
|
|
||||||
|
char HugeText[1025];
|
||||||
|
|
||||||
void numberCall(Control* sender, int type)
|
void numberCall(Control* sender, int type)
|
||||||
{
|
{
|
||||||
@ -166,6 +172,9 @@ void setup(void)
|
|||||||
ESPUI.setVerbosity(Verbosity::VerboseJSON);
|
ESPUI.setVerbosity(Verbosity::VerboseJSON);
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
memset(HugeText, 0x0, sizeof(HugeText));
|
||||||
|
memset(HugeText, 'a', sizeof(HugeText)-1);
|
||||||
|
|
||||||
#if defined(ESP32)
|
#if defined(ESP32)
|
||||||
WiFi.setHostname(hostname);
|
WiFi.setHostname(hostname);
|
||||||
#else
|
#else
|
||||||
@ -239,10 +248,16 @@ void setup(void)
|
|||||||
ESPUI.slider("Slider one", &slider, ControlColor::Alizarin, 30, 0, 30);
|
ESPUI.slider("Slider one", &slider, ControlColor::Alizarin, 30, 0, 30);
|
||||||
ESPUI.slider("Slider two", &slider, ControlColor::None, 100);
|
ESPUI.slider("Slider two", &slider, ControlColor::None, 100);
|
||||||
ESPUI.text("Text Test:", &textCall, ControlColor::Alizarin, "a Text Field");
|
ESPUI.text("Text Test:", &textCall, ControlColor::Alizarin, "a Text Field");
|
||||||
|
|
||||||
|
ESPUI.text("Huge Text Test:", &textCall, ControlColor::Alizarin, HugeText);
|
||||||
|
|
||||||
ESPUI.number("Numbertest", &numberCall, ControlColor::Alizarin, 5, 0, 10);
|
ESPUI.number("Numbertest", &numberCall, ControlColor::Alizarin, 5, 0, 10);
|
||||||
|
|
||||||
fileDisplayId = ESPUI.fileDisplay("Filetest", ControlColor::Turquoise, DisplayTestFileName);
|
fileDisplayId = ESPUI.fileDisplay("Filetest", ControlColor::Turquoise, DisplayTestFileName);
|
||||||
|
|
||||||
|
#ifdef TEST_GRAPH
|
||||||
graphId = ESPUI.graph("Graph Test", ControlColor::Wetasphalt);
|
graphId = ESPUI.graph("Graph Test", ControlColor::Wetasphalt);
|
||||||
|
#endif // def TEST_GRAPH
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* .begin loads and serves all files from PROGMEM directly.
|
* .begin loads and serves all files from PROGMEM directly.
|
||||||
@ -261,15 +276,17 @@ void setup(void)
|
|||||||
* password, for example begin("ESPUI Control", "username", "password")
|
* password, for example begin("ESPUI Control", "username", "password")
|
||||||
*/
|
*/
|
||||||
ESPUI.sliderContinuous = true;
|
ESPUI.sliderContinuous = true;
|
||||||
ESPUI.prepareFileSystem();
|
|
||||||
ESPUI.beginLITTLEFS("ESPUI Control");
|
|
||||||
|
|
||||||
// create a text file
|
ESPUI.prepareFileSystem();
|
||||||
ESPUI.writeFile("/DisplayFile.txt", "Test Line\n");
|
|
||||||
|
ESPUI.beginLITTLEFS("ESPUI Control");
|
||||||
|
|
||||||
// these files are used by browsers to auto config a connection.
|
// these files are used by browsers to auto config a connection.
|
||||||
ESPUI.writeFile("/wpad.dat", " ");
|
ESPUI.writeFile("/wpad.dat", " ");
|
||||||
ESPUI.writeFile("/connecttest.txt", " ");
|
ESPUI.writeFile("/connecttest.txt", " ");
|
||||||
|
|
||||||
|
// create a text file
|
||||||
|
ESPUI.writeFile("/DisplayFile.txt", "Test Line\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop(void)
|
void loop(void)
|
||||||
@ -284,7 +301,9 @@ void loop(void)
|
|||||||
{
|
{
|
||||||
ESPUI.print(millisLabelId, String(millis()));
|
ESPUI.print(millisLabelId, String(millis()));
|
||||||
|
|
||||||
|
#ifdef TEST_GRAPH
|
||||||
ESPUI.addGraphPoint(graphId, random(1, 50));
|
ESPUI.addGraphPoint(graphId, random(1, 50));
|
||||||
|
#endif // def TEST_GRAPH
|
||||||
|
|
||||||
testSwitchState = !testSwitchState;
|
testSwitchState = !testSwitchState;
|
||||||
ESPUI.updateSwitcher(testSwitchId, testSwitchState);
|
ESPUI.updateSwitcher(testSwitchId, testSwitchState);
|
||||||
@ -298,7 +317,7 @@ void loop(void)
|
|||||||
{
|
{
|
||||||
testFile.write((const uint8_t*)TestLine.c_str(), TestLine.length());
|
testFile.write((const uint8_t*)TestLine.c_str(), TestLine.length());
|
||||||
ESPUI.updateControl(fileDisplayId);
|
ESPUI.updateControl(fileDisplayId);
|
||||||
|
|
||||||
TestLine += String("filesize: ") + String(filesize);
|
TestLine += String("filesize: ") + String(filesize);
|
||||||
// Serial.println(TestLine);
|
// Serial.println(TestLine);
|
||||||
}
|
}
|
||||||
|
@ -932,7 +932,7 @@ void ESPUIClass::clearGraph(uint16_t id, int clientId)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicJsonDocument document(jsonUpdateDocumentSize);
|
AllocateJsonDocument(document, jsonUpdateDocumentSize);
|
||||||
JsonObject root = document.to<JsonObject>();
|
JsonObject root = document.to<JsonObject>();
|
||||||
|
|
||||||
root[F("type")] = (int)ControlType::Graph + UpdateOffset;
|
root[F("type")] = (int)ControlType::Graph + UpdateOffset;
|
||||||
@ -954,7 +954,7 @@ void ESPUIClass::addGraphPoint(uint16_t id, int nValue, int clientId)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicJsonDocument document(jsonUpdateDocumentSize);
|
AllocateJsonDocument(document, jsonUpdateDocumentSize);
|
||||||
JsonObject root = document.to<JsonObject>();
|
JsonObject root = document.to<JsonObject>();
|
||||||
|
|
||||||
root[F("type")] = (int)ControlType::GraphPoint;
|
root[F("type")] = (int)ControlType::GraphPoint;
|
||||||
@ -966,7 +966,7 @@ void ESPUIClass::addGraphPoint(uint16_t id, int nValue, int clientId)
|
|||||||
} while (false);
|
} while (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ESPUIClass::SendJsonDocToWebSocket(ArduinoJson::DynamicJsonDocument& document, uint16_t clientId)
|
bool ESPUIClass::SendJsonDocToWebSocket(ArduinoJson::JsonDocument& document, uint16_t clientId)
|
||||||
{
|
{
|
||||||
bool Response = false;
|
bool Response = false;
|
||||||
|
|
||||||
|
19
src/ESPUI.h
19
src/ESPUI.h
@ -5,7 +5,20 @@
|
|||||||
#define WS_AUTHENTICATION false
|
#define WS_AUTHENTICATION false
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
|
#if ARDUINOJSON_VERSION_MAJOR > 6
|
||||||
|
#define AllocateJsonDocument(name, size) JsonDocument name
|
||||||
|
#define AllocateJsonArray(doc, name) doc[name].to<JsonArray>()
|
||||||
|
#define AllocateJsonObject(doc) doc.add<JsonObject>()
|
||||||
|
#define AllocateNamedJsonObject(t, s, n) t[n] = s
|
||||||
|
#else
|
||||||
|
#define AllocateJsonDocument(name, size) DynamicJsonDocument name(size)
|
||||||
|
#define AllocateJsonArray(doc, name) doc.createNestedArray(name)
|
||||||
|
#define AllocateJsonObject(doc) doc.createNestedObject()
|
||||||
|
#define AllocateNamedJsonObject(t, s, n) t = s.createNestedObject(n)
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdlib_noniso.h>
|
#include <stdlib_noniso.h>
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
#if (ESP_IDF_VERSION_MAJOR == 4 && ESP_IDF_VERSION_MINOR >= 4) || ESP_IDF_VERSION_MAJOR > 4
|
#if (ESP_IDF_VERSION_MAJOR == 4 && ESP_IDF_VERSION_MINOR >= 4) || ESP_IDF_VERSION_MAJOR > 4
|
||||||
@ -34,10 +47,10 @@
|
|||||||
#include <ESPAsyncTCP.h>
|
#include <ESPAsyncTCP.h>
|
||||||
#include <Hash.h>
|
#include <Hash.h>
|
||||||
|
|
||||||
#define FILE_WRITING "w"
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define FILE_WRITING "w"
|
||||||
|
|
||||||
// Message Types (and control types)
|
// Message Types (and control types)
|
||||||
|
|
||||||
enum MessageTypes : uint8_t
|
enum MessageTypes : uint8_t
|
||||||
@ -271,7 +284,7 @@ protected:
|
|||||||
void NotifyClients(ClientUpdateType_t newState);
|
void NotifyClients(ClientUpdateType_t newState);
|
||||||
void NotifyClient(uint32_t WsClientId, ClientUpdateType_t newState);
|
void NotifyClient(uint32_t WsClientId, ClientUpdateType_t newState);
|
||||||
|
|
||||||
bool SendJsonDocToWebSocket(ArduinoJson::DynamicJsonDocument& document, uint16_t clientId);
|
bool SendJsonDocToWebSocket(ArduinoJson::JsonDocument& document, uint16_t clientId);
|
||||||
|
|
||||||
std::map<uint32_t, ESPUIclient*> MapOfClients;
|
std::map<uint32_t, ESPUIclient*> MapOfClients;
|
||||||
|
|
||||||
|
@ -74,14 +74,14 @@ bool ESPUIclient::CanSend()
|
|||||||
return Response;
|
return Response;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESPUIclient::FillInHeader(DynamicJsonDocument& document)
|
void ESPUIclient::FillInHeader(JsonDocument& document)
|
||||||
{
|
{
|
||||||
document[F("type")] = UI_EXTEND_GUI;
|
document[F("type")] = UI_EXTEND_GUI;
|
||||||
document[F("sliderContinuous")] = ESPUI.sliderContinuous;
|
document[F("sliderContinuous")] = ESPUI.sliderContinuous;
|
||||||
document[F("startindex")] = 0;
|
document[F("startindex")] = 0;
|
||||||
document[F("totalcontrols")] = ESPUI.controlCount;
|
document[F("totalcontrols")] = ESPUI.controlCount;
|
||||||
JsonArray items = document.createNestedArray(F("controls"));
|
JsonArray items = AllocateJsonArray(document, F("controls"));
|
||||||
JsonObject titleItem = items.createNestedObject();
|
JsonObject titleItem = AllocateJsonObject(items);
|
||||||
titleItem[F("type")] = (int)UI_TITLE;
|
titleItem[F("type")] = (int)UI_TITLE;
|
||||||
titleItem[F("label")] = ESPUI.ui_title;
|
titleItem[F("label")] = ESPUI.ui_title;
|
||||||
}
|
}
|
||||||
@ -104,7 +104,7 @@ bool ESPUIclient::SendClientNotification(ClientUpdateType_t value)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicJsonDocument document(ESPUI.jsonUpdateDocumentSize);
|
AllocateJsonDocument(document, ESPUI.jsonUpdateDocumentSize);
|
||||||
FillInHeader(document);
|
FillInHeader(document);
|
||||||
if(ClientUpdateType_t::ReloadNeeded == value)
|
if(ClientUpdateType_t::ReloadNeeded == value)
|
||||||
{
|
{
|
||||||
@ -259,7 +259,7 @@ number this will represent the entire UI. More likely, it will represent a small
|
|||||||
client will acknowledge receipt by requesting the next chunk.
|
client will acknowledge receipt by requesting the next chunk.
|
||||||
*/
|
*/
|
||||||
uint32_t ESPUIclient::prepareJSONChunk(uint16_t startindex,
|
uint32_t ESPUIclient::prepareJSONChunk(uint16_t startindex,
|
||||||
DynamicJsonDocument & rootDoc,
|
JsonDocument & rootDoc,
|
||||||
bool InUpdateMode,
|
bool InUpdateMode,
|
||||||
String FragmentRequestString)
|
String FragmentRequestString)
|
||||||
{
|
{
|
||||||
@ -267,8 +267,12 @@ uint32_t ESPUIclient::prepareJSONChunk(uint16_t startindex,
|
|||||||
xSemaphoreTake(ESPUI.ControlsSemaphore, portMAX_DELAY);
|
xSemaphoreTake(ESPUI.ControlsSemaphore, portMAX_DELAY);
|
||||||
#endif // def ESP32
|
#endif // def ESP32
|
||||||
|
|
||||||
// Serial.println(String("prepareJSONChunk: Start. InUpdateMode: ") + String(InUpdateMode));
|
// Serial.println(String("prepareJSONChunk: Start. InUpdateMode: ") + String(InUpdateMode));
|
||||||
|
// Serial.println(String("prepareJSONChunk: Start. startindex: ") + String(startindex));
|
||||||
|
// Serial.println(String("prepareJSONChunk: Start. FragmentRequestString: '") + FragmentRequestString + "'");
|
||||||
int elementcount = 0;
|
int elementcount = 0;
|
||||||
|
uint32_t MaxMarshaledJsonSize = (!InUpdateMode) ? ESPUI.jsonInitialDocumentSize: ESPUI.jsonUpdateDocumentSize;
|
||||||
|
uint32_t EstimatedUsedMarshaledJsonSize = 0;
|
||||||
|
|
||||||
do // once
|
do // once
|
||||||
{
|
{
|
||||||
@ -289,12 +293,15 @@ uint32_t ESPUIclient::prepareJSONChunk(uint16_t startindex,
|
|||||||
// this is actually a fragment or directed update request
|
// this is actually a fragment or directed update request
|
||||||
// parse the string we got from the UI and try to update that specific
|
// parse the string we got from the UI and try to update that specific
|
||||||
// control.
|
// control.
|
||||||
DynamicJsonDocument FragmentRequest(FragmentRequestString.length() * 3);
|
AllocateJsonDocument(FragmentRequest, FragmentRequestString.length() * 3);
|
||||||
|
/*
|
||||||
|
ArduinoJson::detail::sizeofObject(N);
|
||||||
if(0 >= FragmentRequest.capacity())
|
if(0 >= FragmentRequest.capacity())
|
||||||
{
|
{
|
||||||
Serial.println(F("ERROR:prepareJSONChunk:Fragmentation:Could not allocate memory for a fragmentation request. Skipping Response"));
|
Serial.println(F("ERROR:prepareJSONChunk:Fragmentation:Could not allocate memory for a fragmentation request. Skipping Response"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
size_t FragmentRequestStartOffset = FragmentRequestString.indexOf("{");
|
size_t FragmentRequestStartOffset = FragmentRequestString.indexOf("{");
|
||||||
DeserializationError error = deserializeJson(FragmentRequest, FragmentRequestString.substring(FragmentRequestStartOffset));
|
DeserializationError error = deserializeJson(FragmentRequest, FragmentRequestString.substring(FragmentRequestStartOffset));
|
||||||
if(DeserializationError::Ok != error)
|
if(DeserializationError::Ok != error)
|
||||||
@ -386,19 +393,35 @@ uint32_t ESPUIclient::prepareJSONChunk(uint16_t startindex,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonObject item = items.createNestedObject();
|
// Serial.println(String(F("prepareJSONChunk: MaxMarshaledJsonSize: ")) + String(MaxMarshaledJsonSize));
|
||||||
|
// Serial.println(String(F("prepareJSONChunk: Cur EstimatedUsedMarshaledJsonSize: ")) + String(EstimatedUsedMarshaledJsonSize));
|
||||||
|
|
||||||
|
JsonObject item = AllocateJsonObject(items);
|
||||||
elementcount++;
|
elementcount++;
|
||||||
control->MarshalControl(item, InUpdateMode, DataOffset);
|
uint32_t RemainingSpace = (MaxMarshaledJsonSize - EstimatedUsedMarshaledJsonSize) - 100;
|
||||||
|
// Serial.println(String(F("prepareJSONChunk: RemainingSpace: ")) + String(RemainingSpace));
|
||||||
if (rootDoc.overflowed() || (ESPUI.jsonChunkNumberMax > 0 && (elementcount % ESPUI.jsonChunkNumberMax) == 0))
|
uint32_t SpaceUsedByMarshaledControl = 0;
|
||||||
|
bool ControlIsFragmented = control->MarshalControl(item,
|
||||||
|
InUpdateMode,
|
||||||
|
DataOffset,
|
||||||
|
RemainingSpace,
|
||||||
|
SpaceUsedByMarshaledControl);
|
||||||
|
// Serial.println(String(F("prepareJSONChunk: SpaceUsedByMarshaledControl: ")) + String(SpaceUsedByMarshaledControl));
|
||||||
|
EstimatedUsedMarshaledJsonSize += SpaceUsedByMarshaledControl;
|
||||||
|
// Serial.println(String(F("prepareJSONChunk: New EstimatedUsedMarshaledJsonSize: ")) + String(EstimatedUsedMarshaledJsonSize));
|
||||||
|
// Serial.println(String(F("prepareJSONChunk: ControlIsFragmented: ")) + String(ControlIsFragmented));
|
||||||
|
|
||||||
|
// did the control get added to the doc?
|
||||||
|
if (0 == SpaceUsedByMarshaledControl ||
|
||||||
|
(ESPUI.jsonChunkNumberMax > 0 && (elementcount % ESPUI.jsonChunkNumberMax) == 0))
|
||||||
{
|
{
|
||||||
// String("prepareJSONChunk: too much data in the message. Remove the last entry");
|
// Serial.println( String("prepareJSONChunk: too much data in the message. Remove the last entry"));
|
||||||
if (1 == elementcount)
|
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("prepareJSONChunk: Control ")) + String(control->id) + F(" is too large to be sent to the browser."));
|
||||||
// Serial.println(String(F("ERROR: prepareJSONChunk: value: ")) + control->value);
|
// Serial.println(String(F("ERROR: prepareJSONChunk: value: ")) + control->value);
|
||||||
rootDoc.clear();
|
rootDoc.clear();
|
||||||
item = items.createNestedObject();
|
item = AllocateJsonObject(items);
|
||||||
control->MarshalErrorMessage(item);
|
control->MarshalErrorMessage(item);
|
||||||
elementcount = 0;
|
elementcount = 0;
|
||||||
}
|
}
|
||||||
@ -413,13 +436,16 @@ uint32_t ESPUIclient::prepareJSONChunk(uint16_t startindex,
|
|||||||
// exit the loop
|
// exit the loop
|
||||||
control = nullptr;
|
control = nullptr;
|
||||||
}
|
}
|
||||||
else if (SingleControl)
|
else if ((SingleControl) ||
|
||||||
|
(ControlIsFragmented) ||
|
||||||
|
(MaxMarshaledJsonSize < (EstimatedUsedMarshaledJsonSize + 100)))
|
||||||
{
|
{
|
||||||
// Serial.println("prepareJSONChunk: exit loop");
|
// Serial.println("prepareJSONChunk: Doc is Full, Fragmented Control or Single Control. exit loop");
|
||||||
control = nullptr;
|
control = nullptr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Serial.println("prepareJSONChunk: Next Control");
|
||||||
control = control->next;
|
control = control->next;
|
||||||
}
|
}
|
||||||
} // end while (control != nullptr)
|
} // end while (control != nullptr)
|
||||||
@ -430,7 +456,7 @@ uint32_t ESPUIclient::prepareJSONChunk(uint16_t startindex,
|
|||||||
xSemaphoreGive(ESPUI.ControlsSemaphore);
|
xSemaphoreGive(ESPUI.ControlsSemaphore);
|
||||||
#endif // def ESP32
|
#endif // def ESP32
|
||||||
|
|
||||||
// Serial.println(String("prepareJSONChunk: elementcount: ") + String(elementcount));
|
// Serial.println(String("prepareJSONChunk: END: elementcount: ") + String(elementcount));
|
||||||
return elementcount;
|
return elementcount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -473,7 +499,7 @@ bool ESPUIclient::SendControlsToClient(uint16_t startidx, ClientUpdateType_t Tra
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicJsonDocument document(ESPUI.jsonInitialDocumentSize);
|
AllocateJsonDocument(document, ESPUI.jsonInitialDocumentSize);
|
||||||
FillInHeader(document);
|
FillInHeader(document);
|
||||||
document[F("startindex")] = startidx;
|
document[F("startindex")] = startidx;
|
||||||
document[F("totalcontrols")] = uint16_t(-1); // ESPUI.controlCount;
|
document[F("totalcontrols")] = uint16_t(-1); // ESPUI.controlCount;
|
||||||
@ -521,7 +547,7 @@ bool ESPUIclient::SendControlsToClient(uint16_t startidx, ClientUpdateType_t Tra
|
|||||||
return Response;
|
return Response;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ESPUIclient::SendJsonDocToWebSocket(DynamicJsonDocument& document)
|
bool ESPUIclient::SendJsonDocToWebSocket(JsonDocument& document)
|
||||||
{
|
{
|
||||||
bool Response = true;
|
bool Response = true;
|
||||||
|
|
||||||
|
@ -43,8 +43,8 @@ protected:
|
|||||||
// bool NeedsNotification() { return pCurrentFsmState != &fsm_EspuiClient_state_Idle_imp; }
|
// bool NeedsNotification() { return pCurrentFsmState != &fsm_EspuiClient_state_Idle_imp; }
|
||||||
|
|
||||||
bool CanSend();
|
bool CanSend();
|
||||||
void FillInHeader(ArduinoJson::DynamicJsonDocument& document);
|
void FillInHeader(ArduinoJson::JsonDocument& document);
|
||||||
uint32_t prepareJSONChunk(uint16_t startindex, DynamicJsonDocument& rootDoc, bool InUpdateMode, String value);
|
uint32_t prepareJSONChunk(uint16_t startindex, JsonDocument& rootDoc, bool InUpdateMode, String value);
|
||||||
bool SendControlsToClient(uint16_t startidx, ClientUpdateType_t TransferMode, String FragmentRequest);
|
bool SendControlsToClient(uint16_t startidx, ClientUpdateType_t TransferMode, String FragmentRequest);
|
||||||
|
|
||||||
bool SendClientNotification(ClientUpdateType_t value);
|
bool SendClientNotification(ClientUpdateType_t value);
|
||||||
@ -62,6 +62,6 @@ public:
|
|||||||
bool IsSyncronized();
|
bool IsSyncronized();
|
||||||
uint32_t id() { return client->id(); }
|
uint32_t id() { return client->id(); }
|
||||||
void SetState(ClientUpdateType_t value);
|
void SetState(ClientUpdateType_t value);
|
||||||
bool SendJsonDocToWebSocket(ArduinoJson::DynamicJsonDocument& document);
|
bool SendJsonDocToWebSocket(ArduinoJson::JsonDocument& document);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -48,20 +48,70 @@ void Control::DeleteControl()
|
|||||||
callback = nullptr;
|
callback = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Control::MarshalControl(JsonObject & _item, bool refresh, uint32_t StartingOffset)
|
bool Control::MarshalControl(JsonObject & _item,
|
||||||
|
bool refresh,
|
||||||
|
uint32_t StartingOffset,
|
||||||
|
uint32_t AvailMarshaledLength,
|
||||||
|
uint32_t &EstimatedMarshaledLength)
|
||||||
{
|
{
|
||||||
JsonObject & item = _item;
|
// this code assumes MaxMarshaledLength > JsonMarshalingRatio
|
||||||
uint32_t length = value.length();
|
// Serial.println(String("MarshalControl: StartingOffset: ") + String(StartingOffset));
|
||||||
uint32_t maxLength = uint32_t(double(ESPUI.jsonInitialDocumentSize) * 0.75);
|
// Serial.println(String("MarshalControl: AvailMarshaledLength: ") + String(AvailMarshaledLength));
|
||||||
if((length > maxLength) || StartingOffset)
|
// Serial.println(String("MarshalControl: Control ID: ") + String(id));
|
||||||
{
|
|
||||||
/*
|
|
||||||
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));
|
|
||||||
|
|
||||||
|
bool ControlIsFragmented = false;
|
||||||
|
// create a new item in the response document
|
||||||
|
JsonObject & item = _item;
|
||||||
|
|
||||||
|
// how much space do we expect to use?
|
||||||
|
uint32_t ValueMarshaledLength = (value.length() - StartingOffset) * JsonMarshalingRatio;
|
||||||
|
uint32_t LabelMarshaledLength = strlen(label) * JsonMarshalingRatio;
|
||||||
|
uint32_t MinimumMarshaledLength = LabelMarshaledLength + JsonMarshaledOverhead;
|
||||||
|
uint32_t MaximumMarshaledLength = ValueMarshaledLength + MinimumMarshaledLength;
|
||||||
|
uint32_t SpaceForMarshaledValue = AvailMarshaledLength - MinimumMarshaledLength;
|
||||||
|
// Serial.println(String("MarshalControl: value.length(): ") + String(value.length()));
|
||||||
|
// Serial.println(String("MarshalControl: ValueMarshaledLength: ") + String(ValueMarshaledLength));
|
||||||
|
// Serial.println(String("MarshalControl: LabelMarshaledLength: ") + String(LabelMarshaledLength));
|
||||||
|
// Serial.println(String("MarshalControl: MaximumMarshaledLength: ") + String(MaximumMarshaledLength));
|
||||||
|
// Serial.println(String("MarshalControl: MinimumMarshaledLength: ") + String(MinimumMarshaledLength));
|
||||||
|
// Serial.println(String("MarshalControl: SpaceForMarshaledValue: ") + String(SpaceForMarshaledValue));
|
||||||
|
|
||||||
|
// will the item fit in the remaining space? Fragment if not
|
||||||
|
if (AvailMarshaledLength < MinimumMarshaledLength)
|
||||||
|
{
|
||||||
|
// Serial.println(String("MarshalControl: Cannot Marshal control. Not enough space for basic headers."));
|
||||||
|
EstimatedMarshaledLength = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t MaxValueLength = (SpaceForMarshaledValue / JsonMarshalingRatio);
|
||||||
|
// Serial.println(String("MarshalControl: MaxValueLength: ") + String(MaxValueLength));
|
||||||
|
|
||||||
|
uint32_t ValueLenToSend = min((value.length() - StartingOffset), MaxValueLength);
|
||||||
|
// Serial.println(String("MarshalControl: ValueLenToSend: ") + String(ValueLenToSend));
|
||||||
|
|
||||||
|
uint32_t AdjustedMarshaledLength = (ValueLenToSend * JsonMarshalingRatio) + MinimumMarshaledLength;
|
||||||
|
// Serial.println(String("MarshalControl: AdjustedMarshaledLength: ") + String(AdjustedMarshaledLength));
|
||||||
|
|
||||||
|
bool NeedToFragment = (ValueLenToSend < value.length());
|
||||||
|
// Serial.println(String("MarshalControl: NeedToFragment: ") + String(NeedToFragment));
|
||||||
|
|
||||||
|
if ((AdjustedMarshaledLength > AvailMarshaledLength) && (0 != ValueLenToSend))
|
||||||
|
{
|
||||||
|
// Serial.println(String("MarshalControl: Cannot Marshal control. Not enough space for marshaled control."));
|
||||||
|
EstimatedMarshaledLength = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
EstimatedMarshaledLength = AdjustedMarshaledLength;
|
||||||
|
|
||||||
|
// are we fragmenting?
|
||||||
|
if(NeedToFragment || StartingOffset)
|
||||||
|
{
|
||||||
|
// Serial.println(String("MarshalControl:Start Fragment Processing"));
|
||||||
|
// Serial.println(String("MarshalControl:id: ") + String(id));
|
||||||
|
// Serial.println(String("MarshalControl:StartingOffset: ") + String(StartingOffset));
|
||||||
|
/*
|
||||||
if(0 == StartingOffset)
|
if(0 == StartingOffset)
|
||||||
{
|
{
|
||||||
Serial.println(String("MarshalControl: New control to fragement. ID: ") + String(id));
|
Serial.println(String("MarshalControl: New control to fragement. ID: ") + String(id));
|
||||||
@ -70,19 +120,20 @@ void Control::MarshalControl(JsonObject & _item, bool refresh, uint32_t Starting
|
|||||||
{
|
{
|
||||||
Serial.println(String("MarshalControl: Next fragement. ID: ") + String(id));
|
Serial.println(String("MarshalControl: Next fragement. ID: ") + String(id));
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// indicate that no additional controls should be sent
|
// indicate that no additional controls should be sent
|
||||||
|
ControlIsFragmented = true;
|
||||||
|
|
||||||
|
// fill in the fragment header
|
||||||
_item[F("type")] = uint32_t(ControlType::Fragment);
|
_item[F("type")] = uint32_t(ControlType::Fragment);
|
||||||
_item[F("id")] = id;
|
_item[F("id")] = id;
|
||||||
|
|
||||||
length = min((length - StartingOffset), maxLength);
|
|
||||||
// Serial.println(String("MarshalControl:Final length: ") + String(length));
|
// Serial.println(String("MarshalControl:Final length: ") + String(length));
|
||||||
|
|
||||||
_item[F("offset")] = StartingOffset;
|
_item[F("offset")] = StartingOffset;
|
||||||
_item[F("length")] = length;
|
_item[F("length")] = ValueLenToSend;
|
||||||
_item[F("total")] = value.length();
|
_item[F("total")] = value.length();
|
||||||
item = _item.createNestedObject(F("control"));
|
AllocateNamedJsonObject(item, _item, F("control"));
|
||||||
}
|
}
|
||||||
|
|
||||||
item[F("id")] = id;
|
item[F("id")] = id;
|
||||||
@ -97,7 +148,7 @@ void Control::MarshalControl(JsonObject & _item, bool refresh, uint32_t Starting
|
|||||||
}
|
}
|
||||||
|
|
||||||
item[F("label")] = label;
|
item[F("label")] = label;
|
||||||
item[F ("value")] = (ControlType::Password == type) ? F ("--------") : value.substring(StartingOffset, length + StartingOffset);
|
item[F ("value")] = (ControlType::Password == type) ? F ("--------") : value.substring(StartingOffset, StartingOffset + ValueLenToSend);
|
||||||
item[F("visible")] = visible;
|
item[F("visible")] = visible;
|
||||||
item[F("color")] = (int)color;
|
item[F("color")] = (int)color;
|
||||||
item[F("enabled")] = enabled;
|
item[F("enabled")] = enabled;
|
||||||
@ -130,6 +181,9 @@ void Control::MarshalControl(JsonObject & _item, bool refresh, uint32_t Starting
|
|||||||
item[F("selected")] = "";
|
item[F("selected")] = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Serial.println(String("MarshalControl:Done"));
|
||||||
|
return ControlIsFragmented;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Control::MarshalErrorMessage(JsonObject & item)
|
void Control::MarshalErrorMessage(JsonObject & item)
|
||||||
@ -280,4 +334,3 @@ void Control::onWsEvent(String & cmd, String& data)
|
|||||||
}
|
}
|
||||||
} while (false);
|
} while (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,18 +83,23 @@ public:
|
|||||||
|
|
||||||
void SendCallback(int type);
|
void SendCallback(int type);
|
||||||
bool HasCallback() { return (nullptr != callback); }
|
bool HasCallback() { return (nullptr != callback); }
|
||||||
void MarshalControl(ArduinoJson::JsonObject& item, bool refresh, uint32_t DataOffset);
|
bool MarshalControl(ArduinoJson::JsonObject& item, bool refresh, uint32_t DataOffset, uint32_t MaxLength, uint32_t & EstimmatedUsedSpace);
|
||||||
void MarshalErrorMessage(ArduinoJson::JsonObject& item);
|
void MarshalErrorMessage(ArduinoJson::JsonObject& item);
|
||||||
void DeleteControl();
|
void DeleteControl();
|
||||||
void onWsEvent(String& cmd, String& data);
|
void onWsEvent(String& cmd, String& data);
|
||||||
inline bool ToBeDeleted() { return _ToBeDeleted; }
|
inline bool ToBeDeleted() { return _ToBeDeleted; }
|
||||||
inline bool NeedsSync(uint32_t lastControlChangeID) {return (false == _ToBeDeleted) && (lastControlChangeID < ControlChangeID);}
|
inline bool NeedsSync(uint32_t lastControlChangeID) {return (false == _ToBeDeleted) && (lastControlChangeID < ControlChangeID);}
|
||||||
void SetControlChangedId(uint32_t value) {ControlChangeID = value;}
|
void SetControlChangedId(uint32_t value) {ControlChangeID = value;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _ToBeDeleted = false;
|
bool _ToBeDeleted = false;
|
||||||
uint32_t ControlChangeID = 0;
|
uint32_t ControlChangeID = 0;
|
||||||
String OldValue = emptyString;
|
String OldValue = emptyString;
|
||||||
|
|
||||||
|
// multiplier for converting a typical controller label or value to a Json object
|
||||||
|
#define JsonMarshalingRatio 3
|
||||||
|
// Marshaed Control overhead length
|
||||||
|
#define JsonMarshaledOverhead 64
|
||||||
};
|
};
|
||||||
|
|
||||||
#define UI_TITLE ControlType::Title
|
#define UI_TITLE ControlType::Title
|
||||||
|
Loading…
Reference in New Issue
Block a user