Translate

Sunday 22 June 2014

The current working sketch of the Room Management System


///////////////////////////////////////////////////////////////////////////////////
////Room Management System Version 1.4.5///////////////////////////////////////////
////by Dieter Achtelstetter////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
////This program is free software: you can redistribute it and/or modify///////////
////it under the terms of the GNU General Public License as published by///////////
////the Free Software Foundation, either version 3 of the License, or   ///////////
////(at your option) any later version.                                 ///////////
///////////////////////////////////////////////////////////////////////////////////
////This program is distributed in the hope that it will be useful,     ///////////
////but WITHOUT ANY WARRANTY; without even the implied warranty of      ///////////
////MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the       ///////////
////GNU General Public License for more details.                        ///////////
///////////////////////////////////////////////////////////////////////////////////
////For details on the GNU General Public License please visit          ///////////
////the website <http://www.gnu.org/licenses/>.                         ///////////
///////////////////////////////////////////////////////////////////////////////////
//////////////////////////Credits//////////////////////////////////////////////////
////A very big thank you goes to my wife and my daughter for all        ///////////
////their support and patience.                                         ///////////
////To Rene, for helping in improofing the input stage and the way      ///////////
////of debugging the code. And showing me a way of programming          ///////////
////which will finde a definite place in future projects.               ///////////
////To Reuben, who was a very great help in optimizing the              ///////////
////menu part of the program.                                           ///////////
////To all the guys in the ARDUINO Forum, answering all my              ///////////
////quetions and also helping debugging some of the code.               ///////////
///////////////////////////////////////////////////////////////////////////////////


/////////////////////Includes/////////////////////////////
#include <DS1307RTC.h>
#include <Time.h>
#include <Wire.h>
#include <ShiftLCD.h>
#include <avr/pgmspace.h>
#include <EEPROM.h>

#define ON  1                        // (RRKM-01) The switch is in ON state
#define OFF 0                        // (RRKM-01) The switch is in OFF state


#define DS1307_ADDRESS 0x68
byte zero = 0x00;

//////////////DEBUGGING///////////////
//uncomment the lines below for debugging
//#define DA_DEBUG_serial //to enable Serial monitor
//#define DA_DEBUG_in //debug the input stage
//#define DA_DEBUG_btnReadings //check button readings
//#define DA_DEBUG_tmp //check temperatur readings
//#define DA_DEBUG_holtimers //debug the holiday timers
//#define DA_DEBUG_ac //Debug AC
//#define DA_DEBUG_AC_2 //Debug AC
//#define DA_DEBUG_out //debug the output stage
//#define DA_DEBUG_photo //debug control from photocell for holiday switching

/////////////////////Declaring the Variables/////////////////

/////////////EEPROM Storage//////////////
int eepromValue = 0;
const byte EEPROM_ID = 111;

const int ID_ADDR = 0;
const byte Sensitivity_ADDR = 1;        //2 byte value
const byte photoCellCutOff_ADDR = 3;    //2 byte value
const byte photoOutsideOff_ADDR = 5;    //2 byte value
const int startDelay_ADDR = 374;        //1 byte value
const int acSwitchDelay_ADDR = 375;     //1 byte value
const int ac_op_mode_ADDR = 376;        //1 byte value
const int ac_set_temp_ADDR = 377;       //1 byte value

const byte delayTime_ADDR[15] PROGMEM = {7, 9, 11, 13, 15, 17,
                                         19, 21, 23, 25, 27, 29, 
                                         31, 33, 35};


const byte timer_active_ADDR[16][4] PROGMEM = {
                                       {37, 38, 39, 40},
                                       {41, 42, 43, 44},
                                       {45, 46, 47, 48},
                                       {49, 50, 51, 52},
                                       
                                       {53, 54, 55, 56},
                                       {57, 58, 59, 60},
                                       {61, 62, 63, 64},
                                       {65, 66, 67, 68},
                                       
                                       {69, 70, 71, 72},
                                       {73, 74, 75, 76},
                                       {77, 78, 79, 80},
                                       {81, 82, 83, 84},
                                       
                                       {85, 86, 87, 88},
                                       {89, 90, 91, 92},
                                       {93, 94, 95, 96},
                                       {97, 98, 99, 100}
                                       };
                                       

const int room_timers_ADDR[16][4][4] PROGMEM = {
                                        {
                                          {102, 103, 104, 105},
                                          {106, 107, 108, 109},
                                          {110, 111, 112, 113},
                                          {114, 115, 116, 117}
                                        },
                                        {
                                          {118, 119, 120, 121},
                                          {122, 123, 124, 125},
                                          {126, 127, 128, 129},
                                          {130, 131, 132, 133}
                                        },
                                        {
                                          {134, 135, 136, 137},
                                          {138, 139, 140, 141},
                                          {142, 143, 144, 145},
                                          {146, 147, 148, 149}
                                        },
                                        {
                                          {150, 151, 152, 153},
                                          {154, 155, 156, 157},
                                          {158, 159, 160, 161},
                                          {162, 163, 164, 165}
                                        },
                                        {
                                          {166, 167, 168, 169},
                                          {170, 171, 172, 173},
                                          {174, 175, 176, 177},
                                          {178, 179, 180, 181}
                                        },
                                        {
                                          {182, 183, 184, 185},
                                          {186, 187, 188, 189},
                                          {190, 191, 192, 193},
                                          {194, 195, 196, 197}
                                        },
                                        {
                                          {198, 199, 200, 201},
                                          {202, 203, 204, 205},
                                          {206, 207, 208, 209},
                                          {210, 211, 212, 213}
                                        },
                                        {
                                          {214, 215, 216, 217},
                                          {218, 219, 220, 221},
                                          {222, 223, 224, 225},
                                          {226, 227, 228, 229}
                                        },
                                        {
                                          {230, 231, 232, 233},
                                          {234, 235, 236, 237},
                                          {238, 239, 240, 241},
                                          {242, 243, 244, 245}
                                        },
                                        {
                                          {246, 247, 248, 249},
                                          {250, 251, 252, 253},
                                          {254, 255, 256, 257},
                                          {258, 259, 260, 261}
                                        },
                                        {
                                          {262, 263, 264, 265},
                                          {266, 267, 268, 269},
                                          {270, 271, 272, 273},
                                          {274, 275, 276, 277}
                                        },
                                        {
                                          {278, 279, 280, 281},
                                          {282, 283, 284, 285},
                                          {286, 287, 288, 289},
                                          {290, 291, 292, 293}
                                        },
                                        {
                                          {294, 295, 296, 297},
                                          {298, 299, 300, 301},
                                          {302, 303, 304, 305},
                                          {306, 307, 308, 309}
                                        },
                                        {
                                          {310, 311, 312, 313},
                                          {314, 315, 316, 317},
                                          {318, 319, 320, 321},
                                          {322, 323, 324, 325}
                                        },
                                        {
                                          {326, 327, 328, 329},
                                          {330, 331, 332, 333},
                                          {334, 335, 336, 337},
                                          {338, 339, 340, 341}
                                        },
                                        {
                                          {342, 343, 344, 345},
                                          {346, 347, 348, 349},
                                          {350, 351, 352, 353},
                                          {354, 355, 356, 357}
                                        }
};

const int ac_forced_on_ADDR[4][2] PROGMEM = {
                                      {358, 359},
                                      {360, 361},
                                      {363, 363},
                                      {364, 365}
};
  
const int ac_periode_ADDR[4][2] PROGMEM = {
                                    {366, 367},
                                    {368, 369},
                                    {370, 371},
                                    {372, 373}
};  


const int ac_master_bypass_ADDR[4] PROGMEM = {378, 379, 380, 381};                                          

///////////Timer and Sensitivity Settings to be changed to individual needs////////////////
unsigned int sensitivity; // = 300; //should be between 200 and 1000 as
                                    //lower the number as more responsive 
                                    //the system will be
unsigned int photoCellCutOn = 320;  //var holding the switching limit for the photocell
unsigned int photoCellCutOff = 280; //var holding the value where the photocell cuts off
unsigned int photoOutsideOn = 220;  //var holding the value which the photocell reading 
unsigned int photoOutsideOff = 260;

/*int delayTime[16] = {dBed1, dBed2, dBed3, dLiving, dBath1, dBath2, dBath3,
                     dBath4, dKitchen, dCorridor, dAC1, dAC2, dAC3, dAC4,
                     dMaster, 0};*/
int delayTime[15] = {120, 120, 120, 600, 180, 180, //delay time in seconds to the above order
                     180, 180, 120, 120, 120, 120, 
                     120, 120, 240};


byte startDelay = 0;       //var to optional ac compressor start delay

byte acSwitchDelay = 2;    //ac puls delay for mode 3
byte ac_op_mode = 3;       //ac mode 1) read switches only
                           //ac mode 2) limited control using ac switch or auto restart of AC
                           //ac mode 3) limited control using ac momentary switch (push button)
byte ac_set_temp = 28;     //temperature at which the AC switches on
byte ac_periode[4][2] = {
                          {1, 5},     //time periode between January and May
                          {6, 9},     //time periode between June and September
                          {10, 10},   //October
                          {11, 12}    //time periode between November and December
};

byte ac_master_bypass[4] = {0};       //array holding values to bypass master relay


//////////////////////holiday and AC timer settings//////////////////////

byte timer_active[16][4] = {
                    {1, 1, 1, 0},    //room 0 timers 0 to 3
                    {1, 1, 0, 0},    //room 1 timers 0 to 3
                    {1, 1, 1, 1},    //room 2 timers 0 to 3
                    {0, 1, 0, 0},    //room 3 timers 0 to 3
                    {1, 1, 2, 2},    //room 4 timers 0 to 3
                    {1, 1, 2, 2},    //room 5 timers 0 to 3
                    {1, 1, 2, 2},    //room 6 timers 0 to 3
                    {1, 0, 2, 2},    //room 7 timers 0 to 3
                    {1, 1, 2, 2},    //room 8 timers 0 to 3
                    {0, 0, 2, 2},    //room 9 timers 0 to 3
                    {1, 1, 1, 0},    //room 0 AC timers 0 to 3
                    {1, 1, 1, 0},    //room 1 AC timers 0 to 3
                    {1, 1, 1, 0},    //room 2 AC timers 0 to 3
                    {1, 1, 2, 0},    //room 3 AC timers 0 to 3
                    {2, 2, 2, 2},    //Dummy room 
                    {0, 1, 2, 2}     //outside lighting
};

//Timer Settings room, timer, hour on, minute on, hour off, minute off
byte room_timers[16][4][4] = {
                               {
                                 {5, 35, 6, 5},        //room 0 timer 0
                                 {19, 35, 20, 15},     //room 0 timer 1
                                 {21, 5, 21, 15},      //room 0 timer 2
                                 {0, 0, 0, 0}          //room 0 timer 3
                               },
                               {
                                 {6, 30, 6, 50},       //room 1 timer 1
                                 {19, 30, 20, 10},     //room 1 timer 2
                                 {0, 0, 0, 0},         //room 1 timer 3
                                 {0, 0, 0, 0}          //room 1 timer 4
                               },
                               {
                                 {5, 50, 6, 20},       //room 2 timer 1
                                 {18, 10, 18, 25},     //room 2 timer 2
                                 {19, 15, 19, 40},     //room 2 timer 3
                                 {23, 20, 23, 35}      //room 2 timer 4
                               },
                               {
                                 {0, 0, 0, 0},         //room 3 timer 1
                                 {17, 30, 23, 30},     //room 3 timer 2
                                 {0, 0, 0, 0},         //room 3 timer 3
                                 {0, 0, 0, 0}          //room 3 timer 4
                               },
                               {
                                 {5, 40, 5, 45},       //room 4 timer 1
                                 {19, 55, 20, 10},     //room 4 timer 2
                                 {0, 0, 0, 0},         //not used
                                 {0, 0, 0, 0}          //not used
                               },
                               {
                                 {6, 35, 6, 45},       //room 5 timer 1
                                 {19, 50, 20, 5},      //room 5 timer 2
                                 {0, 0, 0, 0},         //not used
                                 {0, 0, 0, 0}          //not used
                               },
                               {
                                 {6, 5, 6, 25},        //room 6 timer 1
                                 {22, 50, 23, 15},     //room 6 timer 2
                                 {0, 0, 0, 0},         //not used
                                 {0, 0, 0, 0}          //not used
                               },
                               {
                                 {0, 0, 0, 0},         //room 7 timer 1
                                 {22, 5, 22, 20},      //room 7 timer 2
                                 {0, 0, 0, 0},         //not used
                                 {0, 0, 0, 0}          //not used
                               },
                               {
                                 {5, 50, 6, 45},       //room 8 timer 1
                                 {17, 45, 18, 30},     //room 8 timer 2
                                 {0, 0, 0, 0},         //room 8 timer 3
                                 {0, 0, 0, 0}          //not used
                               },
                               {
                                 {0, 0, 0, 0},         //room 9 timer 1
                                 {0, 0, 0, 0},         //room 9 timer 2
                                 {0, 0, 0, 0},         //not used
                                 {0, 0, 0, 0}          //not used
                               },
                               {
                                 {19, 30, 22, 0},         //room 0 AC timer 1
                                 {19, 30, 5, 30},         //room 0 AC timer 2
                                 {19, 30, 22, 0},         //room 0 AC timer 3
                                 {0, 0, 0, 0}             //room 0 AC timer 4
                               },
                               {
                                 {19, 30, 22, 0},         //room 1 AC timer 1
                                 {19, 30, 5, 30},         //room 1 AC timer 2
                                 {19, 30, 22, 0},         //room 1 AC timer 3
                                 {0, 0, 0, 0}             //room 1 AC timer 4
                               },
                               {
                                 {21, 30, 1, 0},         //room 2 AC timer 1
                                 {21, 30, 6, 0},         //room 2 AC timer 2
                                 {21, 30, 1, 0},         //room 2 AC timer 3
                                 {0, 0, 0, 0}            //room 2 AC timer 4
                               },
                               {
                                 {13, 0, 20, 0},         //room 3 AC timer 1
                                 {5, 0, 23, 59},         //room 3 AC timer 2
                                 {6, 0, 20, 0},          //room 3 AC timer 3
                                 {0, 0, 0, 0}            //room 3 AC timer 4
                               },
                               {
                                 {0, 0, 0, 0},           //Dummy timer not used
                                 {0, 0, 0, 0},       
                                 {0, 0, 0, 0},         
                                 {0, 0, 0, 0}           
                               },
                               {
                                 {0, 0, 0, 0},           //outside lights timer 1
                                 {17, 3, 23, 59},        //outside lights timer 2
                                 {0, 0, 0, 0},           //outside lights timer 3
                                 {0, 0, 0, 0}            //outside lights timer 4
                               }
};
 
