Slow Dashboard Updates

Hi all,
I am experiencing very slow data updates on my dashboards, sometimes they don’t load data at all and you either have to refresh the webpage or go back to the dashboard menu and select it again.
Also dashboards stop updating data after a couple of minutes and you have to refresh again, very frustrating and an impediment to creating a commercial product.
I have had to put a widget on the dashboard to display the processor time (esp32), if it doesn’t appear or stops ticking over you know you can’t trust any data that is displayed and you have to refresh the screen.
What can I do to improve the performance (in simple terms please as I am new to this).
Thanks, Len Hall

Hi, we need much more information to know what can be the cause:

  • Where are you located
  • If you are using community or private instance
  • How do you feed your dashboards (buckets and device? only device)
  • The code for your ESP32

Located in Australia.
Don’t know what you mean by community or private instance, but I am using a 4G Router, signal is not lightning fast but ok, will run uTube videos with no stuttering.
I use Buckets and Device Data.

The Code is quite extensive but here are the relevant bits -

#include <iot_cmd.h>
#include <ThingerESP32.h>
#include <EEPROM.h>

#define USERNAME “”
#define DEVICE_ID “”
#define DEVICE_CREDENTIAL “”

#define SSID “”
#define SSID_PASSWORD “”

#define EEPROM_SIZE 70

const char* ntpServer = “au.pool.ntp.org”;
const long gmtOffset_sec = 36000;
const int daylightOffset_sec = 0;

ThingerESP32 thing(USERNAME, DEVICE_ID, DEVICE_CREDENTIAL);

TaskHandle_t Task1;

#include <sequencer4.h> //imports a 4 function sequencer
#include <sequencer1.h> //imports a 1 function sequencer
#include <Ezo_i2c_util.h> //brings in common print statements
#include <Ezo_i2c.h> //include the EZO I2C library from https://github.com/Atlas-Scientific/Ezo_I2c_lib
#include <Wire.h> //include arduinos i2c library

