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:
- 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 offtimeNow = 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)
- 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.