Need to add flashing LED subroutine

here original code.

// KY-040 encoder for timer

#define NOT !
#define ASSERTED !

// LED config
#define BlinkHalfPeriod 500UL
#define ChangeAfter 5000UL
#define BlinkPin 13

/*-----( Import needed libraries )-----*/
#include <Wire.h>  // Comes with Arduino IDE
// Get the LCD I2C Library here:
// https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads
// Move any other LCD libraries to another folder or delete them
// See Library "Docs" folder for possible commands etc.
// Simple Rotary library will need to be installed via library manager
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
#include <SimpleRotary.h>

/*-----( Declare Constants )-----*/

/* Maximum number of timer minutes we can set. */
const int MAX_MINUTES = 60;

const unsigned long DEBOUNCE_INTERVAL = 100; // msec

typedef class _DBSwitch {
  private:
    bool state;
    bool lastState;
    int pinNumber;
    unsigned long last_change;
  public:
    _DBSwitch(int pPinNumber) {
      pinNumber = pPinNumber;
      state = lastState = false;
      last_change = 0;
      (void) query();
    }

    bool query() {
      unsigned long now = millis();
      bool value = digitalRead(pinNumber);
      if ( value != lastState ) {
        last_change = now;
      } else {
        if ( (value != state) && ( last_change + DEBOUNCE_INTERVAL ) < now ) {
          state = value;
        }
      }
      lastState = value;
      return state;
    }
} DBSwitch;

typedef enum OPERATING_STATE  {
  OST_IDLE,
  OST_RESET_PENDING,
  OST_SET,
  OST_RUNNING,
  OST_EXPIRED1,
  OST_EXPIRED2
} OPERATING_STATE;

static OPERATING_STATE operating_state = OST_IDLE;

/*-----( Declare objects )-----*/
// set the LCD address to 0x27 for a 16 chars 2 line display
// A FEW use address 0x3F
// Set the pins on the I2C chip used for LCD connections:
LiquidCrystal_I2C lcd(0x27, 16, 2); // Set the LCD I2C address
// if the LCD is parallel then uncomment the line below instead - pins may need to change
// LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

// set up rotary encoder Pin A, Pin B, Button Pin
SimpleRotary rotary(3, 2, 4);

/*-----( Declare Variables )-----*/

const int RELAY1_PIN = 7;
const int RELAY2_PIN = 8;
//const int KY_CLK_PIN = 2; // KY-040 CLK
//const int KY_DT_PIN = 3; // KY-040 DT
//const int KY_SET_PIN = 4; // KY-040 Pushbutton
const int RESET_PIN = 5;
const int INHIBIT_PIN = 6;

const int SECURITY_PIN = 9;

//int pinA = 3;  // Connected to CLK on KY-040
//int pinB = 4;  // Connected to DT on KY-040
int encoderPosCount = 30;

int pinALast;
int aVal;

DBSwitch swReset(RESET_PIN);
//DBSwitch swSetTimer(KY_SET_PIN);


bool swResetLast = true;
//bool swSetTimerLast;
bool swInhibitLast;
//boolean bClockwise; // rotation direction

//--
int minutes_remaining = 0;
int seconds_remaining = 0;
unsigned long time_started = 0L;
unsigned long next_tick = 0L;


void setup() {

  //LED PIN
  pinMode(BlinkPin, OUTPUT);

  //pinMode (KY_CLK_PIN, INPUT);
  // pinMode (KY_DT_PIN, INPUT);

  pinMode (SECURITY_PIN, INPUT_PULLUP);
  pinMode (INHIBIT_PIN, INPUT_PULLUP);
  swInhibitLast = digitalRead(INHIBIT_PIN);

  pinMode (RESET_PIN, INPUT_PULLUP);
  //pinMode (KY_SET_PIN, INPUT_PULLUP);
  //swSetTimerLast = digitalRead(KY_SET_PIN);

  bool sw = swReset.query();
  bool signalReset = false;
  bool swResetLast = false;
  if ( sw && ! swResetLast ) { // toggle
    signalReset = true;
  }
  swResetLast = sw;

  pinMode(RELAY1_PIN, OUTPUT);
  pinMode(RELAY2_PIN, OUTPUT);
  /* Read Pin A
    Whatever state it's in will reflect the last position
  */
  // pinALast = digitalRead(KY_CLK_PIN);
  Serial.begin (9600);
  Serial.println("Starting...");

  lcd.init();  // initialize the lcd
  lcd.backlight(); // finish with backlight on

  lcd.setCursor(0, 0); //Start at character 4 on line 0
  lcd.print("Starting...");

  // Restore timer from EEPROM
  reset_relays();
  encoderPosCount = timer_load();
  timer_restart(encoderPosCount);
  setOperatingState(OST_RUNNING); // IDLE
}


void loop() {

  // LED control
  static uint32_t TimerPeriodes = 0;
  static uint32_t TimerBliking = 0;
  static bool isBlinkEnable = false;
  if ( millis() - TimerPeriodes >= ChangeAfter) {
    TimerPeriodes += ChangeAfter;
    isBlinkEnable = !isBlinkEnable;
  }
  if (isBlinkEnable) {
    if ( millis() - TimerBliking >= BlinkHalfPeriod) {
      TimerBliking += BlinkHalfPeriod;
      digitalWrite(BlinkPin, !digitalRead(BlinkPin));
    }
  }  else digitalWrite(BlinkPin, LOW);




  //if ( NOT digitalRead(INHIBIT_PIN) ) {
  //  delay(500);
  //  return;
  //}


  unsigned long now = millis();

  bool keyLock = ! digitalRead(SECURITY_PIN);
  //bool kyKeyPress = digitalRead(KY_SET_PIN);
  if ( ! keyLock ) {
    //lcd.clear();
    lcd.setCursor(0, 1); //Start at character 0 on line 1
    lcd.print("Unlocked");

    handle_locked_operations(now);
  } else {
    //lcd.clear();
    lcd.setCursor(0, 1); //Start at character 0 on line 1
    lcd.print("Locked  ");
  }

  bool resetSignalled = false;


  // ****** Handle Reset button ******

  bool sw = ASSERTED swReset.query();
  if ( sw ) { // Reset held down
    if ( NOT swResetLast ) {
      // Timer interrupted
      lcd.clear();
      lcd.setCursor(2, 1); //Start at character 2 on line 1
      lcd.print("** RESET **");
      delay(1000);
      swResetLast = true;
    }
    return;
  }
  if ( swResetLast ) { // also return from INHIBIT
    resetSignalled = true;
    swResetLast = false;
    reset_relays();
    lcd.clear();
    timer_restart(encoderPosCount);
    setOperatingState(OST_RUNNING);
  }


  switch (operating_state) {
    case OST_IDLE:
    case OST_SET:
      handle_timer_set();
      // Also check for "SET" button pressed to exit state.
      break;
    case OST_RUNNING:
      if ( now > next_tick ) {
        timer_tick_seconds();
        timer_display_count();
        if (( minutes_remaining == 0) && (seconds_remaining == 0)) {
          // FIRE RELAY 1!!!
          digitalWrite(RELAY1_PIN, 1);
          isBlinkEnable = true;
          setOperatingState(OST_EXPIRED1);
          timer_restart(1); // One minute EXPIRED count
        }
      }
      break;
    case OST_EXPIRED1:
      if ( now > next_tick ) {
        timer_tick_seconds();
        timer_display_count();
        if (seconds_remaining == 0) {
          // FIRE RELAY 2!!!
          digitalWrite(RELAY2_PIN, 1);
          setOperatingState(OST_EXPIRED2);
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("*** EXPIRED ***");
        }
      }
      break;
    case OST_EXPIRED2:
      break;
  }
}

/**
   Process things that can only be done if the security switch is not set.
*/
void handle_locked_operations(const unsigned long now) {

  // *** Timer set sw

  bool keyLock = ! digitalRead(SECURITY_PIN);
  if ( !keyLock) {
    byte j;
    // detect if rotary encoder button pressed 0 = not pushed, 1 = pushed
    j = rotary.push();
    // ONLY allow set-mode if SECURITY SWITCH is ON
    if ( j == 1 ) { // act on button-release
      if ( operating_state == OST_SET ) {
        timer_save(encoderPosCount);
        timer_restart(encoderPosCount);
        setOperatingState(OST_RUNNING);
      }
      else {
        setOperatingState(OST_SET);
        display_timer_set();
      }
    }
    //swSetTimerLast = sw;
  }
}

/**
   Return the relays to their "OFF" settings.
*/
void reset_relays() {
  digitalWrite(RELAY1_PIN, 0);
  digitalWrite(RELAY2_PIN, 0);
  //isBlinkEnable = false;
}

