Help With general coding please

hi im using this code to run some timers. the problem im having is i cant figure out how to skip one time and go to the next when i press a button. i can figure out the button code i just dont know how to call back to the class and switch to the next timer. hopefully you understand what i mean.

class PumpTimer {
    using functPtr = void(*)(void);
  public:
    PumpTimer(int pumpPin, uint32_t runTime, uint32_t pauseTime, functPtr stoppedAction = nullptr) : pin(pumpPin), cycleMillis(runTime), offMillis(pauseTime), callback(stoppedAction) {}
    void setTime(uint32_t runTime) {
      cycleMillis = runTime;
    }
    void setTime(uint32_t runTime, uint32_t pauseTime) {
      cycleMillis = runTime;
      offMillis = pauseTime;
    }
    uint8_t getPin() {
      return pin;
    }
    void setPauseTime(uint32_t pauseTime) {
      offMillis = pauseTime;
    }
    void init(void) {
      pinMode(pin, OUTPUT);
    }
    void start(uint32_t duration) {
      cycleMillis = duration;
      start();
    }
    void start(void) {
      startMillis = millis();
      state = ACTIVE_RUNNING;
      digitalWrite(pin, LOW);
      pumponstate = 0;
      digitalWrite(BLUE_PIN, HIGH);
    }
    void process(void) {
      switch (state) {
        case STOPPED:
          break;
        case ACTIVE_RUNNING:
          if (millis() - startMillis > cycleMillis) {
            digitalWrite(pin, HIGH);
            state = ACTIVE_PAUSED;
            startMillis = millis();
            pumponstate = 1;
            digitalWrite(BLUE_PIN, LOW);
            digitalWrite(GREEN_PIN, HIGH);
          }
          break;
        case ACTIVE_PAUSED:
          if (millis() - startMillis > offMillis) {
            state = STOPPED;
            pumponstate = 1;
            digitalWrite(BLUE_PIN, HIGH);
            digitalWrite(GREEN_PIN, LOW);
            if (callback) {
              callback();
            }
          }
          break;
      }
    }
    void stop(void) {
      digitalWrite(pin, HIGH);
      state = STOPPED;
      callback();
    }
  public:
    enum {
      STOPPED,
      ACTIVE_RUNNING,
      ACTIVE_PAUSED,
    } state = STOPPED;
    uint8_t pin;
    uint32_t cycleMillis;
    uint32_t offMillis;
    uint32_t startMillis;
    functPtr callback;
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////
PumpTimer timer[] = {                                                                                 /////
  /*Pin number, On Time, Pause Time and pointer to callback function */                               /////
  { 4, Pump_Timer(ontime1), Pump_Timer(offtime1), []() { //socket 1 pin 4             /////
      timer[1].start();                                                                               /////
   }                                                                                                  /////          
  },                                                                                                  /////    
 { 5, Pump_Timer(ontime1), Pump_Timer(offtime1), []() { //socket 2 pin 5              /////
     timer[0].start();                                                                                /////
      // }                                                                                            /////
      // },                                                                                           /////        
      //  { 6, Pump_Timer(ontime1), Pump_Timer(offtime1), []() { //socket 3 pin 6   /////           
      //    timer[2].start();                                                                         /////
    }                                                                                                 /////            
  },                                                                                                  /////      
};

for example this part of the code,

{ 4, Pump_Timer(ontime1), Pump_Timer(offtime1), []() { //socket 1 pin 4          
      timer[1].start();                                                                              
   }                                                                                                        
  },                                                                                                  
 { 5, Pump_Timer(ontime1), Pump_Timer(offtime1), []() { //socket 2 pin 5         
     timer[0].start();                                                                              
      }                                                                                           
      },                                                                                                
       { 6, Pump_Timer(ontime1), Pump_Timer(offtime1), []() { //socket 3 pin 6         
         timer[2].start();                                                                      
    }                                                                                                         
  },                                                                                                   
};

i would like to skip

