Here's the code
#include <EEPROM.h> //Library for EEPROM
#include <DS3231.h> //Library for temp sensor in clock
#include <Wire.h> //Library for communication to RTC and display.
#include <WireRtcLib.h> //Library for the real time clock.
#include <Adafruit_SSD1306.h> // Display driver.
Adafruit_SSD1306 display(4); // NO CLUE what this does.
WireRtcLib::tm* t; // I think this desclares the structure "t" to contain all the elements of time.
WireRtcLib rtc; // CLUE, anyone? Oh well who cares, it's necessary for the realtime clock.
const bool TestFastMode = true; // If TRUE, a "minute" will elapse in 1 second for testing.
const int Timeout = 120; // Minutes until unit allows itself to shut down, which also kills video.
const int buttonPin = 7;
const int DVRRelay = 6;
const int HoldRelay = 5;
const int DoorPin = 4;
const int ACCPin = 3;
int LastShownScreen = 0;
unsigned long minuteselapsed;
bool BatteryDead = false;
unsigned long TargetMinutes;
unsigned long TimeOfLastDoororACC = 0;
void setup() {
//Hold self-power on, in case doors shut.
pinMode(HoldRelay, OUTPUT);
digitalWrite(HoldRelay, LOW); //LOW = On. HIGH = Off (ON HERE)
//Set up the button.
pinMode(buttonPin, INPUT);
digitalWrite(buttonPin, HIGH); // Activates the internal resistor so no external resistor needed. LOW shall represent a pushed state.
//set up the DVR pin.
pinMode(DVRRelay, OUTPUT);
//And the two inputs.
pinMode(ACCPin, INPUT);
pinMode(DoorPin, INPUT);
Serial.begin(9600);
Wire.begin();
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3C (for the 128x64)
display.clearDisplay();
rtc.begin();
t = rtc.getTime();
if (int(t->wday) == 1) {
BatteryDead = true;
TargetMinutes = 0;
EEPROM.put(0, TargetMinutes);
}
EEPROM.get(0, TargetMinutes);
Serial.print("TargetMinutes=");
Serial.print(TargetMinutes);
}
void loop() {
checktoreset(); // May set the clock way back if a lot of time has passed.
int minutesleft = 0;
if (TestFastMode == true) { // Uses seconds for minutes, and minutes for hours, for testing purposes.
minuteselapsed = int(t->sec) + (int(t->min) * 60);
}
else {
minuteselapsed = int(t->min) + (int(t->hour) * 60);
}
if (TimeOfLastDoororACC == 0) {
TimeOfLastDoororACC = minuteselapsed;
}
if (digitalRead(ACCPin) == LOW || digitalRead(DoorPin) == LOW) {
//Note that LOW = Active.
TimeOfLastDoororACC = minuteselapsed;
}
else if (minuteselapsed > TimeOfLastDoororACC + Timeout) {
Serial.print("Turning off self and DVR.");
digitalWrite(DVRRelay, HIGH); //LOW = On. HIGH = Off (OFF HERE)
digitalWrite(HoldRelay, HIGH); //LOW = On. HIGH = Off (OFF HERE)
}
if (TargetMinutes > 0) {
t = rtc.getTime();
if (minuteselapsed >= TargetMinutes) {
//TIME WITHOUT RECORDING IS NOW EXPIRING. Recording will be re-enabled.
TargetMinutes = 0;
resettime();
//Write zero to eeprom as TargetMinutes. Recording enabled.
EEPROM.put(0, TargetMinutes);
}
}
if (minuteselapsed <= TargetMinutes) {
minutesleft = TargetMinutes - minuteselapsed;
}
if (buttonbefore(50) == true) {
bool changed = false;
if (minutesleft == 0) {
minutesleft = 30;
changed = true;
}
showstatus(minutesleft);
while (buttonbefore(3000) == true) { //Does nothing unless a button is pushed within 3 seconds.
Serial.print("button pushed");
if (minutesleft < 30) {
minutesleft = 30;
}
else if (minutesleft < 60) {
minutesleft = 60;
}
else if (minutesleft < 90) {
minutesleft = 90;
}
else if (minutesleft < 120) {
minutesleft = 120;
}
else {
minutesleft = 0;
}
changed = true;
TargetMinutes = minutesleft;
showstatus(minutesleft);
}
if (changed == true) {
//reset the clock
resettime();
TargetMinutes = minutesleft;
//write TargetMinutes to eeprom.
EEPROM.put(0, TargetMinutes);
}
}
if (minuteselapsed < TargetMinutes) {
if (LastShownScreen != 3) {
LastShownScreen = 3;
Serial.println("Showing Video OFF");
display.clearDisplay();
//display.drawBitmap(0, 0, NowOff_bits, 128, 64, 1); //Commented out for brevity in a forum post.
display.display();
digitalWrite(DVRRelay, HIGH); //LOW = On. HIGH = Off (OFF HERE)
}
}
else {
if (LastShownScreen != 2) {
LastShownScreen = 2;
Serial.println("Blanking Screen");
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
if (BatteryDead) {
display.setCursor(0, 9);
display.println(" REPLACE CLOCK");
display.setCursor(0, 24);
display.println(" BATTERY");
BatteryDead = false; // This is a lie, but it prevents the message from appearing more than once per powerup.
}
display.display();
digitalWrite(DVRRelay, LOW); //LOW = On. HIGH = Off (ON HERE)
}
}
serialshowstuff();
//Test whether it has timed out.
}
void serialshowstuff() {
//Removed for brevity in a forum post.
}
void checktoreset() {
//Not super critical, but sets the clock back to January 1, 2000 if it's not already Jan 1. This way we're only dealing with hours and minutes.
static long counter = 50000;
//Occurs once upon reset, then every 41 minutes or so.
if (counter >= 50000) {
counter = 0;
if (t->mday > 1 || t->mon > 1 || t->year > 0) {
//More than 24 hours have elapsed. FAR EXPIRED.
Serial.print("Resetting Clock");
resettime();
t = rtc.getTime();
TargetMinutes = 0;
//Write zero to eeprom as TargetMinutes. Recording enabled.
EEPROM.put(0, TargetMinutes);
}
}
counter = counter + 1;
}
bool buttonbefore(int ms) {
static bool WasPushed = false;
//ms = at least 50 milliseconds.
//Returns true if a button is pushed or false if milliseconds elapses.
//To qualify, the button must be "unpushed" the moment before.
int count = ms / 50;
for (int x = 0; x < count; x++) {
delay(50);
if (digitalRead(buttonPin) == LOW) {
//Note that LOW = Active
if (WasPushed == false) {
WasPushed = true;
return true;
}
}
else if (WasPushed == true) {
WasPushed = false;
}
}
return false;
}
void showstatus(int minutesleft) {
//This is either "Recording is OFF until..." or "Recording is now ON".
LastShownScreen = 4;
display.clearDisplay();
if (minutesleft == 0) {
// display.drawBitmap(0, 0, NowOn_bits, 128, 64, 1); //Commented out for brevity in a forum post.
}
else {
//display.drawBitmap(0, 0, OffUntil_bits, 128, 64, 1); //Commented out for brevity in a forum post.
showMinutes(minutesleft);
}
display.display();
//wait for input or timeout.
}
void showMinutes (int i) {
display.fillRect(0, 15, 128, 20, 0);
int x = 39; //Reference point
if (i < 100 && i >= 10) {
x = x - 7;
}
if (i > 99) {
showDigit((i % 1000) / 100, x);
}
if (i > 9) {
x = x + 15;
showDigit((i % 100) / 10, x);
}
x = x + 15;
showDigit((i % 10), x);
}
void showDigit (int i, int x)
{
// Code removed for brevity in a forum post.
}
void resettime() { //Resets the time to Jan 1, 2000, which was a Saturday. Actual time doesn't matter to this app, but elapsed time does.
t = rtc.getTime();
t->sec = 0;
t->min = 0;
t->hour = 0;
t->mday = 1;
t->mon = 1;
t->year = 0;
t->wday = 2;
rtc.setTime(t);
}