Pausing Blynk re-connecting to handle button press event

I installed the lib. And under USAGE section i found this code

#define TIMER_INTERRUPT_DEBUG      1

#include "ESP8266TimerInterrupt.h"

#ifndef LED_BUILTIN
#define LED_BUILTIN       2         // Pin D2 mapped to pin GPIO2/ADC12 of ESP32, control on-board LED
#endif

volatile uint32_t lastMillis = 0;

void IRAM_ATTR TimerHandler(void)
{
  static bool toggle = false;
  static bool started = false;

  if (!started)
  {
    started = true;
    pinMode(LED_BUILTIN, OUTPUT);
  }

  #if (TIMER_INTERRUPT_DEBUG > 0)
  if (lastMillis != 0)
    Serial.println("Delta ms = " + String(millis() - lastMillis));
  lastMillis = millis();
  #endif
  
  //timer interrupt toggles pin LED_BUILTIN
  digitalWrite(LED_BUILTIN, toggle);
  toggle = !toggle;
}

#define TIMER_INTERVAL_MS        1000 

// Init ESP8266 timer 0
ESP8266Timer ITimer;


void setup()
{
  Serial.begin(115200);
  Serial.println("\nStarting");
  
  // Interval in microsecs
  if (ITimer.attachInterruptInterval(TIMER_INTERVAL_MS * 1000, TimerHandler))
    Serial.println("Starting  ITimer OK, millis() = " + String(millis()));
  else
    Serial.println("Can't set ITimer correctly. Select another freq. or interval");

}

void loop()
{
  
}

But the code is not compiling

sketch_nov25c:11:16: error: expected initializer before 'TimerHandler'

 void IRAM_ATTR TimerHandler(void)

                ^

sketch_nov25c:11:16: error: expected initializer before 'TimerHandler'

 void IRAM_ATTR TimerHandler(void)

                ^

exit status 1
expected initializer before 'TimerHandler'


Can you please tell me whether the lib has been installed properly ?

Can you please shed more light on this ?? I am finding it difficult to understand the examples you have provided. And even the SwitchDebounce example from your lib is not compiling.
Can you please help me out ?

Sorry to know that you have the problem with installing library.
Can you check that you

  1. Already copy the whole directory ESP8266TimerInterrupt-master into libraries directory, normally ~/Arduino/libraries/ for Linux/Ubuntu
  2. Use the file in the examples subdirectory under ESP8266TimerInterrupt-master to avoid copying mistakes. Just a missing or extra {, } or ; can create issue.
  3. Check if you have the latest Arduino 1.8.10. I havenā€™t checked the earlier versions.
  4. Check if you have ESP8266 newer library version, such as 2.6.0 or 2.6.1. I havenā€™t checked the earlier version.

I tested again and again your posted code as well as files in the library without any compiling error, using Arduino 1.8.10 and ESP8266 library v2.6.1.

Iā€™ll find out if the earlier libraries or Arduino versions can create this kind of error.

The lean/mean function to use in ISR (Interrupt Service Routine) means that it must be short, not using uncontrolled while, for, etc. loop that takes lot of processing time, and especially donā€™t use any delay() or call any function doing so.
Generally, this function is part of ISR, and must follow guidelines to write ISRs.
Thatā€™s the catch in order to bypass being blocked.

Update:
Just find out Arduino 1.8.9 has that compiling problem. Iā€™ll find out why. Update to 1.8.10 now.

I am using 1.8.7 ā€¦
May be thats the issue !

Should i update the arduino build ?
So with your lib i should be getting the buttons working even if there is connection happening ?

Can you please provide any example sketch ?

Can you try removing IRAM_ATTR at TimerHandler(void)

void /*IRAM_ATTR*/ TimerHandler(void)

Itā€™s better you update the Arduino to 1.8.10 and ESP8266 library to 2.6.1 as theyā€™re stable and better now.

So with your lib i should be getting the buttons working even if there is connection happening ?

Yes, thatā€™s the power of ISR. Certainly. it also depends on how you write your function. Anyway, Iā€™ll use your application as an example to use either ISR directly or to use Hardware Timer to poll.
This is something I plan to do to add more examples showing the benefit of ISR. I will finish it shortly and let you know then.

I will do that !

Thank you for taking my request. Please keep us updated on the example sketch.

This is the first version using ISR directly to detect the SW and control lamp relay. It wonā€™t stop functioning even if some other function is blocking. I tested and itā€™s working OK on Arduino1.8.10 and esp8266 2.6.1