byte ac_forced_on[4][2] = {
                            {19, 30},  //Switch on AC room 1
                            {19, 30},  //Switch on AC room 2
                            {22, 0},   //Switch on AC room 3
                            {16, 0}    //Switch on AC room 4
};
///////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////DO NOT MODIVY BELOW HERE///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
////////////////////////////defining Arduino Pins/////////////////////////////
//////////////////////////////////////////////////////////////////////////////
ShiftLCD lcd(9, 11, 10);       //initializing the LCD adaptor pins

const byte latchPin = 2;        //5latch pin input connected to
                               //Arduino digital pin 2
const byte clockPin = 3;        //6clock pin input connected to
                               //Arduino digital pin 3
const byte dataPin = 4;         //7data pin input connected to 
                               //Arduino digital pin 4
                               
const byte latchPinOut = 5;     //2latch pin output shift register
                               //74HC595 connected to Arduino
                               //digital pin 5
const byte clockPinOut = 6;     //3clock pin output shift register
                               //74HC595 connected to Arduino
                               //digital pin 6
const byte dataPinOut = 7;      //4data pin output shift register
                               //74HC595 connected to Arduino
                               //digital pin 7

const byte lightSensor = 0;          //defining the input for the photocell

const byte doorMonitor = 8;           //Arduino pin for a monitor LED
const byte setupMode = 12;            //Arduino pin for switching to setup mode

const byte TMP01 = 2;                 //Arduino analog pin 2 - temperature sensor

/////////////////////////////////////////////////////////////////////////////
///////Variables to hold the data for each input shift register//////////////
/////////////////////////////////////////////////////////////////////////////

byte switchVar1 = 0;           //data for input shift register 1
byte switchVar2 = 0;           //data for input shift register 2
byte switchVar3 = 0;           //data for input shift register 3

///////////////////////////////////////////////////////////////////////////////
///////////////////////////all the other variables/////////////////////////////
///////////////////////////////////////////////////////////////////////////////

////Sensor and timer variables
                     
byte temperatur1 = 0;                        //holding temperatur for room 1

unsigned long lastRun[4] = {0};              //var to hold var when ac was last running
                               
int sensorValue = 0;                         //holding the indicated sensor value of the photocell
byte photocellSwitch = 0;                    //holding the switch command after 
                                             //checking sensor readings (0, 1)
byte photocellSwitchOld = 0;                 //switch command from the previous pass
byte lightLevel[17] ={0};                    //array holding the switch state
                                             //checking timer and photocell (0, 1)

byte roomLight[15] = {0};                    //array holding the switch on command in holiday lighting
const unsigned int outputValues[16] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,0,32768};
unsigned int roomTimer[17] = {0};            //array holding the time when the PIR was last activated
unsigned int currentTime = 0;                //var to hold a reference time to calculate the up time 
                                             //against the preprogrammed delay time
unsigned int endTime = 0;                    //var to hold a temp result to calculate the up time 
                                             //against the preprogrammed delay time
unsigned int displayTimeSet = millis()/1000; //variable needed for display exchange 
                                             
////////////////////////////////////////////////////////////////////////////////////////
//////////////////////PIR and Room switch related Var's/////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////                                            

byte mainOff = 1;                            //variable for master relay control
unsigned int offTime = 0;                    //var needed to calculate delay for master off
byte masterSwitchStateOld = 0;               //var holding the previous door switch state
byte switchState[25] = {0};                  //array holding the state of each switch 
unsigned long lightOutput[17] = {0};         //array holding a integer which converted to binary 
                                             //will trigger the relay to switch in our output code
byte lightStatus[17] = {0};                  //array holding the switch status of each room on/off
byte priorityStatus[17] = {0};               //array holding the priority status of each room on/off

byte switchStateOld[4] = {0};                //var to check if the priority switch state has changed

//////////////////////////////////////////////////////////////////////////////
///////////////////////////Output/////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////

unsigned long outputL = 0;                    //variable holding the output data

/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////RTC and Holiday switch timers///////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
tmElements_t tm;               //initializing RTC

byte currentHour = 0;                 //var holding the time (hour 0-23)
byte currentMinute = 0;               //var holding the time (minute 0-59)
byte currentDay = 0;                  //var holding the date (day 1-31)
byte currentDoM = 0;                  //var holding the weekday (Sun - Sa, 1-7)
byte currentMonth = 0;                //var holding the date (month 1-12)
int currentYear = 0;                  //var holding the year (based on unix time)

//Array holding the day names to replace the weekday index

prog_char weekday_0[] PROGMEM = "Sun";
prog_char weekday_1[] PROGMEM = "Mon";
prog_char weekday_2[] PROGMEM = "Tue";
prog_char weekday_3[] PROGMEM = "Wed";
prog_char weekday_4[] PROGMEM = "Thu";
prog_char weekday_5[] PROGMEM = "Fri";
prog_char weekday_6[] PROGMEM = "Sat";

PROGMEM const char *weekday_table[] = {
  weekday_0,
  weekday_1,
  weekday_2,
  weekday_3,
  weekday_4,
  weekday_5,
  weekday_6
};

char buffer[20];
///////////////////////////////////////////////////////////////////////////
///////////////////Menu and user interface/////////////////////////////////
///////////////////////////////////////////////////////////////////////////

const byte btnMenu = 1;          //defining the menu button – moves through the menu
const byte btnSearch = 2;        //defining the search button – moves through values 
const byte btnSelect = 3;        //defining the select button – selects a menu or a value
const byte btnNone = 0;          //defining the non button pressed var
int act_key_in = 0;              //var holding the key related sensor reading

byte menuOption = 0;             //var to count current menu option
const byte menuOptions = 22;     //available menu options
byte submenu = 0;                //var to count current submenu option
const byte submenus = 10;         //available submenu options
byte acSetup = 0;                //var to count current ac setup menu options
const byte acSetups = 5;         //available ac setup menu options
byte acSubOption = 0;            //var to count current ac sub menu options
const byte acSubOptions = 10;    //available ac sub menu options


char buffer_M[20];               //var holding the menu strings retrieved from
                                 //the program memory

//Storing some menu messages in the program memory
prog_char msg_0[] PROGMEM = "Not Used";      
prog_char msg_1[] PROGMEM = "Saving....";
prog_char msg_2[] PROGMEM = "Setup mode";
prog_char msg_3[] PROGMEM = "Starting....";
prog_char msg_4[] PROGMEM = "RMU 1.4.5";
prog_char msg_5[] PROGMEM = "Weekday";
prog_char msg_6[] PROGMEM = "On  TIMER  Off";
prog_char msg_7[] PROGMEM = "Off   ";
prog_char msg_8[] PROGMEM = "Active";
prog_char msg_9[] PROGMEM = "PIR Delay R";
prog_char msg_10[] PROGMEM = "T1 On/Off R";
prog_char msg_11[] PROGMEM = "T2 On/Off R";
prog_char msg_12[] PROGMEM = "T3 On/Off R";
prog_char msg_13[] PROGMEM = "ADJ Hour On";
prog_char msg_14[] PROGMEM = "ADJ Minute On";
prog_char msg_15[] PROGMEM = "ADJ Hour Off";
prog_char msg_16[] PROGMEM = "ADJ Minute Off";
prog_char msg_17[] PROGMEM = "Set Sensitivity";
prog_char msg_18[] PROGMEM = "Set photocell R";
prog_char msg_19[] PROGMEM = "Set photocell O";
prog_char msg_20[] PROGMEM = "ADJ Time Minute";
prog_char msg_21[] PROGMEM = "ADJ Time Hour";
prog_char msg_22[] PROGMEM = "ADJ Date Day";
prog_char msg_23[] PROGMEM = "ADJ Date Month";
prog_char msg_24[] PROGMEM = "ADJ Date Year";
prog_char msg_25[] PROGMEM = "T4 On/Off R";
prog_char msg_26[] PROGMEM = "ADJ AC Mode";
prog_char msg_27[] PROGMEM = "AC Set Temp";
prog_char msg_28[] PROGMEM = "AC Switch Delay";
prog_char msg_29[] PROGMEM = "AC Seas 1 Start";
prog_char msg_30[] PROGMEM = "AC Seas 1 End";
prog_char msg_31[] PROGMEM = "AC Seas 2 Start";
prog_char msg_32[] PROGMEM = "AC Seas 2 End";
prog_char msg_33[] PROGMEM = "AC Seas 3 Start";
prog_char msg_34[] PROGMEM = "AC Seas 3 End";
prog_char msg_35[] PROGMEM = "AC Seas 4 Start";
prog_char msg_36[] PROGMEM = "AC Seas 4 End";
prog_char msg_37[] PROGMEM = "AC Off delay";
prog_char msg_38[] PROGMEM = "AC master byp";
prog_char msg_39[] PROGMEM = "AC Comp protect";
prog_char msg_40[] PROGMEM = "Initializing....";
prog_char msg_41[] PROGMEM = "Reading....";


//Creating the table for the stored menu messages
PROGMEM const char *msg_table[] = {
  msg_0,
  msg_1,
  msg_2,
  msg_3,
  msg_4,
  msg_5,
  msg_6,
  msg_7,
  msg_8,
  msg_9,
  msg_10,
  msg_11,
  msg_12,
  msg_13,
  msg_14,
  msg_15,
  msg_16,
  msg_17,
  msg_18,
  msg_19,
  msg_20,
  msg_21,
  msg_22,
  msg_23,
  msg_24,
  msg_25,
  msg_26,
  msg_27,
  msg_28,
  msg_29,
  msg_30,
  msg_31,
  msg_32,
  msg_33,
  msg_34,
  msg_35,
  msg_36,
  msg_37,
  msg_38,
  msg_39,
  msg_40,
  msg_41
};

//storing some special char's in the program memory
const byte char_table[] PROGMEM = {
  B01111110,                          //Arrow right
  B01111111,                          //Arrow left
  B00110000,                          //0
  B00111010,                          //seperator
  B00101110,                          //dott
  B00110001,                          //1
  B00110010,                          //2
  B00110011,                          //3
  B00110100,                          //4
  B00110101,                          //5
  B00110110,                          //6
  B00110111,                          //7
  B00111000,                          //8
  B00111001                           //9
};

//storing the main menu points in the program memory
prog_char menu_0[] PROGMEM = "Date/Time";
prog_char menu_1[] PROGMEM = "Sensitivity";
prog_char menu_2[] PROGMEM = "Room photo cut";
prog_char menu_3[] PROGMEM = "Room photo limit";
prog_char menu_4[] PROGMEM = "OS photo cut";
prog_char menu_5[] PROGMEM = "OS photo limit";
prog_char menu_6[] PROGMEM = "Room 1";
prog_char menu_7[] PROGMEM = "Room 2";
prog_char menu_8[] PROGMEM = "Room 3";
prog_char menu_9[] PROGMEM = "Room 4";
prog_char menu_10[] PROGMEM = "Room 5";
prog_char menu_11[] PROGMEM = "Room 6";
prog_char menu_12[] PROGMEM = "Room 7";
prog_char menu_13[] PROGMEM = "Room 8";
prog_char menu_14[] PROGMEM = "Room 9";
prog_char menu_15[] PROGMEM = "Room 10";
prog_char menu_16[] PROGMEM = "AC Setup";
prog_char menu_17[] PROGMEM = "AC 1";
prog_char menu_18[] PROGMEM = "AC 2";
prog_char menu_19[] PROGMEM = "AC 3";
prog_char menu_20[] PROGMEM = "AC 4";
prog_char menu_21[] PROGMEM = "Outside Lights";

PROGMEM const char *menu_table[] = {
  menu_0,
  menu_1,
  menu_2,
  menu_3,
  menu_4,
  menu_5,
  menu_6,
  menu_7,
  menu_8,
  menu_9,
  menu_10,
  menu_11,
  menu_12,
  menu_13,
  menu_14,
  menu_15,
  menu_16,
  menu_17,
  menu_18,
  menu_19,
  menu_20,
  menu_21
};

