Output delay when button pressed

I have worked on this code for a few weeks and am realizing that I need assistance.

I have an arduino which controls the air to the fire of my wood burning stove, and gives a signal to a second arduino which controls an air blower for the stove.

When I push the button (const byte load = 1; //opens the valve to load wood) I want to create a 150 second delay which blocks the enable signal to the air blower. My current code will turn the blower off, wait a second or three, then turn the blower on.

How do I get a 150 second delay when pushing the button. I know how to use blink w/o delay. It runs at a different location in the program. It may be hours before the button is pressed, or just a few minutes but I still want the 150 second delay.

Below is a clip from my larger program showing the segment I am working with.

sketch_for_forum_help.ino (1.5 KB)

unsigned long previousMillis = 0; //stores last time display updated
const long interval = 7000; //this is the display refresh time
unsigned long fanMillis = 0; //stores last time fan off was updated
const long fan_delay = 150000; //this is the fan delay for loading wood
c
boolean fandelay = 0; //delay for fan off timer when the open valve button is pressed
int fanEnable = 4; //yellow wire, green wire at fan harness
int fanAuto = 11; //red wire
int ENA = A3; //enables rotation of stepper motor

void setup() {
  // put your setup code here, to run once:

}

void loop() {
  // put your main code here, to run repeatedly
  unsigned long currentMillis = millis();

 if (digitalRead(load) == LOW) //this will open the air valve and delay the blower fan
  {

   if (fandelay == 0) //writes the fan millis delay time once
   {
     fanMillis = millis();// fixed fan delay time
      fandelay = 1; //disable the capture of the initial time used to delay the fan
    }
        
    digitalWrite(fanEnable, LOW); //disable the fan
    if (currentMillis - fanMillis >= fan_delay) //fan disable timer
     {
       digitalWrite(fanEnable, HIGH); //enable the fan
      fandelay = 0; //enable the capture of the initial time used to delay the fan

    }
    digitalWrite(ENA, LOW); //enable stepper motor
//    stepperHome(); moves the stepper motor home
  //  alreadyRun = 0; stops the stepper from running a second time
    delay (1000);
    digitalWrite(ENA, HIGH);// disables stepper motor
  }
}

thanks for your input!

There is no good reason not to post the entire sketch:

unsigned long previousMillis = 0; //stores last time display updated
const long interval = 7000; //this is the display refresh time
unsigned long fanMillis = 0; //stores last time fan off was updated
const long fan_delay = 150000; //this is the fan delay for loading wood
const byte load = 1;  //opens the valve to load wood
boolean fandelay = 0; //delay for fan off timer when the open valve button is pressed
int fanEnable = 4; //yellow wire, green wire at fan harness
int fanAuto = 11; //red wire
int ENA = A3; //enables rotation of stepper motor

void setup() {
  // put your setup code here, to run once:

}

void loop() {
  // put your main code here, to run repeatedly
  unsigned long currentMillis = millis();

  if (digitalRead(load) == LOW) //this will open the air valve and delay the blower fan
  {

    if (fandelay == 0) //writes the fan millis delay time once
    {
      fanMillis = millis();// fixed fan delay time
      fandelay = 1; //disable the capture of the initial time used to delay the fan
    }

    digitalWrite(fanEnable, LOW); //disable the fan
    if (currentMillis - fanMillis >= fan_delay) //fan disable timer
    {
      digitalWrite(fanEnable, HIGH); //enable the fan
      fandelay = 0; //enable the capture of the initial time used to delay the fan

    }
    digitalWrite(ENA, LOW); //enable stepper motor
    //    stepperHome(); moves the stepper motor home
    //  alreadyRun = 0; stops the stepper from running a second time
    delay (1000);
    digitalWrite(ENA, HIGH);// disables stepper motor
  }
}

Generally, but not always, millis() timing checks should not be inside any conditional statements. There is a risk that the times will expire before the conditions are met.

fandelay is a boolean. You should compare with 'false', not an integer. Also bool types should have "true/false" sounding names, like fandelayEnabled or something like that. It helps sort out how the variables are used when you read it.

Or not! It's boolean, so

if (!fandelay ) //writes the fan millis delay time once
 .
 .
 .
  fandelay = true;
}

Get rid of the not operator by giving the variable a different name.

a7

Yes, and to demonstrate that,

if  (not fandelayEnabled ) //writes the fan millis delay time once
 .
 .
 .
  fandelayEnabled = true;
}

I'm still not quite sure what your system is supposed to do.

What is connected to the ENA pin? Why is it enabled for 1 second?

Is the fan normally on? but if you press the button (load pin) then you want it to stop the fan for 150 seconds, then start it up again?

BTW you probably shouldn't use pin 1 as it is used for serial communication (assuming you have an Uno?).

I thought that providing only the section of code in question would simplify this, but I was wrong. The entire code is posted below.

How do I generate a pause without delay, when pushing a button?
The code is all here, but is commented out so the program will run.

Wood_Stove_Control_11_18_2022.ino (8.5 KB)

Can you answer the questions in post #6.

For the convenience of all users the code attached as *.ino-file as a code-section

