#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
// "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 - 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
}