#define BLYNK_PRINT Serial
//#define BLYNK_DEBUG true

#include <ESP8266WiFi.h>

//#define USE_BLYNK_WM   true
#define USE_BLYNK_WM   false

#define USE_SSL     false

#if USE_BLYNK_WM
  #if USE_SSL
    #include <BlynkSimpleEsp8266_SSL_WM.h>        //https://github.com/khoih-prog/Blynk_WM
  #else
    #include <BlynkSimpleEsp8266_WM.h>            //https://github.com/khoih-prog/Blynk_WM
  #endif
#else
  #if USE_SSL
    #include <BlynkSimpleEsp8266_SSL.h>
    #define BLYNK_HARDWARE_PORT     9443
  #else
    #include <BlynkSimpleEsp8266.h>
    #define BLYNK_HARDWARE_PORT     8080   
  #endif
#endif

#if !USE_BLYNK_WM
  #define USE_LOCAL_SERVER    true
  
  // If local server
  #if USE_LOCAL_SERVER
    char blynk_server[]   = "yourname.duckdns.org";
  #else
    char blynk_server[]   = "";
  #endif

char auth[]     = "***";
char ssid[]     = "***";
char pass[]     = "***";

#endif

#define DEBOUNCE_TIME               25
#define LONG_BUTTON_PRESS_TIME_MS   10
#define DEBUG_ISR                   0
#define VPIN1                       V1

volatile unsigned long  lastDebounceTime  = 0;
volatile bool           buttonPressed     = false;
bool                    alreadyTriggered  = false;

void lightOn1();
void lightOff1();

boolean LampState1 = 0;
boolean SwitchReset1 = true;

const int RelayPin1 = D1;     //D2;
const int buttonPin = D3;     //D1;

BlynkTimer Timer;
unsigned int myServerTimeout      =  3500L;  //  3.5s server connection timeout (SCT)
unsigned int myWiFiTimeout        =  3200L;  //  3.2s WiFi connection timeout   (WCT)

unsigned int buttonInterval       =   500L;  //  0.5s check button state

void ICACHE_RAM_ATTR Falling();
void ICACHE_RAM_ATTR Rising();

void setup() 
{
  Serial.begin(115200);
  
  pinMode(RelayPin1, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);

  attachInterrupt(digitalPinToInterrupt(buttonPin), Falling, FALLING);

  Serial.println("Initialize Blynk");

  #if USE_BLYNK_WM
    Blynk.begin();
  #else
    unsigned long startWiFi = millis();
    WiFi.begin(ssid, pass);
    while (WiFi.status() != WL_CONNECTED)
    {
      delay(500);
      if(millis() > startWiFi + myWiFiTimeout)
      {
        Serial.println("Check the WiFi router. ");
        break;
      }       
    }
    Blynk.config(auth, blynk_server, BLYNK_HARDWARE_PORT);
    Serial.println("This is HomeControl-TEST"); 
    Blynk.connect();  
    
  #endif

  Timer.setInterval(buttonInterval, checkButton);  
}

void Rising()
{
  unsigned long currentTime  = millis();
  unsigned long TimeDiff;
  #if (DEBUG_ISR > 0)  
  Serial.println("rising");
  #endif  
  TimeDiff = currentTime - lastDebounceTime;
  if ( digitalRead(buttonPin) && (TimeDiff > DEBOUNCE_TIME) )
  {
    #if (DEBUG_ISR > 0)     
    Serial.println("Button Released");
    #endif
    buttonPressed = false;

    ButtonCheck1();
          
    if (TimeDiff > LONG_BUTTON_PRESS_TIME_MS)
    {
     #if (DEBUG_ISR > 0)
        Serial.printf("TimeDiff = %d ms => long Button Press (with release)\n", TimeDiff );
       #endif      
      
    } else {
      #if (DEBUG_ISR > 0)
        Serial.println("Short Button Press");
      #endif
    }
    lastDebounceTime = currentTime;
    attachInterrupt(digitalPinToInterrupt(buttonPin), Falling, FALLING);    
  }
}

void  Falling()
{
  unsigned long currentTime  = millis();
  #if (DEBUG_ISR > 0)  
  Serial.println("falling");
  #endif  
     
  if ( !digitalRead(buttonPin) && (currentTime > lastDebounceTime + DEBOUNCE_TIME))
  {
    lastDebounceTime = currentTime;

     #if (DEBUG_ISR > 0)     
    Serial.println("Button Pressed");
    #endif

    ButtonCheck1();
    
    buttonPressed = true;
    attachInterrupt(digitalPinToInterrupt(buttonPin), Rising, RISING);                                                
  }     
}

