Coding a timer based system with ability to 'catch up'

Hi all,
I'm coding a timer system, at the moment something simple but I've already hit what may be a logic problem to how I'm tackling it.
The essence is the user can set ON, OFF and temperature values, which I do by a simple web-page that updates a JSON file on the Arduino/esp8266 littlefs filesystem. The structure is as follows:

{"sc_data":[{"dayofweek":"6","hourofday":"15","minuteofday":"00","settingvalue":"35"},{"dayofweek":"6","hourofday":"15","minuteofday":"45","settingvalue":"40"},{"dayofweek":"0","hourofday":"01","minuteofday":"00","settingvalue":"0"}],"scheduler":"1"}

In "sc_data" we hold the array of 3 values, dayofweek (0-6), hourofday (0-23), minuteofday (0-59) and setting value (int 0 being off, 1 being on, value >1 being a temperature).

In my code, I can check this against RTC (which I've loaded from ntp) and providing my device is running and the loop hits timing correct I can exactly match, dayofweek, hourofday and minuteofday.
However, what if I miss it? What if the unit is rebooted and is in the middle of a time-period?
I also do NOT sort my JSON stored array, so it could be in the wrong order (as in my example above, day 6 entries are first then there is a day 0 entry)

I'm trying to save memory, so I am using JUST the jsondocument store that I query/write and update:

DynamicJsonDocument doc_schedule(2048);

And my current timer check code is like this:

void heatschedule() {
  // read the json file
  File configFile = LittleFS.open("/schedule.json", "r");
  DeserializationError error = deserializeJson(doc_schedule, configFile, DeserializationOption::NestingLimit(4));
  if (error) {
    DEBUG_PRINT("Failed to open config /schedule.json file for reading error : " + String(error.c_str()));
  } else {
    DEBUG_PRINT("opened /schedule.json");
  };
  configFile.close();
	
  DateTimeParts p = DateTime.getParts();
  int CurrDay = p.getWeekDay();
  int Hours = p.getHours();
  int Minutes = p.getMinutes();
  DEBUG_PRINT("Current day of week: " + String(CurrDay));
  DEBUG_PRINT("Current hour: " + String(Hours));
  DEBUG_PRINT("Current mins: " + String(Minutes));
 for (JsonObject elem : doc_schedule["sc_data"].as<JsonArray>()) {
    if ((elem["dayofweek"].as<int>() == CurrDay) && (elem["hourofday"].as<int>() == Hours) && (elem["minuteofday"].as<int>() == Minutes)) {
      DEBUG_PRINT("DAY HOUR AND MINUTES MATCH - trigger value " + String(elem["settingvalue"].as<int>()));
	  trigger_heater(elem["settingvalue"].as<int>());
    };
  };
};

So you can see I do a simple if match for day,hour,minute, which obviously doesn't work if we come to this AFTER the trigger time (It's not an efficient way to do it, I understand that).

I'm trying to get my head round how to solve. Possibly convert day+hour+minute to seconds since epoch/unixtime? Still unsure if I could then do a simple sort/calculate to check the LAST trigger event easily.

Any logical hints/tips anyone can give me please?
Thank you!

You could convert the day/hour/minute value into a numeric value for example

int t = (day*24+hour)*60+min;

Then you can use >, >=, <, <= to compare with the current time so that you don't miss performing the comparison in the critical minute.

When you loop over the trigger times in the JSON message, you need to figure out which is the most recent, which you can do by calculating the trigger time as suggested above, then taking the difference from the current time and finding the smallest difference value. This will work fine for trigger times before the current time, but for future trigger times, you need to subtract 7 * 24 * 60 from the difference, in effect treating that trigger as though it was last week.

Hi Paul,

Thanks, really good suggestion that, I've implemented and running some tests which so far look promising. There is a gap in my logic, in that if say the last setting was a Saturday (day 6) and today is Monday (day 1) then my logic fails which is what I think you mean at the future trigger times?

Code now looks like:

void heatschedule() {
  // read the json file
  File configFile = LittleFS.open("/schedule.json", "r");
  DeserializationError error = deserializeJson(doc_schedule, configFile, DeserializationOption::NestingLimit(4));
  if (error) {
    DEBUG_PRINT("Failed to open config /schedule.json file for reading error : " + String(error.c_str()));
  } else {
    DEBUG_PRINT("opened /schedule.json");
  };
  configFile.close();
	
  DateTimeParts p = DateTime.getParts();
  int CurrDay = p.getWeekDay();
  int Hours = p.getHours();
  int Minutes = p.getMinutes();
  DEBUG_PRINT("Current day of week: " + String(CurrDay));
  DEBUG_PRINT("Current hour: " + String(Hours));
  DEBUG_PRINT("Current mins: " + String(Minutes));
 int curr_dtime_int = (CurrDay*24+Hours)*60+Minutes;
  int smallest_val = 999999999;
  int do_this_action = 999;
  for (JsonObject elem : doc_schedule["sc_data"].as<JsonArray>()) {
    // test int
    int test_dtime_int = curr_dtime_int - ((elem["dayofweek"].as<int>()*24+elem["hourofday"].as<int>())*60+elem["minuteofday"].as<int>());
    DEBUG_PRINT("Loop testing on day: " + String(elem["dayofweek"].as<int>()) + " so curr_dtime_int=" + String(curr_dtime_int) + " and test_dtime_int=" + String(test_dtime_int));
    if ((test_dtime_int > 0) && (smallest_val> test_dtime_int)) {
      smallest_val=test_dtime_int;
      DEBUG_PRINT("THIS is the new smallest value");
      do_this_action=elem["settingvalue"].as<int>();
    };
    
    if ((elem["dayofweek"].as<int>() == CurrDay) && (elem["hourofday"].as<int>() == Hours) && (elem["minuteofday"].as<int>() == Minutes)) {
      DEBUG_PRINT("DAY HOUR AND MINUTES MATCH - trigger value " + String(elem["settingvalue"].as<int>()));
      do_this_action=elem["settingvalue"].as<int>();
    };
  };
  
  // do_this_action now contains what we want to do!
  if (do_this_action < 999) {
  	trigger_heater(do_this_action);
  };
};

Yes, when the trigger time is a future trigger for the current week, your variable test_dtime_int will be negative. When that happens you can add 7 * 24 * 60 to test_dtime_int so that it is treated as a trigger from the previous week.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.