Translate

Tuesday, 29 April 2014

Room Management System – Cleaning up the sketch for Menu

Since I had a few days now calculating and playing around with the program memory I found out, that it will be close to squeeze everything on the Atmega 328. The first step to get it done is to do a little “house keeping”. Since I started the project with just a simple task, making lights go on and off using PIR's and time delays it was growing quite a bit, adding the RTC, the automatic switch mode while the house is vacant and now we try to build a menu on top. Before we start, with the final task, we need to free up some memory, both, program memory and RAM.

First we have a closer look at our sketch where we check the various PIR's and priority switches to determine if a light is to be on or off and we find, that we repeat the same code for every room. That's a call for packing it into a function.

There for we go into the main loop of the sketch and find the part where it says
 “ //////////////////room lights//////////////////////////////” In my sketch it's currently line 885 but that may vary depending on your commenting and the amount of Serial.print statements for debugging.

Here we find the following code:

if(switchState[0] == 1 && lightStatus[16] == 1) { //checking if PIR in Room 1 was
                                                                         //activated (bed 1)
lightStatus[16] = 0;                                             //resetting master off
digitalWrite(doorMonitor, LOW);                          //resetting the door Monitor LED
}

and replace it with:

check_master(0);

Resetting the master timer which we do for every set of PIR's no goes into the function called check_master(switch Number) from switchState[switch Number].

Now we go down to the far end of the sketch and write the function:

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

We find the same peace of code for the next room :

if(switchState[2] == 1 && lightStatus[16] == 1) { //checking if PIR in Room 2 was
                                                                         //activated (bed 2)
lightStatus[14] = 0;                                             //resetting master off
digitalWrite(doorMonitor, LOW);                         //resetting the door Monitor LED
}

and replace it with:

check_master(2);

We do the same thing with all the rooms. Please make sure, that the numbers switchState[switch Number] and the function call check_master[switch Number] match and you use the “switch Number” from the switchState[] you are replacing and not the one from the following code. The following statement in the first 4 rooms is checking the priority switch and not the PIR's.
That wasn't so hard I guess. Now since we got into changing things again, we come to the more difficult part. We put the whole statement where we determine if a light has to be switched on or not into a function.

There for we need to find the part in our sketch where it says:

&& outsideOnTime == 1){
lightOutput[15] = 32768;                 //switching on the lights
}
else {
lightOutput[15] = 0;                        //no matches, they switch off
}
//////////////////room lights//////////////////////////////
check_master(0);                           //check if door switch was activated room 1 (bed1)

//Starting from here, the whole part until “switchState1Old = switchState[1]; “ has to go – but stop, //don't delete it right away cause we use it again to build our function.

if(switchState[1] == 0 && sensorValue <= photoCellCutOff) {   //checking if S2 priority off was
                                                                                            //set bed 1
if(switchState[0] == 1 && priorityStatus[0] == 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[0] = 1;                                                                 //switching on the lights – binary
                                                                                            //000000000000000000000001
lightStatus[0] = 1;                                                                  //setting the light status for bed 1
lightOutput[14] = 16384;                                                        //make sure the master relay
                                                                                           //stays on
lightStatus[14] = 1;                                                               //setting the master relay status
roomTimer[0] = millis();                                                        //setting the timer
}
else if(switchState[0] == 0 && lightStatus[0] == 1) {              //the PIR not activated but the
                                                                                          //lights are on
//Serial.println("We are checking the timer");                           //Debug only
currentTime = millis();                                                         //setting time reference
endTime = currentTime - roomTimer[0];                               //calculating the inactive time
if(endTime >= delayTime[0]) {                                             //comparing inactive time with
                                                                                         //allowed delay time
//Serial.println("Time is up switching off the lights");               //Debug only
lightOutput[0] = 0;                                                               //switching off the lights
lightStatus[0] = 0;                                                                //resetting the light status
roomTimer[0] = 0;                                                              //resetting the room timer
}
}
}
else if(switchState[1] == 1 && lightStatus[0] == 1
&& switchState1Old != 1) {                                                 //if priority is activated and the
//lights are on
//Serial.println("Priority switch activated switching off the lights"); //Debug only
lightOutput[0] = 0;                                                              //switching off the lights
lightStatus[0] = 0;                                                               //resetting the light status
roomTimer[0] = 0;                                                             //resetting the room timer
priorityStatus[0] = 1;                                                          //setting the priority status bed 1
}
else if(switchState[1] == 1 && lightStatus[0] == 0
&& switchState1Old != 1) {                                               //if priority was activated and the
                                                                                        //lights are off
//Serial.println("Priority switch deactivated switching on the lights"); //Debug only
lightOutput[0] =1;                                                               //switching on the lights
lightStatus[0] = 1;                                                               //setting the light status
roomTimer[0] = millis();                                                     //setting the room timer
priorityStatus[0] = 0;                                                          //setting the priority for bed 1 back //to 0
}
switchState1Old = switchState[1];                                     //passing on the switch state