void loop() 
{
  Blynk.run();
  Timer.run();
}

void checkButton()
{
  Blynk.virtualWrite(VPIN1, LampState1);   
}

void ButtonCheck1() 
{
  boolean SwitchState1 = (digitalRead(buttonPin));
  
  if (!SwitchState1 && SwitchReset1) 
  {
    if (LampState1) 
    {
      lightOff1();
    } 
    else 
    {
      lightOn1();
    }
    
    SwitchReset1 = false;
  }
  else if (SwitchState1) 
  {
    SwitchReset1 = true;
  }
}

void ToggleRelay1() 
{
  LampState1 = !LampState1;
  
  if (LampState1) 
  {
    lightOn1();
  }
  else 
    lightOff1();
}

void lightOn1() 
{
  digitalWrite(RelayPin1, LOW);
  LampState1 = 1;
}

void lightOff1() 
{
  digitalWrite(RelayPin1, HIGH);
  LampState1 = 0;
}

BLYNK_WRITE(VPIN1) 
{
  int SwitchStatus1 = param.asInt();
  
  if (SwitchStatus1 == 2)
  {
    ToggleRelay1();
  }
  else if (SwitchStatus1)
  {
    lightOn1();
  }
  else 
    lightOff1();
}

Thank you for the quick update. I will try it shortly and update you on this.
Thank you once again.

Here is the version using ISR to detect the SW press and the Hardware Timer to poll and make decision.
Be noted that all the unnecessary calls, such as delay() or

Blynk.virtualWrite(VPIN1, LampState1);

are either deleted or pushed out to Blynk Software Timer.

#define BLYNK_PRINT Serial
//#define BLYNK_DEBUG true

#include <ESP8266WiFi.h>

//#define USE_BLYNK_WM   true
#define USE_BLYNK_WM   false

#define USE_SSL     false

#if USE_BLYNK_WM
  #if USE_SSL
    #include <BlynkSimpleEsp8266_SSL_WM.h>        //https://github.com/khoih-prog/Blynk_WM
  #else
    #include <BlynkSimpleEsp8266_WM.h>            //https://github.com/khoih-prog/Blynk_WM
  #endif
#else
  #if USE_SSL
    #include <BlynkSimpleEsp8266_SSL.h>
    #define BLYNK_HARDWARE_PORT     9443
  #else
    #include <BlynkSimpleEsp8266.h>
    #define BLYNK_HARDWARE_PORT     8080   
  #endif
#endif

#define TIMER_INTERRUPT_DEBUG      1

#include "ESP8266TimerInterrupt.h"

// Init ESP8266 Hardware timer
ESP8266Timer ITimer;
#define TIMER_INTERVAL_MS         100

#if !USE_BLYNK_WM
  #define USE_LOCAL_SERVER    true
  
  // If local server
  #if USE_LOCAL_SERVER
    char blynk_server[]   = "yourname.duckdns.org";
  #else
    char blynk_server[]   = "";
  #endif

char auth[]     = "***";
char ssid[]     = "***";
char pass[]     = "***";

#endif

#define DEBOUNCE_TIME               25
#define LONG_BUTTON_PRESS_TIME_MS   10
#define DEBUG_ISR                   0
#define VPIN1                       V1

volatile unsigned long  lastDebounceTime  = 0;
volatile bool           buttonPressed     = false;
bool                    alreadyTriggered  = false;

void lightOn1();
void lightOff1();

boolean LampState1 = 0;
boolean SwitchReset1 = true;

const int RelayPin1 = D1;     //D2;
const int buttonPin = D3;     //D1;

BlynkTimer Timer;
unsigned int myServerTimeout      =  3500L;  //  3.5s server connection timeout (SCT)
unsigned int myWiFiTimeout        =  3200L;  //  3.2s WiFi connection timeout   (WCT)

unsigned int buttonInterval       =  2000L;  //  2.0s update button state

void ICACHE_RAM_ATTR Falling();
void ICACHE_RAM_ATTR Rising();