/**
   When we are in OST_SET state, we read the encoder and
   set the timer.
*/
void handle_timer_set() {
  lcd.clear();
  lcd.setCursor(0, 0); //Start at character 0 on line 1
  lcd.print("Timer set:");
  lcd.setCursor(2, 1); //Start at character 2 on line 1
  char buf[3];
  buf[2] = 0;
  lcd.print(format_rj2( buf, encoderPosCount));
  lcd.setCursor(5, 1);
  lcd.print( " Minutes");
  do {
    lcd.setCursor(2, 1); //Start at character 2 on line 1
    byte i;
    // 0 = not turning, 1 = CW, 2 = CCW - you may need to swap these depending on the encoder and pins
    i = rotary.rotate();
    if ( i == 2 && encoderPosCount < MAX_MINUTES) {
      encoderPosCount++;
      char buf[3];
      buf[2] = 0;
      lcd.print(format_rj2( buf, encoderPosCount));
    }
    if ( i == 1 && encoderPosCount > 1) {
      encoderPosCount--;
      char buf[3];
      buf[2] = 0;
      lcd.print(format_rj2( buf, encoderPosCount));
    }
  }
  while (rotary.push() == 0);
  timer_save(encoderPosCount);
  timer_restart(encoderPosCount);
  setOperatingState(OST_RUNNING);

  // byte i;
  // 0 = not turning, 1 = CW, 2 = CCW
  //i = rotary.rotate();
  //if (i==1) {  //  - We're Rotating Clockwise

  /// if ( encoderPosCount < MAX_MINUTES )
  //   encoderPosCount ++;
  //   else encoderPosCount = MAX_MINUTES;
  // }
  // if (i==2) {// Otherwise B changed first and we're moving CCW
  // if ( encoderPosCount > 1 ) {
  //   encoderPosCount--;
  //  }
  // }
  // display_timer_set();
}

static void display_timer_set() {
  //lcd.clear();
  lcd.setCursor(0, 0); //Start at character 0 on line 1
  lcd.print("Timer set:");
  lcd.setCursor(2, 1); //Start at character 2 on line 1
  char buf[3];
  buf[2] = 0;
  //lcd.print(format_rj2( buf, encoderPosCount));
  lcd.print( " Minutes");
}

static void setOperatingState(OPERATING_STATE ost) {
  if ( ost != operating_state ) {
    lcd.clear();
  }
  operating_state = ost;
}

/**
   Restart the time count.
*/
static void timer_restart(int minutes) {
  unsigned long now = millis();
  time_started = now;
  //Serial.print("Timer Restart "); Serial.println(encoderPosCount);
  minutes_remaining = minutes; // MINUTES - todo - pull from EEPROM
  seconds_remaining = 0;
  next_tick = now + 1000; // msec = 1 second
}

/**
   Count down 1 second intervals
*/
static void timer_tick_seconds() {
  seconds_remaining--;
  if ( seconds_remaining < 0 ) {
    seconds_remaining = 59;
    minutes_remaining--;
  }
  next_tick = next_tick + 1000; // msec = 1 second
}

/**
   Display current time remaining.
*/
static void timer_display_count() {
  lcd.setCursor(0, 0); //Start at character 0 on line 0
  char buf[3];
  if ( minutes_remaining > 0 ) {
    lcd.print(format_rj2(buf, minutes_remaining));
    lcd.print(" Min. remain");
  } else {
    lcd.print(format_rj2(buf, seconds_remaining));
    lcd.print(" Sec. remain");
  }
  if ( operating_state == OST_EXPIRED1 ) {
    lcd.setCursor(0, 1); //Start at character 0 on line 0
    lcd.print("Expired");
  }
}

/**
   Right-justified format of a 2-digit number
*/
static char* format_rj2(char* buf, int n) {
  if ( n > 99 ) { // limit range.
    n = n % 100;
  }
  buf[1] = (n % 10) + '0';
  buf[0] = (n / 10) + '0';
  buf[2] = 0;
  if ( buf[0] == '0') {
    buf[0] = ' '; // leading space
  }
  return buf;
}

//**** EEPROM ****

const int ee_addr0 = 0;

static void timer_save(int count) {
  EEPROM.update(ee_addr0, (count >> 8) & 0xff);
  EEPROM.update(ee_addr0 + 1, (count) & 0xff);
}

static int timer_load() {
  int val = EEPROM.read(ee_addr0) << 8;
  val |= EEPROM.read(ee_addr0 + 1);
  return val;
}

