/*
* ============================================================
* INCUBATEUR D'OEUFS DE POULE
* ============================================================
*
* Consignes automatiques :
* - Jours 1 à 18 : T = 37.5 °C, H = 45 %
* - Jours 19 à 21 : T = 37.5 °C, H = 67.5 %
*
* Fonctionnement :
* 1. Au démarrage, RIEN ne se passe : les relais restent éteints
* tant que l'incubation n'a pas été démarrée.
* 2. Un appui sur le bouton enregistre la date de départ dans
* l'EEPROM et met le jour à 1.
*
* ============================================================
*/
#include <Wire.h>
#include <RTClib.h>
#include <DHT.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
// -------- Broches (inchangées) --------
#define PIN_DHT 2 // DHT22 sur D2
#define PIN_RELAIS_CHAUFF 7 // Relais du chauffage
#define PIN_RELAIS_HUMID 8 // Relais de l'humidificateur
#define PIN_BOUTON 3 // Bouton de démarrage
// -------- Niveau d'activation des relais --------
// ⚠️ SI LES RELAIS NE FONCTIONNENT PAS COMME PREVU
// (restent allumés en permanence, ou s'allument quand ils
// devraient être éteints), INVERSEZ CES DEUX LIGNES :
// #define RELAIS_ON LOW
// #define RELAIS_OFF HIGH
// ------------------------------------------------------------
#define RELAIS_ON HIGH
#define RELAIS_OFF LOW
// -------- Type de DHT --------
#define TYPE_DHT DHT22
// -------- Adresse du LCD I2C --------
#define LCD_ADRESSE 0x27
// -------- Consignes (modifiables) --------
const float TEMP_INCUB = 37.5;
const float HUMID_INCUB = 45.0;
const float TEMP_ECLOS = 37.5;
const float HUMID_ECLOS = 67.5;
// -------- Marges pour éviter les oscillations --------
const float MARGE_TEMP = 0.5;
const float MARGE_HUMID = 2.0;
// -------- Adresse EEPROM pour la date de début --------
const int EEPROM_ADR = 0;
// -------- Objets --------
DHT capteur(PIN_DHT, TYPE_DHT);
RTC_DS1307 rtc; // DS1307 pour Wokwi
LiquidCrystal_I2C lcd(LCD_ADRESSE, 16, 2);
// -------- Variables globales --------
unsigned long timestampDebut = 0;
int jour = 0;
float consigneTemp = TEMP_INCUB;
float consigneHumid = HUMID_INCUB;
bool chauffageON = false;
bool humiditeON = false;
bool incubationDemarree = false; // ← nouveau drapeau
unsigned long dernierAffichage = 0;
const unsigned long INTERVALLE = 2000;
// ============================================================
// Calcule les consignes selon le jour actuel
// ============================================================
void calculerConsignes() {
if (jour >= 1 && jour <= 18) {
consigneTemp = TEMP_INCUB;
consigneHumid = HUMID_INCUB;
} else if (jour >= 19) {
consigneTemp = TEMP_ECLOS;
consigneHumid = HUMID_ECLOS;
} else {
consigneTemp = TEMP_INCUB;
consigneHumid = HUMID_INCUB;
}
}
// ============================================================
// Démarre l'incubation : enregistre la date du jour
// ============================================================
void demarrerIncubation() {
timestampDebut = rtc.now().unixtime();
EEPROM.put(EEPROM_ADR, timestampDebut);
jour = 1;
incubationDemarree = true;
calculerConsignes();
Serial.println("Incubation demarree !");
}
// ============================================================
// Lit la date de début dans l'EEPROM et calcule le jour
// ============================================================
void calculerJour() {
EEPROM.get(EEPROM_ADR, timestampDebut);
// EEPROM vierge → pas d'incubation en cours
if (timestampDebut == 0 || timestampDebut == 0xFFFFFFFF) {
jour = 0;
incubationDemarree = false;
return;
}
// Une date valide est présente → incubation en cours
incubationDemarree = true;
unsigned long secondesEcoulees = rtc.now().unixtime() - timestampDebut;
jour = secondesEcoulees / 86400UL + 1;
if (jour > 21) jour = 21;
}
// ============================================================
// Affiche tout sur le LCD
// ============================================================
void afficherLCD(float temp, float humid) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Poule ");
if (!incubationDemarree) {
lcd.print("Attente");
} else {
lcd.print("J");
lcd.print(jour);
lcd.print("/21");
}
lcd.setCursor(0, 1);
lcd.print("T:");
lcd.print(temp, 1);
lcd.print("C H:");
lcd.print(humid, 0);
lcd.print("%");
}
// ============================================================
// SETUP
// ============================================================
void setup() {
Serial.begin(9600);
Serial.println("Incubateur - Demarrage");
capteur.begin();
if (!rtc.begin()) {
Serial.println("RTC introuvable !");
while (1);
}
// Décommentez UNE SEULE FOIS pour régler l'heure du RTC :
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
lcd.init();
lcd.backlight();
lcd.print("Incubateur");
lcd.setCursor(0, 1);
lcd.print("Poule...");
delay(2000);
pinMode(PIN_RELAIS_CHAUFF, OUTPUT);
pinMode(PIN_RELAIS_HUMID, OUTPUT);
pinMode(PIN_BOUTON, INPUT_PULLUP);
digitalWrite(PIN_RELAIS_CHAUFF, RELAIS_OFF);
digitalWrite(PIN_RELAIS_HUMID, RELAIS_OFF);
calculerJour();
calculerConsignes();
}
// ============================================================
// BOUCLE PRINCIPALE
// ============================================================
void loop() {
// ---- 1. Lecture du capteur ----
float temperature = capteur.readTemperature();
float humidite = capteur.readHumidity();
if (isnan(temperature) || isnan(humidite)) {
Serial.println("Erreur DHT !");
delay(1000);
return;
}
// ---- 2. Bouton avec détection de front ----
static bool boutonPrecedent = HIGH;
bool boutonActuel = digitalRead(PIN_BOUTON);
if (boutonPrecedent == HIGH && boutonActuel == LOW) {
delay(50);
if (digitalRead(PIN_BOUTON) == LOW) {
demarrerIncubation();
}
}
boutonPrecedent = boutonActuel;
// ---- 3. Recalcule le jour ----
calculerJour();
calculerConsignes();
// ---- 4. Commande des relais UNIQUEMENT si incubation démarrée ----
if (incubationDemarree) {
if (temperature < consigneTemp) {
digitalWrite(PIN_RELAIS_CHAUFF, RELAIS_ON);
chauffageON = true;
} else if (temperature > consigneTemp + MARGE_TEMP) {
digitalWrite(PIN_RELAIS_CHAUFF, RELAIS_OFF);
chauffageON = false;
}
if (humidite < consigneHumid) {
digitalWrite(PIN_RELAIS_HUMID, RELAIS_ON);
humiditeON = true;
} else if (humidite > consigneHumid + MARGE_HUMID) {
digitalWrite(PIN_RELAIS_HUMID, RELAIS_OFF);
humiditeON = false;
}
} else {
// Pas d'incubation en cours → tout éteint
digitalWrite(PIN_RELAIS_CHAUFF, RELAIS_OFF);
digitalWrite(PIN_RELAIS_HUMID, RELAIS_OFF);
chauffageON = false;
humiditeON = false;
}
// ---- 5. Affichage LCD toutes les 2 secondes ----
if (millis() - dernierAffichage >= INTERVALLE) {
afficherLCD(temperature, humidite);
dernierAffichage = millis();
}
// ---- 6. Debug série (version lisible) ----
Serial.print("Bouton: ");
Serial.print(boutonActuel == LOW ? "APPUYE " : "relache");
Serial.print(" | T="); Serial.print(temperature);
Serial.print("C H="); Serial.print(humidite);
Serial.print("% | J="); Serial.print(jour);
Serial.print(" | Etat="); Serial.print(incubationDemarree ? "ACTIVE " : "ATTENTE");
Serial.print(" | Chauf="); Serial.print(chauffageON ? "ON " : "OFF");
Serial.print(" Hum="); Serial.println(humiditeON ? "ON" : "OFF");
delay(50);
}