Button switches Modes now (Power, 1.8.0, 1.8.1, 1.8.2, 2.8.0)
This commit is contained in:
249
src/main.cpp
249
src/main.cpp
@@ -3,28 +3,37 @@
|
|||||||
#include <LiquidCrystal_I2C.h>
|
#include <LiquidCrystal_I2C.h>
|
||||||
#include <settings.h>
|
#include <settings.h>
|
||||||
|
|
||||||
|
|
||||||
#define BUTTON_PIN D3 // GPIO-Pin verbunden mit Taster (D3 entspricht GPIO0)
|
#define BUTTON_PIN D3 // GPIO-Pin verbunden mit Taster (D3 entspricht GPIO0)
|
||||||
|
|
||||||
const uint32_t connectTimeoutMs = 10000; // WLAN Timeout
|
const uint32_t connectTimeoutMs = 10000; // WLAN Timeout
|
||||||
|
|
||||||
// Globale Variablen
|
// Globale Variablen
|
||||||
unsigned long lastUpdateTime = 0; // Zeitstempel der letzten Aktion
|
unsigned long lastUpdateTime = 0; // Zeitstempel der letzten Aktion
|
||||||
unsigned long refreshRate = 5000; // Anfangsverzögerung in Millisekunden
|
unsigned long refreshRate = 2500; // Aktualisierungsrate in Millisekunden
|
||||||
unsigned long messageDisplayTime = 0; // Zeitstempel für die 5-Sekunden-Anzeige
|
bool isModeChanged = false; // Zustand, ob eine Nachricht angezeigt wird
|
||||||
bool isMessageDisplayed = false; // Zustand, ob die Aktualisierungsrate angezeigt wird
|
|
||||||
|
|
||||||
int currentDelayIndex = 0; // Aktueller Index im Delay-Array
|
|
||||||
const unsigned long delayOptions[] = {5000, 10000, 15000, 20000, 30000, 45000, 60000, 1000, 2000};
|
|
||||||
const int delayOptionsSize = sizeof(delayOptions) / sizeof(delayOptions[0]);
|
|
||||||
|
|
||||||
int lastButtonState = HIGH; // Letzter Zustand des Buttons
|
int lastButtonState = HIGH; // Letzter Zustand des Buttons
|
||||||
int currentButtonState;
|
int currentButtonState;
|
||||||
|
|
||||||
|
// Array für die Werte
|
||||||
|
String ip_netzbezug_values[5];
|
||||||
|
String ip_erzeugung_values[5];
|
||||||
|
|
||||||
|
String ip_netzbezug_values_old[5];
|
||||||
|
String ip_erzeugung_values_old[5];
|
||||||
|
|
||||||
|
// Modus-Definitionen
|
||||||
|
int currentMode = 0;
|
||||||
|
const char* modeNames[] = {"Leistung", "1.8.0", "1.8.1", "1.8.2", "2.8.0"};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
String netzbezug;
|
String netzbezug;
|
||||||
String netzbezug_alt;
|
String netzbezug_alt;
|
||||||
String erzeugung;
|
String erzeugung;
|
||||||
String erzeugung_alt;
|
String erzeugung_alt;
|
||||||
|
String e_in_180;
|
||||||
|
String e_in_180_old;
|
||||||
|
|
||||||
// LCD initialisieren (16x2 Display)
|
// LCD initialisieren (16x2 Display)
|
||||||
LiquidCrystal_I2C lcd(0x27, 16, 2);
|
LiquidCrystal_I2C lcd(0x27, 16, 2);
|
||||||
@@ -45,114 +54,93 @@ byte customChar_wlan[] = {
|
|||||||
B00000
|
B00000
|
||||||
};
|
};
|
||||||
|
|
||||||
// Funktion zum Anzeigen von Text auf einem 1602 LCD Display
|
|
||||||
//
|
|
||||||
// _lcd_display_text(TEXT, ROW, RETURNTOSTART, ALIGNMENT)
|
|
||||||
//
|
|
||||||
// row = 0 Zeile 0 wir beschrieben [default]
|
|
||||||
// = 1 Zeile 1 wir beschrieben [default]
|
|
||||||
// text = Der anzuzeigende Text (default löscht die komplette Zeile)
|
|
||||||
// alignment = left Text Ausrichtung links (Bei <= 16 Zeichen) [default]
|
|
||||||
// = center Text Ausrichtung zentriert (Bei <= 16 Zeichen)
|
|
||||||
// = right Text Ausrichtung links (Bei <= 16 Zeichen)
|
|
||||||
// returnToStart = false Zu langer Text der durchgescrollt wird stoppt am Ende [default]
|
|
||||||
// true Zu langer Text der durchgescrollt wird springt zum 1. Buchstaben zurück
|
|
||||||
void _lcd_display_text(int row = 0, const char* text = " ", const char* alignment = "left", bool returnToStart = false) {
|
void _lcd_display_text(int row = 0, const char* text = " ", const char* alignment = "left", bool returnToStart = false) {
|
||||||
|
|
||||||
// Textlänge ermitteln
|
|
||||||
int textLength = strlen(text);
|
int textLength = strlen(text);
|
||||||
|
|
||||||
// Sicherstellen, dass die Zeile gültig ist (0 oder 1)
|
|
||||||
if (row < 0 || row > 1) {
|
if (row < 0 || row > 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
lcd.setCursor(0, row);
|
lcd.setCursor(0, row);
|
||||||
|
|
||||||
// Wenn der Text <= 16 Zeichen ist, ausrichten
|
|
||||||
if (textLength <= 16) {
|
if (textLength <= 16) {
|
||||||
int padding = 0;
|
int padding = 0;
|
||||||
|
|
||||||
if (strcmp(alignment, "center") == 0) {
|
if (strcmp(alignment, "center") == 0) {
|
||||||
padding = (16 - textLength) / 2; // Zentriert
|
padding = (16 - textLength) / 2;
|
||||||
} else if (strcmp(alignment, "right") == 0) {
|
} else if (strcmp(alignment, "right") == 0) {
|
||||||
padding = 16 - textLength; // Rechtsbündig
|
padding = 16 - textLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
//lcd.clear();
|
|
||||||
lcd.setCursor(0, row);
|
lcd.setCursor(0, row);
|
||||||
|
|
||||||
// Leerzeichen vor dem Text für Ausrichtung
|
|
||||||
for (int i = 0; i < padding; i++) {
|
for (int i = 0; i < padding; i++) {
|
||||||
lcd.print(" ");
|
lcd.print(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Text ausgeben
|
|
||||||
lcd.print(text);
|
lcd.print(text);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Wenn der Text > 16 Zeichen ist, zuerst die ersten 16 Zeichen anzeigen
|
|
||||||
lcd.setCursor(0, row);
|
lcd.setCursor(0, row);
|
||||||
lcd.print(text);
|
lcd.print(text);
|
||||||
delay(2000); // Kurze Pause, damit der Anfang lesbar ist
|
delay(2000);
|
||||||
|
|
||||||
// Danach scrollen
|
|
||||||
for (int i = 1; i <= textLength - 16; i++) {
|
for (int i = 1; i <= textLength - 16; i++) {
|
||||||
lcd.setCursor(0, row);
|
lcd.setCursor(0, row);
|
||||||
lcd.print(text + i); // Ab Offset i den Text anzeigen
|
lcd.print(text + i);
|
||||||
delay(300); // Verzögerung für Scroll-Geschwindigkeit
|
delay(300);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verhalten nach dem Scrollen festlegen
|
|
||||||
if (returnToStart) {
|
if (returnToStart) {
|
||||||
lcd.setCursor(0, row);
|
lcd.setCursor(0, row);
|
||||||
lcd.print(text); // Anfang des Textes wieder anzeigen
|
lcd.print(text);
|
||||||
} else {
|
} else {
|
||||||
lcd.setCursor(0, row);
|
lcd.setCursor(0, row);
|
||||||
lcd.print(text + (textLength - 16)); // Text hinten stehen lassen
|
lcd.print(text + (textLength - 16));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Funktion zum Extrahieren eines Wertes aus der GET-Anfrage von Tasmota-Geräten
|
void extractTasmotaValues(const String& url, String values[5]) {
|
||||||
String _extract_value_tasmota_json(const String& url, const String& key) {
|
WiFiClient client;
|
||||||
WiFiClient client; // WiFiClient-Objekt erstellen
|
|
||||||
HTTPClient http;
|
HTTPClient http;
|
||||||
|
|
||||||
if (http.begin(client, url)) { // Begin mit WiFiClient und URL
|
if (http.begin(client, url)) {
|
||||||
int httpResponseCode = http.GET();
|
int httpResponseCode = http.GET();
|
||||||
|
|
||||||
if (httpResponseCode == 200) {
|
if (httpResponseCode == 200) {
|
||||||
String response = http.getString();
|
String response = http.getString();
|
||||||
http.end();
|
http.end();
|
||||||
|
|
||||||
int startIndex = response.indexOf("\"" + key + "\":");
|
// Array mit den Schlüsseln der gewünschten Werte
|
||||||
if (startIndex == -1) {
|
const String keys[5] = {"Power", "E_in_180", "E_in_181", "E_in_182", "E_out_280"};
|
||||||
return "?"; // Key nicht gefunden
|
|
||||||
|
// Werte initialisieren
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
values[i] = ""; // Standardwert, falls Key nicht gefunden wird
|
||||||
|
int keyIndex = response.indexOf("\"" + keys[i] + "\":");
|
||||||
|
if (keyIndex != -1) {
|
||||||
|
int valueStart = keyIndex + keys[i].length() + 3; // Position nach dem ":"
|
||||||
|
int valueEnd = response.indexOf(",", valueStart); // Ende der Zahl oder des Wertes
|
||||||
|
if (valueEnd == -1) {
|
||||||
|
valueEnd = response.indexOf("}", valueStart); // Falls am Ende der JSON-Objekte
|
||||||
|
}
|
||||||
|
if (valueEnd != -1) {
|
||||||
|
values[i] = response.substring(valueStart, valueEnd);
|
||||||
|
values[i].trim(); // Entfernt überflüssige Leerzeichen
|
||||||
}
|
}
|
||||||
startIndex += key.length() + 3;
|
|
||||||
int endIndex = response.indexOf(",", startIndex);
|
|
||||||
if (endIndex == -1) {
|
|
||||||
endIndex = response.indexOf("}", startIndex);
|
|
||||||
}
|
}
|
||||||
if (endIndex == -1) {
|
|
||||||
return "?";
|
|
||||||
}
|
}
|
||||||
String value = response.substring(startIndex, endIndex);
|
|
||||||
value.trim();
|
|
||||||
return String((int)value.toFloat()); // Nachkommastellen abschneiden
|
|
||||||
} else {
|
} else {
|
||||||
//Serial.println("Fehler bei der Anfrage: " + String(httpResponseCode));
|
Serial.println("HTTP Fehler: " + String(httpResponseCode));
|
||||||
}
|
}
|
||||||
http.end();
|
http.end();
|
||||||
} else {
|
} else {
|
||||||
Serial.println("Verbindung zur URL fehlgeschlagen: " + url);
|
Serial.println("Verbindung zur URL fehlgeschlagen: " + url);
|
||||||
}
|
}
|
||||||
|
|
||||||
return "?";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WLAN-Verbindung herstellen
|
|
||||||
|
|
||||||
void connectToWiFi() {
|
void connectToWiFi() {
|
||||||
Serial.println("WLAN Verbindungsaufbau zu: " + String(ssidList[current_ap]));
|
Serial.println("WLAN Verbindungsaufbau zu: " + String(ssidList[current_ap]));
|
||||||
Serial.println("Passwort: " + String(passwordList[current_ap]));
|
Serial.println("Passwort: " + String(passwordList[current_ap]));
|
||||||
@@ -166,7 +154,6 @@ void connectToWiFi() {
|
|||||||
|
|
||||||
WiFi.begin(ssidList[current_ap], passwordList[current_ap]);
|
WiFi.begin(ssidList[current_ap], passwordList[current_ap]);
|
||||||
|
|
||||||
//Blinkendes WLAN Symbol wärend das WLAN versucht zu verbinden
|
|
||||||
int attempt = 0;
|
int attempt = 0;
|
||||||
while (WiFi.status() != WL_CONNECTED && attempt < 10) {
|
while (WiFi.status() != WL_CONNECTED && attempt < 10) {
|
||||||
delay(500);
|
delay(500);
|
||||||
@@ -179,19 +166,14 @@ void connectToWiFi() {
|
|||||||
attempt++;
|
attempt++;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Verbindung fehlgeschlagen (current_ap erhöhen)
|
|
||||||
if (WiFi.status() != WL_CONNECTED) {
|
if (WiFi.status() != WL_CONNECTED) {
|
||||||
WiFi.disconnect();
|
WiFi.disconnect();
|
||||||
delay(500);
|
delay(500);
|
||||||
Serial.println("\nVerbindung fehlgeschlagen.");
|
Serial.println("\nVerbindung fehlgeschlagen.");
|
||||||
current_ap = (current_ap + 1) % numNetworks;
|
current_ap = (current_ap + 1) % numNetworks;
|
||||||
reconnecting = false;
|
reconnecting = false;
|
||||||
//Verbunden
|
|
||||||
} else {
|
} else {
|
||||||
Serial.print("\nWLAN verbunden: ");
|
Serial.println("\nWLAN verbunden: " + WiFi.SSID());
|
||||||
Serial.print(WiFi.SSID());
|
|
||||||
Serial.print(" ");
|
|
||||||
Serial.println(WiFi.RSSI());
|
|
||||||
|
|
||||||
_lcd_display_text(0, "WLAN verbunden", "center");
|
_lcd_display_text(0, "WLAN verbunden", "center");
|
||||||
_lcd_display_text(1);
|
_lcd_display_text(1);
|
||||||
@@ -207,51 +189,65 @@ void connectToWiFi() {
|
|||||||
|
|
||||||
void update_power_values() {
|
void update_power_values() {
|
||||||
|
|
||||||
Serial.print("SmartMeterReader auslesen: ");
|
|
||||||
netzbezug = _extract_value_tasmota_json("http://" + ip_netzbezug + "/cm?cmnd=Status%208", "Power");
|
|
||||||
Serial.print(netzbezug + "W\n");
|
|
||||||
|
|
||||||
|
|
||||||
Serial.print("Zwischenstecker auslesen : ");
|
|
||||||
erzeugung = _extract_value_tasmota_json("http://" + ip_erzeugung + "/cm?cmnd=Status%208", "Power");
|
|
||||||
Serial.print(erzeugung + "W\n");
|
|
||||||
|
|
||||||
if (netzbezug != netzbezug_alt) {
|
|
||||||
lcd.setCursor(10, 0);
|
lcd.setCursor(10, 0);
|
||||||
lcd.print(" ");
|
lcd.print(" ");
|
||||||
lcd.setCursor(16 - (netzbezug.length() + 1), 0);
|
lcd.setCursor(16 - (ip_netzbezug_values[0].length() + 1), 0);
|
||||||
lcd.print(netzbezug);
|
lcd.print(ip_netzbezug_values[0]);
|
||||||
}
|
lcd.print("W");
|
||||||
|
|
||||||
|
|
||||||
if (erzeugung != erzeugung_alt) {
|
|
||||||
lcd.setCursor(10, 1);
|
lcd.setCursor(10, 1);
|
||||||
lcd.print(" ");
|
lcd.print(" ");
|
||||||
lcd.setCursor(16 - (erzeugung.length() + 1), 1);
|
lcd.setCursor(16 - (ip_erzeugung_values[0].length() + 1), 1);
|
||||||
lcd.print(erzeugung);
|
lcd.print(ip_erzeugung_values[0]);
|
||||||
}
|
lcd.print("W");
|
||||||
|
|
||||||
netzbezug_alt = netzbezug;
|
ip_netzbezug_values_old[0] = ip_netzbezug_values[0];
|
||||||
erzeugung_alt = erzeugung;
|
ip_erzeugung_values_old[0] = ip_erzeugung_values[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_180_values() {
|
||||||
|
_lcd_display_text(1, (ip_netzbezug_values[1] + "kWh").c_str(), "center");
|
||||||
|
ip_netzbezug_values_old[1] = ip_netzbezug_values[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_181_values() {
|
||||||
|
_lcd_display_text(1, (ip_netzbezug_values[2] + "kWh").c_str(), "center");
|
||||||
|
ip_netzbezug_values_old[2] = ip_netzbezug_values[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_182_values() {
|
||||||
|
_lcd_display_text(1, (ip_netzbezug_values[3] + "kWh").c_str(), "center");
|
||||||
|
ip_netzbezug_values_old[3] = ip_netzbezug_values[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_280_values() {
|
||||||
|
_lcd_display_text(1, (ip_netzbezug_values[4] + "kWh").c_str(), "center");
|
||||||
|
ip_netzbezug_values_old[4] = ip_netzbezug_values[4];
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleButtonPress() {
|
void handleButtonPress() {
|
||||||
|
|
||||||
currentButtonState = digitalRead(BUTTON_PIN);
|
currentButtonState = digitalRead(BUTTON_PIN);
|
||||||
|
|
||||||
if (currentButtonState == LOW && lastButtonState == HIGH) {
|
if (currentButtonState == LOW && lastButtonState == HIGH) {
|
||||||
currentDelayIndex = (currentDelayIndex + 1) % delayOptionsSize;
|
|
||||||
refreshRate = delayOptions[currentDelayIndex];
|
|
||||||
|
|
||||||
Serial.print("Neue Aktualisierungsrate: ");
|
lcd.clear();
|
||||||
|
|
||||||
|
currentMode = (currentMode + 1) % 5;
|
||||||
|
|
||||||
|
Serial.print("Neuer Modus: ");
|
||||||
|
Serial.println(modeNames[currentMode]);
|
||||||
|
|
||||||
|
if (currentMode == 0) {
|
||||||
|
refreshRate = 2500;
|
||||||
|
} else {
|
||||||
|
refreshRate = 15000;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.print("Aktualisierungsrate: ");
|
||||||
Serial.println(refreshRate);
|
Serial.println(refreshRate);
|
||||||
|
|
||||||
_lcd_display_text(0, " Aktual. Rate ");
|
isModeChanged = true;
|
||||||
_lcd_display_text(1);
|
|
||||||
_lcd_display_text(1, (String(refreshRate / 1000) + " Sekunden").c_str(), "center");
|
|
||||||
|
|
||||||
isMessageDisplayed = true;
|
|
||||||
messageDisplayTime = millis();
|
|
||||||
|
|
||||||
delay(200);
|
delay(200);
|
||||||
}
|
}
|
||||||
@@ -274,30 +270,77 @@ void setup() {
|
|||||||
|
|
||||||
lcd.setCursor(0, 0);
|
lcd.setCursor(0, 0);
|
||||||
_lcd_display_text(0, "Bereit", "center");
|
_lcd_display_text(0, "Bereit", "center");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
|
|
||||||
handleButtonPress();
|
handleButtonPress();
|
||||||
|
|
||||||
|
//Serial.print(".");
|
||||||
|
|
||||||
if (WiFi.status() != WL_CONNECTED && !reconnecting) {
|
if (WiFi.status() != WL_CONNECTED && !reconnecting) {
|
||||||
reconnecting = true;
|
reconnecting = true;
|
||||||
connectToWiFi();
|
connectToWiFi();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isMessageDisplayed && millis() - messageDisplayTime >= 2500) {
|
|
||||||
isMessageDisplayed = false;
|
|
||||||
_lcd_display_text(0, "Netzbezug: ?W");
|
|
||||||
_lcd_display_text(1, "Erzeugung: ?W");
|
|
||||||
update_power_values();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (WiFi.status() == WL_CONNECTED && !reconnecting) {
|
if (WiFi.status() == WL_CONNECTED && !reconnecting) {
|
||||||
|
if (millis() - lastUpdateTime >= refreshRate) {
|
||||||
if (!isMessageDisplayed && millis() - lastUpdateTime >= refreshRate) {
|
|
||||||
lastUpdateTime = millis();
|
lastUpdateTime = millis();
|
||||||
|
|
||||||
update_power_values();
|
|
||||||
|
extractTasmotaValues("http://" + ip_netzbezug + "/cm?cmnd=Status%208", ip_netzbezug_values);
|
||||||
|
|
||||||
|
switch (currentMode) {
|
||||||
|
case 0:
|
||||||
|
extractTasmotaValues("http://" + ip_erzeugung + "/cm?cmnd=Status%208", ip_erzeugung_values);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
switch (currentMode) {
|
||||||
|
case 0:
|
||||||
|
if (ip_netzbezug_values[0] != ip_netzbezug_values_old[0] || isModeChanged == true) {
|
||||||
|
isModeChanged = false;
|
||||||
|
_lcd_display_text(0, "Netzbezug:", "left");
|
||||||
|
_lcd_display_text(1, "Erzeugung:", "left");
|
||||||
|
update_power_values();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (ip_netzbezug_values[1] != ip_netzbezug_values_old[1] || isModeChanged == true) {
|
||||||
|
isModeChanged = false;
|
||||||
|
_lcd_display_text(0, "1.8.0:", "center");
|
||||||
|
update_180_values();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (ip_netzbezug_values[2] != ip_netzbezug_values_old[2] || isModeChanged == true) {
|
||||||
|
isModeChanged = false;
|
||||||
|
_lcd_display_text(0, "1.8.1:", "center");
|
||||||
|
update_181_values();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (ip_netzbezug_values[3] != ip_netzbezug_values_old[3] || isModeChanged == true) {
|
||||||
|
isModeChanged = false;
|
||||||
|
_lcd_display_text(0, "1.8.2:", "center");
|
||||||
|
update_182_values();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
if (ip_netzbezug_values[4] != ip_netzbezug_values_old[4] || isModeChanged == true) {
|
||||||
|
isModeChanged = false;
|
||||||
|
_lcd_display_text(0, "2.8.0:", "center");
|
||||||
|
update_280_values();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user