#include "max6675.h"
#include "LiquidCrystal_I2C.h"
#include "Wire.h"
#include "AccelStepper.h"

//thermocouple 1 FOR FLUE
int ktcSO = 8;
int ktcCS = 9;
int ktcCLK = 10;
//thermocouple 2 FOR FIREBOX
int ktc2SO = 5;
int ktc2CS = 6;
int ktc2CLK = 7;
//blower relay pin 4
int fanEnable = 4; //yellow wire, green wire at fan harness
int fanAuto = 11; //red wire

MAX6675 ktc(ktcCLK, ktcCS, ktcSO);
MAX6675 ktc2(ktc2CLK, ktc2CS, ktc2SO);
LiquidCrystal_I2C lcd(0x3F, A4, A5);
float temp;
float temp2;

// AccelStepper Setup
AccelStepper stepper(1, A1, A2); //AccelStepper(motorInterfaceType, stepPin, dirPin);
// 1 = Easy Driver type interface
//  Pin A1 connected to STEP pin
//  Pin A2 connected to DIR pin

const byte fullclose = 0; //fully close valve button
const byte load = 1;  //opens the valve to load wood
const byte runposition = 2; //this sets the valve to the run position quickly
const byte home_switch = 3; //stops the stepper at home
int rpm; // new variable sets stepper speed
int location; //new variable for stepper location
int ENA = A3; //enables rotation of stepper
int enablefanLCD; //place to store the status of the fan enable signal which is only used for the LCD
int autofanLCD; //place to store the fan auto signal which is only used for the LCD

// Stepper
// Stepper Travel Variables
long initial_homing = -1; // Used to Home Stepper at startup
int runningposition = 330; //steps for valve close to running position
int fullyclosed = 0; //this is the steps to shut the valve fully
boolean alreadyRun = 0; //lock out valve from opening a second time w/o reset
boolean fandelay = 0; //delay for fan off timer when the open valve button is pressed

unsigned long previousMillis = 0; //stores last time display updated
const long interval = 7000; //this is the display refresh time
unsigned long fanMillis = 0; //stores last time fan off was updated
const long fan_delay = 150000; //this is the fan delay for loading wood

void setup() {
  Serial.begin(9600);
  delay(500); // give the MAX a little time to settle
  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.print("BOOTING");
  digitalWrite(fanEnable, LOW);
  pinMode(fanEnable, OUTPUT);
  digitalWrite(fanAuto, LOW);
  pinMode(fanAuto, OUTPUT);
  delay(1000);
  //the following lines control stepper motor
  pinMode(home_switch, INPUT_PULLUP);
  pinMode(fullclose, INPUT_PULLUP);
  pinMode(load, INPUT_PULLUP);
  pinMode(runposition, INPUT_PULLUP);
  pinMode(ENA, OUTPUT);
  lcd.clear();
  lcd.print("Homing......");
  digitalWrite(ENA, LOW);
  stepperHome();
  digitalWrite(ENA, HIGH);
}

