C++ Blynk (Legacy) - Code Examples for Basic Tasks

#26 - Adjustable pulsing LED that fades in and out with Timers

And now for more Timerception tricks… A variable timed, flashing (pulsing) physical LED that fades in and out, all with nested timers in lambda functions.


One of the lambda tricks I had to discover, via trial and error, was using a “fixed call” interval timer called simply setTimer(long d, timer_callback f, int n) that will run its timed interval course as normal, but only n many times before stopping… the key was finding where to put the integer n in a Lambda.

Note the necessary preceding comma…

int timer.setTimer(long d, []() {
  // your code in lew of timer_callback f
}, int n);

AKA

timerId = timer.setTimer(1000L, []() {
// Repeat me every second but only five times
}, 5);

Another glitch in SimpleTimer (of which BlynkTimer is based) is that when using timer ID labels, needed to do things like disable, enable, delete, etc. timers, it seems like the first timer in your code will also get ‘deleted’… I found making your first timer a simple “Sacrificial Timer” that solves that little issue :slight_smile:

  // "Sacrificial" Timer - needed when deleting timers as using that feature will also kill first timer created...
  timer.setTimeout(10L, []() {
    // do nothing here, or some other task that needs only run once EG. Blynk.virtualWrite(V0, "START");  
  });  // END sacrificial Function

In this example each chosen interval time, measured in quarter “seconds” (measured in binary units of 256, starting at 512 for shortest setting - all due to the math) will result in half that time fading up and the other half fading down. The longer the total duration, the slower the fade will appear.

Due to the fast pace of the active fade count and analogWrite() from 0-255-0, there will be timing constraints needed to mimic this with a virtual LED… Perhaps I will figure that out later :thinking: - EDIT See something like this here

  • Display Widget on V0 for uptime in seconds
  • Built in LED (GPIO2) on NodeMCU and Wemos will blink as a “sign of life” indicator.
  • Display Widget on V1 for current interval value
  • Button Widget V2 for changing the interval
  • Physical button bringing GPIO0 to GND will “sync” with virtual button… and thus you can control this without Server connection.
#define BLYNK_PRINT Serial
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>

char auth[] = "xxxxxxxxxx";
char ssid[] = "xxxxxxxxxx";
char pass[] = "xxxxxxxxxx";
//char server[] = "xxx.xxx.xxx.xxx";  // IP for Local Server
char server[] = "blynk-cloud.com";  // IP for Cloud Server
int port = 8080;

int i;  // PWM count ID
int fadeUP;  // Timer ID
int fadeDOWN;  // Timer ID
int countUP;  // Timer ID
int countDOWN;  // Timer ID
int pulseTime = 256;  // Initial interval, not valid until incremented, else causes divide error
int btnState = HIGH; // Flag
int VbtnPin = LOW; // Flag
int buttonBlock = LOW; // Flag
const int btnPin = 0;  // Pin ID
const int ledPin = 14;  // Pin ID
const int builtinledPin = 2;  // Pin ID

BlynkTimer timer;



void setup() {
  Serial.begin(9600);  // BLYNK_PRINT data
  pinMode(btnPin, INPUT);
  pinMode(builtinledPin, OUTPUT);
  pinMode(ledPin, OUTPUT);

  WiFi.begin(ssid, pass);  // Connect to WiFi
  Blynk.config(auth, server, port);
  Blynk.connect();  // Initialise Connection to Server

  // "Sacrificial" Timer - needed when deleting timers as using that feature will also kill first timer created...
  timer.setTimeout(10L, []() {
    Blynk.virtualWrite(V0, "START");
  });  // END sacrificial Function

  // Timed Lambda Function - UpTime & Heartbeat...
  timer.setInterval(1000L, []() { // Run every second
    Blynk.virtualWrite(V0, millis() / 1000);  // Display the UpTime in seconds
    digitalWrite(builtinledPin, !digitalRead(builtinledPin));  // For "heartbeat" indicator on device
  });  // END UpTime Function

  // Timed Button watcher...
  timer.setInterval(100L, buttonScan);
}



BLYNK_CONNECTED() {
Blynk.virtualWrite(V1, "OFF");  // display the pulse interval as OFF
}


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



void buttonScan() {  // Change interval time via Physical Button
  if (digitalRead(btnPin) == LOW || VbtnPin == HIGH && buttonBlock == LOW) {
    if (btnState != LOW) {  // btnState is used to avoid sequential toggles
      timer.deleteTimer(fadeUP);  // Stop Timer
      timer.deleteTimer(fadeDOWN);  // Stop Timer
      timer.deleteTimer(countUP);  // Stop Timer
      timer.deleteTimer(countDOWN);  // Stop Timer
      pulseTime += 256;  // Increment pulse interval
      if (pulseTime > 5120) {  // Loop the pulse interval time back to the beginning
        pulseTime = 256;
        Blynk.virtualWrite(V1, "OFF");  // display the pulse interval as OFF
        analogWrite(ledPin, 0);  // Turn off LED
        return;
      }
      Blynk.virtualWrite(V1, pulseTime);  // display the pulse interval
      fadeLEDFunction();  // Start the pulsed fading
    }
    btnState = LOW;
  } else {
    btnState = HIGH;
  }
}


BLYNK_WRITE(V2) {  // Change interval time via Blynk button
  VbtnPin = param.asInt();  // Set the virtual button flag
  buttonScan();  // Run the actual button processing function.
}



void fadeLEDFunction() {
  firstPulse();  // Starts the initial pulse right away, while waiting for interval timer to start.
  delay(5);  // subtle delay to make sure initial pulse is finished before interval timer starts
  // Start fade up Lambda timer...
  fadeUP = timer.setInterval(pulseTime, []() {
    // Start count up Lambda counter...
    i = 11;  // Don't go totally dark
    countUP = timer.setTimer(pulseTime / 512, []() {
      i++;  // Count up
      analogWrite(ledPin, i);  // PWM to Fade LED
    }, 245); // END countUP Function
    // Start fade down Lambda timer...
    fadeDOWN = timer.setTimeout(pulseTime / 2, []() {
      // Start count down Lambda counter...
      i = 256;
      countDOWN = timer.setTimer(pulseTime / 512, []() {
        i--;  // Count down
        analogWrite(ledPin, i);  // PWM to fade LED
      }, 245); // END countDOWN Function
    });  // END fadeDOWN Function
  });  // END fadeUP Function
}



void firstPulse() {  // Starts the initial pulse
  buttonBlock = HIGH;  // Lockout flag for preventing further button press until done, else can cause timer duplication
  // Start first fade down Lambda timer...
  fadeDOWN = timer.setTimeout(pulseTime / 2, []() {
    // Start count down Lambda counter...
    i = 256;
    countDOWN = timer.setTimer(pulseTime / 512, []() {
      i--;  // Count down
      analogWrite(ledPin, i);  // PWM to fade LED
    }, 245); // END firstDOWN Function
  });  // END fadeDOWN Function
  // Start first fade up Lambda counter...
  i = 11;  // Don't go totally dark
  fadeUP = timer.setTimer(pulseTime / 512, []() {
    i++;  // Count up
    analogWrite(ledPin, i);  // PWM to fade LED
  }, 245); // END fadeUP Function
  buttonBlock = LOW;  // release lockout Flag
}
7 Likes