Timer event quits!

SOLVED: I could remove this topic as no one answered, but ill leave it in case someone has use for it.
The mistake I made was reuse an old global variable (boolean) noise as timer ID and not check its initialization. which was 0. Noise was initially set to 0 and after 5s a function was called that chained other functions that lead to the deletion of the noise timer…which happened to have the same ID as the checkbuttons (=0). Why this didn’t fail earlier I don’t understand, but it was a mistake on my side.

This took me a frikking age to debug. I initially had a working test setup and then start building the thing and it simply didn’t work, that is the button press event was not detected. After hours of testing and debugging I finally found out that the timer event simply quit as soon as I pressed the button. Fot no apparent reason (there is no timer destruction event).

There might be something in my code which is odd, so let me know please. Especially how to fix this. Or perhaps a bug in the timer event…

Below the full code. Note that the section in the loop() section is for testing purposes only.

Below is the log:
What you see is that the button check event is called every 500ms, then I hit the button after a few seconds, keep it pressed for roughly a second…and then nothing happens anymore. That is, the button check event is cancelled for no apparent reason. Note that this ALSO happens WITHOUT the ‘button pressed’ section in the loop(). I’ve just put it there to make very clear in this post what is happening.

edit: did some more tests, below a different version where the eventbutton ran twice more and then quit. Still no clue

edit2: ok but further: the checkbuttons event is executed 10 times (so 5s) in this case and then its cancelled… Why?!? This is concistent after testing this several times.

edit3: and more testing. It turned out to be specifically 5s not 10 times after I changed the interval. Which happens to be the same amount as

timer.setTimer(5000L, resetMessage, 1);

after changing that to 10000L, the interval indeed quit after 10s

[9811] Connecting to blynk-cloud.com:80
[9915] Ready (ping: 33ms).
[9986]
___ __ __
/ _ )/ /_ _____ / /__
/ _ / / // / _ / '/
/
//_, /////_
/
__/ WOLPH42 CODED

CHECK BUTTONS.
CHECK BUTTONS.
CHECK BUTTONS.
CHECK BUTTONS.
CHECK BUTTONS.
CHECK BUTTONS.
CHECK BUTTONS.
button has been pressed!!!.
button has been pressed!!!.
button has been pressed!!!.
button has been pressed!!!.
button has been pressed!!!.
button has been pressed!!!.
button has been pressed!!!.
button has been pressed!!!.
button has been pressed!!!.
button has been pressed!!!.
button has been pressed!!!.
button has been pressed!!!.
CHECK BUTTONS.
button has been pressed.
Button is relieved.
CHECK BUTTONS.
Button is pressed.

#define BLYNK_PRINT Serial                        // used by Blynk
#include <BlynkSimpleEsp8266.h>                   // ESP8266
#include <U8g2lib.h>                              // OLED

//definitions
#define V_MENU V0
#define V_TEXT V1
#define V_SEND V2
#define V_RCVD V3
#define V_ANOY V4
#define V_TERM V10

#define BLYNK_GREEN "#23C48E" 
#define WHITE "#FFFFFF" 
#define TRUE 1
#define FALSE 0

// constants
const int XS = 0;                                 // starting position for first line
const int YS = 8;                                 // starting position for first line
const int YDIV = 9;                               // the height of a line in pixels +1
const int BTN = 5;                                // the physical button is connected to  (D1 is 5) (D2 is 4) (D4 is 2)
const int SPKR = 16;                              // speaker is attached to D0 = 16
const int TIME_CHECK_BUTTONS = 500;               // timer check for buttons every 100ms

// constructors
U8G2_SSD1306_64X48_ER_F_HW_I2C u8g2(U8G2_R0);     // OLED driver
WidgetTerminal terminal(V_TERM);                  // initialize terminal on vpin V_TERM
BlynkTimer timer;                                 // initialize timer

