I am attempting to build a TIMER that keeps track of now vs what is saved in memory.
the idea is you save a time then you save a number of hours you want the timer to run.
The RTC is checked against the saved start time then if the RTC.now value is inside the window of the timer actions to take place.
So want to turn a light at lets say 1pm. I want that light to run for 12 hours. So the light should turn off at 1am. NOW!!!! OMG!!!! The power goes out at 5pm. I want the code to ensure that I am inside the time window I saved and turn the light back on. Ensure it is still turned off at 1am.
I've been beating my head against a wall. need a little help fellas. thanks.
for the sake of the code below, let me throw out some values.
byte light_hour = 11; // hour I want the lights on
byte light_min = 30; // min I want the lights on
byte light_am_pm = 1; //0 for am 1 for pm
int light_timer = 12; //how many hours I want the lights on
So I want the lights on at 11:30pm and run for 12 hours.
//these are process that always need to run no matter what screen is up
byte light_hour = EEPROM.read(lighthr_eeprom);
byte light_min = EEPROM.read(lightmin_eeprom);
byte light_am_pm = EEPROM.read(lightam_pm_eeprom);
int light_timer = EEPROM.read(lighttimer_eeprom);
DateTime now = RTC.now();
//convert light_hour back to military format if past noon
if(light_am_pm == 1){
light_hour = light_hour + 12;
}
//determine what hour ends the timer
int lightoffhour = light_hour + light_timer;
//adjust for going over 24 hours
Serial.print(" HOUR OFF - ");
Serial.println(lightoffhour);
if(lightoffhour > 23){
lightoffhour = lightoffhour - 24;
}
if(now.hour() >= light_hour ){
if(now.hour() >= lightoffhour){
Serial.println("LIGHTS OFF");
}
else if(now.hour() == light_hour){ // if current hour is same as saved hour
Serial.println("LIGHTS ON");
}
else{
Serial.println("LIGHTS ON");
}
}
if(now.hour() >= lightoffhour){
Serial.println("LIGHTS OFF");
}
Serial.print("light_hour - ");
Serial.println(light_hour);
Serial.print("light_timer - ");
Serial.println(light_timer);
Serial.print("lightoffhour - ");
Serial.println(lightoffhour);
One thing I notice is that you don't use UNIX timestamps, which would make life a lot easier. Then you can simply save the timestamp (seconds since epoch) of when the light went on, and keep it on for 12 * 60 * 60 seconds. Timing becomes very similar to the common millis() based timing, just that you use seconds instead of ms.
What RTC chip/module/method are you using? What RTC library?
All the common libraries will provide a method to get the time as a UNIX timestamp making the calculation simple.
I'm using a tinyRTC module and using the #include "RTClib.h" library.
how does this method ensure the timer restarts in the middle of the timer if the power is lost during that timeframe.
I see getting unix time from the RTC. but unless I store the time in EEPROM. it will get lost on power failure. I am attempting to avoid writing to EEPROM as much as possible. Only for things that need to be stored. I don't want to burn out my EEPROM.
Also, if power fails before timer starts. I cannot poll RTC for unix time as the time already passed. I have to know that oh wait the timer was supposed to turn on at 12am, it's now 12:23am. I just powered up. I need to turn this light on.
Why not just use battery power?
Charge the batteries with the main PS and if the main PS goes away you are powered with batteries until power comes back on, then no fancy save values or restore power code.
You store the timestamp to EEPROM when you start your 12-hour sequence.
The EEPROM is guaranteed to last at least 100,000 writes, so I don't see any issue there.
thaynes:
I have to know that oh wait the timer was supposed to turn on at 12am, it's now 12:23am. I just powered up. I need to turn this light on.
This is not super-difficult logic. Since calculations like this using UNIX timestamps are commonly used in logic in practically every programming environment, a web search will find you 1,000s of examples to study.
Just like in millis() timing you're not checking whether it IS the moment, but whether you're PAST the moment.
if (isOn && now() > switchOffTime) {
// switch off now.
}
if (isOff && now() > switchOnTime) {
// switch on now.
}
The on and off times are stored in EEPROM. Upon startup you read the values from EEPROM and set the state accordingly. Of course you can also use a timestamp in the past + interval, that also works.
ok you helpful people. I get your points using unix timestamp and other ideas presented. I am going to work on this and I'll post back what I figure out. thanks. I may have more questions. stay tuned!
wvmarle
I didn't post my entire sketch as it's several k lines long. I am reading from EEPROM every iteration of the loop(), I only write to it when I change it. I have a touchscreen menu where I set the time I want the lights to come on and for what duration. It's my understanding that the EEPROM flash storage can be read from infinately(within reason0, but only written to 100k times or so. So that's why i am avoiding writing much to EEPROM just data I need to store in case of a power failure, which doesn't change that often via user input via the touchscreen menu.
Many RTCs also have battery backed SRAM that you can store variables into. You can write those infinitely too.
Indeed...
OP mentions the "tinyRTC module". That one probably refers to a specific DS1307 module, which has 56 bytes of battery-backed SRAM, and also comes with 32kb flash (the 24C32 IC) which itself is rated 1 million writes. And that is of course per 32-byte page.
Ok guys. Thanks for all the help. Below is a sketch to get this to work. I store the light on and off times on the RTC module. Only user changes will eventually be stored in EEPROM using a touchscreen module. I will merge this logic into my other sketch. but here is how I did it. The first if logic in the void loop() accounts for blank rtc(for new modules), and sets everything based on time. this is just to make this sketch work. But I hope this helps someone else out in the future.
#include <Wire.h>
#include "RTClib.h"
#include <EEPROM.h>
RTC_DS1307 RTC;
unsigned long now_unix = 0;
unsigned long start_unix = 0;
unsigned long end_unix = 0;
int lighthr_eeprom = 2;
int lightmin_eeprom = 3;
int lightam_pm_eeprom = 4;
int lighttimer_eeprom = 5;
int mintrack = 555;
int doonce = 0;
void setup() {
Serial.begin(9600);
Wire.begin();
RTC.begin();
// Check to see if the RTC is keeping time. If it is, load the time from your computer.
if (! RTC.isrunning()) {
Serial.println("RTC is NOT running!");
// This will reflect the time that your sketch was compiled
RTC.adjust(DateTime(__DATE__, __TIME__));
}
// uncomment line below to reset for testing or to overwrite RTC and EEPROM
//RTC.writenvram(0,99);
// NVRAM 0 = LIGHT ON TIME; NVRAM1 = LIGHT OFF TIME
}
void loop() {
//get stored values
byte light_hour = EEPROM.read(lighthr_eeprom);
byte light_min = EEPROM.read(lightmin_eeprom);
byte light_am_pm = EEPROM.read(lightam_pm_eeprom);
int light_timer = EEPROM.read(lighttimer_eeprom);
DateTime now = RTC.now();
now_unix = now.unixtime();
if(RTC.readnvram(0) == 99){ // this IF statement sets up the eeprom and the rtc.nvram - new use only.
Serial.println("BLANK NVRAM - FIXING");
// used for testing setting sketch to run 1 minute in the future
if(now.hour() > 12){
EEPROM.write(lighthr_eeprom,now.hour()-12);
}
else{
EEPROM.write(lighthr_eeprom,now.hour());
}
EEPROM.write(lightmin_eeprom,now.minute());
int initam_pm = 1;
int inittimer = 18;
EEPROM.write(lightam_pm_eeprom,initam_pm); // set 0 or 1 for AM - PM
EEPROM.write(lighttimer_eeprom,inittimer); // how long timer should run in hours
light_hour = EEPROM.read(lighthr_eeprom);
light_min = EEPROM.read(lightmin_eeprom);
light_am_pm = EEPROM.read(lightam_pm_eeprom);
light_timer = EEPROM.read(lighttimer_eeprom);
Serial.println("EEPROM INFO BELOW");
Serial.print("HOUR - ");
Serial.println(light_hour);
Serial.print("MINUTE - ");
Serial.println(light_min);
Serial.println(light_am_pm);
Serial.print("TIMER IS SET FOR - ");
Serial.println(light_timer);
int hourtrack = 0;
int am_pm_track = 0;
if(now.hour() > 12){
hourtrack = now.hour() - 12;
am_pm_track = 1;
}
if(hourtrack == light_hour){
Serial.println("MATCHING HOUR");
Serial.print("WAITING UNTIL MINUTE MATCH OF ");
Serial.println(light_min);
Serial.print("MINUTE NOW IS ");
Serial.println(now.minute());
if(now.minute() == light_min){
Serial.println("minute matched");
if(am_pm_track == light_am_pm){
Serial.print("Setting timer to ");
Serial.print(light_timer);
Serial.println(" hours in the future");
Serial.println("TURNING LIGHTS ON");
Serial.print("TIME NOW IS ");
Serial.print(hourtrack);
Serial.print(":");
Serial.print(now.minute());
if(am_pm_track == 0){
Serial.print(" AM");
}
else{
Serial.print(" PM");
}
Serial.print(" - UNIX TIME IS ");
Serial.println(now.unixtime());
DateTime lighton (now + TimeSpan(0,light_timer,0,0));
Serial.print("LIGHTS WILL GO OFF AT ");
Serial.print("MILITARY TIME - ");
Serial.print(lighton.hour());
Serial.print(":");
Serial.print(lighton.minute());
Serial.print(" - LIGHT OFF UNIX TIME WILL BE ");
Serial.println(lighton.unixtime());
RTC.writenvram(1,lighton.unixtime());
RTC.writenvram(0,now.unixtime());
}
}
}
}
int rtclighton = RTC.readnvram(0);
int rtclightoff = RTC.readnvram(1);
if(doonce != now.minute()){ //only check once a minute
if(now.unixtime() < rtclightoff){ // TURN LIGHTS ON
Serial.println("LIGHTS ON");
}
else if(now.unixtime() > rtclighton){ // TURN LIGHTS ON
Serial.println("LIGHTS ON");
}
else{ // TURN LIGHTS OFF
Serial.print("LIGHTS OFF");
}
doonce = now.minute();
}
}
void printtime( ){
DateTime now = RTC.now();
if(mintrack != now.minute()){
//init clock
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.day(), DEC);
Serial.print('/');
Serial.print(now.year(), DEC);
Serial.print(" ");
if(now.hour() <=9 ){
Serial.print("0");
Serial.print(now.hour(), DEC);
}
else if(now.hour() > 12){
if((now.hour()-12) <= 9 ){
Serial.print("0");
Serial.print(now.hour()-12, DEC);;
}
else{
Serial.print(now.hour()-12, DEC);
}
}
else{
Serial.print(now.hour(), DEC);
}
Serial.print(':');
if(now.minute() <= 9){
Serial.print("0");
Serial.print(now.minute(), DEC);
}
else{
Serial.print(now.minute(), DEC);
}
mintrack = now.minute();
Serial.print(" ");
if(now.hour() <= 12){
Serial.print("AM");
}
else{
Serial.print("PM");
}
Serial.println(" ");
}
}