//storing the sub menu points in the program memory
prog_char submenu_0[] PROGMEM = "PIR delay R";
prog_char submenu_1[] PROGMEM = "HT1 Active R";
prog_char submenu_2[] PROGMEM = "Timer 1 R";
prog_char submenu_3[] PROGMEM = "HT2 Active R";
prog_char submenu_4[] PROGMEM = "Timer 2 R";
prog_char submenu_5[] PROGMEM = "HT3 Active R";
prog_char submenu_6[] PROGMEM = "Timer 3 R";
prog_char submenu_7[] PROGMEM = "HT4 Active R";
prog_char submenu_8[] PROGMEM = "Timer 4 R";
prog_char submenu_9[] PROGMEM = "Off Delay R";

PROGMEM const char *submenu_table[] = {
  submenu_0,
  submenu_1,
  submenu_2,
  submenu_3,
  submenu_4,
  submenu_5,
  submenu_6,
  submenu_7,
  submenu_8,
  submenu_9
};

//storing the ac setup menu
prog_char ac_setup_0[] PROGMEM = "AC Mode";
prog_char ac_setup_1[] PROGMEM = "Set Temp";
prog_char ac_setup_2[] PROGMEM = "Seasons";
prog_char ac_setup_3[] PROGMEM = "Switch Delay";
prog_char ac_setup_4[] PROGMEM = "Start Delay";

PROGMEM const char *ac_setup_table[] = {
  ac_setup_0,
  ac_setup_1,
  ac_setup_2,
  ac_setup_3,
  ac_setup_4
};

//storing the AC sub menu
prog_char ac_sub_0[] PROGMEM = "AC off delay R";
prog_char ac_sub_1[] PROGMEM = "AC Master byp R";
prog_char ac_sub_2[] PROGMEM = "AC ST1 Active R";
prog_char ac_sub_3[] PROGMEM = "AC Timer 1 R";
prog_char ac_sub_4[] PROGMEM = "AC ST2 Active R";
prog_char ac_sub_5[] PROGMEM = "AC Timer 2 R";
prog_char ac_sub_6[] PROGMEM = "AC ST3 Active R";
prog_char ac_sub_7[] PROGMEM = "AC Timer 3 R";
prog_char ac_sub_8[] PROGMEM = "AC ST4 Active R";
prog_char ac_sub_9[] PROGMEM = "AC Timer 4 R";

PROGMEM const char *ac_sub_table[] = {
  ac_sub_0,
  ac_sub_1,
  ac_sub_2,
  ac_sub_3,
  ac_sub_4,
  ac_sub_5,
  ac_sub_6,
  ac_sub_7,
  ac_sub_8,
  ac_sub_9
};

////////////////Error Handling/////////////
prog_char error_0[] PROGMEM = "RTC ERR";
prog_char error_1[] PROGMEM = "RTC Read ERR";
prog_char error_2[] PROGMEM = "EEPROM empty!";
prog_char error_3[] PROGMEM = "EEP write error";
  
PROGMEM const char *error_table[] = {
  error_0,
  error_1,
  error_2,
  error_3
};


void setup() {
   //////////////Start Serial for Debugging/////////////////////
   #ifdef DA_DEBUG_serial
     Serial.begin(9600);
   #endif
   lcd.begin(16, 2);
  
   lcd.clear();
   eepromValue = Mem_readByte(ID_ADDR);               //check if the eeprom holds valid data
   if(eepromValue != EEPROM_ID){
     get_error(2, 0);                                 //if not, display an error
     delay(5000);
     //load default var values                        //work with default variables declared 
                                                      //in the declaration section above
   }
   else{                                              //read the values from the eeprom
     sensitivity = Mem_readInt(Sensitivity_ADDR);     //sensitivity
     photoCellCutOff = Mem_readInt(photoCellCutOff_ADDR);  //photocell cut off value for rooms
     photoOutsideOff = Mem_readInt(photoOutsideOff_ADDR);  //photocell cut off value for outside
    
     for(int i=0; i<15; i++){                         //PIR and AC cut off delay times
       delayTime[i] = Mem_readInt(pgm_read_byte(&(delayTime_ADDR[i])));
     }

     for(int x=0; x<16; x++){                         //holiday lighting and ac timers active settings
       for(int y=0; y<4; y++){
         timer_active[x][y] = Mem_readByte(pgm_read_byte(&(timer_active_ADDR[x][y])));
       }
     }
          
     for(int x=0; x<16; x++){                         //holiday lighting and ac timer settings
       for(int y=0; y<4; y++){
         for(int z=0; z<4; z++){
           room_timers[x][y][z] = Mem_readByte(pgm_read_byte(&(room_timers_ADDR[x][y][z])));
         }
       }
     }
     
     for(int x=0; x<4; x++){                          //ac forced on setting
       for(int y=0; y<2; y++){
         ac_forced_on[x][y] = Mem_readByte(pgm_read_byte(&(ac_forced_on_ADDR[x][y])));
       }
     }
 
     for(int x=0; x<4; x++){                          //seasonal settings for ac use
       for(int y=0; y<2; y++){
         ac_periode[x][y] = Mem_readByte(pgm_read_byte(&(ac_periode_ADDR[x][y])));
       }
     }
     startDelay = Mem_readByte(startDelay_ADDR);      //ac start delay (compressor protection
     acSwitchDelay = Mem_readByte(acSwitchDelay_ADDR); //ac switch time for op mode 3
     ac_op_mode = Mem_readByte(ac_op_mode_ADDR);      //ac mode
     ac_set_temp = Mem_readByte(ac_set_temp_ADDR);    //ac temperature setting
   
     for(int i=0; i<4; i++){                          //ac master bypass
       ac_master_bypass[i] = Mem_readByte(pgm_read_byte(&(ac_master_bypass_ADDR[i])));
     }
   }
   
   //printing initialisation message
   lcd.clear();
   lcd.print(strcpy_P(buffer_M, (char*)pgm_read_word(&(msg_table[4]))));
   delay(1000);
   lcd.setCursor(0, 1);
   lcd.print(strcpy_P(buffer_M, (char*)pgm_read_word(&(msg_table[3]))));
   delay(2000);
   
   
 
     //////////////////defining pin modes////////////////////
   
   pinMode(doorMonitor, OUTPUT);        //setting the LED pin to output
   
   pinMode(setupMode, INPUT);           //setup switch to activate menu
   
   pinMode(latchPin, OUTPUT);  //setting the latch pin to output
   pinMode(clockPin, OUTPUT);  //setting the clock pin to output
   pinMode(dataPin, INPUT);  //setting the data pin to input
   
   pinMode(latchPinOut, OUTPUT);
   pinMode(clockPinOut, OUTPUT);
   pinMode(dataPinOut, OUTPUT);
   
}  

