//additional useful feature,during brown out or sudden power loss (no power for a couple of seconds or maybe hours)
//it will continue incubating automatically
//plan is to store to eeprom the total time incubated when lowering 5v rail voltage is detected
//then at next power up, set startTime to rtc.now()-totalTime so it will continue coutning up
// calculate a date which is 7 days, 12 hours, 30 minutes, and 6 seconds into the future
// DateTime future (now + TimeSpan(7,12,30,6));
//startTime=rtc.now()-TimeSpan(days,hours,minutes,seconds)
//estimated time of "45deg. to 0deg. "= 5.5 seconds "-45deg. to -45 11s"
#include <Adafruit_Sensor.h>
#include <MsTimer2.h> //for our timing to manage time properly or multitasking
#include <LiquidCrystal_I2C.h>
#include <Button2.h>
#include "DHT.h"
#include "RTClib.h"
#include <Wire.h>
#include <EEPROM.h>
RTC_DS3231 rtc;
DateTime startTime1;
DateTime startTime2;
DateTime startTime3;
TimeSpan deltaTime1;
TimeSpan deltaTime2;
TimeSpan deltaTime3;
#define DHT1_PIN 23
#define DHT2_PIN 25
#define DHT3_PIN 27
#define DHTTYPE DHT11 // DHT 22 (AM2302), AM2321
#define TOTAL_SECONDS1 0 //0,1,2,3 address store long data here
#define TOTAL_SECONDS2 4 //4,5,6,7 address store long data here
#define TOTAL_SECONDS3 8 //8,9,10,11 address store long data here
#define BROWNOUT_FLAG1 1023
#define BROWNOUT_FLAG2 1022
#define BROWNOUT_FLAG3 1021
DHT dht1(DHT1_PIN, DHTTYPE);
DHT dht2(DHT2_PIN, DHTTYPE);
DHT dht3(DHT3_PIN, DHTTYPE);
/////////////////////////////////////////////////////////////////
#define TYPE1_BUTTON_PIN A0
#define TYPE2_BUTTON_PIN A1
#define TYPE3_BUTTON_PIN A2
#define TYPE1_ANGLE_PIN A4
#define TYPE2_ANGLE_PIN A5
#define TYPE3_ANGLE_PIN A6
#define VCC_ADC A15
/////////////////////////////////////////////////////////////////
#define TILT_DELAY_NEG45 11000
#define TILT_DELAY_0 5500
/////////////////////////////////////////////////////////////////
Button2 type1Button, type2Button, type3Button, type4Button;
/////////////////////////////////////////////////////////////////
LiquidCrystal_I2C lcd(0x27, 20, 4);
#define RELAY1_PIN 2
#define RELAY2_PIN 3
#define RELAY3_PIN 4
#define REL_TILT1_PIN 5
#define RELAY5_PIN 6
#define RELAY6_PIN 7
#define RELAY7_PIN 8
#define REL_TILT2_PIN 9
#define RELAY9_PIN 10
#define RELAY10_PIN 11
#define RELAY11_PIN 12
#define REL_TILT3_PIN 13
#define BUZZER_PIN 29
#define LED1R_PIN 41
#define LED2R_PIN 39
#define LED3R_PIN 37
#define LED1G_PIN 35
#define LED2G_PIN 33
#define LED3G_PIN 31
#define BUZZER_PIN 29
byte startedFlag1, startedFlag2, startedFlag3, finishFlag1, finishFlag2, finishFlag3;
volatile unsigned long timer1, timer2, loopStepTimer;
volatile unsigned long eggTiltTimer1, eggTiltTimer2, eggTiltTimer3;
bool toggler2, togglerA, togglerB, togglerC;
unsigned long secondsPassed;
byte displayMode, loopStep, tiltStepEgg1, tiltStepEgg2, tiltStepEgg3;
int tiltAngle1, tiltAngle2, tiltAngle3;
int prevDesiredAngle, prevDesiredAngle2, prevDesiredAngle3;
long totalSeconds1, totalSeconds2, totalSeconds3;
unsigned long currentSecond, currentSecond2, currentSecond3;
unsigned long previousSecond, previousSecond2, previousSecond3;
void timerIsr() { // this are interrupt service //countdown timers
//routine to turn provide a count down timer
//this will decrement every 1 millisecond
if (timer1)
timer1-- ; // Only decrement if non-zero !!!!!!!!!!!!
if (timer2)
timer2-- ;
if (eggTiltTimer1)
eggTiltTimer1-- ;
if (eggTiltTimer2)
eggTiltTimer2-- ;
if (eggTiltTimer3)
eggTiltTimer3-- ;
if (loopStepTimer)
loopStepTimer-- ;
}
void displayControl() {
switch (displayMode) {
case 0:
lcd.setCursor(0, 0);
lcd.print(F("Chicken Egg "));
lcd.setCursor(0, 1);
lcd.print(F("Temperature: ")); lcd.print(dht1.readTemperature());
lcd.print((char)223); lcd.print(F("C "));
lcd.setCursor(0, 2);
lcd.print(F("Humidity: ")); lcd.print(dht1.readHumidity()); lcd.print(F("% "));
lcd.setCursor(0, 3);
lcd.print(F("Time:"));
if (startedFlag1) {
byte days = deltaTime1.days();
byte hr = deltaTime1.hours();
byte min = deltaTime1.minutes();
byte sec = deltaTime1.seconds();
float hrDecimal = hr + min / 60.0;
if (days < 10) {
lcd.print(0);
}
lcd.print(days); lcd.print(F("d,"));
if (hr < 10) {
lcd.print(0);//print zero digit
}
lcd.print(hr);
lcd.print(F("h(21days)"));
}
break;
case 1:
lcd.setCursor(0, 0);
lcd.print(F("Duck Egg "));
lcd.setCursor(0, 1);
lcd.print(F("Temperature: ")); lcd.print(dht2.readTemperature());
lcd.print((char)223); lcd.print(F("C "));
lcd.setCursor(0, 2);
lcd.print(F("Humidity: ")); lcd.print(dht2.readHumidity()); lcd.print(F("% "));
lcd.setCursor(0, 3);
if (startedFlag2) {
lcd.print(F("Time: "));
TimeSpan deltaTime1 = rtc.now() - startTime2;
lcd.print(deltaTime1.days()); lcd.print(F("d,"));
// lcd.setCursor(12, 3);
byte hr = deltaTime1.hours();
byte min = deltaTime1.minutes();
byte sec = deltaTime1.seconds();
lcd.print(hr);
lcd.print(F("h(28days)"));
}
break;
case 2:
timer1 = 1000;
lcd.setCursor(0, 0);
lcd.print(F("Quail Egg"));
lcd.setCursor(0, 1);
lcd.print(F("Temperature: ")); lcd.print(dht3.readTemperature());
lcd.print((char)223); lcd.print(F("C "));
lcd.setCursor(0, 2);
lcd.print(F("Humidity: ")); lcd.print(dht3.readHumidity()); lcd.print(F("% "));
lcd.setCursor(0, 3);
if (startedFlag3) {
lcd.print(F("Time: "));
TimeSpan deltaTime1 = rtc.now() - startTime3;
lcd.print(deltaTime1.days()); lcd.print(F("d,"));
// lcd.setCursor(12, 3);
byte hr = deltaTime1.hours();
byte min = deltaTime1.minutes();
byte sec = deltaTime1.seconds();
lcd.print(hr);
lcd.print(F("h(18days)"));
}
break;
}
}
void setup() {
//secondsPassed = 72;
lcd.init(); // initialize the lcd
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 1);
lcd.print(F(" EGG INCUBATOR"));
delay(1000);
lcd.clear();
dht1.begin();
dht2.begin();
dht3.begin();
Serial.begin(115200);
rtc.begin();
MsTimer2::set(1, timerIsr); // 1ms period
MsTimer2::start();
pinMode(RELAY1_PIN, OUTPUT);
pinMode(RELAY2_PIN, OUTPUT);
pinMode(RELAY3_PIN, OUTPUT);
pinMode(REL_TILT1_PIN, OUTPUT);
pinMode(RELAY5_PIN, OUTPUT);
pinMode(RELAY6_PIN, OUTPUT);
pinMode(RELAY7_PIN, OUTPUT);
pinMode(REL_TILT2_PIN, OUTPUT);
pinMode(RELAY9_PIN, OUTPUT);
pinMode(RELAY10_PIN, OUTPUT);
pinMode(RELAY11_PIN, OUTPUT);
pinMode(REL_TILT3_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(BUZZER_PIN, HIGH); //active low si buzzer
pinMode(BUZZER_PIN, OUTPUT);
pinMode(LED1R_PIN, OUTPUT);
pinMode(LED2R_PIN, OUTPUT);
pinMode(LED3R_PIN, OUTPUT);
pinMode(LED1G_PIN, OUTPUT);
pinMode(LED2G_PIN, OUTPUT);
pinMode(LED3G_PIN, OUTPUT);
pinMode(TYPE1_ANGLE_PIN, INPUT_PULLUP);
pinMode(TYPE2_ANGLE_PIN, INPUT_PULLUP);
pinMode(TYPE3_ANGLE_PIN, INPUT_PULLUP);
type1Button.begin(TYPE1_BUTTON_PIN);
type2Button.begin(TYPE2_BUTTON_PIN);
type3Button.begin(TYPE3_BUTTON_PIN);
type4Button.begin(A3);
type1Button.setClickHandler(buttonHandler1);
// button.setLongClickHandler(handler); // this will only be called upon release
//type1Button.setLongClickDetectedHandler(buttonHandler1); // this will only be called upon detection
type1Button.setDoubleClickHandler(buttonHandler1);
type1Button.setTripleClickHandler(buttonHandler1);
type2Button.setClickHandler(buttonHandler2);
// button.setLongClickHandler(handler); // this will only be called upon release
//type1Button.setLongClickDetectedHandler(buttonHandler1); // this will only be called upon detection
type2Button.setDoubleClickHandler(buttonHandler2);
type2Button.setTripleClickHandler(buttonHandler2);
type3Button.setClickHandler(buttonHandler3);
// button.setLongClickHandler(handler); // this will only be called upon release
//type1Button.setLongClickDetectedHandler(buttonHandler1); // this will only be called upon detection
type3Button.setDoubleClickHandler(buttonHandler3);
type3Button.setTripleClickHandler(buttonHandler3);
type4Button.setClickHandler(buttonHandler4);
type4Button.setDoubleClickHandler(buttonHandler4);
type4Button.setTripleClickHandler(buttonHandler4);
}
void loop() {
loopSetup();
type1Button.loop();
type2Button.loop();
type3Button.loop();
type4Button.loop();
tiltEggAlgorithm1(tiltAngle1);
if (!timer1) {
timer1 = 1000; // execute this every second
displayControl();
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$//
if ( startedFlag1 ) {
if (dht1.readTemperature() >= 37.9) {
digitalWrite(RELAY1_PIN, LOW);
digitalWrite(RELAY2_PIN, LOW);
if (dht1.readHumidity() >= 55 && dht1.readHumidity() <= 65) {
digitalWrite(RELAY3_PIN, HIGH); //fan on
}
else {
digitalWrite(RELAY3_PIN, LOW); //fan off
}
}
else {
digitalWrite(RELAY1_PIN, HIGH);
digitalWrite(RELAY2_PIN, HIGH);
digitalWrite(RELAY3_PIN, LOW); //fan off
}
digitalWrite(LED1G_PIN, 1);//status led
digitalWrite(LED1R_PIN, 0);
digitalWrite(BUZZER_PIN, HIGH);//turn off buzzer
deltaTime1 = rtc.now() - startTime1;
totalSeconds1 = deltaTime1.totalseconds();
eggTiltControl1(totalSeconds1);//fucntion which decides when to tilt
if (deltaTime1.days() >= 21) {
deltaTime1 = 0;
finishFlag1 = 1;
startedFlag1 = 0;
timer1 = 1000;
lcd.clear();
}
else {
finishFlag1 = 0;
}
}
else {
digitalWrite(RELAY1_PIN, LOW); //off all
digitalWrite(RELAY2_PIN, LOW);
digitalWrite(RELAY3_PIN, LOW);
digitalWrite(LED1G_PIN, 0);//status led
if (finishFlag1) { //blink red led
digitalWrite(LED1R_PIN, !digitalRead(LED1R_PIN));
digitalWrite(BUZZER_PIN, !digitalRead(BUZZER_PIN));
}
else {
digitalWrite(LED1R_PIN, 1);
digitalWrite(BUZZER_PIN, HIGH); //active low-buzzer
}
}
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$//
if ( startedFlag2 ) {
if (dht2.readTemperature() >= 38.6) {
digitalWrite(RELAY5_PIN, LOW);
digitalWrite(RELAY6_PIN, LOW);
if (dht2.readHumidity() >= 55 && dht2.readHumidity() <= 60) {
digitalWrite(RELAY7_PIN, HIGH); //fan on
}
else {
digitalWrite(RELAY7_PIN, LOW); //fan off
}
}
else {
digitalWrite(RELAY5_PIN, HIGH);
digitalWrite(RELAY6_PIN, HIGH);
digitalWrite(RELAY7_PIN, LOW); //fan off
}
digitalWrite(LED2G_PIN, 1);//status led
digitalWrite(LED2R_PIN, 0);
}
else {
digitalWrite(RELAY5_PIN, LOW); //off all
digitalWrite(RELAY6_PIN, LOW);
digitalWrite(RELAY7_PIN, LOW);
digitalWrite(LED2G_PIN, 0);//status led
digitalWrite(LED2R_PIN, 1);
}
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$//
if ( startedFlag3 ) {
if (dht3.readTemperature() >= 37.3) {
digitalWrite(RELAY9_PIN, LOW);
digitalWrite(RELAY10_PIN, LOW);
if (dht3.readHumidity() >= 60 && dht3.readHumidity() <= 70) {
digitalWrite(RELAY11_PIN, HIGH); //fan on
}
else {
digitalWrite(RELAY11_PIN, LOW); //fan off
}
}
else {
digitalWrite(RELAY9_PIN, HIGH);
digitalWrite(RELAY10_PIN, HIGH);
digitalWrite(RELAY11_PIN, LOW); //fan off
}
if (finishFlag3) {
digitalWrite(LED3G_PIN, !digitalRead(LED3G_PIN));
}
else {
digitalWrite(LED3G_PIN, 1);//status led
}
digitalWrite(LED3R_PIN, 0);
}
else {
digitalWrite(RELAY9_PIN, LOW); //off all
digitalWrite(RELAY10_PIN, LOW);
digitalWrite(RELAY11_PIN, LOW);
digitalWrite(LED3G_PIN, LOW);//status led
digitalWrite(LED3R_PIN, HIGH);
}
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$//
eggTiltControl1(secondsPassed);
}
}
void buttonHandler1(Button2 & btn) {
switch (btn.getType()) {
case single_click:
lcd.clear();
displayMode = 0;
break;
case double_click://start incubating
if (!startedFlag1) {
startTime1 = rtc.now();
timer1 = 2000;//long delay to give time disPLAYING notification
lcd.clear();
lcd.setCursor(0, 1);
lcd.print(F(" STARTING EGG "));
lcd.setCursor(0, 2);
lcd.print(F(" INCUBATION "));
lcd.setCursor(0, 3);
lcd.print(F(" "));
startedFlag1 = 1;
displayMode = 0;
}
break;
case triple_click://stop incubating
if (startedFlag1) {
timer1 = 2000;//long delay to give time disPLAYING notification
lcd.clear();
lcd.setCursor(0, 1);
lcd.print(F(" STOPPING EGG "));
lcd.setCursor(0, 2);
lcd.print(F(" INCUBATION "));
lcd.setCursor(0, 3);
lcd.print(F(" "));
tiltAngle1 = 0;
startedFlag1 = 0;
displayMode = 0;
}
break;
}
}
void buttonHandler2(Button2 & btn) {
switch (btn.getType()) {
case single_click:
lcd.clear();
displayMode = 1;
break;
case double_click://start incubating
if (!startedFlag2) {
startTime2 = rtc.now();
timer1 = 2000;//long delay to give time disPLAYING notification
lcd.clear();
lcd.setCursor(0, 1);
lcd.print(F(" STARTING EGG "));
lcd.setCursor(0, 2);
lcd.print(F(" INCUBATION "));
lcd.setCursor(0, 3);
lcd.print(F(" "));
startedFlag2 = 1;
displayMode = 1;
}
break;
case triple_click://stop incubating
if (startedFlag2) {
timer1 = 2000;//long delay to give time disPLAYING notification
lcd.clear();
lcd.setCursor(0, 1);
lcd.print(F(" STOPPING EGG "));
lcd.setCursor(0, 2);
lcd.print(F(" INCUBATION "));
lcd.setCursor(0, 3);
lcd.print(F(" "));
tiltAngle3 = 0;
displayMode = 1;
startedFlag2 = 0;
}
break;
}
}
void buttonHandler3(Button2 & btn) {
switch (btn.getType()) {
case single_click:
lcd.clear();
displayMode = 2;
break;
case double_click://start incubating
if (!startedFlag3) {
startTime3 = rtc.now();
timer1 = 2000;//long delay to give time disPLAYING notification
lcd.clear();
lcd.setCursor(0, 1);
lcd.print(F(" STARTING EGG "));
lcd.setCursor(0, 2);
lcd.print(F(" INCUBATION "));
lcd.setCursor(0, 3);
lcd.print(F(" "));
tiltAngle3 = 0;
startedFlag3 = 1;
displayMode = 2;
}
break;
case triple_click://stop incubating
if (startedFlag3) {
timer1 = 2000;//long delay to give time disPLAYING notification
lcd.clear();
lcd.setCursor(0, 1);
lcd.print(F(" STOPPING EGG "));
lcd.setCursor(0, 2);
lcd.print(F(" INCUBATION "));
lcd.setCursor(0, 3);
lcd.print(F(" "));
displayMode = 2;
startedFlag3 = 0;
}
break;
}
}
void eggTiltControl1(const unsigned long totalSeconds) {
float days = totalSeconds / 3600 / 24;
if (days > 18 ) { //go back to flat position
tiltAngle1 = 0;
Serial.println("0 deg");
}
if (days > 3 && days < 19 ) {
currentSecond = totalSeconds;
if (currentSecond - previousSecond >= 17280) { //4.8 hours 1 day
previousSecond = currentSecond;//17280seconds=4.8h
toggler2 = !toggler2;
if (toggler2) {
Serial.println("45 deg");
tiltAngle1 = 45;
}
else {
tiltAngle1 = -45;
Serial.println("-45 deg");
}
}
}
}
void buttonHandler4(Button2 & btn) {
switch (btn.getType()) {
case single_click:
//TimeSpan(days,hours,minutes,seconds)
//startTime1 = startTime1 - TimeSpan(0, 4, 47, 0);//advance the time
startTime1 = startTime1 - TimeSpan(0, 4, 49, 0);//advance the time
//secondsPassed += 1641600;
//Serial.println(F("ADD"));
//startTime1 = startTime1 - TimeSpan(1728000);//advance the time using totalSeconds
//eggTiltControl1(/totalHr);
break;
case double_click:
//TimeSpan(days,hours,minutes,seconds)
startTime1 = startTime1 - TimeSpan(2, 0, 0, 0);//advance the time
//tiltAngle1=45;
break;
}
}
void tiltEggAlgorithm1(const int desiredAngle) {
tiltStepEgg1;
prevDesiredAngle ;
int delayValue;
if (desiredAngle != prevDesiredAngle ) {
tiltStepEgg1 = 0; //change detection
digitalWrite(REL_TILT1_PIN, HIGH);
//eggTiltTimer=1000; //add delay or else it will turn off immideately becuase its in 45 degree position its already in
}
prevDesiredAngle = desiredAngle ;
switch (tiltStepEgg1) {
case 0:
if (digitalRead(TYPE1_ANGLE_PIN) == LOW) { //if 45 deg is reached
if (desiredAngle == 45) delayValue = 0;
if (desiredAngle == 0) delayValue = TILT_DELAY_0;
if (desiredAngle == -45) delayValue = TILT_DELAY_NEG45;
tiltStepEgg1 = 1;
eggTiltTimer1 = delayValue;
}
break;
case 1:
if (!eggTiltTimer1) {
digitalWrite(REL_TILT1_PIN, LOW); //stop Motor
tiltStepEgg1 = 2;
}
break;
}
}
void loopSetup() {
//this will go to flat position on firs boot
switch (loopStep) {
case 0:
tiltAngle1 = 45;
loopStepTimer = 1000;
loopStep = 1;
break;
case 1:
if (!loopStepTimer) {
loopStep = 2;//exit
tiltAngle1 = 0; // flat position
}
break;
}
}