void setup() {

Wire.begin(); //start the I2C
// dht.begin();
Serial.begin(9600); //start the serial communication to the computer
EEPROM.begin(EEPROM_SIZE);

disableCore0WDT();                    //Disable Core 0 Watchdog

thing.add_wifi(SSID, SSID_PASSWORD);
thing["Bucket_Data"] >> [](pson& out){
  out["Sump_Temp"] = Sump_Temp;
  out["Sump_pH"] = Sump_pH;
  out["Sump_EC"] = Sump_EC;
  out["Sump_ORP"] = Sump_ORP;
  out["GH_Temp"] = GH_Temp;
  out["GH_Hum"] = GH_Hum;
  out["GH_Dew"] = GH_Dew;
  out["FT1_DO"] = FT1_DO;
  out["FT2_DO"] = FT2_DO;
  out["Sump_TDS"] = Sump_TDS;
  out["Sump_Sal"] = Sump_Sal;

};
thing[“Device_Data”] >> [](pson& out){
// out[“GH_Fan_Status”] = GH_Fan_Status;
// out[“FD_Status”] = FD_Status;
out[“Blank Widget”] = Blank_Widget;
out[“GH_Weather”] = GH_Weather;
out[“Sump_Low_Level_Alarm”] = Sump_Low_Level_Alarm;
out[“Sump_Temp_Low_Alarm”] = Sump_Temp_Low_Alarm;
out[“Sump_Temp_High_Alarm”] = Sump_Temp_High_Alarm;
out[“Sump_Temp_Low_Point”] = Sump_Temp_Low_Point;
out[“Sump_Temp_High_Point”] = Sump_Temp_High_Point;
out[“pH_Low_Setpoint”] = pH_Low_Setpoint;
out[“pH_High_Setpoint”] = pH_High_Setpoint;
out[“pH_Low_Alarm”] = pH_Low_Alarm;
out[“pH_High_Alarm”] = pH_High_Alarm;
out[“pH_Low_Alarm_Point”] = pH_Low_Alarm_Point;
out[“pH_High_Alarm_Point”] = pH_High_Alarm_Point;
out[“pH_Dose_A_Pump_Alarm”] = pH_Dose_A_Pump_Alarm;
out[“pH_Dose_A_Pump_Status”] = pH_Dose_A_Pump_Status;
out[“pH_Dose_A_Count_String”] = pH_Dose_A_Count_String;
out[“pH_Dose_A_Lockout”] = pH_Dose_A_Lockout;
out[“pH_Dose_B_Pump_Alarm”] = pH_Dose_B_Pump_Alarm;
out[“pH_Dose_B_Pump_Status”] = pH_Dose_B_Pump_Status;
out[“pH_Dose_B_Count_String”] = pH_Dose_B_Count_String;
out[“pH_Dose_B_Lockout”] = pH_Dose_B_Lockout;
out[“GB_Pump_Status”] = GB_Pump_Status;
out[“HX_Pump_Status”] = HX_Pump_Status;
out[“FT1_Level”] = FT1_Level;
out[“FT2_Level”] = FT2_Level;
out[“FT1_DO_Low_Alarm”] = FT1_DO_Low_Alarm;
out[“FT1_DO_Low_Point”] = FT1_DO_Low_Point;
out[“FT2_DO_Low_Alarm”] = FT2_DO_Low_Alarm;
out[“FT2_DO_Low_Point”] = FT2_DO_Low_Point;
out[“StringTime”] = StringTime;
out[“Z1W1Run”] = Zone1Water1Run;
out[“Z1W1SecRem”] = Zone1Water1SecondsRemaining;
out[“Z1W2Run”] = Zone1Water2Run;
out[“Z1W2SecRem”] = Zone1Water2SecondsRemaining;
out[“Z1W3Run”] = Zone1Water3Run;
out[“Z1W3SecRem”] = Zone1Water3SecondsRemaining;
out[“Z1W4Run”] = Zone1Water4Run;
out[“Z1W4SecRem”] = Zone1Water4SecondsRemaining;
out[“Z1WtrVlv”] = Zone1WaterValve;
out[“Z2W1Run”] = Zone2Water1Run;
out[“Z2W1SecRem”] = Zone2Water1SecondsRemaining;
out[“Z2W2Run”] = Zone2Water2Run;
out[“Z2W2SecRem”] = Zone2Water2SecondsRemaining;
out[“Z2W3Run”] = Zone2Water3Run;
out[“Z2W3SecRem”] = Zone2Water3SecondsRemaining;
out[“Z2W4Run”] = Zone2Water4Run;
out[“Z2W4SecRem”] = Zone2Water4SecondsRemaining;
out[“Z2WtrVlv”] = Zone2WaterValve;
out[“NFTWtrVlv”] = NFTWaterValve;
};
thing[“pH_Enable_A”] << [](pson& in){
if(in.is_empty()){
in = pH_Enable_A;
}
else{
pH_Enable_A = in;
}
};
thing[“pH_Enable_B”] << [](pson& in){
if(in.is_empty()){
in = pH_Enable_B;
}
else{
pH_Enable_B = in;
}
};
thing[“pH_Setpoint”] << [](pson& in){
if(in.is_empty()){
in = pH_Setpoint;
}
else{
pH_Setpoint = in;
}
};
thing[“pH_SP_Db”] << [](pson& in){
if(in.is_empty()){
in = pH_Setpoint_Deadband;
}
else{
pH_Setpoint_Deadband = in;
}
};
thing[“pH_Alarm_Db”] << [](pson& in){
if(in.is_empty()){
in = pH_Alarm_Deadband;
}
else{
pH_Alarm_Deadband = in;
}
};
thing[“pH_Dose_A_Volume”] << [](pson& in){
if(in.is_empty()){
in = pH_Dose_A_Volume;
}
else{
pH_Dose_A_Volume = in;
}
};
thing[“pH_Dose_A_Count_Limit”] << [](pson& in){
if(in.is_empty()){
in = pH_Dose_A_Count_Limit;
}
else{
pH_Dose_A_Count_Limit = in;
}
};
thing[“pH_Dose_B_Volume”] << [](pson& in){
if(in.is_empty()){
in = pH_Dose_B_Volume;
}
else{
pH_Dose_B_Volume = in;
}
};
thing[“pH_Dose_B_Count_Limit”] << [](pson& in){
if(in.is_empty()){
in = pH_Dose_B_Count_Limit;
}
else{
pH_Dose_B_Count_Limit = in;
}
};
thing[“Sump_Desired_Temp”] << [](pson& in){
if(in.is_empty()){
in = Sump_Desired_Temp;
}
else{
Sump_Desired_Temp = in;
}
};
thing[“Sump_Temp_Alarm_Db”] << [](pson& in){
if(in.is_empty()){
in = Sump_Temp_Alarm_Deadband;
}
else{
Sump_Temp_Alarm_Deadband = in;
}
};
thing[“FT1_Desired_DO”] << [](pson& in){
if(in.is_empty()){
in = FT1_Desired_DO;
}
else{
FT1_Desired_DO = in;
}
};
thing[“FT1_DO_Db”] << [](pson& in){
if(in.is_empty()){
in = FT1_DO_Deadband;
}
else{
FT1_DO_Deadband = in;
}
};
thing[“FT2_Desired_DO”] << [](pson& in){
if(in.is_empty()){
in = FT2_Desired_DO;
}
else{
FT2_Desired_DO = in;
}
};
thing[“FT2_DO_Db”] << [](pson& in){
if(in.is_empty()){
in = FT2_DO_Deadband;
}
else{
FT2_DO_Deadband = in;
}
};
thing[“Z1W1En”] << [](pson& in){
if(in.is_empty()){
in = Zone1Water1Enable;
}
else{
Zone1Water1Enable = in;
}
};
thing[“Z1W1StHr”] << [](pson& in){
if(in.is_empty()){
in = Zone1Water1StartHour;
}
else{
Zone1Water1StartHour = in;
}
};
thing[“Z1W1StMin”] << [](pson& in){
if(in.is_empty()){
in = Zone1Water1StartMinute;
}
else{
Zone1Water1StartMinute = in;
}
};
thing[“Z1W1Dur”] << [](pson& in){
if(in.is_empty()){
in = Zone1Water1Duration;
}
else{
Zone1Water1Duration = in;
}
};
thing[“Z1W2En”] << [](pson& in){
if(in.is_empty()){
in = Zone1Water2Enable;
}
else{
Zone1Water2Enable = in;
}
};
thing[“Z1W2StHr”] << [](pson& in){
if(in.is_empty()){
in = Zone1Water2StartHour;
}
else{
Zone1Water2StartHour = in;
}
};
thing[“Z1W2StMin”] << [](pson& in){
if(in.is_empty()){
in = Zone1Water2StartMinute;
}
else{
Zone1Water2StartMinute = in;
}
};
thing[“Z1W2Dur”] << [](pson& in){
if(in.is_empty()){
in = Zone1Water2Duration;
}
else{
Zone1Water2Duration = in;
}
};
thing[“Z1W3En”] << [](pson& in){
if(in.is_empty()){
in = Zone1Water3Enable;
}
else{
Zone1Water3Enable = in;
}
};
thing[“Z1W3StHr”] << [](pson& in){
if(in.is_empty()){
in = Zone1Water3StartHour;
}
else{
Zone1Water3StartHour = in;
}
};
thing[“Z1W3StMin”] << [](pson& in){
if(in.is_empty()){
in = Zone1Water3StartMinute;
}
else{
Zone1Water3StartMinute = in;
}
};
thing[“Z1W3Dur”] << [](pson& in){
if(in.is_empty()){
in = Zone1Water3Duration;
}
else{
Zone1Water3Duration = in;
}
};
thing[“Z1W4En”] << [](pson& in){
if(in.is_empty()){
in = Zone1Water4Enable;
}
else{
Zone1Water4Enable = in;
}
};
thing[“Z1W4StHr”] << [](pson& in){
if(in.is_empty()){
in = Zone1Water4StartHour;
}
else{
Zone1Water4StartHour = in;
}
};
thing[“Z1W4StMin”] << [](pson& in){
if(in.is_empty()){
in = Zone1Water4StartMinute;
}
else{
Zone1Water4StartMinute = in;
}
};
thing[“Z1W4Dur”] << [](pson& in){
if(in.is_empty()){
in = Zone1Water4Duration;
}
else{
Zone1Water4Duration = in;
}
};
thing[“Z1WtrOride”] << [](pson& in){
if(in.is_empty()){
in = Zone1WaterOverride;
}
else{
Zone1WaterOverride = in;
}
};
thing[“Z2W1En”] << [](pson& in){
if(in.is_empty()){
in = Zone2Water1Enable;
}
else{
Zone2Water1Enable = in;
}
};
thing[“Z2W1StHr”] << [](pson& in){
if(in.is_empty()){
in = Zone2Water1StartHour;
}
else{
Zone2Water1StartHour = in;
}
};
thing[“Z2W1StMin”] << [](pson& in){
if(in.is_empty()){
in = Zone2Water1StartMinute;
}
else{
Zone2Water1StartMinute = in;
}
};
thing[“Z2W1Dur”] << [](pson& in){
if(in.is_empty()){
in = Zone2Water1Duration;
}
else{
Zone2Water1Duration = in;
}
};
thing[“Z2W2En”] << [](pson& in){
if(in.is_empty()){
in = Zone2Water2Enable;
}
else{
Zone2Water2Enable = in;
}
};
thing[“Z2W2StHr”] << [](pson& in){
if(in.is_empty()){
in = Zone2Water2StartHour;
}
else{
Zone2Water2StartHour = in;
}
};
thing[“Z2W2StMin”] << [](pson& in){
if(in.is_empty()){
in = Zone2Water2StartMinute;
}
else{
Zone2Water2StartMinute = in;
}
};
thing[“Z2W2Dur”] << [](pson& in){
if(in.is_empty()){
in = Zone2Water2Duration;
}
else{
Zone2Water2Duration = in;
}
};
thing[“Z2W3En”] << [](pson& in){
if(in.is_empty()){
in = Zone2Water3Enable;
}
else{
Zone2Water3Enable = in;
}
};
thing[“Z2W3StHr”] << [](pson& in){
if(in.is_empty()){
in = Zone2Water3StartHour;
}
else{
Zone2Water3StartHour = in;
}
};
thing[“Z2W3StMin”] << [](pson& in){
if(in.is_empty()){
in = Zone2Water3StartMinute;
}
else{
Zone2Water3StartMinute = in;
}
};
thing[“Z2W3Dur”] << [](pson& in){
if(in.is_empty()){
in = Zone2Water3Duration;
}
else{
Zone2Water3Duration = in;
}
};
thing[“Z2W4En”] << [](pson& in){
if(in.is_empty()){
in = Zone2Water4Enable;
}
else{
Zone2Water4Enable = in;
}
};
thing[“Z2W4StHr”] << [](pson& in){
if(in.is_empty()){
in = Zone2Water4StartHour;
}
else{
Zone2Water4StartHour = in;
}
};
thing[“Z2W4StMin”] << [](pson& in){
if(in.is_empty()){
in = Zone2Water4StartMinute;
}
else{
Zone2Water4StartMinute = in;
}
};
thing[“Z2W4Dur”] << [](pson& in){
if(in.is_empty()){
in = Zone2Water4Duration;
}
else{
Zone2Water4Duration = in;
}
};
thing[“Z2WtrOride”] << [](pson& in){
if(in.is_empty()){
in = Zone2WaterOverride;
}
else{
Zone2WaterOverride = in;
}
};
thing[“NFTWtrOride”] << [](pson& in){
if(in.is_empty()){
in = NFTWaterOverride;
}
else{
NFTWaterOverride = in;
}
};
thing[“NFTWtrEnable”] << [](pson& in){
if(in.is_empty()){
in = NFTWaterEnable;
}
else{
NFTWaterEnable = in;
}
};
thing[“NFTWinterStHr”] << [](pson& in){
if(in.is_empty()){
in = NFTWinterStartHour;
}
else{
NFTWinterStartHour = in;
}
};
thing[“NFTWinterStMin”] << [](pson& in){
if(in.is_empty()){
in = NFTWinterStartMinute;
}
else{
NFTWinterStartMinute = in;
}
};
thing[“NFTWinterStpHr”] << [](pson& in){
if(in.is_empty()){
in = NFTWinterStopHour;
}
else{
NFTWinterStopHour = in;
}
};
thing[“NFTWinterStpMin”] << [](pson& in){
if(in.is_empty()){
in = NFTWinterStopMinute;
}
else{
NFTWinterStopMinute = in;
}
};
thing[“NFTMildStHr”] << [](pson& in){
if(in.is_empty()){
in = NFTMildStartHour;
}
else{
NFTMildStartHour = in;
}
};
thing[“NFTMildStMin”] << [](pson& in){
if(in.is_empty()){
in = NFTMildStartMinute;
}
else{
NFTMildStartMinute = in;
}
};
thing[“NFTMildStpHr”] << [](pson& in){
if(in.is_empty()){
in = NFTMildStopHour;
}
else{
NFTMildStopHour = in;
}
};
thing[“NFTMildStpMin”] << [](pson& in){
if(in.is_empty()){
in = NFTMildStopMinute;
}
else{
NFTMildStopMinute = in;
}
};
thing[“HXPumpEnable”] << [](pson& in){
if(in.is_empty()){
in = HXPumpEnable;
}
else{
HXPumpEnable = in;
}
};
thing[“HXPumpOverride”] << [](pson& in){
if(in.is_empty()){
in = HXPumpOverride;
}
else{
HXPumpOverride = in;
}
};
thing[“GBPumpEnable”] << [](pson& in){
if(in.is_empty()){
in = GBPumpEnable;
}
else{
GBPumpEnable = in;
}
};

//create a task that will be executed in the Task1code() function, with priority 1 and executed on core 0
xTaskCreatePinnedToCore(
Task1code, /* Task function. /
“Task1”, /
name of task. /
10000, /
Stack size of task /
NULL, /
parameter of the task /
1, /
priority of the task /
&Task1, /
Task handle to keep track of created task /
0); /
pin task to core 0 */
delay(500);
}

//Task1code: runs thinger.io loop, 1 core dedicated to communications
void Task1code( void * pvParameters ){
Serial.print("Thinger.io running on core ");
Serial.println(xPortGetCoreID());

for(;;){
thing.handle();
if(WiFi.status() == WL_CONNECTED){
digitalWrite(WIFI_LED, HIGH);
if(WiFi_Connected == 0){
Serial.print("WiFi Connected with IP Address ");
Serial.println(WiFi.localIP());
}
WiFi_Connected = 1;
}
else{
digitalWrite(WIFI_LED, LOW);
WiFi_Connected = 0;
}
if((WiFi_Connected == 1) and (Time_Set == 0)){
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
// Time_Set = 1;
// Serial.println(“Time Set”);
}
if(!getLocalTime(&timeinfo)){ //loads time data into timeinfo array
Serial.println(“Failed to obtain time”);
}
else if(Time_Set == 0){
Time_Set = 1;
Serial.println(“Time Set”);
}

if((WiFi_Connected == 1) and (Time_Reset == 0) and (timeinfo.tm_sec == 0) and (timeinfo.tm_min == 0) and (timeinfo.tm_hour == 0)){
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
Time_Reset = 1;
Serial.println(“Time Reset”);
}
if(timeinfo.tm_sec != 0){
Time_Reset = 0;
}
StringTime = timeinfo.tm_hour;
StringTime = StringTime + “:”;
StringTime = StringTime + timeinfo.tm_min;
StringTime = StringTime + “:”;
StringTime = StringTime + timeinfo.tm_sec;
DailyMinute = (timeinfo.tm_hour*60)+timeinfo.tm_min;

delay(1000);      //Delay to slow Thinger.handle down and stop Watchdog Tripping

}
}

Hi,

having a delay of 1 second in the thinger.io loop is not a good idea, at least if you have such amount of resources that can be used in the dashboard. How is your dashboard? interval for plotting data? Did you tried to execute the thinger.io loop on core1?

Hi @LenHall,

Sorry to tell you this, but it is so uncomfortable and annoying to read code as plain text and especially code as long as yours, please publish it as code by selecting the text and pressing the “</>” button on the toolbar.

Make easier for us to give you help.

Regards.

Hi alvarolb,
I removed the 1 sec delay, it was not required anymore anyway as I found a way to disable the core watchdog. As well as that I have lowered the update time on all Widgets to 30 sec, update speed is greatly improved, however from time to time a dashboard stops updating and this can be a nuisance when you make a change to an On/Off Button or Slider, it appears that the change has been made but the processor does not see it. You have to refresh the screen and try again, of course you would only notice this when you are sitting right beside the controller.
If you run thinger.io in core 1 the program stops when you first connect to WiFi or lose WiFi connection, if you are controlling as well as monitoring this is not acceptable.

Thanks for your help.