void loop() {
  // basic readout test
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    // save the last time the action happened
    previousMillis = currentMillis;
    digitalWrite(ENA, HIGH); //disables the stepper to allow accurate temperature readings
    delay(150);
    temp = (ktc.readFahrenheit() );
    delay(50);
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(temp);
    lcd.print("F");
    lcd.setCursor(8, 0);
    lcd.print("FLUE TEMP");
    temp2 = (ktc2.readFahrenheit() );
    lcd.setCursor(0, 1);
    lcd.print(temp2);
    lcd.print("F");
    lcd.setCursor(8, 1);
    lcd.print("FIREBOX TEMP");
    lcd.setCursor(0, 2);
    lcd.print(round(stepper.currentPosition()) / 3625 * 100);
    lcd.setCursor(5, 2);
    lcd.print("%");
    lcd.setCursor(8, 2);
    lcd.print("THROTTLE");
    //lcd.setCursor(0, 3);
    enablefanLCD = (digitalRead(fanEnable));
    autofanLCD = (digitalRead(fanAuto));
    lcd.setCursor(0, 3);
    if (enablefanLCD == 0) {
      lcd.print("OFF");
    }
    else if (enablefanLCD == 1 && autofanLCD == 0) {
      lcd.print("LOW");
    }
    else if (enablefanLCD == 1 && autofanLCD == 1) {
      lcd.print("AUTO");
    }
    lcd.setCursor(8, 3);
    lcd.print("FAN");
    digitalWrite(ENA, LOW);//enables the stepper to allow motion
  }
  // begin establishing fan control parameters
  if (temp2 >= 235) {
    digitalWrite(fanEnable, HIGH); //enables the fan power relay
    //delay(500);
    digitalWrite(fanAuto, HIGH); //sets the signal to enable auto fan control
  }
  else if ((temp >= 250) && ((temp2 <= 230) && (temp2 >= 195.5))) {
    digitalWrite(fanEnable, HIGH); //enables the fan power relay
    digitalWrite(fanAuto, LOW);//sets the signal disable auto fan control
  }
  else if ((temp <= 250) && ((temp2 <= 230) && (temp2 >= 195.5))) {
    digitalWrite(fanEnable, HIGH); //enables the fan power relay
    digitalWrite(fanAuto, LOW);//sets the signal disable auto fan control
  }
  else if (temp2 <= 194.5) { //194.5
    digitalWrite(fanEnable, LOW); //disables fan power relay
    digitalWrite(fanAuto, LOW); //sets the signal to disable auto fan control
  }
  //end fan control establishment
  //the following lines control stepper motor
  if (digitalRead(load) == LOW) {//this will open the air valve and delay the blower fan
    //while (digitalRead(load)== LOW)
    //(fandelay == 0) //writes the fan millis delay time once
    // {
    //  fanMillis = millis();// fixed fan delay time
    //fandelay = 1; //disable the capture of the initial time used to delay the fan
    //}
    //delay(500);
    //digitalWrite(fanEnable, LOW); //disable the fan
    //if (currentMillis - fanMillis >= fan_delay) //fan disable timer
    // {
    // delay (150000);
    //digitalWrite(fanEnable, HIGH); //enable the fan
    //fandelay = 0; //enable the capture of the initial time used to delay the fan
    //delay (500);
    //}
    digitalWrite(ENA, LOW); //enable stepper motor
    stepperHome();
    alreadyRun = 0;
    delay (1000);
    digitalWrite(ENA, HIGH);// disables stepper motor
  }
  if (digitalRead(fullclose) == LOW) {//this fully closes the air valve on button push and locks from reopen
    alreadyRun = 1;
    location = fullyclosed;
    digitalWrite(ENA, LOW);
    stepper.setMaxSpeed(500);//stepper.runSpeed();
    stepper.setAcceleration(500);
    stepper.moveTo(location);// Run to target position with set speed and acceleration/deceleration:
  }
  stepper.run();
  if (stepper.distanceToGo() == 0) {
    digitalWrite(ENA, HIGH);
  }
  if (digitalRead(runposition) == LOW) {
    alreadyRun = 1;
    location = runningposition;
    digitalWrite(ENA, LOW);
    stepper.setMaxSpeed(500);
    stepper.setAcceleration(500);
    stepper.moveTo(location); // Run to target position with set speed and acceleration/deceleration:
  }
  stepper.run();
  if (stepper.distanceToGo() == 0) {
    digitalWrite(ENA, HIGH);
  }
  if ((temp > 550) && (temp2 >= 195) && (alreadyRun == 0)) {//this wil close the air valve when the stove is coming up to temp
    alreadyRun = 1;
    location = runningposition;
    digitalWrite(ENA, LOW); //enables the stepper motor
    stepper.setMaxSpeed(3.5);
    stepper.setAcceleration(5000);// Set the target position:
    stepper.moveTo(location);// Run to target position with set speed and acceleration/deceleration
  }
  stepper.run();
  if (stepper.distanceToGo() == 0) {
    digitalWrite(ENA, HIGH); //disables the stepper motor
  }
}

void stepperHome() {
  stepper.setCurrentPosition(0);
  stepper.setMaxSpeed(1000.0);      // Set Max Speed of Stepper (Slower to get better accuracy)
  stepper.setAcceleration(500.0);  // Set Acceleration of Stepper
  // Start Homing procedure of Stepper Motor at startup
  Serial.print("Stepper is Homing . . . . . . . . . . . ");
  while (digitalRead(home_switch)) {
    // Make the Stepper move CCW until the switch is activated
    stepper.moveTo(initial_homing);  // Set the position to move to
    initial_homing++;  // Decrease by 1 for next move if needed
    stepper.run();  // Start moving the stepper
    delay(5);
  }
  stepper.setCurrentPosition(0);  // Set the current position as zero for now
  stepper.setMaxSpeed(100.0);      // Set Max Speed of Stepper (Slower to get better accuracy)
  stepper.setAcceleration(100.0);  // Set Acceleration of Stepper
  initial_homing = 1;
  while (!digitalRead(home_switch)) {
    // Make the Stepper move CW until the switch is deactivated
    stepper.moveTo(initial_homing);
    stepper.run();
    initial_homing--;
    delay(5);
  }
  stepper.setCurrentPosition(3625);
  Serial.println("Homing Completed");
}

You had some doubled and some unescessary curly braces in your code
I removed them

As you are working on a project where the arduino shall control a fire
the whole code should be written to follow the non-blocking paradigma.
This is a medium advanced programming-technique that requires quite some learning

The non-blocking code will even eliminate the second arduino if you wish.

Would you like to learn it?

Your functional description given in post # 1 is not really clear to me

What kind of signal?
I guess voltage 0V / 5V logical LOW / HIGH

what is the reaction of the signal-receiving Arduino if this arduino receives signal LOW ?

what is the reaction of the signal-receiving Arduino if this arduino receives signal HIGH?

This button is connected to which arduino?
wood-feeder-arduino?
or
air-blower-control-arduino?

delay() for exactly what?

Is this more precise version of your question correct?
"How can a switch OFF the air-blower for 150 seconds if I press the "load-wood-button"?

If not correct post the corrected question

best regards Stefan

digitalWrite(ENA, HIGH); //disables the stepper to allow accurate temperature readings

