The circuit is inside the chicken coop, the temperature in France can be from ~ -10°C to 35°C outside, the coop is a bit isolated so should be a bit less in the extreme range.
The motor is a JGA25-370
+12VDC 60 RPM
Current without load: 50mA
Current while blocked: 1.2A
Also the power side is a 7Ah Lead battery, with a 20W solar panel with a small solar charge controller (typical cheap model)
and here is my code:
(sorry for the french comments and variable names, do not hesitate to ask if you have any question about it)
#include <Wire.h>
#include "RTClib.h"
#include <Dusk2Dawn.h>
#include <LowPower.h>
RTC_DS3231 rtc;
Dusk2Dawn soleil(46.6717, 5.3468, 1); // le Fay, UTC+1
const int openButtonPin = 2; // ouverture manuelle
const int closeButtonPin = 3; // fermeture manuelle
const int modeSwitchPin = 4; // Switch controle manuel ou horraire
const int relayPin = 5; // Pin connectée à IN du relais
const int finDeCourseFermePin = 7; // detecteur de fin de course Porte fermée
const int finDeCourseOuvertPin = 8; // detecteur de fin de course Porte ouverte
const int motorPinA = 9; // driver moteur L298 PinA
const int motorPinB = 10; // driver moteur L298 PinB
const int enaPin = 11; // driveur moteur L298 Pin ENA
int offsetSunriseMinutes = 0; // Ouvre X minutes AVANT le lever du soleil
int offsetSunsetMinutes = 30; // Ferme X minutes APRĂS le coucher du soleil
int sunriseTime = -1; // en minutes depuis minuit
int sunsetTime = -1;
// ------------- Mode entrée horaire manuelle pour tests ------------------
bool modeManuelHoraire = false; // false = auto lever/coucher, true = horaires manuels
int heureManuelleOuverture = (7 * 60) + 0; // 07:00 en minutes aprĂšs minuit
int heureManuelleFermeture = (20 * 60) + 0; // 21:00
enum PorteEtat { OUVERTE,
FERMEE,
EN_MOUVEMENT_OUVERTURE,
EN_MOUVEMENT_FERMETURE };
PorteEtat etatPorte = FERMEE;
bool dernierEtatMotorButton = HIGH;
bool dernierEtatSleepButton = HIGH;
bool porteAutoOuverte = false;
bool porteAutoFermee = false;
bool dernierEtatModeManuel = false;
volatile bool demandeOuverture = false;
volatile bool demandeFermeture = false;
volatile bool modeManuel = false;
//-----------SETUP-----------------
void setup() {
Wire.begin();
pinMode(openButtonPin, INPUT_PULLUP);
pinMode(closeButtonPin, INPUT_PULLUP);
pinMode(modeSwitchPin, INPUT_PULLUP);
pinMode(finDeCourseFermePin, INPUT_PULLUP);
pinMode(finDeCourseOuvertPin, INPUT_PULLUP);
pinMode(motorPinA, OUTPUT);
pinMode(motorPinB, OUTPUT);
pinMode(enaPin, OUTPUT);
pinMode(relayPin, OUTPUT);
attachInterrupt(digitalPinToInterrupt(openButtonPin), ouvrirPorteInterrupt, FALLING);
attachInterrupt(digitalPinToInterrupt(closeButtonPin), fermerPorteInterrupt, FALLING);
digitalWrite(enaPin, LOW); // ENA éteint au départ
digitalWrite(relayPin, LOW); // relais désactivé si actif à LOW
arreterMoteur();
Serial.begin(9600);
delay(500);
Serial.println("Début setup");
if (!rtc.begin()) {
Serial.println("RTC non détecté !");
while (1)
;
}
// Décommente une seule fois pour régler l'heure :
//rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
DateTime now = rtc.now();
Serial.print("Heure RTC actuelle : ");
if (now.hour() < 10) Serial.print("0");
Serial.print(now.hour());
Serial.print(":");
if (now.minute() < 10) Serial.print("0");
Serial.print(now.minute());
Serial.print(":");
if (now.second() < 10) Serial.print("0");
Serial.println(now.second());
mettreAJourHeuresSoleil(now);
afficherHorairesProgrammes();
// DĂ©termination de lâĂ©tat initial
bool finDeCourseFerme = digitalRead(finDeCourseFermePin);
bool finDeCourseOuvert = digitalRead(finDeCourseOuvertPin);
if (finDeCourseFerme == LOW) {
etatPorte = FERMEE;
Serial.println("Ătat initial : PORTE FERMĂE");
} else if (finDeCourseOuvert == LOW) {
etatPorte = OUVERTE;
Serial.println("Ătat initial : PORTE OUVERTE");
} else {
// Ni ouvert ni fermé
etatPorte = EN_MOUVEMENT_OUVERTURE; // ou un nouvel état INCONNU
Serial.println("Ătat initial : INCONNU (porte entre les deux)");
}
// Réduction de fréquence pour économie d'énergie
//CLKPR = 0x80;
//CLKPR = 0x01;
}
void loop() {
DateTime now = rtc.now();
int minutesNow = now.hour() * 60 + now.minute();
bool finDeCourseFerme = digitalRead(finDeCourseFermePin); // LOW = activé
bool finDeCourseOuvert = digitalRead(finDeCourseOuvertPin); // LOW = activé
modeManuelHoraire = (digitalRead(modeSwitchPin) == LOW);
// --- LIRE SI MANUEL OU AUTO ---
modeManuelHoraire = (digitalRead(modeSwitchPin) == LOW);
// Pour affichage :
if (modeManuel != dernierEtatModeManuel) {
Serial.print("Mode actuel : ");
Serial.println(modeManuel ? "MANUEL (boutons)" : "AUTOMATIQUE (horaires)");
dernierEtatModeManuel = modeManuel;
}
// --- CONTROLES MANUELS ---
if (demandeOuverture) {
demandeOuverture = false;
if (etatPorte == FERMEE) ouvrirPorte();
}
if (demandeFermeture) {
demandeFermeture = false;
if (etatPorte == OUVERTE) fermerPorte();
}
// --- FINS DE COURSE ---
if (etatPorte == EN_MOUVEMENT_FERMETURE && finDeCourseFerme == LOW) {
arreterMoteur();
etatPorte = FERMEE;
Serial.println("Porte fermée");
}
if (etatPorte == EN_MOUVEMENT_OUVERTURE && finDeCourseOuvert == LOW) {
arreterMoteur();
etatPorte = OUVERTE;
Serial.println("Porte ouverte");
}
// --- OUVERTURE ET FERMETURE AUTO ---
if (!modeManuelHoraire) { // Mode Auto si switch sur position Auto sinon bypass
int heureOuverture = modeManuelHoraire ? heureManuelleOuverture : sunriseTime;
int heureFermeture = modeManuelHoraire ? heureManuelleFermeture : sunsetTime;
PorteEtat etatVoulue;
if (minutesNow < heureOuverture) {
etatVoulue = FERMEE;
} else if (minutesNow < heureFermeture) {
etatVoulue = OUVERTE;
} else {
etatVoulue = FERMEE;
}
if ((etatPorte == FERMEE || etatPorte == OUVERTE) && etatPorte != etatVoulue) {
if (etatVoulue == OUVERTE) {
Serial.println("Ouverture auto");
ouvrirPorte();
} else {
Serial.println("Fermeture auto");
fermerPorte();
}
}
}
// --- MISE EN VEILLE ---
if (etatPorte == OUVERTE || etatPorte == FERMEE) { // Mise en veille si la porte n'est pas en mouvement
arreterMoteur();
desactiverRelais();
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}
// Sinon, on reste actif pour suivre le mouvement
delay(50); // Anti-rebond simple
}
void fermerPorte() {
activerRelais();
Serial.println("L289 alimenté");
digitalWrite(motorPinA, HIGH);
digitalWrite(motorPinB, LOW);
digitalWrite(enaPin, HIGH);
etatPorte = EN_MOUVEMENT_FERMETURE;
mettreAJourHeuresSoleil(rtc.now());
}
void ouvrirPorte() {
activerRelais();
Serial.println("L289 alimenté");
digitalWrite(motorPinA, LOW);
digitalWrite(motorPinB, HIGH);
digitalWrite(enaPin, HIGH);
etatPorte = EN_MOUVEMENT_OUVERTURE;
mettreAJourHeuresSoleil(rtc.now());
}
void arreterMoteur() {
digitalWrite(motorPinA, LOW);
digitalWrite(motorPinB, LOW);
digitalWrite(enaPin, LOW);
desactiverRelais();
Serial.println("L289 en veille");
}
void afficherHeureReadable(int totalMinutes) {
int h = totalMinutes / 60;
int m = totalMinutes % 60;
if (h < 10) Serial.print("0");
Serial.print(h);
Serial.print(":");
if (m < 10) Serial.print("0");
Serial.println(m);
}
void mettreAJourHeuresSoleil(DateTime now) {
int rise = soleil.sunrise(now.year(), now.month(), now.day(), true);
int set = soleil.sunset(now.year(), now.month(), now.day(), true);
sunriseTime = rise + offsetSunriseMinutes;
sunsetTime = set + offsetSunsetMinutes;
Serial.print("Lever du soleil a: ");
afficherHeureReadable(sunriseTime);
Serial.print("Coucher du soleil a: ");
afficherHeureReadable(sunsetTime);
}
void afficherHorairesProgrammes() {
Serial.print("Mode horaire : ");
Serial.println(modeManuelHoraire ? "MANUEL" : "AUTOMATIQUE");
Serial.print("Ouverture programmée à : ");
if (modeManuelHoraire) {
afficherHeureReadable(heureManuelleOuverture);
} else {
afficherHeureReadable(sunriseTime);
}
Serial.print("Fermeture programmée à : ");
if (modeManuelHoraire) {
afficherHeureReadable(heureManuelleFermeture);
} else {
afficherHeureReadable(sunsetTime);
}
}
void activerRelais() {
digitalWrite(relayPin, HIGH); // active relais (ou HIGH selon ton module)
delay(100); // petite temporisation pour que le relais se ferme bien
}
void desactiverRelais() {
digitalWrite(relayPin, LOW); // désactive le relais
delay(50);
}
void ouvrirPorteInterrupt() {
if (digitalRead(modeSwitchPin) == LOW) { // mode manuel
demandeOuverture = true;
}
}
void fermerPorteInterrupt() {
if (digitalRead(modeSwitchPin) == LOW) { // mode manuel
demandeFermeture = true;
}
}
void wakeUp() {
// Juste pour sortir de la veille, rien Ă faire ici
}