Translate

Monday, 31 March 2014

Room Management System – Adding a Real Time Clock


Since I finally got my real time clock module and I had a bit of a play around with it, I want to add it to the controller. To begin with I thought of something simple to start with. We'll be adding some outside lighting to the controller. Could be the garden lights or balcony lights or just the lights in front of the main door. What I would like to do is to switch the lights on controlled by the photocell but I don't want them light up the whole night. At 23:30, when I go sleep, I want them to switch off for the rest of the night.

Let's start with putting the module (tiny RTC, i2C) on to the breadboard. Soon as you have a look at the image you may notice, that I am using the relay board to add the clock. That's only because the relay board is the only one with having a bit a space left to add something. If you remember the relay example we built, just bridge the 5 V bus with the one from one of the other two boards and do the same with the ground. You can connect the input of the relay circuit to any of the used shift register outputs. Important is that you connect straight after the shift register output pin and NOT after the LED or the resistor accompanying the LED. My real time clock module came without connectors and so I had solder quickly some pins to it to attach the jumpers. Careful, the soldering pints are very small. Next step is connecting the 5V pin to the 5V bus of the breadboard and the GND pin to ground on our breadboard. The SCL pin connects to pin 28 of the Atmega 328 and the SDA pin goes to the Atmega pin 27.





Before we can do anything with the clock, we need to download a library and set the time. First things first. We need to download DS1307RTC.zip, the Time library and TimeAlarms.zip from https://www.pjrc.com/teensy/td_libs_DS1307RTC.html. Unzip all three files into the library folder of your Arduino IDE restart the IDE and run the set Time example. To test the module, you can open and run the read time example. Take a bit a time to look over the two examples. Than the upcoming code additions in the room management system will look familiar.

Today we start right on top of our sketch. We go up to line no 1 and add on top of everything

///////////////////////////////includes/////////////////////////////////////
#include <DS1307RTC.h>
#include <Time.h>
#include <Wire.h>

//>>>>>>>>>>end of addition<<<<<<<<<<<<<<<<<

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

from here we move down just a little, where it says:

///////////Timer and Sensitivity Settings to be changed to individual needs////////////////
unsigned int sensitivity = 500;                      //should be between 200 and 1000 as
                                                                  //lower the number as more responsive
                                                                  //the system will be
unsigned int photoCellCutOff = 280;           //var holding the value where the photocell cuts off

//>>>>>>>>>>>>>>>>>>>\\next addition starts here<<<<<<<<<<<<<<<<<<<<<<<

unsigned int photoOutsideOn = 220;           //var holding the value which the photocell reading
                                                                 // has to reach for the lights to switch on
unsigned int hourOutsideOff = 23;              //var holding the time (full hours) in which the lights have
                                                                 //to switch off
unsigned int minuteOutsideOff = 30;           //var holding the time (minutes) in which the lights
                                                                 //have to switch off

//>>>>>>>>>>>>>>>>>>>>addition ends here again<<<<<<<<<<<<<<<<<<<<


Now we move down to the part where it says

////////////////all the other variables//////////////////////////////////
and on the end of this declaration block we add:

unsigned int outsideOnTime = 0;                     //checking result if the time is within
                                                                     //on or off time limits

For the next addition we need to go down a bit more and find the part:

//////////////////checking the light status//////////////////////

sensorValue = analogRead(lightSensor);            //reading the photocell

Serial.print("Sensor value: ");                            //Debug only
Serial.println(sensorValue);                               //Debug only
//////////////////processing the input/////////////////////

//>>>>>>>>>>>>>>>next addition starts here<<<<<<<<<<<<<<<<<<<<<

////////Outside lights////////////////////
outsideOnTime = checkOnTime(17, 00, hourOutsideOff, minuteOutsideOff); //function call to check time
Serial.print("Timer: ");                                                             //debug only
Serial.println(outsideOnTime);                                                 //Debug only
if(sensorValue <= photoOutsideOn | sensorValue < (photoOutsideOn + 50)  //checking the light value
&& outsideOnTime == 1){
lightOutput[15] = 32768;                                                        //switching on the lights
}
else {
lightOutput[15] = 0;                                                               //switching off the lights
}
//////////////////room lights//////////////////////////////

Last thing for today, we go all the way down to the bottom of the sketch and write a little function to check the times.

///////simple function to check on times