void setup() 
{
  Serial.begin(115200);
  
  pinMode(RelayPin1, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);

  attachInterrupt(digitalPinToInterrupt(buttonPin), Falling, FALLING);

  // Interval in microsecs, so MS to multiply by 1000
  // Be sure to place this HW Timer well ahead blocking calls, because it needs to be initialized.
  if (ITimer.attachInterruptInterval(TIMER_INTERVAL_MS * 1000, HWCheckButton))
    Serial.println("Starting  ITimer OK, millis() = " + String(millis()));
  else
    Serial.println("Can't set ITimer. Select another freq. or interval");

  Serial.println("Initialize Blynk");

  #if USE_BLYNK_WM
    Blynk.begin();
  #else
    unsigned long startWiFi = millis();
    WiFi.begin(ssid, pass);
    while (WiFi.status() != WL_CONNECTED)
    {
      delay(500);
      if(millis() > startWiFi + myWiFiTimeout)
      {
        Serial.println("Check the WiFi router. ");
        break;
      }       
    }
    Blynk.config(auth, blynk_server, BLYNK_HARDWARE_PORT);
    Serial.println("This is HomeControl-TEST"); 
    Blynk.connect();  
    
  #endif

  Timer.setInterval(buttonInterval, checkButton);  
}

void Rising()
{
  unsigned long currentTime  = millis();
  unsigned long TimeDiff;
  #if (DEBUG_ISR > 0)  
  Serial.println("rising");
  #endif  
  TimeDiff = currentTime - lastDebounceTime;
  if ( digitalRead(buttonPin) && (TimeDiff > DEBOUNCE_TIME) )
  {
    #if (DEBUG_ISR > 0)     
    Serial.println("Button Released");
    #endif
    buttonPressed = false;

    //ButtonCheck1();
          
    if (TimeDiff > LONG_BUTTON_PRESS_TIME_MS)
    {
     #if (DEBUG_ISR > 0)
        Serial.printf("TimeDiff = %d ms => long Button Press (with release)\n", TimeDiff );
       #endif      
      
    } else {
      #if (DEBUG_ISR > 0)
        Serial.println("Short Button Press");
      #endif
    }
    lastDebounceTime = currentTime;
    attachInterrupt(digitalPinToInterrupt(buttonPin), Falling, FALLING);    
  }
}

void  Falling()
{
  unsigned long currentTime  = millis();
  #if (DEBUG_ISR > 0)  
  Serial.println("falling");
  #endif  
     
  if ( !digitalRead(buttonPin) && (currentTime > lastDebounceTime + DEBOUNCE_TIME))
  {
    lastDebounceTime = currentTime;

     #if (DEBUG_ISR > 0)     
    Serial.println("Button Pressed");
    #endif

    //ButtonCheck1();
    
    buttonPressed = true;
    attachInterrupt(digitalPinToInterrupt(buttonPin), Rising, RISING);                                                
  }     
}

void loop() 
{
  Blynk.run();
  Timer.run();
}

void HWCheckButton()
{
  if (!alreadyTriggered && buttonPressed)
  {
    alreadyTriggered = true;
    #if (DEBUG_ISR > 0)
      Serial.println("Long Button Press");
    #endif
    
    // Doing something here without waiting for button released (long press)
   ButtonCheck1();
  
  }
  else if (!buttonPressed)
  {
    // Reset flag when button released to avoid triggered repeatedly
    alreadyTriggered = false;
    ButtonCheck1();
  }
}

void checkButton()
{
  Blynk.virtualWrite(VPIN1, LampState1);   
}

void ButtonCheck1() 
{
  boolean SwitchState1 = (digitalRead(buttonPin));
  
  if (!SwitchState1 && SwitchReset1) 
  {
    if (LampState1) 
    {
      lightOff1();
    } 
    else 
    {
      lightOn1();
    }
    
    SwitchReset1 = false;
  }
  else if (SwitchState1) 
  {
    SwitchReset1 = true;
  }
}

void ToggleRelay1() 
{
  LampState1 = !LampState1;
  
  if (LampState1) 
  {
    lightOn1();
  }
  else 
    lightOff1();
}

void lightOn1() 
{
  digitalWrite(RelayPin1, LOW);
  LampState1 = 1;
}

void lightOff1() 
{
  digitalWrite(RelayPin1, HIGH);
  LampState1 = 0;
}

BLYNK_WRITE(VPIN1) 
{
  int SwitchStatus1 = param.asInt();
  
  if (SwitchStatus1 == 2)
  {
    ToggleRelay1();
  }
  else if (SwitchStatus1)
  {
    lightOn1();
  }
  else 
    lightOff1();
}

Tried it just now. Seems to work ok. But once in a while the ESP is crashing. And dumping
something like this

ctx: sys 
sp: 3ffffd90 end: 3fffffb0 offset: 01a0

