/*
Based on a project by Jason Poel Smith
https://www.allaboutcircuits.com/projects/convert-a-vintage-thermostat-into-a-modern-energy-saver/
*/

#include <Servo.h>     //include libraries
Servo myservo;

int defaultTemperature = 70;     //Default temperature that will be adjusted throughout the week

//Day and Time Variables
int dayTimeArray [7][24]=     
{     

//Sunday Array (Day 0)
  {
  0,     // 12:00 am (hour 0)
  0,     // 1:00 am  (hour 1)
  0,     // 2:00 am  (hour 2)
  0,     // 3:00 am  (hour 3)
  0,     // 4:00 am  (hour 4)
  0,     // 5:00 am  (hour 5)
  0,     // 6:00 am  (hour 6)
  0,     // 7:00 am  (hour 7)
  0,     // 8:00 am  (hour 8)
  0,     // 9:00 am  (hour 9)
  0,     // 10:00 am (hour 10)
  0,     // 11:00 am (hour 11)
  0,     // 12:00 pm (hour 12)
  0,     // 1:00 pm  (hour 13)
  0,     // 2:00 pm  (hour 14)
  0,     // 3:00 pm  (hour 15)
  0,     // 4:00 pm  (hour 16)
  0,     // 5:00 pm  (hour 17)
  0,     // 6:00 pm  (hour 18)
  0,     // 7:00 pm  (hour 19)
  0,     // 8:00 pm  (hour 20)
  0,     // 9:00 pm  (hour 21)
  0,     // 10:00 pm (hour 22)
  0      // 11:00 pm (hour 23)
  },

//Monday Array (Day 1)
  {
  0,     // 12:00 am (hour 0)
  0,     // 1:00 am  (hour 1)
  0,     // 2:00 am  (hour 2)
  0,     // 3:00 am  (hour 3)
  0,     // 4:00 am  (hour 4)
  0,     // 5:00 am  (hour 5)
  0,     // 6:00 am  (hour 6)
  0,     // 7:00 am  (hour 7)
  0,     // 8:00 am  (hour 8)
  0,     // 9:00 am  (hour 9)
  0,     // 10:00 am (hour 10)
  0,     // 11:00 am (hour 11)
  0,     // 12:00 pm (hour 12)
  0,     // 1:00 pm  (hour 13)
  0,     // 2:00 pm  (hour 14)
  0,     // 3:00 pm  (hour 15)
  0,     // 4:00 pm  (hour 16)
  0,     // 5:00 pm  (hour 17)
  0,     // 6:00 pm  (hour 18)
  0,     // 7:00 pm  (hour 19)
  0,     // 8:00 pm  (hour 20)
  0,     // 9:00 pm  (hour 21)
  0,     // 10:00 pm (hour 22)
  0      // 11:00 pm (hour 23)
  },

//Tuesday Array (Day 2)  
  {
  0,     // 12:00 am (hour 0)
  0,     // 1:00 am  (hour 1)
  0,     // 2:00 am  (hour 2)
  0,     // 3:00 am  (hour 3)
  0,     // 4:00 am  (hour 4)
  0,     // 5:00 am  (hour 5)
  0,     // 6:00 am  (hour 6)
  0,     // 7:00 am  (hour 7)
  0,     // 8:00 am  (hour 8)
  0,     // 9:00 am  (hour 9)
  0,     // 10:00 am (hour 10)
  0,     // 11:00 am (hour 11)
  0,     // 12:00 pm (hour 12)
  0,     // 1:00 pm  (hour 13)
  0,     // 2:00 pm  (hour 14)
  0,     // 3:00 pm  (hour 15)
  0,     // 4:00 pm  (hour 16)
  0,     // 5:00 pm  (hour 17)
  0,     // 6:00 pm  (hour 18)
  0,     // 7:00 pm  (hour 19)
  0,     // 8:00 pm  (hour 20)
  0,     // 9:00 pm  (hour 21)
  0,     // 10:00 pm (hour 22)
  0      // 11:00 pm (hour 23)
  },

//Wednesday Array (Day 3)
  {
  0,     // 12:00 am (hour 0)
  0,     // 1:00 am  (hour 1)
  0,     // 2:00 am  (hour 2)
  0,     // 3:00 am  (hour 3)
  0,     // 4:00 am  (hour 4)
  0,     // 5:00 am  (hour 5)
  0,     // 6:00 am  (hour 6)
  0,     // 7:00 am  (hour 7)
  0,     // 8:00 am  (hour 8)
  0,     // 9:00 am  (hour 9)
  0,     // 10:00 am (hour 10)
  0,     // 11:00 am (hour 11)
  0,     // 12:00 pm (hour 12)
  0,     // 1:00 pm  (hour 13)
  0,     // 2:00 pm  (hour 14)
  0,     // 3:00 pm  (hour 15)
  0,     // 4:00 pm  (hour 16)
  0,     // 5:00 pm  (hour 17)
  0,     // 6:00 pm  (hour 18)
  0,     // 7:00 pm  (hour 19)
  0,     // 8:00 pm  (hour 20)
  0,     // 9:00 pm  (hour 21)
  0,     // 10:00 pm (hour 22)
  0      // 11:00 pm (hour 23)
  },

//Thursday Array (Day 4) 
  {
  0,     // 12:00 am (hour 0)
  0,     // 1:00 am  (hour 1)
  0,     // 2:00 am  (hour 2)
  0,     // 3:00 am  (hour 3)
  0,     // 4:00 am  (hour 4)
  0,     // 5:00 am  (hour 5)
  0,     // 6:00 am  (hour 6)
  0,     // 7:00 am  (hour 7)
  0,     // 8:00 am  (hour 8)
  0,     // 9:00 am  (hour 9)
  0,     // 10:00 am (hour 10)
  0,     // 11:00 am (hour 11)
  0,     // 12:00 pm (hour 12)
  0,     // 1:00 pm  (hour 13)
  0,     // 2:00 pm  (hour 14)
  0,     // 3:00 pm  (hour 15)
  0,     // 4:00 pm  (hour 16)
  0,     // 5:00 pm  (hour 17)
  0,     // 6:00 pm  (hour 18)
  0,     // 7:00 pm  (hour 19)
  0,     // 8:00 pm  (hour 20)
  0,     // 9:00 pm  (hour 21)
  0,     // 10:00 pm (hour 22)
  0      // 11:00 pm (hour 23)
  },

//Friday Array (Day 5) 
  {
  0,     // 12:00 am (hour 0)
  0,     // 1:00 am  (hour 1)
  0,     // 2:00 am  (hour 2)
  0,     // 3:00 am  (hour 3)
  0,     // 4:00 am  (hour 4)
  0,     // 5:00 am  (hour 5)
  0,     // 6:00 am  (hour 6)
  0,     // 7:00 am  (hour 7)
  0,     // 8:00 am  (hour 8)
  0,     // 9:00 am  (hour 9)
  0,     // 10:00 am (hour 10)
  0,     // 11:00 am (hour 11)
  0,     // 12:00 pm (hour 12)
  0,     // 1:00 pm  (hour 13)
  0,     // 2:00 pm  (hour 14)
  0,     // 3:00 pm  (hour 15)
  0,     // 4:00 pm  (hour 16)
  0,     // 5:00 pm  (hour 17)
  0,     // 6:00 pm  (hour 18)
  0,     // 7:00 pm  (hour 19)
  0,     // 8:00 pm  (hour 20)
  0,     // 9:00 pm  (hour 21)
  0,     // 10:00 pm (hour 22)
  0      // 11:00 pm (hour 23)
  },

//Saturday Array (Day 6) 
  {
  0,     // 12:00 am (hour 0)
  0,     // 1:00 am  (hour 1)
  0,     // 2:00 am  (hour 2)
  0,     // 3:00 am  (hour 3)
  0,     // 4:00 am  (hour 4)
  0,     // 5:00 am  (hour 5)
  0,     // 6:00 am  (hour 6)
  0,     // 7:00 am  (hour 7)
  0,     // 8:00 am  (hour 8)
  0,     // 9:00 am  (hour 9)
  0,     // 10:00 am (hour 10)
  0,     // 11:00 am (hour 11)
  0,     // 12:00 pm (hour 12)
  0,     // 1:00 pm  (hour 13)
  0,     // 2:00 pm  (hour 14)
  0,     // 3:00 pm  (hour 15)
  0,     // 4:00 pm  (hour 16)
  0,     // 5:00 pm  (hour 17)
  0,     // 6:00 pm  (hour 18)
  0,     // 7:00 pm  (hour 19)
  0,     // 8:00 pm  (hour 20)
  0,     // 9:00 pm  (hour 21)
  0,     // 10:00 pm (hour 22)
  0      // 11:00 pm (hour 23)
  },

};



int currentDay = 0;
int currentHour = 0;
int currentMinute = 0;
int currentSecond = 0;

int goalTemperature = 70;     //Current temperature setting
int manualTemperatureAdjustment = 0;     //Manually adjustment to the temperature setting with buttons
int servoTemperatureConversion = 4;     //How many degrees of the servo rotation correspond to a degree in temperature
int temperatureDifference = 0;     //Difference between current temperature setting and the default temperature
int defaultPosition = 70;     //Default servo position that will be adjusted based on temperature setting
int servoDifference = 0;     //Difference between current servo position setting and the default position
int currentPosition = 70;     //Current servo position 
int previousPosition = 69;     //Previous servo position

int upButtonPin = 11;     //Pin to read positive manual adjustment buttons
int downButtonPin = 10;     //Pin to read negative manual adjustment buttons
int upButtonState = 0;     //Current state of positive adjustment button
int downButtonState = 0;     //Current state of negative adjustment button        

unsigned long currentTime = 0;     //Milliseconds since start of program
unsigned long secondMarker = 1000;     //1000 milliseconds per second



void setup() 
{
  pinMode(upButtonPin, INPUT);
  pinMode(downButtonPin, INPUT);
  myservo.attach(9);     //Attaches the servo on pin 9 to the servo object
  Serial.begin(9600);     //Serial Monitor fuction for debugging and monitoring
}



void loop() 
{

currentTime = millis();     //Tracks current time

if(currentTime > secondMarker)
 {
  currentSecond = currentSecond + 1;     //Adjust second counter
  if(currentSecond > 59)
   {
     currentSecond = 0;
     currentMinute = currentMinute + 1;     //Adjust minute counter  
   }
  if(currentMinute > 59)
   {
     currentMinute = 0;
     currentHour = currentHour + 1;     //Adjust hour counter  
   }
  if(currentHour > 23)
   {
     currentHour = 0;
     currentDay = currentDay + 1;     //Adjust day counter  
   }
  if(currentDay > 6)
   {
     currentDay = 0;
   }
        
  secondMarker = secondMarker + 1000;     //Adjust time marker to update seconds

  if(secondMarker < 1000 && currentTime > 10000)     //Resets clock counter when the millis() function resets
   {
    delay(1000);
   } 
 }


                        
Serial.print(currentDay);     //display clock for debugging   
Serial.print("  ");
Serial.print(currentHour);
Serial.print("  ");
Serial.print(currentMinute);
Serial.print("  ");
Serial.print(currentSecond);
Serial.print("  ");
Serial.print(currentTime);
Serial.print("  ");
Serial.println(secondMarker);



temperatureDifference = dayTimeArray[currentDay][currentHour] + manualTemperatureAdjustment;  
servoDifference = temperatureDifference * servoTemperatureConversion;
currentPosition = defaultPosition + servoDifference;
goalTemperature = defaultTemperature + temperatureDifference;     



if (previousPosition != currentPosition) 
 {
  Serial.print("Default Temperature ");     //Display updated temperature information
  Serial.println(defaultTemperature);  
  Serial.print("Day Time Adjustment ");  
  Serial.println(dayTimeArray[currentDay][currentHour]);  
  Serial.print("Manual Adjustment ");  
  Serial.println(manualTemperatureAdjustment); 
  Serial.print("Goal Temperature "); 
  Serial.println(goalTemperature);   
  Serial.println();  
  Serial.print("Default Servo Position ");  
  Serial.println(defaultPosition);    
  Serial.print("Servo Position Adjustment "); 
  Serial.println(servoDifference); 
  Serial.print("Current Servo Position "); 
  Serial.println(currentPosition); 
  Serial.println();   
  Serial.println();  
  
  myservo.write(currentPosition);     //Adjust the servo to match the current settings
  delay(500);
  previousPosition = currentPosition;
 }
  


upButtonState = digitalRead(upButtonPin);     //Check buttons for manual adjustments
downButtonState = digitalRead(downButtonPin);     //Check buttons for manual adjustments
  
if (upButtonState == HIGH) 
 {
  manualTemperatureAdjustment = manualTemperatureAdjustment + 1;     //Adjust temperature setting up   
 }

if (downButtonState == HIGH) 
 {
  manualTemperatureAdjustment = manualTemperatureAdjustment - 1;     //Adjust temperature setting down 
 }

}