/*
===========================================================================
Hayfeeder
===========================================================================
*/
/* Connections
Arduino | RTC | Transistor | Ext Battery Package | Solenoid
--------------------------------------------------------------
SDA | SDA | | |
SCL | SLC | | |
VCC | VCC | | |
GND | GND | | |
D2 | SQW | | |
D13 | | BASE | |
| | Emitter | - |
| | Collector | | - (Hatch 1)
D12 | | BASE | |
| | Emitter | - |
| | Collector | | - (Hatch 2)
Arduino Mini Pro 5V --> Max 12VDC connected to RAW and GND. Not to VCC!
Transitor flat side up, left leg --> emitter, right leg --> collector
Power mosfet -> Gate = Base, Drain = Collector, Source = Emitter
Hatch 1 -> Blue
Hatch 2 -> Green
Hatch 3 -> Yellow
Hatch 4 -> White
Improvements for next time:
Check witch alarm's active, then choose next_Hatch
Make a new if-loop for next_Hatch resetting
Maybe make a new variable for number of hatches in use. Use this variable for hatch resetting.
*/
#include "RTClib.h" // DS3231 library
#include <avr/sleep.h> // AVR library for controlling the sleep modes
const int alarmPin = 2; // The number of the pin for monitoring alarm status on DS3231, (interrupt pin).
const int transistor_1_Pin = 13; // transistor for hatch 1
const int transistor_2_Pin = 12; // transistor for hatch 2
// Varibale for controlling which hatch is opening and how long it should be open
int next_Hatch = 1; // If time of day is beyond 1. alarm, next_Hatch = 2, else if time is beyond 2. alarm, next_Hatch = 1
int hatch_Time = 2000; // miliseconds for hatch to hold open
// Setting time for action to happen (1 minute delay)
int alarm_HOUR = 12;
int alarm_MINUTE = 59;
int alarm_HOUR_2 = 16;
int alarm_MINUTE_2 = 59;
// Making sure nothing happens during startup. Only when isAlarm = true.
bool isAlarm = false;
RTC_DS3231 rtc;
void setup() {
delay(2000); // delaying startup by 2 seconds
Serial.begin(9600); // Start serial port for monitoring
pinMode(alarmPin, INPUT_PULLUP); // Set alarm pin as pullup
pinMode(transistor_1_Pin, OUTPUT);
pinMode(transistor_2_Pin, OUTPUT);
// pinMode(LED_BUILTIN, OUTPUT); // just for testing purpose with built in led
if (!rtc.begin()) {
Serial.println("Couldn't find RTC, bad connection somewhere!");
Serial.flush();
abort();
}
// If set time is required
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // To compiled time <-- syntax description
//rtc.adjust(DateTime(2020, 7, 3, 20, 0, 0)); // Or explicitly, e.g. July 3, 2020 at 8pm
// Disable analog IO
ADCSRA = 0;
// Disable and clear both alarms
rtc.disableAlarm(1);
rtc.disableAlarm(2);
rtc.clearAlarm(1);
rtc.clearAlarm(2);
rtc.writeSqwPinMode(DS3231_OFF); // Place SQW pin into alarm interrupt mode
isAlarm = false; // set to false to make sure nothing happens during startup.
Serial.println("All good, cya when batteries dead");
// Serial.end(); // Only want to use monitoring during setup to see if all's good.
}
void loop() {
if (isAlarm) {
openDoor(); // Runs the action
printDate(); // Just for testing
// Serial.println(next_Hatch); // Just for testing ++ command
}
// Get current time and set alarm to a time to wake
DateTime now = rtc.now(); // Get current time
// rtc.setAlarm1(now + TimeSpan(0, 0, 0, 10), DS3231_A1_Second); // In 10 seconds
rtc.setAlarm1(DateTime(2022, 6, 25, alarm_HOUR, alarm_MINUTE, 0), DS3231_A1_Hour); // alarm set explicity, every day at (alarm_HOUR : alarm_MINUTE)
rtc.setAlarm2(DateTime(2022, 6, 25, alarm_HOUR_2, alarm_MINUTE_2,0), DS3231_A2_Hour); // alarm set explicity, every day at (alarm_HOUR : alarm_MINUTE)
enterSleep(); // Go to sleep
}
void enterSleep() {
sleep_enable(); // Enabling sleep mode
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Setting the sleep mode, in this case full sleep
// MCUCR = bit(BODS) | bit(BODSE); // Turn of Brown Out Detection (low voltage) only works for ATmega48PA/88PA/168PA/328P
// MCUCR = bit(BODS); // The BODS bit is automatically cleared after three clock cycles so we better get on with it
noInterrupts(); // Disable interrupts
attachInterrupt(digitalPinToInterrupt(alarmPin), alarm_ISR, LOW);
Serial.println("I'm tired, going to bed now!"); // Print message to serial monitor
Serial.flush(); // Ensure all characters are sent to the serial monitor
interrupts(); // Allow interrupts again
sleep_cpu(); // Enter sleep mode
/* The program will continue from here when it wakes */
if (!isAlarm) {
isAlarm = true; // make if statement come true in void loop
}
// Disable and clear alarm
rtc.disableAlarm(1);
rtc.clearAlarm(1);
rtc.disableAlarm(2);
rtc.clearAlarm(2);
Serial.println("Sleeping beauty's awake!"); // Print message to show we're back, just for testing purposes
}
void alarm_ISR() {
// This runs when SQW pin is low. It will wake up the µController
sleep_disable(); // Disable sleep mode
detachInterrupt(digitalPinToInterrupt(alarmPin)); // Detach the interrupt to stop it firing
}
void openDoor() {
if(next_Hatch == 1){
digitalWrite(transistor_1_Pin, HIGH);
delay(hatch_Time);
digitalWrite(transistor_1_Pin, LOW);
}
if(next_Hatch == 2){
digitalWrite(transistor_2_Pin, HIGH);
delay(hatch_Time);
digitalWrite(transistor_2_Pin, LOW);
next_Hatch = 0; // Should only be resett in the last if-loop, if more than 2 hatches, move line to last if loop
}
++next_Hatch;
}
// just for testing purposes, prints the date and time in serial monitor
void printDate() {
DateTime now = rtc.now();
Serial.print(now.year(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.day(), DEC);
Serial.print("--");
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.println();
}