void loop() {
 
  ///////////////////checking the setup switch/////////////////////////
  while(digitalRead(setupMode) != 0){        //stay in here if activated

    lcd.clear();                             //clear display
    lcd.print(strcpy_P(buffer_M, (char*)pgm_read_word(&(msg_table[2]))));                 //print Setup mode
    delay(500);                              //small delay
    
    button_loop();                           //function call to monitore menu buttons
  }
  
   //////////////////////////////////////getting the input////////////////////////////////////////////////// 
   //Serial.print("switchVar1 first: ");
   //Serial.println(switchVar1, BIN);
   //Serial.print("switchVar2 first: ");
   //Serial.println(switchVar2, BIN);
   //Serial.print("switchVar3 first: ");
   //Serial.println(switchVar3, BIN);
   
   //pulse the latch pin, set to high to collect serial data
   digitalWrite(latchPin, HIGH);
   //give it chance to collect the data
   delayMicroseconds(25);
   //set latch pin to low to transmit data serially
   digitalWrite(latchPin, LOW);

   //while in serial mode, collect data into a byte
   switchVar1 = shiftIn(dataPin, clockPin);
   switchVar2 = shiftIn(dataPin, clockPin);
   switchVar3 = shiftIn(dataPin, clockPin);
   
   /////////////do something with the collected Data/////////////////////
   //checks for debugging
   #ifdef DA_DEBUG_in
     Serial.println();                       //debug only
     Serial.print("Switch variable 1: ");    //debug only
     Serial.println(switchVar1, BIN);        //debug only
     Serial.println("-------------------");  //debug only
     Serial.println();                       //debug only
     Serial.print("Switch variable 2: ");    //debug only
     Serial.println(switchVar2, BIN);        //debug only
     Serial.println("-------------------");  //debug only
     Serial.println();                       //debug only
     Serial.print("Switch variable 3: ");    //debug only
     Serial.println(switchVar3, BIN);        //debug only
     Serial.println("-------------------");  //debug only
   #endif
   ////////////loop through the 8 input pins to check their status////////////
     // (RRKM-01) shift register 1
     switchState[0]  = IIFi((switchVar1 &      (1)), ON, OFF); //checking S1
     switchState[1]  = IIFi((switchVar1 & (1 << 1)), ON, OFF); //checking S2
     switchState[2]  = IIFi((switchVar1 & (1 << 2)), ON, OFF); //checking S3
     switchState[3]  = IIFi((switchVar1 & (1 << 3)), ON, OFF); //checking S4
    
     switchState[7]  = IIFi((switchVar1 & (1 << 4)), ON, OFF); //checking S5, notice bit locations!!!
     switchState[6]  = IIFi((switchVar1 & (1 << 5)), ON, OFF); //checking S6
     switchState[5]  = IIFi((switchVar1 & (1 << 6)), ON, OFF); //checking S7
     switchState[4]  = IIFi((switchVar1 & (1 << 7)), ON, OFF); //checking S8
  
     // (RRKM-01) shift register 2
     switchState[8]  = IIFi((switchVar2 &      (1)), ON, OFF); //checking S9
     switchState[9]  = IIFi((switchVar2 & (1 << 1)), ON, OFF); //checking S10
     switchState[10] = IIFi((switchVar2 & (1 << 2)), ON, OFF); //checking S11
     switchState[11] = IIFi((switchVar2 & (1 << 3)), ON, OFF); //checking S12
    
     switchState[15] = IIFi((switchVar2 & (1 << 4)), ON, OFF); //checking S13, same here!!!
     switchState[14] = IIFi((switchVar2 & (1 << 5)), ON, OFF); //checking S14
     switchState[13] = IIFi((switchVar2 & (1 << 6)), ON, OFF); //checking S15
     switchState[12] = IIFi((switchVar2 & (1 << 7)), ON, OFF); //checking S16
    
     // (RRKM-01) shift register 3
     switchState[16] = IIFi((switchVar3 &      (1)), ON, OFF); //checking S17
     switchState[17] = IIFi((switchVar3 & (1 << 1)), ON, OFF); //checking S18
     switchState[18] = IIFi((switchVar3 & (1 << 2)), ON, OFF); //checking S19
     switchState[19] = IIFi((switchVar3 & (1 << 3)), ON, OFF); //checking S20
     
     switchState[20] = IIFi((switchVar3 & (1 << 4)), ON, OFF); //checking S21
     switchState[21] = IIFi((switchVar3 & (1 << 5)), ON, OFF); //checking S22
     switchState[22] = IIFi((switchVar3 & (1 << 6)), ON, OFF); //checking S23

   
  //////////////Debug Statements//////////////////////////////////
     #ifdef DA_DEBUG_in  // (RRKM-01) Only when debugging
       for(int x=0; x<23; x++) {
         Serial.println( "Status of Switch S" + String(x+1) + ": " +
                         IIFs((switchState[x] == ON), "ON", "OFF" )
                         );
       }
     #endif
   //////////////////checking the light status (photo cell)//////////////////////
  
    sensorValue = 0; 
    int reading = 0;                                  //the readings
     for(int i=0; i<15; i++){                         //take 15 readings
      reading += analogRead(lightSensor);
    }
    //average the readings
    sensorValue = reading / 15;
   //Serial.print("Sensor value: ");
   //Serial.println(sensorValue);
   
   ///////////////Checking the room temperature/////////////
    int temp1 = 0;               //var to take the readings
    for(int i=0; i<15; i++){     //take 15 readings for a stable output
      temp1 += map(analogRead(TMP01),0,410,-40,125);
    }
    temperatur1 = temp1/15;      //average the readings
    #ifdef DA_DEBUG_tmp          //check the output
      Serial.print("Current Temperatur: ");
      Serial.println(temperatur1);
    #endif
   
  
   //////////////////processing the input/////////////////////
  if(RTC.read(tm)) {             //Reading the clock
    currentHour = tm.Hour;       //passing the time into a var
    currentMinute = tm.Minute;   //passing the time into a var
    currentDay = tm.Wday - 1;        //passing Weekday 
                                 //(Mon - Sun eg 1-7) into var
    currentDoM = tm.Day;         //passing day in to var (1-31)
    currentMonth = tm.Month;     //passing month into var (1-12)
    currentYear = tmYearToCalendar(tm.Year); //passing year to var
    
  }
  else {
    get_error(0, 1);
  }
  
  endTime = (millis()/1000) - displayTimeSet;
  if(endTime <= 15) displayDateTime();
  if(endTime > (15) && endTime <= (30)) displayTemp();
  if(endTime > 30) displayTimeSet = millis()/1000;
  
  
  
  photocellSwitch = getSensorValue(sensorValue, photoCellCutOff, 
                                   photoCellCutOn, photocellSwitchOld);
  photocellSwitchOld = photocellSwitch;
  //allowing the lights to switch on between 17:00 and 23:00 h
  if(photocellSwitch == 1 && currentHour >= 17 && currentHour <= 23) {
    for(int i=0; i<10; i++){
      lightLevel[i] = 1;
    }
    lightLevel[15] = 1;
  }
  //allowing the lights to switch on between 00:00 and 08:00 h
  else if(photocellSwitch == 1 && currentHour >= 0 && currentHour <= 8){
    for(int i=0; i<10; i++){
      lightLevel[i] = 1;
    }
    lightLevel[15] = 1;
  }
  //make sure the lights switch off on sunrise during morning hours
  else if(photocellSwitch == 0 && currentHour >= 5 && currentHour <= 8){
    for(int c=0; c<17; c++){
      lightLevel[c] = 0;
    }
  }
  
  #ifdef DA_DEBUG_photo
    Serial.print("Photo cell switch: ");
    Serial.println(photocellSwitch);
    for(int c=0; c<17; c++){
      Serial.print("Light level ");
      Serial.print(c);
      Serial.print(" :");
      Serial.println(lightLevel[c]);
    }
  #endif      
    
  //////////////Holiday lighting/////////////////////////
    
  if(switchState[20] == 1) {       //check if the holliday switch
                                   //is activated
    lightOutput[14] = 0;           //make sure the master  relay is off
    
    ///////////////loop through all the lights///////////////
    for(int x=0; x<16; x++){
      if(x >= 0 && x < 10 | x == 15){
        for(int i=0; i<4; i++){
          
          if(timer_active[x][i] == 1 && currentHour >= room_timers[x][i][0] && 
             currentHour <= (room_timers[x][i][2] + 1)){ //checking if we came passed
                                                 //the hour where the lights
                                                 //to be switched on                                    
            //checking the times                              
            roomLight[x] = checkOnTime(room_timers[x][i][0], room_timers[x][i][1], 
                                      room_timers[x][i][2], room_timers[x][i][3]);
          }
        } 
        if(roomLight[x] == 1 && lightLevel[x] == 1){   //if with in the on time
          lightOutput[x] = outputValues[x];           //switch on the lights
        }
        else {
          lightOutput[x] = 0;           //other keep them off
          lightLevel[x] = 0;
        }
      }
    }
     
     #ifdef DA_DEBUG_holtimers
       for(int x=0; x<16; x++){
         for(int y=0; y<4; y++){
           Serial.print("Room ");
           Serial.print(x);
           Serial.print(": ");
           Serial.println(timer_active[x][y]);
           Serial.print("Room ");
           Serial.print(x);
           Serial.print(" Lights: ");
           Serial.println(room1Light[x]);
         }
       }
     #endif
 
  }  
  else {
      
     ////////Outside lights////////////////////
     for(int i=0; i<4; i++){
       if(timer_active[15][i] == 1){
         roomLight[15] = checkOnTime(room_timers[15][i][0], room_timers[15][i][1], 
                                        room_timers[15][i][2], room_timers[15][i][3]);
       }
       if(roomLight[15] == 1) break;    
     }
     if(roomLight[15] == 1 && lightLevel[15] == 1){
         lightOutput[15] = outputValues[15];
     }
     else{
       lightOutput[15] = 0;
       lightLevel[15] = 0;
     }

     //////////////////room lights//////////////////////////////
         
      lightStatus[16] = check_master(0);                 //check if doorswitch was activated room 1 (bed1)
     
      lightOutput[0] = check_light_P(0, 1, 0, 1);        //check status room 1 (bed 1)
      delay(5);
      lightStatus[16] = check_master(2);                 //check if doorswitch was activated room 2 (bed 2)
     
      lightOutput[1] = check_light_P(2, 3, 1, 2);       //check status room 2 (bed 2)
      delay(5);
      lightStatus[16] = check_master(4);                 //check if doorswitch was activated room 3 (bed 3)
      
      lightOutput[2] = check_light_P(4, 5, 2, 4);       //check status room 3 (bed 3)
      delay(5);
      lightStatus[16] = check_master(6);                 //check if doorswitch was activated room 4 (living)
     
      lightOutput[3] = check_light_P(6, 7, 3, 8);       //check status room 4 (living)
      delay(5);
      lightStatus[16] = check_master(8);                 //check if doorswitch was activated room 5 (bath 1)
      
      lightOutput[4] = check_light_N(8, 4, 16);         //check status room 5 (bath 1)
      delay(5);
      lightStatus[16] = check_master(9);                 //check if door switch was activated room 6 (bath 2)
      
      lightOutput[5] = check_light_N(9, 5, 32);
      delay(5);
      lightStatus[16] = check_master(10);
    
      lightOutput[6] = check_light_N(10, 6, 64);
      delay(5);
      lightStatus[16] = check_master(11);  
      
      lightOutput[7] = check_light_N(11, 7, 128);
      delay(5);
      lightStatus[16] = check_master(12); 
      
      lightOutput[8] = check_light_N(12, 8, 256);
      delay(5);
      lightStatus[16] = check_master(13);
    
      lightOutput[9] = check_light_N(13, 9, 512);
  
  /////////////////////Ac Read Switches////////////////////////
    #ifdef DA_DEBUG_ac
      for(int i=10; i<14; i++){
        Serial.print("light output before ");
        Serial.print(i);
        Serial.print(": ");
        Serial.println(lightOutput[i]);
        Serial.print("output Value: ");
        Serial.println(outputValues[i]);
        Serial.print("Light Status before ");
        Serial.print(i);
        Serial.print(": ");
        Serial.println(lightStatus[i]);
      }
    #endif
     
    lightOutput[10] = ac_read(14, 10);
    delay(5);
    lightOutput[11] = ac_read(15, 11);
    delay(5);
    lightOutput[12] = ac_read(16, 12);
    delay(5);
    lightOutput[13] = ac_read(17, 13);

    #ifdef DA_DEBUG_ac
      for(int i=10; i<14; i++){
        Serial.print("light output after ");
        Serial.print(i);
        Serial.print(": ");
        Serial.println(lightOutput[i]);
        Serial.print("output Value: ");
        Serial.println(outputValues[i]);
        Serial.print("Light Status after ");
        Serial.print(i);
        Serial.print(": ");
        Serial.println(lightStatus[i]);
      }
    #endif
    
      /////////////Door switch control ////////////////////
    //Serial.print("switchState 18 :");
    //Serial.println(switchState[18]);
    //Serial.print("Switch state old: ");
    //Serial.println(masterSwitchStateOld);
    //Serial.print("Light status 16: ");
    //Serial.println(lightStatus[16]);
      
    if(switchState[18] != masterSwitchStateOld) {               //door switch check if the switch state
                                                                //has changed
      //Serial.println("Door switch was activated");            //debug only
      currentTime = millis()/1000;                              //setting time reference
      lightStatus[16] = 1;                                      //setting light status
      digitalWrite(doorMonitor, HIGH);                          //setting the control LED
      for(int i=0; i<17; i++){                                  //looping through the timers
        roomTimer[i] = currentTime;                             //setting the timers
      }
    }
    else if(switchState[18] == masterSwitchStateOld && lightStatus[16] == 1){ //if the switch state
                                                                //has not changed and the lights are on
      //Serial.println("Checking off status");                    //debug only
      currentTime = millis()/1000;                                   //setting the time reference
      offTime = roomTimer[16] + delayTime[14];                  //setting the allowed delay time
      //Serial.print("off Time: ");
      //Serial.println(offTime);
      //Serial.print("current Time: ");
      //Serial.println(currentTime);
      if(currentTime >= offTime) {                              //comparing the times
        for(int c=0; c<17; c++) {                               //looping through the circuits
          if(roomTimer[c] != roomTimer[16]) {                   //comparing timers
            mainOff = 1;                                        //setting the switch off all command
            lightStatus[16] = 0;                                //switching off the master relay
          }
          else {
            mainOff = 0;                                        //if the timers match we set the 
                                                                //switch off all command to 0
            break;                                              //leaving the loop
          }
        }
      }
      //Serial.print("Main off: ");
      //Serial.println(mainOff);
      if(mainOff == 0) {                                        //master off command is 0
        //Serial.println("switching off everything and reset all"); //debug only
        for(int i=0; i<17; i++) {                               //looping through the circuits
          lightStatus[i] = 0;                                   //resetting all light status
          lightOutput[i] = 0;                                   //switching off all lights
          priorityStatus[i] = 0;                                //resetting all set priorities
          roomTimer[i] = 0;                                     //resetting all room timers
        }
        digitalWrite(doorMonitor, LOW);                         //resetting the control LED
        mainOff = 1;                                            //resetting master off command
      }
    }
    masterSwitchStateOld = switchState[18];                     //setting the switchState to old
  }  
  ///////////////////////////Output/////////////////////////////////////////////////
  
  for(int i=0; i<17; i++) {                                //loop through the light output array
    #ifdef DA_DEBUG_out
      Serial.print("Light Output ");                        //debug only
      Serial.print(i);                                      //debug only
      Serial.print(": ");                                   //debug only
      Serial.println(lightOutput[i]);                       //debug only
      Serial.print("Light status: ");                       //debug only
      Serial.println(lightStatus[i]);                       //debug only
      Serial.print("Room Timer: ");                         //debug only
      Serial.println(roomTimer[i]);                         //debug only
      delay(100);
    #endif
    outputL += lightOutput[i];                            //adding up the numbers
  }
  
  if(switchState[19] == 1) {              //if maintenance switch is active
    for(int i=0; i>17; i++){             //loop through all circuits
      lightStatus[i] = 1;                //setting the light status of everything
      roomTimer[i] = millis()/1000;           //setting all the room timers
    }
    outputL = 65535;                     //setting the output 
                                         //binary 1111111111111111
  }  
  
  lcd.setCursor(0,0);
  //lcd.print(outputL, BIN);
   printBinary16(outputL);
  
  
  #ifdef DA_DEBUG_out
    Serial.print("Output value: ");
    Serial.print(outputL);
    Serial.print("   ");
    Serial.println(outputL, BIN);
  #endif
  digitalWrite(latchPinOut, LOW);                   //setting the latch pin to low to
                                                    //be able to send the data
  shiftOut(dataPinOut, clockPinOut, MSBFIRST, (outputL >> 8)); //sending the date for the 
                                                               //second shift register
  shiftOut(dataPinOut, clockPinOut, MSBFIRST, outputL);        //sending the data for the
                                                               //first shift register
  digitalWrite(latchPinOut, HIGH);                  //setting the latch pin back to
                                                    //high to finish the data transmission
  //outputOld = outputL;
  outputL = 0;                                      //setting the var holding the output 
                                                    //number back to 0 
  delay(sensitivity);                               //delay to adjust how responsive the
                                                    //system will react
  
}

//function to keep a 16 digit (bit) display
void printBinary16(unsigned int iIn)  {
  //                       0b1234567812345678
  for (unsigned int mask = 0b1000000000000000; mask; mask >>= 1) { //create a bit mask
    if (mask & iIn) {      //add the incoming data
      lcd.print('1');      //print if active
    }
    else {
      lcd.print('0');      //if empty, still print the 0
    }
  }
}

//function to display date and time
void displayDateTime(){
  lcd.setCursor(0, 1);             //set cursor to row 2 pos 1
  lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(weekday_table[currentDay]))));
  lcd.print(" ");
  if(currentDoM < 10) lcd.write(pgm_read_byte(&char_table[2]));  //print 0
  lcd.print(currentDoM);
  lcd.write(pgm_read_byte(&char_table[4]));   //print dott
  if(currentMonth < 10) lcd.write(pgm_read_byte(&char_table[2]));  //print 0
  lcd.print(currentMonth);
  lcd.print(" ");
  if(currentHour < 10) lcd.write(pgm_read_byte(&char_table[2]));  
                                   //if the hour is less than 10
                                   //we print a 0 to keep 2 digits
  lcd.print(currentHour);          //print current time (hour)
  lcd.write(pgm_read_byte(&char_table[3]));   //print seperator
  if(currentMinute < 10) lcd.write(pgm_read_byte(&char_table[2]));  
                                   //if the minute is less than
                                   //10 print 0 to keep 2 digits
  lcd.print(currentMinute);        //print current time (minutes)
  lcd.print(" ");
}

//function to display temperature and light reading
void displayTemp() {
  lcd.setCursor(0, 1);    //set cursor column 0 row 1
  lcd.print("T ");        //print T for temerature
  lcd.print(temperatur1); //print the reading
  lcd.print(" C");        //print C for Celsius
  lcd.print(" ");         //print a space
  lcd.print("L ");        //print L for light
  lcd.print(map(sensorValue, 0, 1023, 0, 100000)); //convert the photocell reading to lux
  if(map(sensorValue, 0, 1023, 0, 100000) < 10000) lcd.print(" "); //print a space if below 10000
  lcd.print(" L");        //print L for Lux
}

////////////////Shift In Function for Input processing ////////////

