TimeAlarm - timers over 24 hours?

Afternoon,

I'm making a PID controller for meat curing which will control temperature and humidity with a heater, cooler, humidifier and dehumidifier in a sealed and insulated container. The quirk being that the set point for the RH and temp will change every few hours which may be above or below ambient (hence needing all four output devices).

To provide timing for these changes i'm using the TimeAlarm library, however some of the time periods these set points will be held at for will exceed 24 hours. I'm unsure if its possible for the "timerOnce" command to accept values above 23?

I've been programming without an Arduino in front of me, and it's far from finished code, when i do get a chance to test it, the thought of doing so over 30 or so hours is not something i look forward too. So to save me some time and hopefully get it right first time, could this excellent community browse over my code. I expect there to be many errors! but it does compile.

This is the part that i think i'll probably have a problem with:

Alarm.timerOnce(hour() + prgHour,0,0, prg);

The aim is to reset the alarm that calls the function that this line is within, whilst updating it be called again x amount of hours on top of the current time. The problem being, if the current time was 11pm, and the next phase needed to run for 30 hours, would 23+30 = 2 days and 5 hours later or just a confused Arduino?

Full code:

#include <PID_v1.h>
#include <Time.h>
#include <TimeAlarms.h>
#include <DS1307RTC.h>
#include <LiquidCrystal.h>
#include <Bounce.h>
#include <Encoder.h>
#include <Wire.h>

int RH, Temp, programme, prgStep, prgHour;

// Programme One - Snack Salami
int prgOne[] = {2, 36, 6, 6, 6, 6, 36, 144}; // Hours
int prgOneRH[] = {85, 92, 88, 85, 82, 80, 80, 80}; // Relative Humidity
int prgOneTemp[] = {22, 25, 22, 20, 17, 14, 12, 10}; // Temperature
// Programme Two - Saucison Sec
int prgTwo[] = {2, 48, 6, 6, 6, 12, 72, 144}; // Hours
int prgTwoRH[] = {85, 92, 88, 85, 82, 80, 80, 80}; // Relative Humidity
int prgTwoTemp[] = {22, 25, 22, 20, 17, 14, 12, 10}; // Temperature
// Programme three - Bacon
int prgThree[] = {2, 12, 3, 3, 3, 3, 3, 9}; // Hours
int prgThreeRH[] = {85, 92, 88, 85, 82, 80, 80, 80}; // Relative Humidity
int prgThreeTemp[] = {22, 25, 22, 20, 17, 14, 12, 10}; // Temperature
// Programme Four - Large Meat
int prgFour[] = {2, 60, 12, 12, 12, 12, 48, 132}; // Hours
int prgFourRH[] = {85, 92, 88, 85, 82, 80, 80, 80}; // Relative Humidity
int prgFourTemp[] = {22, 25, 22, 20, 17, 14, 12, 10}; // Temperature

//heater
double heInput, heOutput, heSetpoint;
double heKp = 1, heKi = 0.05, heKd = 0.25;
int windowSize = 5000;
unsigned long windowStartTime;
//cooler
double coInput, coOutput, coSetpoint;
double coKp = 1, coKi = 0.05, coKd = 0.25;
//humidifier
double huInput, huOutput, huSetpoint;
double huKp = 1, huKi = 0.05, huKd = 0.25;
//dehumidifier
double deInput, deOutput, deSetpoint;
double deKp = 1, deKi = 0.05, deKd = 0.25;

PID heater(&heInput, &heOutput, &heSetpoint, heKp, heKi, heKd, DIRECT);
PID cooler(&coInput, &coOutput, &coSetpoint, coKp, coKi, coKd, REVERSE);
PID humidifier(&huInput, &huOutput, &huSetpoint, huKp, huKi, huKd, DIRECT);
PID dehumidifier(&deInput, &deOutput, &deSetpoint, deKp, deKi, deKd, REVERSE);

void setup()
{
  Serial.begin(9600);
  setTime(0,0,0,1,1,13); // set time to Saturday 0:00:00am Jan 1 2013
  // setTime to be synced to RTC
  // Select program, map to 1,2,3 or 4
  programme = 1; // call function to get user input
  
  prgStep = 0;
  //Alarm.timerOnce(now() + prgHour,0,0, prg);
  prg;
  
  heInput = analogRead(0); // needs changing to input pin
  coInput = heInput;
  huInput = analogRead(0); // needs changing to input pin
  deInput = huInput;
  
  heSetpoint = Temp;
  coSetpoint = Temp;
  huSetpoint = RH;
  deSetpoint = RH;
  
  windowStartTime = millis();
  
  heater.SetOutputLimits(0, windowSize);
  
  heater.SetMode(AUTOMATIC);
  cooler.SetMode(AUTOMATIC);
  humidifier.SetMode(AUTOMATIC);
  dehumidifier.SetMode(AUTOMATIC);
  //output RH and Temp values to PID and initilise
}    


