// June 2009 Eemnes. By Jan Willem Kooi. See www.thesimplepages.nl

#include <LiquidCrystal.h> // Library LCD
// LiquidCrystal display with:
// rs on pin 12
// rw on pin 11
// enable on pin 10
// d0, d1, d2, d3 on pins 9, 8, 7, 6
// Backlight on Pin 1
// Used display: 16x2 4 bits. (Ordered by BudgeTronics Art. Code DIS101 12,95 Dutch) 

LiquidCrystal lcd(12, 11, 10, 9, 8, 7, 6);

#include <RemoteSwitch.h> // Library Klik-Aan-Klik-Uit (KaKu)
// KaKu send on pin 13 
// 433Mhz send module QAM-TX1 433 (Ordered by Quasar UK Lrd Art. Code 220380178906) 
KaKuSwitch kaKuSwitch(13); //Send on pin 13 (digital output)

// Declaration variables for apparatus
int in1 = 2; // push button 1 from left
int in2 = 3; // push button 2
int in3 = 4; // push button 3
int in4 = 5; // push button 4

boolean backlight = false;     // backlight on = TRUE, backlight off = FALSE;
boolean light_status = false;   // light on = TRUE, light off = False; 
int lcdledport = 1; // The backlight LCD is on dig pin 1 verbonden

// light measere variables
int lightport = 4; // The LDR is on analog 4 
int lightvalue = 0;
int lightswitch = 300; // initial value for light switch on

// variables for roling average of light measurements
int max_lightarray = 14; // Array will be 15 positions
int lightarray[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};   // every minute, 3 measures makes 15 values.
float alllightvalues = 0;
float roll_light_value = 0; 
boolean calculation_done = true; // in one second only one calculation

// variables for clock
int csecond = 0;
int cminute = 0;
int chour = 0;

float maxmillis = 4294967295;  // maximum millis = 4,294,967,295 
float nextmillis = 0;          // will give next interval 
float interval = 996.8;        // every second a new tick (if time runs behind, lower the number)

// variables switch on light 
int forsure_switch_value = 0;     // Check variable if signal had been given to switch on lights
int forsure_switch_value_max = 5; // After the light is deminised send signal 5 times

int chour_on = 0;      // remember time when lights are on
int cminute_on = 0;
int csecond_on = 0;

// variables swith off light
int chour_switch_off = 23;
int cminute_switch_off = 30;

void setup()
{  

lcd.clear();  

pinMode (in1, INPUT);      //  Push button 1 
pinMode (in2, INPUT);      //  Push button 2 
pinMode (in3, INPUT);      //  Push button 3 
pinMode (in4, INPUT);      //  Push button 4 

pinMode (lcdledport, OUTPUT); // Backlight LCD

} // end void setup

