From fe75655eccb158456286c259dd3dcf8fc9a3aeeb Mon Sep 17 00:00:00 2001 From: Nikola Kirov Date: Wed, 13 Dec 2023 09:27:21 +0200 Subject: [PATCH] Update --- README.md | 27 ++- data/js/controls.js | 170 +------------- data/js/controls.min.js | 233 +++++++++---------- examples/completeExample/completeExample.cpp | 6 +- examples/completeExample/completeExample.ino | 3 - examples/gui-generic-api/gui-generic-api.ino | 7 +- examples/gui/gui.ino | 5 +- examples/tabbedGui/tabbedGui.ino | 5 +- library.json | 5 + src/ESPUI.cpp | 154 ++++++------ src/ESPUIclient.cpp | 127 +++++----- 11 files changed, 295 insertions(+), 447 deletions(-) diff --git a/README.md b/README.md index dffefc9..4659d70 100644 --- a/README.md +++ b/README.md @@ -62,9 +62,6 @@ The Library runs on any kind of **ESP8266** and **ESP32** (NodeMCU, AI Thinker, - Time control by @iangray001 - Vertical controls by @iangray001 - Time/date/password/color input types by @pcbbc -- Delayed response support @MartinMueller2003 -- Fragmented control transfer @ MartinMueller2003 -- Extended Callback @MartinMueller2003 ## Roadmap @@ -156,9 +153,7 @@ This section will explain in detail how the Library is to be used from the Ardui

Alternativly you may use the extended callback funtion which provides three parameters to the callback function `myCallback(Control *sender, int eventname, void * UserParameter)`. The `UserParameter` is provided as part of the `ESPUI.addControl` method set and allows the user to define contextual information that is to be presented to the callback function in an unmodified form.

-It also possible to use a lambda function in the callback parameter. It also allows the user to define, in a more C++ way, contextual information in any form. This is shown by the [completeLambda](examples/completeLambda/completeLambda.ino) example. -

-The below example creates a button and defines a lambda function to invoke a more specialized button callback handler: +The below example creates a button and defines a lambda function to implicitly create an `ExtendedCallback` which then invokes a more specialized button callback handler. The example uses the `UserParameter` to hold the `this` pointer to an object instance, providing a mechanism for sending the event to a specific object without the need for a switch / map / lookup translation of the Sender Id to an object reference. ``` void YourClassName::setup() { @@ -168,18 +163,26 @@ void YourClassName::setup() " Button Face Text ", ControlColor::None, ParentElementId, - [&](Control *sender, int eventname) + [](Control *sender, int eventname, void* param) { - myButtonCallback(sender, eventname); // class method - }); + if(param) + { + reinterpret_cast(param)->myButtonCallback(sender, eventname); + } + }, + this); // <-Third parameter for the extended callback // or ButtonElementId = ESPUI.button( " Button Face Text ", - [&](Control *sender, int eventname) + [](Control *sender, int eventname, void* param) { - myButtonCallback(sender, eventname); // class method - }); + if(param) + { + reinterpret_cast(param)->myButtonCallback(sender, eventname); + } + }, + this); // <-Third parameter for the extended callback } ``` ``` diff --git a/data/js/controls.js b/data/js/controls.js index 0395071..36fabe3 100644 --- a/data/js/controls.js +++ b/data/js/controls.js @@ -60,8 +60,6 @@ const UPDATE_SEPARATOR = 119; const UI_TIME = 20; const UPDATE_TIME = 120; -const UI_FRAGMENT = 21; - const UP = 0; const DOWN = 1; const LEFT = 2; @@ -79,8 +77,6 @@ const C_ALIZARIN = 6; const C_DARK = 7; const C_NONE = 255; -var controlAssemblyArray = new Object(); -var FragmentAssemblyTimer = new Object(); var graphData = new Array(); var hasAccel = false; var sliderContinuous = false; @@ -194,12 +190,6 @@ function restart() { } function conStatusError() { - FragmentAssemblyTimer.forEach(element => { - clearInterval(element); - }); - FragmentAssemblyTimer = new Object(); - controlAssemblyArray = new Object(); - if (true === websockConnected) { websockConnected = false; websock.close(); @@ -220,20 +210,17 @@ function handleVisibilityChange() { } function start() { - let location = window.location.hostname; - let port = window.location.port; -// let location = "192.168.10.229"; -// let port = ""; - document.addEventListener("visibilitychange", handleVisibilityChange, false); if ( - port != "" || - port != 80 || - port != 443 + window.location.port != "" || + window.location.port != 80 || + window.location.port != 443 ) { - websock = new WebSocket( "ws://" + location + "/ws" ); + websock = new WebSocket( + "ws://" + window.location.hostname + ":" + window.location.port + "/ws" + ); } else { - websock = new WebSocket("ws://" + location + "/ws"); + websock = new WebSocket("ws://" + window.location.hostname + "/ws"); } // is the timer running? @@ -254,54 +241,33 @@ function start() { $("#conStatus").addClass("color-green"); $("#conStatus").text("Connected"); websockConnected = true; - FragmentAssemblyTimer.forEach(element => { - clearInterval(element); - }); - FragmentAssemblyTimer = new Object(); - controlAssemblyArray = new Object(); }; websock.onclose = function (evt) { - // console.log("Close evt: '" + evt + "'"); - // console.log("Close reason: '" + evt.reason + "'"); - // console.log("Close code: '" + evt.code + "'"); console.log("websock close"); conStatusError(); - FragmentAssemblyTimer.forEach(element => { - clearInterval(element); - }); - FragmentAssemblyTimer = new Object(); - controlAssemblyArray = new Object(); }; websock.onerror = function (evt) { console.log("websock Error"); - // console.log("Error evt: '" + evt + "'"); - // console.log("Error data: '" + evt.data + "'"); + console.log(evt); restart(); - FragmentAssemblyTimer.forEach(element => { - clearInterval(element); - }); - FragmentAssemblyTimer = new Object(); - controlAssemblyArray = new Object(); }; var handleEvent = function (evt) { - // console.log("handleEvent:Data evt: '" + evt + "'"); - // console.log("handleEvent:Data data: '" + evt.data + "'"); + console.log(evt); try { var data = JSON.parse(evt.data); } catch (Event) { console.error(Event); - // console.info("start the update over again"); + // start the update over again websock.send("uiok:" + 0); return; } var e = document.body; var center = ""; - // console.info("data.type: '" + data.type + "'"); switch (data.type) { case UI_INITIAL_GUI: @@ -313,9 +279,7 @@ function start() { if (data.sliderContinuous) { sliderContinuous = data.sliderContinuous; } - // console.info("UI_INITIAL_GUI:data record: '" + data + "'"); data.controls.forEach(element => { - // console.info("element: '" + JSON.stringify(element) + "'"); var fauxEvent = { data: JSON.stringify(element), }; @@ -331,9 +295,7 @@ function start() { break; case UI_EXTEND_GUI: - // console.info("UI_EXTEND_GUI data record: '" + data + "'"); data.controls.forEach(element => { - // console.info("UI_EXTEND_GUI:element: '" + JSON.stringify(element) + "'"); var fauxEvent = { data: JSON.stringify(element), }; @@ -639,88 +601,6 @@ function start() { websock.send("time:" + rv + ":" + data.id); break; - case UI_FRAGMENT: - let FragmentLen = data.length; - let FragementOffset = data.offset; - let NextFragmentOffset = FragementOffset + FragmentLen; - let Total = data.total; - let Arrived = (FragmentLen + FragementOffset); - let FragmentFinal = Total === Arrived; - // console.info("UI_FRAGMENT:FragmentLen '" + FragmentLen + "'"); - // console.info("UI_FRAGMENT:FragementOffset '" + FragementOffset + "'"); - // console.info("UI_FRAGMENT:NextFragmentOffset '" + NextFragmentOffset + "'"); - // console.info("UI_FRAGMENT:Total '" + Total + "'"); - // console.info("UI_FRAGMENT:Arrived '" + Arrived + "'"); - // console.info("UI_FRAGMENT:FragmentFinal '" + FragmentFinal + "'"); - - if (!data.hasOwnProperty('control')) - { - console.error("UI_FRAGMENT:Missing control record, skipping control"); - break; - } - let control = data.control; - StopFragmentAssemblyTimer(data.control.id); - - // is this the first fragment? - if(0 === FragementOffset) - { - // console.info("Found first fragment"); - controlAssemblyArray[control.id] = data; - // console.info("Value: " + controlAssemblyArray[control.id].control.value); - controlAssemblyArray[control.id].offset = NextFragmentOffset; - StartFragmentAssemblyTimer(control.id); - let TotalRequest = JSON.stringify({ 'id' : control.id, 'offset' : NextFragmentOffset }); - websock.send("uifragmentok:" + 0 + ": " + TotalRequest + ":"); - // console.info("asked for fragment 2"); - break; - } - - // not first fragment. are we assembling this control? - if("undefined" === typeof controlAssemblyArray[control.id]) - { - // it looks like we missed the first fragment. Start the control over - console.error("Missing first fragment for control: " + control.id); - StartFragmentAssemblyTimer(control.id); - let TotalRequest = JSON.stringify({ 'id' : control.id, 'offset' : 0 }); - websock.send("uifragmentok:" + 0 + ": " + TotalRequest + ":"); - // console.info("asked for fragment 1"); - break; - } - - // is this the expected next fragment - if(FragementOffset !== controlAssemblyArray[control.id].offset) - { - console.error("Wrong next fragment. Expected: " + controlAssemblyArray[control.id].offset + " Got: " + FragementOffset); - StartFragmentAssemblyTimer(control.id); - let TotalRequest = JSON.stringify({ 'id' : control.id, 'offset' : controlAssemblyArray[control.id].length + controlAssemblyArray[control.id].offset }); - websock.send("uifragmentok:" + 0 + ": " + TotalRequest + ":"); - // console.info("asked for the expected fragment"); - break; - } - - // console.info("Add to existing fragment"); - controlAssemblyArray[control.id].control.value += control.value; - controlAssemblyArray[control.id].offset = NextFragmentOffset; - // console.info("Value: " + controlAssemblyArray[control.id].control.value); - - if(true === FragmentFinal) - { - var fauxEvent = { - data: JSON.stringify(controlAssemblyArray[control.id].control), - }; - handleEvent(fauxEvent); - controlAssemblyArray[control.id] = null; - // console.info("Found last fragment"); - } - else - { - // console.info("Ask for next fragment."); - StartFragmentAssemblyTimer(control.id); - let TotalRequest = JSON.stringify({ 'id' : control.id, 'offset' : NextFragmentOffset}); - websock.send("uifragmentok:" + 0 + ": " + TotalRequest + ":"); - } - break; - default: console.error("Unknown type or event"); break; @@ -770,36 +650,6 @@ function start() { websock.onmessage = handleEvent; } -function StartFragmentAssemblyTimer(Id) -{ - StopFragmentAssemblyTimer(Id); - FragmentAssemblyTimer[Id] = setInterval(function(_Id) - { - // does the fragment assembly still exist? - if("undefined" !== typeof controlAssemblyArray[_Id]) - { - if(null !== controlAssemblyArray[_Id]) - { - // we have a valid control that is being assembled - // ask for the next part - let TotalRequest = JSON.stringify({ 'id' : controlAssemblyArray[_Id].control.id, 'offset' : controlAssemblyArray[_Id].offset}); - websock.send("uifragmentok:" + 0 + ": " + TotalRequest + ":"); - } - } - }, 1000, Id); -} - -function StopFragmentAssemblyTimer(Id) -{ - if("undefined" !== typeof FragmentAssemblyTimer[Id]) - { - if(FragmentAssemblyTimer[Id]) - { - clearInterval(FragmentAssemblyTimer[Id]); - } - } -} - function sliderchange(number) { var val = $("#sl" + number).val(); websock.send("slvalue:" + val + ":" + number); diff --git a/data/js/controls.min.js b/data/js/controls.min.js index 9fa8cef..48be64b 100644 --- a/data/js/controls.min.js +++ b/data/js/controls.min.js @@ -1,128 +1,107 @@ -const UI_INITIAL_GUI=200;const UI_RELOAD=201;const UPDATE_OFFSET=100;const UI_EXTEND_GUI=210;const UI_TITEL=0;const UI_PAD=1;const UPDATE_PAD=101;const UI_CPAD=2;const UPDATE_CPAD=102;const UI_BUTTON=3;const UPDATE_BUTTON=103;const UI_LABEL=4;const UPDATE_LABEL=104;const UI_SWITCHER=5;const UPDATE_SWITCHER=105;const UI_SLIDER=6;const UPDATE_SLIDER=106;const UI_NUMBER=7;const UPDATE_NUMBER=107;const UI_TEXT_INPUT=8;const UPDATE_TEXT_INPUT=108;const UI_GRAPH=9;const ADD_GRAPH_POINT=10;const CLEAR_GRAPH=109;const UI_TAB=11;const UPDATE_TAB=111;const UI_SELECT=12;const UPDATE_SELECT=112;const UI_OPTION=13;const UPDATE_OPTION=113;const UI_MIN=14;const UPDATE_MIN=114;const UI_MAX=15;const UPDATE_MAX=115;const UI_STEP=16;const UPDATE_STEP=116;const UI_GAUGE=17;const UPDATE_GAUGE=117;const UI_ACCEL=18;const UPDATE_ACCEL=118;const UI_SEPARATOR=19;const UPDATE_SEPARATOR=119;const UI_TIME=20;const UPDATE_TIME=120;const UI_FRAGMENT=21;const UP=0;const DOWN=1;const LEFT=2;const RIGHT=3;const CENTER=4;const C_TURQUOISE=0;const C_EMERALD=1;const C_PETERRIVER=2;const C_WETASPHALT=3;const C_SUNFLOWER=4;const C_CARROT=5;const C_ALIZARIN=6;const C_DARK=7;const C_NONE=255;var controlAssemblyArray=new Object();var FragmentAssemblyTimer=new Object();var graphData=new Array();var hasAccel=false;var sliderContinuous=false;function colorClass(colorId){colorId=Number(colorId);switch(colorId){case C_TURQUOISE:return"turquoise";case C_EMERALD:return"emerald";case C_PETERRIVER:return"peterriver";case C_WETASPHALT:return"wetasphalt";case C_SUNFLOWER:return"sunflower";case C_CARROT:return"carrot";case C_ALIZARIN:return"alizarin";case C_DARK:case C_NONE:return"dark";default:return"";}} -var websock;var websockConnected=false;var WebSocketTimer=null;function requestOrientationPermission(){} -function saveGraphData(){localStorage.setItem("espuigraphs",JSON.stringify(graphData));} -function restoreGraphData(id){var savedData=localStorage.getItem("espuigraphs",graphData);if(savedData!=null){savedData=JSON.parse(savedData);let idData=savedData[id];return Array.isArray(idData)?idData:[];} -return[];} -function restart(){$(document).add("*").off();$("#row").html("");conStatusError();start();} -function conStatusError(){FragmentAssemblyTimer.forEach(element=>{clearInterval(element);});FragmentAssemblyTimer=new Object();controlAssemblyArray=new Object();if(true===websockConnected){websockConnected=false;websock.close();$("#conStatus").removeClass("color-green");$("#conStatus").addClass("color-red");$("#conStatus").html("Error / No Connection ↻");$("#conStatus").off();$("#conStatus").on({click:restart,});}} -function handleVisibilityChange(){if(!websockConnected&&!document.hidden){restart();}} -function start(){let location=window.location.hostname;let port=window.location.port;document.addEventListener("visibilitychange",handleVisibilityChange,false);if(port!=""||port!=80||port!=443){websock=new WebSocket("ws://"+location+"/ws");}else{websock=new WebSocket("ws://"+location+"/ws");} -if(null===WebSocketTimer){WebSocketTimer=setInterval(function(){if(websock.readyState===3){restart();}},5000);} -websock.onopen=function(evt){console.log("websock open");$("#conStatus").addClass("color-green");$("#conStatus").text("Connected");websockConnected=true;FragmentAssemblyTimer.forEach(element=>{clearInterval(element);});FragmentAssemblyTimer=new Object();controlAssemblyArray=new Object();};websock.onclose=function(evt){console.log("websock close");conStatusError();FragmentAssemblyTimer.forEach(element=>{clearInterval(element);});FragmentAssemblyTimer=new Object();controlAssemblyArray=new Object();};websock.onerror=function(evt){console.log("websock Error");restart();FragmentAssemblyTimer.forEach(element=>{clearInterval(element);});FragmentAssemblyTimer=new Object();controlAssemblyArray=new Object();};var handleEvent=function(evt){try{var data=JSON.parse(evt.data);} -catch(Event){console.error(Event);websock.send("uiok:"+0);return;} -var e=document.body;var center="";switch(data.type){case UI_INITIAL_GUI:$("#row").html("");$("#tabsnav").html("");$("#tabscontent").html("");if(data.sliderContinuous){sliderContinuous=data.sliderContinuous;} -data.controls.forEach(element=>{var fauxEvent={data:JSON.stringify(element),};handleEvent(fauxEvent);});if(data.totalcontrols>(data.controls.length-1)){websock.send("uiok:"+(data.controls.length-1));} -break;case UI_EXTEND_GUI:data.controls.forEach(element=>{var fauxEvent={data:JSON.stringify(element),};handleEvent(fauxEvent);});if(data.totalcontrols>data.startindex+(data.controls.length-1)){websock.send("uiok:"+(data.startindex+(data.controls.length-1)));} -break;case UI_RELOAD:window.location.reload();break;case UI_TITEL:document.title=data.label;$("#mainHeader").html(data.label);break;case UI_LABEL:case UI_NUMBER:case UI_TEXT_INPUT:case UI_SELECT:case UI_GAUGE:case UI_SEPARATOR:if(data.visible)addToHTML(data);break;case UI_BUTTON:if(data.visible){addToHTML(data);$("#btn"+data.id).on({touchstart:function(e){e.preventDefault();buttonclick(data.id,true);},touchend:function(e){e.preventDefault();buttonclick(data.id,false);},});} -break;case UI_SWITCHER:if(data.visible){addToHTML(data);switcher(data.id,data.value);} -break;case UI_CPAD:case UI_PAD:if(data.visible){addToHTML(data);$("#pf"+data.id).on({touchstart:function(e){e.preventDefault();padclick(UP,data.id,true);},touchend:function(e){e.preventDefault();padclick(UP,data.id,false);},});$("#pl"+data.id).on({touchstart:function(e){e.preventDefault();padclick(LEFT,data.id,true);},touchend:function(e){e.preventDefault();padclick(LEFT,data.id,false);},});$("#pr"+data.id).on({touchstart:function(e){e.preventDefault();padclick(RIGHT,data.id,true);},touchend:function(e){e.preventDefault();padclick(RIGHT,data.id,false);},});$("#pb"+data.id).on({touchstart:function(e){e.preventDefault();padclick(DOWN,data.id,true);},touchend:function(e){e.preventDefault();padclick(DOWN,data.id,false);},});$("#pc"+data.id).on({touchstart:function(e){e.preventDefault();padclick(CENTER,data.id,true);},touchend:function(e){e.preventDefault();padclick(CENTER,data.id,false);},});} -break;case UI_SLIDER:if(data.visible){addToHTML(data);rangeSlider(!sliderContinuous);} -break;case UI_TAB:if(data.visible){$("#tabsnav").append("
  • "+data.value+"
  • ");$("#tabscontent").append("
    ");tabs=$(".tabscontent").tabbedContent({loop:true}).data("api");$("a").filter(function(){return $(this).attr("href")==="#click-to-switch";}).on("click",function(e){var tab=prompt("Tab to switch to (number or id)?");if(!tabs.switchTab(tab)){alert("That tab does not exist :\\");} -e.preventDefault();});} -break;case UI_OPTION:if(data.parentControl){var parent=$("#select"+data.parentControl);parent.append("");} -break;case UI_MIN:if(data.parentControl){if($('#sl'+data.parentControl).length){$('#sl'+data.parentControl).attr("min",data.value);}else if($('#num'+data.parentControl).length){$('#num'+data.parentControl).attr("min",data.value);}} -break;case UI_MAX:if(data.parentControl){if($('#sl'+data.parentControl).length){$('#sl'+data.parentControl).attr("max",data.value);}else if($('#text'+data.parentControl).length){$('#text'+data.parentControl).attr("maxlength",data.value);}else if($('#num'+data.parentControl).length){$('#num'+data.parentControl).attr("max",data.value);}} -break;case UI_STEP:if(data.parentControl){if($('#sl'+data.parentControl).length){$('#sl'+data.parentControl).attr("step",data.value);}else if($('#num'+data.parentControl).length){$('#num'+data.parentControl).attr("step",data.value);}} -break;case UI_GRAPH:if(data.visible){addToHTML(data);graphData[data.id]=restoreGraphData(data.id);renderGraphSvg(graphData[data.id],"graph"+data.id);} -break;case ADD_GRAPH_POINT:var ts=new Date().getTime();graphData[data.id].push({x:ts,y:data.value});saveGraphData();renderGraphSvg(graphData[data.id],"graph"+data.id);break;case CLEAR_GRAPH:graphData[data.id]=[];saveGraphData();renderGraphSvg(graphData[data.id],"graph"+data.id);break;case UI_ACCEL:if(hasAccel)break;hasAccel=true;if(data.visible){addToHTML(data);requestOrientationPermission();} -break;case UPDATE_LABEL:$("#l"+data.id).html(data.value);if(data.hasOwnProperty('elementStyle')){$("#l"+data.id).attr("style",data.elementStyle);} -break;case UPDATE_SWITCHER:switcher(data.id,data.value=="0"?0:1);if(data.hasOwnProperty('elementStyle')){$("#sl"+data.id).attr("style",data.elementStyle);} -break;case UPDATE_SLIDER:$("#sl"+data.id).attr("value",data.value) -slider_move($("#sl"+data.id).parent().parent(),data.value,"100",false);if(data.hasOwnProperty('elementStyle')){$("#sl"+data.id).attr("style",data.elementStyle);} -break;case UPDATE_NUMBER:$("#num"+data.id).val(data.value);if(data.hasOwnProperty('elementStyle')){$("#num"+data.id).attr("style",data.elementStyle);} -break;case UPDATE_TEXT_INPUT:$("#text"+data.id).val(data.value);if(data.hasOwnProperty('elementStyle')){$("#text"+data.id).attr("style",data.elementStyle);} -if(data.hasOwnProperty('inputType')){$("#text"+data.id).attr("type",data.inputType);} -break;case UPDATE_SELECT:$("#select"+data.id).val(data.value);if(data.hasOwnProperty('elementStyle')){$("#select"+data.id).attr("style",data.elementStyle);} -break;case UPDATE_BUTTON:$("#btn"+data.id).val(data.value);$("#btn"+data.id).text(data.value);if(data.hasOwnProperty('elementStyle')){$("#btn"+data.id).attr("style",data.elementStyle);} -break;case UPDATE_PAD:case UPDATE_CPAD:break;case UPDATE_GAUGE:$("#gauge"+data.id).val(data.value);if(data.hasOwnProperty('elementStyle')){$("#gauge"+data.id).attr("style",data.elementStyle);} -break;case UPDATE_ACCEL:break;case UPDATE_TIME:var rv=new Date().toISOString();websock.send("time:"+rv+":"+data.id);break;case UI_FRAGMENT:let FragmentLen=data.length;let FragementOffset=data.offset;let NextFragmentOffset=FragementOffset+FragmentLen;let Total=data.total;let Arrived=(FragmentLen+FragementOffset);let FragmentFinal=Total===Arrived;if(!data.hasOwnProperty('control')) -{console.error("UI_FRAGMENT:Missing control record, skipping control");break;} -let control=data.control;StopFragmentAssemblyTimer(data.control.id);if(0===FragementOffset) -{controlAssemblyArray[control.id]=data;controlAssemblyArray[control.id].offset=NextFragmentOffset;StartFragmentAssemblyTimer(control.id);let TotalRequest=JSON.stringify({'id':control.id,'offset':NextFragmentOffset});websock.send("uifragmentok:"+0+": "+TotalRequest+":");break;} -if("undefined"===typeof controlAssemblyArray[control.id]) -{console.error("Missing first fragment for control: "+control.id);StartFragmentAssemblyTimer(control.id);let TotalRequest=JSON.stringify({'id':control.id,'offset':0});websock.send("uifragmentok:"+0+": "+TotalRequest+":");break;} -if(FragementOffset!==controlAssemblyArray[control.id].offset) -{console.error("Wrong next fragment. Expected: "+controlAssemblyArray[control.id].offset+" Got: "+FragementOffset);StartFragmentAssemblyTimer(control.id);let TotalRequest=JSON.stringify({'id':control.id,'offset':controlAssemblyArray[control.id].length+controlAssemblyArray[control.id].offset});websock.send("uifragmentok:"+0+": "+TotalRequest+":");break;} -controlAssemblyArray[control.id].control.value+=control.value;controlAssemblyArray[control.id].offset=NextFragmentOffset;if(true===FragmentFinal) -{var fauxEvent={data:JSON.stringify(controlAssemblyArray[control.id].control),};handleEvent(fauxEvent);controlAssemblyArray[control.id]=null;} -else -{StartFragmentAssemblyTimer(control.id);let TotalRequest=JSON.stringify({'id':control.id,'offset':NextFragmentOffset});websock.send("uifragmentok:"+0+": "+TotalRequest+":");} -break;default:console.error("Unknown type or event");break;} -if(data.type>=UI_TITEL&&data.type=UPDATE_OFFSET&&data.type0){var parent=data.hasOwnProperty('parentControl')?$("#tab"+data.parentControl):$("#row");var html="";switch(data.type){case UI_LABEL:case UI_BUTTON:case UI_SWITCHER:case UI_CPAD:case UI_PAD:case UI_SLIDER:case UI_NUMBER:case UI_TEXT_INPUT:case UI_SELECT:case UI_GRAPH:case UI_GAUGE:case UI_ACCEL:html="
    "+data.label+"

    "+ -elementHTML(data)+ -"
    ";break;case UI_SEPARATOR:html="
    "+ -"
    "+data.label+"

    ";break;case UI_TIME:break;} -parent.append(html);}else{var parent=$("#id"+data.parentControl);parent.append(elementHTML(data));}} -var elementHTML=function(data){var id=data.id -var elementStyle=data.hasOwnProperty('elementStyle')?" style='"+data.elementStyle+"' ":"";var inputType=data.hasOwnProperty('inputType')?" type='"+data.inputType+"' ":"";switch(data.type){case UI_LABEL:return""+data.value+"";case UI_BUTTON:return"";case UI_SWITCHER:return"";case UI_CPAD:case UI_PAD:return"";case UI_SLIDER:return"
    "+ -""+ -data.value+"
    ";case UI_NUMBER:return"";case UI_TEXT_INPUT:return"";case UI_SELECT:return"";case UI_ACCEL:return"ACCEL // Not implemented fully!
    ";default:return"";}}
    -var processEnabled=function(data){switch(data.type){case UI_SWITCHER:case UPDATE_SWITCHER:if(data.enabled){$("#sl"+data.id).removeClass('disabled');$("#s"+data.id).prop("disabled",false);}else{$("#sl"+data.id).addClass('disabled');$("#s"+data.id).prop("disabled",true);}
    -break;case UI_SLIDER:case UPDATE_SLIDER:$("#sl"+data.id).prop("disabled",!data.enabled);break;case UI_NUMBER:case UPDATE_NUMBER:$("#num"+data.id).prop("disabled",!data.enabled);break;case UI_TEXT_INPUT:case UPDATE_TEXT_INPUT:$("#text"+data.id).prop("disabled",!data.enabled);break;case UI_SELECT:case UPDATE_SELECT:$("#select"+data.id).prop("disabled",!data.enabled);break;case UI_BUTTON:case UPDATE_BUTTON:$("#btn"+data.id).prop("disabled",!data.enabled);break;case UI_PAD:case UI_CPAD:case UPDATE_PAD:case UPDATE_CPAD:if(data.enabled){$("#id"+data.id+" nav").removeClass('disabled');}else{$("#id"+data.id+" nav").addClass('disabled');}
    +const UI_INITIAL_GUI=200;const UI_RELOAD=201;const UPDATE_OFFSET=100;const UI_EXTEND_GUI=210;const UI_TITEL=0;const UI_PAD=1;const UPDATE_PAD=101;const UI_CPAD=2;const UPDATE_CPAD=102;const UI_BUTTON=3;const UPDATE_BUTTON=103;const UI_LABEL=4;const UPDATE_LABEL=104;const UI_SWITCHER=5;const UPDATE_SWITCHER=105;const UI_SLIDER=6;const UPDATE_SLIDER=106;const UI_NUMBER=7;const UPDATE_NUMBER=107;const UI_TEXT_INPUT=8;const UPDATE_TEXT_INPUT=108;const UI_GRAPH=9;const ADD_GRAPH_POINT=10;const CLEAR_GRAPH=109;const UI_TAB=11;const UPDATE_TAB=111;const UI_SELECT=12;const UPDATE_SELECT=112;const UI_OPTION=13;const UPDATE_OPTION=113;const UI_MIN=14;const UPDATE_MIN=114;const UI_MAX=15;const UPDATE_MAX=115;const UI_STEP=16;const UPDATE_STEP=116;const UI_GAUGE=17;const UPDATE_GAUGE=117;const UI_ACCEL=18;const UPDATE_ACCEL=118;const UI_SEPARATOR=19;const UPDATE_SEPARATOR=119;const UI_TIME=20;const UPDATE_TIME=120;const UP=0;const DOWN=1;const LEFT=2;const RIGHT=3;const CENTER=4;const C_TURQUOISE=0;const C_EMERALD=1;const C_PETERRIVER=2;const C_WETASPHALT=3;const C_SUNFLOWER=4;const C_CARROT=5;const C_ALIZARIN=6;const C_DARK=7;const C_NONE=255;var graphData=new Array();var hasAccel=false;var sliderContinuous=false;function colorClass(colorId){colorId=Number(colorId);switch(colorId){case C_TURQUOISE:return"turquoise";case C_EMERALD:return"emerald";case C_PETERRIVER:return"peterriver";case C_WETASPHALT:return"wetasphalt";case C_SUNFLOWER:return"sunflower";case C_CARROT:return"carrot";case C_ALIZARIN:return"alizarin";case C_DARK:case C_NONE:return"dark";default:return"";}}
    +var websock;var websockConnected=false;var WebSocketTimer=null;function requestOrientationPermission(){}
    +function saveGraphData(){localStorage.setItem("espuigraphs",JSON.stringify(graphData));}
    +function restoreGraphData(id){var savedData=localStorage.getItem("espuigraphs",graphData);if(savedData!=null){savedData=JSON.parse(savedData);let idData=savedData[id];return Array.isArray(idData)?idData:[];}
    +return[];}
    +function restart(){$(document).add("*").off();$("#row").html("");conStatusError();start();}
    +function conStatusError(){if(true===websockConnected){websockConnected=false;websock.close();$("#conStatus").removeClass("color-green");$("#conStatus").addClass("color-red");$("#conStatus").html("Error / No Connection ↻");$("#conStatus").off();$("#conStatus").on({click:restart,});}}
    +function handleVisibilityChange(){if(!websockConnected&&!document.hidden){restart();}}
    +function start(){document.addEventListener("visibilitychange",handleVisibilityChange,false);if(window.location.port!=""||window.location.port!=80||window.location.port!=443){websock=new WebSocket("ws://"+window.location.hostname+":"+window.location.port+"/ws");}else{websock=new WebSocket("ws://"+window.location.hostname+"/ws");}
    +if(null===WebSocketTimer){WebSocketTimer=setInterval(function(){if(websock.readyState===3){restart();}},5000);}
    +websock.onopen=function(evt){console.log("websock open");$("#conStatus").addClass("color-green");$("#conStatus").text("Connected");websockConnected=true;};websock.onclose=function(evt){console.log("websock close");conStatusError();};websock.onerror=function(evt){console.log("websock Error");console.log(evt);restart();};var handleEvent=function(evt){console.log(evt);try{var data=JSON.parse(evt.data);}
    +catch(Event){console.error(Event);websock.send("uiok:"+0);return;}
    +var e=document.body;var center="";switch(data.type){case UI_INITIAL_GUI:$("#row").html("");$("#tabsnav").html("");$("#tabscontent").html("");if(data.sliderContinuous){sliderContinuous=data.sliderContinuous;}
    +data.controls.forEach(element=>{var fauxEvent={data:JSON.stringify(element),};handleEvent(fauxEvent);});if(data.totalcontrols>(data.controls.length-1)){websock.send("uiok:"+(data.controls.length-1));}
    +break;case UI_EXTEND_GUI:data.controls.forEach(element=>{var fauxEvent={data:JSON.stringify(element),};handleEvent(fauxEvent);});if(data.totalcontrols>data.startindex+(data.controls.length-1)){websock.send("uiok:"+(data.startindex+(data.controls.length-1)));}
    +break;case UI_RELOAD:window.location.reload();break;case UI_TITEL:document.title=data.label;$("#mainHeader").html(data.label);break;case UI_LABEL:case UI_NUMBER:case UI_TEXT_INPUT:case UI_SELECT:case UI_GAUGE:case UI_SEPARATOR:if(data.visible)addToHTML(data);break;case UI_BUTTON:if(data.visible){addToHTML(data);$("#btn"+data.id).on({touchstart:function(e){e.preventDefault();buttonclick(data.id,true);},touchend:function(e){e.preventDefault();buttonclick(data.id,false);},});}
    +break;case UI_SWITCHER:if(data.visible){addToHTML(data);switcher(data.id,data.value);}
    +break;case UI_CPAD:case UI_PAD:if(data.visible){addToHTML(data);$("#pf"+data.id).on({touchstart:function(e){e.preventDefault();padclick(UP,data.id,true);},touchend:function(e){e.preventDefault();padclick(UP,data.id,false);},});$("#pl"+data.id).on({touchstart:function(e){e.preventDefault();padclick(LEFT,data.id,true);},touchend:function(e){e.preventDefault();padclick(LEFT,data.id,false);},});$("#pr"+data.id).on({touchstart:function(e){e.preventDefault();padclick(RIGHT,data.id,true);},touchend:function(e){e.preventDefault();padclick(RIGHT,data.id,false);},});$("#pb"+data.id).on({touchstart:function(e){e.preventDefault();padclick(DOWN,data.id,true);},touchend:function(e){e.preventDefault();padclick(DOWN,data.id,false);},});$("#pc"+data.id).on({touchstart:function(e){e.preventDefault();padclick(CENTER,data.id,true);},touchend:function(e){e.preventDefault();padclick(CENTER,data.id,false);},});}
    +break;case UI_SLIDER:if(data.visible){addToHTML(data);rangeSlider(!sliderContinuous);}
    +break;case UI_TAB:if(data.visible){$("#tabsnav").append("
  • "+data.value+"
  • ");$("#tabscontent").append("
    ");tabs=$(".tabscontent").tabbedContent({loop:true}).data("api");$("a").filter(function(){return $(this).attr("href")==="#click-to-switch";}).on("click",function(e){var tab=prompt("Tab to switch to (number or id)?");if(!tabs.switchTab(tab)){alert("That tab does not exist :\\");} +e.preventDefault();});} +break;case UI_OPTION:if(data.parentControl){var parent=$("#select"+data.parentControl);parent.append("");} +break;case UI_MIN:if(data.parentControl){if($('#sl'+data.parentControl).length){$('#sl'+data.parentControl).attr("min",data.value);}else if($('#num'+data.parentControl).length){$('#num'+data.parentControl).attr("min",data.value);}} +break;case UI_MAX:if(data.parentControl){if($('#sl'+data.parentControl).length){$('#sl'+data.parentControl).attr("max",data.value);}else if($('#text'+data.parentControl).length){$('#text'+data.parentControl).attr("maxlength",data.value);}else if($('#num'+data.parentControl).length){$('#num'+data.parentControl).attr("max",data.value);}} +break;case UI_STEP:if(data.parentControl){if($('#sl'+data.parentControl).length){$('#sl'+data.parentControl).attr("step",data.value);}else if($('#num'+data.parentControl).length){$('#num'+data.parentControl).attr("step",data.value);}} +break;case UI_GRAPH:if(data.visible){addToHTML(data);graphData[data.id]=restoreGraphData(data.id);renderGraphSvg(graphData[data.id],"graph"+data.id);} +break;case ADD_GRAPH_POINT:var ts=new Date().getTime();graphData[data.id].push({x:ts,y:data.value});saveGraphData();renderGraphSvg(graphData[data.id],"graph"+data.id);break;case CLEAR_GRAPH:graphData[data.id]=[];saveGraphData();renderGraphSvg(graphData[data.id],"graph"+data.id);break;case UI_ACCEL:if(hasAccel)break;hasAccel=true;if(data.visible){addToHTML(data);requestOrientationPermission();} +break;case UPDATE_LABEL:$("#l"+data.id).html(data.value);if(data.hasOwnProperty('elementStyle')){$("#l"+data.id).attr("style",data.elementStyle);} +break;case UPDATE_SWITCHER:switcher(data.id,data.value=="0"?0:1);if(data.hasOwnProperty('elementStyle')){$("#sl"+data.id).attr("style",data.elementStyle);} +break;case UPDATE_SLIDER:$("#sl"+data.id).attr("value",data.value) +slider_move($("#sl"+data.id).parent().parent(),data.value,"100",false);if(data.hasOwnProperty('elementStyle')){$("#sl"+data.id).attr("style",data.elementStyle);} +break;case UPDATE_NUMBER:$("#num"+data.id).val(data.value);if(data.hasOwnProperty('elementStyle')){$("#num"+data.id).attr("style",data.elementStyle);} +break;case UPDATE_TEXT_INPUT:$("#text"+data.id).val(data.value);if(data.hasOwnProperty('elementStyle')){$("#text"+data.id).attr("style",data.elementStyle);} +if(data.hasOwnProperty('inputType')){$("#text"+data.id).attr("type",data.inputType);} +break;case UPDATE_SELECT:$("#select"+data.id).val(data.value);if(data.hasOwnProperty('elementStyle')){$("#select"+data.id).attr("style",data.elementStyle);} +break;case UPDATE_BUTTON:$("#btn"+data.id).val(data.value);$("#btn"+data.id).text(data.value);if(data.hasOwnProperty('elementStyle')){$("#btn"+data.id).attr("style",data.elementStyle);} +break;case UPDATE_PAD:case UPDATE_CPAD:break;case UPDATE_GAUGE:$("#gauge"+data.id).val(data.value);if(data.hasOwnProperty('elementStyle')){$("#gauge"+data.id).attr("style",data.elementStyle);} +break;case UPDATE_ACCEL:break;case UPDATE_TIME:var rv=new Date().toISOString();websock.send("time:"+rv+":"+data.id);break;default:console.error("Unknown type or event");break;} +if(data.type>=UI_TITEL&&data.type=UPDATE_OFFSET&&data.type0){var parent=data.hasOwnProperty('parentControl')?$("#tab"+data.parentControl):$("#row");var html="";switch(data.type){case UI_LABEL:case UI_BUTTON:case UI_SWITCHER:case UI_CPAD:case UI_PAD:case UI_SLIDER:case UI_NUMBER:case UI_TEXT_INPUT:case UI_SELECT:case UI_GRAPH:case UI_GAUGE:case UI_ACCEL:html="
    "+data.label+"

    "+ +elementHTML(data)+ +"
    ";break;case UI_SEPARATOR:html="
    "+ +"
    "+data.label+"

    ";break;case UI_TIME:break;} +parent.append(html);}else{var parent=$("#id"+data.parentControl);parent.append(elementHTML(data));}} +var elementHTML=function(data){var id=data.id +var elementStyle=data.hasOwnProperty('elementStyle')?" style='"+data.elementStyle+"' ":"";var inputType=data.hasOwnProperty('inputType')?" type='"+data.inputType+"' ":"";switch(data.type){case UI_LABEL:return""+data.value+"";case UI_BUTTON:return"";case UI_SWITCHER:return"";case UI_CPAD:case UI_PAD:return"";case UI_SLIDER:return"
    "+ +""+ +data.value+"
    ";case UI_NUMBER:return"";case UI_TEXT_INPUT:return"";case UI_SELECT:return"";case UI_ACCEL:return"ACCEL // Not implemented fully!
    ";default:return"";}}
    +var processEnabled=function(data){switch(data.type){case UI_SWITCHER:case UPDATE_SWITCHER:if(data.enabled){$("#sl"+data.id).removeClass('disabled');$("#s"+data.id).prop("disabled",false);}else{$("#sl"+data.id).addClass('disabled');$("#s"+data.id).prop("disabled",true);}
    +break;case UI_SLIDER:case UPDATE_SLIDER:$("#sl"+data.id).prop("disabled",!data.enabled);break;case UI_NUMBER:case UPDATE_NUMBER:$("#num"+data.id).prop("disabled",!data.enabled);break;case UI_TEXT_INPUT:case UPDATE_TEXT_INPUT:$("#text"+data.id).prop("disabled",!data.enabled);break;case UI_SELECT:case UPDATE_SELECT:$("#select"+data.id).prop("disabled",!data.enabled);break;case UI_BUTTON:case UPDATE_BUTTON:$("#btn"+data.id).prop("disabled",!data.enabled);break;case UI_PAD:case UI_CPAD:case UPDATE_PAD:case UPDATE_CPAD:if(data.enabled){$("#id"+data.id+" nav").removeClass('disabled');}else{$("#id"+data.id+" nav").addClass('disabled');}
     break;}}
    \ No newline at end of file
    diff --git a/examples/completeExample/completeExample.cpp b/examples/completeExample/completeExample.cpp
    index 6833310..364a4f9 100644
    --- a/examples/completeExample/completeExample.cpp
    +++ b/examples/completeExample/completeExample.cpp
    @@ -30,7 +30,6 @@
     #include 
     #include 
     #include 
    -#ifndef CORE_MOCK
     #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)
    @@ -40,7 +39,6 @@
     #error on ESP8266 and ESPUI, you must define OOM debug option when developping
     #endif
     #endif
    -#endif
     
     //Settings
     #define SLOW_BOOT 0
    @@ -398,8 +396,7 @@ void extendedCallback(Control* sender, int type, void* param)
         Serial.print(sender->label);
         Serial.print("' = ");
         Serial.println(sender->value);
    -    Serial.print("param = ");
    -    Serial.println((long)param);
    +    Serial.println(String("param = ") + String((int)param));
     }
     
     void setup() {
    @@ -446,7 +443,6 @@ void loop() {
     				#if !defined(ESP32)
     					((void (*)())0xf00fdead)();
     				#endif
    -				break;
     			default:
     				Serial.print('#');
     				break;
    diff --git a/examples/completeExample/completeExample.ino b/examples/completeExample/completeExample.ino
    index a4db808..ff7bd09 100644
    --- a/examples/completeExample/completeExample.ino
    +++ b/examples/completeExample/completeExample.ino
    @@ -1,4 +1 @@
     // placeholder
    -#if CORE_MOCK
    -#include "completeExample.cpp"
    -#endif
    diff --git a/examples/gui-generic-api/gui-generic-api.ino b/examples/gui-generic-api/gui-generic-api.ino
    index 556596b..815e66d 100644
    --- a/examples/gui-generic-api/gui-generic-api.ino
    +++ b/examples/gui-generic-api/gui-generic-api.ino
    @@ -11,17 +11,15 @@ DNSServer dnsServer;
     // esp8266
     #include 
     #include 
    -#ifndef CORE_MOCK
     #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:///heap
     #endif // MMU_IRAM_HEAP
    -#if !defined(DEBUG_ESP_OOM)
    +#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* password = "espui";
    @@ -69,8 +67,7 @@ void buttonCallback(Control* sender, int type)
     
     void buttonExample(Control* sender, int type, void* param)
     {
    -    Serial.print("param: ");
    -    Serial.println((long)param);
    +    Serial.println(String("param: ") + String(long(param)));
         switch (type)
         {
         case B_DOWN:
    diff --git a/examples/gui/gui.ino b/examples/gui/gui.ino
    index 71ab831..1aca2f1 100644
    --- a/examples/gui/gui.ino
    +++ b/examples/gui/gui.ino
    @@ -11,7 +11,6 @@ DNSServer dnsServer;
     // esp8266
     #include 
     #include 
    -#ifndef CORE_MOCK
     #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)
    @@ -21,7 +20,6 @@ DNSServer dnsServer;
     #error on ESP8266 and ESPUI, you must define OOM debug option when developping
     #endif
     #endif
    -#endif
     
     const char* ssid = "ESPUI";
     const char* password = "espui";
    @@ -74,8 +72,7 @@ void buttonCallback(Control* sender, int type)
     
     void buttonExample(Control* sender, int type, void* param)
     {
    -    Serial.print("param: ");
    -    Serial.println((long)param);
    +    Serial.println(String("param: ") + String(long(param)));
         switch (type)
         {
         case B_DOWN:
    diff --git a/examples/tabbedGui/tabbedGui.ino b/examples/tabbedGui/tabbedGui.ino
    index 4831a6b..7aa0b2f 100644
    --- a/examples/tabbedGui/tabbedGui.ino
    +++ b/examples/tabbedGui/tabbedGui.ino
    @@ -11,7 +11,6 @@ DNSServer dnsServer;
     // esp8266
     #include 
     #include 
    -#ifndef CORE_MOCK
     #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)
    @@ -21,7 +20,6 @@ DNSServer dnsServer;
     #error on ESP8266 and ESPUI, you must define OOM debug option when developping
     #endif
     #endif
    -#endif
     
     const char* ssid = "ESPUI";
     const char* password = "espui";
    @@ -68,8 +66,7 @@ void buttonCallback(Control* sender, int type)
     
     void buttonExample(Control* sender, int type, void* param)
     {
    -    Serial.print("param: ");
    -    Serial.println((long)param);
    +    Serial.println(String("param: ") + String(long(param)));
         switch (type)
         {
         case B_DOWN:
    diff --git a/library.json b/library.json
    index 2d40950..76d3173 100644
    --- a/library.json
    +++ b/library.json
    @@ -24,6 +24,11 @@
           "name": "ArduinoJson",
           "authors": "Benoit Blanchon",
           "frameworks": "arduino"
    +    },
    +    {
    +      "name": "LittleFS_esp32",
    +      "authors": "lorol",
    +      "frameworks": "arduino"
         }
       ],
       "version": "2.2.3",
    diff --git a/src/ESPUI.cpp b/src/ESPUI.cpp
    index 78ec95c..c69a0e7 100644
    --- a/src/ESPUI.cpp
    +++ b/src/ESPUI.cpp
    @@ -5,7 +5,11 @@
     #include 
     
     #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 
     #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);
             }
         }
    @@ -702,7 +719,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
     
    @@ -919,7 +936,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);
         }
    @@ -943,7 +960,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;
    @@ -972,7 +989,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;
    @@ -993,7 +1010,7 @@ 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;
    @@ -1146,7 +1163,7 @@ void ESPUIClass::jsonReload()
     {
         for (auto& CurrentClient : MapOfClients)
         {
    -        // Serial.println("Requesting Reload");
    +        // ESPU_DBGL("Requesting Reload");
             CurrentClient.second->NotifyClient(ClientUpdateType_t::ReloadNeeded);
         }
     }
    @@ -1189,7 +1206,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
    @@ -1218,7 +1235,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
    @@ -1285,7 +1302,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
     }
    @@ -1365,17 +1382,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))
    @@ -1445,7 +1463,7 @@ void ESPUIClass::begin(const char* _title, const char* username, const char* pas
     #if defined(DEBUG_ESPUI)
         if (verbosity)
         {
    -        Serial.println(F("UI Initialized"));
    +        ESPU_DBGL(F("UI Initialized"));
         }
     #endif
     }
    diff --git a/src/ESPUIclient.cpp b/src/ESPUIclient.cpp
    index a0b6cc3..75eb2d5 100644
    --- a/src/ESPUIclient.cpp
    +++ b/src/ESPUIclient.cpp
    @@ -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);