{ 4, Pump_Timer(ontime1), Pump_Timer(offtime1), []() { //socket 1 pin 4          
      timer[1].start();

and move directly to

{ 5, Pump_Timer(ontime1), Pump_Timer(offtime1), []() { //socket 2 pin 5         
     timer[0].start();                                                                              
      }

when i press a button. i just cant figure out how to call for such a thing?

i tried chopping it up and using somthing like this but with no luck..,

      for (auto& t : timer) {
         t.startMillis = (millis() + t.cycleMillis);
         delay(100);
         t.startMillis = (millis() + t.startMillis);
         t.stop();
         t.start();
           
        }

Hold on a moment; rewind a little.

What are you trying to do? Explain it without using any Arduino code or class names.

Where did this code come from? Is there a link to a library we can see?

Can you post a complete program with setup() and loop() which demonstrates the problem?

well i got this code from someone on here. i asked for help creating a reliable timing systems and this is what they gave me. i changed it slightly to make things easier for me and so far its been working perfect. the only thing is when i start the timers it starts at pin 4 runs for a specific duration then moves to pin 5 then 6 then back to pin 4 and just repeats the timers. the problem im having is when i start my arduino the timers always start back at t.timer[0] which mean it always starts at the top of the list. well there are occasions i would like to skip timer 1 and 2 and start the timers on pin 6 then continue normally. i can handle the button side of things but i dont know what to tell the code to do when i push the button to skip the current timer that its on a proceed to the next?

when i want to stop the timers i can call this,

if (somevar == 0) {
 for (auto& t : timer) {
      t.stop();
      digitalWrite(4, HIGH); //off relay 1
      digitalWrite(5, HIGH); //off relay 2
      digitalWrite(6, HIGH); //off relay 3
    }
  }

to re enable them i can call this,

if (somevar == 1) {
 for (auto& t : timer) {
      t.init();
    }

but how can i skip the current timer its on and proceed directly to the next?

sorry im everywhere all over the place but right now i have the whole project offline when its being used in the field and i have no idea what im looking at. this code is a level of sophistication im not yet on that level. and i got sidetracked working with python to create a gui application to control this then when i went back to the arduino code to implement the feature to goto the next timer i barley new what i was looking at anymore.

this is the original code that is a little cleaner,

class PumpTimer {
  using functPtr = void(*)(void);
  public:
    PumpTimer(int pumpPin, uint32_t runTime, uint32_t pauseTime, functPtr stoppedAction) : pin(pumpPin), cycleMillis(runTime), offMillis(pauseTime), callback(stoppedAction) {}
    void setTime(uint32_t runTime) {
      cycleMillis = runTime;
    }
    void init(void) {
      pinMode(pin, OUTPUT);
    }
    void start(uint32_t duration) {
      cycleMillis = duration;
      start();
    }
    void start(void) {
      startMillis = millis();
      state = ACTIVE_RUNNING;
      digitalWrite(pin, HIGH);
    }
    void process(void) {
      switch (state) {
        case STOPPED:
          break;
        case ACTIVE_RUNNING:
          if (millis() - startMillis > cycleMillis) {
            digitalWrite(pin, LOW);
            state = ACTIVE_PAUSED;
            startMillis = millis();
          }
          break;
        case ACTIVE_PAUSED:
          if (millis() - offMillis > cycleMillis) {
            state = STOPPED;
            callback();
          }
          break;
      }
    }
    void stop(void) {
      digitalWrite(pin, LOW);
      state = STOPPED;
      callback();
    }
  private:
    enum {
      STOPPED,
      ACTIVE_RUNNING,
      ACTIVE_PAUSED,
    }state = STOPPED;
    uint8_t pin;
    uint32_t cycleMillis;
    uint32_t offMillis;
    uint32_t startMillis;
    functPtr callback;
};

PumpTimer timer[] = {   
/*Pin number, On Time, Pause Time and pointer to callback function */
  { 4, 8*60*1000UL, 12*60*1000UL, [](){timer[1].start();} },  // 8*60*1000UL, 12*60*1000UL, 
  { 5, 8*60*1000UL, 12*60*1000UL, [](){timer[2].start();} },
  { 6, 8*60*1000UL, 12*60*1000UL, [](){timer[0].start();} },
};

void setup() {
  for (auto& t : timer) {
    t.init();
  }
  timer[0].start();
}

void loop() {
  for (auto& t : timer) {
    t.process();
  }
  // do other non-blocking things here...
}

Yes, that’s a fairly advanced C++ code. It took me a little while to see what it does.

Basically, it declares an array of timers and makes each one’s final act to call the .start() method of the ‘next’ one in the sequence. The sequence is basically fixed and you can’t really interrupt or pause the timers because it’s difficult to see which timer is currently active. Even if you found which one was currently running, calling .stop() on it will cause it to start the next one.

But perhaps the solution to your problem is simple. Can you see in the setup() function that it calls .start() on the first timer? So you need to read the buttons at that point and then call the appropriate start.

const int buttonToStartWithSecondTimer = 2; //put the 'hold this down when switching on' button on pin 2
void setup() {
  for (auto& t : timer) {
    t.init();
  }
  pinMode(buttonToStartWithSecondTimer, INPUT_PULLUP);
  if(digitalRead(buttonToStartWithSecondTimer) == LOW) {
    //button is pushed now (during startup)    
    timer[1].start();
  } else {
    //default - start at the first timer
    timer[0].start();
  }
}

notsolowki:
well i got this code from someone on here.

Who? From whom?

Post a link to the Thread where you got the code.
Why did you not ask your question in the Thread where you got the code?
Why not ask the person who gave you the code to help out?

More generally, why not describe what you want to achieve - maybe there is a much simpler way.

...R

Robin2:
Who? From whom?

Post a link to the Thread where you got the code.
Why did you not ask your question in the Thread where you got the code?
Why not ask the person who gave you the code to help out?

More generally, why not describe what you want to achieve - maybe there is a much simpler way.

...R

The much simple way was to call these and based on there order it could start the next timer

  }
        else if (mode == 'N') {
            for (auto& t : timer) {
      timer[2].stop();
      timer[1].stop();
      
      
  }
   Serial.print("T 1 Started");
    }

    else if (mode == 'O') {
            for (auto& t : timer) {
      timer[0].stop();
      timer[1].stop();
      timer[0].stop();
      
  }
  Serial.print("T 2 Started");
    }

       else if (mode == 'P') {
            for (auto& t : timer) {
      timer[0].stop();
      timer[0].stop();
      timer[2].stop();
      
  }
  Serial.print("T 3 Started");
    }

duct tape.

notsolowki:
The much simple way was to call these and based on there order it could start the next timer

I had not realized my questions were so difficult.

...R

Robin2:
I had not realized my questions were so difficult.

...R

im pretty sure the person who wrote that for me is @BulldogLowell i dont know where the original thread is its been a while. and even though he wrote that for me i have since change a few things so its not entirely his work. i had to cut some corners to merge it with my project so the error you see are probably my doing for sure

notsolowki:
im pretty sure the person who wrote that for me is @BulldogLowell i dont know where the original thread is its been a while. and even though he wrote that for me i have since change a few things so its not entirely his work. i had to cut some corners to merge it with my project so the error you see are probably my doing for sure

OK. That deals with my first 4 questions. How about answering the 5th one as well?

...R

Original code:

enum SwitchState{
  TOGGLE_OFF,
  TOGGLE_ON,
  UNKNOWN,
} savedState = UNKNOWN;

void setCycle(SwitchState state);

constexpr uint32_t MINUTES_TO_MILLIS(uint32_t min) {
  return min * 60 * 1000;
};

constexpr uint32_t DEBOUNCE_TIME = 50;

class PumpTimer {
  using functPtr = void(*)(void);
  
  public:
    PumpTimer(int pumpPin, uint32_t runTime, uint32_t pauseTime, functPtr stoppedAction = nullptr) : pin(pumpPin), cycleMillis(runTime), offMillis(pauseTime), callback(stoppedAction) {}
    void setTime(uint32_t runTime) {
      cycleMillis = runTime;
    }
    void setTime(uint32_t runTime, uint32_t pauseTime) {
      cycleMillis = runTime;
      offMillis = pauseTime;
    }
    void setPauseTime(uint32_t pauseTime) {
      offMillis = pauseTime;
    }
    void init(void) {
      pinMode(pin, OUTPUT);
    }
    void start(uint32_t duration) {
      cycleMillis = duration;
      start();
    }
    void start(void) {
      startMillis = millis();
      state = ACTIVE_RUNNING;
      digitalWrite(pin, HIGH);
    }
    void process(void) {
      switch (state) {
        case STOPPED:
          break;
        case ACTIVE_RUNNING:
          if (millis() - startMillis > cycleMillis) {
            digitalWrite(pin, LOW);
            state = ACTIVE_PAUSED;
            startMillis = millis();
          }
          break;
        case ACTIVE_PAUSED:
          if (millis() - startMillis > offMillis) {
            state = STOPPED;
            if (callback) {
              callback();
            }
          }
          break;
      }
    }
    void stop(bool runCallback = false) {
      digitalWrite(pin, LOW);
      state = STOPPED;
      if (callback and runCallback) {
        callback();
      }
    }
  private:
    enum {
      STOPPED,
      ACTIVE_RUNNING,
      ACTIVE_PAUSED,
    } state = STOPPED;
    uint8_t pin;
    uint32_t cycleMillis;
    uint32_t offMillis;
    uint32_t startMillis;
    functPtr callback;
};

PumpTimer timer[] = {
  /*Pin number, On Time, Pause Time and pointer to callback function */
  { 4, MINUTES_TO_MILLIS(8), MINUTES_TO_MILLIS(12), []() {
      timer[1].start();
    }
  },
  { 5, MINUTES_TO_MILLIS(8), MINUTES_TO_MILLIS(12), []() {
      timer[2].start();
    }
  },
  { 6, MINUTES_TO_MILLIS(8), MINUTES_TO_MILLIS(12), []() {
      timer[0].start();
    }
  },
};

const uint8_t togglePin = 7;

void setup() {
  pinMode(togglePin, INPUT_PULLUP);
  for (auto& t : timer) {
    t.init();
  }
  timer[0].start();
}

void loop() {
  for (auto& t : timer) {
    t.process();
  }

  static uint32_t lastSwitchMillis = 0;
  SwitchState currentState = digitalRead(togglePin)? TOGGLE_OFF : TOGGLE_ON;
  if (currentState != savedState) {
    if (millis() - lastSwitchMillis > DEBOUNCE_TIME) {
      lastSwitchMillis = millis();
      savedState = currentState;
      setCycle(currentState);
    }
  }
}

void setCycle(SwitchState state) {
  switch (state) {
    case TOGGLE_OFF:
      for (auto& t : timer) {
        t.stop();
        t.setTime(MINUTES_TO_MILLIS(8), MINUTES_TO_MILLIS(12));
      }
      timer[0].start();
      break;
    case TOGGLE_ON:
      for (auto& t : timer) {
        t.stop();
        t.setTime(MINUTES_TO_MILLIS(15), MINUTES_TO_MILLIS(20));
      }
      timer[0].start();
      break;
    case UNKNOWN:
      // nothing to do here
      break;
  }
}

I "lent" it to OP, having once done something similar...

notsolowki:
i can figure out the button code i just dont know how to call back to the class and switch to the next timer. hopefully you understand what i mean.

you want something like this (not tested):

enum SwitchState{
  TOGGLE_OFF,
  TOGGLE_ON,
  UNKNOWN,
} savedState = UNKNOWN;

void setCycle(SwitchState state);
bool skipStep = false;

constexpr uint32_t MINUTES_TO_MILLIS(uint32_t min) {
  return min * 60 * 1000;
};

constexpr uint32_t DEBOUNCE_TIME = 50;

class PumpTimer {
  using functPtr = void(*)(void);
  
  public:
    PumpTimer(int pumpPin, uint32_t runTime, uint32_t pauseTime, functPtr stoppedAction = nullptr) : pin(pumpPin), cycleMillis(runTime), offMillis(pauseTime), callback(stoppedAction) {}
    void setTime(uint32_t runTime) {
      cycleMillis = runTime;
    }
    void setTime(uint32_t runTime, uint32_t pauseTime) {
      cycleMillis = runTime;
      offMillis = pauseTime;
    }
    void setPauseTime(uint32_t pauseTime) {
      offMillis = pauseTime;
    }
    void init(void) {
      pinMode(pin, OUTPUT);
    }
    void start(uint32_t duration) {
      cycleMillis = duration;
      start();
    }
    void start(void) {
      startMillis = millis();
      state = ACTIVE_RUNNING;
      digitalWrite(pin, HIGH);
    }
    void process(void) {
      switch (state) {
        case STOPPED:
          break;
        case ACTIVE_RUNNING:
          if (millis() - startMillis > cycleMillis) {
            digitalWrite(pin, LOW);
            state = ACTIVE_PAUSED;
            startMillis = millis();
          }
          break;
        case ACTIVE_PAUSED:
          if (millis() - startMillis > offMillis) {
            state = STOPPED;
            if (callback) {
              callback();
            }
          }
          break;
      }
    }
    void stop(bool runCallback = false) {
      digitalWrite(pin, LOW);
      state = STOPPED;
      if (callback and runCallback) {
        callback();
      }
    }
  private:
    enum {
      STOPPED,
      ACTIVE_RUNNING,
      ACTIVE_PAUSED,
    } state = STOPPED;
    uint8_t pin;
    uint32_t cycleMillis;
    uint32_t offMillis;
    uint32_t startMillis;
    functPtr callback;
};

PumpTimer timer[] = {
  /*Pin number, On Time, Pause Time and pointer to callback function */
  { 4, MINUTES_TO_MILLIS(8), MINUTES_TO_MILLIS(12), [&]() {
      if (skipStep) {
        timer[2].start();
        skipStep = false;
        digitalWrite(13, LOW);
      } else {
        timer[1].start();
      }
    }
  },
  { 5, MINUTES_TO_MILLIS(8), MINUTES_TO_MILLIS(12), [&]() {
      timer[2].start();
    }
  },
  { 6, MINUTES_TO_MILLIS(8), MINUTES_TO_MILLIS(12), [&]() {
      timer[0].start();
    }
  },
};

const uint8_t togglePin = 7;

void setup() {
  pinMode(13, OUTPUT);
  pinMode(togglePin, INPUT_PULLUP);
  for (auto& t : timer) {
    t.init();
  }
  timer[0].start();
}

void loop() {
//  pseudoCode... <<<<<< Insert your button press detection here!
//  if(buttonPressed) {
//    skipStep = true;
//    digitalWrite(D7, HIGH);
//  }
  for (auto& t : timer) {
    t.process();
  }

  static uint32_t lastSwitchMillis = 0;
  SwitchState currentState = digitalRead(togglePin)? TOGGLE_OFF : TOGGLE_ON;
  if (currentState != savedState) {
    if (millis() - lastSwitchMillis > DEBOUNCE_TIME) {
      lastSwitchMillis = millis();
      savedState = currentState;
      setCycle(currentState);
    }
  }
}

void setCycle(SwitchState state) {
  switch (state) {
    case TOGGLE_OFF:
      for (auto& t : timer) {
        t.stop();
        t.setTime(MINUTES_TO_MILLIS(8), MINUTES_TO_MILLIS(12));
      }
      timer[0].start();
      break;
    case TOGGLE_ON:
      for (auto& t : timer) {
        t.stop();
        t.setTime(MINUTES_TO_MILLIS(15), MINUTES_TO_MILLIS(20));
      }
      timer[0].start();
      break;
    case UNKNOWN:
      // nothing to do here
      break;
  }
}

Thankyou so much for this. I thank you every day i wake up and my timers are working perfectly! its really hard to learn everything so fast i’ve been working on python and java and i’m about to start visual studio and its hard to keep track of everything but ill be there one day. @BulldogLowell,