/* ; Project: ESP GLCD SOLAR MONITOR ; Date: 3rd Sep 2022 ; ; (C) 2022 Carsten Schmiemann ; ; Permission is hereby granted, free of charge, to any person obtaining a copy ; of this software and associated documentation files (the "Software"), to deal ; in the Software without restriction, including without limitation the rights ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ; copies of the Software, and to permit persons to whom the Software is ; furnished to do so, subject to the following conditions: ; ; The above copyright notice and this permission notice shall be included in ; all copies or substantial portions of the Software. ; ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ; THE SOFTWARE. */ //#include #include #ifdef ESP32 #include #define Flash SPIFFS #include #endif #ifdef ESP8266 #include #define Flash LittleFS #include #endif #include #include #include #include #include #include #include #include "time.h" //Program parts #include #include #include char VERSION[6] = "v1.0"; //Defaults char mqtt_server[15] = ""; char gx_vrm_id[20] = ""; char disp_refresh_interval[6] = "500"; char disp_screen_interval[6] = "10000"; char address_pv_charger[6] = ""; char address_grid_meter[6] = ""; char address_inverter[6] = ""; char address_battery[6] = ""; char address_outside_temperature[6] = ""; char display_lang[6] = ""; char time_zone[40] = "CET-1CEST,M3.5.0,M10.5.0/3"; // Europe/Berlin char time_server[20] = ""; char show_graph[4] = ""; char show_statistics[4] = ""; long unsigned int DISPLAY_REFRESH_INTERVAL; long unsigned int DISPLAY_SCREEN_INTERVAL; //MQTT connect strings char mqtt_pv_voltage[80]; char mqtt_pv_power[80]; char mqtt_pv_yield[80]; char mqtt_pv_bat_current[80]; char mqtt_grid_power[80]; char mqtt_inv_power[80]; char mqtt_inv_current[80]; char mqtt_bat_soc[80]; char mqtt_bat_voltage[80]; char mqtt_bat_current[80]; char mqtt_bat_power[80]; char mqtt_bat_max_cell_volt[80]; char mqtt_bat_min_cell_volt[80]; char mqtt_temp_outside[80]; char mqtt_grid_power_l1[80]; char mqtt_grid_power_l2[80]; char mqtt_grid_power_l3[80]; //Display config bool display_conf_temp_oa_present = false; bool display_conf_time_present = false; bool display_conf_dc_pvcharger_present = false; bool display_conf_graph_present = false; bool display_conf_statistics_present = false; const int display_graph_buffersize = 110; float display_graph_ringbuffer_load_1h[display_graph_buffersize] = { 0 }; float display_graph_ringbuffer_load_24h[display_graph_buffersize] = { 0 }; float display_graph_ringbuffer_pv_1h[display_graph_buffersize] = { 0 }; float display_graph_ringbuffer_pv_24h[display_graph_buffersize] = { 0 }; int display_refresh_counter = 0; int display_refresh_time; //WiFiManager flag for saving data bool shouldSaveConfig = false; //WiFiManager callback notifying us of the need to save config void saveConfigCallback () { logPrintlnI("Should save config"); shouldSaveConfig = true; } //Library setup WiFiClient espClient; PubSubClient client(espClient); //Time library setup time_t now; tm tm; //Globals long lastMsg = 0; char msg[50]; float pv_v = 0, pv_w = 0, pv_i = 0, pv_kwh = 0, inv_p = 0, inv_i = 0, batt_v = 0, batt_i = 0, batt_p = 0, batt_c_min = 0, batt_c_max = 0, grid_p = 0, consum_p = 0, batt_soc = 0, load_ph1 = 0, load_ph2 = 0, load_ph3 = 0; bool lastButtonRotationState = HIGH, lastButtonSetupState = HIGH; bool currentButtonRotationState, currentButtonSetupState; static unsigned long lastDispRefreshTime = 0; static unsigned long lastScreenChangeTime = 0; static unsigned long lastGraphRecord_1h = 0; static unsigned long lastGraphRecord_24h = 0; int display_screen = 0; //Display graph ringbuffer void display_graph_ringbuffer_add(float ringbuffer [display_graph_buffersize], float value) { ringbuffer[0] = value; memmove(ringbuffer, ringbuffer + 1, sizeof(int)*(display_graph_buffersize - 1)); ringbuffer[display_graph_buffersize - 1] = value; } //MQTT topics void callback(char* topic, byte* message, unsigned int length) { logPrintlnD("Message arrived on topic: "); logPrintlnD(topic); logPrintlnD("Message: "); String messageTemp; //Status LED flash on receive digitalWrite(STATUS_LED, !digitalRead(STATUS_LED)); for (byte i = 0; i < length; i++) { char tmp = char(message[i]); messageTemp += tmp; } logPrintlnD(messageTemp); //PV Charger - solar voltage if (String(topic) == mqtt_pv_voltage) { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); pv_v = json["value"]; } //PV Charger - solar power if (String(topic) == mqtt_pv_power) { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); pv_w = json["value"]; } //PV Charger - solar yield if (String(topic) == mqtt_pv_yield) { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); pv_kwh = json["value"]; } //PV Charger - bat charge current if (String(topic) == mqtt_pv_bat_current) { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); pv_i = json["value"]; } //Grid meter - power if (String(topic) == mqtt_grid_power) { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); grid_p = json["value"]; } //Inverter - power if (String(topic) == mqtt_inv_power) { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); inv_p = json["value"]; } //Inverter - current if (String(topic) == mqtt_inv_current) { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); inv_i = json["value"]; } //Battery - SOC if (String(topic) == mqtt_bat_soc) { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); batt_soc = json["value"]; } //Battery - voltage if (String(topic) == mqtt_bat_voltage) { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); batt_v = json["value"]; } //Battery - current if (String(topic) == mqtt_bat_current) { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); batt_i = json["value"]; } //Battery - power if (String(topic) == mqtt_bat_power) { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); batt_p = json["value"]; } //Battery - max cell volts if (String(topic) == mqtt_bat_max_cell_volt) { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); batt_c_max = json["value"]; } //Battery - min cell volts if (String(topic) == mqtt_bat_min_cell_volt) { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); batt_c_min = json["value"]; } //Temperature - outside if (String(topic) == mqtt_temp_outside) { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); display_temp_outside(json["value"]); } //System - AC Load Phase 1 if (String(topic) == mqtt_grid_power_l1) { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); load_ph1 = json["value"]; consum_p = load_ph1 + load_ph2 + load_ph3; //calc consumption on each msg for faster response } //System - AC Load Phase 2 if (String(topic) == mqtt_grid_power_l2) { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); load_ph2 = json["value"]; consum_p = load_ph1 + load_ph2 + load_ph3; //calc consumption on each msg for faster response } //System - AC Load Phase 3 if (String(topic) == mqtt_grid_power_l3) { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); load_ph3 = json["value"]; consum_p = load_ph1 + load_ph2 + load_ph3; //calc consumption on each msg for faster response } } //Wifi re-/connect void reconnect() { // Loop until we're reconnected while (!client.connected()) { logPrintlnI("Attempting MQTT connection..."); display_text((char*)"Connect to GX MQTT...", mqtt_server); delay(2000); // Attempt to connect if (client.connect("PV_solar_monitor")) { logPrintlnI("connected"); // Subscribe if (display_conf_dc_pvcharger_present) { client.subscribe(mqtt_pv_voltage); client.subscribe(mqtt_pv_power); client.subscribe(mqtt_pv_yield); client.subscribe(mqtt_pv_bat_current); } client.subscribe(mqtt_grid_power); client.subscribe(mqtt_inv_power); client.subscribe(mqtt_inv_current); client.subscribe(mqtt_bat_soc); client.subscribe(mqtt_bat_voltage); client.subscribe(mqtt_bat_current); client.subscribe(mqtt_bat_power); client.subscribe(mqtt_bat_max_cell_volt); client.subscribe(mqtt_bat_min_cell_volt); if (display_conf_temp_oa_present) { client.subscribe(mqtt_temp_outside); } client.subscribe(mqtt_grid_power_l1); client.subscribe(mqtt_grid_power_l2); client.subscribe(mqtt_grid_power_l3); logPrintlnI("subscribed to topics"); } else { logPrintlnE("failed, rc="); logPrintlnE((char*)client.state()); logPrintlnE(" try again in 10 seconds"); String msg = " MQTT Error rc=" + (String)client.state(); display_text_fullscreen((char*)"MQTT Connection Error", (char*)"Did you enable MQTT", (char*)"on your GX device?", (char*)msg.c_str(), (char*)"", (char*)"Retry in 10 seconds..."); // Wait 10 seconds before retrying delay(5000); } } } void setup() { Serial.begin(115200); logPrintlnI("Booting..."); pinMode(BUTTON_ROTATION, INPUT_PULLUP); pinMode(BUTTON_SETUP, INPUT_PULLUP); pinMode(STATUS_LED, OUTPUT); display_begin(); logPrintlnI("Display init..."); display_init(VERSION); delay(2000); //read configuration from Flash json logPrintlnI("mounting Flash..."); if (Flash.begin()) { logPrintlnI("mounted file system"); if (Flash.exists("/config.json")) { //file exists, reading and loading logPrintlnI("reading config file"); File configFile = Flash.open("/config.json", "r"); if (configFile) { logPrintlnI("opened config file"); size_t size = configFile.size(); // Allocate a buffer to store contents of the file. std::unique_ptr buf(new char[size]); configFile.readBytes(buf.get(), size); #if defined(ARDUINOJSON_VERSION_MAJOR) && ARDUINOJSON_VERSION_MAJOR >= 6 DynamicJsonDocument json(1024); auto deserializeError = deserializeJson(json, buf.get()); serializeJson(json, Serial); if ( ! deserializeError ) { #else DynamicJsonBuffer jsonBuffer; JsonObject& json = jsonBuffer.parseObject(buf.get()); json.printTo(Serial); if (json.success()) { #endif logPrintlnI("\nparsed json"); strcpy(mqtt_server, json["mqtt_server"]); strcpy(gx_vrm_id, json["gx_vrm_id"]); strcpy(disp_refresh_interval, json["disp_refresh_interval"]); strcpy(disp_screen_interval, json["disp_screen_interval"]); strcpy(address_pv_charger, json["address_pv_charger"]); strcpy(address_grid_meter, json["address_grid_meter"]); strcpy(address_inverter, json["address_inverter"]); strcpy(address_battery, json["address_battery"]); strcpy(address_outside_temperature, json["address_outside_temperature"]); strcpy(display_lang, json["display_language"]); strcpy(time_zone, json["time_zone"]); strcpy(time_server, json["time_server"]); strcpy(show_graph, json["show_graph"]); strcpy(show_statistics, json["show_statistics"]); } else { logPrintlnI("failed to load json config"); } configFile.close(); } } } else { logPrintlnI("failed to mount Flash"); } delay(2000); String bootmsg = "Booting solar monitor app..." + (String)VERSION; logPrintlnI(bootmsg.c_str()); display_text((char*)"Connect to AP:PV_Mon", (char*)" for configuration"); #ifdef ESP8266 WiFi.hostname("ESP_Solar_Monitor"); #endif #ifdef ESP32 WiFi.setHostname("ESP_Solar_Monitor"); #endif //Wifi Manager parameters WiFiManagerParameter custom_mqtt_server("mqtt_server", "IP adress of GX Device (MQTT No SSL)", mqtt_server, 15); WiFiManagerParameter custom_gx_vrm_id("gx_vrm_id", "VRM ID of GX device", gx_vrm_id, 20); WiFiManagerParameter custom_disp_refresh_interval("disp_refresh_interval", "Refresh cycle of display in ms", disp_refresh_interval, 6); WiFiManagerParameter custom_disp_screen_interval("disp_screen_interval", "Rotation time of screens in ms", disp_screen_interval, 6); WiFiManagerParameter custom_address_pv_charger("address_pv_charger", "Address of pv charger", address_pv_charger, 6); WiFiManagerParameter custom_address_grid_meter("address_grid_meter", "Address of grid meter", address_grid_meter, 6); WiFiManagerParameter custom_address_inverter("address_inverter", "Address of vebus inverter", address_inverter, 6); WiFiManagerParameter custom_address_battery("address_battery", "Address of can battery", address_battery, 6); WiFiManagerParameter custom_address_outside_temperature("address_outside_temperature", "Address of outside temperature", address_outside_temperature, 6); WiFiManagerParameter custom_display_lang("display_lang", "Display language en, de", display_lang, 6); WiFiManagerParameter custom_time_zone("time_zone", "Set timezone string", time_zone, 40); WiFiManagerParameter custom_time_server("time_server", "Set time server", time_server, 20); WiFiManagerParameter custom_show_graph("show_graph", "Show PV graph yes=enable", show_graph, 4); WiFiManagerParameter custom_show_statistics("show_statistics", "Show statistics screen yes=enable", show_statistics, 4); WiFiManager wm; wm.setSaveConfigCallback(saveConfigCallback); wm.addParameter(&custom_mqtt_server); wm.addParameter(&custom_gx_vrm_id); wm.addParameter(&custom_disp_refresh_interval); wm.addParameter(&custom_disp_screen_interval); wm.addParameter(&custom_address_pv_charger); wm.addParameter(&custom_address_grid_meter); wm.addParameter(&custom_address_inverter); wm.addParameter(&custom_address_battery); wm.addParameter(&custom_address_outside_temperature); wm.addParameter(&custom_display_lang); wm.addParameter(&custom_time_zone); wm.addParameter(&custom_time_server); wm.addParameter(&custom_show_graph); wm.addParameter(&custom_show_statistics); //Start wifi manager configuration if BUTTON_SETUP is pressed on start-up currentButtonSetupState = digitalRead(BUTTON_SETUP); if(lastButtonSetupState == HIGH && currentButtonSetupState == LOW) { display_text((char*)"Connect to AP:PV_Mon", (char*)"for re-configuration"); wm.startConfigPortal("PV_Mon"); } else { wm.autoConnect("PV_Mon"); } display_text((char*)" Connecting wifi...", (char*)""); delay(500); logPrintlnI("Connecting wifi..."); IPAddress ip = WiFi.localIP(); strcpy(mqtt_server, custom_mqtt_server.getValue()); strcpy(gx_vrm_id, custom_gx_vrm_id.getValue()); strcpy(disp_refresh_interval, custom_disp_refresh_interval.getValue()); strcpy(disp_screen_interval, custom_disp_screen_interval.getValue()); strcpy(address_pv_charger, custom_address_pv_charger.getValue()); strcpy(address_grid_meter, custom_address_grid_meter.getValue()); strcpy(address_inverter, custom_address_inverter.getValue()); strcpy(address_battery, custom_address_battery.getValue()); strcpy(address_outside_temperature, custom_address_outside_temperature.getValue()); strcpy(display_lang, custom_display_lang.getValue()); strcpy(time_zone, custom_time_zone.getValue()); strcpy(time_server, custom_time_server.getValue()); strcpy(show_graph, custom_show_graph.getValue()); strcpy(show_statistics, custom_show_statistics.getValue()); DISPLAY_REFRESH_INTERVAL = strtol(disp_refresh_interval, NULL, 10); DISPLAY_SCREEN_INTERVAL = strtol(disp_screen_interval, NULL, 10); display_refresh_time = DISPLAY_SCREEN_INTERVAL / DISPLAY_REFRESH_INTERVAL; //parse config and set display parameter if (strtol(address_outside_temperature, NULL, 10) != 0) { display_conf_temp_oa_present = true; } else { display_conf_temp_oa_present = false; } if (strcmp(time_server,"") != 0) { display_conf_time_present = true; } else { display_conf_time_present = false; } if (strtol(address_pv_charger, NULL, 10) != 0) { display_conf_dc_pvcharger_present = true; } else { display_conf_dc_pvcharger_present = false; } if (strcmp(show_graph,"yes") == 0) { display_conf_graph_present = true; } else { display_conf_graph_present = false; } if (strcmp(show_statistics,"yes") == 0) { display_conf_statistics_present = true; } else { display_conf_statistics_present = false; } display_setup(display_lang, display_conf_temp_oa_present, display_conf_time_present, display_conf_dc_pvcharger_present, display_conf_graph_present, display_conf_statistics_present); client.setServer(mqtt_server, 1883); client.setCallback(callback); char* ip_address = new char[40](); sprintf(ip_address, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); display_text((char*)" Connected. IP:", ip_address); //save the custom parameters to Flash if (shouldSaveConfig) { logPrintlnI("saving config"); #if defined(ARDUINOJSON_VERSION_MAJOR) && ARDUINOJSON_VERSION_MAJOR >= 6 DynamicJsonDocument json(1024); #else DynamicJsonBuffer jsonBuffer; JsonObject& json = jsonBuffer.createObject(); #endif json["mqtt_server"] = mqtt_server; json["gx_vrm_id"] = gx_vrm_id; json["disp_refresh_interval"] = disp_refresh_interval; json["disp_screen_interval"] = disp_screen_interval; json["address_pv_charger"] = address_pv_charger; json["address_grid_meter"] = address_grid_meter; json["address_inverter"] = address_inverter; json["address_battery"] = address_battery; json["address_outside_temperature"] = address_outside_temperature; json["display_language"] = display_lang; json["time_zone"] = time_zone; json["time_server"] = time_server; json["show_graph"] = show_graph; json["show_statistics"] = show_statistics; File configFile = Flash.open("/config.json", "w"); if (!configFile) { logPrintlnI("failed to open config file for writing"); } #if defined(ARDUINOJSON_VERSION_MAJOR) && ARDUINOJSON_VERSION_MAJOR >= 6 serializeJson(json, Serial); serializeJson(json, configFile); #else json.printTo(Serial); json.printTo(configFile); #endif configFile.close(); //end save } if (display_conf_time_present) { //NTP setup #ifdef ESP32 configTime(0, 0, time_server); setenv("TZ", time_zone, 1); tzset(); #endif #ifdef ESP8266 configTime(time_zone, time_server); #endif } delay(1000); //for screen display //Generate mqtt topics from id and address logPrintlnI("-------------- MQTT topic list --------------"); sprintf(mqtt_pv_voltage, "N/%s/solarcharger/%s/Pv/V", gx_vrm_id, address_pv_charger); logPrintlnI(mqtt_pv_voltage); sprintf(mqtt_pv_power, "N/%s/solarcharger/%s/Yield/Power", gx_vrm_id, address_pv_charger); logPrintlnI(mqtt_pv_power); sprintf(mqtt_pv_yield, "N/%s/solarcharger/%s/History/Daily/0/Yield", gx_vrm_id, address_pv_charger); logPrintlnI(mqtt_pv_yield); sprintf(mqtt_pv_bat_current, "N/%s/solarcharger/%s/Dc/0/Current", gx_vrm_id, address_pv_charger); logPrintlnI(mqtt_pv_bat_current); sprintf(mqtt_grid_power, "N/%s/grid/%s/Ac/Power", gx_vrm_id, address_grid_meter); logPrintlnI(mqtt_grid_power); sprintf(mqtt_inv_power, "N/%s/vebus/%s/Ac/ActiveIn/L1/P", gx_vrm_id, address_inverter); logPrintlnI(mqtt_inv_power); sprintf(mqtt_inv_current, "N/%s/vebus/%s/Dc/0/Current", gx_vrm_id, address_inverter); logPrintlnI(mqtt_inv_current); sprintf(mqtt_bat_soc, "N/%s/battery/%s/Soc", gx_vrm_id, address_battery); logPrintlnI(mqtt_bat_soc); sprintf(mqtt_bat_voltage, "N/%s/battery/%s/Dc/0/Voltage", gx_vrm_id, address_battery); logPrintlnI(mqtt_bat_voltage); sprintf(mqtt_bat_current, "N/%s/battery/%s/Dc/0/Current", gx_vrm_id, address_battery); logPrintlnI(mqtt_bat_current); sprintf(mqtt_bat_power, "N/%s/battery/%s/Dc/0/Power", gx_vrm_id, address_battery); logPrintlnI(mqtt_bat_power); sprintf(mqtt_bat_max_cell_volt, "N/%s/battery/%s/System/MaxCellVoltage", gx_vrm_id, address_battery); logPrintlnI(mqtt_bat_max_cell_volt); sprintf(mqtt_bat_min_cell_volt, "N/%s/battery/%s/System/MinCellVoltage", gx_vrm_id, address_battery); logPrintlnI(mqtt_bat_min_cell_volt); sprintf(mqtt_temp_outside, "N/%s/temperature/%s/Temperature", gx_vrm_id, address_outside_temperature); logPrintlnI(mqtt_temp_outside); sprintf(mqtt_grid_power_l1, "N/%s/system/0/Ac/ConsumptionOnInput/L1/Power", gx_vrm_id); logPrintlnI(mqtt_grid_power_l1); sprintf(mqtt_grid_power_l2, "N/%s/system/0/Ac/ConsumptionOnInput/L2/Power", gx_vrm_id); logPrintlnI(mqtt_grid_power_l2); sprintf(mqtt_grid_power_l3, "N/%s/system/0/Ac/ConsumptionOnInput/L3/Power", gx_vrm_id); logPrintlnI(mqtt_grid_power_l3); Serial.println(); Serial.println("-------------- Settings --------------"); Serial.print("mqtt server: "); Serial.println(mqtt_server); Serial.print("gx_vrm_id: "); Serial.println(gx_vrm_id); Serial.print("disp_refresh_interval: "); Serial.println(DISPLAY_REFRESH_INTERVAL); Serial.print("disp_screen_interval: "); Serial.println(DISPLAY_SCREEN_INTERVAL); Serial.print("display language: "); Serial.println(display_lang); Serial.print("display temp present: "); Serial.println(display_conf_temp_oa_present); Serial.print("display time present: "); Serial.println(display_conf_time_present); Serial.print("display dc pc chg present: "); Serial.println(display_conf_dc_pvcharger_present); Serial.print("display graph present: "); Serial.println(display_conf_graph_present); Serial.print("display stats present: "); Serial.println(display_conf_statistics_present); display_text_fullscreen((char*)"Configuration summary", (char*)"GX MQTT Server IP:", mqtt_server, (char*)"GX VRM ID:", gx_vrm_id, (char*)" 1/2"); delay(3000); display_text_fullscreen((char*)"Configuration summary", (char*)"Disp. Refresh:", disp_refresh_interval, (char*)"Disp. rotation:", disp_screen_interval, (char*)" 2/2"); delay(3000); lastDispRefreshTime = millis(); lastScreenChangeTime = millis(); lastGraphRecord_1h = millis(); lastGraphRecord_24h = millis(); } void loop() { //Refresh display values if(millis() - lastDispRefreshTime >= DISPLAY_REFRESH_INTERVAL) { digitalWrite(STATUS_LED, LOW); //Turn Status LED ON again lastDispRefreshTime += DISPLAY_REFRESH_INTERVAL; if (display_refresh_counter <= display_refresh_time) { display_screen_grid(grid_p, consum_p, inv_p, inv_i, pv_w); } if (display_refresh_counter >= display_refresh_time && display_refresh_counter <= (display_refresh_time*2)) { display_screen_battery(batt_v, batt_i, batt_p, batt_soc, batt_c_min, batt_c_max); } if (display_refresh_counter >= (display_refresh_time*2) && display_refresh_counter <= (display_refresh_time*3)) { if (display_conf_dc_pvcharger_present) { display_screen_pv(pv_v, pv_w, batt_v, pv_i, pv_kwh); } else { display_refresh_counter = (display_refresh_time*3) + 1; } } if (display_refresh_counter >= (display_refresh_time*3) && display_refresh_counter <= (display_refresh_time*4)) { if (display_conf_graph_present) { display_screen_graph(display_graph_ringbuffer_load_1h, (char*)"1h", 0, display_graph_buffersize); } else { display_refresh_counter = (display_refresh_time*4) + 1; } } if (display_refresh_counter >= (display_refresh_time*4) && display_refresh_counter <= (display_refresh_time*5)) { if (display_conf_graph_present) { display_screen_graph(display_graph_ringbuffer_load_24h, (char*)"24h", 0, display_graph_buffersize); } else { display_refresh_counter = (display_refresh_time*5) + 1; } } if (display_refresh_counter >= (display_refresh_time*5) && display_refresh_counter <= (display_refresh_time*6)) { if (display_conf_graph_present && display_conf_dc_pvcharger_present) { display_screen_graph(display_graph_ringbuffer_pv_1h, (char*)"1h", 1, display_graph_buffersize); } else { display_refresh_counter = (display_refresh_time*6) + 1; } } if (display_refresh_counter >= (display_refresh_time*6) && display_refresh_counter <= (display_refresh_time*7)) { if (display_conf_graph_present && display_conf_dc_pvcharger_present) { display_screen_graph(display_graph_ringbuffer_pv_24h, (char*)"24h", 1, display_graph_buffersize); } else { display_refresh_counter = (display_refresh_time*7) + 1; } } if (display_refresh_counter >= (display_refresh_time*7) && display_refresh_counter <= (display_refresh_time*8)) { if (display_conf_statistics_present) { //To Do: display_screen_statistics(mqtt_grid_power_l1, mqtt_grid_power_l2, mqtt_grid_power_l3); } else { display_refresh_counter = (display_refresh_time*8) + 1; } } display_refresh_counter++; if (display_refresh_counter > (display_refresh_time*8)) { display_refresh_counter = 0; } } //Change screen after time if intervall setting not zero if (DISPLAY_SCREEN_INTERVAL != 0) { if(millis() - lastScreenChangeTime >= DISPLAY_SCREEN_INTERVAL) { time(&now); localtime_r(&now, &tm); //Get local time display_time(tm.tm_hour, tm.tm_min); lastScreenChangeTime += DISPLAY_SCREEN_INTERVAL; } } //Graph recorder - 1h if (display_conf_graph_present) { if(millis() - lastGraphRecord_1h >= ((1 *60*60*1000 ) / display_graph_buffersize)) //temporarily set to half minute { display_graph_ringbuffer_add(display_graph_ringbuffer_load_1h, consum_p); if (display_conf_dc_pvcharger_present) { display_graph_ringbuffer_add(display_graph_ringbuffer_pv_1h, pv_w); } lastGraphRecord_1h += (1 *60*60*1000 ) / display_graph_buffersize; } if(millis() - lastGraphRecord_24h >= ((24 *60*60*1000 ) / display_graph_buffersize)) { display_graph_ringbuffer_add(display_graph_ringbuffer_load_24h, consum_p); if (display_conf_dc_pvcharger_present) { display_graph_ringbuffer_add(display_graph_ringbuffer_pv_24h, pv_w); } lastGraphRecord_24h += (24 *60*60*1000 ) / display_graph_buffersize; } } //Rotate screen if BUTTON_ROTATION is pressed currentButtonRotationState = digitalRead(BUTTON_ROTATION); if(lastButtonRotationState == HIGH && currentButtonRotationState == LOW) { display_screen++; lastButtonRotationState = currentButtonRotationState; } if (!client.connected()) { reconnect(); } client.loop(); }