#include <EEPROM.h>
#include <DHT.h>
#include <Servo.h>
#include "AlarmTone.h"
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define I2C_ADDR    0x27
#define LCD_COLUMNS 20
#define LCD_LINES   4
#define DHTPIN 2
#define DHTTYPE DHT22
#define RELAY_HEAT 3
#define FAN_PIN 4
#define UMIDIFICADOR_PIN 6 // Novo pino para o relé do umidificador
#define SPEAKER_PIN A3
LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLUMNS, LCD_LINES);
DHT dht(DHTPIN, DHTTYPE);
AlarmTone alarmTone;
int pos = 0;
float tempMin = 37.0;
float tempMax = 38.0;
float umidadeMin = 45.0;
float umidadeMax = 55.0;
unsigned long media = 0;
unsigned long umedia = 0;
unsigned long ultimoUpdateLCD = 0;
const long intervalo = 1UL * 60UL * 1000UL;    // 1 minutos (ajuste para TEMPO real de viragem)
const unsigned long tempMedia = 1UL * 60UL * 1000UL;       // 1 minuto
const unsigned long umiMedia = 1UL * 60UL * 1000UL;       // 1 minuto
const int TEMPO_INCUBACAO_DIAS = 21; // 21 dias para eclosão de ovos de galinha
const int DIAS_ALARME_ECLOSAO = 3;   // Alerta 3 dias antes da eclosão
const unsigned long updateLCDInterval = 2000UL; // Atualiza LCD a cada 2 segundos
Servo meuServo; 
unsigned long tempoAnterior = 0; // Armazena o último tempo que o servo se moveu
int estadoServo = 0;             // 0 para 0 graus, 1 para 180 graus
// Contagem de dias sem RTC
unsigned long dataInicioMillis = 0;
const int ENDERECO_DATA_INICIO = 0;
void setup() {
   pinMode(13, OUTPUT);
  // EEPROM limpa apenas se necessário
   for (int i = 0 ; i < EEPROM.length() ; i++) {
   EEPROM.write(i, 0);
  }
   // Init
  lcd.init();
  lcd.backlight();
  Serial.begin(9600);
  lcd.begin(16, 2);
  dht.begin();
  pinMode(RELAY_HEAT, OUTPUT);
  pinMode(FAN_PIN, OUTPUT);
  pinMode(UMIDIFICADOR_PIN, OUTPUT); // Novo pino do umidificador
  pinMode(13, OUTPUT);
  meuServo.attach(5); 
  meuServo.write(0);
  tempoAnterior = millis(); // Inicializa o tempo anterior
  alarmTone.begin(SPEAKER_PIN);
  lcd.setCursor(0, 0);
  lcd.print("Incubadora");
  delay(2000);
  lcd.clear();
  // Carrega a data de início da EEPROM
  EEPROM.get(ENDERECO_DATA_INICIO, dataInicioMillis);
  
  // Se o valor for 0, é a primeira inicialização. Salva o millis() atual.
  if (dataInicioMillis == 0) {
    dataInicioMillis = millis();
    EEPROM.put(ENDERECO_DATA_INICIO, dataInicioMillis);
    lcd.clear();
     lcd.setCursor(0, 0);
     lcd.print("Incubacao ");
     lcd.setCursor(0, 1);
     lcd.print("iniciada!");
     delay(2000);
     lcd.clear();
  }
}
void loop() {
 unsigned long tempoAtual = millis();
  
  // --- Leitura do sensor e atualização do LCD (não bloqueante) ---
 if (tempoAtual - ultimoUpdateLCD >= updateLCDInterval) {
    float temperatura = dht.readTemperature();
    float umidade = dht.readHumidity();
   if (isnan(temperatura) || isnan(umidade)) {
     Serial.println("Falha na leitura do sensor DHT!");
     lcd.setCursor(0, 0);
     lcd.print("Erro no sensor");
     delay(2000);
     return;
   }
    // --- Lógica de Contagem de Dias e Alarme de Eclosão ---
   long diasPassados = (tempoAtual - dataInicioMillis) / 86400000UL; // 86400000UL = milissegundos em um dia
   long diasRestantes = TEMPO_INCUBACAO_DIAS - diasPassados;
    lcd.setCursor(0, 0);
    lcd.print("T:");
    lcd.print(temperatura, 1); // Exibe com uma casa decimal
    lcd.print((char)223); // Símbolo de grau
    lcd.print("C");
    
    lcd.setCursor(0, 1);
    lcd.print("U:");
    lcd.print(umidade, 1); // Exibe com uma casa decimal
    lcd.print("%");
    lcd.setCursor(9, 1);
    lcd.print("D:");
    if (diasRestantes < 10)lcd.print("-");
      lcd.print(diasRestantes);
    // Controle de aquecimento
   if (temperatura < tempMin) {
     digitalWrite(RELAY_HEAT, HIGH);
     lcd.setCursor(12, 0);
     lcd.print(" Aqc");
   } else if (temperatura > tempMax) {
     digitalWrite(RELAY_HEAT, LOW);
     lcd.setCursor(12, 0);
     lcd.print("    ");
   }
   // Controle de ventilação
   if (temperatura > tempMax || umidade > umidadeMax) {
     digitalWrite(FAN_PIN, HIGH);
     digitalWrite(UMIDIFICADOR_PIN, HIGH);
     lcd.setCursor(13, 1);
     lcd.print(" Vt");
   } else {
     digitalWrite(FAN_PIN, LOW);
     digitalWrite(UMIDIFICADOR_PIN, HIGH);
     lcd.setCursor(13, 1);
     lcd.print("   ");
   }
   // Controle de umidade
   if (umidade > umidadeMin - 5 && umidade < umidadeMax) {
      analogWrite(UMIDIFICADOR_PIN, 1);
      delayMicroseconds(random(15000));
      analogWrite(UMIDIFICADOR_PIN, 10);
      delayMicroseconds(random(15000));
      analogWrite(UMIDIFICADOR_PIN, 100);
      delayMicroseconds(random(15000));
      analogWrite(UMIDIFICADOR_PIN, 255); // 100% duty cycle
      delayMicroseconds(random(15000));
     lcd.setCursor(8, 0);
     lcd.print(" Umd");
   } else {
     analogWrite(UMIDIFICADOR_PIN, 0);
     lcd.setCursor(8, 0);
     lcd.print("    ");
   }
    
   // Alarme de temperatura fora da média
   if (temperatura < tempMin || temperatura > tempMax) {
    if (millis() - media > tempMedia) {
      alarmTone.play();
    analogWrite(13, 255);
    }
   } else {
    media = millis();
    alarmTone.stop();
    analogWrite(13, 0);
   }
   // --- Alerta de eclosão (opcional, pode ser removido) ---
   if (diasRestantes <= 3) {   
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Eclodindo: pinto");
    lcd.setCursor(0, 1);
    lcd.print("Aguarde: Verifica");
    // Não atualiza eclode para manter a mensagem
   }
   // Alarme de umidade fora da média
   if (umidade < umidadeMin) {
    if (millis() - umedia > umiMedia) {
      alarmTone.play();
    }
   } else{
    if (umidade >= umidadeMax){
     umedia = millis();
     alarmTone.stop();
   }
   }
    ultimoUpdateLCD = tempoAtual;
  }
  // Viragem dos ovos
 unsigned long tempAtual = millis();
  // Se o tempo atual menos o tempo anterior for maior que o intervalo,
  // é hora de mover o servo
  if (tempAtual - tempoAnterior >= intervalo) {
    tempoAnterior = tempAtual; // Atualiza o tempo anterior
    if (estadoServo == 0) {
      meuServo.write(180);
      estadoServo = 1;
    } else {
      meuServo.write(0);
      estadoServo = 0;
    }
  }
  delay(1000); // 1 segundo
}