/* ; Project: ESP32 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 //#include -ESP32 #include #include #include #include #include //Program parts #include #include #include #define VERSION "0.1a" static const unsigned long DISPLAY_REFRESH_INTERVAL = 500; // ms static const unsigned long DISPLAY_SCREEN_INTERVAL = 10000; // ms //Wifi Setup const char* WIFI_SSID = "IoT_Temp"; const char* WIFI_PASS = "FpgtW6LMeZjmTH6J2KoSTTiE7rpEEhtfH8LaCjgFbajH2Bk88fkZFu9CopF96i"; const char* mqtt_server = "10.1.0.9"; //Library setup WiFiClient espClient; PubSubClient client(espClient); //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, batt_soc = 0, temp_outside = 0, load_ph1 = 0, load_ph2 = 0, load_ph3 = 0; int lastButtonState = HIGH; int currentButtonState; int display_screen = 0; int display_last_screen = 2; //MQTT topics void callback(char* topic, byte* message, unsigned int length) { logPrintlnD("Message arrived on topic: "); logPrintlnD(topic); logPrintlnD("Message: "); String messageTemp; for (byte i = 0; i < length; i++) { char tmp = char(message[i]); messageTemp += tmp; } logPrintlnD(messageTemp); //PV Charger - solar voltage if (String(topic) == "N/48e7da87c8df/solarcharger/279/Pv/V") { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); pv_v = json["value"]; } //PV Charger - solar power if (String(topic) == "N/48e7da87c8df/solarcharger/279/Yield/Power") { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); pv_w = json["value"]; } //PV Charger - solar yield if (String(topic) == "N/48e7da87c8df/solarcharger/279/History/Daily/0/Yield") { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); pv_kwh = json["value"]; } //PV Charger - bat charge current if (String(topic) == "N/48e7da87c8df/solarcharger/279/Dc/0/Current") { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); pv_i = json["value"]; } //Grid meter - power if (String(topic) == "N/48e7da87c8df/grid/40/Ac/Power") { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); grid_p = json["value"]; } //Inverter - power if (String(topic) == "N/48e7da87c8df/vebus/276/Ac/ActiveIn/L1/P") { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); inv_p = json["value"]; } //Inverter - current if (String(topic) == "N/48e7da87c8df/vebus/276/Dc/0/Current") { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); inv_i = json["value"]; } //Battery - SOC if (String(topic) == "N/48e7da87c8df/battery/512/Soc") { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); batt_soc = json["value"]; } //Battery - voltage if (String(topic) == "N/48e7da87c8df/battery/512/Dc/0/Voltage") { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); batt_v = json["value"]; } //Battery - current if (String(topic) == "N/48e7da87c8df/battery/512/Dc/0/Current") { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); batt_i = json["value"]; } //Battery - power if (String(topic) == "N/48e7da87c8df/battery/512/Dc/0/Power") { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); batt_p = json["value"]; } //Battery - max cell volts if (String(topic) == "N/48e7da87c8df/battery/512/System/MaxCellVoltage") { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); batt_c_max = json["value"]; } //Battery - min cell volts if (String(topic) == "N/48e7da87c8df/battery/512/System/MinCellVoltage") { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); batt_c_min = json["value"]; } //Temperature - outside if (String(topic) == "N/48e7da87c8df/temperature/18/Temperature") { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); temp_outside = json["value"]; } //System - AC Load Phase 1 if (String(topic) == "N/48e7da87c8df/system/0/Ac/ConsumptionOnInput/L1/Power") { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); load_ph1 = json["value"]; } //System - AC Load Phase 2 if (String(topic) == "N/48e7da87c8df/system/0/Ac/ConsumptionOnInput/L2/Power") { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); load_ph2 = json["value"]; } //System - AC Load Phase 3 if (String(topic) == "N/48e7da87c8df/system/0/Ac/ConsumptionOnInput/L3/Power") { DynamicJsonDocument json(512); deserializeJson(json, messageTemp); load_ph3 = json["value"]; } } //Wifi re-/connect void reconnect() { // Loop until we're reconnected while (!client.connected()) { logPrintlnI("Attempting MQTT connection..."); display_mqtt(); delay(1500); // Attempt to connect if (client.connect("PV_solar_monitor")) { logPrintlnI("connected"); // Subscribe client.subscribe("N/48e7da87c8df/solarcharger/279/Pv/V"); client.subscribe("N/48e7da87c8df/solarcharger/279/Yield/Power"); client.subscribe("N/48e7da87c8df/solarcharger/279/History/Daily/0/Yield"); client.subscribe("N/48e7da87c8df/solarcharger/279/Dc/0/Current"); client.subscribe("N/48e7da87c8df/grid/40/Ac/Power"); client.subscribe("N/48e7da87c8df/vebus/276/Ac/ActiveIn/L1/P"); client.subscribe("N/48e7da87c8df/vebus/276/Dc/0/Current"); client.subscribe("N/48e7da87c8df/battery/512/Soc"); client.subscribe("N/48e7da87c8df/battery/512/Dc/0/Voltage"); client.subscribe("N/48e7da87c8df/battery/512/Dc/0/Current"); client.subscribe("N/48e7da87c8df/battery/512/Dc/0/Power"); client.subscribe("N/48e7da87c8df/battery/512/System/MaxCellVoltage"); client.subscribe("N/48e7da87c8df/battery/512/System/MinCellVoltage"); client.subscribe("N/48e7da87c8df/temperature/18/Temperature"); client.subscribe("N/48e7da87c8df/system/0/Ac/ConsumptionOnInput/L1/Power"); client.subscribe("N/48e7da87c8df/system/0/Ac/ConsumptionOnInput/L2/Power"); client.subscribe("N/48e7da87c8df/system/0/Ac/ConsumptionOnInput/L3/Power"); } else { logPrintlnE("failed, rc="); logPrintlnE((char*)client.state()); logPrintlnE(" try again in 5 seconds"); // Wait 5 seconds before retrying delay(5000); } } } void setup() { Serial.begin(115200); display_begin(); display_init((char*)VERSION); delay(2000); logPrintlnI("Booting solar monitor app..." VERSION); pinMode(BUTTON_PIN, INPUT_PULLUP); logPrintlnI( "Set WLAN Mode to STA..."); WiFi.mode(WIFI_STA); logPrintlnI("Resetting..."); WiFi.disconnect(); logPrintlnI("Connecting ..."); delay(1000); WiFi.begin(WIFI_SSID, WIFI_PASS); while (WiFi.status() != WL_CONNECTED) { Serial.println("Retry connection to WiFi.."); display_wifi((char*)"wait"); delay(500); client.setServer(mqtt_server, 1883); client.setCallback(callback); } IPAddress ip = WiFi.localIP(); char* ip_address = new char[40](); sprintf(ip_address, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); display_wifi(ip_address); delay(2000); } void loop() { if (!client.connected()) { reconnect(); } client.loop(); static unsigned long lastDispRefreshTime = 0; static unsigned long lastScreenChangeTime = 0; //Refresh display values if(millis() - lastDispRefreshTime >= DISPLAY_REFRESH_INTERVAL) { lastDispRefreshTime += DISPLAY_REFRESH_INTERVAL; if (display_screen == 0) { display_screen_0(pv_v, pv_w, batt_v, pv_i, pv_kwh); } if (display_screen == 1) { display_screen_1(batt_v, batt_i, batt_p, batt_soc, batt_c_min, batt_c_max); } if (display_screen == 2) { display_screen_2(grid_p, inv_p, inv_i, load_ph1, load_ph2, load_ph3, pv_w); } } //Change screen after time if(millis() - lastScreenChangeTime >= DISPLAY_SCREEN_INTERVAL) { display_screen++; lastScreenChangeTime += DISPLAY_SCREEN_INTERVAL; if (display_screen == display_last_screen + 1) { display_screen = 0; } } currentButtonState = digitalRead(BUTTON_PIN); if(lastButtonState == LOW && currentButtonState == HIGH) { display_screen++; if (display_screen == display_last_screen + 1) { display_screen = 0; } lastButtonState = currentButtonState; } }