remains the question: Why is it enabled for 1 second?

ENA is the enable pin of a TB6600 stepper motor driver. I have to disable the motor when it is not moving. The noise generated by the motor holding current interferes with the thermocouple temperatures. The 1 second delay is in place because I didn't remove it after messing with the millis delay function. Its a relic of troubleshooting.

the fan is normally on when the wood burner is hot

I want the fan to stop for 150 seconds when the load button is pressed. That delay will stop the fan from blowing smoke into the room when the fire door is opened

Yes, this is an UNO - good call!

Type of signal - I have a shared ground wire between the two arduino, and a 0V / 5V logical LOW / HIGH for the signals.

If the receiver receives LOW, it disables the fan.
If the receiver receives HIGH, it enables the fan.

The button is question is connected to the arduino which controls the wood burner (the sketch shared in this post)

This is a great rephrasing of my question "How can a switch OFF the air-blower for 150 seconds if I press the "load-wood-button"?

This is a hobby for me, I am a much better mechanic. I am open to suggestions and appreciate the input.

OK. This means your wood-burner-code has to put the IO-pin called "fanEnable" to state LOW for 150 seconds if you have pressed the load-wood-button.

    digitalWrite(fanEnable, LOW); //disables fan power relay

your actual code-version switches on/off the fan depending on temperatures.

My basic idea is to use a new variable called something like fanONOffState
at all places where your actual code does execute

  if (temp2 >= 235) {
    digitalWrite(fanEnable, HIGH); //enables the fan power relay
    //delay(500);
    digitalWrite(fanAuto, HIGH); //sets the signal to enable auto fan control
  }

