#include <LiquidCrystal.h>
#include <ESP32Servo.h>  //Servo-Bibliothek zur Steuerung des Servomotors
#include "DHTesp.h"
#include <WiFi.h>
#include <HTTPClient.h>
LiquidCrystal lcd(14, 13, 12, 11, 10, 9);
const int DHT_PIN = 46;
DHTesp dhtSensor;
int ledPins[10] = {4, 5, 6, 7, 15, 16, 17, 18, 8, 3};
//WLAN
const char* ssid = "Wokwi-GUEST";  // Public Gateway von Wokwi
const char* password = "";  // Ohne Passwort
//Zeit zum Senden der Daten an den Server
unsigned long lastSendTime = 0;
const unsigned long sendInterval = 10000;  // 10 Sekunden (in Millisekunden)
//Verbindung mit Server
const char* serverName = "https://climbing-jumbled-prepared.glitch.me/datos";
//Knopf
const int buttonPin1 = 38;
const int buttonPin2 = 39;
const int buttonPin3 = 37;
int buttonState1 = 0;  // Speichert den Status der Schaltfläche
int lastButtonState1 = 0;  // Speichert den vorherigen Zustand der Schaltfläche
// Variablen zum Speichern der alten Werte jeder Schaltfläche
//int oldValue1 = HIGH; // Anfangswert von Pin 38 (High, wenn nicht gedrückt)
int oldValue2 = HIGH; // Anfangswert von Pin 39
int oldValue3 = HIGH; // Anfangswert von Pin 37
// Variablen für den Fortschrittsbalken
unsigned long previousMillisProgress = 0;
const long intervalProgress = 200;  // 200ms Intervall zum Aktualisieren des Fortschrittsbalkens
int progress = 0;  // Fortschrittsbalken in Prozent (0-100)
bool resetInProgress = false;  // Status zurücksetzen (gestartet oder nicht)
//Potentiometer 
const int potentiometerPin = 1; // Analoger Pin des Potentiometers
int potentiometerValue = 0; // Potentiometerwert
// Variable für die „Temperaturgrenze“
float temperaturGrenze = 0.0;
float currentTemperature = 25.0; // Variable zum Speichern der aktuellen Temperatur des Sensors
//Servo motor
Servo ventiladorServo; // Servoobjekt zur Steuerung des Lüfters
// LED-Steuervariablen
bool allLedsOn = false; // Flag, um zu wissen, ob alle LEDs an sind
unsigned long previousMillis = 0; // Variable zur Steuerung der Zeit
unsigned long interval = 100; // 5 Sekunden Intervall zum Ausschalten einer LED
bool ledState = false;  // Variable zum Umschalten des Zustands der LEDs
void setup() {
  Serial.begin(115200);
  dhtSensor.setup(DHT_PIN, DHTesp::DHT22);
//LCD  
  lcd.begin(20, 4);
  lcd.setCursor(4, 0);
  lcd.print("Projekt-LF-7");
//LED
   //alle Pins als Ausgänge definieren
  for (int i = 0; i <= 9; i++) {
    pinMode(ledPins[i], OUTPUT);
    digitalWrite(ledPins[i], LOW); // Schalten Sie die LEDs zunächst aus
  }
//Servo Motor
  // Den Servomotor an Pin 19 anschließen
  ventiladorServo.attach(19);
  // Initialisiere das Servo auf eine Position (z. B. 0 Grad)
  ventiladorServo.write(0);  // Servomotor in Ausgangsposition (aus)    
  
//Knopf
  // Initialisiere die Pins, um die Tasten zu lesen
  pinMode(buttonPin1, INPUT_PULLUP);  // Konfiguration für den ersten Button
  pinMode(buttonPin2, INPUT_PULLUP);  // Konfiguration für den zweiten Button
  pinMode(buttonPin3, INPUT_PULLUP);  // Konfiguration für den dritten Button
// Initialisiere den Potentiometer-Pin
  pinMode(potentiometerPin, INPUT);  
// Initialisiere die simulierte Temperatur
  currentTemperature = 25.0; // Anfängliche Simulationstemperatur (25 Grad)
//WLAN
  // Mit WLAN verbinden
  Serial.println("Verbindung zum WLAN herstellen...");
  WiFi.begin(ssid, password);
  // Auf Verbindung warten
  while (WiFi.status() != WL_CONNECTED) {
    delay(4000);  // Warte 1 Sekunde
    Serial.println("Versuch, eine Verbindung zum WLAN herzustellen...");
  }
  // Sobald die Verbindung hergestellt ist
  Serial.println("Verbindung erfolgreich!");
  Serial.print("IP-Adresse: ");
  Serial.println(WiFi.localIP());  // Anzeige der vom Router zugewiesenen IP-Adresse
}
void loop() {
//Potentiometer
  // Lies den Potentiometerwert (0 bis 1023)
  potentiometerValue = analogRead(potentiometerPin);
  // Mappe den Potentiometerwert auf einen Bereich von 15 bis 35 Grad Celsius
  temperaturGrenze = map(potentiometerValue, 0, 1023, 15, 35);
//DHT22
  TempAndHumidity  data = dhtSensor.getTempAndHumidity();
//  currentTemperature = data.temperature;  // Weise der Variable die aktuelle Temperatur des Sensors zu
// Variable zum Speichern der Luftfeuchtigkeit des Sensors für den Server
  float humidity = data.humidity; 
//POST (Daten senden)
  if(WiFi.status() == WL_CONNECTED && millis() - lastSendTime >= sendInterval && !resetInProgress){
    lastSendTime = millis();  // Aktualisieren Sie die Zeit der letzten Sendung
    HTTPClient http;
    http.begin(serverName);
    http.addHeader("Content-Type", "application/json");
    String jsonData = "{";
    jsonData += "\"Temperatur\":" + String(currentTemperature, 1) + ",";
    jsonData += "\"Luftfeuchtigkeit\":" + String(humidity, 1) + ",";
    jsonData += "\"Temperaturgrenze\":" + String(temperaturGrenze, 1);
    jsonData += "}";
    int httpResponseCode = http.POST(jsonData);
    Serial.println("Daten an den Server senden...");
    if(httpResponseCode > 0){
      String response = http.getString();
      Serial.println("Antwort: " + response);
    } else {
     Serial.print("Fehler beim POST: ");
     Serial.println(httpResponseCode);
    }
    http.end();
  } /*else {
    Serial.println("WLAN nicht verbunden");
  }*/  
//LCD
  
  // Es wird geprüft, ob die Taste gedrückt wurde
  buttonState1 = digitalRead(buttonPin1);
  if (buttonState1 == LOW && lastButtonState1 == HIGH) {
    // Taste wurde gedrückt, starte Reset
    resetInProgress = true;
    progress = 0;  // Setzt den Fortschrittsbalken zurück
    previousMillisProgress = millis();  // Starten Sie den Timer für den Fortschrittsbalken
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Resetting system...");
  }
  
  // Wenn der Reset läuft, aktualisiere den Fortschrittsbalken
  if (resetInProgress) {
    unsigned long currentMillisProgress = millis();
    if (currentMillisProgress - previousMillisProgress >= intervalProgress) {
      previousMillisProgress = currentMillisProgress;  // Aktualisiere den Timer
      progress++;  // Fortschritt steigern
      // Nur den Fortschritt auf dem LCD anzeigen
      lcd.setCursor(0, 1);
      lcd.print("Progress: " + String(progress) + "%");
      // Löschen Sie die anderen Zeilen des LCD, um zu verhindern, dass unnötige Daten angezeigt werden
      lcd.setCursor(0, 2);
      lcd.print("                ");  // Zeile 2 löschen
      lcd.setCursor(0, 3);
      lcd.print("                ");  // Zeile 3 löschen
      Serial.print(".");
      // Wenn der Fortschritt 100 % erreicht, Ende zurücksetzen
      if (progress >= 100) {
        resetInProgress = false;  // Stoppen Sie das Zurücksetzen
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Reset completed");
        Serial.println("Zurücksetzen abgeschlossen");
        delay(1000);  // Die Abschlussmeldung 1 Sekunde lang anzeigen
        lcd.clear();
        lcd.setCursor(0, 0);
      }
    }
  }
  // Anzeige der DHT22-Sensorwerte
  // Wenn kein Reset durchgeführt wird, Sensordaten und Grenztemperatur anzeigen
  if (!resetInProgress) {
    lcd.setCursor(4, 0);
    lcd.print("Projekt-LF-7");
    lcd.setCursor(4, 1);
    lcd.print("Temp: " + String(currentTemperature, 1) + " C");
    lcd.setCursor(0, 2);
    lcd.print("Feuchtigkeit: " + String(data.humidity, 1) + " %");
  // Den Wert von „Temperatur Grenze“ anzeigen
    lcd.setCursor(0, 3);
    lcd.print("Temp Grenze: " + String(temperaturGrenze,1) + " C"); // Temperaturgrenze anzeigen 
//Serial Monitor
    Serial.println("Temp: " + String(currentTemperature, 1) + "°C");
    Serial.println("Feuchtigkeit: " + String(data.humidity, 1) + "%");
    Serial.println("Temperatur Grenze: " + String(temperaturGrenze, 1) + "°C");
    Serial.println("---");
    delay(2000); // Auf einen neuen Messwert vom Sensor warten (DHT22 has ~0.5Hz sample rate)
  
  
  
//Servo Motor
  // Wenn die Sensortemperatur höher als die Grenztemperatur ist, schalte den Lüfter ein
    if (currentTemperature > temperaturGrenze) {
    // Den Lüfter (Servomotor) mithilfe einer „for“-Schleife von 0 auf 180 Grad und umgekehrt drehen lassen
      for (int pos = 0; pos <= 180; pos++) {  // Drehen Sie das Servo von 0 bis 180 Grad
        ventiladorServo.write(pos);  // Bewegen Sie den Servomotor in die Position „pos“
        delay(5);  // Warten Sie 15 ms, damit das Servo die Position erreichen kann
      }
      for (int pos = 180; pos >= 0; pos--) {  // Drehe das Servo von 180 auf 0 Grad
        ventiladorServo.write(pos);  // Bewegen Sie den Servomotor in die Position „pos“
        delay(5);  // Warten Sie 15 ms, damit das Servo die Position erreichen kann
      }
    
    // Simulieren Sie, dass die Temperatur durch den Lüfter sinkt
      currentTemperature -= 0.50;  // Die Temperatur allmählich senken (den Lüftereffekt simulieren)
      Serial.println("Lüfter an, Temperatur sinkt");
    } 
    else {
    // Wenn die Sensortemperatur gleich oder niedriger als die Grenztemperatur ist, schalten Sie den Lüfter aus
      ventiladorServo.write(0);  // Lüfter ausschalten (Servo auf 0 Grad stellen)
      Serial.println("Lüfter aus");
    }
//LED
  // Wenn die Sensortemperatur höher als die Grenztemperatur ist, schalte die LEDs ein und aus (blinke)
    if (currentTemperature > temperaturGrenze) {
    // Verwenden Sie millis(), um einen Flackereffekt zu erzeugen
      unsigned long currentMillis = millis();
      if (currentMillis - previousMillis >= interval) {
        previousMillis = currentMillis;  // Aktualisiere die Zeit
      // Ändern Sie den Zustand der LEDs (an oder aus)
        ledState = !ledState;  // Ein- und Ausschalten
      // Den Zustand der LEDs übernehmen
        for (int i = 0; i < 10; i++) {
          digitalWrite(ledPins[i], ledState ? HIGH : LOW);  // LEDs blinken lassen
        }
      }
      Serial.println("LEDs blinken");
    } 
    else {
    // Wenn die Sensortemperatur gleich oder niedriger als die Grenztemperatur ist, schalten Sie alle LEDs ein
      for (int i = 0; i < 10; i++) {
        digitalWrite(ledPins[i], LOW);  // Alle LEDs einschalten
      }
      Serial.println("LEDs aus");
    }
  }
  
  // Speichert den vorherigen Zustand der Schaltfläche
  lastButtonState1 = buttonState1;
  
  
  // Verzögerung, um zu schnelles Lesen zu vermeiden
//  delay(1000);
//Knopf
  // Lesen Sie den Wert jeder Schaltfläche
 // int newValue1 = digitalRead(buttonPin1);
  int newValue2 = digitalRead(buttonPin2);
  int newValue3 = digitalRead(buttonPin3);
  // Überprüfen Sie, ob sich der Wert jeder Taste geändert hat und ob sie gedrückt oder losgelassen wurde
 /* if(newValue1 != oldValue1) 
  {
    if(newValue1 == LOW)  // Wenn die Taste gedrückt wurde
    {
      Serial.println("Taste 1 ist gedrückt.");
    }
    else  // Wenn die Taste losgelassen wurde
    {
      Serial.println("Taste 1 wird losgelassen.");
    }
    oldValue1 = newValue1;  // Merken Sie sich den Wert für das nächste Mal
  }
*/
  if(newValue2 != oldValue2)
  {
    if(newValue2 == LOW)
    {
      Serial.println("Button 2 is pressed.");
    }
    else
    {
      Serial.println("Button 2 is released.");
    }
    oldValue2 = newValue2;
  }
  if(newValue3 != oldValue3)
  {
    if(newValue3 == LOW)
    {
      Serial.println("Button 3 is pressed.");
    }
    else
    {
      Serial.println("Button 3 is released.");
    }
    oldValue3 = newValue3;
  }
  // Debouncing Entprellverzögerung (Tastenentprellung)
 // delay(100);
}