byte shiftIn(int myDataPin, int myClockPin) {
  int i;
  int temp = 0;
  int pinState;
  byte myDataIn = 0;
  
  pinMode(myClockPin, OUTPUT);
  pinMode(myDataPin, INPUT);
  
  for(i=7; i>=0; i--) {
    digitalWrite(myClockPin, LOW);
    delayMicroseconds(2);
    temp = digitalRead(myDataPin);
    if(temp) {
      pinState = 1;
      myDataIn = myDataIn | (1 << i);
    }
    else {
      pinState = 0;
    }
    //Serial.print("PinState: ");    //debug only
    //Serial.print(pinState);        //debug only
    //Serial.print("        ");      //debug only
    //Serial.println(myDataIn, BIN); //debug only
    
    digitalWrite(myClockPin, HIGH);
  }
  //Serial.println();                //debug only
  //Serial.println(myDataIn, BIN);   //debug only
  return myDataIn;
}


////////////function to check timer/////////
byte checkOnTime(byte hourOn, byte minuteOn, byte hourOff, byte minuteOff){
  tmElements_t tm;
  byte onTime = 0;
  unsigned long timeNow = 0;
  unsigned long onTrigger = 0;
  unsigned long offTrigger = 0;
  
  if(RTC.read(tm)){ 
    
    timeNow = tmConvert_t(tmYearToCalendar(tm.Year), tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second);
    
    onTrigger = tmConvert_t(tmYearToCalendar(tm.Year), tm.Month, tm.Day, hourOn, minuteOn, 0);
    
    if(hourOff < hourOn) {
      offTrigger = tmConvert_t(tmYearToCalendar(tm.Year), tm.Month, tm.Day+1, hourOff, minuteOff, 0);
    }
    else {
      offTrigger = tmConvert_t(tmYearToCalendar(tm.Year), tm.Month, tm.Day, hourOff, minuteOff, 0);
    }
    if(timeNow >= onTrigger && timeNow < offTrigger) {
      onTime = 1;
    }
    else {
      onTime = 0;
    }
  }
  //Serial.print("   Time now: ");
  //Serial.println(timeNow);
  //Serial.print(" On trigger: ");
  //Serial.println(onTrigger);
  //Serial.print("Off Trigger: ");
  //Serial.println(offTrigger);
  return onTime;
}

/////function to convert real time to unix timne////////
time_t tmConvert_t(int YYYY, byte MM, byte DD, byte hh, byte mm, byte ss){
  tmElements_t tmSet;
  tmSet.Year = YYYY - 1970;
  tmSet.Month = MM;
  tmSet.Day = DD;
  tmSet.Hour = hh;
  tmSet.Minute = mm;
  tmSet.Second = ss;
  return makeTime(tmSet);         //convert to time_t
}

byte getSensorValue(int sensorReading, int switchValue, 
                    int switchLimit, byte switchStatus){
  byte onStatus = 0;
  
  if(switchStatus == 0){
    if(sensorReading <= switchValue){
      onStatus = 1;
    }
    else if(sensorReading > switchLimit){
      onStatus = 0;
    }
    else if(sensorReading > switchValue &&
            sensorReading <= switchLimit){
      onStatus = 0;
    }
  }
  else if(switchStatus == 1){
    if(sensorReading <= switchValue){
      onStatus = 1;
    }
    else if(sensorReading > switchValue &&
            sensorReading <= switchLimit){
      onStatus = 1;
    }
    else if(sensorReading > switchLimit){
      onStatus = 0;
    }
  }
  return onStatus;
} 

byte check_master(byte swNo){
  if(switchState[swNo] == 1 && lightStatus[16] == 1) {         //checking if PIR with switch Number  was
                                                               //activated (bed 1)
     lightStatus[16] = 0;                                      //resetting master off
     digitalWrite(doorMonitor, LOW);                           //resetting the door Monitor LED
  }
  //else {
    //lightStatus[16] = 1;
 // }
  return lightStatus[16];
}

boolean allTimer(unsigned long timeSet, unsigned int timeLimit){
  currentTime = millis()/1000;
  endTime = currentTime - timeSet;
  if(endTime >= timeLimit){
    return true;
  }
  else{
    return false;
  }
}

unsigned long check_light_P(byte pir, byte prio, byte room, unsigned long light){
  if(switchState[prio] == 0 && sensorValue <= photoCellCutOff) {  //checking if S2 priority off was
      if(switchState[pir] == 1 && priorityStatus[room] == 0) {    //check if the PIR in bed 1 was
                                                                  //activated and no priority was set
         //Serial.println("We switch in the lights in bedroom 1");//Debug only
         lightOutput[room] = light;                               //switching on the lights – binary
         lightStatus[room] = 1;                                   //setting the light status for bed 1
         lightOutput[14] = 16384;                                 //make sure the master relay
                                                                  //stays on
         lightStatus[14] = 1;                                     //setting the master yelay status
         roomTimer[room] = millis()/1000;                         //setting the timer
      }
      else if(switchState[pir]  == 0 && lightStatus[room] == 1) { //the PIR not activated but the
                                                                  //lights are on        
         if(allTimer(roomTimer[room], delayTime[room])){          // check allowed delay time
            //Serial.println("Time is up switching off the lights");  //Debug only
            lightOutput[room] = 0;                                //switching off the lights
            lightStatus[room] = 0;                                //resetting the light status
            roomTimer[room] = 0;                                  //resetting the room timer
         }
      }
   }
   else if(switchState[prio] == 1 && lightStatus[room] == 1
           && switchStateOld[room] != 1) {                         //if priority is activated and the
                                                                    //lights are on
      //Serial.println("Priority switch activated switching off the lights");  //Debug only
      lightOutput[room] = 0;                                        //switching off the lights
      lightStatus[room] = 0;                                        //resetting the light status
      roomTimer[room] = 0;                                          //resetting the room timer
      priorityStatus[room] = 1;                                     //setting the priority status bed 1
   }
   else if(switchState[prio] == 1 && lightStatus[room] == 0
           && switchStateOld[room] != 1) {                         //if priority was activated and the 
                                                                    //lights are off
      //Serial.println("Priority switch deactivated switching on the lights");    //Debug only
      lightOutput[room] = light;                                    //switching on the lights
      lightStatus[room] = 1;                                        //setting the light status
      roomTimer[room] = millis()/1000;                              //setting the room timer
      priorityStatus[room] = 0;                                     //setting the priority for bed 1 back                                                                  //to 0
   }
   switchStateOld[room] = switchState[prio];                       //passing on the switch state
   return lightOutput[room];
}

unsigned long check_light_N(byte pir, byte room, unsigned long light){
  if(switchState[pir] == 1) {                                     //checking passed on PIR (byte pir)
                                                                  //of passed on room (byte room)
    //Serial.println("We switch on the lights");                  //Debug only
    lightOutput[room] = light;                                    //switching on the lights
    lightStatus[room] = 1;                                        //setting the light status
    lightOutput[14] = 16384;                                      //make sure the master relay
                                                                  //stays on
    lightStatus[14] = 1;                                          //setting the master relay status
    roomTimer[room] = millis()/1000;                              //setting the room timer
  }
  else if(switchState[pir] == 0 && lightStatus[room] == 1) {      //if no PIR was activated and 
                                                                  //the lights are on
    if(allTimer(roomTimer[room], delayTime[room])){               //check if the time limit is reached
      //Serial.println("We are switching off the lights");        //debug only 
      lightOutput[room] = 0;                                      //switching off the lights
      lightStatus[room] = 0;                                      //resetting the light status
      roomTimer[room] = 0;                                        //resetting the room timer
    }
  }
  return lightOutput[room];
}

unsigned long ac_read(byte readSw, byte room){
  byte periode = get_ac_periode();        //function call to check time periode (season)
  //check if a forced switch on is defined and the set temperature
  if(ac_forced_on[room-10][0] != 99 && checkOnTime(room_timers[room][periode][0], room_timers[room][periode][1],
                                                   room_timers[room][periode][2], room_timers[room][periode][3]) == 1 &&
     temperatur1 >= ac_set_temp){
     priorityStatus[room] = 1;            //set priority status to 1 if yes
  }
  else{
     priorityStatus[room] = 0;            //set priority status to 0 if no
  }
  if(ac_op_mode == 1){
    if(switchState[readSw] == 1 && lightStatus[14] == 1 && startDelay == 1){       //Checking if readswitches are activated                        
                                                                  //and the master relay is on AC 
      if(allTimer(lastRun[room - 10], 480)){                      //check if 8 minute lock is passed since last run
        lightOutput[room] = outputValues[room];                   //providing the ability to
                                                                  //switch on the AC
        lightStatus[room] = 1;                                    //setting the light (AC) status
        roomTimer[room] = millis()/1000;                          //setting the timer
        lastRun[room - 10] = 0;
      }
      else{
        lightOutput[room] = 0;                                  //canceling ability to switch on the 
                                                                //AC
        lightStatus[room] = 0;                                  //resetting the light (AC) status
        roomTimer[room] = 0;   
      }
    }
    else if(switchState[readSw] == 1 && lightStatus[14] == 1 && startDelay == 0){
      lightOutput[room] = outputValues[room];                  //providing the ability to
                                                               //switch on the AC
      lightStatus[room] = 1;                                   //setting the light (AC) status
      roomTimer[room] = millis()/1000;                         //setting the timer
      lastRun[room - 10] = 0;
    }
    else if(switchState[readSw] == 0 && lightStatus[14] == 1){  //if a door is opened and the master
                                                                //relay is on
      if(allTimer(roomTimer[room], delayTime[room])){           //checking the time limit
        lightOutput[room] = 0;                                  //canceling ability to switch on the 
                                                                //AC
        lightStatus[room] = 0;                                  //resetting the light (AC) status
        roomTimer[room] = 0;                                    //resetting the timer
        lastRun[room - 10] = millis()/1000;
      }
    }
    return lightOutput[room];
  }
  else if(ac_op_mode == 2){
    if(ac_master_bypass[room - 10] == 0){                                                //check if the master bypass is set
      if(switchState[readSw] == 1 && lightStatus[14] == 1 && startDelay == 1){           //Checking if readswitches are activated
        if(checkOnTime(room_timers[room][periode][0], room_timers[room][periode][1],     //checking if AC is allowed to run
                       room_timers[room][periode][2], room_timers[room][periode][3]) == 1){
          if(allTimer(lastRun[room - 10], 480)){                                         //check if 8 minute lock is passed since last run
            lightOutput[room] = outputValues[room]; //switch on the AC                                                                                           
            lightStatus[room] = 1;                  //setting the light (AC) status
            roomTimer[room] = millis()/1000;        //setting the timer
            lastRun[room - 10] = 0;
          }
          else{
            lightOutput[room] = 0;                  //keep it off                                                                              
            lightStatus[room] = 0;           
          } 
        }
      }
      else if(switchState[readSw] == 1 && priorityStatus[room] == 1 && startDelay == 1){          //if doors and windowa are closed and priority is set
        if(currentHour >= ac_forced_on[room-10][0] && currentMinute >= ac_forced_on[room-10][1]){ //check if it's time to start
          if(allTimer(lastRun[room - 10], 480)){                                                  //check if 8 minute lock is passed since last run
            lightOutput[room] = outputValues[room]; //switch on the AC                                                                                           
            lightStatus[room] = 1;                  //setting the light (AC) status
            roomTimer[room] = millis()/1000;        //setting the timer
            lastRun[room - 10] = 0;
          }
          else{
            lightOutput[room] = 0;            //keep it off                                                                              
            lightStatus[room] = 0;           
          } 
        }
        else{
          lightOutput[room] = 0;            //keep it off
          lightStatus[room] = 0;            //setting the light (AC) status
          roomTimer[room] = 0;              //resetting the room timer
        }
      }
      if(switchState[readSw] == 1 && lightStatus[14] == 1 && startDelay == 0){
        if(checkOnTime(room_timers[room][periode][0], room_timers[room][periode][1],     //checking if AC is allowed to run
                       room_timers[room][periode][2], room_timers[room][periode][3]) == 1){   
          lightOutput[room] = outputValues[room]; //switch on the AC                                                                                           
          lightStatus[room] = 1;                  //setting the light (AC) status
          roomTimer[room] = millis()/1000;        //setting the timer
          lastRun[room - 10] = 0;     
        }
      }
      else if(switchState[readSw] == 1 && priorityStatus[room] == 1 && startDelay == 0){
        if(checkOnTime(room_timers[room][periode][0], room_timers[room][periode][1],     //checking if AC is allowed to run
                       room_timers[room][periode][2], room_timers[room][periode][3]) == 1){   
          lightOutput[room] = outputValues[room]; //switch on the AC                                                                                           
          lightStatus[room] = 1;                  //setting the light (AC) status
          roomTimer[room] = millis()/1000;        //setting the timer
          lastRun[room - 10] = 0;     
        }
      }
      else if(switchState[readSw] == 0 && lightStatus[14] == 1){   //if a door is opened and the master
                                                                   //relay is on
                                                                   //delay time
        if(allTimer(roomTimer[room], delayTime[room])){            //checking the time limit
          lightOutput[room] = 0;                                   //canceling ability to switch on the 
                                                                   //AC
          lightStatus[room] = 0;                                   //resetting the light (AC) status
          roomTimer[room] = 0;                                     //resetting the timer
          lastRun[room - 10] = millis()/1000;
        }
      }
    }
    else if(ac_master_bypass[room - 10] == 1){                //if master relay bypass is on
      if(switchState[readSw] == 1  && startDelay == 1){       //Checking if readswitches are activated
        if(checkOnTime(room_timers[room][periode][0], room_timers[room][periode][1],      
                       room_timers[room][periode][2], room_timers[room][periode][3]) == 1 &&
           temperatur1 >= ac_set_temp){
                                                              
          if(allTimer(lastRun[room - 10], 480)){    //check if 8 minute lock is passed since last run
            lightOutput[room] = outputValues[room]; //switch on the AC                                                                                           
            lightStatus[room] = 1;                  //setting the light (AC) status
            roomTimer[room] = millis()/1000;        //setting the timer
            lastRun[room - 10] = 0;
          }
          else{
            lightOutput[room] = 0;                 //keep it off                                                                              
            lightStatus[room] = 0;           
          }
        }
      }
      else if(switchState[readSw] == 1  && startDelay == 0){ 
              lightOutput[room] = outputValues[room];       //switch on the AC                                                                                           
        lightStatus[room] = 1;                              //setting the light (AC) status
        roomTimer[room] = millis()/1000;                    //setting the timer
        lastRun[room - 10] = 0;
      }
      else if(switchState[readSw] == 0){                    //if a door is opened and the master
                                                            //relay is on
                                                            //delay time
        if(allTimer(roomTimer[room], delayTime[room])){     //checking the time limit
          lightOutput[room] = 0;                            //canceling ability to switch on the 
                                                            //AC
          lightStatus[room] = 0;                            //resetting the light (AC) status
          roomTimer[room] = 0;                              //resetting the timer
          lastRun[room - 10] = millis() / 1000;
        }
      }
    }
    return lightOutput[room];
  }
  else if(ac_op_mode == 3){                       //AC operating mode 3
    lightOutput[room] = 0;                        //Setting the lightOutput to 0
    if(startDelay == 1){
      if(roomLight[room] == 1 && lastRun[room - 10] == 0){ //if a "on" command was given and the time since last run is more than 8 minutes
      
        if(allTimer(roomTimer[room], acSwitchDelay)){   
          lightStatus[room] = 1;                    //set AC status to on
          roomLight[room] = 0;                      //cancel "on" command
          return 0;                                 //return 0
        }
        else{
          return outputValues[room]; //pulse the switch while "on" command active
        }
      }
      if(roomLight[room] == 1 && lastRun[room - 10] != 0){  //if a "on" command was given and the time since last run is less than 8 minutes
        if(allTimer(lastRun[room - 10], 480)) lastRun[room - 10] = 0;
        return 0;                                          //return 0
      }
    }
    if(startDelay == 0){
      if(roomLight[room] == 1){ //if a "on" command was given 
      
        if(allTimer(roomTimer[room], acSwitchDelay)){   
          lightStatus[room] = 1;                    //set AC status to on
          roomLight[room] = 0;                      //cancel "on" command
          return 0;                                 //return 0
        }
        else{
          return outputValues[room];                //pulse the switch while "on" command active
        }
      }
    } 
    if(roomLight[room] == 2){                     //if an "off" command was given check delay timer
                                                  //check if it matches allowed difference
      if(allTimer(roomTimer[room], delayTime[room])){  
        roomLight[room] = 3;                      //final command to switch off
        return 0;                                 //return 0
      }
      else{
        roomLight[room] = 2;                      //keep the status
        return 0;                                 //return 0
      }
    }
    if(roomLight[room] == 3){                     //final off command given
      if(allTimer(roomTimer[room], acSwitchDelay)){  
        lightStatus[room] = 0;                    //reset command status
        roomLight[room] = 0;                      //reset AC status
        lastRun[room - 10] = millis()/1000;       //set swith off time
        return 0;                                 //return 0
      }
      else{
        return outputValues[room]; //pulse the switch
      }
    }
      
    if(ac_master_bypass[room-10] == 0){
      if(lightStatus[room] == 0 && roomLight[room] == 0){
        if(switchState[readSw] == 1 && lightStatus[14] == 1 && 
           temperatur1 >= ac_set_temp && priorityStatus[room] == 0){
          if(checkOnTime(room_timers[room][periode][0], room_timers[room][periode][1],     //checking if AC is allowed to run
                         room_timers[room][periode][2], room_timers[room][periode][3]) == 1){
            roomLight[room] = 1;
            roomTimer[room] = millis()/1000;
            return 0;
          }
          else {
            return 0;
          }
        }
        if(switchState[readSw] == 1 && priorityStatus[room] == 1 &&
           temperatur1 >= ac_set_temp){
          if(currentHour >= ac_forced_on[room-10][0] && 
             currentMinute >= ac_forced_on[room-10][1]){ //check if it's time to start
            roomLight[room] = 1;
            roomTimer[room] = millis()/1000;
            return 0;
          }
          else {
            return 0;
          }
        }
      }
      if(lightStatus[room] == 1 && roomLight[room] == 0){
        if(currentHour == room_timers[room][periode][2] &&   //if the allowed running limit is reached
           currentMinute >= room_timers[room][periode][3]){
          roomLight[room] = 2;
          roomTimer[room] = millis()/1000;
          return 0;
        }
        else{
          return 0;
        }
        if(priorityStatus[room] == 1 &&  switchState[readSw] == 0){
          roomLight[room] = 2;
          roomTimer[room] = millis()/1000;
          return 0;  
        }
        else{
          return 0;
        }
        if(priorityStatus[room] == 0){
          if(switchState[readSw] == 0 | lightStatus[14] == 0){
            roomLight[room] = 2;
            roomTimer[room] = millis()/1000;
            return 0;
          }
          else{
            return 0;
          }
        }
      }
    }
  }
  return 0;
}