void loop() // main program loop
{
  
int program_modus = 0; // program mode: 0 is normal mode, higher than 0 is program mode (e.g. set time, adjust, light)

//
  if (digitalRead(in1) == HIGH)  // first button triggers program mode (e.g. set time, adjust, light)
  {program_modus = 1;}

while (program_modus != 0)  // go into set modus until everything is set.
{
 digitalWrite (lcdledport, HIGH); // set backlight on
 delay (150); 
   // adjust hour 
   if (program_modus == 1)
   {
    delay(150); // additional delay to prevent jump over set hour.
    lcd.clear();
    lcd.print("Set Hour");
    lcd.setCursor(0, 1); // Next line
 
    if (digitalRead(in3) == HIGH) // if button 2 is push, increase hour
      {
        if (chour < 23)
          {
            chour++;
          }
      }    
     if (digitalRead(in2) == HIGH) // if button 3 is pushed, decrease hour
      {
        if (chour > 0)
          {
            chour--;
          }
      }    
   prt_lcd_clck (chour, cminute, csecond);
   }
   // end adjust hour

   // adjust minute
   if (program_modus == 2)
   {
    lcd.clear();
    lcd.print("Set Minute");
    lcd.setCursor(0, 1); // Next line
 
    if (digitalRead(in3) == HIGH) // if button 3 is push, increase minute
      {
        if (cminute < 59)
          {
            cminute++;
          }
      }    
     if (digitalRead(in2) == HIGH) // if button 2 is pushed, decrease minute
      {
        if (cminute > 0)
          {
            cminute--;
          }
      }    
   prt_lcd_clck (chour, cminute, csecond);
   }
   // end adjust minute

   // adjust minute
   if (program_modus == 3)
   {
    lcd.clear();
    lcd.print("Set Second");
    lcd.setCursor(0, 1); // Next line
 
    if (digitalRead(in3) == HIGH) // if button 3 is push, increase second
      {
        if (csecond < 59)
          {
            csecond++;
          }
      }    
     if (digitalRead(in2) == HIGH) // if button 2 is pushed, decrease second
      {
        if (csecond > 0)
          {
            csecond--;
          }
      }    
   prt_lcd_clck (chour, cminute, csecond);
   }
   // end adjust second
  
  // adjust clock
  if (program_modus == 4)
  {
    lcd.clear();
    lcd.print("Adjust interval");
    lcd.setCursor(0, 1); // Next line
 
    if (digitalRead(in3) == HIGH) // if button 3 is push, increase interval
      {
        if (interval < 1100 )
          {
            interval = interval + 0.1;
          }
      }    
     if (digitalRead(in2) == HIGH) // if button 2 is pushed, decrease interval
      {
        if (interval > 500)
          {
            interval = interval - 0.1;
          }
      }    
   lcd.print(interval);    
  }
  // end adjust clock
  
  // adjust light sensitivity
  if (program_modus == 5)
  {
    lcd.clear();
    lcd.print("Adjust lights On");
    lcd.setCursor(0, 1); // Next line
 
    if (digitalRead(in3) == HIGH) // if button 3 is push, increase interval
      {
        if (lightswitch < 1024 )
          {
            lightswitch = lightswitch + 1;
          }
      }    
     if (digitalRead(in2) == HIGH) // if button 2 is pushed, decrease interval
      {
        if (lightswitch > 0)
          {
            lightswitch = lightswitch - 1;
          }
      }    
   lcd.print(lightswitch);
   lightvalue = analogRead(lightport);
   lcd.setCursor(8,1);
   lcd.print(lightvalue);
  }
  if (digitalRead(in1) == HIGH)
    {
      program_modus ++;
      delay (300);
    }
  
  if (program_modus >= 6) // end of program loop
    {
      lcd.clear();
      lcd.print("Press 1 to start");
      lcd.setCursor(0,1);
      prt_lcd_clck (chour, cminute, csecond);
      delay(400);
      while (digitalRead(in1) == LOW)
      {}   //wait until button 1 is pressed start with the time set 
      lcd.clear();
      program_modus = 0;
      nextmillis = millis();
    }
   
} // end while    

// Running clock program part with adjust possibilities

// if one second has pasted, add 1 to csecond

if (millis() >= nextmillis)    // will only be true after 1 second
  {    
    nextmillis = nextmillis + interval; // set for next second
    csecond ++;  
  }

if (nextmillis > maxmillis - interval)  // check is maximum millis = 34,359,739 will be reached 
  {
    nextmillis = nextmillis + interval - maxmillis; // Rollover of millis, reset nextmillis
  } 

// Minute check
if (csecond > 59)
  {
    csecond = 0;
    cminute ++;
  }  
// Hour check
if (cminute > 59)
  {
    cminute = 0;
    chour ++;
  }  
// Day check
if (chour > 23)
  {
    chour = 0;
  }  

// push button 2 in normal mode to see the last switch-on time 

if (digitalRead(in2) == HIGH)
  {  
    lcd.clear();
    lcd.print("Last time light");
    lcd.setCursor(0, 1);
    lcd.print("on :");
    prt_lcd_clck(chour_on, cminute_on , csecond_on);
    delay(250);
  }
  
// in normal mode you can switch the lights on and off with button 3  
if (digitalRead(in3) == HIGH)
  {  
    if (light_status == true)
      {
        kaKuSwitch.sendSignal('A',1,false);
        kaKuSwitch.sendSignal('A',2,false); 
        kaKuSwitch.sendSignal('A',3,false);
        light_status = false;
      }
    else
      {
        kaKuSwitch.sendSignal('A',1,true);
        kaKuSwitch.sendSignal('A',2,true); 
        kaKuSwitch.sendSignal('A',3,true);
        light_status = true;
      }
            
    delay(300);    
  }
  
// in normal mode you can toggle the backlight with button 3
if (digitalRead(in4) == HIGH)
  {  
    if (backlight == false)
      {
        lcd.setCursor(0,1);
        lcd.print("Backlight on    ");
        digitalWrite (lcdledport, HIGH);
        backlight = true;   
        delay (500);
      }  
    else
      {  
        lcd.setCursor(0,1);
        lcd.print("Backlight off   ");
        digitalWrite (lcdledport, LOW);
        backlight = false;
        delay (500);
      }  
  }

delay (300);
  lightvalue = analogRead(lightport);
  if (lightvalue == 0)
    {
      lightvalue = 1; // Bug somehow, but program has strange behaviour if lightvalue = 0
    }
  lcd.clear();
  lcd.print("Time ");

  prt_lcd_clck(chour, cminute , csecond);

// Light on second row
  lcd.setCursor(0, 1);
  lcd.print(lightvalue);
  lcd.print("-");
  lcd.print(lightswitch);
  lcd.print("-");
  lcd.print(roll_light_value);

// rolling average calculation

if (calculation_done == false) // To prevent multiple calculation within one second
                               // calculation_done will be false after the first run within the 
                               // second (on 10, 30 and 50). Otherwise the
                               // calculation_done will be reset to false 
                               // 
  {
//    Measure 3 times every minute at 10, 30 and 50 seconds
  if (csecond == 10 || csecond == 30|| csecond == 50)

    {
      for (int i=max_lightarray; i > 0 ; i--)
        {
          lightarray[i] = lightarray[i-1];  // shift all values in array except [0]
        }     
      lightarray[0] = lightvalue;  // put new light valua in array at position [0]
      
      alllightvalues = 0;
      
      for (int i=0; i < max_lightarray ; i++)
        {
          alllightvalues = alllightvalues + lightarray[i];
        }
      roll_light_value = alllightvalues / (max_lightarray + 1); 
      calculation_done = true;      
    }
  }
  
// Reset calculation_done after the trigger seconds (10, 30 and 50) are over   
if (csecond != 10 && csecond != 30 && csecond != 50)
   {
    calculation_done = false;
   } 

// Automatic light switch on when a adjustable lightvalue has been reached

if (chour>=15 && chour<=22 ) // only between 15:00 and 22:59 switch on lights on decreasing daylight
  {
      if (roll_light_value <= lightswitch)
        {if (forsure_switch_value <= forsure_switch_value_max)
            {
              forsure_switch_value ++; // Light on signal is given more than ones

              kaKuSwitch.sendSignal('A',1,true);
              kaKuSwitch.sendSignal('A',2,true); 
              kaKuSwitch.sendSignal('A',3,true);
              
              light_status = true;
              chour_on = chour;      // remember time when lights are on
              cminute_on = cminute;
              csecond_on = cminute;

              delay(250);
            }
        }
  }        

// Turn lights off (3 times)

if (chour == chour_switch_off && cminute == cminute_switch_off && csecond <= 5)      
    {  
      // first time turn off
       kaKuSwitch.sendSignal('A',1,false);
       kaKuSwitch.sendSignal('A',2,false); 
       kaKuSwitch.sendSignal('A',3,false);
       delay (100);
     // second time turn off  
       kaKuSwitch.sendSignal('A',1,false);
       kaKuSwitch.sendSignal('A',2,false); 
       kaKuSwitch.sendSignal('A',3,false);
       delay (100);
     // third time turn off  
       kaKuSwitch.sendSignal('A',1,false);
       kaKuSwitch.sendSignal('A',2,false); 
       kaKuSwitch.sendSignal('A',3,false);
       
       forsure_switch_value = 0;
       light_status = false;      
       delay(250);
    }

// Just to be sure, an other switch off at 04:30
if (chour == 4 && cminute == 30 && csecond <= 5)      
    {  
      // first time turn off
       kaKuSwitch.sendSignal('A',1,false);
       kaKuSwitch.sendSignal('A',2,false); 
       kaKuSwitch.sendSignal('A',3,false);
       delay (100);
       forsure_switch_value =0;
       light_status = false;
    }
 
// print status of light switch 
lcd.setCursor(13, 1);
if (light_status == true)
  {
    lcd.print ("on");
  }
else
  {
    lcd.print ("off");
  }
    
} // end of program loop

// Print hh:mm:ss on LCD screen without newline before or after
void prt_lcd_clck (int fhour, int fminute, int fsecond)
{
  if (fhour < 10)
    {
      lcd.print("0"); // if hour is only one digit, print a zero before
    }
  lcd.print(fhour);
  lcd.print (":");
  if (fminute < 10)
    {
      lcd.print("0");
    }
  lcd.print(fminute);
  lcd.print (":");
  if (fsecond < 10)
    {
      lcd.print("0");
    }  
  lcd.print(fsecond);
}  
// End: Print hh:mm:ss on LCD screen without newline before or after