byte checkOnTime(byte hourOn, byte minuteOn, byte hourOff, byte minuteOff){
tmElements_t tm;
byte onTime = 0;                                               //return variable as no or off command (1,0)
long timeNow = 0;                                            //current time converted to Unix time
long onTrigger = 0;                                            //On time setting converted to Unix time
long offTrigger = 0;                                           //Off time setting converted to Unix time
if(RTC.read(tm)){                                            //reading the clock
timeNow = tmConvert_t(tmYearToCalendar(tm.Year), tm.Month, 
                                       tm.Day, tm.Hour, tm.Minute, tm.Second);      
                                                                       //function call to convert current time
onTrigger = tmConvert_t(tmYearToCalendar(tm.Year), tm.Month, 
                                      tm.Day, hourOn, minuteOn, 0); 
                                                                       //function call to convert switch on time
if(hourOff < hourOn) {                                     //checking if the off time is past midnight
offTrigger = tmConvert_t(tmYearToCalendar(tm.Year), 
                                       tm.Month, tm.Day+1, hourOff, minuteOff, 0); 
                                                                       //function call to convert switch off time
}
else {
offTrigger = tmConvert_t(tmYearToCalendar(tm.Year), 
                                       tm.Month, tm.Day, hourOff, minuteOff, 0); 
                                                                       //function call to convert switch off time before
                                                                       //midnight
}
if(timeNow >= onTrigger && timeNow < offTrigger) {               //comparing times
onTime = 1;
}
else {
onTime = 0;
}
}
Serial.print("Time now: ");                    //debug only
Serial.println(timeNow);                      //debug only
Serial.print("On trigger: ");                   //debug only
Serial.println(onTrigger);                      //debug only
Serial.print("Off Trigger: ");                  //debug only
Serial.println(offTrigger);                      //debug only

return onTime;                                     //return value on or off command (1, 0)
}


////////Function to convert real time to Unix time//////////////////
time_t tmConvert_t(int YYYY, byte MM, byte DD, byte hh, byte mm, byte ss)
{
tmElements_t tmSet;                                         //initializing the var holding the time to convert
tmSet.Year = YYYY – 1970;                          //year to be converted - 1970
tmSet.Month = MM;                                       //month to be converted
tmSet.Day = DD;                                            //day to be converted
tmSet.Hour = hh;                                            //hour to be converted
tmSet.Minute = mm;                                       //minute to be converted
tmSet.Second = ss;                                        //seconds to be converted
return makeTime(tmSet);                               //convert to Unix time
}

To see the results of our additions we need to add another LED to the test circuit. There for we connect a LED to the last free output of the second 74HC595 shift register with a 330 ohm resistor to ground.



After having a long play around with the real time clock and a hard time converting real time to Unix time I finally found a solution. All the standard approaches I found where I could have a peak how it is done didn't help me much since setting a time to trigger an on event and setting another time to trigger an off event will work as long as nothing goes wrong. Here in Malta we have something between 4 and 7 power cuts a year and we are dealing with people in rooms. A over filled kettle spilling water while it starts to boil, flooding the kettle base will through the circuit breaker and there we are. The clock module does have its on battery and as long as the battery is still good, it doesn't forget the time but we do not have the trigger any more to switch the light on or off. Unless we want to go through running the controller as well of a backup battery or having it run of a UPS I needed to find a way of checking also the time in between the on and off trigger.

Lets have a quick look at the added functions:
  1. byte checkOnTime(byte hourOn, byte minuteOn, byte hourOff, byte minuteOff)
    We are going in with hour and minutes we want to switch something on and off
    timeNow = tmConvert_t(tmYearToCalendar(tm.Year), tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second);
    Here we call the function tmConvert_t to convert the given real time to Unix time. In this call we just pass the readout of the clock module to get the current time.
    tmConvert_t(tmYearToCalendar(tm.Year), tm.Month, tm.Day, hourOn, minuteOn, 0);
    The same function call only this time we pass Year, Month and Day as it comes from the clock readout but the time variables are the preset times when we want to switch on the lights. The same happens with the next two function calls. The difference is that in the next call we pass the variables for the time we want the lights to switch off. The only thing we need to pay attention to is when the switch off time is passed midnight being carried to the next day. A simple if-statement is checking if the switch off time value is smaller than the switch on time value. Now, if the switch off time is passed midnight, we just add 1 day to the tm.Day readout and convert the result to Unix time.
    In the following if-statement we just need to compare the times to determine if the lights are to be switched on or off.
    if(timeNow >= onTrigger && timeNow < offTrigger)
  2. time_t tmConvert_t(int YYYY, byte MM, byte DD, byte hh, byte mm, byte ss)
    This little function was keeping busy for a whole afternoon. Since I didn't think about to deduct 1970 from the current year. I found the same function with a few valuable hints on the Arduino blog and still, it took me another 10 minutes to figure out why my one wasn't working properly and this one was. As you can see we are coming in with the complete date and time variables we want to convert. With “tmElements_t tmSet;” we initialize the variable tmSet. With the tmSet.Year, tmSet.Month, tmSet.Day....., we set the real-time time-string as we need it to be processed. The command makeTime(tmSet) converts the in tmSet contained real-time time-string in to Unix time.
Now we are good to go. In a future article we need to implement a function to accommodate for day light saving time and a possibility to update the time while the controller is connected to a network or a computer.

No comments:

Post a Comment