void  loop(){  
  Alarm.delay(0); // wait one second between clock display
  
  heInput = analogRead(0); // needs changing to input pin
  coInput = heInput;
  huInput = analogRead(0); // needs changing to input pin
  deInput = huInput;
  
  heater.Compute();
  cooler.Compute();
  humidifier.Compute();
  dehumidifier.Compute();
  unsigned long now = millis();
  if(now - windowStartTime>windowSize){ //time to shift the Relay Window
    windowStartTime += windowSize;
  }
  if(heOutput > now - windowStartTime){
    digitalWrite(1,HIGH); // Needs changing to output pin
  }
  else{
    digitalWrite(1,LOW); // Needs changing to output pin
  }
  analogWrite(1, coOutput); // Needs changing to output pin
  analogWrite(1, huOutput); // Needs changing to output pin
  analogWrite(1, deOutput); // Needs changing to output pin
  
  //write statistics to the screen and monitor buttons for exit (with conformation)
  //feedback current step, current temp, target temp, current RH, target RH, time left total, time to next step
}

void restart(){
  RH = 80;
  Temp = 10;
  programme = 2;// call function to get user input
  //setTime(0,0,0,1,1,13);
  prgStep = 0;
  
}
void prg(){
  if(prgStep == 8){
    restart;
    return;
  }
  else {
    switch (programme) {
      case 1:{ // Programme One - Snack Salami
        prgHour = prgOne[prgStep];
        RH = prgOneRH[prgStep];
        Temp = prgOneTemp[prgStep];
        break;
      }
      case 2:{ // Programme Two - Saucison Sec
        prgHour = prgTwo[prgStep];
        RH = prgTwoRH[prgStep];
        Temp = prgTwoTemp[prgStep];
        break;
      }
      case 3:{ // Programme three - Bacon
        prgHour = prgThree[prgStep];
        RH = prgThreeRH[prgStep];
        Temp = prgThreeTemp[prgStep];
        break;
      }
      case 4:{ // Programme Four - Large Meat
        prgHour = prgFour[prgStep];
        RH = prgFourRH[prgStep];
        Temp = prgFourTemp[prgStep];
        break;
      }
    }
    Alarm.timerOnce(hour() + prgHour,0,0, prg);
    prgStep = prgStep + 1;
    Serial.println("Program "); 
    Serial.print(programme);
    Serial.print(". Step ");
    Serial.print(prgStep -1);
    Serial.print(" of 8.");
  }
}
  prg;

What's this? It's not calling a function.

  Alarm.delay(0); // wait one second between clock display

The code does not match the comment. Delay calls with a value of 0 can cause problems.

    restart;

Not calling a function, either.

    prgStep = prgStep + 1;

Ah, yes, the infamous C=C+1 style of coding. Perhaps you've noticed that the Arduino is programed with C++, not C=C+1.

I think that adding an RTC, and triggering actions on your own is going to be a much better idea.

Alternatively, you could trigger the alarm every hour, and in the callback decide if it is actually time to do something.

I'm very new to this. As i said, my first real project. I've not had very much experiance with C++.

The majority of this code has been guess work as i dont actually have my arduino infront of me.

Looks like i missed the brackets off my attempts to call a function, so:
prg(); and restart(); i assume?

I missed updating the comment on the delay, it was a delay of 1000ms. Within the documentation is says you can use Alarm.delay(0) to just check the alarm status. prehaps i should raise it to 1 or 10 milliseconds?

prgStep incrementation changed to prgStep++;

I've bought a DS1307, it's in the mail so i'll impliment the code for that in the future. So far this is just one session of coding so plenty to do still!

Looks like i missed the brackets off my attempts to call a function, so:
prg(); and restart(); i assume?

Yes.

Within the documentation is says you can use Alarm.delay(0) to just check the alarm status.

That means that the library is specifically handling the delay(0) issue, so using the delay() method with a value of 0 is OK. Using the delay() function with a value of 0 is not.

prgStep incrementation changed to prgStep++;

Good. It's always better to look like you know what you are doing.

If you want to trigger an alarm at a date and time in the future then have a look at the trigger.Once method.

From the TimeAlarms readme :

"If you want to trigger once at a specified date and time you can use the trigger Once() method:
Alarm. triggerOnce(time_t value, explicitAlarm); // value specifies a date and time
(See the makeTime() method in the Time library to convert dates and times into time_t)"