Compare commits

...

10 Commits

5 changed files with 197 additions and 66 deletions

View File

@ -39,6 +39,9 @@ U8G2_ST7920_128X64_F_HW_SPI display(U8G2_R2, LCD_CS, U8X8_PIN_NONE);
char* title_pv;
char* title_battery;
char* title_grid;
char* title_graph;
char* title_graph_load;
char* title_graph_pv;
bool pv_charging = false;
bool show_temp_outside;
@ -244,29 +247,90 @@ void display_screen_grid(float grid_power, float consum, float inv_power, float
}
//Graph last 100 values
void display_screen_graph(float values[100])
void display_screen_graph(float *values, char* key, int type, int buffersize)
{
logPrintD("Display graph...");
logPrintlnD("Display graph...");
display.firstPage();
do {
display_header((char*)"Graph");
display.drawLine(7, 60, 9, 60); //X mark
display.drawLine(9, 8, 9, 62); //Y boarder
display.drawStr(1,17, "1");
display.drawStr(1,40, "5");
display.drawStr(1,63, "0");
display.drawLine(7, 36, 9, 36); //marker Y 5
display.drawLine(7, 13, 9, 13); //marker Y 1
display_header(title_graph);
if (type == 0)
{
display.drawStr(58,17, title_graph_load);
}
else if (type == 1)
{
display.drawStr(58,17, title_graph_pv);
}
display.drawLine(16, 60, 9, 60); //X mark
display.drawLine(15, 8, 15, 62); //Y boarder
display.drawStr(7,63, "0");
display.drawStr(7,34, "k");
display.drawStr(7,46, "W");
display.drawLine(13, 36, 15, 36); //marker Y 5
display.drawLine(13, 13, 15, 13); //marker Y 1
for (int i = 19; i<120; i += 10)
for (int i = 25; i<120; i += 10)
{
display.drawLine(i, 60, i, 62); //marker X
}
for (int i = 0; i<126; i++)
// Auto-scale graph (scale 1kW to 15kW automatically)
float max = values[0];
// find highest value
for (int i = 0; i<buffersize; i++)
{
display.drawLine((10+i), 60, (10+i), map(values[i], 0, 1000, 60, 10));
if (max < values[i])
{
max = values[i];
}
}
int graph_max_kW = 1000;
if (max > 1000) { graph_max_kW = 2000; }
if (max > 2000) { graph_max_kW = 3000; }
if (max > 3000) { graph_max_kW = 4000; }
if (max > 4000) { graph_max_kW = 5000; }
if (max > 5000) { graph_max_kW = 6000; }
if (max > 6000) { graph_max_kW = 7000; }
if (max > 7000) { graph_max_kW = 8000; }
if (max > 8000) { graph_max_kW = 9000; }
if (max > 9000) { graph_max_kW = 10000; }
if (max > 10000) { graph_max_kW = 11000; }
if (max > 11000) { graph_max_kW = 12000; }
if (max > 12000) { graph_max_kW = 13000; }
if (max > 13000) { graph_max_kW = 14000; }
if (max > 14000) { graph_max_kW = 15000; }
if (max > 15000) { graph_max_kW = 16000; }
if (max > 16000) { graph_max_kW = 17000; }
if (max > 17000) { graph_max_kW = 18000; }
if (max > 18000) { graph_max_kW = 19000; }
if (max > 19000) { graph_max_kW = 20000; }
if (max > 20000) { graph_max_kW = 21000; }
if (max > 21000) { graph_max_kW = 22000; }
if (max > 22000) { graph_max_kW = 23000; }
if (max > 23000) { graph_max_kW = 24000; }
if ((graph_max_kW/1000) < 10)
{
display.setCursor(7,17);
}
else
{
display.setCursor(1,17);
}
display.print(graph_max_kW/1000);
for (int i = 0; i<buffersize; i++)
{
display.drawLine((15+i), 60, (15+i), map(values[i], 0, graph_max_kW, 60, 13));
}
if (strlen(key) < 3) {
display.drawStr(117, 17, key);
}
else
{
display.drawStr(111, 17, key);
}
} while ( display.nextPage() );
}