//function to return the current time periode of the year
byte get_ac_periode(){
  int i = 0;             //declare the counter
  for(i=0; i<4; i++){    //loop through the array
    //and compare the settings with the current month
    //if the current month is found with in a defined 
    //limit break the loop and return the counter at the moment of breaking
    if(currentMonth >= ac_periode[i][0] && currentMonth <= ac_periode[i][1]) break;
  }
  return i;  //return the counter
}



int read_act_buttons(){
  act_key_in = analogRead(1);      //reading the sensor
  delay(250);                      //button debounce delay
  //Readings centered at 170 for menu
  //203 for search and 252 for select
  #ifdef DA_DEBUG_btnReadings
    Serial.print("Reading: ");
    Serial.println(act_key_in);
  #endif
  if(act_key_in < 160) return btnNone; //most likely result first
  //adding a range of +/- 10 to compensate for bouncing
  //readings
  if(act_key_in > 158 && act_key_in < 188) return btnMenu;  
  if(act_key_in > 195 && act_key_in < 225) return btnSearch;
  if(act_key_in > 231 && act_key_in < 270) return btnSelect;
  return btnNone;
}

//Checking for a pressed menu button
void button_loop(){
  //Serial.println("in button loop");
  byte button = read_act_buttons();   //function call to read the buttons
  if(button == btnMenu){              //if button menu was pressed
    selectMenu();                   //delay for readability
  }
}

void selectMenu(){
  //Serial.println("SelectMenu");
  byte button = 0;                    //var holding the button value
  byte subButton = 0;                 //var holding the subButton value
  menuOption = 1;                     //current menu option
  lcd.clear();                        //clear screen
  //print the retrieved string on lcd
  lcd.print(strcpy_P(buffer_M, (char*)pgm_read_word(&(menu_table[0]))));
  
  while(menuOption <= menuOptions){   //loop through menu options
    button = read_act_buttons();      //check if button was pressed
    if(button == btnMenu){            //if it was btn menu
      menuOption++;                   //add 1 to menu option
      lcd.clear();                    //clear screen
      //retrieve and print the actal menu point
      lcd.print(strcpy_P(buffer_M, (char*)pgm_read_word(&(menu_table[menuOption -1]))));
      switch(menuOption){
        case 2:                       //only menu point no option
        case 3:                       //only menu point no option
        case 5:                       //only menu point no option
          break;
        case 4:                       //menu point with option not used
        case 6:                       //menu point with option not used
          lcd.setCursor(0,1);         //set cursor column 0, row 1
          //retrieve and print "not used"
          lcd.print(strcpy_P(buffer_M, (char*)pgm_read_word(&(msg_table[0]))));
          break;
        case 7:                       //menu point with option arrow right
        case 8:                       //menu point with option arrow right
        case 9:                       //menu point with option arrow right
        case 10:                      //menu point with option arrow right
        case 11:                      //menu point with option arrow right
        case 12:                      //menu point with option arrow right
        case 13:                      //menu point with option arrow right
        case 14:                      //menu point with option arrow right
        case 15:                      //menu point with option arrow right
        case 16:                      //menu point with option arrow right
        case 17:                      //menu point with option arrow right
        case 18:                      //menu point with option arrow right
        case 19:                      //menu point with option arrow right
        case 20:                      //menu point with option arrow right
        case 21:                      //menu point with option arrow right
        case 22:                      //menu point with option arrow right
          lcd.setCursor(15,0);        //set cursor column 15, row 0
          //retrieve and print "arrow right"
          lcd.write(pgm_read_byte(&char_table[0]));
          break;
      }
    }
    
    
    if(button == btnSelect){ //if the select button is pressed
      if(menuOption == 1){   //amd menu option is 1
        adjust_date_time();  //go to ajdust date and time
        return;
      }
      if(menuOption == 2){                                 //and menu option is 2
        sensitivity = get_Timer(17, sensitivity, 0, 1000); //go to function 
        Mem_updateInt(Sensitivity_ADDR, sensitivity);
        return;
      }
      if(menuOption == 3){   //and menu option is 3
        photoCellCutOff = get_Timer(18, photoCellCutOff, 0, 1024); //go to function
        Mem_updateInt(photoCellCutOff_ADDR, photoCellCutOff);
        return;
      }
      if(menuOption == 4) return; //and menu option is 4 return (not used)
      if(menuOption == 5){   //and menu option is 5     
        photoOutsideOff = get_Timer(19, photoOutsideOff, 0, 1024); //go to function
        Mem_updateInt(photoOutsideOff_ADDR, photoOutsideOff);
        return;
      }
      if(menuOption == 6) return; //and menu option is 6 return (not used)
      if(menuOption == 7){ //and menu option is 7 (room 1)
        get_submenu(0);
      }
      if(menuOption == 8){ //and menu option is 8 (room 2)
        get_submenu(1);
      } //submenu end
      if(menuOption == 9){ //and menu option is 9 (room 3)
        get_submenu(2);
      } //submenu end
      if(menuOption == 10){ //and menu option is 9 (room 4)
        get_submenu(3);
      }
      if(menuOption == 11){ //and menu option is 11 (room 5)
        get_submenu(4);
      }
      if(menuOption == 12){ //and menu option is 12 (room 6)
        get_submenu(5);
      } //submenu end
      if(menuOption == 13){ //and menu option is 13 (room 7)
        get_submenu(6);
      } //submenu end
      if(menuOption == 14){ //and menu option is 14 (room 8)
        get_submenu(7);
      } //submenu end
      if(menuOption == 15){ //and menu option is 15 (room 9)
        get_submenu(8);
      } //submenu end
      if(menuOption == 16){ //and menu option is 16 (room 10)
        get_submenu(9);
      } //submenu end
      if(menuOption == 17){ //and menu option is 17 (AC setup)
        get_ac_setup();
        //submenu end
      }
      if(menuOption == 18){ //and menu option is 18 (AC room 1)
        get_ac_sub(10);
        //submenu end
      }
      if(menuOption == 19){ //and menu option is 19 (AC room 2)
        get_ac_sub(11);
        //submenu end
      }
      if(menuOption == 20){ //and menu option is 20 (AC room 3)
        get_ac_sub(12);
        //submenu end
      }
      if(menuOption == 21){ //and menu option is 21 (AC room 4)
        get_ac_sub(13);
        //submenu end
      }
      if(menuOption == 22){ //and menu option is 16 (room 10)
        get_submenu(15);
      } //submenu end
    }   
  }
}

