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