#include <Wire.h>
#include <RTClib.h>
#include <Toggle.h> // https://github.com/Dlloydev/Toggle
#include <Stepper.h>
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h> // i2c expander i/o class header
// les constantes
const byte pinB1 = 2;
const byte pinB2 = 3;
const byte pinB3 = 4;
const byte pinModeConfiguration = 13;
const int pasParTour = 200;
const char * jours[] = {"Dimanche", "Lundi ", "Mardi ", "Mercredi", "Jeudi ", "Vendredi", "Samedi "};
const byte nbJours = sizeof jours / sizeof * jours;
const unsigned long periodUnPas = 5; // un pas toutes les 5ms quand le moteur est activé
const unsigned long dureeNourriture = 5000;
const int nbCols = 16;
const int nbLignes = 2;
// les variables
enum {uneFoisJour, deuxFoisJour, uneFoisSemaine, modeConfiguration } mode = uneFoisJour;
byte heureAlarme1 = 12; // 12h
byte heureAlarme2 = 19; // 12h
byte heureAlarme3 = 0; // 0h
byte jourAlarme3 = 0; // dimanche
bool moteurActif = false;
unsigned long chronoFeeder;
unsigned long chronoPaP;
long nbPas = 1; // influe sur la vitesse perçue
// les instances
hd44780_I2Cexp lcd;
Stepper moteur(pasParTour, 8, 9, 10, 11);
RTC_DS1307 rtc; // pins A4 et A5 pour SDA et SCL
Toggle b1(pinB1);
Toggle b2(pinB2);
Toggle b3(pinB3);
void debutDistribution() {
Serial.println("activation moteur");
moteurActif = true;
chronoPaP = chronoFeeder = millis();
}
void finDistribution() {
Serial.println("arrêt moteur");
nbPas = -nbPas; // on tournera dans l'autre sens la prochain fois
moteurActif = false;
}
void mode1x() {
Serial.println("Mode une fois par jour");
lcd.setCursor(0, 1);
lcd.print("journalier x 1 ");
mode = uneFoisJour;
}
void mode2x() {
Serial.println("Mode deux fois par jour");
lcd.setCursor(0, 1);
lcd.print("journalier x 2 ");
mode = deuxFoisJour;
}
void majAlarme3() {
lcd.setCursor(0, 1);
for (byte i = 0; i < nbCols; i++) lcd.write(' '); // efface la ligne
lcd.setCursor(0, 1);
lcd.print(jours[jourAlarme3]);
lcd.setCursor(13, 1);
if (heureAlarme3 < 10) lcd.print('0');
lcd.print(heureAlarme3);
lcd.print('h');
}
void finParametrage() {
digitalWrite(pinModeConfiguration, LOW);
Serial.print("Mode une fois par semaine, le ");
lcd.setCursor(0, 1);
lcd.print("hebdomadaire x 1");
Serial.print(jours[jourAlarme3]);
Serial.print(" à ");
Serial.print(heureAlarme3);
Serial.println(" h.");
mode = uneFoisSemaine;
}
void debutParametrage() {
Serial.println("Mode Configuration");
majAlarme3();
mode = modeConfiguration;
}
void majHeure() {
static DateTime datePrecente(2000, 1, 1, 0, 0, 0);
DateTime maintenant = rtc.now();
if (maintenant.hour() != datePrecente.hour()) {
lcd.setCursor(0, 0);
if (maintenant.hour() < 10) lcd.print(' ');
lcd.print(maintenant.hour());
lcd.print(':');
}
if (maintenant.minute() != datePrecente.minute()) {
lcd.setCursor(3, 0);
if (maintenant.minute() < 10) lcd.print('0');
lcd.print(maintenant.minute());
lcd.print(':');
}
if (maintenant.second() != datePrecente.second()) {
lcd.setCursor(6, 0);
if (maintenant.second() < 10) lcd.print('0');
lcd.print(maintenant.second());
}
if (maintenant.day() != datePrecente.day()) {
lcd.setCursor(11, 0);
if (maintenant.day() < 10) lcd.print(' ');
lcd.print(maintenant.day());
lcd.print('/');
}
if (maintenant.month() != datePrecente.month()) {
lcd.setCursor(14, 0);
if (maintenant.month() < 10) lcd.print('0');
lcd.print(maintenant.month());
}
datePrecente = maintenant;
}
void setup() {
pinMode(pinModeConfiguration, OUTPUT);
b1.begin(pinB1);
b2.begin(pinB2);
b3.begin(pinB3);
Serial.begin(115200);
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
abort();
}
if (! rtc.isrunning()) {
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
int lcdAbsent = lcd.begin(nbCols, nbLignes);
if (lcdAbsent) {
Serial.print(" initialisation LCD - erreur ");
Serial.println(lcdAbsent);
hd44780::fatalError(lcdAbsent);
}
mode1x();
}
void loop() {
majHeure();
// gestion du moteur
if (moteurActif) {
if (millis() - chronoFeeder >= dureeNourriture) finDistribution();
else if (millis() - chronoPaP >= periodUnPas) {
chronoPaP += periodUnPas;
moteur.step(nbPas);
}
}
// gestion des boutons
b1.poll();
b2.poll();
b3.poll();
if (mode != modeConfiguration) {
static unsigned long debutChrono;
if (b1.onPress()) debutChrono = millis();
if (b1.isPressed() && (millis() - debutChrono >= 3000)) digitalWrite(pinModeConfiguration, HIGH);
if (b1.onRelease()) {
if (millis() - debutChrono >= 3000)
debutParametrage();
else
mode1x();
}
if (b2.onRelease()) mode2x();
if (b3.onRelease()) if (moteurActif) finDistribution(); else debutDistribution();
} else {
if (b1.onRelease()) {
jourAlarme3 = (jourAlarme3 + 1) % nbJours;
Serial.print("Jour Alarme hebdomadaire : "); Serial.println(jours[jourAlarme3]);
majAlarme3();
}
if (b2.onRelease()) {
heureAlarme3 = (heureAlarme3 + 1) % 24;
Serial.print("Heure Alarme hebdomadaire : "); Serial.print(heureAlarme3); Serial.println(" h.");
majAlarme3();
}
if (b3.onRelease()) finParametrage();
}
// gestion des alarmes
DateTime maintenant = rtc.now();
switch (mode) {
case uneFoisJour:
if (!moteurActif &&
(maintenant.hour() == heureAlarme1) && (maintenant.minute() == 0) && (maintenant.second() == 0)) {
debutDistribution();
}
break;
case deuxFoisJour:
if (!moteurActif &&
(maintenant.hour() == heureAlarme1) && (maintenant.minute() == 0) && (maintenant.second() == 0)) {
debutDistribution();
}
if (!moteurActif &&
(maintenant.hour() == heureAlarme2) && (maintenant.minute() == 0) && (maintenant.second() == 0)) {
debutDistribution();
}
break;
case uneFoisSemaine:
if (!moteurActif &&
(maintenant.dayOfTheWeek() == jourAlarme3) &&
(maintenant.hour() == heureAlarme3) && (maintenant.minute() == 0) && (maintenant.second() == 0)) {
debutDistribution();
}
break;
default: break;
}
}