Initial commit

This commit is contained in:
2024-12-21 20:33:38 +01:00
commit 8277a07417
12 changed files with 515 additions and 0 deletions

303
src/main.cpp Normal file
View File

@@ -0,0 +1,303 @@
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <LiquidCrystal_I2C.h>
#include <settings.h>
#define BUTTON_PIN D3 // GPIO-Pin verbunden mit Taster (D3 entspricht GPIO0)
const uint32_t connectTimeoutMs = 10000; // WLAN Timeout
// Globale Variablen
unsigned long lastUpdateTime = 0; // Zeitstempel der letzten Aktion
unsigned long refreshRate = 5000; // Anfangsverzögerung in Millisekunden
unsigned long messageDisplayTime = 0; // Zeitstempel für die 5-Sekunden-Anzeige
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 currentButtonState;
String netzbezug;
String netzbezug_alt;
String erzeugung;
String erzeugung_alt;
// LCD initialisieren (16x2 Display)
LiquidCrystal_I2C lcd(0x27, 16, 2);
int numNetworks = sizeof(ssidList) / sizeof(ssidList[0]);
int current_ap = 0; // Start mit der ersten SSID
bool reconnecting = false; // Flag für den Reconnect-Status
// WLAN Symbol
byte customChar_wlan[] = {
B00000,
B01110,
B10001,
B00100,
B01010,
B00000,
B00100,
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) {
// Textlänge ermitteln
int textLength = strlen(text);
// Sicherstellen, dass die Zeile gültig ist (0 oder 1)
if (row < 0 || row > 1) {
return;
}
lcd.setCursor(0, row);
// Wenn der Text <= 16 Zeichen ist, ausrichten
if (textLength <= 16) {
int padding = 0;
if (strcmp(alignment, "center") == 0) {
padding = (16 - textLength) / 2; // Zentriert
} else if (strcmp(alignment, "right") == 0) {
padding = 16 - textLength; // Rechtsbündig
}
//lcd.clear();
lcd.setCursor(0, row);
// Leerzeichen vor dem Text für Ausrichtung
for (int i = 0; i < padding; i++) {
lcd.print(" ");
}
// Text ausgeben
lcd.print(text);
} else {
// Wenn der Text > 16 Zeichen ist, zuerst die ersten 16 Zeichen anzeigen
lcd.setCursor(0, row);
lcd.print(text);
delay(2000); // Kurze Pause, damit der Anfang lesbar ist
// Danach scrollen
for (int i = 1; i <= textLength - 16; i++) {
lcd.setCursor(0, row);
lcd.print(text + i); // Ab Offset i den Text anzeigen
delay(300); // Verzögerung für Scroll-Geschwindigkeit
}
// Verhalten nach dem Scrollen festlegen
if (returnToStart) {
lcd.setCursor(0, row);
lcd.print(text); // Anfang des Textes wieder anzeigen
} else {
lcd.setCursor(0, row);
lcd.print(text + (textLength - 16)); // Text hinten stehen lassen
}
}
}
// Funktion zum Extrahieren eines Wertes aus der GET-Anfrage von Tasmota-Geräten
String _extract_value_tasmota_json(const String& url, const String& key) {
WiFiClient client; // WiFiClient-Objekt erstellen
HTTPClient http;
if (http.begin(client, url)) { // Begin mit WiFiClient und URL
int httpResponseCode = http.GET();
if (httpResponseCode == 200) {
String response = http.getString();
http.end();
int startIndex = response.indexOf("\"" + key + "\":");
if (startIndex == -1) {
return "?"; // Key nicht gefunden
}
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 {
//Serial.println("Fehler bei der Anfrage: " + String(httpResponseCode));
}
http.end();
} else {
Serial.println("Verbindung zur URL fehlgeschlagen: " + url);
}
return "?";
}
// WLAN-Verbindung herstellen
void connectToWiFi() {
Serial.println("WLAN Verbindungsaufbau zu: " + String(ssidList[current_ap]));
Serial.println("Passwort: " + String(passwordList[current_ap]));
_lcd_display_text(0, "Bitte warten", "center");
_lcd_display_text(1, "WLAN verbinden ", "left");
lcd.createChar(0, customChar_wlan);
lcd.setCursor(15, 1);
lcd.write(byte(0));
WiFi.begin(ssidList[current_ap], passwordList[current_ap]);
//Blinkendes WLAN Symbol wärend das WLAN versucht zu verbinden
int attempt = 0;
while (WiFi.status() != WL_CONNECTED && attempt < 10) {
delay(500);
Serial.print(".");
lcd.setCursor(15, 1);
lcd.print(" ");
delay(500);
lcd.setCursor(15, 1);
lcd.write(byte(0));
attempt++;
}
//Verbindung fehlgeschlagen (current_ap erhöhen)
if (WiFi.status() != WL_CONNECTED) {
WiFi.disconnect();
delay(500);
Serial.println("\nVerbindung fehlgeschlagen.");
current_ap = (current_ap + 1) % numNetworks;
reconnecting = false;
//Verbunden
} else {
Serial.print("\nWLAN verbunden: ");
Serial.print(WiFi.SSID());
Serial.print(" ");
Serial.println(WiFi.RSSI());
_lcd_display_text(0, "WLAN verbunden", "center");
_lcd_display_text(1);
_lcd_display_text(1, WiFi.SSID().c_str());
reconnecting = false;
delay(2500);
_lcd_display_text(0, "Netzbezug: ?W");
_lcd_display_text(1, "Erzeugung: ?W");
}
}
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.print(" ");
lcd.setCursor(16 - (netzbezug.length() + 1), 0);
lcd.print(netzbezug);
}
if (erzeugung != erzeugung_alt) {
lcd.setCursor(10, 1);
lcd.print(" ");
lcd.setCursor(16 - (erzeugung.length() + 1), 1);
lcd.print(erzeugung);
}
netzbezug_alt = netzbezug;
erzeugung_alt = erzeugung;
}
void handleButtonPress() {
currentButtonState = digitalRead(BUTTON_PIN);
if (currentButtonState == LOW && lastButtonState == HIGH) {
currentDelayIndex = (currentDelayIndex + 1) % delayOptionsSize;
refreshRate = delayOptions[currentDelayIndex];
Serial.print("Neue Aktualisierungsrate: ");
Serial.println(refreshRate);
_lcd_display_text(0, " Aktual. Rate ");
_lcd_display_text(1);
_lcd_display_text(1, (String(refreshRate / 1000) + " Sekunden").c_str(), "center");
isMessageDisplayed = true;
messageDisplayTime = millis();
delay(200);
}
lastButtonState = currentButtonState;
}
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP);
Serial.begin(115200);
delay(1000);
lcd.init();
lcd.backlight();
lcd.createChar(0, customChar_wlan);
WiFi.setHostname(hostname);
WiFi.mode(WIFI_STA);
lcd.setCursor(0, 0);
_lcd_display_text(0, "Bereit", "center");
}
void loop() {
handleButtonPress();
if (WiFi.status() != WL_CONNECTED && !reconnecting) {
reconnecting = true;
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 (!isMessageDisplayed && millis() - lastUpdateTime >= refreshRate) {
lastUpdateTime = millis();
update_power_values();
}
}
}