// global variables
char auth[] = "087e25a36cb240bfb6070c7acff7de1f"; // You should get Auth Token in the Blynk App.
char ssid[] = "";                           // WiFi credentials.
char pass[] = "";

int frequency = 50;                               // starting frequency of annoying alarm
long alarmTime = 0;                               // used for normal alarm, increases globally upto a certain range (then it stops and after a while it starts again)
int noise = 0;                                    // check whether alarm is on
bool annoying = 0;                                // check whether the annoying alarm should be used

bool buttonState     = 1;                         // current state of the button, for some reason in this setup it starts HIGH??
bool lastButtonState = 0;                         // previous state of the button
bool screenOn = 0;                                // bool to keep track whether theres text on the screen
String sending = "";                              // string to store message in, in case the message is paused and resumed


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////// OLED FUNCTIONS ///////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

boolean tooLong(String line){                     // bool func to check whether the string is too long for the OLED screen
  char nText[100];
  int Width; 
  line.toCharArray(nText,100);
  Width = (int)(u8g2.getStrWidth(nText));
  return Width > 64;
}

void write_OLED(String text){                     // simple function to write the text to the OLED 
  char nText[100];
  
  terminal.println(text);
  text.toCharArray(nText,100);
  u8g2.clearBuffer();
  u8g2.drawStr(XS,YS,nText); 
  u8g2.sendBuffer();
  screenOn = 1;
}

void fillBuffer(String stuff){                    // used to cut the text into lines so it fits on OLED ; | (bar) is also used as newline
  String t="", nt="";                             // had an exception(3) stack dump error in this function, so did two things: 1 split it up into
  char nText[100];                                // two functions and used 2 char variables
  int x = XS, y = YS;
  String newLine = "|";
  
  for (int i=0; i <= stuff.length(); i++) {
    nt += stuff[i];
    if ( tooLong(nt) || stuff.substring(i,i+1)=="|" ){
      t.toCharArray(nText,100);
      u8g2.drawStr(x,y,nText);                                      //0,8 is linksboven 48,57 is laatste letter, x space (nieuwe regel) is 9; 64 is max width.
      y+=YDIV;
      if(stuff.substring(i,i+1)!="|"){nt = stuff[i];}else{nt = "";} //nt becomes the next letter of the big string
    }else{
      t=nt;
    }
  }
  char nnText[100];
  t.toCharArray(nnText,100);
  u8g2.drawStr(x,y,nnText);
}

void write_Long_OLED(String text){               // THE OLED function to get (long) text onto screen, cut into lines
  terminal.println(text);
  u8g2.clearBuffer();
  fillBuffer(text);
  u8g2.sendBuffer();
  screenOn = 1;
  terminal.println(text);
  terminal.println("DONE");
}

void clearScreen(){                              // clear the OLED screen
  u8g2.clearBuffer();
  u8g2.sendBuffer();
  screenOn = 0;  
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////// ALARM AND BUTTON FUNCTIONS ///////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void startNoise(){                               // start the alarm
  pinMode(SPKR, OUTPUT); 
  if (annoying){
    frequency += 10;
    tone (SPKR, frequency);
    if (frequency >= 1024) {frequency = 50;};
  }else{
    frequency = 700;
    if(alarmTime++ < 150){
      tone (SPKR, frequency);
    }else{
      analogWrite(SPKR,0);      
      alarmTime = alarmTime > 300 ? 0 : alarmTime;
    }
  }
}

void stopNoise(){                               // stop the alarm
  pinMode(SPKR, OUTPUT); 
  timer.deleteTimer(noise);
  analogWrite(SPKR,0);
  alarmTime = 0;
}