View File

@ -35,4 +35,4 @@ void display_header(char* TEXT);
void display_screen_pv(float pv_voltage, float pv_wattage, float battery_voltage, float pv_amps, float pv_kwh);
void display_screen_battery(float battery_voltage, float battery_amps, float battery_wattage, float battery_soc, float batt_cell_v_min, float batt_cell_v_max);
void display_screen_grid(float grid_power, float consum, float inv_power, float inv_current, float pv_wattage);
void display_screen_graph(float values[100]);
void display_screen_graph(float *values, char* key, int type, int buffersize);

View File

@ -32,11 +32,17 @@ void set_display_language(char lang[2])
title_pv = (char*)"PV Module";
title_battery = (char*)"Batterie";
title_grid = (char*)"Netz";
title_graph = (char*)"Verlauf";
title_graph_load = (char*)"Last";
title_graph_pv = (char*)"PV";
}
else
{
title_pv = (char*)"PV modules";
title_battery = (char*)"Battery";
title_grid = (char*)"Grid";
title_graph = (char*)"Graph";
title_graph_load = (char*)"Load";
title_graph_pv = (char*)"PV";
}
}

View File

@ -25,5 +25,8 @@
extern char* title_pv;
extern char* title_battery;
extern char* title_grid;
extern char* title_graph;
extern char* title_graph_load;
extern char* title_graph_pv;
void set_display_language(char lang[2]);

View File

