/*

*/
#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <ArduinoJson.h>  

#define DHTPIN 4
#define DHTTYPE DHT22
#define LED_CHANNEL 0
#define IS2_ADDR 0x27
#define LCD_COLS 20
#define LCD_ROWS 4

DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(IS2_ADDR, LCD_COLS, LCD_ROWS);

const char* ssid = "Wokwi-GUEST";
const char* password = "";

const char* clientId = "pserumu";
const char* mqtt_server = "broker.mqtt-dashboard.com";
const int mqtt_port = 1883;
const char* mqtt_topic = "psergeraur";
const char* mqttUser="";
const char* mqttPassword="";

const float BETA = 3950;

const int pinBuzzer = 32;
const int pinLed = 5;
const int pinPressureValve = 14;
const int pinCoolValve = 27;
const int pinTrig = 19; //Sensor de presión
const int pinEcho = 18; //Sensor de presión

const int max_temp = 50;
const int high_temp = 40;
const int min_temp = -20;
const int cool_temp = -10;
const int high_press = 150;
const int max_press = 170;


WiFiClient espClient;
PubSubClient client(espClient);

void reconnect() {
  while (!client.connected()) {
    Serial.print("Conectando al servidor MQTT...");
    if (client.connect(clientId)) {
      Serial.println("conectado");
      client.subscribe(mqtt_topic);
      client.setCallback(callback);
    } else {
      Serial.print("Error, rc=");
      Serial.print(client.state());
      Serial.println(". Intentando de nuevo en 5 segundos");
      delay(5000);
    }
  }
}

void callback(char* topic, byte* payload, unsigned int length) {  
  if(length <= 40){
      cleanLine(2);
    cleanLine(3);
    lcd.setCursor(0,2);
    lcd.print("Message received:");
    delay(200);
    cleanLine(2);
    cleanLine(3);
    lcd.setCursor(0,2);
    for (int i = 0; i < length; i++) {
      lcd.print((char)payload[i]);
    }
    lcd.println();
    delay(400);
  }
}

void setup() {
  dht.begin(); // Inicia el sensor de temperatura y humedad
  Wire.begin();
  lcd.init();
  lcd.backlight();
  ledcSetup(LED_CHANNEL, 5000, 8); //Led Rojo
  ledcAttachPin(pinLed, LED_CHANNEL);
  pinMode(pinPressureValve, OUTPUT);
  pinMode(pinCoolValve, OUTPUT);
  pinMode(pinBuzzer, OUTPUT);
  pinMode(pinTrig, OUTPUT);
  pinMode(pinEcho, INPUT);

  moveServo(pinPressureValve,0);
  moveServo(pinCoolValve,0);

  WiFi.begin(ssid, password);
  Serial.println("Connecting");
  while(WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Se ha conectado al wifi con la IP: ");
  Serial.println(WiFi.localIP());

  client.setServer(mqtt_server, mqtt_port);


}

void moveServo(int servoPin, int angle) {
  int pulseWidth = map(angle, 0, 180, 500, 2400); // Mapea el ángulo a un ancho de pulso entre 500us y 2400us
  digitalWrite(servoPin, HIGH); // Envía un pulso alto
  delayMicroseconds(pulseWidth); // Espera el ancho de pulso deseado
  digitalWrite(servoPin, LOW); // Vuelve a un pulso bajo
  delay(20); // Pequeño retardo para estabilidad
}

void cleanLine(int n){
  lcd.setCursor(0, n);
  lcd.print("                    ");
}

void alarm(){
  ledcWrite(LED_CHANNEL, 255);
  tone(pinBuzzer, 300, 500);
  
}

void loop() {
  if(WiFi.status()== WL_CONNECTED){
    if (!client.connected()) {
      reconnect();
    }
    client.loop();
  }
  else {
    Serial.println("WiFi Desconectado");
  }
   
  lcd.clear();
  ledcWrite(LED_CHANNEL, 0);

  float temp = dht.readTemperature();
  float hum = dht.readHumidity();

  //Preparamos el sensor de presión
  digitalWrite(pinTrig, HIGH);
  delayMicroseconds(10);
  digitalWrite(pinTrig, LOW);

  int press = pulseIn(pinEcho, HIGH) /58;
  
  StaticJsonDocument<100> jsonDoc;
  jsonDoc["temperature"] = temp;
  jsonDoc["humidity"] = hum;
  jsonDoc["pressure"] = press;

  char jsonStr[100];
  serializeJson(jsonDoc, jsonStr);

  client.publish("psergeraur", jsonStr);

  //Vávulas
  if(temp > high_temp){
    moveServo(pinCoolValve,90);
  }
  if(press > high_press){
    moveServo(pinPressureValve,90);
  }
  if (temp <= high_temp && press <= high_press){
    moveServo(pinPressureValve,0);
    moveServo(pinCoolValve,0);
  }

  //Alarma

  if(temp > max_temp || temp < min_temp || hum > 90 || press > max_press){
    alarm();
  }

  //Monitoreo de temperatura
  cleanLine(0);
  lcd.setCursor(0,0);
  lcd.print("Temperature: ");
  lcd.println(temp);
  if(temp > max_temp){
    cleanLine(1);
    lcd.setCursor(0,1);
    lcd.println("WARNING: HIGH TEMP");
  }
  if(temp < min_temp){
    cleanLine(1);
    lcd.setCursor(0,1);
    lcd.println("WARNING: LOW TEMP");
  }
  delay(400);

  //Monitoreo de humedad
  cleanLine(0);
  lcd.setCursor(0,0);
  lcd.print("Humidity: ");
  lcd.println(hum);
  if(hum > 90){
    cleanLine(1);
    lcd.setCursor(0,1);
    lcd.println("WARNING: WATER LEAK");
  }
  delay(400);

  //Monitoreo de presión
  cleanLine(0);
  lcd.setCursor(0,0);
  lcd.print("Pressure: ");
  lcd.println(press);
  if(press > max_press){
    cleanLine(1);
    lcd.setCursor(0,1);
    lcd.println("WARNING: HIGH PRESS");
  }
  delay(400);
  
  noTone(pinBuzzer);

  delay(2000);
}