void checkButtons(){                            // time function to check the physical button state, act when its state changes (in this case: it is pressed)
    Serial.println("CHECK BUTTONS.");
  //pinMode(BTN , INPUT);
  bool buttonState = digitalRead(BTN);

            boolean btnPressed = !digitalRead(BTN);
            if(btnPressed == true)
            {
                Serial.println("button has been pressed.");
            }



  if (buttonState != lastButtonState && buttonState == HIGH) { //state has changed AND button is pressed (LOW) then do stuff
    lastButtonState = buttonState;              // save the current state as the last state, for next time through the loop
    Serial.println("Button is pressed.");
    terminal.println("Button is pressed.");
    messageReceived();
    //Blynk.notify("Yaaay... button is pressed!");
  }
  if (buttonState != lastButtonState && buttonState == LOW) { //state has changed AND button is no Longer pressed
    lastButtonState = buttonState;              // save the current state as the last state, for next time through the loop
    Serial.println("Button is relieved.");
  }
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////// MESSAGE FUNCTIONS ////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void sendMessage(String text){                                // prepare all the stuff to send a message, initiate buttons, turn on alarm, send to OLED
  BLYNK_LOG1(BLYNK_F("start sendmessage" BLYNK_NEWLINE));
  write_Long_OLED(text);
  noise = timer.setInterval(10, startNoise);                  // every 0.1 second: check if a button is pressed
  Blynk.setProperty(V_RCVD, "onLabel", "Waiting");
  Blynk.setProperty(V_RCVD, "offLabel", "Waiting");
  Blynk.setProperty(V_SEND, "onBackColor", BLYNK_GREEN);
  Blynk.setProperty(V_SEND, "offBackColor", BLYNK_GREEN);
  Blynk.setProperty(V_RCVD, "onBackColor", WHITE);
  Blynk.setProperty(V_RCVD, "offBackColor", WHITE);
  
  Blynk.virtualWrite(V_SEND,TRUE);
  BLYNK_LOG1(BLYNK_F("end sendmessage" BLYNK_NEWLINE));
  sending = text;
}

void resetMessage(){                                          // reset all buttons, clear screen etc.
  clearScreen();
  stopNoise();
  Blynk.setProperty(V_RCVD, "onLabel", "");
  Blynk.setProperty(V_RCVD, "offLabel", "");
  Blynk.setProperty(V_RCVD, "onBackColor", BLYNK_GREEN);
  Blynk.setProperty(V_RCVD, "offBackColor", BLYNK_GREEN);
  Blynk.setProperty(V_SEND, "onBackColor", WHITE);
  Blynk.setProperty(V_SEND, "offBackColor", WHITE);
  Blynk.virtualWrite(V_SEND,FALSE);
  sending = "";
}

void pauseMessage(){                                          // if SENDING buttton is pressed (while sending) the message is paused
  clearScreen();
  stopNoise();
  Blynk.setProperty(V_RCVD, "onLabel", "");
  Blynk.setProperty(V_RCVD, "offLabel", "");
  Blynk.virtualWrite(V_SEND,FALSE);
}

void resumeMessage(){                                         // if SENDING buton is pressed (while sending is interrupted) the message and alarm is continued
  write_Long_OLED(sending);
  noise = timer.setInterval(10, startNoise);                 // every 0.1 second: check if a button is pressed
  Blynk.setProperty(V_RCVD, "onLabel", "Waiting...");
  Blynk.setProperty(V_RCVD, "offLabel", "Waiting...");
  Blynk.virtualWrite(V_SEND,TRUE);
}

