Repeat timer with ds3231

I want to make a timer that repeats its cycle, I want to be able to pick any "on time" HH:MM with 24hr time format. I have rtc setup but im trying without rtc and am changing the time values with irRemote.

This code below sort of makes sense. Im not able to make it work completely.

  unsigned long offTime = (unsigned long )(12L * 60 * 60) + (23 * 60) + 0;
  unsigned long onTime = (unsigned long )(12L * 60 * 60) + (20 * 60) + 0;
  unsigned long current = ((12 * 60) + 24) * 60;

  if ((current > onTime) && (current < offTime)) {
    Serial.println("off");
    Serial.print("offTime:");
    Serial.println(offTime);
    Serial.print("onTime:");
    Serial.println(onTime);
    Serial.print("current:");
    Serial.println(current);
  } else {
    Serial.println("on");
    Serial.print("offTime:");
    Serial.println(offTime);
    Serial.print("onTime:");
    Serial.println(onTime);
    Serial.print("current:");
    Serial.println(current);
    // turn on
  }

No matter what hour i change "current" to the i just see "on" in the serial console. current IS > than onTime but current is never less than offTime no matter what hour i set current to.

How can i make this work ?

Im not sure the logic of what i am trying to do. The 24hr time format has me confused a bit.

at 0 hours current would be very low, but what if i set to turn on at 23:23 and time rolls over to 01:01 how do i handle this?

And to add to this, can someone show me how i can also check after boot if the output should be on based on the current time?

Here is another program i have been messing with, in the current configuration "ON" never prints, just "?" and "off"

Im lost for words. Dont know what to do about this problem whatever it may be i wish i knew. i know it has something to do with the resulting seconds after the 24hr marker rolls back over to 0.

  unsigned long  currentHour = 1;
  unsigned long currentMinute = 20;
  unsigned long nowInSeconds = 0;
  unsigned long  onInSeconds = 0;
  unsigned long  offInSeconds = 0;
  int onHour = 22;
  int offHour = 3;
  int onMinute = 0;
  int offMinute = 0;

 // currentHour = now.hour();
  currentMinute = now.minute();
  nowInSeconds = ((23 * 60) + 1) * 60;
  onInSeconds = ((onHour * 60) + onMinute) * 60;
  offInSeconds = ((offHour * 60) + offMinute) * 60;

  if ((nowInSeconds >= onInSeconds) && (nowInSeconds < offInSeconds))
  {
    isTime = true;
    Serial.println("ON");
    //Serial.println(a);
  }
  else if ((nowInSeconds <= onInSeconds) && (nowInSeconds < offInSeconds))
  {
    isTime = true;
    Serial.println("?");
  //  Serial.println(a);
  } else {
    isTime = false;
    Serial.println("OFF");
   // Serial.println(a);
  }

This configuration,

  unsigned long  currentHour = 1;
  unsigned long currentMinute = 20;
  unsigned long nowInSeconds = 0;
  unsigned long  onInSeconds = 0;
  unsigned long  offInSeconds = 0;
  int onHour = 1;
  int offHour = 3;
  int onMinute = 0;
  int offMinute = 0;

 // currentHour = now.hour();
  currentMinute = now.minute();
  nowInSeconds = ((0 * 60) + 1) * 60;
  onInSeconds = ((onHour * 60) + onMinute) * 60;
  offInSeconds = ((offHour * 60) + offMinute) * 60;

and "?" is returned at serial.

this configuration,

  unsigned long  currentHour = 1;
  unsigned long currentMinute = 20;
  unsigned long nowInSeconds = 0;
  unsigned long  onInSeconds = 0;
  unsigned long  offInSeconds = 0;
  int onHour = 1;
  int offHour = 3;
  int onMinute = 0;
  int offMinute = 0;

 // currentHour = now.hour();
  currentMinute = now.minute();
  nowInSeconds = ((2 * 60) + 1) * 60;
  onInSeconds = ((onHour * 60) + onMinute) * 60;
  offInSeconds = ((offHour * 60) + offMinute) * 60;

prints "ON" in the serial console as i expect.

this configuration,

  unsigned long  currentHour = 1;
  unsigned long currentMinute = 20;
  unsigned long nowInSeconds = 0;
  unsigned long  onInSeconds = 0;
  unsigned long  offInSeconds = 0;
  int onHour = 1;
  int offHour = 3;
  int onMinute = 0;
  int offMinute = 0;

 // currentHour = now.hour();
  currentMinute = now.minute();
  nowInSeconds = ((4 * 60) + 1) * 60;
  onInSeconds = ((onHour * 60) + onMinute) * 60;
  offInSeconds = ((offHour * 60) + offMinute) * 60;

prints "OFF" in the serial consoles, also as i expect.

But i become really confused when setting the on/of time to something like this dont work as i want.

  int onHour = 22;
  int offHour = 3;

its not clear to me why im getting the results i am. Obviously because the if statement is doing its job, but how do i handle the hour rollover then?

Why not use the TimeAlarms library?

Im considering it. it seems like alot for this task but simplifies it for the user. Im trying to make a timerLib code work with RTC and sync the times but im getting a compiler error now,

#include "RTClib.h"
#include <TimeLib.h>
#include <TimeAlarms.h>
RTC_DS3231 rtc;
AlarmId id;
uint32_t syncProvider()
{
  return rtc.now().unixtime();  //either format works
  // DateTime now = RTC.now();
  // uint32_t s = now.unixtime();
  // return s;
}
void setup() {
  Serial.begin(115200);
  while (!Serial) ; // wait for Arduino Serial Monitor
  setSyncProvider(syncProvider()); // set the external time provider
  setSyncInterval(20); // set the number of seconds between re-sync
  if (timeStatus() != timeSet) {
    Serial.println("Unable to sync with the RTC");
  } else {
    Serial.println("RTC has set the system time");
  }
  setTime(8, 29, 0, 1, 1, 11); // set time to Saturday 8:29:00am Jan 1 2011

  // create the alarms, to trigger at specific times
  Alarm.alarmRepeat(4, 33, 0, MorningAlarm); // 8:30am every day
  Alarm.alarmRepeat(4, 34, 0, EveningAlarm); // 5:45pm every day
  // Serial.print(Time);
}

void loop() {
}

// functions to be called when an alarm triggers:
void MorningAlarm() {
  Serial.println("Alarm: - turn lights off");
}

void EveningAlarm() {
  Serial.println("Alarm: - turn lights on");
}


void OnceOnly() {
  Serial.println("This timer only triggers once, stop the 2 second timer");
  // use Alarm.free() to disable a timer and recycle its memory.
  Alarm.free(id);
  // optional, but safest to "forget" the ID after memory recycled
  id = dtINVALID_ALARM_ID;
  // you can also use Alarm.disable() to turn the timer off, but keep
  // it in memory, to turn back on later with Alarm.enable().
}
Arduino: 1.8.13 (Windows 10), Board: "Generic ESP8266, None, dtr (aka nodemcu), 26 MHz, 40MHz, DOUT (compatible), 1MB (FS:64KB OTA:~470KB), 2, 160 MHz, Flash, Legacy (new can return nullptr), All SSL ciphers (most compatible), Disabled, None, v2 Lower Memory, Only Sketch, 512000"

exit status 1

invalid conversion fro

m 'uint32_t {aka unsigned int}' to 'getExternalTime {aka long int (*)()}' [-fpermissive]

Okay i have come up with a more complete program, but the timers are not triggered. the rtc time is correct.

#include <LiquidCrystal_I2C.h>
#include "RTClib.h"
#include <TimeLib.h>
#include <TimeAlarms.h>
RTC_DS3231 rtc;
LiquidCrystal_I2C lcd(0x27, 5, 4);
unsigned long now2 = 0;
AlarmId id;
time_t  syncProvider()
{
  // return rtc.now().unixtime();  //either format works
  DateTime now = rtc.now();
  uint32_t s = now.unixtime();
  return s;
}
void setup() {
  rtc.begin();
  lcd.init();
  lcd.backlight();
  Serial.begin(115200);
  while (!Serial) ; // wait for Arduino Serial Monitor
  setSyncProvider(syncProvider); // set the external time provider
  setSyncInterval(2); // set the number of seconds between re-sync
  if (timeStatus() != timeSet) {
    Serial.println("Unable to sync with the RTC");
  } else {
    Serial.println("RTC has set the system time");
  }
  // setTime(8, 29, 0, 1, 1, 11); // set time to Saturday 8:29:00am Jan 1 2011

  // create the alarms, to trigger at specific times
  Alarm.alarmRepeat(5, 17, 0, MorningAlarm); // 8:30am every day
  Alarm.alarmRepeat(5, 18, 0, EveningAlarm); // 5:45pm every day
  // Serial.print(Time);
}

void loop() {
  if (millis() - now2 >= 500) {
    DateTime now = rtc.now();
    //  Serial.println(hour());
    now2 = millis();
    lcd.clear();
    lcd.setCursor(0, 3);
    lcd.print("         ");
    lcd.setCursor(0, 3);
    lcd.print("Clock:");

    lcd.setCursor(6, 3);
    lcd.print(now.hour());
    lcd.print(':');
    lcd.print(now.minute());
    lcd.print(':');
    lcd.print(now.second());
  }
}

// functions to be called when an alarm triggers:
void MorningAlarm() {
  Serial.println("Alarm: - turn lights off");
}

void EveningAlarm() {
  Serial.println("Alarm: - turn lights on");
}

i wish someone would just help me make this work without all these libraries

Okay it looks like i forgot to add Alarm.delay(0);

in the documentation is says set to 0 for minimal delay, how bad does using this library slow down the loop??

You could use some Serial.prints to see what is happening then go from there.

Serial.print( "current " );
Serial. print( current );
Serial.print( " onTime " );
Serial.print( onTime );
Serial.print( " offTime " );
Serial.print( offTime );
Serial.println();
`if ((current > onTime) && (current < offTime))`

With this configuration,

    unsigned long offTime = (unsigned long )(12L * 60 * 60) + (23 * 60) + 0;
  unsigned long onTime = (unsigned long )(12L * 60 * 60) + (20 * 60) + 0;
  unsigned long current = ((12 * 60) + 19) * 60;

i get this in the serial console,

21:16:07.017 -> on
21:16:07.017 -> offTime:44580
21:16:07.017 -> onTime:44400
21:16:07.017 -> current:44340

To make things more complicated, i need to be able to pick any time combination with an on duration of less than 24hrs.

It print on no matter what hour i set.

It is doing what you told it to do... (current is Less than onTime so showing "on")

I think you have on/off around the wrong way.

Also.. you need to allow for when the on time crosses midnight.

1 Like

That is exactly what im having trouble with the most. It seems so simple but i dont get it.

Well think of it this way...

1). If onTime is less than offTime... then you know it doesn't span midnight.
2). If onTime is more than offTime... then you know it does span midnight.

For each of these cases you need to do a different check.
1). onTime <= current && current < offTime, then On, else Off
2). offTime <= current && current < onTime, then Off, else On

1 Like

Forgive me for asking but can you explain how you come to this logic? im not saying your wrong i just want to be sure i understand why

Just think about it...

Consider a timeline representing the clock...

0-1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-0-1-2-3-4-5-6-7-8-9-10-11. ...

Your onAlarm sits on that line somewhere...

Lets say your onAlarm is 7-8-9-10 ... so the offTime is higher than the onTime. and you can check the current time is between them (7 and 10)... easy.

However, if you span midnight, say 22-23-0-2-3 then this isn't true. So you are better to look at the offAlarm 4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21... and compare currentTime to that (between 4 and 21), if it's not off it must be on.

1 Like

Okay it seems the explanation dont get better than that. thankyou.

So lets assume my times do span across the midnight point.

here is a sketch where i check if is am or pm hours, sadly this is far as my knowledge will take me.

  unsigned long offTime = (unsigned long )(12L * 60 * 60) + (23 * 60) + 0;
  unsigned long onTime = (unsigned long )(12L * 60 * 60) + (20 * 60) + 0;
  unsigned long current = ((a * 60) + 19) * 60;
  bool isAm = 0;
  if (now.hour() > 12) {
    isAm = false;
  } else {
    isAm = true;
  }

  if ((current > onTime) && (current < offTime)) {
    //on
  } else if ((current > onTime) && (current < offTime)) {
    
  }else{
    //off
  }

when im checking a time that spans midnight, am i comparing to offTime and current or onTime and current?

To figure out whether your on time spans midnight... just need onTime and offTime.

Once you know that, then you check whether current is between on and off (if yes then on, else off), or between off and on (if yes then off, else on)

1 Like

I'm sort of understanding the if statement a little more i think.

  unsigned long offTime = (unsigned long )(12L * 60 * 60) + (23 * 60) + 0;
  unsigned long onTime = (unsigned long )(12L * 60 * 60) + (20 * 60) + 0;
  unsigned long current = ((a * 60) + 19) * 60;

  if ((current > onTime) && (current < offTime)) {
    //on
  } else if ((current > offTime) && (current < onTime)) {
    //off?
  }else{
    //off
  }

Did i create that right? i hate to say but im still a little confused about the midnight point in the code.

I saw your other post where that guy was trying to help you... he actually said most of the same stuff I have. I still don't think you quite understand.

You need 2 layers of if...

if (not spanning midnight)
  if ((current >= onTime) && (current < offTime))
    // On
  else
    // Off
else if (spanning midnight)
  if ((current >= offTime) && (current < onTime))
    // Off
  else
    // On
1 Like

I think i have maybe close to what i need? But i must still have something wrong because im not getting anything in the serial console from the timer code.

Is my way for checking if offtime spans midnight okay?

  unsigned long offTime = (unsigned long )(1L * 60 * 60) + (23 * 60) + 0;
  unsigned long onTime = (unsigned long )(12L * 60 * 60) + (20 * 60) + 0;
  unsigned long current = ((a * 60) + 21) * 60;

  bool spanningMidnight = 0;
  if (offTime / 3600 > 12) {
    spanningMidnight = true;
  } else {
    spanningMidnight = false;
  }
  if (!spanningMidnight) {
    if ((current > onTime) && (current < offTime)) {
      Serial.println("on");
      //on
    } else {
      Serial.println("off");
      //off
    }
  } else if (spanningMidnight) {
    if ((current >= offTime) && (current < onTime)) {
      Serial.println("off2");
      //off
    }
  } else {
    Serial.println("on2");
    //on
  }

No. Where did that logic come from?

Did you not read this?

1 Like

Okay please forgive me i misunderstood. Should i have a variable to set a flag if spanning midnight?

Like this?

bool spanningMidnight = 0;
  if (onTime < offTime) {
    spanningMidnight = false;
  } else {
    spanningMidnight = true;
  }