Loosing value of a variable after exiting the if statement

This is my first post
This is my first Arduino project, took me a week to get here :slight_smile:
Thanks in advance.

Problem Summary: Varible "VacuumOnTimeStamp" looses it's value right after the code exits the if statement.
Question: How do I fix this variable so it keeps it's value?

Sample Console Output:

Vacuum State Changed to: HIGH
TimeNow equals: 1589219458
VacuumOnTimeStamp equals: 1589219458
TimeNow equals: 1589219458
VacuumOnTimeStamp equals: 0 <-This is the WTF Moment, should still equal 1589219458
TimeNow equals: 1589219458
VacuumOnTimeStamp equals: 0
TimeNow equals: 1589219459
VacuumOnTimeStamp equals: 0
TimeNow equals: 1589219459

Here is my code:

// Allows printing and interaction with the Arduino Yun Console
#include <Console.h>
#include <Process.h>
#include <Time.h>

// Adafruit SSD1306 - Version: Latest 
//#include <Adafruit_SSD1306.h>
//#include <splash.h>

// Adafruit GFX Library - Version: Latest 
//#include <Adafruit_GFX.h>
//#include <Adafruit_SPITFT.h>
//#include <Adafruit_SPITFT_Macros.h>
//#include <gfxfont.h>

/*Vacuum and Compressed Air Controller
Written by Douglas Rich
Initial Creation Date: 5/3/2020
Current Version: 0.01
Version Date: */

// Varibles for keeping track of time
Process date;                 // process used to get the date
String sHours, sMinutes, sSeconds, sDay, sMonth, sYear;
int iHours, iMinutes, iSeconds, iDay, iMonth, iYear;
String timeString;
int ind1, ind2, ind3, ind4, ind5;
unsigned long AirTimeFuture, VacuumTimeFuture, AirOnTimeStamp, VacuumOnTimeStamp;
const int DefaultRunTime = 60;

// constants won't change. They're used here to set pin numbers:
const int AirButtonPin = 4;    // the number of the pushbutton pin for the Air Compressor
const int VacuumButtonPin = 8;    // the number of the pushbutton pin for the Vacuum
const int AirPin = 5;      // the number of the  Air Relay pin
const int VacuumPin = 6;      // the number of the Vacuum Relay pin

// Variables will change:
int AirState = LOW;         // the current state of the output pin
int VacuumState = LOW;         // the current state of the output pin
int AirButtonState = HIGH;             // the current reading from the input pin
int AirLastButtonState = HIGH;   // the previous reading from the input pin
int VacuumButtonState = HIGH;             // the current reading from the input pin
int VacuumLastButtonState = HIGH;   // the previous reading from the input pin

// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long AirLastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long VacuumLastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  // Initialize Console and wait for port to open:
  Bridge.begin();
  Console.begin();

  // Wait for Console port to connect, requires console input to continue
//  while (!Console);
    
  pinMode(AirButtonPin, INPUT_PULLUP);
  pinMode(VacuumButtonPin, INPUT_PULLUP);
  pinMode(AirPin, OUTPUT);
  pinMode(VacuumPin, OUTPUT);

  // set initial Relay state
  digitalWrite(AirPin, AirState);
  digitalWrite(VacuumPin, VacuumState);
  
  // Define process parameters
  date.begin("/bin/date");
  date.addParameter("+%H,%M,%S,%d,%m,%y");
  date.run();

  // if there's a result from the date process, get it.
  while (date.available() > 0) {
    timeString = date.readString();
    timeString.trim();
  }

  // Parse the substrings of the csv string "timeString"
  ind1 = timeString.indexOf(',');  //finds location of first ,
  sHours = timeString.substring(0, ind1);   //captures first data String
  ind2 = timeString.indexOf(',', ind1 + 1 ); //finds location of second ,
  sMinutes = timeString.substring(ind1 + 1, ind2); //captures second data String
  ind3 = timeString.indexOf(',', ind2 + 1 );
  sSeconds = timeString.substring(ind2 + 1, ind3);
  ind4 = timeString.indexOf(',', ind3 + 1 );
  sDay = timeString.substring(ind3 + 1, ind4); //captures remain part of data after last ,
  ind5 = timeString.indexOf(',', ind4 + 1 );
  sMonth = timeString.substring(ind4 + 1, ind5); //captures remain part of data after last ,
  sYear = timeString.substring(ind5 + 1); //captures remain part of data after last ,

  // convert to ints
  iHours = sHours.toInt();
  iMinutes = sMinutes.toInt();
  iSeconds = sSeconds.toInt();
  iDay = sDay.toInt();
  iMonth = sMonth.toInt();
  iYear = sYear.toInt();

  // Sets the Arduino Time
  setTime(iHours, iMinutes, iSeconds, iDay, iMonth, iYear);
  delay(100);
  time_t TimeNow = now();
}

