#include <DHT.h>                  //https://github.com/adafruit/DHT-sensor-library Written by Tony DiCola for Adafruit Industries ; https://github.com/adafruit/Adafruit_Sensor
#include <Wire.h>                 //https://github.com/adafruit/TinyWireM
#include <LiquidCrystal_I2C.h>    //https://github.com/johnrickman/LiquidCrystal_I2C
#include <PID_v1_bc.h>            //https://github.com/drf5n/Arduino-PID-Library

#define brocheDeBranchementDHT 4  // Le DHT22 est branché sur le pin 4
#define typeDeDHT DHT22
DHT dht(brocheDeBranchementDHT, typeDeDHT);

int fanPin = 18;  // Le ventilateur est branché sur le pin 18
int irSensorPin = 17;

LiquidCrystal_I2C lcd(0x27, 16, 2);  // Le LCD peut afficher 16 caractères par ligne sur 2 lignes

// Définition du caractère "°" sur le LCD (tableau 5x8 en binaire)
byte Degres[] = {
  B00111,
  B00101,
  B00111,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000
};

// Variables pour gestion du temps
unsigned long dernierMajDHT = 0;           // dernier moment où le DHT a été lu
const unsigned long IntervalleDHT = 2000;  // Intervalle de lecture DHT en millisecondes

unsigned long dernierMajPID = 0;          // dernier moment où le PID a été lu
const unsigned long IntervallePID = 300;  // Intervalle de lecture PID en millisecondes

// Variable PID
double Setpoint = 50;  // Humidité ciblée
double Input;
double Output;

double Kp = 1.5;   // Proportionnel
double Ki = 1;  // Intégral
double Kd = 0.16;  // Dérivé

PID pid(&Input, &Output, &Setpoint, Kp, Ki, Kd, REVERSE);

void setup() {

  pinMode(fanPin, OUTPUT);
  pinMode(irSensorPin, INPUT);

  Wire.begin(21, 22);  // SDA = 21, SCL = 22 (pins par défaut du LCD sur un ESP32)

  lcd.init();
  lcd.backlight();
  lcd.createChar(0, Degres);  // Création du caractère degrés
  lcd.clear();

  // Moniteur série
  Serial.begin(115200);
  dht.begin();

  pid.SetMode(AUTOMATIC);
  pid.SetOutputLimits(0, 255);  // PMW correspond à une valeur entre 0 et 255
}

void loop() {

  unsigned long millisActuels = millis();

  // Lecture DHT toutes les 2 sec
  if (millisActuels - dernierMajDHT >= IntervalleDHT) {
    dernierMajDHT = millisActuels;

    // Lecture des données
    float tauxHumidite = dht.readHumidity();        // Lecture du taux d'humidité (en %)
    float tauxTemperature = dht.readTemperature();  // Lecture de la température (en °C)

    // Vérification des données
    if (!isnan(tauxHumidite) && !isnan(tauxTemperature)) {
      Input = tauxHumidite;

      // Affichage sur le LCD
      lcd.setCursor(3, 0);
      lcd.print(tauxHumidite);
      lcd.print(" %RH");
      lcd.setCursor(4, 1);
      lcd.print(tauxTemperature);
      lcd.print(" ");
      lcd.write(0);
      lcd.print("C");
    }
  }

  // Lecture PID toutes les 300 ms
  if (millisActuels - dernierMajPID >= IntervallePID) {
    dernierMajPID = millisActuels;

    pid.Compute();  // Calcule PID
    analogWrite(fanPin, (int)Output);

    Serial.print("Vitesse du ventilateur : ");
    Serial.println(Output);
  }
}