Here is the revised code.
Im still having compiler errors and, it also seems that the LED is flashing the whole time.

    // KY-040 encoder for timer

    #define NOT !
    #define ASSERTED !

    // LED config
    #define BlinkHalfPeriod 100UL
    #define ChangeAfter 1000UL
    #define BlinkPin 13

    /*-----( Import needed libraries )-----*/
    #include <Wire.h>  // Comes with Arduino IDE
    // Get the LCD I2C Library here:
    // https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads
    // Move any other LCD libraries to another folder or delete them
    // See Library "Docs" folder for possible commands etc.
    // Simple Rotary library will need to be installed via library manager
    #include <LiquidCrystal_I2C.h>
    #include <EEPROM.h>
    #include <SimpleRotary.h>

    /*-----( Declare Constants )-----*/

    /* Maximum number of timer minutes we can set. */
    const int MAX_MINUTES = 60;

    const unsigned long DEBOUNCE_INTERVAL = 100; // msec

    typedef class _DBSwitch {
      private:
        bool state;
        bool lastState;
        int pinNumber;
        unsigned long last_change;
      public:
        _DBSwitch(int pPinNumber) {
          pinNumber = pPinNumber;
          state = lastState = false;
          last_change = 0;
          (void) query();
        }

        bool query() {
          unsigned long now = millis();
          bool value = digitalRead(pinNumber);
          if ( value != lastState ) {
            last_change = now;
          } else {
            if ( (value != state) && ( last_change + DEBOUNCE_INTERVAL ) < now ) {
              state = value;
            }
          }
          lastState = value;
          return state;
        }
    } DBSwitch;

    typedef enum OPERATING_STATE  {
      OST_IDLE,
      OST_RESET_PENDING,
      OST_SET,
      OST_RUNNING,
      OST_EXPIRED1,
      OST_EXPIRED2
    } OPERATING_STATE;

    static OPERATING_STATE operating_state = OST_IDLE;

    /*-----( Declare objects )-----*/
    // set the LCD address to 0x27 for a 16 chars 2 line display
    // A FEW use address 0x3F
    // Set the pins on the I2C chip used for LCD connections:
    LiquidCrystal_I2C lcd(0x27, 16,2);  // Set the LCD I2C address
    // if the LCD is parallel then uncomment the line below instead - pins may need to change
    // LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

    // set up rotary encoder Pin A, Pin B, Button Pin
    SimpleRotary rotary(3,2,4);
    
    /*-----( Declare Variables )-----*/

    const int RELAY1_PIN = 7;
    const int RELAY2_PIN = 8;
    //const int KY_CLK_PIN = 2; // KY-040 CLK
    //const int KY_DT_PIN = 3; // KY-040 DT
    //const int KY_SET_PIN = 4; // KY-040 Pushbutton
    const int RESET_PIN = 5;
    const int INHIBIT_PIN = 6;

    const int SECURITY_PIN = 9;

    //int pinA = 3;  // Connected to CLK on KY-040
    //int pinB = 4;  // Connected to DT on KY-040
    int encoderPosCount = 30;

    int pinALast;
    int aVal;

    DBSwitch swReset(RESET_PIN);
    //DBSwitch swSetTimer(KY_SET_PIN);


    bool swResetLast = true;
    //bool swSetTimerLast;
    bool swInhibitLast;
    //boolean bClockwise; // rotation direction

    //--
    int minutes_remaining = 0;
    int seconds_remaining = 0;
    unsigned long time_started = 0L;
    unsigned long next_tick = 0L;


    void setup() {

      //pinMode (KY_CLK_PIN, INPUT);
     // pinMode (KY_DT_PIN, INPUT);

      pinMode (SECURITY_PIN, INPUT_PULLUP);
      pinMode (INHIBIT_PIN, INPUT_PULLUP);
      swInhibitLast = digitalRead(INHIBIT_PIN);

      pinMode (RESET_PIN, INPUT_PULLUP);
      //pinMode (KY_SET_PIN, INPUT_PULLUP);
      //swSetTimerLast = digitalRead(KY_SET_PIN);

      bool sw = swReset.query();
      bool signalReset = false;
      bool swResetLast = false;
      if ( sw && ! swResetLast ) { // toggle
        signalReset = true;
      }
      swResetLast = sw;

      pinMode(RELAY1_PIN, OUTPUT);
      pinMode(RELAY2_PIN, OUTPUT);
      /* Read Pin A
        Whatever state it's in will reflect the last position
      */
     // pinALast = digitalRead(KY_CLK_PIN);
      Serial.begin (9600);
      Serial.println("Starting...");

      lcd.init();  // initialize the lcd 
      lcd.backlight(); // finish with backlight on

      lcd.setCursor(0, 0); //Start at character 4 on line 0
      lcd.print("Starting...");

      // Restore timer from EEPROM
      reset_relays();
      encoderPosCount = timer_load();
      timer_restart(encoderPosCount);
      setOperatingState(OST_RUNNING); // IDLE
    }


    void loop() {

      // LED control
      static uint32_t TimerPeriodes = 0;
      static uint32_t TimerBliking = 0;
      static bool isBlinkEnable = false;
      if ( millis() - TimerPeriodes >= ChangeAfter) {
        TimerPeriodes += ChangeAfter;
       isBlinkEnable = !isBlinkEnable;
      }
      if (isBlinkEnable) {
         if ( millis() - TimerBliking >= BlinkHalfPeriod) {
           TimerBliking += BlinkHalfPeriod;
           digitalWrite(BlinkPin, !digitalRead(BlinkPin));
         }
      }  else digitalWrite(BlinkPin, LOW);
  
    



      //if ( NOT digitalRead(INHIBIT_PIN) ) {
      //  delay(500);
      //  return;
      //}


      unsigned long now = millis();

      bool keyLock = ! digitalRead(SECURITY_PIN);
      //bool kyKeyPress = digitalRead(KY_SET_PIN);
      if ( ! keyLock ) {
        //lcd.clear();
        lcd.setCursor(0, 1); //Start at character 0 on line 1
        lcd.print("Unlocked");

        handle_locked_operations(now);
      } else {
        //lcd.clear();
        lcd.setCursor(0, 1); //Start at character 0 on line 1
        lcd.print("Locked  ");
      }

      bool resetSignalled = false;


      // ****** Handle Reset button ******

      bool sw = ASSERTED swReset.query();
      if ( sw ) { // Reset held down
        if ( NOT swResetLast ) {
          // Timer interrupted
          lcd.clear();
          lcd.setCursor(2, 1); //Start at character 2 on line 1
          lcd.print("** RESET **");
          delay(1000);
          swResetLast = true;
        }
        return;
      }
      if ( swResetLast ) { // also return from INHIBIT
        resetSignalled = true;
        swResetLast = false;
        reset_relays();
        lcd.clear();
        timer_restart(encoderPosCount);
        setOperatingState(OST_RUNNING);
      }


      switch (operating_state) {
        case OST_IDLE:
        case OST_SET:
          handle_timer_set();
          // Also check for "SET" button pressed to exit state.
          break;
        case OST_RUNNING:
          if ( now > next_tick ) {
            timer_tick_seconds();
            timer_display_count();
            if (( minutes_remaining == 0) && (seconds_remaining == 0)) {
              // FIRE RELAY 1!!!
              digitalWrite(RELAY1_PIN, 1);
              setOperatingState(OST_EXPIRED1);
              isBlinkEnable = true;
              timer_restart(1); // One minute EXPIRED count
            }
          }
          break;
        case OST_EXPIRED1:
          if ( now > next_tick ) {
            timer_tick_seconds();
            timer_display_count();
            if (seconds_remaining == 0) {
              // FIRE RELAY 2!!!
              digitalWrite(RELAY2_PIN, 1);
              setOperatingState(OST_EXPIRED2);
              lcd.clear();
              lcd.setCursor(0, 0);
              lcd.print("*** EXPIRED ***");
            }
          }
          break;
        case OST_EXPIRED2:
          break;
      }
    }

    /**
       Process things that can only be done if the security switch is not set.
    */
    void handle_locked_operations(const unsigned long now) {
      
      // *** Timer set sw

      bool keyLock = ! digitalRead(SECURITY_PIN);
      if ( !keyLock) {
        byte j;
        // detect if rotary encoder button pressed 0 = not pushed, 1 = pushed
        j = rotary.push();
        // ONLY allow set-mode if SECURITY SWITCH is ON
        if ( j==1 ) { // act on button-release
          if ( operating_state == OST_SET ) {
            timer_save(encoderPosCount);
            timer_restart(encoderPosCount);
            setOperatingState(OST_RUNNING);
          } 
          else {
            setOperatingState(OST_SET);
            display_timer_set();
          }
        }
        //swSetTimerLast = sw;
      }
    }

    /**
       Return the relays to their "OFF" settings.
    */
    void reset_relays() {
      digitalWrite(RELAY1_PIN, 0);
      digitalWrite(RELAY2_PIN, 0);
      isBlinkEnable = false;
    }

    /**
       When we are in OST_SET state, we read the encoder and
       set the timer.
    */
    void handle_timer_set() {
       lcd.clear();
       lcd.setCursor(0, 0); //Start at character 0 on line 1
       lcd.print("Timer set:");
       lcd.setCursor(2, 1); //Start at character 2 on line 1
       char buf[3];
       buf[2] = 0;
       lcd.print(format_rj2( buf, encoderPosCount));
       lcd.setCursor(5,1);
       lcd.print( " Minutes");
       do {
        lcd.setCursor(2, 1); //Start at character 2 on line 1  
        byte i;
        // 0 = not turning, 1 = CW, 2 = CCW - you may need to swap these depending on the encoder and pins
        i = rotary.rotate();
        if ( i == 2 && encoderPosCount < MAX_MINUTES) {
          encoderPosCount++;
          char buf[3];
          buf[2] = 0;
          lcd.print(format_rj2( buf, encoderPosCount));
          }
        if ( i == 1 && encoderPosCount > 1) {
          encoderPosCount--;
          char buf[3];
          buf[2] = 0;
          lcd.print(format_rj2( buf, encoderPosCount));
          }
        }
        while (rotary.push()==0);
        timer_save(encoderPosCount);
        timer_restart(encoderPosCount);
        setOperatingState(OST_RUNNING);
  
       // byte i;
        // 0 = not turning, 1 = CW, 2 = CCW
       //i = rotary.rotate();
        //if (i==1) {  //  - We're Rotating Clockwise

         /// if ( encoderPosCount < MAX_MINUTES ) 
         //   encoderPosCount ++;
         //   else encoderPosCount = MAX_MINUTES;
       // }  
       // if (i==2) {// Otherwise B changed first and we're moving CCW
         // if ( encoderPosCount > 1 ) {
         //   encoderPosCount--;
        //  }
       // }
       // display_timer_set();
    }

    static void display_timer_set() {
      //lcd.clear();
      lcd.setCursor(0, 0); //Start at character 0 on line 1
      lcd.print("Timer set:");
      lcd.setCursor(2, 1); //Start at character 2 on line 1
      char buf[3];
      buf[2] = 0;
      //lcd.print(format_rj2( buf, encoderPosCount));
      lcd.print( " Minutes");
    }

    static void setOperatingState(OPERATING_STATE ost) {
      if ( ost != operating_state ) {
        lcd.clear();
      }
      operating_state = ost;
    }

    /**
       Restart the time count.
    */
    static void timer_restart(int minutes) {
      unsigned long now = millis();
      time_started = now;
      //Serial.print("Timer Restart "); Serial.println(encoderPosCount);
      minutes_remaining = minutes; // MINUTES - todo - pull from EEPROM
      seconds_remaining = 0;
      next_tick = now + 1000; // msec = 1 second
    }

    /**
       Count down 1 second intervals
    */
    static void timer_tick_seconds() {
      seconds_remaining--;
      if ( seconds_remaining < 0 ) {
        seconds_remaining = 59;
        minutes_remaining--;
      }
      next_tick = next_tick + 1000; // msec = 1 second
    }

    /**
       Display current time remaining.
    */
    static void timer_display_count() {
      lcd.setCursor(0, 0); //Start at character 0 on line 0
      char buf[3];
      if ( minutes_remaining > 0 ) {
        lcd.print(format_rj2(buf, minutes_remaining));
        lcd.print(" Min. remain");
      } else {
        lcd.print(format_rj2(buf, seconds_remaining));
        lcd.print(" Sec. remain");
      }
      if ( operating_state == OST_EXPIRED1 ) {
        lcd.setCursor(0, 1); //Start at character 0 on line 0
        lcd.print("Expired");
      }
    }

    /**
       Right-justified format of a 2-digit number
    */
    static char* format_rj2(char* buf, int n) {
      if ( n > 99 ) { // limit range.
        n = n % 100;
      }
      buf[1] = (n % 10) + '0';
      buf[0] = (n / 10) + '0';
      buf[2] = 0;
      if ( buf[0] == '0') {
        buf[0] = ' '; // leading space
      }
      return buf;
    }

    //**** EEPROM ****

    const int ee_addr0 = 0;

    static void timer_save(int count) {
      EEPROM.update(ee_addr0, (count >> 8) & 0xff);
      EEPROM.update(ee_addr0 + 1, (count) & 0xff);
    }

    static int timer_load() {
      int val = EEPROM.read(ee_addr0) << 8;
      val |= EEPROM.read(ee_addr0 + 1);
      return val;
    }

how can you say the LED is flashing the while time if the code doesn't compile and can't be tested

"isBlinkEnable" is defined within "loop()" but is being used outside loop() in "reset_relays()"

looks like the last posted code enables blinking for second then disables it for a seconds.

this is what i see happening when i add configuring "BlinkPin" as an OUTPUT