void loop() {
  // Added a delay for power outages. Slow pullup resistors will trigger Control Pins high without this delay.
//  if (millis() < 10000 ) {
//    delay(10000);
//  }

  // Update the Current Time
  time_t TimeNow = now();
  
  // read the state of the switch into a local variable:
   int AirReading = digitalRead(AirButtonPin);
   int VacuumReading = digitalRead(VacuumButtonPin);
  
  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH), and you've waited long enough
  // since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (AirReading != AirLastButtonState) {
    // reset the debouncing timer
    AirLastDebounceTime = millis();
  }
  if (VacuumReading != VacuumLastButtonState) {
    // reset the debouncing timer
    VacuumLastDebounceTime = millis();
  }
  
  if ((millis() - AirLastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:

    // if the button state has changed:
    if (AirReading != AirButtonState) {
      AirButtonState = AirReading;

      // only toggle the Relay if the new button state is LOW
      if (AirButtonState == LOW) {
        AirState = !AirState;
        if (AirState) {
        Console.println("Air State Changed to: HIGH");
        time_t AirOnTimeStamp = now();
        Console.print("TimeNow equals: ");
        Console.println(TimeNow);
        Console.print("AirOnTimeStamp equals: ");
        Console.println(AirOnTimeStamp);
        }
        else {
        Console.println("Air State Changed to: LOW");
        }
      }
    }
  }
  if ((millis() - VacuumLastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:

    // if the button state has changed:
    if (VacuumReading != VacuumButtonState) {
      VacuumButtonState = VacuumReading;

      // only toggle the Relay if the new button state is LOW
      if (VacuumButtonState == LOW) {
        VacuumState = !VacuumState;
        if (VacuumState) {
        Console.println("Vacuum State Changed to: HIGH");
        time_t VacuumOnTimeStamp = now();
        Console.print("TimeNow equals: ");
        Console.println(TimeNow);
        Console.print("VacuumOnTimeStamp equals: ");
        Console.println(VacuumOnTimeStamp);
        }
        else {
        Console.println("Vacuum State Changed to: LOW");
        }        
      }
    }
  }

  // set the Relay State:
   digitalWrite(AirPin, AirState);
   digitalWrite(VacuumPin, VacuumState);

   Console.print("TimeNow equals: ");
   Console.println(TimeNow);
   Console.print("VacuumOnTimeStamp equals: ");
   Console.println(VacuumOnTimeStamp);
//  if (TimeNow > (AirOnTimeStamp + DefaultRunTime)) {
//    Console.println("Air Time Elapsed");
//    digitalWrite(AirPin, LOW);
//  }
//  if (TimeNow > (VacuumOnTimeStamp + DefaultRunTime)) {
//    Console.println("Vacuum Time Elapsed");
//    digitalWrite(VacuumPin, LOW);
//  }

  // save the reading. Next time through the loop, it'll be the lastButtonState:
  AirLastButtonState = AirReading;
  VacuumLastButtonState = VacuumReading;
}

the variable needs to be defined uniquely outside the function in order to use it outside the function and not define both outside and inside the function

it's defined globally at the top.

So I just changed this line:
time_t VacuumOnTimeStamp = now();

to this:
VacuumOnTimeStamp = now();

and that seemed to fix it.. Perhaps that's what you were saying.. my vocabulary here is limited so I didn't really understand completely.

I think this is a result of me copy past others code without fully understanding what: "time_t" does

Yes, that’s exactly it.

This...

time_t VacuumOnTimeStamp;

Is a declaration of variable named VacuumOnTimeStamp of type time_t.
It is a completely different variable (with different memory allocation) from any other variable declaration that the programmer may have declared earlier with the same name.

This...

VacuumOnTimeStamp = now();

Is a variable assignment.
It assigns a new value to the previously declared variable VacuumOnTimeStamp.

This...

time_t VacuumOnTimeStamp = now();

Is a “shorthand” declaration and an assignment in one go.
It is NOT the same as just an assignment.

It is very bad coding style to have multiple declarations (either on their own or the shorthand flavour) with the same name in any C program. C allows it and, if you understand variable scope, you as a human can probably work out what it does.

However best avoided. It doesn’t add anything to the language that you can’t express more clearly using unique names for every variable declaration, and thus not Run the risk of getting caught out by not recognising where an inner scoped variable overrides one declared with the same name in an outer scope.

Thanks Guys!

Here is the fixed working code:

// Allows printing and interaction with the Arduino Yun Console
#include <Console.h>
#include <Process.h>
#include <Time.h>

// Adafruit SSD1306 - Version: Latest
//#include <Adafruit_SSD1306.h>
//#include <splash.h>

// Adafruit GFX Library - Version: Latest
//#include <Adafruit_GFX.h>
//#include <Adafruit_SPITFT.h>
//#include <Adafruit_SPITFT_Macros.h>
//#include <gfxfont.h>

/*Vacuum and Compressed Air Controller
  Written by Douglas Rich
  Initial Creation Date: 5/3/2020
  Current Version: 0.01
  Version Date: */

// Varibles for keeping track of time
Process date;                 // process used to get the date
String sHours, sMinutes, sSeconds, sDay, sMonth, sYear;
int iHours, iMinutes, iSeconds, iDay, iMonth, iYear;
String timeString;
int ind1, ind2, ind3, ind4, ind5;
unsigned long AirTimeFuture, VacuumTimeFuture, AirOnTimeStamp, VacuumOnTimeStamp;
const unsigned long DefaultRunTime = 20;

// constants won't change. They're used here to set pin numbers:
const int AirButtonPin = 4;    // the number of the pushbutton pin for the Air Compressor
const int VacuumButtonPin = 8;    // the number of the pushbutton pin for the Vacuum
const int AirPin = 5;      // the number of the  Air Relay pin
const int VacuumPin = 6;      // the number of the Vacuum Relay pin

// Variables will change:
int AirState = LOW;         // the current state of the output pin
int VacuumState = LOW;         // the current state of the output pin
int AirButtonState = HIGH;             // the current reading from the input pin
int AirLastButtonState = HIGH;   // the previous reading from the input pin
int VacuumButtonState = HIGH;             // the current reading from the input pin
int VacuumLastButtonState = HIGH;   // the previous reading from the input pin

// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long AirLastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long VacuumLastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers
time_t TimeNow = now();

void setup() {
  // Initialize Console and wait for port to open:
  Bridge.begin();
  Console.begin();

  // Wait for Console port to connect, requires console input to continue
  //  while (!Console);

  pinMode(AirButtonPin, INPUT_PULLUP);
  pinMode(VacuumButtonPin, INPUT_PULLUP);
  pinMode(AirPin, OUTPUT);
  pinMode(VacuumPin, OUTPUT);

  // set initial Relay state
  digitalWrite(AirPin, AirState);
  digitalWrite(VacuumPin, VacuumState);

  // Define process parameters
  date.begin("/bin/date");
  date.addParameter("+%H,%M,%S,%d,%m,%y");
  date.run();

  // if there's a result from the date process, get it.
  while (date.available() > 0) {
    timeString = date.readString();
    timeString.trim();
  }

  // Parse the substrings of the csv string "timeString"
  ind1 = timeString.indexOf(',');  //finds location of first ,
  sHours = timeString.substring(0, ind1);   //captures first data String
  ind2 = timeString.indexOf(',', ind1 + 1 ); //finds location of second ,
  sMinutes = timeString.substring(ind1 + 1, ind2); //captures second data String
  ind3 = timeString.indexOf(',', ind2 + 1 );
  sSeconds = timeString.substring(ind2 + 1, ind3);
  ind4 = timeString.indexOf(',', ind3 + 1 );
  sDay = timeString.substring(ind3 + 1, ind4); //captures remain part of data after last ,
  ind5 = timeString.indexOf(',', ind4 + 1 );
  sMonth = timeString.substring(ind4 + 1, ind5); //captures remain part of data after last ,
  sYear = timeString.substring(ind5 + 1); //captures remain part of data after last ,

  // convert to ints
  iHours = sHours.toInt();
  iMinutes = sMinutes.toInt();
  iSeconds = sSeconds.toInt();
  iDay = sDay.toInt();
  iMonth = sMonth.toInt();
  iYear = sYear.toInt();

  // Sets the Arduino Time
  setTime(iHours, iMinutes, iSeconds, iDay, iMonth, iYear);
  delay(1000);
  //  time_t TimeNow = now();

  // Set Varibles to starting value
  TimeNow = now();
  AirOnTimeStamp = TimeNow;
  VacuumOnTimeStamp = TimeNow;

}

void loop() {
  // Added a delay for power outages. Slow pullup resistors will trigger Control Pins high without this delay.
  //  if (millis() < 10000 ) {
  //    Console.println("Start Up!");
  //    delay(10000);
  //  }

  // Update the Current Time and set Startup values
  TimeNow = now();


  // read the state of the switch into a local variable:
  int AirReading = digitalRead(AirButtonPin);
  int VacuumReading = digitalRead(VacuumButtonPin);

  // check to see if you just pressed the button
  // (i.e. the input went from HIGH to LOW), and you've waited long enough
  // since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (AirReading != AirLastButtonState) {
    // reset the debouncing timer
    AirLastDebounceTime = millis();
  }
  if (VacuumReading != VacuumLastButtonState) {
    // reset the debouncing timer
    VacuumLastDebounceTime = millis();
  }

  if ((millis() - AirLastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:

    // if the button state has changed:
    if (AirReading != AirButtonState) {
      AirButtonState = AirReading;

      // only toggle the Relay if the new button state is LOW
      if (AirButtonState == LOW) {
        AirState = !AirState;
        if (AirState) {
          Console.println("Air State Changed to: HIGH");
          AirOnTimeStamp = TimeNow;
          Console.print("TimeNow equals: ");
          Console.println(TimeNow);
          Console.print("AirOnTimeStamp equals: ");
          Console.println(AirOnTimeStamp);
        }
        else {
          Console.println("Air State Changed to: LOW");
        }
      }
    }
  }
  if ((millis() - VacuumLastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:

    // if the button state has changed:
    if (VacuumReading != VacuumButtonState) {
      VacuumButtonState = VacuumReading;

      // only toggle the Relay if the new button state is LOW
      if (VacuumButtonState == LOW) {
        VacuumState = !VacuumState;
        if (VacuumState) {
          Console.println("Vacuum State Changed to: HIGH");
          VacuumOnTimeStamp = TimeNow;
          Console.print("TimeNow equals: ");
          Console.println(TimeNow);
          Console.print("VacuumOnTimeStamp equals: ");
          Console.println(VacuumOnTimeStamp);
        }
        else {
          Console.println("Vacuum State Changed to: LOW");
        }
      }
    }
  }

  // set the Relay State:
  digitalWrite(AirPin, AirState);
  digitalWrite(VacuumPin, VacuumState);

  //add an and AirState High
  if ((TimeNow > (AirOnTimeStamp + DefaultRunTime)) && (AirState)) {
    Console.println("Air Time Elapsed");
    AirState = !AirState;
    //    digitalWrite(AirPin, LOW);
  }
  else if (AirState) {
   Console.print(minute(DefaultRunTime - (TimeNow - AirOnTimeStamp)));
   Console.print(":");
   Console.println(second(DefaultRunTime - (TimeNow - AirOnTimeStamp)));
  }
  if ((TimeNow > (VacuumOnTimeStamp + DefaultRunTime)) && (VacuumState)) {
    Console.println("Vacuum Time Elapsed");
    VacuumState = !VacuumState;
    //    digitalWrite(VacuumPin, LOW);
  }
  else if (VacuumState) {
   Console.print(minute(DefaultRunTime - (TimeNow - VacuumOnTimeStamp)));
   Console.print(":");
   Console.println(second(DefaultRunTime - (TimeNow - VacuumOnTimeStamp)));
  }
  // save the reading. Next time through the loop, it'll be the lastButtonState:
  AirLastButtonState = AirReading;
  VacuumLastButtonState = VacuumReading;
}

@dooglave, in the future, please post your code using CODE TAGS. See Item #6 at Read this before posting a programming question ...

pcbbc:
This...

time_t VacuumOnTimeStamp;

Is a declaration of variable named VacuumOnTimeStamp of type time_t.
It is a completely different variable (with different memory allocation) from any other variable declaration that the programmer may have declared earlier with the same name.

It's actually a definition as it reserves storage space for the variable. See: What's the difference between declaring and defining in C and C++ - Cprogramming.com