2022-09-03 03:04:57 +00:00
|
|
|
/*
|
|
|
|
; 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.
|
|
|
|
*/
|
2022-08-21 21:32:23 +00:00
|
|
|
#include <Arduino.h>
|
2022-09-03 03:04:57 +00:00
|
|
|
#include <logger.h>
|
2022-08-21 23:54:57 +00:00
|
|
|
#include <WiFi.h>
|
2022-09-03 03:04:57 +00:00
|
|
|
#include <PubSubClient.h>
|
|
|
|
#include <ArduinoJson.h>
|
2022-08-21 23:54:57 +00:00
|
|
|
#include <Wire.h>
|
2022-09-03 03:04:57 +00:00
|
|
|
#include <U8g2lib.h>
|
|
|
|
|
|
|
|
//Program parts
|
2022-08-21 23:54:57 +00:00
|
|
|
#include <pins.h>
|
2022-09-03 03:04:57 +00:00
|
|
|
#include <screens.h>
|
|
|
|
#include <display.h>
|
|
|
|
|
|
|
|
#define VERSION "0.1a"
|
2022-09-03 19:01:56 +00:00
|
|
|
static const unsigned long DISPLAY_REFRESH_INTERVAL = 500; // ms
|
2022-09-03 03:04:57 +00:00
|
|
|
static const unsigned long DISPLAY_SCREEN_INTERVAL = 10000; // ms
|
2022-08-21 23:54:57 +00:00
|
|
|
|
2022-09-03 03:04:57 +00:00
|
|
|
//Wifi Setup
|
2022-08-21 23:54:57 +00:00
|
|
|
const char* WIFI_SSID = "IoT_Temp";
|
2022-09-03 03:04:57 +00:00
|
|
|
const char* WIFI_PASS = "FpgtW6LMeZjmTH6J2KoSTTiE7rpEEhtfH8LaCjgFbajH2Bk88fkZFu9CopF96i";
|
2022-08-21 23:54:57 +00:00
|
|
|
const char* mqtt_server = "10.1.0.9";
|
|
|
|
|
2022-09-03 03:04:57 +00:00
|
|
|
//Library setup
|
2022-08-21 23:54:57 +00:00
|
|
|
WiFiClient espClient;
|
|
|
|
PubSubClient client(espClient);
|
2022-09-03 03:04:57 +00:00
|
|
|
|
|
|
|
//Globals
|
2022-08-21 23:54:57 +00:00
|
|
|
long lastMsg = 0;
|
|
|
|
char msg[50];
|
2022-09-03 19:01:56 +00:00
|
|
|
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;
|
2022-09-03 03:04:57 +00:00
|
|
|
int lastButtonState = HIGH;
|
|
|
|
int currentButtonState;
|
|
|
|
int display_screen = 0;
|
|
|
|
int display_last_screen = 2;
|
2022-08-21 23:54:57 +00:00
|
|
|
|
2022-09-03 03:04:57 +00:00
|
|
|
//MQTT topics
|
2022-08-21 23:54:57 +00:00
|
|
|
void callback(char* topic, byte* message, unsigned int length) {
|
|
|
|
logPrintlnD("Message arrived on topic: ");
|
|
|
|
logPrintlnD(topic);
|
|
|
|
logPrintlnD("Message: ");
|
2022-09-03 03:04:57 +00:00
|
|
|
String messageTemp;
|
2022-08-21 23:54:57 +00:00
|
|
|
|
2022-09-03 03:04:57 +00:00
|
|
|
for (byte i = 0; i < length; i++) {
|
|
|
|
char tmp = char(message[i]);
|
|
|
|
messageTemp += tmp;
|
2022-08-21 23:54:57 +00:00
|
|
|
}
|
2022-09-03 03:04:57 +00:00
|
|
|
logPrintlnD(messageTemp);
|
|
|
|
|
|
|
|
//PV Charger - solar voltage
|
2022-08-21 23:54:57 +00:00
|
|
|
if (String(topic) == "N/48e7da87c8df/solarcharger/279/Pv/V") {
|
2022-09-03 03:04:57 +00:00
|
|
|
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"];
|
|
|
|
}
|
2022-09-03 19:01:56 +00:00
|
|
|
//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"];
|
|
|
|
}
|
2022-09-03 03:04:57 +00:00
|
|
|
|
|
|
|
//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"];
|
2022-08-21 23:54:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-03 03:04:57 +00:00
|
|
|
//Wifi re-/connect
|
2022-08-21 23:54:57 +00:00
|
|
|
void reconnect() {
|
|
|
|
// Loop until we're reconnected
|
|
|
|
while (!client.connected()) {
|
|
|
|
logPrintlnI("Attempting MQTT connection...");
|
2022-09-03 03:04:57 +00:00
|
|
|
display_mqtt();
|
|
|
|
delay(1500);
|
2022-08-21 23:54:57 +00:00
|
|
|
// Attempt to connect
|
2022-09-03 03:04:57 +00:00
|
|
|
if (client.connect("PV_solar_monitor")) {
|
|
|
|
logPrintlnI("connected");
|
2022-08-21 23:54:57 +00:00
|
|
|
// Subscribe
|
|
|
|
client.subscribe("N/48e7da87c8df/solarcharger/279/Pv/V");
|
|
|
|
client.subscribe("N/48e7da87c8df/solarcharger/279/Yield/Power");
|
2022-09-03 03:04:57 +00:00
|
|
|
client.subscribe("N/48e7da87c8df/solarcharger/279/History/Daily/0/Yield");
|
2022-08-21 23:54:57 +00:00
|
|
|
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");
|
2022-09-03 03:04:57 +00:00
|
|
|
client.subscribe("N/48e7da87c8df/vebus/276/Dc/0/Current");
|
2022-08-21 23:54:57 +00:00
|
|
|
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");
|
2022-09-03 03:04:57 +00:00
|
|
|
client.subscribe("N/48e7da87c8df/battery/512/Dc/0/Power");
|
2022-09-03 19:01:56 +00:00
|
|
|
client.subscribe("N/48e7da87c8df/battery/512/System/MaxCellVoltage");
|
|
|
|
client.subscribe("N/48e7da87c8df/battery/512/System/MinCellVoltage");
|
2022-09-03 03:04:57 +00:00
|
|
|
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");
|
2022-08-21 23:54:57 +00:00
|
|
|
} else {
|
|
|
|
logPrintlnE("failed, rc=");
|
|
|
|
logPrintlnE((char*)client.state());
|
|
|
|
logPrintlnE(" try again in 5 seconds");
|
|
|
|
// Wait 5 seconds before retrying
|
|
|
|
delay(5000);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-08-21 21:32:23 +00:00
|
|
|
|
|
|
|
void setup() {
|
2022-08-21 23:54:57 +00:00
|
|
|
Serial.begin(115200);
|
2022-09-03 03:04:57 +00:00
|
|
|
display_begin();
|
|
|
|
display_init((char*)VERSION);
|
|
|
|
delay(2000);
|
|
|
|
logPrintlnI("Booting solar monitor app..." VERSION);
|
|
|
|
pinMode(BUTTON_PIN, INPUT_PULLUP);
|
2022-08-21 23:54:57 +00:00
|
|
|
logPrintlnI( "Set WLAN Mode to STA...");
|
|
|
|
WiFi.mode(WIFI_STA);
|
|
|
|
logPrintlnI("Resetting...");
|
|
|
|
WiFi.disconnect();
|
|
|
|
logPrintlnI("Connecting ...");
|
2022-09-03 03:04:57 +00:00
|
|
|
delay(1000);
|
2022-08-21 23:54:57 +00:00
|
|
|
WiFi.begin(WIFI_SSID, WIFI_PASS);
|
|
|
|
while (WiFi.status() != WL_CONNECTED) {
|
|
|
|
Serial.println("Retry connection to WiFi..");
|
2022-09-03 03:04:57 +00:00
|
|
|
display_wifi((char*)"wait");
|
|
|
|
delay(500);
|
|
|
|
client.setServer(mqtt_server, 1883);
|
|
|
|
client.setCallback(callback);
|
2022-08-21 23:54:57 +00:00
|
|
|
}
|
|
|
|
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]);
|
2022-09-03 03:04:57 +00:00
|
|
|
display_wifi(ip_address);
|
|
|
|
delay(2000);
|
2022-08-21 21:32:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void loop() {
|
2022-08-21 23:54:57 +00:00
|
|
|
if (!client.connected()) {
|
|
|
|
reconnect();
|
|
|
|
}
|
|
|
|
client.loop();
|
2022-09-03 03:04:57 +00:00
|
|
|
|
|
|
|
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) {
|
2022-09-03 19:01:56 +00:00
|
|
|
display_screen_1(batt_v, batt_i, batt_p, batt_soc, batt_c_min, batt_c_max);
|
2022-09-03 03:04:57 +00:00
|
|
|
}
|
|
|
|
if (display_screen == 2) {
|
2022-09-03 19:01:56 +00:00
|
|
|
display_screen_2(grid_p, inv_p, inv_i, load_ph1, load_ph2, load_ph3, pv_w);
|
2022-09-03 03:04:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//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;
|
|
|
|
}
|
2022-08-21 21:32:23 +00:00
|
|
|
}
|