Stopwatch with cumulative time using millis

Trying to display a stopwatch time and a cumulative time on a Photon in Blynk.

Stopwatch runs fine. Press a button and time starts counting from 0 until button is pressed again. Upon next press, time starts from 0.

What I am trying to do is sum the amount of time whenever the button is HIGH.
Something like an Hour Meter on an engine.

// This #include statement was automatically added by the Particle IDE.
#include <blynk.h>

SYSTEM_MODE(AUTOMATIC)
SYSTEM_THREAD(ENABLED);
char auth[] = "xxxxxxxxxxxxxxxxxxxxx";  

BlynkTimer timer; 

int latchButton;
int latchFlag;
int runHours;
int runMinutes;
int runSeconds;
int secsRemaining;
char buf[21];
unsigned long startMillis;
unsigned long endMillis;
unsigned long allSeconds;
unsigned long sumOfTime;
//===== Timed latching button =====
BLYNK_WRITE(V61) {  // Button Widget set as switch
  latchButton = param.asInt();
  if (latchButton == 1 && latchFlag == 0) {
    latchFlag = 1;  
  }
    else{
      Blynk.virtualWrite(V61, 0);  // Reset Latching Button to OFF
      latchFlag = 0;  // resets to allow next interaction
    }
  }

void ElapsedTime(){
  if (latchFlag == 1){ //When the button is active
    startMillis = millis(); // start from 0
    //The key process for displaying the converted duration
    
    allSeconds = (startMillis - endMillis) / 1000;
    
    secsRemaining = allSeconds % 86400;
    runHours = secsRemaining / 3600;
    secsRemaining = allSeconds % 3600;
    runMinutes = secsRemaining / 60;
    runSeconds = secsRemaining % 60;
    sprintf(buf, "Duration: %04d:%02d:%02d", runHours, runMinutes, runSeconds);
    Blynk.virtualWrite(V60, buf); // Label display widget
      //Blynk.virtualWrite(V61, sumOfTime);  // Need sumOfTime to be the amount of allSeconds + the next amount of allSeconds and so on. Measure the amount of time button was pressed in total.
  }
   else{
    endMillis = millis();
   }
}


void setup()
{
Serial.begin(115200);
Blynk.begin(auth);
timer.setInterval(1000L, ElapsedTime);
}

void loop()
{
Blynk.run();
timer.run();
}

Is there a request of any kind in there?
What does or doesn't your code do?
What is the delta between what it does and what you want it to do?
Have you actually tried coding what you have written in that elaborate comment?

sum = sum + x (or shorter sum += x) would jump to mind :wink:

BTW, what is this supposed to mean?

Hi @ScruffR. Sorry, copy paste mistake! Edited the original post.

I have tried a few things but the result was wrong.
Just trying to work out how to add the allSeconds after each flag change and save as sumOfTime to be displayed Blynk.virtualWrite(V61, sumOfTime);

The rest of the code works fine. Time resets after each flag change.

I don’t quite follow the logic.
Usually I’d expect your code to capture the starting time once on each odd (1st, 3rd, …) hit of the button and on each even hit (2nd, 4th, …) you’d capture the end time, calculate the difference, display that as latest lap time and add that difference to the accumulated time.
Between odd and even hit you’d not alter startMillis but only calculate millis() - startMillis for displaying the ongoing lap’s time.

You lost me on the odd and even part!

I understand you have one button to start an stop the timer, right?
If so, the first (odd number) press will start the timing, the second (even number) will stop, then the third (odd) will start again and the fourth (even) will stop again and so forth, right?

So start equals odd number triggers of the button while even number triggers will stop, or not?

Sure, you may not actually use a counter in your code, but in real life there will always be a first trigger followed by n subsequent ones, each time toggling between start and stop.

That is correct.
Didnt see the reason why it would be needed to use a counter. Is it needed in your opinion?
That part is working correctly, just dont know how to go about getting the cumulative time.

No, as indicated by this

Let me rewrite your code to what I'd think you want to do

#include <blynk.h>

SYSTEM_MODE(AUTOMATIC)
SYSTEM_THREAD(ENABLED);

const char auth[] = "xxxxxxxxxxxxxxxxxxxxx";  
BlynkTimer timer; 

unsigned long msStart     = 0;               // millis snapshot on last start / when 0 timing was stopped
unsigned long msLatestLap = 0;               // number of milliseconds for last lap 
unsigned long msTotal     = 0;               // number of milliseconds in total