void setup() {
    pinMode (BlinkPin, OUTPUT);

Sorry for the late reply,
yes I was talking about 2 different thing sorry.
There was some other code i was provided here that caused the LED to blink the whole time.

What I submitted above was my attempt to resolve it myself.
Your right about that code blinking for a second and then pausing for a bit.

Im not good with code, so I didnt really know what I was doing.
How can i get that defined in the loop for "reset_relays()" ?

edit:

This is my updated code and ive called the isblinkenable either true or false accordingly in the main loop, but the LED is staying on the whole time.
I think this is the same issue i had earlier.

    // KY-040 encoder for timer

    #define NOT !
    #define ASSERTED !

    // LED config
    #define BlinkHalfPeriod 100UL
    #define ChangeAfter 1000UL
    #define BlinkPin 13

    /*-----( Import needed libraries )-----*/
    #include <Wire.h>  // Comes with Arduino IDE
    // Get the LCD I2C Library here:
    // https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads
    // Move any other LCD libraries to another folder or delete them
    // See Library "Docs" folder for possible commands etc.
    // Simple Rotary library will need to be installed via library manager
    #include <LiquidCrystal_I2C.h>
    #include <EEPROM.h>
    #include <SimpleRotary.h>

    /*-----( Declare Constants )-----*/

    /* Maximum number of timer minutes we can set. */
    const int MAX_MINUTES = 60;

    const unsigned long DEBOUNCE_INTERVAL = 100; // msec

    typedef class _DBSwitch {
      private:
        bool state;
        bool lastState;
        int pinNumber;
        unsigned long last_change;
      public:
        _DBSwitch(int pPinNumber) {
          pinNumber = pPinNumber;
          state = lastState = false;
          last_change = 0;
          (void) query();
        }

        bool query() {
          unsigned long now = millis();
          bool value = digitalRead(pinNumber);
          if ( value != lastState ) {
            last_change = now;
          } else {
            if ( (value != state) && ( last_change + DEBOUNCE_INTERVAL ) < now ) {
              state = value;
            }
          }
          lastState = value;
          return state;
        }
    } DBSwitch;

    typedef enum OPERATING_STATE  {
      OST_IDLE,
      OST_RESET_PENDING,
      OST_SET,
      OST_RUNNING,
      OST_EXPIRED1,
      OST_EXPIRED2
    } OPERATING_STATE;

    static OPERATING_STATE operating_state = OST_IDLE;

    /*-----( Declare objects )-----*/
    // set the LCD address to 0x27 for a 16 chars 2 line display
    // A FEW use address 0x3F
    // Set the pins on the I2C chip used for LCD connections:
    LiquidCrystal_I2C lcd(0x27, 16,2);  // Set the LCD I2C address
    // if the LCD is parallel then uncomment the line below instead - pins may need to change
    // LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

    // set up rotary encoder Pin A, Pin B, Button Pin
    SimpleRotary rotary(3,2,4);
    
    /*-----( Declare Variables )-----*/

    const int RELAY1_PIN = 7;
    const int RELAY2_PIN = 8;
    //const int KY_CLK_PIN = 2; // KY-040 CLK
    //const int KY_DT_PIN = 3; // KY-040 DT
    //const int KY_SET_PIN = 4; // KY-040 Pushbutton
    const int RESET_PIN = 5;
    const int INHIBIT_PIN = 6;

    const int SECURITY_PIN = 9;

    //int pinA = 3;  // Connected to CLK on KY-040
    //int pinB = 4;  // Connected to DT on KY-040
    int encoderPosCount = 30;

    int pinALast;
    int aVal;

    DBSwitch swReset(RESET_PIN);
    //DBSwitch swSetTimer(KY_SET_PIN);


    bool swResetLast = true;
    //bool swSetTimerLast;
    bool swInhibitLast;
    //boolean bClockwise; // rotation direction

    //--
    int minutes_remaining = 0;
    int seconds_remaining = 0;
    unsigned long time_started = 0L;
    unsigned long next_tick = 0L;


    void setup() {

      //pinMode (KY_CLK_PIN, INPUT);
     // pinMode (KY_DT_PIN, INPUT);
     
      pinMode (SECURITY_PIN, INPUT_PULLUP);
      pinMode (INHIBIT_PIN, INPUT_PULLUP);
      swInhibitLast = digitalRead(INHIBIT_PIN);

      pinMode (RESET_PIN, INPUT_PULLUP);
      //pinMode (KY_SET_PIN, INPUT_PULLUP);
      //swSetTimerLast = digitalRead(KY_SET_PIN);

      bool sw = swReset.query();
      bool signalReset = false;
      bool swResetLast = false;
      if ( sw && ! swResetLast ) { // toggle
        signalReset = true;
      }
      swResetLast = sw;

      pinMode(RELAY1_PIN, OUTPUT);
      pinMode(RELAY2_PIN, OUTPUT);
      /* Read Pin A
        Whatever state it's in will reflect the last position
      */
     // pinALast = digitalRead(KY_CLK_PIN);
      Serial.begin (9600);
      Serial.println("Starting...");

      lcd.init();  // initialize the lcd 
      lcd.backlight(); // finish with backlight on

      lcd.setCursor(0, 0); //Start at character 4 on line 0
      lcd.print("Starting...");

      // Restore timer from EEPROM
      reset_relays();
      encoderPosCount = timer_load();
      timer_restart(encoderPosCount);
      setOperatingState(OST_RUNNING); // IDLE
    }


    void loop() {

      // LED control
      static uint32_t TimerPeriodes = 0;
      static uint32_t TimerBliking = 0;
      static bool isBlinkEnable = false;
      if ( millis() - TimerPeriodes >= ChangeAfter) {
        TimerPeriodes += ChangeAfter;
       isBlinkEnable = !isBlinkEnable;
      }
      if (isBlinkEnable) {
         if ( millis() - TimerBliking >= BlinkHalfPeriod) {
           TimerBliking += BlinkHalfPeriod;
           digitalWrite(BlinkPin, !digitalRead(BlinkPin));
         }
      }  else digitalWrite(BlinkPin, LOW);
  
   
    

      //if ( NOT digitalRead(INHIBIT_PIN) ) {
      //  delay(500);
      //  return;
      //}
      
      unsigned long now = millis();

      bool keyLock = ! digitalRead(SECURITY_PIN);
      //bool kyKeyPress = digitalRead(KY_SET_PIN);
      if ( ! keyLock ) {
        //lcd.clear();
        lcd.setCursor(0, 1); //Start at character 0 on line 1
        lcd.print("Unlocked");

        handle_locked_operations(now);
      } else {
        //lcd.clear();
        lcd.setCursor(0, 1); //Start at character 0 on line 1
        lcd.print("Locked  ");
      }

      bool resetSignalled = false;


      // ****** Handle Reset button ******

      bool sw = ASSERTED swReset.query();
      if ( sw ) { // Reset held down
        if ( NOT swResetLast ) {
          // Timer interrupted
          lcd.clear();
          lcd.setCursor(2, 1); //Start at character 2 on line 1
          lcd.print("** RESET **");
          delay(1000);
          swResetLast = true;
         
        }
        return;
      }
      if ( swResetLast ) { // also return from INHIBIT
        resetSignalled = true;
        swResetLast = false;
        reset_relays();
        isBlinkEnable = false;
        lcd.clear();
        timer_restart(encoderPosCount);
        setOperatingState(OST_RUNNING);
      }


      switch (operating_state) {
        case OST_IDLE:
        case OST_SET:
          handle_timer_set();
          // Also check for "SET" button pressed to exit state.
          break;
        case OST_RUNNING:
          if ( now > next_tick ) {
            timer_tick_seconds();
            timer_display_count();
            if (( minutes_remaining == 0) && (seconds_remaining == 0)) {
              // FIRE RELAY 1!!!
              digitalWrite(RELAY1_PIN, 1);
              setOperatingState(OST_EXPIRED1);
              isBlinkEnable = true;
              timer_restart(1); // One minute EXPIRED count
            }
          }
          break;
        case OST_EXPIRED1:
          if ( now > next_tick ) {
            timer_tick_seconds();
            timer_display_count();
            if (seconds_remaining == 0) {
              // FIRE RELAY 2!!!
              digitalWrite(RELAY2_PIN, 1);
              setOperatingState(OST_EXPIRED2);
              lcd.clear();
              lcd.setCursor(0, 0);
              lcd.print("*** EXPIRED ***");
            }
          }
          break;
        case OST_EXPIRED2:
          break;
      }
    }

    /**
       Process things that can only be done if the security switch is not set.
    */
    void handle_locked_operations(const unsigned long now) {
      
      // *** Timer set sw

      bool keyLock = ! digitalRead(SECURITY_PIN);
      if ( !keyLock) {
        byte j;
        // detect if rotary encoder button pressed 0 = not pushed, 1 = pushed
        j = rotary.push();
        // ONLY allow set-mode if SECURITY SWITCH is ON
        if ( j==1 ) { // act on button-release
          if ( operating_state == OST_SET ) {
            timer_save(encoderPosCount);
            timer_restart(encoderPosCount);
            setOperatingState(OST_RUNNING);
          } 
          else {
            setOperatingState(OST_SET);
            display_timer_set();
          }
        }
        //swSetTimerLast = sw;
      }
    }

    /**
       Return the relays to their "OFF" settings.
    */
    void reset_relays() {

      digitalWrite(RELAY1_PIN, 0);
      digitalWrite(RELAY2_PIN, 0);

    }

    /**
       When we are in OST_SET state, we read the encoder and
       set the timer.
    */
    void handle_timer_set() {
       lcd.clear();
       lcd.setCursor(0, 0); //Start at character 0 on line 1
       lcd.print("Timer set:");
       lcd.setCursor(2, 1); //Start at character 2 on line 1
       char buf[3];
       buf[2] = 0;
       lcd.print(format_rj2( buf, encoderPosCount));
       lcd.setCursor(5,1);
       lcd.print( " Minutes");
       do {
        lcd.setCursor(2, 1); //Start at character 2 on line 1  
        byte i;
        // 0 = not turning, 1 = CW, 2 = CCW - you may need to swap these depending on the encoder and pins
        i = rotary.rotate();
        if ( i == 2 && encoderPosCount < MAX_MINUTES) {
          encoderPosCount++;
          char buf[3];
          buf[2] = 0;
          lcd.print(format_rj2( buf, encoderPosCount));
          }
        if ( i == 1 && encoderPosCount > 1) {
          encoderPosCount--;
          char buf[3];
          buf[2] = 0;
          lcd.print(format_rj2( buf, encoderPosCount));
          }
        }
        while (rotary.push()==0);
        timer_save(encoderPosCount);
        timer_restart(encoderPosCount);
        setOperatingState(OST_RUNNING);
  
       // byte i;
        // 0 = not turning, 1 = CW, 2 = CCW
       //i = rotary.rotate();
        //if (i==1) {  //  - We're Rotating Clockwise

         /// if ( encoderPosCount < MAX_MINUTES ) 
         //   encoderPosCount ++;
         //   else encoderPosCount = MAX_MINUTES;
       // }  
       // if (i==2) {// Otherwise B changed first and we're moving CCW
         // if ( encoderPosCount > 1 ) {
         //   encoderPosCount--;
        //  }
       // }
       // display_timer_set();
    }

    static void display_timer_set() {
      //lcd.clear();
      lcd.setCursor(0, 0); //Start at character 0 on line 1
      lcd.print("Timer set:");
      lcd.setCursor(2, 1); //Start at character 2 on line 1
      char buf[3];
      buf[2] = 0;
      //lcd.print(format_rj2( buf, encoderPosCount));
      lcd.print( " Minutes");
    }

    static void setOperatingState(OPERATING_STATE ost) {
      if ( ost != operating_state ) {
        lcd.clear();
      }
      operating_state = ost;
    }

    /**
       Restart the time count.
    */
    static void timer_restart(int minutes) {
      unsigned long now = millis();
      time_started = now;
      //Serial.print("Timer Restart "); Serial.println(encoderPosCount);
      minutes_remaining = minutes; // MINUTES - todo - pull from EEPROM
      seconds_remaining = 0;
      next_tick = now + 1000; // msec = 1 second
    }

    /**
       Count down 1 second intervals
    */
    static void timer_tick_seconds() {
      seconds_remaining--;
      if ( seconds_remaining < 0 ) {
        seconds_remaining = 59;
        minutes_remaining--;
      }
      next_tick = next_tick + 1000; // msec = 1 second
    }

    /**
       Display current time remaining.
    */
    static void timer_display_count() {
      lcd.setCursor(0, 0); //Start at character 0 on line 0
      char buf[3];
      if ( minutes_remaining > 0 ) {
        lcd.print(format_rj2(buf, minutes_remaining));
        lcd.print(" Min. remain");
      } else {
        lcd.print(format_rj2(buf, seconds_remaining));
        lcd.print(" Sec. remain");
      }
      if ( operating_state == OST_EXPIRED1 ) {
        lcd.setCursor(0, 1); //Start at character 0 on line 0
        lcd.print("Expired");
      }
    }

    /**
       Right-justified format of a 2-digit number
    */
    static char* format_rj2(char* buf, int n) {
      if ( n > 99 ) { // limit range.
        n = n % 100;
      }
      buf[1] = (n % 10) + '0';
      buf[0] = (n / 10) + '0';
      buf[2] = 0;
      if ( buf[0] == '0') {
        buf[0] = ' '; // leading space
      }
      return buf;
    }

    //**** EEPROM ****

    const int ee_addr0 = 0;

    static void timer_save(int count) {
      EEPROM.update(ee_addr0, (count >> 8) & 0xff);
      EEPROM.update(ee_addr0 + 1, (count) & 0xff);
    }

    static int timer_load() {
      int val = EEPROM.read(ee_addr0) << 8;
      val |= EEPROM.read(ee_addr0 + 1);
      return val;
    }

OK, here is an update.

I ended up adding some more simple code which does the job and ive got it 90% working.
Only issue im having is that it only works 50/50 of the time when reset is pressed.

Whats happening is that sometimes, when reset is pressed, the LED stops flashing, but instead stays on. Pressing reset again wont turn it off, but typically will when the timer expires and reset is pressed again after the time has expired.

Is there somewhere else I need to add a line to bring pin 13 back to low?

I used the blinking code from here:

Here is my code:

    // KY-040 encoder for timer

    #define NOT !
    #define ASSERTED !

    // LED config
    #define LED_PIN 13
    
    /*-----( Import needed libraries )-----*/
    #include <Wire.h>  // Comes with Arduino IDE
    // Get the LCD I2C Library here:
    // https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads
    // Move any other LCD libraries to another folder or delete them
    // See Library "Docs" folder for possible commands etc.
    // Simple Rotary library will need to be installed via library manager
    #include <LiquidCrystal_I2C.h>
    #include <EEPROM.h>
    #include <SimpleRotary.h>

    /*-----( Declare Constants )-----*/

    /* Maximum number of timer minutes we can set. */
    const int MAX_MINUTES = 60;

    const unsigned long DEBOUNCE_INTERVAL = 100; // msec

    typedef class _DBSwitch {
      private:
        bool state;
        bool lastState;
        int pinNumber;
        unsigned long last_change;
      public:
        _DBSwitch(int pPinNumber) {
          pinNumber = pPinNumber;
          state = lastState = false;
          last_change = 0;
          (void) query();
        }

        bool query() {
          unsigned long now = millis();
          bool value = digitalRead(pinNumber);
          if ( value != lastState ) {
            last_change = now;
          } else {
            if ( (value != state) && ( last_change + DEBOUNCE_INTERVAL ) < now ) {
              state = value;
            }
          }
          lastState = value;
          return state;
        }
    } DBSwitch;

    typedef enum OPERATING_STATE  {
      OST_IDLE,
      OST_RESET_PENDING,
      OST_SET,
      OST_RUNNING,
      OST_EXPIRED1,
      OST_EXPIRED2
    } OPERATING_STATE;

    static OPERATING_STATE operating_state = OST_IDLE;

    /*-----( Declare objects )-----*/
    // set the LCD address to 0x27 for a 16 chars 2 line display
    // A FEW use address 0x3F
    // Set the pins on the I2C chip used for LCD connections:
    LiquidCrystal_I2C lcd(0x27, 16,2);  // Set the LCD I2C address
    // if the LCD is parallel then uncomment the line below instead - pins may need to change
    // LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

    // set up rotary encoder Pin A, Pin B, Button Pin
    SimpleRotary rotary(3,2,4);
    
    /*-----( Declare Variables )-----*/

    //Start with LED flashstate "off"
    boolean flashState = false;
    int ledState = LOW;
    unsigned long prevMillis = 0;
    const long interval = 1000;

    
    const int RELAY1_PIN = 7;
    const int RELAY2_PIN = 8;
    //const int KY_CLK_PIN = 2; // KY-040 CLK
    //const int KY_DT_PIN = 3; // KY-040 DT
    //const int KY_SET_PIN = 4; // KY-040 Pushbutton
    const int RESET_PIN = 5;
    const int INHIBIT_PIN = 6;

    const int SECURITY_PIN = 9;

    //int pinA = 3;  // Connected to CLK on KY-040
    //int pinB = 4;  // Connected to DT on KY-040
    int encoderPosCount = 30;

    int pinALast;
    int aVal;

    DBSwitch swReset(RESET_PIN);
    //DBSwitch swSetTimer(KY_SET_PIN);


    bool swResetLast = true;
    //bool swSetTimerLast;
    bool swInhibitLast;
    //boolean bClockwise; // rotation direction

    //--
    int minutes_remaining = 0;
    int seconds_remaining = 0;
    unsigned long time_started = 0L;
    unsigned long next_tick = 0L;


    void setup() {

      //pinMode LED
      pinMode(LED_PIN, OUTPUT);
      //pinMode (KY_CLK_PIN, INPUT);
      //pinMode (KY_DT_PIN, INPUT);
     
      pinMode (SECURITY_PIN, INPUT_PULLUP);
      pinMode (INHIBIT_PIN, INPUT_PULLUP);
      swInhibitLast = digitalRead(INHIBIT_PIN);

      pinMode (RESET_PIN, INPUT_PULLUP);
      //pinMode (KY_SET_PIN, INPUT_PULLUP);
      //swSetTimerLast = digitalRead(KY_SET_PIN);

      bool sw = swReset.query();
      bool signalReset = false;
      bool swResetLast = false;
      if ( sw && ! swResetLast ) { // toggle
        signalReset = true;
      }
      swResetLast = sw;

      pinMode(RELAY1_PIN, OUTPUT);
      pinMode(RELAY2_PIN, OUTPUT);
      /* Read Pin A
        Whatever state it's in will reflect the last position
      */
     // pinALast = digitalRead(KY_CLK_PIN);
      Serial.begin (9600);
      Serial.println("Starting...");

      lcd.init();  // initialize the lcd 
      lcd.backlight(); // finish with backlight on

      lcd.setCursor(0, 0); //Start at character 4 on line 0
      lcd.print("Starting...");

      // Restore timer from EEPROM
      reset_relays();
      flashState = false; //Disable LED Flasher
      ledState = LOW;
      encoderPosCount = timer_load();
      timer_restart(encoderPosCount);
      setOperatingState(OST_RUNNING); // IDLE
    }


    void loop() {

     //LED control
     unsigned long currentMillis = millis();
      
      //if ( NOT digitalRead(INHIBIT_PIN) ) {
      //  delay(500);
      //  return;
      //}
      
      unsigned long now = millis();

      bool keyLock = ! digitalRead(SECURITY_PIN);
      //bool kyKeyPress = digitalRead(KY_SET_PIN);
      if ( ! keyLock ) {
        //lcd.clear();
        lcd.setCursor(0, 1); //Start at character 0 on line 1
        lcd.print("Unlocked");

        handle_locked_operations(now);
      } else {
        //lcd.clear();
        lcd.setCursor(0, 1); //Start at character 0 on line 1
        lcd.print("Locked  ");
      }

      bool resetSignalled = false;


      // ****** Handle Reset button ******

      bool sw = ASSERTED swReset.query();
      if ( sw ) { // Reset held down
        if ( NOT swResetLast ) {
          // Timer interrupted
          lcd.clear();
          lcd.setCursor(2, 1); //Start at character 2 on line 1
          lcd.print("** RESET **");
          delay(1000);
          swResetLast = true;
          flashState = false; //Disable LED Flasher
          ledState = LOW;
        }
        return;
      }
      if ( swResetLast ) { // also return from INHIBIT
        resetSignalled = true;
        swResetLast = false;
        reset_relays();
        flashState = false; //Disable LED Flasher
        ledState = LOW;
        lcd.clear();
        timer_restart(encoderPosCount);
        setOperatingState(OST_RUNNING);
      }


      switch (operating_state) {
        case OST_IDLE:
        case OST_SET:
          handle_timer_set();
          // Also check for "SET" button pressed to exit state.
          break;
        case OST_RUNNING:
          if ( now > next_tick ) {
            timer_tick_seconds();
            timer_display_count();
            if (( minutes_remaining == 0) && (seconds_remaining == 0)) {
              // FIRE RELAY 1!!!
              digitalWrite(RELAY1_PIN, 1);
              setOperatingState(OST_EXPIRED1);      
              flashState = true;  //Flash LED
              timer_restart(1); // One minute EXPIRED count
            }
          }
          break;
        case OST_EXPIRED1:
          if ( now > next_tick ) {
            timer_tick_seconds();
            timer_display_count();
            if (seconds_remaining == 0) {
              // FIRE RELAY 2!!!
              digitalWrite(RELAY2_PIN, 1);
              setOperatingState(OST_EXPIRED2);
              lcd.clear();
              lcd.setCursor(0, 0);
              lcd.print("*** EXPIRED ***");
            }
          }
          break;
        case OST_EXPIRED2:
          break;
      }
    
      if (currentMillis - prevMillis >= interval)
      {
        prevMillis = currentMillis;

        if (ledState == LOW)
          ledState = HIGH;
        else
         ledState = LOW;
        // only flash LED if the flashState is true
       if (flashState == true)
         digitalWrite(LED_PIN, ledState);
     }

    }
      
    /**
       Process things that can only be done if the security switch is not set.
    */
    void handle_locked_operations(const unsigned long now) {
      
      // *** Timer set sw

      bool keyLock = ! digitalRead(SECURITY_PIN);
      if ( !keyLock) {
        byte j;
        // detect if rotary encoder button pressed 0 = not pushed, 1 = pushed
        j = rotary.push();
        // ONLY allow set-mode if SECURITY SWITCH is ON
        if ( j==1 ) { // act on button-release
          if ( operating_state == OST_SET ) {
            timer_save(encoderPosCount);
            timer_restart(encoderPosCount);
            setOperatingState(OST_RUNNING);
          } 
          else {
            setOperatingState(OST_SET);
            display_timer_set();
          }
        }
        //swSetTimerLast = sw;
      }
    }

    /**
       Return the relays to their "OFF" settings.
    */
    void reset_relays() {

      digitalWrite(RELAY1_PIN, 0);
      digitalWrite(RELAY2_PIN, 0);
    }



    /**
       When we are in OST_SET state, we read the encoder and
       set the timer.
    */
    void handle_timer_set() {
       lcd.clear();
       lcd.setCursor(0, 0); //Start at character 0 on line 1
       lcd.print("Timer set:");
       lcd.setCursor(2, 1); //Start at character 2 on line 1
       char buf[3];
       buf[2] = 0;
       lcd.print(format_rj2( buf, encoderPosCount));
       lcd.setCursor(5,1);
       lcd.print( " Minutes");
       do {
        lcd.setCursor(2, 1); //Start at character 2 on line 1  
        byte i;
        // 0 = not turning, 1 = CW, 2 = CCW - you may need to swap these depending on the encoder and pins
        i = rotary.rotate();
        if ( i == 2 && encoderPosCount < MAX_MINUTES) {
          encoderPosCount++;
          char buf[3];
          buf[2] = 0;
          lcd.print(format_rj2( buf, encoderPosCount));
          }
        if ( i == 1 && encoderPosCount > 1) {
          encoderPosCount--;
          char buf[3];
          buf[2] = 0;
          lcd.print(format_rj2( buf, encoderPosCount));
          }
        }
        while (rotary.push()==0);
        timer_save(encoderPosCount);
        timer_restart(encoderPosCount);
        setOperatingState(OST_RUNNING);
  
       // byte i;
        // 0 = not turning, 1 = CW, 2 = CCW
       //i = rotary.rotate();
        //if (i==1) {  //  - We're Rotating Clockwise

         /// if ( encoderPosCount < MAX_MINUTES ) 
         //   encoderPosCount ++;
         //   else encoderPosCount = MAX_MINUTES;
       // }  
       // if (i==2) {// Otherwise B changed first and we're moving CCW
         // if ( encoderPosCount > 1 ) {
         //   encoderPosCount--;
        //  }
       // }
       // display_timer_set();
    }

    static void display_timer_set() {
      //lcd.clear();
      lcd.setCursor(0, 0); //Start at character 0 on line 1
      lcd.print("Timer set:");
      lcd.setCursor(2, 1); //Start at character 2 on line 1
      char buf[3];
      buf[2] = 0;
      //lcd.print(format_rj2( buf, encoderPosCount));
      lcd.print( " Minutes");
    }

    static void setOperatingState(OPERATING_STATE ost) {
      if ( ost != operating_state ) {
        lcd.clear();
      }
      operating_state = ost;
    }

    /**
       Restart the time count.
    */
    static void timer_restart(int minutes) {
      unsigned long now = millis();
      time_started = now;
      //Serial.print("Timer Restart "); Serial.println(encoderPosCount);
      minutes_remaining = minutes; // MINUTES - todo - pull from EEPROM
      seconds_remaining = 0;
      next_tick = now + 1000; // msec = 1 second
    }

    /**
       Count down 1 second intervals
    */
    static void timer_tick_seconds() {
      seconds_remaining--;
      if ( seconds_remaining < 0 ) {
        seconds_remaining = 59;
        minutes_remaining--;
      }
      next_tick = next_tick + 1000; // msec = 1 second
    }

    /**
       Display current time remaining.
    */
    static void timer_display_count() {
      lcd.setCursor(0, 0); //Start at character 0 on line 0
      char buf[3];
      if ( minutes_remaining > 0 ) {
        lcd.print(format_rj2(buf, minutes_remaining));
        lcd.print(" Min. remain");
      } else {
        lcd.print(format_rj2(buf, seconds_remaining));
        lcd.print(" Sec. remain");
      }
      if ( operating_state == OST_EXPIRED1 ) {
        lcd.setCursor(0, 1); //Start at character 0 on line 0
        lcd.print("Expired");
      }
    }

    /**
       Right-justified format of a 2-digit number
    */
    static char* format_rj2(char* buf, int n) {
      if ( n > 99 ) { // limit range.
        n = n % 100;
      }
      buf[1] = (n % 10) + '0';
      buf[0] = (n / 10) + '0';
      buf[2] = 0;
      if ( buf[0] == '0') {
        buf[0] = ' '; // leading space
      }
      return buf;
    }

    //**** EEPROM ****

    const int ee_addr0 = 0;

    static void timer_save(int count) {
      EEPROM.update(ee_addr0, (count >> 8) & 0xff);
      EEPROM.update(ee_addr0 + 1, (count) & 0xff);
    }

    static int timer_load() {
      int val = EEPROM.read(ee_addr0) << 8;
      val |= EEPROM.read(ee_addr0 + 1);
      return val;
    }

Been playing around with this all day and have discovered its basically stopping the LED from flashing when reset, but the LED stays on if it happens to be on at the same time as pressing the reset button.
Ive added a line under "flashstate = false to tell pin 13 to go LOW, but its still staying on.

Any ideas?

post the code

Your code does not (yet) use serial printing to give you additional information about:

  • which lines of code gets really executed
  • printing values of all kinds of variables
  • give feedback about if-conditions beeing true or false

If I will ever decide to engage myself more to support you this are the things I will do.
It will take my 20 to 30 minutes to add all these serial output and it is very clear this time-investment stays at this amount of time. But after investing this time the time for analysing the code will shrink down from not knowing if it will take 8 to 12 hours and still no luck to 30 to 90 minutes getting to know what happends.

Me personal I use two so called macros for serial debugging one that allows for non-blocking but "intervalled" printing even in very fast running loops and one that prints every time
both printing in a convenient way where a single line of code does print three things

  1. a fixed text for easy re-locating the line of code that was printing
  2. the variable-name
  3. the value of this variable

with this information it is much easier to understand what the code is really doing.

best regards Stefan

Here is a version of your code with a lot of serial debug-output

// MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START *
// Take it for granted at the moment scroll down to void setup
// start of macros dbg and dbgi
#define dbg(myFixedText, variableName) \
  Serial.print( F(#myFixedText " "  #variableName"=") ); \
  Serial.println(variableName);
// usage: dbg("1:my fixed text",myVariable);
// myVariable can be any variable or expression that is defined in scope

#define dbgi(myFixedText, variableName,timeInterval) \
  do { \
    static unsigned long intervalStartTime; \
    if ( millis() - intervalStartTime >= timeInterval ){ \
      intervalStartTime = millis(); \
      Serial.print( F(#myFixedText " "  #variableName"=") ); \
      Serial.println(variableName); \
    } \
  } while (false);
// usage: dbgi("2:my fixed text",myVariable,1000);
// myVariable can be any variable or expression that is defined in scope
// third parameter is the time in milliseconds that must pass by until the next time a
// Serial.print is executed
// end of macros dbg and dbgi
// MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END *


// KY-040 encoder for timer

#define NOT !
#define ASSERTED !

// LED config
#define LED_PIN 13

/*-----( Import needed libraries )-----*/
#include <Wire.h>  // Comes with Arduino IDE
// Get the LCD I2C Library here:
// https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads
// Move any other LCD libraries to another folder or delete them
// See Library "Docs" folder for possible commands etc.
// Simple Rotary library will need to be installed via library manager
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
#include <SimpleRotary.h>

/*-----( Declare Constants )-----*/

/* Maximum number of timer minutes we can set. */
const int MAX_MINUTES = 60;

const unsigned long DEBOUNCE_INTERVAL = 100; // msec

typedef class _DBSwitch {
  private:
    bool state;
    bool lastState;
    int pinNumber;
    unsigned long last_change;
  public:
    _DBSwitch(int pPinNumber) {
      pinNumber = pPinNumber;
      state = lastState = false;
      last_change = 0;
      (void) query();
    }

    bool query() {
      unsigned long now = millis();
      bool value = digitalRead(pinNumber);
      if ( value != lastState ) {
        last_change = now;
      } else {
        if ( (value != state) && ( last_change + DEBOUNCE_INTERVAL ) < now ) {
          state = value;
        }
      }
      lastState = value;
      return state;
    }
} DBSwitch;

typedef enum OPERATING_STATE  {
  OST_IDLE,
  OST_RESET_PENDING,
  OST_SET,
  OST_RUNNING,
  OST_EXPIRED1,
  OST_EXPIRED2
} OPERATING_STATE;

static OPERATING_STATE operating_state = OST_IDLE;

/*-----( Declare objects )-----*/
// set the LCD address to 0x27 for a 16 chars 2 line display
// A FEW use address 0x3F
// Set the pins on the I2C chip used for LCD connections:
LiquidCrystal_I2C lcd(0x27, 16, 2); // Set the LCD I2C address
// if the LCD is parallel then uncomment the line below instead - pins may need to change
// LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

// set up rotary encoder Pin A, Pin B, Button Pin
SimpleRotary rotary(3, 2, 4);

/*-----( Declare Variables )-----*/

//Start with LED flashstate "off"
boolean flashState = false;
int ledState = LOW;
unsigned long prevMillis = 0;
const long interval = 1000;


const int RELAY1_PIN = 7;
const int RELAY2_PIN = 8;
//const int KY_CLK_PIN = 2; // KY-040 CLK
//const int KY_DT_PIN = 3; // KY-040 DT
//const int KY_SET_PIN = 4; // KY-040 Pushbutton
const int RESET_PIN = 5;
const int INHIBIT_PIN = 6;

const int SECURITY_PIN = 9;

//int pinA = 3;  // Connected to CLK on KY-040
//int pinB = 4;  // Connected to DT on KY-040
int encoderPosCount = 30;

int pinALast;
int aVal;

DBSwitch swReset(RESET_PIN);
//DBSwitch swSetTimer(KY_SET_PIN);


bool swResetLast = true;
//bool swSetTimerLast;
bool swInhibitLast;
//boolean bClockwise; // rotation direction

//--
int minutes_remaining = 0;
int seconds_remaining = 0;
unsigned long time_started = 0L;
unsigned long next_tick = 0L;


void setup() {

  //pinMode LED
  pinMode(LED_PIN, OUTPUT);
  //pinMode (KY_CLK_PIN, INPUT);
  //pinMode (KY_DT_PIN, INPUT);

  pinMode (SECURITY_PIN, INPUT_PULLUP);
  pinMode (INHIBIT_PIN, INPUT_PULLUP);
  swInhibitLast = digitalRead(INHIBIT_PIN);

  pinMode (RESET_PIN, INPUT_PULLUP);
  //pinMode (KY_SET_PIN, INPUT_PULLUP);
  //swSetTimerLast = digitalRead(KY_SET_PIN);

  bool sw = swReset.query();
  bool signalReset = false;
  bool swResetLast = false;
  if ( sw && ! swResetLast ) { // toggle
    signalReset = true;
  }
  swResetLast = sw;

  pinMode(RELAY1_PIN, OUTPUT);
  pinMode(RELAY2_PIN, OUTPUT);
  /* Read Pin A
    Whatever state it's in will reflect the last position
  */
  // pinALast = digitalRead(KY_CLK_PIN);
  Serial.begin (9600);
  Serial.println("Starting...");

  lcd.init();  // initialize the lcd
  lcd.backlight(); // finish with backlight on

  lcd.setCursor(0, 0); //Start at character 4 on line 0
  lcd.print("Starting...");

  // Restore timer from EEPROM
  reset_relays();
  flashState = false; //Disable LED Flasher
  ledState = LOW;
  encoderPosCount = timer_load();
  timer_restart(encoderPosCount);
  setOperatingState(OST_RUNNING); // IDLE
}


void loop() {

  //LED control
  unsigned long currentMillis = millis();

  //if ( NOT digitalRead(INHIBIT_PIN) ) {
  //  delay(500);
  //  return;
  //}

  unsigned long now = millis();

  bool keyLock = ! digitalRead(SECURITY_PIN);
  //bool kyKeyPress = digitalRead(KY_SET_PIN);
  if ( ! keyLock ) {
    dbgi("01:if ( ! keyLock )", 0, 1000);
    //lcd.clear();
    lcd.setCursor(0, 1); //Start at character 0 on line 1
    lcd.print("Unlocked");
    handle_locked_operations(now);
  } else {
    dbgi("02:else locked", 0, 1000);
    //lcd.clear();
    lcd.setCursor(0, 1); //Start at character 0 on line 1
    lcd.print("Locked  ");
  }

  bool resetSignalled = false;


  // ****** Handle Reset button ******

  bool sw = ASSERTED swReset.query();
  if ( sw ) { // Reset held down
    dbgi("03:if ( sw )", sw, 1000);
    if ( NOT swResetLast ) {
      dbgi("04:if ( NOT swResetLast )", flashState, 1000);
      // Timer interrupted
      lcd.clear();
      lcd.setCursor(2, 1); //Start at character 2 on line 1
      lcd.print("** RESET **");
      delay(1000);
      swResetLast = true;
      flashState = false; //Disable LED Flasher
      ledState = LOW;
    }
    dbgi("05:returning to top of loop", flashState, 1000);
    return;
  }

  if ( swResetLast ) { // also return from INHIBIT
    dbgi("06:if ( swResetLast )", flashState, 1000);
    resetSignalled = true;
    swResetLast = false;
    reset_relays();
    flashState = false; //Disable LED Flasher
    ledState = LOW;
    lcd.clear();
    timer_restart(encoderPosCount);
    setOperatingState(OST_RUNNING);
  }


  switch (operating_state) {
    case OST_IDLE:
    case OST_SET:
      handle_timer_set();
      // Also check for "SET" button pressed to exit state.
      break;
    case OST_RUNNING:
      if ( now > next_tick ) {
        timer_tick_seconds();
        timer_display_count();
        if (( minutes_remaining == 0) && (seconds_remaining == 0)) {
          // FIRE RELAY 1!!!
          digitalWrite(RELAY1_PIN, 1);
          setOperatingState(OST_EXPIRED1);
          flashState = true;  //Flash LED
          timer_restart(1); // One minute EXPIRED count
        }
      }
      break;
    case OST_EXPIRED1:
      if ( now > next_tick ) {
        timer_tick_seconds();
        timer_display_count();
        if (seconds_remaining == 0) {
          // FIRE RELAY 2!!!
          digitalWrite(RELAY2_PIN, 1);
          setOperatingState(OST_EXPIRED2);
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("*** EXPIRED ***");
        }
      }
      break;
    case OST_EXPIRED2:
      break;
  }

  if (currentMillis - prevMillis >= interval)
  {
    prevMillis = currentMillis;

    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;
    // only flash LED if the flashState is true
    if (flashState == true)
      digitalWrite(LED_PIN, ledState);
  }

}

/**
   Process things that can only be done if the security switch is not set.
*/
void handle_locked_operations(const unsigned long now) {
  dbgi("0A: entering handle_locked_operations",now,1000);
  // *** Timer set sw

  bool keyLock = ! digitalRead(SECURITY_PIN);
  if ( !keyLock) {
    byte j;
    // detect if rotary encoder button pressed 0 = not pushed, 1 = pushed
    j = rotary.push();
    dbgi("0B: if ( !keyLock)",j,1000);
    // ONLY allow set-mode if SECURITY SWITCH is ON
    if ( j == 1 ) { // act on button-release
      if ( operating_state == OST_SET ) {
        timer_save(encoderPosCount);
        timer_restart(encoderPosCount);
        setOperatingState(OST_RUNNING);
      }
      else {
        setOperatingState(OST_SET);
        display_timer_set();
      }
    }
    //swSetTimerLast = sw;
  }
  dbgi("0Z: leaving handle_locked_operations",now,1000);
}

/**
   Return the relays to their "OFF" settings.
*/
void reset_relays() {
  dbgi("0A: entering reset_relays()",0,1000);

  digitalWrite(RELAY1_PIN, 0);
  digitalWrite(RELAY2_PIN, 0);
}



/**
   When we are in OST_SET state, we read the encoder and
   set the timer.
*/
void handle_timer_set() {
  dbgi("0A: entering handle_timer_set()",0,200);
  lcd.clear();
  lcd.setCursor(0, 0); //Start at character 0 on line 1
  lcd.print("Timer set:");
  lcd.setCursor(2, 1); //Start at character 2 on line 1
  char buf[3];
  buf[2] = 0;
  lcd.print(format_rj2( buf, encoderPosCount));
  lcd.setCursor(5, 1);
  lcd.print( " Minutes");
  do {
    lcd.setCursor(2, 1); //Start at character 2 on line 1
    byte i;
    // 0 = not turning, 1 = CW, 2 = CCW - you may need to swap these depending on the encoder and pins
    i = rotary.rotate();
    if ( i == 2 && encoderPosCount < MAX_MINUTES) {
      encoderPosCount++;
      char buf[3];
      buf[2] = 0;
      lcd.print(format_rj2( buf, encoderPosCount));
    }
    if ( i == 1 && encoderPosCount > 1) {
      encoderPosCount--;
      char buf[3];
      buf[2] = 0;
      lcd.print(format_rj2( buf, encoderPosCount));
    }
  }
  while (rotary.push() == 0);
  timer_save(encoderPosCount);
  timer_restart(encoderPosCount);
  setOperatingState(OST_RUNNING);

  // byte i;
  // 0 = not turning, 1 = CW, 2 = CCW
  //i = rotary.rotate();
  //if (i==1) {  //  - We're Rotating Clockwise

  /// if ( encoderPosCount < MAX_MINUTES )
  //   encoderPosCount ++;
  //   else encoderPosCount = MAX_MINUTES;
  // }
  // if (i==2) {// Otherwise B changed first and we're moving CCW
  // if ( encoderPosCount > 1 ) {
  //   encoderPosCount--;
  //  }
  // }
  // display_timer_set();
  dbgi("0Z: leaving handle_timer_set()",0,200);

}

static void display_timer_set() {
  dbgi("0A: entering display_timer_set()",0,200);
  
  //lcd.clear();
  lcd.setCursor(0, 0); //Start at character 0 on line 1
  lcd.print("Timer set:");
  lcd.setCursor(2, 1); //Start at character 2 on line 1
  char buf[3]; // this defines a LOCAL array 
  buf[2] = 0;
  //lcd.print(format_rj2( buf, encoderPosCount));
  lcd.print( " Minutes");
}

static void setOperatingState(OPERATING_STATE ost) {
  dbgi("0A: entering setOperatingState(",ost,200);
  if ( ost != operating_state ) {
    lcd.clear();
  }
  operating_state = ost;
}

/**
   Restart the time count.
*/
static void timer_restart(int minutes) {
  dbgi("0A: entering timer_restart(",minutes,200);
  unsigned long now = millis();
  time_started = now;
  //Serial.print("Timer Restart "); Serial.println(encoderPosCount);
  minutes_remaining = minutes; // MINUTES - todo - pull from EEPROM
  seconds_remaining = 0;
  next_tick = now + 1000; // msec = 1 second
  dbgi("0Z: leaving timer_restart(",next_tick,200);
}

/**
   Count down 1 second intervals
*/
static void timer_tick_seconds() {
  seconds_remaining--;
  if ( seconds_remaining < 0 ) {
    seconds_remaining = 59;
    minutes_remaining--;
    dbgi("0A if ( seconds_remaining < 0 )",minutes_remaining,200);
  }
  next_tick = next_tick + 1000; // msec = 1 second
}

/**
   Display current time remaining.
*/
static void timer_display_count() {
  lcd.setCursor(0, 0); //Start at character 0 on line 0
  char buf[3];
  if ( minutes_remaining > 0 ) {
    lcd.print(format_rj2(buf, minutes_remaining));
    lcd.print(" Min. remain");
    dbgi("if ( minutes_remaining > 0 )",minutes_remaining,200);
  } else {
    dbgi("else  ( minutes_remaining > 0 )",seconds_remaining,200);
    lcd.print(format_rj2(buf, seconds_remaining));
    lcd.print(" Sec. remain");
  }
  dbgi("timer_display_count()",operating_state,200);
  if ( operating_state == OST_EXPIRED1 ) {
    lcd.setCursor(0, 1); //Start at character 0 on line 0
    lcd.print("Expired");
    dbgi("if ( operating_state == OST_EXPIRED1 )",operating_state,200);
  }
}

/**
   Right-justified format of a 2-digit number
*/
static char* format_rj2(char* buf, int n) {
  if ( n > 99 ) { // limit range.
    n = n % 100;
  }
  buf[1] = (n % 10) + '0';
  buf[0] = (n / 10) + '0';
  buf[2] = 0;
  if ( buf[0] == '0') {
    buf[0] = ' '; // leading space
  }
  return buf;
}

//**** EEPROM ****

const int ee_addr0 = 0;

static void timer_save(int count) {
  EEPROM.update(ee_addr0, (count >> 8) & 0xff);
  EEPROM.update(ee_addr0 + 1, (count) & 0xff);
}

static int timer_load() {
  int val = EEPROM.read(ee_addr0) << 8;
  val |= EEPROM.read(ee_addr0 + 1);
  return val;
}

best regards Stefan

Thanks for that, ive never had much to do with serial debugging, so will give this a go.
In the end I figured out what to do and I was right that basically the code was working as intended and disabling the flasher, but the code was leaving it in whatever state the pin was, either high or low when executed.

I ended up adding the line

digitalWrite(LED_PIN, 0);

Which addressed the issue

I had been using

ledState = LOW;

but this doesnt work, perhaps the debugging will show why this line of code wasnt executing, but at least ive got it working now.

I really need to go over this code and make sure there is nothing else thats going to cause any issues, but so far, its looking good.