void messageReceived(){                                      // indicator that the physical button was pressed, everything is reset, alarm turned off 
  stopNoise();
  Blynk.setProperty(V_RCVD, "onLabel", "RECEIVED");
  Blynk.setProperty(V_RCVD, "offLabel", "RECEIVED");

  Blynk.setProperty(V_RCVD, "onBackColor", BLYNK_GREEN);
  Blynk.setProperty(V_RCVD, "offBackColor", BLYNK_GREEN);
  Blynk.setProperty(V_SEND, "onBackColor", WHITE);
  Blynk.setProperty(V_SEND, "offBackColor", WHITE);
  
  Blynk.virtualWrite(V_SEND,FALSE);
  timer.setTimer(20000L, resetMessage, 1);                  // reset everything after 20s

  Blynk.virtualWrite(V0, 0);                                // reset widget
  Blynk.virtualWrite(V1, " ");                              // reset widget
  sending = "";
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////// BLYNK VIRTUAL PINS ///////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

BLYNK_WRITE(V_MENU){                                        //send choice of menu ; bar | is new line
  String text;
  
  switch (param.asInt()){
      case 1: { // Item 1
        text = "We gaan eten";
        break;
      }
      case 2: { // Item 1
        text = "Tanden|poetsen en|douchen";
        break;
      }
      case 3: { // Item 1
        text = "Ga je|huiswerk|doen";
        break;
      }
      case 4: { // Item 1
        text = "Tafel dekken";
        break;
      }
      case 5: { // Item 1
        text = "Bel me|(Gean)";
        break;
      }
      case 6: { // Item 1
        text = "Bel me|(Rolph)";
        break;
      }
      case 7: { // Item 1
        text = "Kan het wat|zachter!";
        break;
      }
      case 8: { // Item 1
        text = "Kom naar|beneden s.v.p";
        break;
      }
    } //switch
  sendMessage(text);                                                // any text entered is send to the OLED (after broken into pieces
  terminal.println(text);
}

BLYNK_WRITE(V_TEXT){                                                // send entered text
  sendMessage(param.asStr());                                       // any text entered is send to the OLED (after broken into pieces
}

BLYNK_WRITE(V_SEND){                                                // the actual send message (basically should only be used to turn sending OFF
  bool value = (bool) param.asInt();                                // Get value as integer
  if (value && sending != ""){
    resumeMessage();
  }else{
    pauseMessage();                                                 // stop message and alarm, but don't reset everything...yet
  }
}

BLYNK_WRITE(V_RCVD){                                                // shows indicator that the message was received
  //this is not a button
}

BLYNK_WRITE(V_ANOY){  //button to turn on annoying alarm            // button for annoying alarm on or off
  annoying = (bool)param.asInt();
  terminal.print("annoy is set to: ");
  terminal.println(annoying);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////// SETUP AND LOOP ///////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void setup(){
  Serial.begin(9600);                                               // Debug console ; can be addressed by: BLYNK_LOG1(BLYNK_F(stuff))
  u8g2.begin();                                                     // initializer for OLED
  u8g2.setFont(u8g2_font_helvR08_te);                               // set font for OLED
  terminal.println("Connecting...");

  write_OLED("Connecting");
  Blynk.begin(auth, ssid, pass);
  
  //pinMode(BTN, INPUT);                                              // Setup notification button on pin 5
  pinMode(BTN, INPUT_PULLUP);
  lastButtonState = buttonState;                                    // initiate lastbuttonstate
  pinMode(SPKR, OUTPUT);                                            // Setup speaker on pin 16
  timer.setInterval(500L, checkButtons);              // every 0.1 second: check if a button is pressed ; constantly!

  terminal.println("...READY");
  write_OLED("READY");
  timer.setTimer(5000L, resetMessage, 1);                           // clear READY from screen after 5s and reset all widgets

  BLYNK_LOG1(BLYNK_F(BLYNK_NEWLINE
      "    ___  __          __" BLYNK_NEWLINE
      "   / _ )/ /_ _____  / /__" BLYNK_NEWLINE
      "  / _  / / // / _ \\/  '_/" BLYNK_NEWLINE
      " /____/_/\\_, /_//_/_/\\_\\" BLYNK_NEWLINE
      "        /___/ WOLPH42 CODED" BLYNK_NEWLINE
  ));
}

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

            boolean btnPressed = !digitalRead(BTN);
            if(btnPressed == true)
            {
                Serial.println("button has been pressed!!!!!!!!!!.");
            }

  
}