BLYNK_WRITE(V61) {                           // Button Widget set as switch
  if (!msStart) {                            // when startMillis == =
    msStart = millis();                      // start the timing
    reportLap(0);                            // report started lap immediately
  }
  else {                                     // subsequent write will stop timing
    msLatestLap = millis() - msStart;        // calculate duration of last lap
    msStart = 0;                             // reset start snapshot (indicating no current timing)
    msTotal += msLatestLap;                  // add to total laps time
    reportLap(msLatestLap);                  // report final result for lap
    Blynk.virtualWrite(V61, msTotal/1000.0); // send back accumulated total  
  }
}

void ElapsedTime() {
  if (msStart)                               // when timing is ongoing
    reportLap(millis() - msStart);           // update current lap time
} 

void reportLap(uint32_t ms) {
  char buf[20];
  snprintf(buf, sizeof(buf), "Duration: %s", (const char*)Time.format(ms / 1000, "%T"));
  Blynk.virtualWrite(V60, buf);             // Label display widget
}

void setup() {
  Serial.begin(115200);
  Blynk.begin(auth);
  timer.setInterval(1000L, ElapsedTime);
}

void loop() {
  Blynk.run();
  timer.run();
}

Like this @ScruffR ?

// This #include statement was automatically added by the Particle IDE.
#include <blynk.h>



SYSTEM_MODE(AUTOMATIC)
SYSTEM_THREAD(ENABLED);
const char auth[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxx";  

BlynkTimer timer; 

int latchButton;
int latchFlag;
int runHours;
int runMinutes;
int runSeconds;
int secsRemaining;
char buf[21];
unsigned long startMillis;
unsigned long endMillis;
unsigned long allSeconds;
unsigned long sumOfTime;

unsigned long msStart     = 0;               // millis snapshot on last start / when 0 timing was stopped
unsigned long msLatestLap = 0;               // number of milliseconds for last lap 
unsigned long msTotal     = 0;               // number of milliseconds in total
//===== Timed latching button =====
BLYNK_WRITE(V61) {  // Button Widget set as switch
  latchButton = param.asInt();
  if (latchButton == 1 && latchFlag == 0) {
    latchFlag = 1;
  }
  if (!startMillis) {                        // when startMillis == =
    msStart = millis();                      // start the timing
    reportLap(0);                                      // report started lap immediately
  }
    else{
      Blynk.virtualWrite(V61, 0);                 // Reset Latching Button to OFF
      latchFlag = 0;                                   // resets to allow next interaction
      msLatestLap = millis() - msStart;        // calculate duration of last lap
    msStart = 0;                             // reset start snapshot (indicating no current timing)
    msTotal += msLatestLap;                  // add to total laps time
    reportLap(msLatestLap);                  // report final result for lap
    Blynk.virtualWrite(V59, msTotal/1000.0); // send back accumulated total  
    }
  }

void ElapsedTime(){
  if (latchFlag == 1){ //When the button is active
    startMillis = millis(); // start from 0
    //The key process for displaying the converted duration
    
    allSeconds = (startMillis - endMillis) / 1000;
    
    secsRemaining = allSeconds % 86400;
    runHours = secsRemaining / 3600;
    secsRemaining = allSeconds % 3600;
    runMinutes = secsRemaining / 60;
    runSeconds = secsRemaining % 60;
    sprintf(buf, "Duration: %04d:%02d:%02d", runHours, runMinutes, runSeconds);
    Blynk.virtualWrite(V60, buf);
  }
  if (msStart) {                                    // when timing is ongoing
    reportLap(millis() - msStart);           // update current lap time
  }
   else{
    endMillis = millis();
   }
}
void reportLap(uint32_t ms) {
  
}

void setup()
{
Serial.begin(115200);
Blynk.begin(auth);
timer.setInterval(1000L, ElapsedTime);
}

void loop()
{
Blynk.run();
timer.run();
}

Had to remove this to compile

void reportLap(uint32_t ms) {
  char buf[20];
  snprintf(buf, sizeof(buf), "Duration: %s", (const char*)Time.timeStr(ms / 1000, "%T"));
  Blynk.virtualWrite(V60, buf);             // Label display widget
}

Why? What was the error message?
Repairing that error should allow you to use my code (which seems somewhat less cluttered) as is.


I have updated the code above.