@ -49,7 +49,7 @@
#include <lang.h>
#include <display.h>
char VERSION[6] = "v0.9a";
char VERSION[6] = "v0.9d";
//Defaults
char mqtt_server[15] = "";
@ -92,10 +92,13 @@ char mqtt_grid_power_l3[80];
bool display_conf_temp_oa_present = false;
bool display_conf_time_present = false;
bool display_conf_dc_pvcharger_present = false;
bool display_conf_graph_pv_present = false;
bool display_conf_graph_present = false;
bool display_conf_statistics_present = false;
float display_graph_ringbuffer[126] = { 0 };
int display_graph_ringbuffer_index = 0;
float display_graph_ringbuffer_load_1h[100] = { 0 };
float display_graph_ringbuffer_load_24h[100] = { 0 };
float display_graph_ringbuffer_pv_1h[100] = { 0 };
float display_graph_ringbuffer_pv_24h[100] = { 0 };
const int display_graph_buffersize = 100;
int display_refresh_counter = 0;
int display_refresh_time;
@ -104,7 +107,7 @@ bool shouldSaveConfig = false;
//WiFiManager callback notifying us of the need to save config
void saveConfigCallback () {
Serial.println("Should save config");
logPrintlnI("Should save config");
shouldSaveConfig = true;
}
@ -125,14 +128,15 @@ 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 value) {
float tmp = value;
display_graph_ringbuffer[0] = value;
memmove(display_graph_ringbuffer,display_graph_ringbuffer+1,sizeof(int)*(125));
display_graph_ringbuffer[125] = tmp;
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
@ -181,9 +185,6 @@ void callback(char* topic, byte* message, unsigned int length) {
DynamicJsonDocument json(512);
deserializeJson(json, messageTemp);
grid_p = json["value"];
//add every measurement to rbuffer
display_graph_ringbuffer_add(grid_p);
}
//Inverter - power
@ -315,26 +316,26 @@ void reconnect() {
void setup() {
Serial.begin(115200);
Serial.println("Booting...");
logPrintlnI("Booting...");
pinMode(BUTTON_ROTATION, INPUT_PULLUP);
pinMode(BUTTON_SETUP, INPUT_PULLUP);
pinMode(STATUS_LED, OUTPUT);
display_begin();
Serial.println("Display init...");
logPrintlnI("Display init...");
display_init(VERSION);
delay(2000);
//read configuration from Flash json
Serial.println("mounting Flash...");
logPrintlnI("mounting Flash...");
if (Flash.begin()) {
Serial.println("mounted file system");
logPrintlnI("mounted file system");
if (Flash.exists("/config.json")) {
//file exists, reading and loading
Serial.println("reading config file");
logPrintlnI("reading config file");
File configFile = Flash.open("/config.json", "r");
if (configFile) {
Serial.println("opened config file");
logPrintlnI("opened config file");
size_t size = configFile.size();
// Allocate a buffer to store contents of the file.
std::unique_ptr<char[]> buf(new char[size]);
@ -352,7 +353,7 @@ void setup() {
json.printTo(Serial);
if (json.success()) {
#endif
Serial.println("\nparsed json");
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"]);
@ -368,13 +369,13 @@ void setup() {
strcpy(show_graph, json["show_graph"]);
strcpy(show_statistics, json["show_statistics"]);
} else {
Serial.println("failed to load json config");
logPrintlnI("failed to load json config");
}
configFile.close();
}
}
} else {
Serial.println("failed to mount Flash");
logPrintlnI("failed to mount Flash");
}
delay(2000);
@ -483,11 +484,11 @@ void setup() {
}
if (strcmp(show_graph,"yes") == 0)
{
display_conf_graph_pv_present = true;
display_conf_graph_present = true;
}
else
{
display_conf_graph_pv_present = false;
display_conf_graph_present = false;
}
if (strcmp(show_statistics,"yes") == 0)
{
@ -498,7 +499,7 @@ void setup() {
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_pv_present, display_conf_statistics_present);
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);
@ -507,7 +508,7 @@ void setup() {
display_text((char*)" Connected. IP:", ip_address);
//save the custom parameters to Flash
if (shouldSaveConfig) {
Serial.println("saving config");
logPrintlnI("saving config");
#if defined(ARDUINOJSON_VERSION_MAJOR) && ARDUINOJSON_VERSION_MAJOR >= 6
DynamicJsonDocument json(1024);
#else
@ -531,7 +532,7 @@ void setup() {
File configFile = Flash.open("/config.json", "w");
if (!configFile) {
Serial.println("failed to open config file for writing");
logPrintlnI("failed to open config file for writing");
}
#if defined(ARDUINOJSON_VERSION_MAJOR) && ARDUINOJSON_VERSION_MAJOR >= 6
@ -562,42 +563,42 @@ void setup() {
delay(1000); //for screen display
//Generate mqtt topics from id and address
Serial.println();
Serial.println("-------------- MQTT topic list --------------");
logPrintlnI("-------------- MQTT topic list --------------");
sprintf(mqtt_pv_voltage, "N/%s/solarcharger/%s/Pv/V", gx_vrm_id, address_pv_charger);
Serial.println(mqtt_pv_voltage);
logPrintlnI(mqtt_pv_voltage);
sprintf(mqtt_pv_power, "N/%s/solarcharger/%s/Yield/Power", gx_vrm_id, address_pv_charger);
Serial.println(mqtt_pv_power);
logPrintlnI(mqtt_pv_power);
sprintf(mqtt_pv_yield, "N/%s/solarcharger/%s/History/Daily/0/Yield", gx_vrm_id, address_pv_charger);
Serial.println(mqtt_pv_yield);
logPrintlnI(mqtt_pv_yield);
sprintf(mqtt_pv_bat_current, "N/%s/solarcharger/%s/Dc/0/Current", gx_vrm_id, address_pv_charger);
Serial.println(mqtt_pv_bat_current);
logPrintlnI(mqtt_pv_bat_current);
sprintf(mqtt_grid_power, "N/%s/grid/%s/Ac/Power", gx_vrm_id, address_grid_meter);
Serial.println(mqtt_grid_power);
logPrintlnI(mqtt_grid_power);
sprintf(mqtt_inv_power, "N/%s/vebus/%s/Ac/ActiveIn/L1/P", gx_vrm_id, address_inverter);
Serial.println(mqtt_inv_power);
logPrintlnI(mqtt_inv_power);
sprintf(mqtt_inv_current, "N/%s/vebus/%s/Dc/0/Current", gx_vrm_id, address_inverter);
Serial.println(mqtt_inv_current);
logPrintlnI(mqtt_inv_current);
sprintf(mqtt_bat_soc, "N/%s/battery/%s/Soc", gx_vrm_id, address_battery);
Serial.println(mqtt_bat_soc);
logPrintlnI(mqtt_bat_soc);
sprintf(mqtt_bat_voltage, "N/%s/battery/%s/Dc/0/Voltage", gx_vrm_id, address_battery);
Serial.println(mqtt_bat_voltage);
logPrintlnI(mqtt_bat_voltage);
sprintf(mqtt_bat_current, "N/%s/battery/%s/Dc/0/Current", gx_vrm_id, address_battery);
Serial.println(mqtt_bat_current);
logPrintlnI(mqtt_bat_current);
sprintf(mqtt_bat_power, "N/%s/battery/%s/Dc/0/Power", gx_vrm_id, address_battery);
Serial.println(mqtt_bat_power);
logPrintlnI(mqtt_bat_power);
sprintf(mqtt_bat_max_cell_volt, "N/%s/battery/%s/System/MaxCellVoltage", gx_vrm_id, address_battery);
Serial.println(mqtt_bat_max_cell_volt);
logPrintlnI(mqtt_bat_max_cell_volt);
sprintf(mqtt_bat_min_cell_volt, "N/%s/battery/%s/System/MinCellVoltage", gx_vrm_id, address_battery);
Serial.println(mqtt_bat_min_cell_volt);
logPrintlnI(mqtt_bat_min_cell_volt);
sprintf(mqtt_temp_outside, "N/%s/temperature/%s/Temperature", gx_vrm_id, address_outside_temperature);
Serial.println(mqtt_temp_outside);
logPrintlnI(mqtt_temp_outside);
sprintf(mqtt_grid_power_l1, "N/%s/system/0/Ac/ConsumptionOnInput/L1/Power", gx_vrm_id);
Serial.println(mqtt_grid_power_l1);
logPrintlnI(mqtt_grid_power_l1);
sprintf(mqtt_grid_power_l2, "N/%s/system/0/Ac/ConsumptionOnInput/L2/Power", gx_vrm_id);
Serial.println(mqtt_grid_power_l2);
logPrintlnI(mqtt_grid_power_l2);
sprintf(mqtt_grid_power_l3, "N/%s/system/0/Ac/ConsumptionOnInput/L3/Power", gx_vrm_id);
Serial.println(mqtt_grid_power_l3);
logPrintlnI(mqtt_grid_power_l3);
Serial.println();
Serial.println("-------------- Settings --------------");
Serial.print("mqtt server: "); Serial.println(mqtt_server);
@ -608,7 +609,7 @@ void setup() {
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_pv_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);
@ -616,6 +617,8 @@ void setup() {
delay(3000);
lastDispRefreshTime = millis();
lastScreenChangeTime = millis();
lastGraphRecord_1h = millis();
lastGraphRecord_24h = millis();
}
void loop() {
@ -646,16 +649,49 @@ void loop() {
}
if (display_refresh_counter >= (display_refresh_time*3) && display_refresh_counter <= (display_refresh_time*4))
{
if (display_conf_graph_pv_present)
if (display_conf_graph_present)
{
display_screen_graph(display_graph_ringbuffer);
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_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)
{
@ -663,12 +699,12 @@ void loop() {
}
else
{
display_refresh_counter = (display_refresh_time*5) + 1;
display_refresh_counter = (display_refresh_time*8) + 1;
}
}
display_refresh_counter++;
if (display_refresh_counter > (display_refresh_time*5))
if (display_refresh_counter > (display_refresh_time*8))
{
display_refresh_counter = 0;
}
@ -686,6 +722,28 @@ void loop() {
}
}
//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, grid_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, grid_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);