void get_submenu(byte room){
  byte subButton = 0;        //resetting the button var
  submenu = 1;       //submenu counter
  lcd.clear();       //clear screen
  //retrieving and printing first sub menu point
  lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(submenu_table[0]))));
  lcd.print(room + 1);    //printing assigned room number
  if(room == 15){
    lcd.setCursor(0, 1);            //set cursor to column 0, row 1
    //retrieve and print not used
    lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(msg_table[0])))); //print not used
  }
  while(submenu <= submenus){ //loop through the sub menu points
    subButton = read_act_buttons();  //checking for pressed buttons
    if(subButton == btnMenu){   //if button Menu was pressed
      submenu++;                //add 1 - move to the next sub menu point
      lcd.clear();              //clear screen
      //retrieve and print menu options
      lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(submenu_table[submenu -1]))));
      lcd.print(room + 1);    //printing assigned room number
      switch(submenu){
        case 2:               //only sub menu point no option
        case 3:               //only sub menu point no option
        case 4:               //only sub menu point no option
        case 5:               //only sub menu point no option
          break;
        case 6:               //menu point + checking timer 2 options
        case 7:               //menu point + checking timer 2 options
          if(timer_active[room][2] == 2){   //if set to 2
            lcd.setCursor(0, 1);            //set cursor to column 0, row 1
            //retrieve and print not used
            lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(msg_table[0])))); //print not used
          } 
          break;
        case 8:               //menu point + checking timer 3 options
        case 9:               //menu point + checking timer 3 options
          if(timer_active[room][3] == 2){    //if set to 2
            lcd.setCursor(0, 1);             //set cursor to column 0, row 1
            //retrieve and print not used
            lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(msg_table[0])))); //print not used
          }
          break;
        case 10:
          lcd.setCursor(0, 1);             //set cursor to column 0, row 1
          //retrieve and print not used
          lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(msg_table[0])))); //print not used
          break;
      }
    }
    if(subButton == btnSelect){   //if we pressed btnSelect
      if(submenu == 1){           //and submenu is 1
        //call the function get_delay() to change the setting
        if(room == 15) return;
        delayTime[room] = get_delay(9, room, delayTime[room]);
        Mem_updateInt(delayTime_ADDR[room], delayTime[room]);
        return;
      }
      if(submenu == 2){           //and sub menu is 2
        //call the function get_offon to change the setting
        timer_active[room][0] = get_offon(10, room, timer_active[room][0]);
        Mem_updateByte(pgm_read_byte(&(timer_active_ADDR[room][0])), timer_active[room][0]);
        return;
      }
      if(submenu == 3){           //and submenu is 3
        //call the function get_setTime() to change timer 1
        get_setTime(room_timers[room][0][0], room_timers[room][0][1],
                    room_timers[room][0][2], room_timers[room][0][3], 
                    room, 0);
        return;
      }
      if(submenu == 4){           //and submenu is 4
        //call the function get_offon() to change the setting
        timer_active[room][1] = get_offon(11, room, timer_active[room][1]);
        Mem_updateByte(pgm_read_byte(&(timer_active_ADDR[room][1])), timer_active[room][1]);
        return;
      }
      if(submenu == 5){           //and submenu is 5
        //call the function get_setTime() to change timer 2
        get_setTime(room_timers[room][1][0], room_timers[room][1][1],
                    room_timers[room][1][2], room_timers[room][1][3], 
                    room, 1);
        return;
      }
      if(submenu == 6 && timer_active[room][2] != 2){   //and submenu is 6
        //call the function get_offon() to change the setting
        timer_active[room][2] = get_offon(12, room, timer_active[room][2]);
        Mem_updateByte(pgm_read_byte(&(timer_active_ADDR[room][2])), timer_active[room][2]);
        return;
      }
      if(submenu == 7 && timer_active[room][2] != 2){          //and submenu == 7
        //call function get_setTime() to change timer 3
        get_setTime(room_timers[room][2][0], room_timers[room][2][1],
                    room_timers[room][2][2], room_timers[room][2][3], 
                    room, 2);
        return;
      }
      if(submenu == 8 && timer_active[room][3] != 2){           //and submenu is 6
        //call the function get_offon() to change the setting
        timer_active[room][3] = get_offon(25, room, timer_active[room][3]);
        Mem_updateByte(pgm_read_byte(&(timer_active_ADDR[room][3])), timer_active[room][3]);
        return;
      }
      if(submenu == 9 && timer_active[room][3] != 2){          //and submenu == 7
        //call function get_setTime() to change timer 3
        get_setTime(room_timers[room][3][0], room_timers[room][3][1],
                    room_timers[room][3][2], room_timers[room][3][3], 
                    room, 3);
        return;
      }
      if(submenu == 10) return;
    }
  }
} 

 
void get_ac_setup(){
  byte subButton = 0;
  acSetup = 1;                        //submenu counter (AC Mode)
  lcd.clear();                        //clear screen
  //retrieving and printing first sub menu point
  lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(ac_setup_table[0]))));
  while(acSetup <= acSetups){        //loop through the submenu points
    subButton = read_act_buttons();  //checking for pressed buttons
    if(subButton == btnMenu){        //if button menu was pressed
      acSetup++;                     //add 1 -  move to the next point
      lcd.clear();
      //printing and retrieving the menu points
      lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(ac_setup_table[acSetup - 1]))));
    }
    if(subButton == btnSelect){      //if btn select was pressed
      switch(acSetup){               //going right through the options
      case 1:
        //call the function get_timer() to update settings
        ac_op_mode = get_Timer(26, ac_op_mode, 1, 4);
        Mem_updateByte(ac_op_mode_ADDR, ac_op_mode);
        return;
      case 2:
        //call the function get_timer() to update settings
        ac_set_temp = get_Timer(27, ac_set_temp, 18, 32);
        Mem_updateByte(ac_set_temp_ADDR, ac_set_temp);
        return;
      case 3:
        adj_seasons();
        return;
      case 4:
        //call the function get_timer() to update settings
        acSwitchDelay = get_Timer(28, acSwitchDelay, 1, 5);
        Mem_updateByte(acSwitchDelay_ADDR, acSwitchDelay);
        return;
      case 5:
        //call the function get_offon() tu update settings
        startDelay = get_offon(39, 0, startDelay);
        Mem_updateByte(startDelay_ADDR, startDelay);
        return;
      }
    }
  }
}


void get_ac_sub(byte room){
  byte subButton = 0;               //resetting the button var
  acSubOption = 1;                  //submenu counter
  lcd.clear();                      //clear screen
  //retrieving and printing first submenu point
  lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(ac_sub_table[0]))));
  lcd.print(room - 9);              //printing assigned room number
  while(acSubOption <= acSubOptions){ //loop through the submenu points
    subButton = read_act_buttons();  //checking for pressed buttons
    if(subButton == btnMenu){       //if btn menu was pressed
      acSubOption++;                // add 1 to move to the next sub menu point
      lcd.clear();
      //retrieving and printing the menu points
      lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(ac_sub_table[acSubOption - 1]))));
      lcd.print(room - 9);       //printing assigned room number
    }
    if(subButton == btnSelect){
      switch(acSubOption){
        case 1:               //only sub menu point no option
          //call the function get_delay() to change the setting
          delayTime[room] = get_delay(37, room, delayTime[room]);
          Mem_updateInt(pgm_read_byte(&(delayTime_ADDR[room])), delayTime[room]);
          
          return;
        case 2:               //only sub menu point no option
          //call the function get_offon to change setting
          ac_master_bypass[room - 10] = get_offon(38, room, ac_master_bypass[room - 10]);
          Mem_updateByte(pgm_read_byte(&(ac_master_bypass_ADDR[room - 10])), ac_master_bypass[room - 10]);
          return;
        case 3:               //only sub menu point no option
          //call the function get_offon to change setting
          timer_active[room][0] = get_offon(10, room, timer_active[room][0]);
          Mem_updateByte(pgm_read_byte(&(timer_active_ADDR[room][0])), timer_active[room][0]);
          return;
        case 4:               //only sub menu point no option
          //call the function get_setTime() to change timer 1
          get_setTime(room_timers[room][0][0], room_timers[room][0][1],
                      room_timers[room][0][2], room_timers[room][0][3], 
                      room, 0);
          return;
        case 5:               //only sub menu point no option
          //call the function get_offon() to change the setting
          timer_active[room][1] = get_offon(11, room, timer_active[room][1]);
          Mem_updateByte(pgm_read_byte(&(timer_active_ADDR[room][1])), timer_active[room][1]);
          return;
        case 6:               //only sub menu point no option
          //call the function get_setTime() to change timer 2
          get_setTime(room_timers[room][1][0], room_timers[room][1][1],
                      room_timers[room][1][2], room_timers[room][1][3], 
                      room, 1);
          return;
        case 7:               //only sub menu point no option
          //call the function get_offon() to change the setting
          timer_active[room][2] = get_offon(12, room, timer_active[room][2]);
          Mem_updateByte(pgm_read_byte(&(timer_active_ADDR[room][2])), timer_active[room][2]);
          return;
        case 8:               //only sub menu point no option
          //call function get_setTime() to change timer 3
          get_setTime(room_timers[room][2][0], room_timers[room][2][1],
                      room_timers[room][2][2], room_timers[room][2][3], 
                      room, 2);
          return;
        case 9:               //only sub menu point no option
          //call the function get_offon() to change the setting
          timer_active[room][3] = get_offon(25, room, timer_active[room][3]);
          Mem_updateByte(pgm_read_byte(&(timer_active_ADDR[room][3])), timer_active[room][3]);
          return;
        case 10:               //only sub menu point no option
          //call function get_setTime() to change timer 3
          get_setTime(room_timers[room][3][0], room_timers[room][3][1],
                      room_timers[room][3][2], room_timers[room][3][3], 
                      room, 3);
          return;
      }
    }
  }
}

void adj_seasons(){
  byte subButton = 0;  //set button var to 0
  ac_periode[0][0] = get_Timer(29, ac_periode[0][0], 0, 13);  //get the first value
  if(ac_periode[0][0] >= 0 && ac_periode[0][0] <= 12){        //check if it is within range
    if(ac_periode[0][0] == 12){                               //predefine closing value
      ac_periode[0][1] = 1;
      ac_periode[0][1] = get_Timer(30, ac_periode[0][1], 1, 13);
    }
    else if(ac_periode[0][0] != 12){ 
      ac_periode[0][1] = ac_periode[0][0] + 1;
      ac_periode[0][1] = get_Timer(30, ac_periode[0][1], ac_periode[0][1], 13);
    }
    if(ac_periode[0][1] >= 0 && ac_periode[0][1] <= 12){
      ac_periode[1][0] = get_Timer(31, ac_periode[1][0], 0, 13);
      if(ac_periode[1][0] >= 0 && ac_periode[1][0] <= 12){
        if(ac_periode[1][0] == 12){
          ac_periode[1][1] = 1;
          ac_periode[1][1] = get_Timer(32, ac_periode[1][1], 1, 13);
        }
        else if(ac_periode[1][0] != 12){ 
          ac_periode[1][1] = ac_periode[1][0] + 1;
          ac_periode[1][1] = get_Timer(32, ac_periode[1][1], ac_periode[0][1], 13);
        }
        if(ac_periode[1][1] >= 0 && ac_periode[1][1] <= 12){
          ac_periode[2][0] = get_Timer(33, ac_periode[2][0], 0, 13);
          if(ac_periode[2][0] >= 0 && ac_periode[2][0] <= 12){
            if(ac_periode[2][0] == 12){
              ac_periode[2][1] = 1;
              ac_periode[2][1] = get_Timer(34, ac_periode[2][1], 1, 13);
            }
            else if(ac_periode[2][0] != 12){ 
              ac_periode[2][1] = ac_periode[2][0] + 1;
              ac_periode[2][1] = get_Timer(34, ac_periode[2][1], ac_periode[2][1], 13);
            }
            if(ac_periode[2][1] >= 0 && ac_periode[2][1] <= 12){
              ac_periode[3][0] = get_Timer(35, ac_periode[3][0], 0, 13);
              if(ac_periode[3][0] >= 0 && ac_periode[3][0] <= 12){
                if(ac_periode[3][0] == 12){
                  ac_periode[3][1] = 1;
                  ac_periode[3][1] = get_Timer(36, ac_periode[3][1], 1, 13);
                }
                else if(ac_periode[3][0] != 12){ 
                  ac_periode[3][1] = ac_periode[2][0] + 1;
                  ac_periode[3][1] = get_Timer(36, ac_periode[3][1], ac_periode[3][1], 13);
                }
                lcd.clear();
                if(ac_periode[0][0] < 10) lcd.write(pgm_read_byte(&char_table[2]));  //print 0
                lcd.print(ac_periode[0][0]);
                lcd.print(" | ");
                if(ac_periode[0][1] < 10) lcd.write(pgm_read_byte(&char_table[2]));  //print 0
                lcd.print(ac_periode[0][1]);
                lcd.print(" ");
                if(ac_periode[1][0] < 10) lcd.write(pgm_read_byte(&char_table[2]));  //print 0
                lcd.print(ac_periode[1][0]);
                lcd.print(" | ");
                if(ac_periode[1][1] < 10) lcd.write(pgm_read_byte(&char_table[2]));  //print 0
                lcd.print(ac_periode[1][1]);
                lcd.setCursor(0, 1);
                if(ac_periode[2][0] < 10) lcd.write(pgm_read_byte(&char_table[2]));  //print 0
                lcd.print(ac_periode[2][0]);
                lcd.print(" | ");
                if(ac_periode[2][1] < 10) lcd.write(pgm_read_byte(&char_table[2]));  //print 0
                lcd.print(ac_periode[2][1]);
                lcd.print(" ");
                if(ac_periode[3][0] < 10) lcd.write(pgm_read_byte(&char_table[2]));  //print 0
                lcd.print(ac_periode[3][0]);
                lcd.print(" | ");
                if(ac_periode[3][1] < 10) lcd.write(pgm_read_byte(&char_table[2]));  //print 0
                lcd.print(ac_periode[3][1]);
                while(subButton != btnSelect){
                  lcd.clear();
                  lcd.print(strcpy_P(buffer_M, (char*)pgm_read_word(&(msg_table[1])))); //save the values
                  Mem_updateByte(pgm_read_byte(&(ac_periode_ADDR[0][0])), ac_periode[0][0]);
                  Mem_updateByte(pgm_read_byte(&(ac_periode_ADDR[0][1])), ac_periode[0][1]);
                  Mem_updateByte(pgm_read_byte(&(ac_periode_ADDR[1][0])), ac_periode[1][0]);
                  Mem_updateByte(pgm_read_byte(&(ac_periode_ADDR[1][1])), ac_periode[1][1]);
                  Mem_updateByte(pgm_read_byte(&(ac_periode_ADDR[2][0])), ac_periode[2][0]);
                  Mem_updateByte(pgm_read_byte(&(ac_periode_ADDR[2][1])), ac_periode[2][1]);
                  Mem_updateByte(pgm_read_byte(&(ac_periode_ADDR[3][0])), ac_periode[3][0]);
                  Mem_updateByte(pgm_read_byte(&(ac_periode_ADDR[3][1])), ac_periode[3][1]);
                  delay(1000);
                  return;
                }
              }
            }
          }
        }
      }
    }
  }
}
                
                  
byte get_setTime( byte onTimeH, byte onTimeM, byte offTimeH,
                  byte offTimeM, byte room, byte timer){
  byte subButton = 0;
  onTimeH = get_Timer(13, onTimeH, 0, 24);
  if(onTimeH >= 0 && onTimeH < 24){
    onTimeM = get_Timer(14, onTimeM, 0, 60);
    if(onTimeM < 60){
      offTimeH = get_Timer(15, offTimeH, 0, 24);
      if(offTimeH >= 0 && offTimeH < 24){
        offTimeM = get_Timer(16, offTimeM, 0, 60);
        if(offTimeM < 60){
          lcd.clear();
          lcd.print(strcpy_P(buffer_M, (char*)pgm_read_word(&(msg_table[6]))));
          lcd.setCursor(0, 1);
          if(onTimeH < 10) lcd.write(pgm_read_byte(&char_table[2]));  //print 0
          lcd.print(onTimeH);
          lcd.write(pgm_read_byte(&char_table[3]));   //print seperator
          if(onTimeM < 10) lcd.write(pgm_read_byte(&char_table[2]));  //print 0
          lcd.print(onTimeM);
          lcd.setCursor(11, 1);
          if(offTimeH < 10) lcd.write(pgm_read_byte(&char_table[2]));  //print 0
          lcd.print(offTimeH);
          lcd.write(pgm_read_byte(&char_table[3]));   //print seperator
          if(offTimeM < 10) lcd.write(pgm_read_byte(&char_table[2]));  //print 0
          lcd.print(offTimeM);
          while(subButton != btnSelect){
            subButton = read_act_buttons();
            if(subButton == btnMenu) return 0;
            if(subButton == btnSelect){
              lcd.clear();
              lcd.print(strcpy_P(buffer_M, (char*)pgm_read_word(&(msg_table[1]))));
              delay(1000);
              Mem_updateByte(pgm_read_byte(&(room_timers_ADDR[room][timer][0])), onTimeH);
              room_timers[room][timer][0] = onTimeH;
              Mem_updateByte(pgm_read_byte(&(room_timers_ADDR[room][timer][1])), onTimeM);
              room_timers[room][timer][1] = onTimeM;
              Mem_updateByte(pgm_read_byte(&(room_timers_ADDR[room][timer][2])), offTimeH);
              room_timers[room][timer][2] = offTimeH;
              Mem_updateByte(pgm_read_byte(&(room_timers_ADDR[room][timer][3])), offTimeM);
              room_timers[room][timer][3] = offTimeM;
              return 0;
            }
          }
        }
      }
    }
  }
}
          