>>>stack>>>
3fffff30:  00000014 00000210 00000210 3fff1418  
3fffff40:  4023920a 3ffe9f14 3ffef398 4021a955  
3fffff50:  4023930c 3ffe9f14 3ffef3c0 009c8f9c  
3fffff60:  40104d7e 0030c940 3ffef3c0 60000600  
3fffff70:  40240a9d 3ffe9f14 3ffef3c0 009c82fc  
3fffff80:  40240ae2 3fffdab0 00000000 3fffdcb0  
3fffff90:  3ffef3d0 3fffdad0 3ffefdb8 4021164f  
3fffffa0:  40000f49 3fffdab0 3fffdab0 40000f49  
<<<stack<<<

 ets Jan  8 2013,rst cause:2, boot mode:(3,6)

May be the problem is with ESP core and Arduino buildā€¦
I will try it out with your version of CORE and arduino build.

I did not get this !! :cold_sweat:

@khoih
I tried to upgrade to arduino version to 1.8.10 and updated esp8266 core to 2.6.1
Now none of my previous codes are compilingā€¦

It says multiple libraries were foundā€¦ I tried deleting all the user files from previous build and reinstalled !! But no use. Should i change back to the older version ?? Sure its not a blynk related issue. But want to know whether you faced the same issue earlier when you upgradedā€¦

EDIT

But the code compiles with ESP core 2.5.2
Gives no errorā€¦

Sorry to know that you got problem arising from updating.
Normally, multiple libraries were found warning is OK, provided the compiler uses the correct intended library. So you have to know what the real error is.

If you can use 2.5.2 without problem, then use it for now. But which Arduino version? 1.8.10 or 1.8.7?

I havenā€™t experienced that kind of problem and donā€™t have direct knowledge of what the issue is. Which OS are you running (Win/Ubuntu/Linux)??
Anyway, itā€™s better to go to Arduino forum to search or ask for advice. You can also go to my GitHub

and post Issues there, and Iā€™ll try my best to help you out. Iā€™m afraid here is not a good place to deal with that problem.

RE: random reset of the board:
ets Jan 8 2013,rst cause:2, boot mode:(3,6)

Selection_343

The reset came from your reset pin. This means you might use the wrong pins, or some other external devices pulse the RST pin. Did you change the pins in the code?

const int RelayPin1 = D1;     //D2;
const int buttonPin = D3;     //D1;

Iā€™ve been running several boards continuously from the time I posted the code until now without any issue.

I found out the compiling error problem with Arduino before 1.8.10.
The version before 1.8.10 uses

ICACHE_RAM_ATTR

from 1.8.10, we can use

either ICACHE_RAM_ATTR or IRAM_ATTR

Iā€™ll change all IRAM_ATTR to ICACHE_RAM_ATTR for better compatibility.

I tested with Arduino 1.8.9 and ESP8266 2.5.2 and itā€™s working OK.

Sorry. If you still have problems with updating, keep using the old version now.

Updated:

Just post new release v1.0.1 to fix those compiler errors.

1 Like

This is the build i have installed.

need to check whether this core will solve the problem or not.

i am on win8.1

same here @PeteKnight i guess Pete has not come across this thread or may be busy :wink::stuck_out_tongue_winking_eye:

I guess the problem is, i am using wifimanager to input the credentials !! May that is taking up a lot of memory !
Any ways i will check it out with core 2.5.2 and let you know !!

The new release v1.0.1 of ESP8266TimerInterrupt with new Blynk examples (inspired from your code) has been published.
It fixes all the pre-1.8.10-Arduino and pre-2.6.0-ESP8266-core compiler error issues as well as start-up and random resets youā€™ve experienced.

Please go to GitHub to download and test in examples subdirectory. They are too long to post here.

You can test using 1.8.10 and 2.5.2. I tested with 1.8.9 amd 2.5.2 OK.

1 Like

wooooow !! thats amazing !! I will try that shortly !!

@khoih
Hello !!
Sorry for the late update.
I tried your new example ! But it still crashes while trying to connect to the server. But works fine when both wifi and internet is up. If only wifi is available without the internet it crashes when i push the buttonā€¦ I tried changing the pins, changed the nodemcu module !! But still the same.
Is there any other way out ? :thinking:

The issue has been moved to

1 Like

Hello @khoih
Problem with the crash was
i had Blynk.virtualWrite on the Hardware Timer. So as soon as the connection drops(internet) it was crashingā€¦

My bad i did not pay attention to thisā€¦ Sorry !!