The whole mentioned part we replace with:

check_light_P(0, 1, 0, 1);                                                 //check status room 1 (bed 1)


check_light_P() is our function call. Don't worry about yet, we will build the function in a minute. The first number we are passing to the function is the place in the switchState[] - array holding the variable assigned to the pir switch state for that room. (0 for room bed 1, 2 for bed 2, 4 for bed 3, 6 for living, 8 for bath 1, 9 for bath 2, 10 for bath 3 and so on. The second number is the place in the switchState[] - array holding the variable assigned to the priority switch for that room (1 for priority bed 1, 3 for priority bed 2, 5 for priority bed 3 and 5 for priority living. The third number is the place in various arrays holding variables direct assigned to the room like light status, room timer etc. (0 = room 1, 1 = room 2, 2 = room 3, …) and the last number is the light output command for the particular room representing the integer of a binary controlling the output shift register.

Now we take the part we just cut and go all the way down again, right to the end of our sketch and build the function. First thing we paste the replaced part at the very end of the sketch.
First we add:

void check_light_P(byte pir, byte prio, byte room, unsigned long light){ //adding the function entry

//before we do anything else, we go to the bottom of the sketch and close the function with a “}”.
//The variable pir is the place holder of the space in the switchState array for the room we want
// to process. Now careful because the first 4 rooms have to switchState variables, one for the
// PIR's and one for the priority switch. The first is the one for the PIR the second for the priority
//switch. The first one is “0”. Where ever it reads switchState[0] in the function, we replace the 0
//with pir so it reads switchState[pir]. The second switchState variable we are using is
//switchState[1]. Where ever in the function we find switchState[1] we replace the “1” with prio so
//it reads switchState[prio]. The next variable addresses everything in arrays related direct to the
//room like lightOutput[0], lightStatus[0], roomTimer[0] etc. There we replace the “0” with room so
//it reads lightOutput[room], lightStatus[room], roomTimer[room]...
//The last thing we need to change is the lightOutput. After you made all the other changes, you will //find two statements lightOutput[room] = 1;. This two statements have to change to //lightOutput[room] = light;


if(switchState[1] == 0 && sensorValue <= photoCellCutOff) { //checking if S2 priority off was
                                                                                          //set bed 1
if(switchState[0] == 1 && priorityStatus[0] == 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[0] = 1;                                                              //switching on the lights – binary
                                                                                         //000000000000000000000001
lightStatus[0] = 1;                                                               //setting the light status for bed 1
lightOutput[14] = 16384;                                                     //make sure the master relay
                                                                                        //stays on
lightStatus[14] = 1;                                                            //setting the master relay status
roomTimer[0] = millis();                                                     //setting the timer
}
else if(switchState[0] == 0 && lightStatus[0] == 1) {           //the PIR not activated but the
                                                                                       //lights are on
//Serial.println("We are checking the timer");                       //Debug only
currentTime = millis();                                                     //setting time reference
endTime = currentTime - roomTimer[0];                           //calculating the inactive time
if(endTime >= delayTime[0]) {                                         //comparing inactive time with
                                                                                     //allowed delay time
//Serial.println("Time is up switching off the lights");          //Debug only
lightOutput[0] = 0;                                                         //switching off the lights
lightStatus[0] = 0;                                                          //resetting the light status
roomTimer[0] = 0;                                                         //resetting the room timer
}
}
}
else if(switchState[1] == 1 && lightStatus[0] == 1
&& switchState1Old != 1) {                                         //if priority is activated and the
                                                                                 //lights are on
//Serial.println("Priority switch activated switching off the lights"); //Debug only
lightOutput[0] = 0;                                                     //switching off the lights
 lightStatus[0] = 0;                                                     //resetting the light status
roomTimer[0] = 0;                                                     //resetting the room timer
priorityStatus[0] = 1;                                                  //setting the priority status bed 1
}
else if(switchState[1] == 1 && lightStatus[0] == 0
&& switchState1Old != 1) {                                      //if priority was activated and the
                                                                               //lights are off
//Serial.println("Priority switch deactivated switching on the lights"); //Debug only
lightOutput[0] =1;                                                     //switching on the lights
lightStatus[0] = 1;                                                    //setting the light status
roomTimer[0] = millis();                                          //setting the room timer
priorityStatus[0] = 0;                                               //setting the priority for bed 1 back //to 0
}
switchState1Old = switchState[1];
}                                                                          //closing the function