//function to set a timer active / inactive
byte get_offon(byte info, byte room, byte reading){
  byte subButton = 0;        //resetting button value
  lcd.clear();          //clear screen
  lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(msg_table[info]))));  //print passed info text
  if(room >= 10 && room <= 13){ //calculating room for AC units
    lcd.print(room - 9);        //AC room 
  }
  else if(room == 0){
    lcd.print("  ");
  }
  else{
    lcd.print(room + 1);     //light room
  }
  lcd.setCursor(0, 1);  //set cursor to second row column 1
  if(reading != 1) lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(msg_table[7]))));  //if value is not 1 timer is off
                                           //print off
  if(reading == 1) lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(msg_table[8]))));    //if timer is 1, timer is active
                                           //print active
  while(subButton != btnSelect){           //waiting for btnSelect to be pressed
    subButton = read_act_buttons();        //checking for pressed buttons
    if(subButton == btnSearch){            //if btnSearch is pressed
      if(reading == 1) reading = 0;       //set to 0 if 1
      else
      if(reading == 0) reading = 1;        //set to 1 if 0
    }
    lcd.setCursor(0, 1);                   //set cursor to first column, second row
    if(reading != 1) lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(msg_table[7])))); //print off if not set to 1
    if(reading == 1) lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(msg_table[8]))));  //print Active if set to 1
  }
  return reading;
}
  

//function to adjust the pir delay time
int get_delay(byte info, byte room, int reading){
  byte subButton = 0;      //resetting the button value
  byte value = reading / 60; //converting to Minutes
  lcd.clear();             //clear screen
  lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(msg_table[info]))));  //print passed message
  if(room >= 10 && room <= 13){ //calculating room for AC units
    lcd.print(room - 9);     //AC room 
  }
  else{
    lcd.print(room + 1);     //light room
  }
  lcd.setCursor(0, 1);     //set cursor to second row, first column
  if(value < 10) lcd.write(pgm_read_byte(&char_table[2]));  //print 0
  lcd.print(value);        //print the passed value in minutes
  lcd.setCursor(4, 1);     //set cursor to second row, column 6
  lcd.print("Min");        //just print Min.
  while(subButton != btnSelect){    //wait for select btn
    subButton = read_act_buttons(); //check if a button was pressed
    if(subButton == btnSearch){      //if btnSearch was pressed
      if(value > 0 && value < 30){  //we are within allowed range
        value++;                    //add 1 to value while btnSearch is pressed
      }
      if(value >= 30) value = 1;    //if reaches upper limit set to lower limit
      lcd.setCursor(0, 1);         //setting the cursor
      if(value < 10) lcd.write(pgm_read_byte(&char_table[2]));  //print 0
      lcd.print(value);             //printing the updated value
    }
  }
  return value*60;
}

void adjust_date_time(){
  byte button = 0; //set button var to 0
  //function call to adjust the minute part of the system time
  byte minuteT = get_Timer(20, tm.Minute, 0, 60); 
  if(minuteT >= 0 && minuteT < 60){ //check the returned result
    //function call to adjust the hour part of the system time
    byte hourT = get_Timer(21, tm.Hour, 0, 24);
    if(hourT >= 0 && hourT < 24){ //check the returned result
      //function call to adjust the day of the week
      byte weekDay = get_weekday();  
      if(weekDay > 0 && weekDay <= 7){ //check the returned result
        //function call to adjust the day of the month
        byte monthDay = get_Timer(22, tm.Day, 1, 32);
        if(monthDay >= 1 && monthDay <=31){  //check the returned result
          //function call to adjust the month
          byte monthT = get_Timer(23, tm.Month, 1, 13);
          if(monthT >= 1 && monthT <= 12){ //check returned result
            //function call to adjust the year
            byte yearT = get_Timer(24, tmYearToCalendar(tm.Year)-2000, 0, 99);
            if(yearT >= 0 && yearT <= 99){ //check the returned results
              byte value = weekDay;   //passing on the variable for calculations
              //the following lcd statements print the adjusted results 
              //on the LCD
              lcd.clear();
              if(hourT < 10) lcd.write(pgm_read_byte(&char_table[2]));    //print 0
              lcd.print(hourT);
              lcd.write(pgm_read_byte(&char_table[3]));   //print seperator
              if(minuteT < 10) lcd.write(pgm_read_byte(&char_table[2]));  //print 0
              lcd.print(minuteT);
              lcd.setCursor(0, 1);
              lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(weekday_table[value-1]))));
              lcd.print(" ");
              if(monthDay < 10) lcd.write(pgm_read_byte(&char_table[2]));  //print 0
              lcd.print(monthDay);
              lcd.write(pgm_read_byte(&char_table[4]));   //print dott
              if(monthT < 10) lcd.write(pgm_read_byte(&char_table[2]));    //print 0
              lcd.print(monthT);
              lcd.write(pgm_read_byte(&char_table[4]));   //print dott
              lcd.print(yearT);
              while(button != btnSelect){   //loop until button select is pressed
                button = read_act_buttons();
                if(button == btnMenu) return; //if button Menu is pressed return without saving
                if(button == btnSelect){ //if button select is pressed
                  lcd.clear();
                  lcd.print(strcpy_P(buffer_M, (char*)pgm_read_word(&(msg_table[1])))); //print saving
                  delay(1000);
                  //function call to save the adjusted values to RTC
                  save_time(minuteT, hourT, weekDay, monthDay, monthT, yearT);
                }
              }
              return;
            }
          }
        }
      }
    }
  }
}

void save_time(byte mi, byte hr, byte wkDay, byte da, byte mo, byte yr){
  Wire.beginTransmission(DS1307_ADDRESS);  //starting transmission to DS 1307 RTC
  Wire.write(zero);                        //needed leading zero byte
  
  Wire.write(decToBcd(0));       //set seconds to 0
  Wire.write(decToBcd(mi));      //set minutes to updated value
  Wire.write(decToBcd(hr));      //set hour to updated value
  Wire.write(decToBcd(wkDay));   //set weekday to updated value
  Wire.write(decToBcd(da));      //set month day to updated value
  Wire.write(decToBcd(mo));      //set month to updated value
  Wire.write(decToBcd(yr));      //set year to updated value
  
  Wire.write(zero);              //send finishing zero byte
  
  Wire.endTransmission();        //close transmission
}

byte decToBcd(byte val){
  return ((val/10*16) + (val%10));
}

int get_Timer(byte info, int reading, int startVal, int maxCount){
  byte button = 0;                 //reseting the button var
  lcd.clear();                     //clear the screen
  lcd.print(strcpy_P(buffer_M, (char*)pgm_read_word(&(msg_table[info]))));  //print the passed on info text
  lcd.setCursor(0, 1);             //set the cursor to second row first column
  lcd.print(reading);              //print the passed on value to be changed
  while(button != btnSelect){      //wait for a button to be pressed
    button = read_act_buttons();   //check if a button is pressed
    if(button == btnSearch){       //if btnSearch is pressed
      //if the reading is somewhere between the limit we add 1
      //to the value with every loop through while the btnSearch
      //is pressed
      if(reading >= startVal && reading < maxCount) reading++;
      if(reading >= maxCount)reading = startVal;   //reset the value to be changed to
                                                   //the lower limit
      lcd.setCursor(0, 1);      //setting the cursor to first column, second row
      lcd.print(reading);       //print the updating value
      lcd.print("    ");        //print 4 empty spaces to delete left overs
                                //if the value changes from high to
                                //low limit
    }
  }
  return reading;               //return the value
}

byte get_weekday(){
  byte button = 0;              //reseting the button var
  byte value = currentDay;      //passing the global weekday variable to a
                                //local one for calculations
  //Serial.println(currentDay); //debug only
  lcd.clear();                  //clear the screen
  //print what we are updating (weekday)
  lcd.print(strcpy_P(buffer_M, (char*)pgm_read_word(&(msg_table[5])))); 
  lcd.setCursor(0, 1);          //set the cursor to second row, first column
  //print the current value for weekday
  lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(weekday_table[value]))));
  while(button != btnSelect){   //waite for a button to be pressed
    button = read_act_buttons(); //checking for a button pressed 
    if(button == btnSearch){     //if it was btnSearch
      if(value >= 0 && value < 7) value++; //checking between 0 and 6
      if(value >= 7) value = 0;    //setting the value back to 0 
      //Serial.print("Value: "); //debug only
      //Serial.println(value);   //debug only
      lcd.setCursor(0, 1);       //set cursor to second row, first column
      //printing the ubdating value
      lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(weekday_table[value]))));
    }
  }
  return value + 1; //return the value and add 1 to be stored in RTC memory 
}

void get_error(byte msg, byte row){
  lcd.setCursor(0, row);
  lcd.print(strcpy_P(buffer_M, (char*)pgm_read_word(&(error_table[msg])))); 
}

///////////////////some easy inline logical functions////////////////////////////////////
int IIFi( boolean iLogicalValue, int iWhenTrue, int iWhenFalse ) {
  if (iLogicalValue) return iWhenTrue;
  else               return iWhenFalse;
}

String IIFs( boolean iLogicalValue, String iWhenTrue, String iWhenFalse ) {
  if (iLogicalValue) return iWhenTrue;
  else               return iWhenFalse;
}


void Mem_writeByte(int address, byte value){
  EEPROM.write(address, value);
  delay(5);
  byte reading = Mem_readByte(address);
  if(reading != value){
    get_error(3, 1);
    delay(60000);
  }
}

// the writeBytes takes care of the delay..
void Mem_writeInt(int address, int value)
{
  Mem_writeByte(address, highByte(value) );
  Mem_writeByte(address+1, lowByte(value) );
}



void Mem_updateByte(int address, byte value){
  byte reading = EEPROM.read(address);
  if(reading != value) Mem_writeByte(address, value);
}

void Mem_updateInt(int address, int value){
  Mem_updateByte(address, highByte(value));  //high byte
  Mem_updateByte(address+1, lowByte(value)); //low byte
}

byte Mem_readByte(int address){
  byte value = EEPROM.read(address);
  return value;
}

int Mem_readInt(int address){
  byte hiByte = EEPROM.read(address);
  byte loByte = EEPROM.read(address+1);
  int value = word(hiByte, loByte);
  return value;
}

No comments:

Post a Comment