/*
 Autores: Alba Sánchez Ibáñez, Lucas Colbert Eastgate
 Refatorado e corrigido por Gemini
 
 Este código foi refeito para usar a biblioteca PID_v1.h do Arduino.
 A lógica de controle agora é delegada para a biblioteca, tornando o
 código mais robusto e fácil de entender.
*/
#include <math.h>
#include <PID_v1.h>
// PINOS
const byte LEDROJO = 3;
const byte LEDVERDE = 5;
const byte THERMISTOR_PIN = A0;
const byte TRANSISTOR_PIN = 6; // PWM Pin para controle de potência
// PERIODOS em milissegundos
const unsigned long PERIODO_TMP_MS = 1000;
const unsigned long PERIODO_MONITOR_MS = 1000;
// VALORES DO TERMISTOR (NTC 10kOhm)
const float THERMISTOR_T0 = 25.0; // Temperatura de referência
const float THERMISTOR_R0 = 10000.0; // Resistência na temperatura de referência
const float THERMISTOR_B = 3950.0; // Constante Beta
const int RESISTOR_DIVISOR = 10000; // Resistor em série com o termistor
//const8ES DE TEMPERATURA
double TMP_REF = 38.0; // Setpoint para a incubadora
const double TMP_MIN = 37.0;
const double TMP_MAX = 39.0;
// VALORES DO CONTROLADOR PID
const float KP = 0.4044;
const float KI = 0.0100;
const float KD = 3.3718;
// VARIÁVEIS DE CONTROLE DO PID
double pid_input;
double pid_output;
// Cria a instância do objeto PID
PID myPID(&pid_input, &pid_output, &TMP_REF, KP, KI, KD, DIRECT);
// CALCULO DE TEMPERATURA (Função Steinhart-Hart)
float val2tmp(int analog_value) {
  float resistance = RESISTOR_DIVISOR / ((1023.0 / analog_value) - 1.0);
  float celsius = 1.0 / (log(resistance / THERMISTOR_R0) / THERMISTOR_B + 1.0 / (THERMISTOR_T0 + 273.15)) - 273.15;
  return celsius;
}
// ESTRUTURAS DE ESTADO
struct Tmp {
  unsigned long last_ms;
  float val;
};
struct Monitor {
  unsigned long last_ms;
};
// --- SETUP DAS TAREFAS ---
void setup_tmp(unsigned long curr_ms, struct Tmp& tmp) {
  pinMode(LEDVERDE, OUTPUT);
  tmp.last_ms = curr_ms - PERIODO_TMP_MS;
  tmp.val = 0;
}
void setup_monitor(unsigned long curr_ms, struct Monitor& mtr) {
  Serial.begin(9600);
  while (!Serial); // Aguarda a conexão serial
  Serial.println(" # > Arduino Control de Temperatura PID 0.4044 0.0100 3.3718");
  Serial.println(" # $ - y20 :45 - w4 - l37.0 - l38.0 - l39.0 - tTemperatura - tCalefactor ");
  mtr.last_ms = curr_ms - PERIODO_MONITOR_MS;
}
void setup_pid() {
  myPID.SetMode(AUTOMATIC);
  myPID.SetOutputLimits(0, 255); // Saída PID irá de 0 a 255 (PWM)
}
// --- TAREFAS DE LOOP ---
void tarea_tmp(unsigned long curr_ms, struct Tmp& tmp) {
  if (curr_ms - tmp.last_ms >= PERIODO_TMP_MS) {
    tmp.last_ms += PERIODO_TMP_MS;
    int val = analogRead(THERMISTOR_PIN);
    tmp.val = val2tmp(val);
    byte est_tmp = (TMP_MIN <= tmp.val && tmp.val <= TMP_MAX) ? HIGH : LOW;
    digitalWrite(LEDVERDE, est_tmp);
  }
}
void tarea_monitor(unsigned long curr_ms, struct Monitor& mtr, const struct Tmp& tmp, const double& rele_estado) {
  if (curr_ms - mtr.last_ms >= PERIODO_MONITOR_MS) {
    mtr.last_ms += PERIODO_MONITOR_MS;
    if (Serial) {
      Serial.print(tmp.val);
      Serial.print(" ");
      Serial.println(rele_estado);
    }
  }
}
// --- MAIN ---
Tmp tmp;
Monitor mtr;
void setup() {
  unsigned long curr_ms = millis();
  pinMode(TRANSISTOR_PIN, OUTPUT);
  pinMode(LEDROJO, OUTPUT);
  setup_tmp(curr_ms, tmp);
  setup_monitor(curr_ms, mtr);
  setup_pid();
}
void loop() {
  unsigned long curr_ms = millis();
  
  // Tarefa de leitura de temperatura
  tarea_tmp(curr_ms, tmp);
  // Atualiza a entrada do PID e computa o novo valor de saída
  pid_input = tmp.val;
  myPID.Compute();
  // Aplica a saída do PID para o aquecedor e o LED vermelho (PWM)
  analogWrite(TRANSISTOR_PIN, pid_output);
  analogWrite(LEDROJO, pid_output);
  // Tarefa de monitoramento serial
  tarea_monitor(curr_ms, mtr, tmp, pid_output);
}