You found everything, - great, to confirm, below you have the complete function with all the changes.

void check_light_P(byte pir, byte prio, byte room, unsigned long light){
if(switchState[prio] == 0 && sensorValue <= photoCellCutOff) {   //checking if S2 priority off was
                                                                                                //set bed 1
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
                                                                                              //000000000000000000000001
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 relay status
roomTimer[room] = millis();                                                    //setting the timer
}
else if(switchState[pir] == 0 && lightStatus[room] == 1) {         //the PIR not activated but the
                                                                                             //lights are on
//Serial.println("We are checking the timer");                             //Debug only
currentTime = millis();                                                           //setting time reference
endTime = currentTime - roomTimer[room];                           //calculating the inactive time
if(endTime >= delayTime[room]) {                                         //comparing inactive time with
                                                                                          //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
&& switchState1Old != 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
&& switchState1Old != 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();                                             //setting the room timer
priorityStatus[room] = 0;                                                  //setting the priority for bed 1 back 
                                                                                      //to 0
}
switchState1Old = switchState[prio];                                 //passing on the switch state
}

And we are back up in the main loop where it says:

//////////////////room lights//////////////////////////////
check_master(0);                      //check if door switch was activated room 1 (bed1)
check_light_P(0, 1, 0, 1);          //check status room 1 (bed 1)
check_master(2);                      //check if door switch was activated room 2 (bed 2)

//Next we replace the following part including switchState3Old = switchState[3]; with

//check_light_P(2, 3, 1, 2); //check status room 2 (bed 2)


if(switchState[3] == 0 && sensorValue <= photoCellCutOff){     //checking if S4 priority off was
                                                                                             //set bed 2
if(switchState[2] == 1 && priorityStatus[1] == 0){                    //check if the PIR in bed 2 was
                                                                                             //activated (S3)
//Serial.println("We switch on the lights");                                 //debug only
lightOutput[1] = 2;                                                                  //switch on the lights
                                                                                             //Binary 0000000000000010
lightStatus[1] = 1;                                                                   //setting the light status
lightOutput[14] = 16384;                                                        //make sure the master relay
                                                                                            //stays on
lightStatus[14] = 1;                                                                 //setting the master relay status
roomTimer[1] = millis();                                                        //setting the timer
}
else if(switchState[2] == 0 && lightStatus[1] == 1) {               //the PIR not activated but the
                                                                                           //the lights are on
//Serial.println("We are checking the timer");                            //debug only
currentTime = millis();                                                           //setting time reference
endTime = currentTime - roomTimer[1];                                 //calculating the inactive time
if(endTime >= delayTime[1]) {                                               //comparing inactive time with
//Serial.println("Time is up we switch the lights off");                //debug only
lightOutput[1] = 0;                                                                 //switching off the lights
lightStatus[1] = 0;                                                                 //resetting the light status
roomTimer[1] = 0;                                                                //resetting the room timer
}
}
}
else if(switchState[3] == 1 && lightStatus[1] == 1
&& switchState3Old != 1) {                                         //if priority is activated and the
//lights are on
//Serial.println("Priority switch activated, switching off the lights");     //debug only
lightOutput[1] = 0;                                                       //switching off the lights
lightStatus[1] = 0;                                                        //resetting the light status
roomTimer[1] = 0;                                                       //resetting the room timer
priorityStatus[1] = 1;                                                    //setting the priority status for
                                                                                  //bed 2
}
else if(switchState[3] == 1 && lightStatus[1] == 0
&& switchState3Old != 1) {                                        //if priority is activated and the
//lights are off
//Serial.println("Priority switch off, switching the light back to normal"); //debug only
lightOutput[1] = 2;                                                     //switching ion the lights
lightStatus[1] = 1;                                                      //setting the light status
roomTimer[1] = millis();                                             //setting the room timer
priorityStatus[1] = 0;                                                  //resetting the priority status
}
switchState3Old = switchState[3];

The same we do with the next two rooms including the living room, so the part below reads like:

//////////////////room lights//////////////////////////////
check_master(0);                 //check if door switch was activated room 1 (bed1)
check_light_P(0, 1, 0, 1);     //check status room 1 (bed 1)
check_master(2);                 //check if door switch was activated room 2 (bed 2)
check_light_P(2, 3, 1, 2);     //check status room 2 (bed 2)
check_master(4);                 //check if door switch was activated room 3 (bed 3)
check_light_P(4, 5, 2, 4);     //check status room 3 (bed 3)
check_master(6);                //check if door switch was activated room 4 (living)
check_light_P(6, 7, 3, 8);      //check status room 4 (living)
check_master(8);                //check if door switch was activated room 5 (bath 1)
if(switchState[8] == 1) {     //checking S9 PIR of bathroom 1
                                         //(room 5)
//Serial.println("We switch on the lights"); //Debug only
lightOutput[4] = 16;            //switching on the lights
lightStatus[4] = 1;               //setting the light status
lightOutput[14] = 16384;     //make sure the master relay
                                        //stays on
lightStatus[14] = 1;             //setting the master relay status
roomTimer[4] = millis();      //setting the room timer
}

If you didn't catch up with everything don't worry to much. There will be quite a few changes now and before we start building the menu, I prepare and post a full code again with all valid changes.

Saturday, 26 April 2014

Room Management System – Adding a 16 x 2 LCD

I finally got around to do a little research and some homework do add the LCD to the room management system using only 3 wires and a shift register. First of all a big thanks to Chris Parish for publishing his circuit diagrams and the library to make it work.

Second, before we start, a small explanation what I would like to do with the display. The main goal is still the menu project, implementing a way of adjusting timers and sensitivity settings without hooking the system up to a computer or pulling the chip out for reprogramming. A second goal is to display a permanent system status. For example displaying if a circuit has to be activated or not which makes troubleshooting a little easier if something goes wrong.

We need a HD44780 based LCD display, a 74HC595 shift register, a 10 k trim pot, a 220 ohm resistor (optional) a pref board, some wire and about an hour time for soldering or a breadboard and some jump wires if you like to make it temporary for experimenting first. To get started we make a quick D-tour to Chris blog at http://cjparish.blogspot.com/2010/01/controlling-lcd-display-with-shift.html to have a look at the original wiring diagram and a different approach of building the adaptor. Please also download the library from his site and place it as usual with all the other libraries in the library folder of the Arduino IDE. All done so far?
Let me show you how I wired up my display adapter. All brown drawn wire connections are on the solder side. The two yellow wires are on the parts side as jumpers. I couldn't get the MOSFET which Chris originally used in his diagram, so I used a FQP30N06L which works as well. I added also a 220 ohm resistor between the VCC connection and the LCD pin 15 cause I found the back light a little bright. However, that's up to your liking, putting it in or change the value to your needs.



Finally we connect it to the Atmega chip. The data pin (74HC595 pin 14) goes to Arduino pin DI 9, the latch pin (74HC595 pin 12) goes to Arduino pin DI 10 and the clock pin (74HC595 pin 11) connects to Arduino pin DI 11. Don't forget to connect GND and VCC.




Now comes the interesting part. First we need to include the ShiftLcd library and there fore we go right on top of our room management system sketch:


#include <DS1307RTC.h>
#include <Time.h>
#include <Wire.h>
//>>>>>>>>>>>>>>>>That's' the library to include<<<<<<<<<<
#include <ShiftLCD.h>

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


From here we jump down to the end of the timer variables to where it says


byte room901Active = 1;                   //Set to 1 if you want to process
                                                      //Timer will be ignored when set to 0
unsigned int room9On[2] = {17, 45}; //Time to switch on the lights
unsigned int room9Off[2] = {18, 30}; //Time to switch off the lights
////////////////////////////DO NOT MODIVY BELOW HERE///////////////////////////////////////

//////////defining Arduino Pins/////////////////
//>>>>>>>>>>>>>here we add<<<<<<<<<<<<<<<<<<
ShiftLCD lcd(9, 11, 10);                  //initializing the LCD adaptor pins

Next, we go down to the setup loop:

void setup() {
//////////////Start Serial for Debugging/////////////////////

Serial.begin(9600);
//>>>>>>>>>>>>>>addition starts here<<<<<<<<<<<<<<<<<<
lcd.begin(16, 2);                           //start lcd
lcd.print("RMU 1.2.3");                 //print something 
delay(2000);                                //for read abilety
//>>>>>>>>>>>addition ends here<<<<<<<<<<<<<<<<<<<<<<
//////////////////defining pin modes////////////////////
pinMode(doorMonitor, OUTPUT);     //setting the LED pin to output
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);
OK so far. We move on and go down to the beginning of the holiday switch processing.

//////////////Holiday lighting/////////////////////////
//we need to move everything below this comment up to
// currentYear = tmYearToCalendar(tm.Year); //passing year to var
// }
//below the line, where it says “ //////////////////processing the input/////////////////////”
tmElements_t tm;                 //initializing RTC
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;        //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
}


After movement it looks like this:
//////////////////processing the input/////////////////////
tmElements_t tm;                   //initializing RTC
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;         //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
}

Right below the moved time declaration part we add the following

lcd.setCursor(0, 0);         //set the cursor to line 1 pos 1
lcd.print(" ");                  //print 15 blanks to delete all
                                     //prior statements
lcd.setCursor(0, 1);         //set cursor to row 2 pos 1
if(currentHour < 10) lcd.print("0");           //if the hour is less than 10
                                                            //we print a 0 to keep 2 digits
lcd.print(currentHour);                            //print current time (hour)
lcd.print(":");                                          //print separator
if(currentMinute < 10) lcd.print("0");        //if the minute is less than
                                                            //10 print 0 to keep 2 digits
lcd.print(currentMinute);                        //print current time (minutes)

The last statement will print the current time generated by the implemented RTC. Now it's time to see if it all works.

If everything went well the sketch will compile and if you have added a delay(1000), in the setup loop just after the lcd.print statement, what ever you wrote in this statement will show up and disappear and the current time will show at the beginning of row 2.
If you are getting an compiler error like:
/Users/dan/Documents/Arduino/libraries/ShiftLCD/ShiftLCD.h:116: error: conflicting return type specified for 'virtual void ShiftLCD::write(uint8_t)'

Please do the following:

Open the whatever/Arduino/libraries/ShiftLCD folder and

In ShiftLCD.h
Change line 116 to virtual size_t write(uint8_t);

In ShiftLCD.cpp
Change line 6 to #include "Arduino.h"
Change line 252 to inline size_t ShiftLCD::write(uint8_t value) {

If you have any further issues, please go through Chris blog, there are lots of explanations how things work. I have it running and compile with Arduino IDE 1.5.6 r2 and a Funduino Uno clone for testing and it is connected now to a stand alone Atmega 328.

In the next post I build the switch shield for the menu entries and start building the menu.

Thursday, 24 April 2014

Writing a menu for the Room Management System - Part 4


The final part of this approach will add the missing function to update the timers a dirty way of printing the updated values and a explanation how to carry on in the menu structure.

Let's start with showing the updated values on the lcd. Es just mentioned, it is not the most elegant way of doing it but I just wanted a quick possibility to check the response of the functions and the updated values. There fore we go straight down to the main loop.

void loop() {
while(digitalRead(btnMenu) != HIGH){      //keep on rolling over the values
                                                              //until we press the menu button
                                                              //with all the delays for readability
                                                              //you got to press the menu button
                                                             //for about 8 seconds to get out of it
lcd.clear();                                              //empty the screen
lcd.print("Sensitivity");                             //print the variable name
lcd.setCursor(0, 1);                                 //set the cursor to the next row
lcd.print(sensitivity);                                //print the value
delay(1000);                                           //delay for readability
lcd.clear();                                             //empty the screen
lcd.print("Room photo cut");                    //print the variable name
lcd.setCursor(0, 1);                                 //set the cursor to the next row
lcd.print(photoCellCutOff);                      //print the value
delay(1000);                                          //same thing for all the variables
lcd.clear();
lcd.print("Out photo cut");
lcd.setCursor(0, 1);
lcd.print(photoOutsideOff);
delay(1000);
lcd.clear(); //until here
lcd.print("R1 PIR delay");                           //print the variable name
lcd.setCursor(0,1);                                     //set the cursor to the next row
lcd.print(dBed1/60000);                              //print the value / 60000
                                                               //since the value is held in milliseconds
                                                               //we need to divide it through
                                                               //milliseconds contained in 1 minute
                                                               //(60000) to get the value displayed
                                                              //in minutes
lcd.setCursor(5, 1);                                  //set cursor to pos 5 in the second row
lcd.print("min");                                       //print min for minutes
delay(1000);                                            //delay for readability
lcd.clear();                                              //clear the screen
lcd.print("R1 HT On/Off");                       //print the variable name
lcd.setCursor(0, 1);                                 //set cursor to next row
if(room1MActive == 1){                          //if the timer is used (value 1)
lcd.print("Active");                                  //print “Active”
}
else {                                                     //if anything else is held in the var
lcd.print("Off");                                      //print “off”
}
delay(1000);                                          //delay for readability
lcd.clear();                                            //clear screen
lcd.print("R1 T1 Set time");                    //print var name
lcd.setCursor(0, 1);                               //set cursor to next row
lcd.print(room1OnM[0]);                       //print hour the timer activates
lcd.print(":");                                         //print separator
if(room1OnM[1] < 10) lcd.print("0");      //if the minute part is less then 10
                                                           //we add a leading 0
lcd.print(room1OnM[1]);                       //print minute the timer activates
lcd.setCursor(8, 1);                               //set cursor to second half of the row
lcd.print(room1OffM[0]);                     //print hour the timer deactivates
lcd.print(":");                                       //print separator
if(room1OffM[1] < 10) lcd.print("0");   //if the minute part is less than 10
                                                         //we add a leading 0
lcd.print(room1OffM[1]);                    //print minute the timer deactivates
delay(1000);                                       //delay for readability
}
delay(1000);                                       //delay for reaction time
lcd.clear();                                         //clear screen
lcd.print("Setup Mode");                      //now press menu button again to
                                                        //get into the setup mode
delay(1000);                                      //compensation for reaction time
button_loop();
}


As said, not an elegant way of doing it but I only needed a feedback to what is happening and it's nice to see that the values are changing.

For real implementation in the room management system a elegant way would be to add a switch to a free atmega pin and loop button_loop() function while the switch is activated like:

while(digitalRead(setupSwitch) == HIGH) button_loop();

This will keep the menu buttons accessible as long as the implemented switch is active.

Next we look at the function updating the timer. We can add it again right after the selectMenu() function. Variables the function needs is again a describing text what we are changing, the hour to switch on, the minutes to switch on, hour to switch off, minutes to switch off and the menu point where the call comes from.

unsigned int get_setTime(char timeText[], unsigned int onTimeH,
unsigned int onTimeM, unsigned int offTimeH,
unsigned int offTimeM, int menuPoint){
int subButton = 0;                            //resetting the subButton var
unsigned int onHourTS = onTimeH;   //passing the hour var for processing

//next we call the timer function we have already used to change some values.
//This comes in pretty handy since the entry is again a describing text, the actual
//value of the variable we need to change, the minimum and maximum set points
//here we pass the hour part of the switch on time of the timer

unsigned int onHourValue = get_Timer("Hour On", onHourTS, 0, 23);
if(onHourValue >= 0 && onHourValue < 24){              //if the returned value is
                                                                              //within the limits
unsigned int onMinuteTS = onTimeM;                        //we move on to the next
//next part. This time we pass the minutes of the switch on time to the get_Timer
//function
unsigned int onMinuteValue = get_Timer("Minutes On", onMinuteTS, 0, 59);
if(onMinuteValue < 60){                                            //if the returned value is
                                                                              //within the limits
unsigned int offHourTS = offTimeH;                          //we move on to the next part.
unsigned int offHourValue = get_Timer("Hour off", offHourTS, 0, 23);
if(offHourValue >= 0 && offHourValue < 24){
unsigned int offMinuteTS = offTimeM;
unsigned int offMinuteValue = get_Timer("Minute off", offMinuteTS, 0, 59);
if(offMinuteValue < 60){                                            //after processing all the parts
                                                                               //of the timer
lcd.clear();                                                               //clear the screen
lcd.setCursor(0, 1);                                                   //and print the updated results
lcd.print(onHourValue);
lcd.print(":");
if(onMinuteValue < 10)lcd.print("0");
lcd.print(onMinuteValue);
lcd.setCursor(8, 1);
lcd.print(offHourValue);
lcd.print(":");
if(offMinuteValue < 10) lcd.print("0");
lcd.print(offMinuteValue);
while(subButton != btnSelect){                                   //if we are happy with the results
subButton = read_buttons();                                       //we keep them
if(subButton == btnSelect){
lcd.clear();
lcd.print("Saving..... ");
delay(1000);
if(menuPoint == 3){                                                 //and pass them back to the original
room1OnM[0] = onHourValue;                                  //variables
room1OnM[1] = onMinuteValue;
room1OffM[0] = offHourValue;
room1OffM[1] = offMinuteValue;
}
}
}
return 0;
}
}
}
}
}

Looking through, we have all the functions we need to change all values in the main setup part of the sketch. Now lets have a quick look how to carry on in the menu structure. To carry on with the sub menus, we just go to the end of the selectMenu() function. And keep on adding:

if(room1SubMenu == 2){
get_offon("R1 T1 On Off", room1MActive);
return;
}
if(room1SubMenu == 3){
get_setTime("R1 T1 On/Off", room1OnM[0], room1OnM[1],
room1OffM[0], room1OffM[1], room1SubMenu);
return;
}
//>>>>>>>>>>>>>Keep on adding from here<<<<<<<<<<<<<<
//To finish the already initialised sub menus, we adding from here
if(room1SubMenu == 4){
get_offon(“R1 T2 On/Off”, room101Active);
return;
}
}
return;
}
}
}
}

And so on. Check the next sub menu point, call the appropriate function with the corresponding variables and we are done. Please don't forget to declare the variables in the top part of the sketch.
To carry on on the next main menu point, we have to pay a little attention. Our last main menu point was menuOption 6. We find exactly the part where we process the last main menu point (current case 6). We go to the opening bracket and find the corresponding closing bracket
if(menuOption == 4){
get_Timer("Set photo cut O", photoOutsideOff, 0, 1024);
return;
}
if(menuOption == 5){
return;
}
if(menuOption == 6){ //<<<<<<<<find the corresponding closing bracket
int subButton = 0;
room1SubMenu = 1;
lcd.clear();
lcd.print("R 1 PIR delay");
while(room1SubMenu < room1SubMenus){
subButton = read_buttons();
if(subButton == btnMenu){
|
|
|
if(room1SubMenu == 2){
get_offon("R1 T1 On Off", room1MActive);
return;
}
if(room1SubMenu == 3){
get_setTime("R1 T1 On/Off", room1OnM[0], room1OnM[1],
room1OffM[0], room1OffM[1], room1SubMenu);
return;
}
}
}
return;
} //<<<<<<<<<<<<<<after this bracket we have to carry on with main menu options
if(menuOption == 7){
int subButton = 0;
room2SubMenu = 1;
lcd.clear();
lcd.print("R 2 PIR delay");
while(room2SubMenu < room2SubMenus){
subButton = read_buttons();
if(subButton == btnMenu){
room2SubMenu++;
if(room2SubMenu == 2){

//to be carried on same like menu point 6.
//again, please do not forget to declare your new
//variables accordingly and close the opened brackets!!
//you also need to go back into the corresponding functions
//and add the statement to passing the updated value back to the 
//original variable
}
}

That's it for this approach. As mentioned, my next task is to get the 3 wire version of the lcd working and have a look in to working with the program memory not to use up to much RAM. If you have any questions about this one, please feel free to post it on the end and I will try to answer it as good as I can.