Translate

Friday 27 June 2014

Room Management System – Project Summary

Room Management System – Project Summary

Overall, it was a fun project to do and quite a challenge to get it up to the state as it is now. The originating request was just simple controlling the lights for 4 rooms using PIR's and a few momentary switches, which was done very quick. Than there where additional ideas and also a few upcoming requests and so I took the challenge and the final result is now controlling the light of 10 rooms and 4 AC units independently using PIR's, a photocell, a temperature sensor and a few momentary switches. Implemented is a automated light control to switch lights automatically in a programmable sequence to hide a vacant home controlled through a real time clock. Also implemented a user interface with LCD display to make it more user friendly and to adjust it to different needs.

Prototyping on a breadboard:
Using breadboards for prototyping is a great thing since circuits can be changed and adjusted very quick and easy. The downside is that loose connections produce noise and components like the RTC and LCD displays are very sensitive in that matter. Just a little noise can stop the rtc- module responding or get the LCD to display a heap of garbage instead of the wanted information. Also very noise sensitive are the 74HC595 shift registers. To avoid disappointment and long fault searching, great care has to be taken in wiring your circuit on a breadboard. To make sure the connections are as good as they can be to avoid noise by bad contacts, use dupont wire connectors. Since I was using lots of connections I used also some other rigid wire but with plenty of noise producing contact problems. Since I am running my LCD of a shift register, I had to add a few components. Starting out on a breadboard the noise problems drove me kind of crazy so I just soldered everything together on a pref board and the noise problems I had with the LCD where reduced to a minimum. Even building your own RTC will work on a breadboard but not very reliable. The RTC is also best, soldered straight to a pref board or use a ready made shield. You will encounter the same problems with running the Atmega chip of the breadboard. Even here is best to use the original ARDUINO board or if you really need or want to run it independent, solder everything on a pref board. It also helps later with designing the final circuit board for your project.

Button input through Arduino's analogue inputs
Sure it is a nice idea to connect several buttons separated by a resistor and read the analogue input to determine which button was pressed.
However, be aware that the readings change depending on the load drawing of the Arduino's digital I/o pins. I used only 10K resistors to separate the buttons and it proofed not enough, since the readings jump about 100 points. The centred readings of the buttons are only about 45 points apart which causes on extreme jumps the button not to work while completely out of range. In my next project, I would rather add another CD4021B shift register to extend the inputs than using a analogue input to read multiple buttons of it.

Power supply
Great care has to be taken also in choosing the power source used. For small projects controlling a few LED's, the power drawn from a USB port is more than enough. However, the absolute maximum current which can be drawn from a Arduino pin is 40 mA not exceeding a total current draw of 200 mA which we have already reached lighting up 10 standard 3 or 5mm LED's. Running a few shift registers, a RTC and a LCD of the same power source, through the Arduino board we come pretty fast to the over all limit. Even if we get the current 5V output, which is not running through the chip but than we still have to check the limitations of the voltage regulator. I tried once running 1A on a 12 Volt input through a 7805 voltage regulator and it got untouchable hot within seconds. Another reason for having a steady and reasonable dimensioned power supply are analogue readings. Reading a photocell, a temperature sensor or a button shield depends on a steady power supply. Just see what happens to your readings, running the Arduino board of your USB port and than plug in a 9V power supply, giving at least 1 A of current. You definitely have to recalibrate your temperature sensor and recheck the centre points for your buttons.
A small advise out of own experience and hours of looking for faults which turned out to be power related. Calculate the estimated power consumption of your project and add a little reserve right from the beginning. Depending a little on your computer, USB ports can deliver only
500 mA 4.4 to 5.25 Volts on a USB 2.0 port
900 mA 4.4 to 5.25 Volts on a USB 3.0 port

Your computer will not turn in to smoke on a slight overload but your analogue readings will change if you need to read sensors like temperature, photo cells or reading a button shield through a analogue input.

It's just a simple calculation. The analogRead read the voltage on the port from 0 to1023 corresponding with 0 to 5 Volt.

OK, using a USB 2.0 port, being able to give as a power of 5.25 Volts * 0.5A = 3.125 W
3.125 Watts is the power the USB port can give us.
If we no try to draw 800 mA out of our USB port the following will happen:

3.125 Watts is a constant in this case and it will not change. But we draw 800 mA. Lets do the calculation:

3.125 Watts / 0.8A = 3.09 Volt

The available Voltage will drop to 3.09. Our analogue reading where based on a available voltage of about 5.

Got the point?

Debugging
Since it was my first large project, it's far away from being perfect and I already know a few things which could have been done better. However, if you are looking through the sketch and you see something which can be done differently, or something jumps in your eye where I have goofed or what I've missed please feel free to drop me a note. I am always happy to hear constructive critics.

Updates and requests
I keep on working on this project and I will post updates in the future as I go along. Since I am doing this project in my free time in between work, family and various other duties, any posted question will be answered eventually but please be patiend with me especially during summer when I am most busy.

Some final words
A great thanks to the guys from the Arduino forum which did a great deal in pointing me in right directions when I was stuck and giving a hand in finding some major bugs.
Another great thanks to everybody from the Arduino blog adding suggestions and helping in improving and cleaning up parts of the code.
Not to forget to mention the kind support and all the likes on google which where quite encouraging at times to carry on and finding solutions when I was stuck.

Again, Thank you to all of you!

Upcoming projects:
A real world time clock including automatic compensation for day light saving time
and 
a Solar charger which doesn't fry the batteries

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;
}