or

  else if (temp2 <= 194.5) { //194.5
    digitalWrite(fanEnable, LOW); //disables fan power relay

to only set the new variable to HIGH or LOW

  if (temp2 >= 235) {
    //digitalWrite(fanEnable, HIGH); //enables the fan power relay
    fanONOffState = HIGH;
    //delay(500);
    digitalWrite(fanAuto, HIGH); //sets the signal to enable auto fan control
  }

or

  else if (temp2 <= 194.5) { //194.5
    //digitalWrite(fanEnable, LOW); //disables fan power relay
    fanONOffState = LOW;

etc.

and then below the temperature-conditions add code
if load-wood-button is pressed start a millis() based timer
set a boolean variable called FanOffForLoading to true

if (FanOffForLoading == true) {
  fanONOffState = LOW;
}

if timer has expired then

  FanOffForLoading = false;

which means the condition above is no longer executed
and below that all a single call to set the IO-pin to the value of variable fanONOffState

digitalWrite(fanEnable, fanONOffState );

Thank you! I will spend some time with this tonight after the children are in bed.

Thank you for your detailed response. I interpret your sketch suggestions as an alternate method to change the state of the output. Is this correct?

My sketch will change the output, but my one shot timer isn't working. I am going to study these more and when/if can generate a working one shot timer I will report back.

I am also open to ideas on how to make the one shot work.

This is where I am now

  if (digitalRead(load) == LOW) //this will open the air valve and delay the blower fan
  {
//    digitalWrite(ENA, LOW); //enable stepper motor
    //unsigned long fanMillis = millis();// fixed fan delay time
    unsigned long fanMillis = millis();// fixed fan delay time
    fanDelay();
    //delay(25);
    //stepperHome();
    alreadyRun = 0;
    //delay (1000);
    digitalWrite(ENA, HIGH);// disables stepper motor
  }
-------
void fanDelay()
{
  //unsigned long currentMillis = millis();
    digitalWrite(fanEnable, LOW); //disable the fan
  //delay(fan_delay);
  unsigned long currentMillis = millis();
 if (currentMillis - fanMillis >= fan_delay) //fan disable timer
 {
    digitalWrite(fanEnable, HIGH); //enable the fan
 }
}

The fan output will drop for one second, then come back on. I thought that capturing the "fanMillis" on button press would save the current time. Then running a void() with a currentMillis-fanMillis would do the math to let me re-enable the fan. But something isn't working as I hoped.
Full code below this line


#include "max6675.h"
#include "LiquidCrystal_I2C.h"
#include "Wire.h"
#include "AccelStepper.h"

//thermocouple 1 FOR FLUE
int ktcSO = 8;
int ktcCS = 9;
int ktcCLK = 10;
//thermocouple 2 FOR FIREBOX
int ktc2SO = 5;
int ktc2CS = 6;
int ktc2CLK = 7;
//blower relay pin 4
int fanEnable = 4; //yellow wire, green wire at fan harness
int fanAuto = 11; //red wire

MAX6675 ktc(ktcCLK, ktcCS, ktcSO);
MAX6675 ktc2(ktc2CLK, ktc2CS, ktc2SO);
LiquidCrystal_I2C lcd(0x3F, A4, A5);
float temp;
float temp2;

// AccelStepper Setup
AccelStepper stepper(1, A1, A2); //AccelStepper(motorInterfaceType, stepPin, dirPin);
// 1 = Easy Driver type interface
//  Pin A1 connected to STEP pin
//  Pin A2 connected to DIR pin

const byte fullclose = 0; //fully close valve button
const byte load = 1;  //opens the valve to load wood
const byte runposition = 2; //this sets the valve to the run position quickly
const byte home_switch = 3; //stops the stepper at home
int rpm; // new variable sets stepper speed
int location; //new variable for stepper location
int ENA = A3; //enables rotation of stepper
int enablefanLCD; //place to store the status of the fan enable signal which is only used for the LCD
int autofanLCD; //place to store the fan auto signal which is only used for the LCD

// Stepper
// Stepper Travel Variables
long initial_homing = -1; // Used to Home Stepper at startup
int runningposition = 330; //steps for valve close to running position
int fullyclosed = 0; //this is the steps to shut the valve fully
boolean alreadyRun = 0; //lock out valve from opening a second time w/o reset
boolean fandelay = 0; //delay for fan off timer when the open valve button is pressed

unsigned long previousMillis = 0; //stores last time display updated
const long interval = 7000; //this is the display refresh time
unsigned long fanMillis = 0; //stores last time fan off was updated
const long fan_delay = 150000; //this is the fan delay for loading wood

void setup() {
  Serial.begin(9600);
  delay(500); // give the MAX a little time to settle
  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.print("BOOTING");
  digitalWrite(fanEnable, LOW);
  pinMode(fanEnable, OUTPUT);
  digitalWrite(fanAuto, LOW);
  pinMode(fanAuto, OUTPUT);
  delay(1000);
  //the following lines control stepper motor
  pinMode(home_switch, INPUT_PULLUP);
  pinMode(fullclose, INPUT_PULLUP);
  pinMode(load, INPUT_PULLUP);
  pinMode(runposition, INPUT_PULLUP);
  pinMode(ENA, OUTPUT);
  lcd.clear();
  lcd.print("Homing......");
  digitalWrite(ENA, LOW);
  stepperHome();
  digitalWrite(ENA, HIGH);
}

void loop() {
  // basic readout test
  unsigned long currentMillis = millis();
  
  
  if (currentMillis - previousMillis >= interval)
  {
    // save the last time the action happened
    previousMillis = currentMillis;
    digitalWrite(ENA, HIGH); //disables the stepper to allow accurate temperature readings
    delay(150);
    temp = (ktc.readFahrenheit() );
    delay(50);
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(temp);
    lcd.print("F");
    lcd.setCursor(8, 0);
    lcd.print("FLUE TEMP");
    temp2 = (ktc2.readFahrenheit() );
    lcd.setCursor(0, 1);
    lcd.print(temp2);
    lcd.print("F");
    lcd.setCursor(8, 1);
    lcd.print("FIREBOX TEMP");
    lcd.setCursor(0, 2);
    lcd.print(round(stepper.currentPosition()) / 3625 * 100);
    lcd.setCursor(5, 2);
    lcd.print("%");
    lcd.setCursor(8, 2);
    lcd.print("THROTTLE");
    //lcd.setCursor(0, 3);
    enablefanLCD = (digitalRead(fanEnable));
    autofanLCD = (digitalRead(fanAuto));
    lcd.setCursor(0, 3);
    if (enablefanLCD == 0)
    {
      lcd.print("OFF");
    }
    else if (enablefanLCD == 1 && autofanLCD == 0)
    {
      lcd.print("LOW");
    }
    else if (enablefanLCD == 1 && autofanLCD == 1)
    {
      lcd.print("AUTO");
    }

    lcd.setCursor(8, 3);
    lcd.print("FAN");
    digitalWrite(ENA, LOW);//enables the stepper to allow motion
  }

  // begin establishing fan control parameters
  if (temp2 >= 235)
  {
    digitalWrite(fanEnable, HIGH); //enables the fan power relay
    //delay(500);
    digitalWrite(fanAuto, HIGH); //sets the signal to enable auto fan control
  }
  else if ((temp >= 250) && ((temp2 <= 230) && (temp2 >= 195.5)))
  {

    digitalWrite(fanEnable, HIGH); //enables the fan power relay
    digitalWrite(fanAuto, LOW);//sets the signal disable auto fan control
  }
  else if ((temp <= 250) && ((temp2 <= 230) && (temp2 >= 195.5)))

  {

    digitalWrite(fanEnable, HIGH); //enables the fan power relay
    digitalWrite(fanAuto, LOW);//sets the signal disable auto fan control
  }

  else if (temp2 <= 194.5) //194.5
  {
    digitalWrite(fanEnable, LOW); //disables fan power relay
    digitalWrite(fanAuto, LOW); //sets the signal to disable auto fan control
  }

  //end fan control establishment

  //the following lines control stepper motor

  if (digitalRead(load) == LOW) //this will open the air valve and delay the blower fan
  {
//    digitalWrite(ENA, LOW); //enable stepper motor
    //unsigned long fanMillis = millis();// fixed fan delay time
    unsigned long fanMillis = millis();// fixed fan delay time
    fanDelay();
    //delay(25);
    //stepperHome();
    alreadyRun = 0;
    //delay (1000);
    digitalWrite(ENA, HIGH);// disables stepper motor
  }
  if (digitalRead(fullclose) == LOW) //this fully closes the air valve on button push and locks from reopen
  {
    alreadyRun = 1;
    {
      location = fullyclosed;
      digitalWrite(ENA, LOW);
      stepper.setMaxSpeed(500);//stepper.runSpeed();
      stepper.setAcceleration(500);
      stepper.moveTo(location);// Run to target position with set speed and acceleration/deceleration:
    }
  }
  stepper.run();
  if (stepper.distanceToGo() == 0)
  {
    digitalWrite(ENA, HIGH);
  }

  if (digitalRead(runposition) == LOW)
  {{
      alreadyRun = 1;
      {
        location = runningposition;
        digitalWrite(ENA, LOW);
        stepper.setMaxSpeed(500);
        stepper.setAcceleration(500);
        stepper.moveTo(location); // Run to target position with set speed and acceleration/deceleration:
      }
    }
    stepper.run();
    if (stepper.distanceToGo() == 0)
    {
      digitalWrite(ENA, HIGH);
    }
  }
  if ((temp > 550) && (temp2 >= 195) && (alreadyRun == 0)) //this wil close the air valve when the stove is coming up to temp
  {{
      alreadyRun = 1;
      location = runningposition;
      digitalWrite(ENA, LOW); //enables the stepper motor
      stepper.setMaxSpeed(3.5);
      stepper.setAcceleration(5000);// Set the target position:
      stepper.moveTo(location);// Run to target position with set speed and acceleration/deceleration

    }
    stepper.run();

    if (stepper.distanceToGo() == 0)
    {
      digitalWrite(ENA, HIGH); //disables the stepper motor
    }
  }

}

void fanDelay()
{
  //unsigned long currentMillis = millis();
    digitalWrite(fanEnable, LOW); //disable the fan
  //delay(fan_delay);
  unsigned long currentMillis = millis();
 if (currentMillis - fanMillis >= fan_delay) //fan disable timer
 {
    digitalWrite(fanEnable, HIGH); //enable the fan
 }
}

void stepperHome()
{
  stepper.setCurrentPosition(0);
  stepper.setMaxSpeed(1000.0);      // Set Max Speed of Stepper (Slower to get better accuracy)
  stepper.setAcceleration(500.0);  // Set Acceleration of Stepper
  // Start Homing procedure of Stepper Motor at startup

  Serial.print("Stepper is Homing . . . . . . . . . . . ");

  while (digitalRead(home_switch))
  {

    // Make the Stepper move CCW until the switch is activated
    stepper.moveTo(initial_homing);  // Set the position to move to
    initial_homing++;  // Decrease by 1 for next move if needed
    stepper.run();  // Start moving the stepper
    delay(5);
  }

  stepper.setCurrentPosition(0);  // Set the current position as zero for now
  stepper.setMaxSpeed(100.0);      // Set Max Speed of Stepper (Slower to get better accuracy)
  stepper.setAcceleration(100.0);  // Set Acceleration of Stepper
  initial_homing = 1;

  while (!digitalRead(home_switch))
  {
    // Make the Stepper move CW until the switch is deactivated
    stepper.moveTo(initial_homing);
    stepper.run();
    initial_homing--;
    delay(5);
  }

  stepper.setCurrentPosition(3625);
  Serial.println("Homing Completed");

}

Yes this is correct. assigning the output-state to a variable reduces if-conditions.
Your code-version sets the output state at multiple places directly
digitalWrite(...,LOW);
digitalWrite(...,HIGH);

using a variable as some kind of a buffer enables to change the value of the variable
when running down your lines of code without affecting the real IO-pin
This means the code can change the state mutliple times and only at the bottom of the loop
the IO-pin is set to a certain state.

digitalWrite(fanEnable, fanONOffState );

A oneshot timer is done this way

I'm using this helper-function for non-blocking timing

// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}

additional code

unsigned long myFanOffTimer= 0;                   // Timer-variables MUST be of type unsigned long
byte fanONOffState;
boolean FanOffForLoading = false;

if (load-wood-button == pressed) { // button is pressed  RENAMING required
  // if boolean flag-variable named "FanOffForLoading" is false 
  if (FanOffForLoading == false) {
    // set flag-variable to true which has a self-locking effect
    // the if-condition above is no longer true
    FanOffForLoading = true; 
    myFanOffTimer = millis();
  }
}


if (FanOffForLoading == true) {
  fanONOffState = LOW;
  if (TimePeriodIsOver(myFanOffTimer,150000) { // check if 150 seconds have passed by
    // if 150 seconds REALLY HAVE passed by
    FanOffForLoading = false; // switch flag to false to stop time-checking
  }
}

Thank you so much - I am beginning to understand what you are getting at with assigning state variables. I am going to work on my sketch and will share what I learn / do.

I thought I would get up an hour early this morning to work on this, but I hear one of my kids waking up - maybe I will get to it this evening...

I was able to make your program edits Wednesday and Thursday morning I loaded the updated sketch. First it didn't work - why? I had the line

digitalWrite(fanEnable, fanONOFFstate);

in the wrong place so when the timer ran, it didn't trigger this line of code.

Moved the line below the timer and the 150 second delay performed perfectly. I doubt I would have ever figured out that timer without help -Thank you.

I did do a little searching forums and found that boolean "TimePeriodIsOver" needed to be placed prior to "setup." (I was concerned this may be a library) It appears to me that the boolean operates like a void sub-program.

Enough rambling - here is the updated code for anyone else who wants it.
I loaded the code at 5:50 this morning so I can watch it through the day for anything funny.
Thank you again for the help.


#include "max6675.h"
#include "LiquidCrystal_I2C.h"
#include "Wire.h"
#include "AccelStepper.h"

//thermocouple 1 FOR FLUE
int ktcSO = 8;
int ktcCS = 9;
int ktcCLK = 10;
//thermocouple 2 FOR FIREBOX
int ktc2SO = 5;
int ktc2CS = 6;
int ktc2CLK = 7;
//blower relay pin 4
int fanEnable = 4; //yellow wire, green wire at fan harness
int fanAuto = 11; //red wire

MAX6675 ktc(ktcCLK, ktcCS, ktcSO);
MAX6675 ktc2(ktc2CLK, ktc2CS, ktc2SO);
LiquidCrystal_I2C lcd(0x3F, A4, A5);
float temp;
float temp2;

// AccelStepper Setup
AccelStepper stepper(1, A1, A2); //AccelStepper(motorInterfaceType, stepPin, dirPin);
// 1 = Easy Driver type interface
//  Pin A1 connected to STEP pin
//  Pin A2 connected to DIR pin

const byte fullclose = 0; //fully close valve button
const byte load = 1;  //opens the valve to load wood
const byte runposition = 2; //this sets the valve to the run position quickly
const byte home_switch = 3; //stops the stepper at home
int rpm; // new variable sets stepper speed
int location; //new variable for stepper location
int ENA = A3; //enables rotation of stepper
int enablefanLCD; //place to store the status of the fan enable signal which is only used for the LCD
int autofanLCD; //place to store the fan auto signal which is only used for the LCD

// Stepper
// Stepper Travel Variables
long initial_homing = -1; // Used to Home Stepper at startup
int runningposition = 330; //steps for valve close to running position
int fullyclosed = 0; //this is the steps to shut the valve fully
boolean alreadyRun = 0; //lock out valve from opening a second time w/o reset
boolean fanONOFFstate = 0; //delay for fan off timer when the open valve button is pressed

unsigned long previousMillis = 0; //stores last time display updated
const long interval = 7000; //this is the display refresh time
//unsigned long fanMillis = 0; //stores last time fan off was updated
//const long fan_delay = 150000; //this is the fan delay for loading wood
unsigned long myFanOffTimer = 0;                  // Timer-variables MUST be of type unsigned long
boolean fanOffForLoading = false;
// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}

void setup() {
  Serial.begin(9600);
  delay(500); // give the MAX a little time to settle
  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.print("BOOTING");
  digitalWrite(fanEnable, LOW);
  pinMode(fanEnable, OUTPUT);
  digitalWrite(fanAuto, LOW);
  pinMode(fanAuto, OUTPUT);
  delay(1000);
  //the following lines control stepper motor
  pinMode(home_switch, INPUT_PULLUP);
  pinMode(fullclose, INPUT_PULLUP);
  pinMode(load, INPUT_PULLUP);
  pinMode(runposition, INPUT_PULLUP);
  pinMode(ENA, OUTPUT);
  lcd.clear();
  lcd.print("Homing......");
  digitalWrite(ENA, LOW);
  stepperHome();
  digitalWrite(ENA, HIGH);
}

void loop() {
  // basic readout test
  unsigned long currentMillis = millis();


  if (currentMillis - previousMillis >= interval)
  {
    // save the last time the action happened
    previousMillis = currentMillis;
    digitalWrite(ENA, HIGH); //disables the stepper to allow accurate temperature readings
    delay(150);
    temp = (ktc.readFahrenheit() );
    delay(50);
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(temp);
    lcd.print("F");
    lcd.setCursor(8, 0);
    lcd.print("FLUE TEMP");
    temp2 = (ktc2.readFahrenheit() );
    lcd.setCursor(0, 1);
    lcd.print(temp2);
    lcd.print("F");
    lcd.setCursor(8, 1);
    lcd.print("FIREBOX TEMP");
    lcd.setCursor(0, 2);
    lcd.print(round(stepper.currentPosition()) / 3625 * 100);
    lcd.setCursor(5, 2);
    lcd.print("%");
    lcd.setCursor(8, 2);
    lcd.print("THROTTLE");
    //lcd.setCursor(0, 3);
    enablefanLCD = (digitalRead(fanEnable));
    autofanLCD = (digitalRead(fanAuto));
    lcd.setCursor(0, 3);
    if (enablefanLCD == 0)
    {
      lcd.print("OFF");
    }
    else if (enablefanLCD == 1 && autofanLCD == 0)
    {
      lcd.print("LOW");
    }
    else if (enablefanLCD == 1 && autofanLCD == 1)
    {
      lcd.print("AUTO");
    }

    lcd.setCursor(8, 3);
    lcd.print("FAN");
    digitalWrite(ENA, LOW);//enables the stepper to allow motion
  }

  // begin establishing fan control parameters
  if (temp2 >= 235)
  {
    fanONOFFstate = HIGH; //enables the fan power relay
    //delay(500);
    digitalWrite(fanAuto, HIGH); //sets the signal to enable auto fan control
  }
  else if ((temp >= 250) && ((temp2 <= 230) && (temp2 >= 195.5)))
  {
    fanONOFFstate = HIGH; //enables the fan power relay
    digitalWrite(fanAuto, LOW);//sets the signal disable auto fan control
  }
  else if ((temp <= 250) && ((temp2 <= 230) && (temp2 >= 195.5)))

  {
    fanONOFFstate = HIGH; //enables the fan power relay
    digitalWrite(fanAuto, LOW);//sets the signal disable auto fan control
  }

  else if (temp2 <= 194.5) //194.5
  {
    fanONOFFstate = LOW; //disables fan power relay
    digitalWrite(fanAuto, LOW); //sets the signal to disable auto fan control
  }
  

  //end fan control establishment

  //the following lines control stepper motor

  if (digitalRead(load) == LOW) //this will open the air valve and delay the blower fan
  {
    {
      // if boolean flag-variable named "fanOffForLoading" is false
      if (fanOffForLoading == false) 
      {
        // set flag-variable to true which has a self-locking effect
        // the if-condition above is no longer true
        fanOffForLoading = true;
        myFanOffTimer = millis();
      }
    }

    digitalWrite(ENA, LOW); //enable stepper motor
    stepperHome();
    alreadyRun = 0;
    //delay (1000);
    digitalWrite(ENA, HIGH);// disables stepper motor
  }
  
  //next lines time fan off for loading
  if (fanOffForLoading == true)
  {
    fanONOFFstate = LOW;
    if (TimePeriodIsOver(myFanOffTimer, 150000)) // check if 150 seconds have passed by
  { 
    // if 150 seconds REALLY HAVE passed by
    fanOffForLoading = false; // switch flag to false to stop time-checking
  }
}
digitalWrite(fanEnable, fanONOFFstate);
//end fan off for loading timer
if (digitalRead(fullclose) == LOW) //this fully closes the air valve on button push and locks from reopen
  {
    alreadyRun = 1;
    {
      location = fullyclosed;
      digitalWrite(ENA, LOW);
      stepper.setMaxSpeed(500);//stepper.runSpeed();
      stepper.setAcceleration(500);
      stepper.moveTo(location);// Run to target position with set speed and acceleration/deceleration:
    }
  }
  stepper.run();
  if (stepper.distanceToGo() == 0)
  {
    digitalWrite(ENA, HIGH);
  }

  if (digitalRead(runposition) == LOW)
  {{
      alreadyRun = 1;
      {
        location = runningposition;
        digitalWrite(ENA, LOW);
        stepper.setMaxSpeed(500);
        stepper.setAcceleration(500);
        stepper.moveTo(location); // Run to target position with set speed and acceleration/deceleration:
      }
    }
    stepper.run();
    if (stepper.distanceToGo() == 0)
    {
      digitalWrite(ENA, HIGH);
    }
  }
  if ((temp > 550) && (temp2 >= 195) && (alreadyRun == 0)) //this wil close the air valve when the stove is coming up to temp
  {{
      alreadyRun = 1;
      location = runningposition;
      digitalWrite(ENA, LOW); //enables the stepper motor
      stepper.setMaxSpeed(3.5);
      stepper.setAcceleration(5000);// Set the target position:
      stepper.moveTo(location);// Run to target position with set speed and acceleration/deceleration

    }
    stepper.run();

    if (stepper.distanceToGo() == 0)
    {
      digitalWrite(ENA, HIGH); //disables the stepper motor
    }
  }

}


void stepperHome()
{
  stepper.setCurrentPosition(0);
  stepper.setMaxSpeed(1000.0);      // Set Max Speed of Stepper (Slower to get better accuracy)
  stepper.setAcceleration(500.0);  // Set Acceleration of Stepper
  // Start Homing procedure of Stepper Motor at startup

  Serial.print("Stepper is Homing . . . . . . . . . . . ");

  while (digitalRead(home_switch))
  {

    // Make the Stepper move CCW until the switch is activated
    stepper.moveTo(initial_homing);  // Set the position to move to
    initial_homing++;  // Decrease by 1 for next move if needed
    stepper.run();  // Start moving the stepper
    delay(5);
  }

  stepper.setCurrentPosition(0);  // Set the current position as zero for now
  stepper.setMaxSpeed(100.0);      // Set Max Speed of Stepper (Slower to get better accuracy)
  stepper.setAcceleration(100.0);  // Set Acceleration of Stepper
  initial_homing = 1;

  while (!digitalRead(home_switch))
  {
    // Make the Stepper move CW until the switch is deactivated
    stepper.moveTo(initial_homing);
    stepper.run();
    initial_homing--;
    delay(5);
  }

  stepper.setCurrentPosition(3625);
  Serial.println("Homing Completed");

}

How, when you can copy and paste from the post?

Tom.... :smiley: :+1: :coffee: :australia: