I think keypad.waitForKey is resetting my d1 Mini

Hello all.
I have a wemos d1 mini clone that I am sing for a small device. The code has bits from different parts of other code, and seems to work well all together.

My problem is that the d1 mini resets whenever the code reaches the keypad.waitForKey(), at least that's what I think is going on.
Whenever the code reaches a pause for a key press, it will reset after about 4 seconds.
Is this normal behavior for the keypad.waitForKey() function?

This is my code:

#include <Wire.h> 
#include <Keypad.h>
#include <LiquidCrystal_I2C.h>
#include <Adafruit_NeoPixel.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

char* menu1[]={"Domination", "Configuracion"};
char* menu2[]={"Tiempo de Juego", "Probar Relay"};

const int PIN = 0;
#define NUM_LEDS 10

const byte ROWS = 1; //four rows
const byte COLS = 3; //four columns
char keys[ROWS][COLS] = {
  {'u','d','c'}
 };
byte rowPins[ROWS] = {14}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {15, 13, 12}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800);

 //leds

//const int REDLED = 4;
//const int BLUELED = 3;

int GAMEMINUTES = 3;

boolean cancelando;
char var;
boolean defusing;

char BT_UP = 'u';
char BT_DOWN = 'd';
char BT_CANCEL = 'c';

boolean doStatus = false; //for DEmolition

int tonepin = 2; // Pin 9 for the sound
//const int RELAYPIN = 7;
int ACTIVATESECONDS = 3;

boolean endGame = false;
unsigned long redTime;
unsigned long blueTime;
unsigned long iZoneTime;//initial time for zone
byte team=0; // 0 = neutral, 1 = blue team, 2 = red team
unsigned long timeCalcVar;
boolean soundEnable = true;
int activeTone = 1330;
int alarmTone1 = 700;
int alarmTone2 = 2600;
boolean refresh=true;   //1 refresh one time...

void setup(){
  //PinModes
  //pinMode(BLUELED, OUTPUT);     
  //pinMode(REDLED, OUTPUT); 
  //pinMode(RELAYPIN, OUTPUT);  
  //pinMode(tonepin, OUTPUT);
    
  lcd.init();
  lcd.backlight();
  Serial.begin(9600);
  strip.begin();
  strip.show();
  lcd.setCursor(2,0);
  tone(tonepin,800,300);
  lcd.print("Programmable");// you can add your team name or someting cool
  lcd.setCursor(1,1);
  lcd.print("Airsoft Device");// you can add your team name or someting cool
  delay(1000);
  lcd.clear();
  lcd.setCursor(3,0); 
  tone(tonepin,2400,30); 
  lcd.print("Objetivo");// you can add your team name or someting cool
  lcd.setCursor(1,1);
  lcd.print("Dominable V2.0");// you can add your team name or someting cool
  delay(1000);
  keypad.setHoldTime(50);
  keypad.setDebounceTime(50);
  keypad.addEventListener(keypadEvent);

  //digitalWrite(RELAYPIN, HIGH);   //turn off power to relay channels
    
  // CONFIGURE THE BARS OF PROGRESS BAR
  byte bar1[8] = {
    B10000,
    B10000,
    B10000,
    B10000,
    B10000,
    B10000,
    B10000,
    B10000,
  };
  byte bar2[8] = {
    B11000,
    B11000,
    B11000,
    B11000,
    B11000,
    B11000,
    B11000,
    B11000,
  };
  byte bar3[8] = {
    B11100,
    B11100,
    B11100,
    B11100,
    B11100,
    B11100,
    B11100,
    B11100,
  };
  byte bar4[8] = {
    B11110,
    B11110,
    B11110,
    B11110,
    B11110,
    B11110,
    B11110,
    B11110,
  };
  byte bar5[8] = {
    B11111,
    B11111,
    B11111,
    B11111,
    B11111,
    B11111,
    B11111,
    B11111,
  };
  byte up[8] = {
    B00000,
    B00100,
    B01110,
    B11111,
    B11111,
    B00100,
    B00100,
  };
  byte down[8] = {
    B00100,
    B00100,
    B11111,
    B11111,
    B01110,
    B00100,
    B00000,
  };
  lcd.createChar(0,bar1);
  lcd.createChar(1,bar2);
  lcd.createChar(2,bar3);
  lcd.createChar(3,bar4);
  lcd.createChar(4,bar5);
  lcd.createChar(5,up);
  lcd.createChar(6,down);
}

void loop(){
   
  menuPrincipal();
}

//##################MENUS###############################

void menuPrincipal(){   //MAIN MENU
  
  //digitalWrite(BLUELED, LOW); 
  //digitalWrite(REDLED, LOW); 
  strip.show();

  //   if whe start a new game from another we need to restart propertly this variables
  doStatus=false;
  
  //Draw menu
  int i=0;
  
 // HERE YOU CAN ADD MORE ITEMS ON THE MAIN MENU
  
  cls(); 
  lcd.print(menu1[i]);
  lcd.setCursor(0,1);
  lcd.print(menu1[i+1]);
  lcd.setCursor(15,1);
  checkArrows(i,2);
  lcd.setCursor(15,0);
  checkArrows(i+1,1);
  delay(10);
  var = keypad.waitForKey();
  while(1){
    
    if(var == BT_UP && i >= 0){
      tone(tonepin,2400,30);
      cls();
      lcd.print(menu1[i]);
      delay(1000);
      cls();
      delay(500);
      lcd.print("one");
      delay(1000);
      cls();
      delay(500);
      lcd.print(menu1[i]);
      delay(1000);
      cls();
      delay(500);
      lcd.print("three");
      delay(500);
      doStatus=true;
      domination();
    }
    if(var == BT_DOWN && i<1){ 
      tone(tonepin,2400,30);
      i++;
      cls();
      lcd.print(menu1[i]);
      delay(1000);
      cls();
      delay(500);
      lcd.print("config 1");
      delay(1000);
      cls();
      delay(500);
      lcd.print("config2");
      delay(1000);
      cls();
      delay(500);
      lcd.print("config 3");
      delay(500);
      config();
    }
    yield();
 }
}

void keypadEvent(KeypadEvent key){
  switch (keypad.getState()){
    case RELEASED:
      switch (key){
         case 'u': defusing=false;
         break;
         case 'd': cancelando=false;
         break;
      }
    break;
    case HOLD:
      switch (key){
        case 'u': defusing= true;
        break;
        case 'd': cancelando=true;
        break;
      }
    break;
  }
}

void config(){
  //Draw menu
  lcd.clear();
  lcd.setCursor(0, 0);
  int i=0;
  
  //delay(500);
  lcd.print(menu2[i]);
  checkArrows(i+1,1);
  lcd.setCursor(0,1);
  lcd.print(menu2[i+1]);
  checkArrows(i,2);

  while(1){
    var=keypad.waitForKey();
    if(var == BT_UP && i>=0){
      tone(tonepin,2400,30);
      //i--;
      lcd.clear();  
      lcd.print(menu2[i]);
      delay(500);
      cls();
      delay(500);
      lcd.print(menu2[i]);
      delay(500);
      cls();
      delay(500);
      lcd.print(menu2[i]);
      delay(500);
      cls();
      delay(300);
      lcd.print(menu2[i]);
      delay(50);
      gameTimeMenu();
    }
    if(var == BT_DOWN && i<1){
      tone(tonepin,2400,30);
      i++;
      lcd.clear();  
      lcd.print(menu2[i]);
      //checkArrows(i,1);
      delay(300);
      lcd.print(menu2[i]);
      delay(300);
      lcd.print(menu2[i]);
      delay(300);
      lcd.print(menu2[i]);
      delay(50);
      relayTest();
    }
    if(var == BT_CANCEL){
      tone(tonepin,2400,30);
      cls();
      menuPrincipal();
      }
   }
   }

void relayTest(){ 
        cls();
        lcd.print("RELAYPIN ON!");
        //digitalWrite(RELAYPIN, LOW);   // turn the LED on (RELAY IS LOW TRIGGER)
        delay(1200);   // wait for 1.5 second
        cls();
        lcd.print("RELAYPIN OFF!");
        //digitalWrite(RELAYPIN, HIGH);
        delay(1200);
        config();
       }
    
  
void checkArrows(byte i,byte maxx ){

  if(i==0){
    lcd.setCursor(15,1);
    lcd.write(6); 
  }
  if(i==maxx){  
    lcd.setCursor(15,0);
    lcd.write(5);
  }
}

void gameTimeMenu () {
 
   cls();
   lcd.setCursor(1,0);
   lcd.print("Tiempo de Juego");
   lcd.setCursor(5,1);
   lcd.print(GAMEMINUTES);  
   lcd.println(" minutos  ");
   var = keypad.waitForKey();
   if(var == BT_UP) {
      tone(tonepin,2400,30);
      GAMEMINUTES++;
      lcd.setCursor(5,1);
      lcd.print(GAMEMINUTES); 
      delay(50);
      gameTimeMenu();
   }
    if(var == BT_DOWN){ 
      if(GAMEMINUTES > 0) {
   tone(tonepin,800,30);
   GAMEMINUTES--;
   lcd.setCursor(5,1);
   lcd.print(GAMEMINUTES); 
   delay(50);
   gameTimeMenu();
   }
   gameTimeMenu();
      }
    if(var == BT_CANCEL){
      tone(tonepin,2400,30);
      config();
     }
  }

void domination(){

  //SETUP INITIAL TIME 
  int minutos = GAMEMINUTES-1;
  boolean showGameTime=true;
  unsigned long a;
  unsigned long iTime=millis(); //  initialTime in millisec 
  unsigned long aTime;
 
  team=0;
  iZoneTime=0;
  aTime=0;
  redTime=0;
  blueTime=0;

  int largoTono = 50;
  // 0 = neutral, 1 = blue team, 2 = red team
  a=millis();
  //Starting Game Code
  while(1)  // this is the important code, is a little messy but works well.
  {
    if(endGame){
      gameOver();
    }
    
    keypad.getKey();
    aTime=millis()- iTime;
    //Code for led blinking
    timeCalcVar=(millis()- iTime)%1000;
    if(timeCalcVar >= 0 && timeCalcVar <= 40)
    {
      if(team==1){
        //digitalWrite(BLUELED, HIGH);
        RunningLights(0,0,0xff, 50); 
      }
      if(team==2){
        //digitalWrite(REDLED, HIGH);
        RunningLights(0xff,0,0, 50);  
      }
    }
    if(timeCalcVar >= 50 && timeCalcVar <= 100)
    {    
      //if(team==1)digitalWrite(BLUELED, LOW);  
      //if(team==2)digitalWrite(REDLED, LOW);
      strip.show();
    }
    // Sound!!! same as Destroy 
    if(timeCalcVar >= 0 && timeCalcVar <= 40 && soundEnable)tone(tonepin,activeTone,largoTono);

    if(timeCalcVar >= 245 && timeCalcVar <= 255 && minutos-aTime/60000<2 && soundEnable)tone(tonepin,activeTone,largoTono);
    if(timeCalcVar >= 495 && timeCalcVar <= 510 && minutos-aTime/60000<4 && soundEnable)tone(tonepin,activeTone,largoTono);
    if(timeCalcVar >= 745 && timeCalcVar <= 760 && minutos-aTime/60000<2 && soundEnable)tone(tonepin,activeTone,largoTono);
    //Help to count 3 secs
    if(a+2000<millis()){
      a=millis();   
      showGameTime=!showGameTime;
      cls();
    }
    //THE NEXT TWO METHODS SHOW "GAME TIME" AND "CONTROLED ZONE TIME" IT SHOWS 2 AND 2 SEC EACH

    if(showGameTime){ //THE SECOND IS /2
      lcd.setCursor(0,0);
      lcd.print("TIEMPO DE JUEGO");
      lcd.setCursor(3,1);
      printTime(minutos, aTime);
    }
    else if (!showGameTime){

      lcd.setCursor(2,0);
      if(team == 0)lcd.print("Zona Neutral");
      if(team == 1)lcd.print(" Zona AZUL");
      if(team == 2)lcd.print(" Zona ROJA");

      if(team>0){
        lcd.setCursor(3,1);
        printTimeDom(millis()-iZoneTime,true);
      }
    }

    //###########################CHECKINGS##################

    //Check If Game End
    if(minutos-aTime/60000==0 && 59-((aTime/1000)%60)==0)
    {
      gameOver();
    }

    //Check If IS neutral
    while((defusing || cancelando) && team > 0)
    {
      cls();
      if(team>0)lcd.print("Neutralizando...");
      lcd.setCursor(0,1);
      unsigned int percent=0;
      unsigned long xTime=millis(); //start disabling time
      while(defusing || cancelando)
      {
        //check if game time runs out during the disabling
        aTime= millis()- iTime;
        if((minutos-aTime/60000==0 && 59-((aTime/1000)%60)==0) || minutos-aTime/60000>4000000000){ 
          endGame = true;
        }
        
        keypad.getKey();
        timeCalcVar = (millis()- xTime)%1000;

        if( timeCalcVar >= 0 && timeCalcVar <= 20)
        {
          if(soundEnable)tone(tonepin,alarmTone1,200);
        }
        if(timeCalcVar >= 480 && timeCalcVar <= 500)
        {
          if(soundEnable)tone(tonepin,alarmTone2,200);
          //digitalWrite(REDLED, LOW);
          strip.show();
        }

        unsigned long seconds= millis() - xTime;
        percent = (seconds)/(ACTIVATESECONDS*10);
        drawBar(percent);

        if(percent >= 100)
        {
          delay(1000);

          if(team==1){ 
            blueTime+=millis()-iZoneTime;
            iZoneTime=0; 

          }
          if(team==2){ 
            redTime+=millis()-iZoneTime;
            iZoneTime=0; 
          }
          team=0;
          break;
        }
      }
      cls();
    }

    //Capturing red

    while(defusing && team == 0 )
    {
      cls();
      if(team==0)lcd.print("Capturando Zona");
      lcd.setCursor(0,1);
      unsigned int percent=0;
      unsigned long xTime=millis(); //start disabling time
      while(defusing)
      {
        keypad.getKey();
        //check if game time runs out during the disabling
        aTime= millis()- iTime;
        if((minutos-aTime/60000==0 && 59-((aTime/1000)%60)==0) || minutos-aTime/60000>4000000000){ 
          endGame = true;
        }
        timeCalcVar = (millis()- xTime)%1000;

        if( timeCalcVar >= 0 && timeCalcVar <= 20)
        {
          //digitalWrite(REDLED, HIGH); 
          RunningLights(0xff,0,0, 50); 
          if(soundEnable)tone(tonepin,alarmTone1,200);
        }
        if(timeCalcVar >= 480 && timeCalcVar <= 500)
        {
          if(soundEnable)tone(tonepin,alarmTone2,200);
          //digitalWrite(REDLED, LOW);
          strip.show();
        }

        unsigned long seconds= millis() - xTime;
        percent = (seconds)/(ACTIVATESECONDS*10);
        drawBar(percent);

        if(percent >= 100)
        {
          //digitalWrite(BLUELED, LOW);
          strip.show();
          team=2;
          iZoneTime=millis();
          delay(1000);
          break;
        }
      }
      cls();
      //digitalWrite(REDLED, LOW);
      strip.show();
    }

    //getting to blue zone
    while(cancelando && team == 0 )
    {
      cls();
      if(team==0)lcd.print("Capturando Zona");
      lcd.setCursor(0,1);
      unsigned int percent=0;
      unsigned long xTime=millis(); //start disabling time
      while(cancelando)
      {
        keypad.getKey();
        //check if game time runs out during the disabling
        aTime= millis()- iTime;
        if((minutos-aTime/60000==0 && 59-((aTime/1000)%60)==0) || minutos-aTime/60000>4000000000){ 
          endGame = true;
        }
        timeCalcVar = (millis()- xTime)%1000;

        if( timeCalcVar >= 0 && timeCalcVar <= 20)
        {
          //digitalWrite(BLUELED, HIGH); 
          RunningLights(0,0,0xff, 50);  
          if(soundEnable)tone(tonepin,alarmTone1,200);
        }
        if(timeCalcVar >= 480 && timeCalcVar <= 500)
        {
          if(soundEnable)tone(tonepin,alarmTone2,200);
          //digitalWrite(BLUELED, LOW);
          strip.show();
        }

        unsigned long seconds= millis() - xTime;
        percent = (seconds)/(ACTIVATESECONDS*10);
        drawBar(percent);

        if(percent >= 100)
        {
          //digitalWrite(BLUELED, LOW);
          strip.show();
          team=1;
          iZoneTime=millis();
          delay(1000);
          break;
        }
      }
      cls();
      //digitalWrite(BLUELED, LOW);  
      strip.show();
    }
  }
}

void printTime(unsigned long minutos, unsigned long aTiempo){

  timeCalcVar=minutos-aTiempo/60000;
  //Hours
  
  if(timeCalcVar/60==0 && refresh){
      lcd.clear();
      refresh=false;
      //delay(100);
      lcd.setCursor(3,1);
      Serial.println("!!!!");
  }
   
  if(timeCalcVar/60>=1){
    
    if(timeCalcVar/60<10)
  {
    lcd.setCursor(2,1);
    lcd.print("0");
    lcd.print(timeCalcVar/60);
  }
  else
  {
    lcd.print(timeCalcVar/60);
  }
  
  lcd.print(":");
  
  }
  //minutes
  if(timeCalcVar%60<10)
  {
    lcd.print("0");
    lcd.print(timeCalcVar%60);
  }
  else
  {
    lcd.print(timeCalcVar%60);
  }
  lcd.print(":");
  //seconds
  timeCalcVar=aTiempo/1000;
  if(59-(timeCalcVar%60)<10)
  {
    lcd.print("0");
    lcd.print(59-(timeCalcVar%60));
  }
  else
  {
    lcd.print(59-(timeCalcVar%60));
  }
  lcd.print(":");
  //this not mach with real time, is just a effect, it says 999 because millis%1000 sometimes give 0 LOL
  lcd.print(999-(millis()%1000));
}

void RunningLights(byte red, byte green, byte blue, int WaveDelay) {
  int Position=0;
  for(int j=0; j<NUM_LEDS*2; j++)
  {
      Position++; // = 0; //Position + Rate;
      for(int i=0; i<NUM_LEDS; i++) {
   setPixel(i,((sin(i+Position) * 127 + 128)/255)*red,
      ((sin(i+Position) * 127 + 128)/255)*green,
                  ((sin(i+Position) * 127 + 128)/255)*blue);
      }
     
      showStrip();
      delay(WaveDelay);
  }
}

void showStrip() {
   strip.show();
}

void setPixel(int Pixel, byte red, byte green, byte blue) {
   strip.setPixelColor(Pixel, strip.Color(red, green, blue));
}

void gameOver(){

  if(team==1)blueTime+=millis()-iZoneTime;
  if(team==2)redTime+=millis()-iZoneTime;
  //digitalWrite(BLUELED, LOW);
  //digitalWrite(REDLED, LOW);
  strip.show();
  while(!defusing){
    keypad.getKey();
    if(defusing){
      keypad.getKey();
      break;
    }
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("TIEMPO ACABADO!");
    lcd.setCursor(1,1);

    //check who team win the base
    if(blueTime>redTime){
      //blueteam wins
      lcd.print("AZULES GANAN");
      //digitalWrite(BLUELED, HIGH);
      RunningLights(0,0,0xff, 50);
    }
    else{
      //redteam wins 
      lcd.print(" ROJOS GANAN");
      //digitalWrite(REDLED, HIGH);
      RunningLights(0xff,0,0, 50);
    }
    delay(2000);
    keypad.getKey();
    if(defusing){
      keypad.getKey();
      break;
    }
    cls();
    lcd.print("Tiempo ROJO:");
    lcd.setCursor(5,1);
    printTimeDom(redTime,false);
    delay(3000);
    keypad.getKey();
    if(defusing){
      keypad.getKey();
      break;
    }
    cls();
    lcd.print("Tiempo AZUL:");
    lcd.setCursor(5,1);
    printTimeDom(blueTime,false);
    delay(2000);
    keypad.getKey();
    if(defusing){
      keypad.getKey();
      break;
    }
  }
  cls();
  delay(100);
  lcd.print("Jugar Otra Vez?");
  lcd.setCursor(0,1);
  lcd.print("UP: Si   CAN: No");
  while(1)
  {
    var = keypad.waitForKey();
    if(var == 'u' ){
      tone(tonepin,2400,30);
      cls();
      domination();
      break;
    }  
    if(var == 'c' ){
      tone(tonepin,2400,30);
      cls();
      menuPrincipal();
      break;
    }  
  } 
}
void printTimeDom(unsigned long aTiempo, boolean showMillis){
  //minutes
  if((aTiempo/60000)<10)
  {
    lcd.print("0");
    lcd.print(aTiempo/60000);
  }
  else
  {
    lcd.print(aTiempo/60000);
  }
  lcd.print(":");
  //seconds
  if(((aTiempo/1000)%60)<10)
  {
    lcd.print("0");
    lcd.print((aTiempo/1000)%60);
  }
  else
  {
    lcd.print((aTiempo/1000)%60);
  }
  if(showMillis){
    lcd.print(":");
    //this not mach with real time, is just a effect, it says 999 because millis%1000 sometimes give 0 LOL
      lcd.print(999-millis()%1000);

  }
}

void drawBar(byte porcent){
 
  int box=(8*porcent)/10;
  lcd.setCursor(0,1);
  while(box>=5){
    if(box>=5)
    {
      lcd.write(4);
      box-=5;
    }
  }
    switch(box){
    case 0:
      break;
    case 1:
      lcd.write((uint8_t)0);
      break;
    case 2:
      lcd.write(1);
      break;
    case 3:
      lcd.write(2);
      break;
    case 4:
      lcd.write(3);
      break;
    }
}

void cls(){
  lcd.clear();
  lcd.setCursor(0,0);
}

I appreciate any help you can offer. Thanks in advance

This is likely normal for an ESP. If you look at the error message, you will probably find "rst cause:4" (if I am right).

I have never worked with the library containing a waitForKey function, but the word "wait" raises a red flag. "rst cause:4" means a watchdog timer reset. You will get this anytime the watchdog timer is not reset in a couple of seconds (I forget the exact timeout). The ESP is designed to be used in consumer IOT devices and the WDT is a failsafe for those.

Again, if I am right, the wait function in the library contains blocking code which means the loop() function is not, well, looping. (When the loop() function starts, the WDT timer is reset). A while() statement is blocking code and will cause a WDT timeout on an ESP.

The solution- if I am right- is to find the blocking code in the library and add a yield(); statement. This will reset the WDT.

If your rst cause is not 4, then ignore everything I just said.

void loop(){
   
  menuPrincipal();
}

//##################MENUS###############################

void menuPrincipal(){   //MAIN MENU
  
  //digitalWrite(BLUELED, LOW); 
  //digitalWrite(REDLED, LOW); 
  strip.show();

  //   if whe start a new game from another we need to restart propertly this variables
  doStatus=false;
  
  //Draw menu
  int i=0;
  
 // HERE YOU CAN ADD MORE ITEMS ON THE MAIN MENU
  
  cls(); 
  lcd.print(menu1[i]);
  lcd.setCursor(0,1);
  lcd.print(menu1[i+1]);
  lcd.setCursor(15,1);
  checkArrows(i,2);
  lcd.setCursor(15,0);
  checkArrows(i+1,1);
  delay(10);
  waitforKey();
  while(1){
    
    if(var == BT_UP && i >= 0){
      tone(tonepin,2400,30);
      cls();
      lcd.print(menu1[i]);
      delay(1000);
      cls();
      delay(500);
      lcd.print("one");
      delay(1000);
      cls();
      delay(500);
      lcd.print(menu1[i]);
      delay(1000);
      cls();
      delay(500);
      lcd.print("three");
      delay(500);
      doStatus=true;
      domination();
    }
    if(var == BT_DOWN && i<1){ 
      tone(tonepin,2400,30);
      i++;
      cls();
      lcd.print(menu1[i]);
      delay(1000);
      cls();
      delay(500);
      lcd.print("config 1");
      delay(1000);
      cls();
      delay(500);
      lcd.print("config2");
      delay(1000);
      cls();
      delay(500);
      lcd.print("config 3");
      delay(500);
      config();
    }
    yield();
 }
}

void keypadEvent(KeypadEvent key){
  switch (keypad.getState()){
    case RELEASED:
      switch (key){
         case 'u': defusing=false;
         break;
         case 'd': cancelando=false;
         break;
      }
    break;
    case HOLD:
      switch (key){
        case 'u': defusing= true;
        break;
        case 'd': cancelando=true;
        break;
      }
    break;
  }
}

void config(){
  //Draw menu
  lcd.clear();
  lcd.setCursor(0, 0);
  int i=0;
  
  //delay(500);
  lcd.print(menu2[i]);
  checkArrows(i+1,1);
  lcd.setCursor(0,1);
  lcd.print(menu2[i+1]);
  checkArrows(i,2);

  while(1){
    waitforKey();
    if(var == BT_UP && i>=0){
      tone(tonepin,2400,30);
      //i--;
      lcd.clear();  
      lcd.print(menu2[i]);
      delay(500);
      cls();
      delay(500);
      lcd.print(menu2[i]);
      delay(500);
      cls();
      delay(500);
      lcd.print(menu2[i]);
      delay(500);
      cls();
      delay(300);
      lcd.print(menu2[i]);
      delay(50);
      gameTimeMenu();
    }
    if(var == BT_DOWN && i<1){
      tone(tonepin,2400,30);
      i++;
      lcd.clear();  
      lcd.print(menu2[i]);
      //checkArrows(i,1);
      delay(300);
      lcd.print(menu2[i]);
      delay(300);
      lcd.print(menu2[i]);
      delay(300);
      lcd.print(menu2[i]);
      delay(50);
      relayTest();
    }
    if(var == BT_CANCEL){
      tone(tonepin,2400,30);
      cls();
      menuPrincipal();
      }
   }
   }

void relayTest(){ 
        cls();
        lcd.print("RELAYPIN ON!");
        //digitalWrite(RELAYPIN, LOW);   // turn the LED on (RELAY IS LOW TRIGGER)
        delay(1200);   // wait for 1.5 second
        cls();
        lcd.print("RELAYPIN OFF!");
        //digitalWrite(RELAYPIN, HIGH);
        delay(1200);
        config();
       }
    
  
void checkArrows(byte i,byte maxx ){

  if(i==0){
    lcd.setCursor(15,1);
    lcd.write(6); 
  }
  if(i==maxx){  
    lcd.setCursor(15,0);
    lcd.write(5);
  }
}

void gameTimeMenu () {
 
   cls();
   lcd.setCursor(1,0);
   lcd.print("Tiempo de Juego");
   lcd.setCursor(5,1);
   lcd.print(GAMEMINUTES);  
   lcd.println(" minutos  ");
   waitforKey();
   if(var == BT_UP) {
      tone(tonepin,2400,30);
      GAMEMINUTES++;
      lcd.setCursor(5,1);
      lcd.print(GAMEMINUTES); 
      delay(50);
      gameTimeMenu();
   }
    if(var == BT_DOWN){ 
      if(GAMEMINUTES > 0) {
   tone(tonepin,800,30);
   GAMEMINUTES--;
   lcd.setCursor(5,1);
   lcd.print(GAMEMINUTES); 
   delay(50);
   gameTimeMenu();
   }
   gameTimeMenu();
      }
    if(var == BT_CANCEL){
      tone(tonepin,2400,30);
      config();
     }
  }

void domination(){

  //SETUP INITIAL TIME 
  int minutos = GAMEMINUTES-1;
  boolean showGameTime=true;
  unsigned long a;
  unsigned long iTime=millis(); //  initialTime in millisec 
  unsigned long aTime;
 
  team=0;
  iZoneTime=0;
  aTime=0;
  redTime=0;
  blueTime=0;

  int largoTono = 50;
  // 0 = neutral, 1 = blue team, 2 = red team
  a=millis();
  //Starting Game Code
  while(1)  // this is the important code, is a little messy but works well.
  {
    if(endGame){
      gameOver();
    }
    
    keypad.getKey();
    aTime=millis()- iTime;
    //Code for led blinking
    timeCalcVar=(millis()- iTime)%1000;
    if(timeCalcVar >= 0 && timeCalcVar <= 40)
    {
      if(team==1){
        //digitalWrite(BLUELED, HIGH);
        RunningLights(0,0,0xff, 50); 
      }
      if(team==2){
        //digitalWrite(REDLED, HIGH);
        RunningLights(0xff,0,0, 50);  
      }
    }
    if(timeCalcVar >= 50 && timeCalcVar <= 100)
    {    
      //if(team==1)digitalWrite(BLUELED, LOW);  
      //if(team==2)digitalWrite(REDLED, LOW);
      strip.show();
    }
    // Sound!!! same as Destroy 
    if(timeCalcVar >= 0 && timeCalcVar <= 40 && soundEnable)tone(tonepin,activeTone,largoTono);

    if(timeCalcVar >= 245 && timeCalcVar <= 255 && minutos-aTime/60000<2 && soundEnable)tone(tonepin,activeTone,largoTono);
    if(timeCalcVar >= 495 && timeCalcVar <= 510 && minutos-aTime/60000<4 && soundEnable)tone(tonepin,activeTone,largoTono);
    if(timeCalcVar >= 745 && timeCalcVar <= 760 && minutos-aTime/60000<2 && soundEnable)tone(tonepin,activeTone,largoTono);
    //Help to count 3 secs
    if(a+2000<millis()){
      a=millis();   
      showGameTime=!showGameTime;
      cls();
    }
    //THE NEXT TWO METHODS SHOW "GAME TIME" AND "CONTROLED ZONE TIME" IT SHOWS 2 AND 2 SEC EACH

    if(showGameTime){ //THE SECOND IS /2
      lcd.setCursor(0,0);
      lcd.print("TIEMPO DE JUEGO");
      lcd.setCursor(3,1);
      printTime(minutos, aTime);
    }
    else if (!showGameTime){

      lcd.setCursor(2,0);
      if(team == 0)lcd.print("Zona Neutral");
      if(team == 1)lcd.print(" Zona AZUL");
      if(team == 2)lcd.print(" Zona ROJA");

      if(team>0){
        lcd.setCursor(3,1);
        printTimeDom(millis()-iZoneTime,true);
      }
    }

    //###########################CHECKINGS##################

    //Check If Game End
    if(minutos-aTime/60000==0 && 59-((aTime/1000)%60)==0)
    {
      gameOver();
    }

    //Check If IS neutral
    while((defusing || cancelando) && team > 0)
    {
      cls();
      if(team>0)lcd.print("Neutralizando...");
      lcd.setCursor(0,1);
      unsigned int percent=0;
      unsigned long xTime=millis(); //start disabling time
      while(defusing || cancelando)
      {
        //check if game time runs out during the disabling
        aTime= millis()- iTime;
        if((minutos-aTime/60000==0 && 59-((aTime/1000)%60)==0) || minutos-aTime/60000>4000000000){ 
          endGame = true;
        }
        
        keypad.getKey();
        timeCalcVar = (millis()- xTime)%1000;

        if( timeCalcVar >= 0 && timeCalcVar <= 20)
        {
          if(soundEnable)tone(tonepin,alarmTone1,200);
        }
        if(timeCalcVar >= 480 && timeCalcVar <= 500)
        {
          if(soundEnable)tone(tonepin,alarmTone2,200);
          //digitalWrite(REDLED, LOW);
          strip.show();
        }

        unsigned long seconds= millis() - xTime;
        percent = (seconds)/(ACTIVATESECONDS*10);
        drawBar(percent);

        if(percent >= 100)
        {
          delay(1000);

          if(team==1){ 
            blueTime+=millis()-iZoneTime;
            iZoneTime=0; 

          }
          if(team==2){ 
            redTime+=millis()-iZoneTime;
            iZoneTime=0; 
          }
          team=0;
          break;
        }
      }
      cls();
    }

    //Capturing red

    while(defusing && team == 0 )
    {
      cls();
      if(team==0)lcd.print("Capturando Zona");
      lcd.setCursor(0,1);
      unsigned int percent=0;
      unsigned long xTime=millis(); //start disabling time
      while(defusing)
      {
        keypad.getKey();
        //check if game time runs out during the disabling
        aTime= millis()- iTime;
        if((minutos-aTime/60000==0 && 59-((aTime/1000)%60)==0) || minutos-aTime/60000>4000000000){ 
          endGame = true;
        }
        timeCalcVar = (millis()- xTime)%1000;

        if( timeCalcVar >= 0 && timeCalcVar <= 20)
        {
          //digitalWrite(REDLED, HIGH); 
          RunningLights(0xff,0,0, 50); 
          if(soundEnable)tone(tonepin,alarmTone1,200);
        }
        if(timeCalcVar >= 480 && timeCalcVar <= 500)
        {
          if(soundEnable)tone(tonepin,alarmTone2,200);
          //digitalWrite(REDLED, LOW);
          strip.show();
        }

        unsigned long seconds= millis() - xTime;
        percent = (seconds)/(ACTIVATESECONDS*10);
        drawBar(percent);

        if(percent >= 100)
        {
          //digitalWrite(BLUELED, LOW);
          strip.show();
          team=2;
          iZoneTime=millis();
          delay(1000);
          break;
        }
      }
      cls();
      //digitalWrite(REDLED, LOW);
      strip.show();
    }

    //getting to blue zone
    while(cancelando && team == 0 )
    {
      cls();
      if(team==0)lcd.print("Capturando Zona");
      lcd.setCursor(0,1);
      unsigned int percent=0;
      unsigned long xTime=millis(); //start disabling time
      while(cancelando)
      {
        keypad.getKey();
        //check if game time runs out during the disabling
        aTime= millis()- iTime;
        if((minutos-aTime/60000==0 && 59-((aTime/1000)%60)==0) || minutos-aTime/60000>4000000000){ 
          endGame = true;
        }
        timeCalcVar = (millis()- xTime)%1000;

        if( timeCalcVar >= 0 && timeCalcVar <= 20)
        {
          //digitalWrite(BLUELED, HIGH); 
          RunningLights(0,0,0xff, 50);  
          if(soundEnable)tone(tonepin,alarmTone1,200);
        }
        if(timeCalcVar >= 480 && timeCalcVar <= 500)
        {
          if(soundEnable)tone(tonepin,alarmTone2,200);
          //digitalWrite(BLUELED, LOW);
          strip.show();
        }

        unsigned long seconds= millis() - xTime;
        percent = (seconds)/(ACTIVATESECONDS*10);
        drawBar(percent);

        if(percent >= 100)
        {
          //digitalWrite(BLUELED, LOW);
          strip.show();
          team=1;
          iZoneTime=millis();
          delay(1000);
          break;
        }
      }
      cls();
      //digitalWrite(BLUELED, LOW);  
      strip.show();
    }
  }
}

void printTime(unsigned long minutos, unsigned long aTiempo){

  timeCalcVar=minutos-aTiempo/60000;
  //Hours
  
  if(timeCalcVar/60==0 && refresh){
      lcd.clear();
      refresh=false;
      //delay(100);
      lcd.setCursor(3,1);
      Serial.println("!!!!");
  }
   
  if(timeCalcVar/60>=1){
    
    if(timeCalcVar/60<10)
  {
    lcd.setCursor(2,1);
    lcd.print("0");
    lcd.print(timeCalcVar/60);
  }
  else
  {
    lcd.print(timeCalcVar/60);
  }
  
  lcd.print(":");
  
  }
  //minutes
  if(timeCalcVar%60<10)
  {
    lcd.print("0");
    lcd.print(timeCalcVar%60);
  }
  else
  {
    lcd.print(timeCalcVar%60);
  }
  lcd.print(":");
  //seconds
  timeCalcVar=aTiempo/1000;
  if(59-(timeCalcVar%60)<10)
  {
    lcd.print("0");
    lcd.print(59-(timeCalcVar%60));
  }
  else
  {
    lcd.print(59-(timeCalcVar%60));
  }
  lcd.print(":");
  //this not mach with real time, is just a effect, it says 999 because millis%1000 sometimes give 0 LOL
  lcd.print(999-(millis()%1000));
}

void RunningLights(byte red, byte green, byte blue, int WaveDelay) {
  int Position=0;
  for(int j=0; j<NUM_LEDS*2; j++)
  {
      Position++; // = 0; //Position + Rate;
      for(int i=0; i<NUM_LEDS; i++) {
   setPixel(i,((sin(i+Position) * 127 + 128)/255)*red,
      ((sin(i+Position) * 127 + 128)/255)*green,
                  ((sin(i+Position) * 127 + 128)/255)*blue);
      }
     
      showStrip();
      delay(WaveDelay);
  }
}

void showStrip() {
   strip.show();
}

void setPixel(int Pixel, byte red, byte green, byte blue) {
   strip.setPixelColor(Pixel, strip.Color(red, green, blue));
}

void gameOver(){

  if(team==1)blueTime+=millis()-iZoneTime;
  if(team==2)redTime+=millis()-iZoneTime;
  //digitalWrite(BLUELED, LOW);
  //digitalWrite(REDLED, LOW);
  strip.show();
  while(!defusing){
    keypad.getKey();
    if(defusing){
      keypad.getKey();
      break;
    }
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("TIEMPO ACABADO!");
    lcd.setCursor(1,1);

    //check who team win the base
    if(blueTime>redTime){
      //blueteam wins
      lcd.print("AZULES GANAN");
      //digitalWrite(BLUELED, HIGH);
      RunningLights(0,0,0xff, 50);
    }
    else{
      //redteam wins 
      lcd.print(" ROJOS GANAN");
      //digitalWrite(REDLED, HIGH);
      RunningLights(0xff,0,0, 50);
    }
    delay(2000);
    keypad.getKey();
    if(defusing){
      keypad.getKey();
      break;
    }
    cls();
    lcd.print("Tiempo ROJO:");
    lcd.setCursor(5,1);
    printTimeDom(redTime,false);
    delay(3000);
    keypad.getKey();
    if(defusing){
      keypad.getKey();
      break;
    }
    cls();
    lcd.print("Tiempo AZUL:");
    lcd.setCursor(5,1);
    printTimeDom(blueTime,false);
    delay(2000);
    keypad.getKey();
    if(defusing){
      keypad.getKey();
      break;
    }
  }
  cls();
  delay(100);
  lcd.print("Jugar Otra Vez?");
  lcd.setCursor(0,1);
  lcd.print("UP: Si   CAN: No");
  while(1)
  {
    waitforKey();
    if(var == 'u' ){
      tone(tonepin,2400,30);
      cls();
      domination();
      break;
    }  
    if(var == 'c' ){
      tone(tonepin,2400,30);
      cls();
      menuPrincipal();
      break;
    }  
  } 
}
void printTimeDom(unsigned long aTiempo, boolean showMillis){
  //minutes
  if((aTiempo/60000)<10)
  {
    lcd.print("0");
    lcd.print(aTiempo/60000);
  }
  else
  {
    lcd.print(aTiempo/60000);
  }
  lcd.print(":");
  //seconds
  if(((aTiempo/1000)%60)<10)
  {
    lcd.print("0");
    lcd.print((aTiempo/1000)%60);
  }
  else
  {
    lcd.print((aTiempo/1000)%60);
  }
  if(showMillis){
    lcd.print(":");
    //this not mach with real time, is just a effect, it says 999 because millis%1000 sometimes give 0 LOL
      lcd.print(999-millis()%1000);

  }
}

void drawBar(byte porcent){
 
  int box=(8*porcent)/10;
  lcd.setCursor(0,1);
  while(box>=5){
    if(box>=5)
    {
      lcd.write(4);
      box-=5;
    }
  }
    switch(box){
    case 0:
      break;
    case 1:
      lcd.write((uint8_t)0);
      break;
    case 2:
      lcd.write(1);
      break;
    case 3:
      lcd.write(2);
      break;
    case 4:
      lcd.write(3);
      break;
    }
}

void cls(){
  lcd.clear();
  lcd.setCursor(0,0);
}

void waitforKey ()
{
  yield();
  var = keypad.waitForKey();
}

Hi. Steve. Thanks for the reply.

Where can I find this information?

I tried a yield() after the first use of waitForKey() with no success. Maybe I have to put it somewhere else?

Hi Pancake.

I see you changed

for just

Is there a specific reason for this, or is it just simbolic? I am not quite clear on all the structure of the keypad library.

There were several instances, so I made that function.
No joy?
If not, then that yield() might have to be placed in the 'keypad' CPP

void waitforKey ()
{
  yield();
  var = keypad.waitForKey();
}

You have to edit the library and put the yield(); INSIDE of the blocking code.

Do you have a serial monitor open?

:cake:

https://github.com/Chris--A/Keypad/blob/master/src/Keypad.cpp

char Keypad::waitForKey() {
	char waitKey = NO_KEY;
	while( (waitKey = getKey()) == NO_KEY );	// Block everything while waiting for a keypress.
	return waitKey;
}     //  <  <  <

PE - end brace was missing.

Try this:

do{
  yield();
  waitKey = getKey()
} while (waitKey == NO_KEY
return waitKey;

If this fixes the problem, you might want to post a suggestion to the library maintainer.

Ugh! I missed seeing the function at the very end of the code! Let me try it out and see what happens.

Was not aware of this feature in the IDE. Did some googleing and found how to enable it.
My serial monitor actually shows: "ets Jan 8 2013,rst cause:2, boot mode:(3,6)"

Edit: I don't mean the serial monitor, that I was aware of. I meant the reset causes and exceptions text.

Tried this, didn't work.

Tried modifying the keypad.cpp but that didn't work either.

Where would I put this, in the library or in my sketch code?

PE: Had to delete several replies I made one after another, and put them all into a single reply. My apologies, for the noob mistakes

How did you modify the library? The original looks like this:

char Keypad::waitForKey() {
  char waitKey = NO_KEY;
  while( (waitKey = getKey()) == NO_KEY );  // Block everything while waiting for a keypress.
  return waitKey;
}

Changing the while statement should solve the problem:

  while ( (waitKey = getKey()) == NO_KEY ) yield(); // Block everything while waiting for a keypress.

"The body of a while can be one or more statements enclosed in braces,... or a single statement without braces".
-- K & R

char Keypad::waitForKey() {
	char waitKey = NO_KEY;
	while( (waitKey = getKey()) == NO_KEY )
     yield();
	return waitKey;
}  

Looks off though. (That's just me.)
Assuming this works, it will not compile in non-ESP applications.

Library does not appear to be actively maintained, there was a pull request for this issue in mid-2017.
https://github.com/Chris--A/Keypad/pull/14

The pull request used delay(0) instead of yield(), probably for that reason. delay() on an ESP8266 calls yield().

The conditional statement is a bit unusual. waitKey is set to the return value of getKey(), then is compared to NO_KEY. The original code has no body as such.

I used notepad++ to edit the .cpp file and modified the waitforKey function in the file with the yield() command, as you and @runaway_pancake suggested.
still wouldn't work.
Then I realized I was uploading to the esp my old code, not the one I fixed with @runaway_pancake waitforKey function. Uploaded that code and it finally works! Don't quite understand why it only works with the function, though.
Thankyou all for your help.

ESP is not as carefree as straight-up Arduino (they took care of that/this for you).
If your ESP doesn't make loop progress in approx. 2.5msec then it will watchdog.
(If your sketch goes into a long delay, it will not watchdog.)
If you have a millis-based wait-for-it then you need yield() to relieve that.
Anytime you wait, as with your example, until no-matter-what, you need a yield() there too.

You do need to be careful when editing library files. When compiling code the IDE caches the compiled library code, so that it only has to be compiled once instead of every time you re-compile the sketch. Closing and re-opening the IDE, or changing Tools > Board to another board, compiling, and then switching back to the ESP8266 will force recompilation of the libraries.

How easy would it be to rename the modified library as ESPkeypad ?
(There are probably a couple of bear-traps in there.)

Probably best to implement the function in the code itself, relying on a modified library will come back to haunt you later when you cannot figure out why the code will not work when compiled on another computer.

The actual watchdog timeout is 3.2 seconds.

The delay() function does call yield() every millisecond, so delay(0) should also work. I've never tried it.

Basically, you need yield() anytime the program flow doesn't get back to the top of the loop() every three seconds.