Translate

Sunday, 22 June 2014

Room Management System – Some final bug fixes and improvements


Being so focused on saving memory space and optimizing the code so everything fits on a Atmega 328 chip or a Arduino Uno board, I missed something. I just realized, that with the current code, the priority switches which we are using to stop the light from coming on in bed room while asleep are working but we have again the effect, that the light keeps on switching on and off while the button is pressed for a longer periode of time. But we want the light only to switch once per button press no matter for how long the button is pressed.
Let's go down in the declaration part of the sketch and find the section “/PIR and Room switch related var's/”

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

//>>>>>>>>>>>>>DELETE from here<<<<<<<<<<<<<<

byte switchState1Old = 0; //var to check if the priority switch state has changed

byte switchState3Old = 0; //var to check if the priority switch state has changed

byte switchState5Old = 0; //var to check if the priority switch state has changed

byte switchState7Old = 0; //var to check if the priority switch state has changed

//>>>>>>>>>>>>>DELETE ends here<<<<<<<<<<<<<<

//>>>>>>>>>>>>>ADD the line below<<<<<<<<<<<<<<

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

//////////////////////////////////////////////////////////////////////////////

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

The 4 variables which where checking if the switchState of the priority switches in the 3 bedrooms and the living room have changed don't work any more since we have banned this part of the code into a function and the function is not handling only 1 room, its handling all four rooms having a priority switch. Since it's the first four rooms it's easy, we just replace the the for variables with a 4 spaces containing array. To make it work we have to go down to our function check_light_P() and where ever we find a variable called “switchState1Old”, we replace it with switchStateOld[room]. Below you find the already updated function:

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 relay 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];

}

Here comes a small upgrade. In our lcd display, in row 0 , where we display the status of the shift register, displaying 1 or 0 to show if a output is activated or not I would like to keep a 16 digit display, so I can see straight away which room should be on or off. Currently we are loosing 1 digit every time the outside lighting goes off and if we are in the holiday timer option at some points of the day the display in row 0 isn't showing anything and that is because binary numbers drop there upper most digits soon as they turn 0.
The number 4 in a 16 bit binary would be:
0000000000000100
But the display would only show
100
since all the upper most digits turning to 0 are dropped.

This we do with help of a little function, which we place at the end of the main loop. Since we are currently displaying the output status in the first row and date and time in the second row of our display but having a bit more information to show, I made a little routine to change the display in the second row a little to show date and time in an interval exchanging with temperature and photocell reading.

We start again in the declaration part and there we go into the “all the other variables” section.

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

///////////////////////////////////////////////////////////////////////////////

////Sensor and timer variables

byte temperatur1 = 0; //holding temperature 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

//>>>>>>>>>>>>>ADD the line below<<<<<<<<<<<<<<

unsigned int displayTimeSet = millis()/1000; //variable needed for display exchange

////////////////////////////////////////////////////////////////////////////////////////

//////////////////////PIR and Room switch related var's/////////////////////////////////

from here we go down into the main loop in to the section where it says “processing the input”

//////////////////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 e.g. 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

//>>>>>>>>>>>>>DELETE the part marked<<<<<<<<<<<<<<

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

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 dot

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 separator

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)

//>>>>>>>>>>>>>DELETE ends here<<<<<<<<<<<<<

}

else {

get_error(0, 1);

}

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;

There fore we add:

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 e.g. 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);

}

//>>>>>>>>>>>>>ADDITION starts here<<<<<<<<<<<<<

endTime = (millis()/1000)  displayTimeSet; //set time reference

if(endTime <= 15) displayDateTime(); //display time for 15 seconds

if(endTime > (15) && endTime <= (30)) displayTemp(); //display temp and photocell reading for 15 sec.

if(endTime > 30) displayTimeSet = millis()/1000; //reset the timer

//>>>>>>>>>>>>>>ADDITION ends here

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;

now we go down to the end of the main loop:

outputL = 65535; //setting the output

//binary 1111111111111111

}

lcd.setCursor(0,0);

//>>>>>>>>>>>>>REPLACE the line below<<<<<<<<<<<<<<

lcd.print(outputL, BIN);

//>>>>>>>>>>>>>>>>>>>WITH this line <<<<<<<<<<<<<<<<<<<

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

outputL = 0; //setting the var holding the output

//number back to 0

delay(sensitivity); //delay to adjust how responsive the

//system will react

}

Time to build the three functions needed right at the end of the main loop:
The first function is the one keeping a 16 bit (digit) display. In praxis we can mark above the display what every digit is for. In our case from right to left it would be

bed room 1
bed room 2
bed room 3
Living
Bath room 1
Bath room 2
Bath room 3
Bath room 4
Kitchen
Corridor
AC bed 1
AC bed 2
AC bed 3
AC bed 4
Master relay
Outside lights

Having it setup this way might help in a later state trouble shooting since we no if a corresponding relay should be activated or not. If the corresponding digit indicates a 1 and a light does not come on you got to check if the relay itself is working and if it does than the problem is some where in the external part of the system. If the corresponding digit shows 0 while you jumping in front of the indicating PIR, than you might have to have a look at the PIR first and if you are sure that the PIR is working you have a more serious electronic problem.

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

}

}

}

Next is the function to display the time and date. If you deleted the part of code in the main loop which was displaying it you are fine. If you have been lazy like I was and just copied the part into a function, please delete the firs three lines:

  lcd.setCursor(0, 0);            //set the cursor to line 1 pos
  lcd.print("               ");   //print 15 blanks to delete all
                                  //prior statements

This part was responsible for a unsteady (blinking) first row on the LCD, which I was looking for to fix it for nearly a week!

//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 dot

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 separator

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(" ");

}

The last function is the one printing the temperature and light reading. The temperature reading we use direct since it returns the directly the temperature in degrees Celsius. OK, got the point. I put an option in to change it to Fahrenheit. The photocell reading is converted to output the value in lux from 0 (all dark) to 100000 (direct bright sunlight).

//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 temperature

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

}


No comments:

Post a Comment