#include <EEPROM.h>
#include <DHT.h>
#include <Servo.h>
#include <Wire.h>
#include "RTClib.h"
#include "AlarmTone.h"
#include <LiquidCrystal.h>
// Definição dos pinos
#define DHTPIN 2
#define DHTTYPE DHT22
#define RELAY_HEAT 3
#define FAN_PIN 4
#define SERVO_PIN 5
#define SPEAKER_PIN 6
#define STATUS_LED_PIN 13 // Usando o pino 13 como LED de status
// Pinos do LCD
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);
// Inicialização dos objetos
DHT dht(DHTPIN, DHTTYPE);
Servo virador;
RTC_DS1307 rtc;
AlarmTone alarmTone;
// Constantes de controle
const float TEMP_MIN = 37.0;
const float TEMP_MAX = 38.0;
const float UMIDADE_MIN = 45.0;
const float UMIDADE_MAX = 55.0;
// Constantes de tempo (em milissegundos)
const unsigned long INTERVALO_VIRADA = 4UL * 60UL * 60UL * 1000UL; // 4 horas
const unsigned long ALARME_TEMP_DELAY = 1UL * 60UL * 1000UL; // 1 minuto
const unsigned long UPDATE_LCD_INTERVAL = 2000UL; // 2 segundos
const int TEMPO_INCUBACAO_DIAS = 21; // Duração total da incubação
const int DIAS_ALARME_ECLOSAO = 3; // Alarme 3 dias antes da eclosão
// Variáveis de estado
unsigned long ultimaVirada = 0;
unsigned long ultimoAlarmeTemp = 0;
unsigned long ultimoUpdateLCD = 0;
unsigned long dataInicioUnix = 0;
bool alarmeEclosaoAtivado = false;
bool alarmeTempAtivado = false;
// Endereços da EEPROM
const int ENDERECO_DATA_INICIO = 0;
void setup() {
Serial.begin(9600);
pinMode(RELAY_HEAT, OUTPUT);
pinMode(FAN_PIN, OUTPUT);
pinMode(STATUS_LED_PIN, OUTPUT);
virador.attach(SERVO_PIN);
alarmTone.begin(SPEAKER_PIN);
lcd.begin(16, 2);
lcd.print("Iniciando...");
delay(2000);
dht.begin();
if (!rtc.begin()) {
lcd.clear();
lcd.print("Erro no RTC!");
while (1);
}
EEPROM.get(ENDERECO_DATA_INICIO, dataInicioUnix);
// CORREÇÃO: Salva a data de início APENAS se for 0 (primeira vez)
if (dataInicioUnix == 0) {
dataInicioUnix = rtc.now().unixtime();
EEPROM.put(ENDERECO_DATA_INICIO, dataInicioUnix);
lcd.clear();
lcd.print("Incubacao iniciada!");
delay(2000);
}
digitalWrite(RELAY_HEAT, LOW);
digitalWrite(FAN_PIN, LOW);
digitalWrite(STATUS_LED_PIN, LOW);
lcd.clear();
}
void loop() {
unsigned long tempoAtual = millis();
// --- Leitura do sensor e atualização do LCD (não bloqueante) ---
if (tempoAtual - ultimoUpdateLCD >= UPDATE_LCD_INTERVAL) {
float temperatura = dht.readTemperature();
float umidade = dht.readHumidity();
if (isnan(temperatura) || isnan(umidade)) {
lcd.setCursor(0, 0);
lcd.print("Erro no sensor");
return;
}
lcd.setCursor(0, 0);
lcd.print("T:");
lcd.print(temperatura, 1);
lcd.print((char)223);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print("U:");
lcd.print(umidade, 1);
lcd.print("%");
DateTime now = rtc.now();
lcd.setCursor(8, 0);
if (now.hour() < 10) lcd.print('0');
lcd.print(now.hour(), DEC);
lcd.print(':');
if (now.minute() < 10) lcd.print('0');
lcd.print(now.minute(), DEC);
lcd.print(':');
if (now.second() < 10) lcd.print('0');
lcd.print(now.second(), DEC);
// Controle de aquecimento
if (temperatura < TEMP_MIN) {
digitalWrite(RELAY_HEAT, HIGH);
} else {
digitalWrite(RELAY_HEAT, LOW);
}
// Controle de ventilação
if (temperatura > TEMP_MAX || umidade > UMIDADE_MAX) {
digitalWrite(FAN_PIN, HIGH);
} else {
digitalWrite(FAN_PIN, LOW);
}
ultimoUpdateLCD = tempoAtual;
}
// --- Alarme de temperatura fora da faixa (com temporização não bloqueante) ---
float tempLeitura = dht.readTemperature();
if (tempLeitura < TEMP_MIN || tempLeitura > TEMP_MAX) {
if (tempoAtual - ultimoAlarmeTemp >= ALARME_TEMP_DELAY) {
if (!alarmeTempAtivado) {
alarmTone.play();
alarmeTempAtivado = true;
digitalWrite(STATUS_LED_PIN, HIGH);
Serial.println("Alarme de temperatura!");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Alarme: Temp");
}
}
} else {
alarmeTempAtivado = false;
ultimoAlarmeTemp = tempoAtual;
alarmTone.stop();
digitalWrite(STATUS_LED_PIN, LOW);
}
// --- Lógica de Contagem de Dias e Alarme de Eclosão ---
unsigned long tempoAtualUnix = rtc.now().unixtime();
long diasPassados = (tempoAtualUnix - dataInicioUnix) / 86400;
long diasRestantes = TEMPO_INCUBACAO_DIAS - diasPassados;
if (diasRestantes > DIAS_ALARME_ECLOSAO) {
lcd.setCursor(8, 1);
lcd.print("D:");
if (diasRestantes < 10) lcd.print(" ");
lcd.print(diasRestantes);
alarmeEclosaoAtivado = false;
} else if (diasRestantes > 0) { // Dentro da janela de alarme de eclosão
if (!alarmeEclosaoAtivado) {
alarmTone.play();
alarmeEclosaoAtivado = true;
Serial.println("Alarme de eclosao!");
}
lcd.setCursor(8, 1);
lcd.print("ALARME");
} else if (diasRestantes <= 0) {
lcd.setCursor(8, 1);
lcd.print("ECLODE!");
alarmTone.stop();
}
// --- Viragem dos ovos (não bloqueante) ---
if (tempoAtual - ultimaVirada >= INTERVALO_VIRADA) {
virador.write(90);
delay(500); // Mantido para o movimento do servo
virador.write(0);
ultimaVirada = tempoAtual;
Serial.println("Ovos virados!");
}
}