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

#13 - The All-in-One Timer Function (AKA Lambda Function) - No, I don’t entirely understand it… but it works :stuck_out_tongue_winking_eye:

I like this for it’s relative simplicity… no separate function to call (or write in the code) I just copy/paste my most used into my new sketches…


in your pre-setup…

BlynkTimer timer;

And in your void setup()

  // Timed Lambda Function - UpTime counter
  timer.setInterval(1000L, []() {  // Run every second
    Blynk.virtualWrite(V0, millis() / 60000);  // Display the UpTime in Minutes
  });  // END Timer Function

  • Lambda routine for the DHT sensor. With the Lambda, you you can combine commands and even add in some logic, just like normal… just more compact. Here is a simple example…
    In your pre-setup…
#include <DHT.h>  // For DHT22
#define DHTPIN 0  // GPIO0(D3) on Wemos D1 Mini
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
float h, t;

And in your void setup()

  // Timed Lambda Function - DHT22 Temp & Humidity sensor
  timer.setInterval(300000L, []() {  // Run every 5 minutes
    h = dht.readHumidity();
    t = dht.readTemperature(); // or dht.readTemperature(true) for Fahrenheit
    if (isnan(h) || isnan(t)) {  // Check if any reads failed and try once more this cycle.
      delay(250);  // short delay before recheck
      h = dht.readHumidity();
      t = dht.readTemperature(); // or dht.readTemperature(true) for Fahrenheit
    }
    Blynk.virtualWrite(V1, h);  // Display Humidity
    Blynk.virtualWrite(V2, t);  // Display Temperature
  });  // END Timer Function
5 Likes

#14 - ESP32 - Alternate way to control PWM pins for Servos and/or LEDs

At the time of this posting, the ESP32 Arduino Core does not support the handy analogWrite() command. So how do we do the PWM dodo we want to do?

Well, a little G :eyes: gling later and I found a few different websites that describe in more detail then I will get into here. How profoundly customisable the ESP32 GPIO pins are :smiley:

First you need this library…

And here is just a couple of sites with usage examples…

Basicly the GPIO pins can be linked to 16 independent channels, with configurable duty cycles and wave periods. The accuracy of the duty cycle can be configured up to 16 bits of resolution.

I am using 50Hz and 16-bits for the Servo control. for my servo 2000-8000 was a good range in the settings, without pushing the limits of the servo.

And for the RGB LED I am using 5000Hz but only 8-bits to give the range of 0-255 in the settings

For those that like to visually see results right darn now!!.. here is a small project that you can use… and even if you don’t have a servo motor or a 4 lead RGB LED, you will see the results on the App (OK a Gauge Widget is a poor substitute for a Servo :blush: but the HEX data that shows the corresponding colour is useful)

image

//#define BLYNK_PRINT Serial // This prints to Serial Monitor

#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>

#include <ESPmDNS.h>  // For OTA - ESP32
#include <WiFiUdp.h>  // For OTA
#include <ArduinoOTA.h>  // For OTA

#include "esp32-hal-ledc.h" // For Servo & RGB PWM control

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

int rrr, ggg, bbb;  // Set RED BLUE GREEN channe
int ServoPos;



void setup() {
  //Serial.begin(115200);  // BLYNK_PRINT data

  //===== Servo pin setup for ESP32 =====
  ledcSetup(1, 50, 16); // For Servo - channel 1, 50 Hz, 16-bit width
  ledcAttachPin(2, 1);   // For Servo - GPIO 2 assigned to channel 1

  //===== RGB LED pin setup for ESP32 =====
  ledcSetup(2, 5000, 8); // For RGB-Red - channel 2, 5000 Hz, 8-bit width
  ledcAttachPin(25, 2);   // For RGB-Red - GPIO 25 assigned to channel 2

  ledcSetup(3, 5000, 8); // For RGB-Green - channel 3, 5000 Hz, 8-bit width
  ledcAttachPin(27, 3);   // For RGB-Green - GPIO 27 assigned to channel 3

  ledcSetup(4, 5000, 8); // For RGB-Blue - channel 4, 5000 Hz, 8-bit width
  ledcAttachPin(26, 4);   // For RGB-Blue - GPIO 26 assigned to channel 4


  WiFi.begin(ssid, pass);
  Blynk.config(auth, server, port);
  Blynk.connect();

  ArduinoOTA.setHostname("ESP32 Servo RGB");  // For OTA - Use your own device identifying name
  ArduinoOTA.begin();  // For OTA
}



//===== Servo Control Widgets =====
BLYNK_WRITE(V1) {  // Slider for selective servo positioning
  ServoPos = param.asInt();  // Get position data
  ledcWrite(1, ServoPos);  // Move servo to position
  Blynk.virtualWrite(V0, ServoPos);  // Display servo position
  Blynk.virtualWrite(V5, ServoPos);  // Show servo position
}  // END Blynk Function


BLYNK_WRITE(V2) {  // Button for servo endstop positioning
  ServoPos = param.asInt();  // Get position data (pre set in MIN/MAX settings
  ledcWrite(1, ServoPos);  // Move servo to position
  Blynk.virtualWrite(V0, ServoPos);  // Display servo position
  Blynk.virtualWrite(V5, ServoPos);  // Show servo position
  Blynk.virtualWrite(V1, ServoPos);  // Sync slider position
}  // END Blynk Function



//===== zeRGBa Widget =====
BLYNK_WRITE(V4) { // START Blynk Function
  rrr = param[0].asInt(); // get a RED channel value
  ggg = param[1].asInt(); // get a GREEN channel value
  bbb = param[2].asInt(); // get a BLUE channel value
  RGBprocess(); // Run Arduino funtion
}  // END Blynk Function


//===== Physical RGB LED Control and HEX conversion =====
void RGBprocess() {  // START Arduino funtion

  // For Common Anode+ RGB LED
  ledcWrite(2, 256 - rrr); // Write to RED RGB pin
  ledcWrite(3, 256 - ggg); // Write to GREEN RGB pin
  ledcWrite(4, 256 - bbb); // Write to BLUE RGB pin

  // For Common Cathode- RGB LED
  //  ledcWrite(2, rrr); // Write to RED RGB pin
  //  ledcWrite(3, ggg); // Write to GREEN RGB pin
  //  ledcWrite(4, bbb); // Write to BLUE RGB pin

  // zeRGBa pin to #HEX conversion
  String strRED = String(rrr, HEX);  // Convert RED DEC to HEX
  if (rrr < 16) {
    strRED = String("0" + strRED);  // Buffer with 0 if required
  }  // END if
  String strGRN = String(ggg, HEX);  // Convert GREEN DEC to HEX
  if (ggg < 16)  {
    strGRN = String("0" + strGRN);  // Buffer with 0 if required
  }  // END if
  String strBLU = String(bbb, HEX);  // Convert BLUE DEC to HEX
  if (bbb < 16)  {
    strBLU = String("0" + strBLU);  // Buffer with 0 if required
  }  // END if
  String HEXstring = String("#" + strRED + strGRN + strBLU);  // Combine HEX fragments
  HEXstring.toUpperCase();  // Change HEX value to all upper case for ease of visuals.
  Blynk.setProperty(V3, "color", HEXstring);  // Change background colour of HEX Data Label
  Blynk.virtualWrite(V3, HEXstring);  // Display HEX data
}  // END Arduino Function



void loop() {
  Blynk.run();
  ArduinoOTA.handle();  // For OTA
}
6 Likes

#15 - Dual Blynk sliders for High Range High Precision values

And for all those precision slider fanatics who want their cake and eat it too (PS the cake is a lie :wink: )…

I introduce the solution for High Range AND High Precision using only sliders (no ugly step widgets for analog purists :stuck_out_tongue: ) Good luck trying to do both with a single slider.

int FullRange;
float Precision;

BLYNK_WRITE(V0) {  // Higher Range slider 0 to 255
  Blynk.virtualWrite(V1, 0);  // Zero out Precision slider
  FullRange = param.asInt();
  Blynk.virtualWrite(V2, FullRange);  // Display widget
}

BLYNK_WRITE(V1) {  // High Precision slider -0.99 to 0.99
  Precision = param.asFloat();
  Blynk.virtualWrite(V2, FullRange + Precision);  // Display widget
}

image

image

image

image

10 Likes

#16 - Ultrasonic Distance Sensor with Servo

This little project used the HC-SR04 Ultrasonic sensor… but instead of boring old distance numbers, it will also position a servo within a range of selected distances.

This sketch demonstrates a timer that can be enabled and disabled, so as not to be running something like the Ultrasonic sensor if other critical timing functions need to run.

And also demonstrates enabling and disabling the servo, so that there is no jitter or fluttering when it is not supposed to be moving, as can sometimes be caused by other timer routines.

Sensor and Servo need 5v, so best to draw from a separate 5v PSU than the Wemos’s 5v pin… particularly for the servo.

Wire the sensor and servo pins as shown in the sketch.

int trigPin = 12;  // D5 on Wemos D1 Mini
int echoPin = 13;  // D6 on Wemos D1 Mini
int servoPin = 4;  // D2 on Wemos D1 Mini

As a precaution, I wired a 1K resistor in series between the ECHO pin of the sensor and Pin 13 (D7) of the Wemos… this drops the current potential down, so that the 5v signal will not hurt the Wemos.

//#define BLYNK_PRINT Serial
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>

#include <ESP8266mDNS.h>  // For OTA
#include <WiFiUdp.h>  // For OTA
#include <ArduinoOTA.h>  // For OTA

#include <Servo.h>

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

int trigPin = 12;  // D5 on Wemos D1 Mini
int echoPin = 13;  // D6 on Wemos D1 Mini
int servoPin = 4;  // D2 on Wemos D1 Mini

int PingTimer; // TimerID
int SrvoPos;  // Servo position
long duration, distance;  // For Ping sensor 

BlynkTimer timer;
Servo myservo;



void setup() {
  //Serial.begin(115200);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(servoPin, OUTPUT);

  WiFi.begin(ssid, pass);
  Blynk.config(auth, server, port);
  Blynk.connect();

  // ===== Timer Setup =====
  PingTimer = timer.setInterval(250L, PingSensor);  // Ping distance routine - Button Controlled
  timer.disable(PingTimer);  // Disable timer until needed

  ArduinoOTA.setHostname("Wemos D1 Mini");  // For OTA - Use your own device identifying name
  ArduinoOTA.begin();  // For OTA
}



BLYNK_CONNECTED() {
    Blynk.syncVirtual(V2)
}



void loop() {
  Blynk.run();
  timer.run(); // Initiates BlynkTimer
  ArduinoOTA.handle();  // For OTA
}



BLYNK_WRITE(V2) { // Button to Enable/Disable Ultrasonic Sensor Routine
  if (param.asInt() == 1) {  // If button state is 1 (HIGH) then...
    timer.enable(PingTimer);  // Enable timer
    myservo.attach(servoPin);  // Connect survo
  } else {  // If button state is 0 (LOW) then...
    timer.disable(PingTimer);  // Disable timer
    myservo.write(5);  // Set servo at 0 position
    Blynk.virtualWrite(V1, 0);  // Reset Gauge for servo position
    Blynk.virtualWrite(V0, "N/A");  // Reset Display for Ultrasonic Sensor status
    delay(500);  // Small delay to allow servo reposition before disabling it.
    myservo.detach();  // Disconnect survo
  }
}



void PingSensor() {  // Ultrasonic (Ping) Distance Sensor
    // Pulse
    digitalWrite(trigPin, LOW);
    delayMicroseconds(2);
    digitalWrite(trigPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigPin, LOW);

    // End Pulse & Calculate didtance
    duration = pulseIn(echoPin, HIGH);
    distance = (duration / 2) / 29.1;

    // Map and constrain the Ultrasonic range 1-50cm to the servo position of 10-160
    SrvoPos = constrain(map(distance, 1, 50, 10, 160), 10, 160);  

    // Show results
    myservo.write(SrvoPos);  // Position servo
    Blynk.virtualWrite(V0, distance);  // To Display Widget
    Blynk.virtualWrite(V1, SrvoPos);  // To Gauge Widget
}
5 Likes

#17 - Dual Temperature Sensors running on ESP-01

This is a simple example of running both a DHTxx (in this case DHT11) and DS18B20 1-wire sensors on the lowly ESP-01

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>

#include <ESP8266mDNS.h>  // For OTA
#include <WiFiUdp.h>  // For OTA
#include <ArduinoOTA.h>  // For OTA

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

BlynkTimer timer;

// DHT22 Sensor setup
#include <DHT.h>
#define DHTPIN 0  // GPIO0 - pin5 on ESP-01
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
float h;
float t;

// DS18B20 Sensor setup
#include <OneWire.h>
#include<DallasTemperature.h>
#define ONE_WIRE_BUS 2  // GPIO2 - pin3 on ESP-01
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);
float DS18B20Temp;




void setup()
{
  DS18B20.begin();

  Blynk.connectWiFi(ssid, pass);
  Blynk.config(auth, server, 8080);
  Blynk.connect();

  timer.setInterval(1000L, UpTime);
  timer.setInterval(60000L, DS18B20TempSensor);
  timer.setInterval(10050L, DHTTempHumSensor);

  Blynk.virtualWrite(2, BLYNK_VERSION);
  Blynk.virtualWrite(6, ESP.getCoreVersion());

  ArduinoOTA.setHostname("ESP-01 Multi-temp");  // For OTA
  ArduinoOTA.begin();  // For OTA
}



void DS18B20TempSensor()  // DS18B20 sensor reading
{
  DS18B20.requestTemperatures();
  delay(500);  // Yes, the evil delay... but only for a really short time every 10s .  Alternative options are avail with timers.
  Blynk.virtualWrite(V3, DS18B20.getTempCByIndex(0));
}



void DHTTempHumSensor()  // DHT sensor reading
{
  h = dht.readHumidity();
  t = dht.readTemperature(); // or dht.readTemperature(true) for Fahrenheit
  Blynk.virtualWrite(V4, h);
  Blynk.virtualWrite(V5, t);
}



BLYNK_WRITE(V1) {  // Quick test read.  Clears all values and reloads
  if (param.asInt()) {
    Blynk.virtualWrite(V0, 0);
    Blynk.virtualWrite(V3, 0);
    Blynk.virtualWrite(V4, 0);
    Blynk.virtualWrite(V5, 0);
    DS18B20TempSensor();
    DHTTempHumSensor();
  }
}



void UpTime()
{
  Blynk.virtualWrite(V0, millis() / 1000);
  Blynk.virtualWrite(V7, WiFi.RSSI());
}



void loop()
{
  Blynk.run();
  timer.run();
  ArduinoOTA.handle();  // For OTA
}
8 Likes

#18 - Multi Colour Button, one color for ON one for OFF

NOTE - This has been rendered obsolete with the new Styled Button :+1:


The button (in switch mode) is essentially ON all the time, but pressing it toggles a variable (buttonState) between 0 & 1 so you can still control things outside the Blynk Function if you want.

You can also change the small labeling… However, there is no current way, that I am aware of, to change the buttons center text from within code.

You can make both ON and OFF colours whatever you want… just use my zeRGBa examples above to get the #HEX code you need for the colour you want.

In pre-setup…

int buttonToggle = 1;  // Set buttonToggle to 1 to start buttonState in OFF mode
int buttonState = 0;  // Set buttonState variable OFF

In setup after connection…

Blynk.virtualWrite(V0, 1); // set coloured button to default ON state
BLYNK_WRITE(V0) {
  if (param.asInt() == 0 && buttonToggle == 1) {
    buttonToggle = 0;
    buttonState = 1;
    Blynk.setProperty(V0, "color", "#23C48E"); // GREEN
    Blynk.setProperty(V0, "label", "ON"); // ON
  } else if (param.asInt() == 0 && buttonToggle == 0) {
    buttonToggle = 1;
    buttonState = 0;
    Blynk.setProperty(V0, "color", "#D3435C"); // RED
    Blynk.setProperty(V0, "label", "OFF"); // OFF
  }
  Blynk.virtualWrite(V1, buttonState);  // Display buttons usable state
  Blynk.virtualWrite(V0, 1);  // reset button widget to ON
}

5 Likes

A post was merged into an existing topic: Blynk.setProperty() command not changing button color

A post was split to a new topic: How to repeat the same activity or stop the activity form a function that is called by a BLYNK_WRITE(V?) function

#19 - Modified Text Input Widget performance - Now with 100% more line feed :stuck_out_tongue:

Well, here is another modification to make a widget work how I at least think it could (and possibly temporary… see my supplanted multi-coloured button above :wink: )

NOTE: This is NOT intended to undermine what Blynk has made… just add in my own personal preferences to somthing I wish to use in a particular way.

The text Input widget is great… easy to use and compact, compared to the Terminal input option. Only one thing… It doesn’t act like a ‘true’ (IMHO) text input. No EOL, ‘carriage return’ or clearing upon hitting return. All by design? Perhaps :smiley:

Well, here is my simple code mod to supply all those “missing” features :sunglasses:

You can still use the Widget as intended, or with the addition of a space and two periods (customisable) followed by the return key. you can get a cleared widget and a new line in the resulting string.

Due to the need for a SPACE to “clear” the widget… some post processing is used to remove a single leading SPACE from your string, if present.

String textIn; // declare global variable

//===== Modified Text Input Widget - BLYNK Function =====
BLYNK_WRITE(V0) {
  String textIn = param.asStr(); // Get string from Text Input Widget
  if (textIn.startsWith(" ")) {  // If it has a leading SPACE...
    textIn.remove(0, 1);  // ...remove it.
  }
  if (textIn.endsWith(" ..")) {  // If it has customisable EOL indicator, In my case SPACE and 2 PERIODS...
    textIn.replace(" ..", "\n"); // ...replace with newline command
    Blynk.virtualWrite(V0, " ");  // "clear" the Text Input field.  A null "" will not work, so needs a space
  }
  Serial.print(textIn);  // Show string output as intended, or do whatever you want with the string.
  Blynk.virtualWrite(vPin, textIn);  // Like send it to a terminal Widget
}

So if you want or need a truer text entry feeling, with carriage return effects… this…

image

…can become this, just by ending with a SPACE and 2 PERIODS (customisable)

image

image

image

To give this output…

image


And for the fun of it, here is some code to add a Clear Terminal button.

//===== Clear Terminal Widget =====
BLYNK_WRITE(vPin) {  // Button Widget
  if (param.asInt()) {
    Blynk.virtualWrite(vPin, "clr");  // Clears terminal if button state is 1
  }
}

image

3 Likes

5 posts were merged into an existing topic: Server connection dropouts

#20 - Variable timer

There has been a few discussions about how to vary the interval time of a timer… I have even used one way in an earlier post above with the adjustable servo sweep.

But here is an easier way… use a one-shot Timeout Timer instead…

Create your function that you want to run on a variable interval, but don’t call that function with an outside timer, just call it the first time (if you want) in your setup or upon Blynk connect, or even wait until you chose a time, etc.

Then, using a global variable acquired from some other source (Slider, Step Control, Numeric input, etc.) end your custom timed function with a timeout timer, set to the required variable, that calls the same function it is already in.

If you really want to get fancy, you can setup Timer IDs and run a delete timer at the beginning of the function, thus allowing you to interrupt and cancel whatever previous setting… preventing duplicate function runs from leftover timeout timers.

long variableTime = 1000; // default interval time of 1 second
int varTimer;  // Setup Timeout Timer ID 
BLYNK_WRITE(V0) { // Widget for interval timing
  variableTime = param.asInt();
  if (variableTime <= 0) { // prevents a timer from becoming 0 or less
    variableTime = 1;
  }
  timerLoop();  // Call your timed loop
}



void timerLoop() {
  timer.deleteTimer(varTimer);  // Cancel previous Timeout Timer
  //  
  //  Do your stuff here every (variableTime) seconds
  //
  varTimer = timer.setTimeout(variableTime, timerLoop);  // Set new Timeout timer
}
9 Likes

#21 - Sonoff Basic - Blynk and physical button control - with LED (showing ON status), OTA and displaying device specifics.

This is just a simple sketch for a Blynkified Sonoff Basic. Use either App or physical button to toggle the Sonoff. Physical button works even if no Server connected.

/*
   Sonoff Basic
   1MB (No SPIFS) flash size
   115200 BAUD
   MUST USE DOUT for Flash Mode!!

   sonoff header
   1 - vcc 3v3
   2 - rx
   3 - tx
   4 - gnd
   5 - gpio 14

   esp8266 connections
   gpio  0 - button
   gpio 12 - relay
   gpio 13 - green led - active low
   gpio 14 - pin 5 on header
*/

#include <ESP8266WiFi.h>  // for ESP8266
#include <BlynkSimpleEsp8266.h>  // for ESP8266
#include <ESP8266mDNS.h>  // For OTA w/ ESP8266
#include <WiFiUdp.h>  // For OTA
#include <ArduinoOTA.h>  // For OTA

char auth[] = "xxxxxxxxxx";  // Sonoff
char ssid[] = "xxxxx";
char pass[] = "xxxxx";
char server[] = "xxx.xxx.xxx.xxx";  // IP for your Local Server
int port = 8080;

int pinState = LOW;
int btnState = HIGH;

BlynkTimer timer;
void PhysButton();

void setup() {
  pinMode(0, INPUT);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);  // Turn OFF LED

  timer.setInterval(250L, PhysButton);  // scan for physical button press

  WiFi.begin(ssid, pass);
  Blynk.config(auth, server, port);
  Blynk.connect();

  ArduinoOTA.setHostname("Sonoff");  // For OTA - Use your own device identifying name
  ArduinoOTA.begin();  // For OTA
}



void loop() {
  Blynk.run();
  timer.run();
  ArduinoOTA.handle();  // For OTA
}



BLYNK_CONNECTED() {
  Blynk.syncVirtual(V0);
  Blynk.virtualWrite(V1, BLYNK_VERSION);
  Blynk.virtualWrite(V2, ESP.getCoreVersion());
  Blynk.virtualWrite(V3, WiFi.macAddress());
  Blynk.virtualWrite(V4, WiFi.localIP().toString());
}



BLYNK_WRITE(V0) { // Button Widget in switch mode
  digitalWrite(12, param.asInt());  // Toggle relay
  digitalWrite(13, !param.asInt());  // Toggle LED
}

void PhysButton() {
  if (digitalRead(0) == LOW) {
    // btnState is used to avoid sequential toggles
    if (btnState != LOW) {

      // Toggle LED state
      pinState = !pinState;
      digitalWrite(12, pinState);
      digitalWrite(13, !pinState);  // Toggle LED

      // Update Button Widget
      Blynk.virtualWrite(V0, pinState);
    }
    btnState = LOW;
  } else {
    btnState = HIGH;
  }
}

My simple display used to fit everything the way I wanted (centered columns under the buttons)… but now it looks lopsided with extended displays, that still crop on some devices… Boo!! Hiss!!

The sketch fits on the Sonoff, with a bit of room for more code :smiley:

9 Likes

#22 - Super Simple Duration Counter

OK, 'fess up time… I have rarely used millis() unless it was already included in some example or snippet copied from elsewhere, so I just assumed using it for actual human readable time was difficult… Well, it is not!! :blush:

V0 is a Button Widget set to switch mode
V1 is a Display Widget

And that is it… If all you need is a readable Hours/Minutes/Seconds duration display, without using Time library, RTC, etc. then here you go.

EDIT - Updated to count days as well, should your MCU stay running without reset that long :stuck_out_tongue_winking_eye:

You can take the key commands & process and implement them in any other type of displayable duration routine you want.

int runDays;
int runHours;
int secsRemaining;
int runMinutes;
int runSeconds;
char buf[21];
unsigned long startMillis;
unsigned long endMillis;
unsigned long allSeconds;


BLYNK_WRITE(V0) { // Switch Widget
  if (param.asInt() == 1) {
    startMillis = millis();  // The key command for starting the count
    Blynk.virtualWrite(V1, "Counting...");  // Display Widget
  } else {
    endMillis = millis();  // The key command for ending the count

    // The key process for displaying the converted duration
    allSeconds = (endMillis - startMillis) / 1000;
    runDays = allSeconds / 86400;
    secsRemaining = allSeconds % 86400;
    runHours = secsRemaining / 3600;
    secsRemaining = allSeconds % 3600;
    runMinutes = secsRemaining / 60;
    runSeconds = secsRemaining % 60;
    sprintf(buf, "Duration: %02d D : %02d H : %02d M : %02d S", runDays, runHours, runMinutes, runSeconds);
    Blynk.virtualWrite(V1, buf);  // Display Widget showing duration the Switch was 
  }
}

8 Likes

#23 - Basic Stepper Motor Control

Who says Blynk can’t control Stepper motors… well, OK, I have said it may require fancy non-blocking timing… so here it is (disclaimer, not all that fancy after all :stuck_out_tongue_winking_eye: )

Yes, it is using the old and decrepit Stepper.h library… only because I was too lazy to learn simple accelStepper commands at this moment :blush:

I am also controlling a 4.29v 1.8deg NEMA 17 stepper with an equally old L298D motor controller… Hey, I works with what I gots :wink:

UPDATE - Chose the commented out commands for ESP8266 (default) or ESP32, both with OTA (no I haven’t mastered #ifndef yet :blush: )

Uses a Slider Widget for speed - Slider V0 set with 0-100 and Send On Release ON (But if you really want it OFF, preferably at around 300-500ms, so you don’t flood the connection unnecessarily).

And a Button Widget for direction - Button V1 set as Switch with 0-1

#define BLYNK_PRINT Serial // This prints to Serial Monitor
//#define BLYNK_DEBUG  // Optional, this enables more detailed prints

////  Pick one Blynk Device Library group or other
////----------
// #include <WiFi.h>  // for ESP32
// #include <WiFiClient.h>  // for ESP32
// #include <BlynkSimpleEsp32.h>  // for ESP32
////----------
#include <ESP8266WiFi.h>  // for ESP8266
#include <BlynkSimpleEsp8266.h>  // for ESP8266
////----------

////  Pick one OTA Library or other
////----------
// #include <ESPmDNS.h>  // For OTA w/ ESP32
////----------
#include <ESP8266mDNS.h>  // For OTA w/ ESP8266
////----------

#include <WiFiUdp.h>  // For OTA
#include <ArduinoOTA.h>  // For OTA

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

BlynkTimer timer;

#include <Stepper.h>
const int stepsPerRevolution = 200;  // change this to fit the number of steps per revolution for your motor

// ESP8266 use GPIO pin designation, not silk-screened labeling
Stepper myStepper(stepsPerRevolution, 5, 4, 0, 2); // ESP8266 - initialize the stepper library for IN1, IN2, IN3, IN4

// ESP32 GPIO/Silk-screened pin designation
//Stepper myStepper(stepsPerRevolution, 15,2,0,4); // ESP32 - initialize the stepper library for IN1, IN2, IN3, IN4

int motorSpeed;
int motorDirection;



void setup() {
  Serial.begin(9600);

  timer.setInterval(10, stepperControl);  // This here is all the fancy timing part... it just updates the stepper control every 5ms

  WiFi.begin(ssid, pass);
  Blynk.config(auth, server, port);
  Blynk.connect();

  ArduinoOTA.setHostname("ESP Blynk Stepper");  // For OTA - Use your own device identifying name
  ArduinoOTA.begin();  // For OTA
}


void loop() {
  Blynk.run();
  timer.run();
  ArduinoOTA.handle();  // For OTA
}



BLYNK_CONNECTED() {
  Blynk.syncVirtual(V0, V1);
}

BLYNK_WRITE(V0) {  // Motor Speed - Slider set with 0-100 and Send On Relese OFF
  motorSpeed = param.asInt();
  myStepper.setSpeed(motorSpeed);
}

BLYNK_WRITE(V1) {  // Motor Direction - Button set as Switch with 0-1
  motorDirection = param.asInt();
}



void stepperControl() {
  if (motorSpeed > 0) {
    if (motorDirection == 0) {  // Rotate Clockwise
      myStepper.step(stepsPerRevolution / 100);
    } else {  // Rotate CounterClockwise
      myStepper.step(-stepsPerRevolution / 100);
    }
  }
}

7 Likes

#24 - Timed Button Widget

Just cuz it keeps getting asked for :stuck_out_tongue_winking_eye: It is an improved & simplified version of my Latch & indicator example in my #12 - Timers Simplified post above.

Set your vPin, dPin and timeout accordingly… And exchange the digitalWrite() for whatever you want to happen for the timed duration

int latchButton;
int latchFlag;

//===== Timeed latching button =====
BLYNK_WRITE(vPin) {  // Button Widget set as switch
  latchButton = param.asInt();
  if (latchButton == 1 && latchFlag == 0) {
    latchFlag = 1;  // Keeps from allowing button press more then once while relay activated
    // ----- Start your timed thing here
    digitalWrite(dPin, HIGH); // Activate digital pin
    // -----
    timer.setTimeout(5000L, []() {  // Timed Lambda Function - Latching Button release after 5 seconds
      // ----- Stop your timed thing here
      digitalWrite(dPin, LOW); // Deactivate digital pin
      // -----
      Blynk.virtualWrite(vPin, 0);  // Reset Latching Button to OFF
      latchFlag = 0;  // resets to allow next interaction
    });  // END Timer Function
  } else {
    if (latchButton == 0 && latchFlag == 1) {  // If you try to tun off the button before time is up
      Blynk.virtualWrite(vPin, 1);  // Restore Latching Button ON until timer is finished
    }
  }
}

If you add in timer ID and some different } else { coding you can make the timer reset if you turn OFF the button before the timer is finished.

If you do nothing in the ON mode and only activate your “thing” once the timeout occurs, you can call this a delayed reaction button… a little more code and you can make it so you MUST hold the button for the timeout to occur

But for now I will leave all that experimenting to you :stuck_out_tongue_winking_eye:

6 Likes

#25 - Das Timed Blinkin’ LED… Without any delay() - AKA Timerception :sleeping::timer_clock:

This is simply just two nested Lambda functions using BlynkTimer and two different timer types to flash a Virtual LED ON for 1 second and Off for 1 second… If this is placed in the void setup() it just repeats in the background… marquee style.

Here it is integrated into a bare bones Blynk Blink Sketch… There should be enough commenting to figure it out from here. LED Widget set to V0

#include <ESP8266WiFi.h>  // for ESP8266
#include <BlynkSimpleEsp8266.h>  // for ESP8266
#define BLYNK_MSG_LIMIT 0  // In theory this disables the "anti-flood governor"... might only work on Local Server

BlynkTimer timer;

char auth[] = "xxxxxxxxxx";  // Auth Token
char ssid[] = "xxxxxxxxxx";  // Your WiFi network name
char pass[] = "xxxxxxxxxx";  // Your WiFi network password
char server[] = "blynk-cloud.com";  // Cloud Server address
int port = 8080;  //  MCU Hardware Device port



void setup() {
  pinMode(2, OUTPUT);  // Setup GPIO2 (D4 the ESP On-Board LED) as an output pin

  // Connect to your WiFi network, then to the Blynk Server
  WiFi.begin(ssid, pass);
  Blynk.config(auth, server, port);
  Blynk.connect();

  // This dual nested timer routine will constantly blink both a Virtual LED and the onboard LED of an ESP8266 Dev Board
  timer.setInterval(2000L, []() {  // Start 1st Timed Lambda Function - Turn ON LED every 2 seconds (repeating)
    timer.setTimeout(1000L, []() {  // Start 2nd Timed Lambda Function - Turn OFF LED 1 second later (once per loop)
      Blynk.virtualWrite(V0, 0);  // Turn Virtual LED OFF
      digitalWrite(2, HIGH); // Turn ESP On-Board LED OFF
    });  // END 2nd Timer Function
    Blynk.virtualWrite(V0, 255);  // Turn Virtual LED ON
    digitalWrite(2, LOW); // Turn ESP On-Board LED ON
  });  // END 1st Timer Function
}



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

So… why…?

Well I have heard that it is too complicated to make or understand the code to blink an LED without using delay() You be the judge :stuck_out_tongue_winking_eye:

Also, because it is a nice, non-blocking (payload depending), simple package of code that can be used to repeatedly do just about anything you want, as many times as you need (E.g. replace the first setInterval() timer with a setTimer() and designate your total loops to run. See - timer.setTimer()

Challenge - I am nesting only two functions here… How many nested lambda timed functions can you make use of? Either for practical or just visual purposes.

8 Likes

#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

#27 - Code solutions for “Secure” Buttons & Switches

I will start with this one and add more in later…

A simple slider set with a range of 0-1, Decimals to #.# and Send on Release ON works just like a spring loaded toggle or slide switch. Then with a 10 “digit” range of 0.0-1.0 You have to commit to the full slide to activate.

You can “slide” it ON and even returns back to OFF if you change your mind and don’t slide all the way or don’t release before sliding back… it only processes if released in the FULL ON position, then it automatically returns to OFF.

As per this example where either a button press or full slide & release will increment the interval…

The last sync command is only required if you actually need your code to actively register the return to OFF.

BLYNK_WRITE(V0) {  // Slider as "secure" Button - Set 0/1 Decimals to #.# and Send on Release ON
  if (param.asInt()) {  // If HIGH
    // Do ON stuff here, or call a function to do it
    Blynk.virtualWrite(V0, 0);  // Resets Slider LOW
    Blynk.syncVirtual(V0);  // Processes Button "release"
  } else {
    Blynk.virtualWrite(V0, 0);  // Resets Slider LOW
  }
}

Add in a non-blocking ‘delay’ timer (before turning OFF) if needed…

BLYNK_WRITE(V0) {  // Slider as "secure" Button - Set 0/1 Decimals to #.# and Send on Release ON
  if (param.asInt()) {  // If HIGH
    // Do ON stuff here, or call a function to do it
    timer.setTimeout(1000L, []() {  // non-blocking delay timer
      Blynk.virtualWrite(V0, 0);  // Resets Slider LOW
      Blynk.syncVirtual(V0);  // Processes Button "release"
    });  // END delay timer
  } else {
    Blynk.virtualWrite(V0, 0);  // Resets Slider LOW
  }
}
3 Likes

#28 - Dual LED Fade/Flasher for both Virtual and Physical LEDs

Here is a simpler? or just more compact Dual LED Fade/Flash that works with both Virtual and physical LEDs. It uses two nested Lambda type Timer Functions with if() logic to determine which timer is running… all in one Arduino function (speed switching aside)

UPDATE EDIT - I made some tweaks and added some 1ms delays in critical spots… it seems to work much nicer now and switch speeds smoothly… at least in my tests.

20190212_192031

image

#define BLYNK_PRINT Serial // This prints to Serial Monitor
#include <ESP8266WiFi.h>  // for ESP8266
#include <BlynkSimpleEsp8266.h>  // for ESP8266

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;

const int blueLEDphysical = 12;  // GPIO ID - AKA D6
const int redLEDphysical = 14;  // GPIO ID - AKA D5
int redLEDvalue;
int blueLEDvalue;
int redblueLEDtimer;
int stepLED = 32;

BlynkTimer timer;



void setup() {
  Serial.begin(115200);  // BLYNK_PRINT data
  pinMode(redLEDphysical, OUTPUT);
  pinMode(blueLEDphysical, OUTPUT);

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

  // "Sacrificial" Timer - Seems to be needed when deleting timers as that will kill first timer created...
  redblueLEDtimer = timer.setTimeout(10L, []() {
    // Do nothing
  });  // END sacrificial Function

}

BLYNK_CONNECTED() {
  Blynk.virtualWrite(V2, 1);  // Set the pulse interval as OFF
  Blynk.syncVirtual(V2);
}



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

BLYNK_WRITE(V2) {
  switch (param.asInt()) {
    case 1:  // OFF
      timer.deleteTimer(redblueLEDtimer);  // Delete timer to have clean start
      Blynk.virtualWrite(V0, 0);  // Virtual LED OFF
      analogWrite(redLEDphysical, 0);  // redLEDphysical OFF
      Blynk.virtualWrite(V1, 0);  // Virtual LED OFF
      analogWrite(blueLEDphysical, 0);  // blueLEDphysical OFF
      break;
    case 2:  // Slow
      timer.deleteTimer(redblueLEDtimer);  // Delete timer to have clean start
      stepLED = 32;  // 8 levels of intensity per fade
      flashRedBlueLED();
      break;
    case 3:  // Medium
      timer.deleteTimer(redblueLEDtimer);  // Delete timer to have clean start
      stepLED = 64;  // 4 levels of intensity per fade
      flashRedBlueLED();
      break;
    case 4:  // Fast
      timer.deleteTimer(redblueLEDtimer);  // Delete timer to have clean start
      stepLED = 128;  // 2 levels of intensity per fade
      flashRedBlueLED();
      break;
  }
}


void flashRedBlueLED() { // Timer controlled alternating fade/flasher routine
  redLEDvalue = 0;  // 1st cycle starting level
  blueLEDvalue = 255;  // 1st cycle starting level
  redblueLEDtimer = timer.setTimer(stepLED / 2, []() {  // 1st cycle Lambda timer function
    Blynk.virtualWrite(V0, redLEDvalue);  // Output to Widget LED
    analogWrite(redLEDphysical, redLEDvalue);  // Output to Physical LED
    delay(1);  // Give a little time for things to settle
    redLEDvalue += stepLED;  // Increment red step
    Blynk.virtualWrite(V1, blueLEDvalue);  // Send value to Widget
    analogWrite(blueLEDphysical, blueLEDvalue);  // Output to Physical LED
    delay(1);  // Give a little time for things to settle
    blueLEDvalue -= stepLED;  // Decrement blue step
    if (blueLEDvalue == -1) {  // End of 1st cycle logic detector
      redLEDvalue = 255;  // 2nd cycle starting level
      blueLEDvalue = 0;  // 2nd cycle starting level
      timer.deleteTimer(redblueLEDtimer);  // Delete timer to have clean start
      redblueLEDtimer = timer.setTimer(stepLED / 2, []() {  // 1st cycle Lambda timer function
        Blynk.virtualWrite(V0, redLEDvalue);  // Output to Widget LED
        analogWrite(redLEDphysical, redLEDvalue);  // Output to Physical LED
        delay(1);  // Give a little time for things to settle
        redLEDvalue -= stepLED;  // Decrement red step
        Blynk.virtualWrite(V1, blueLEDvalue);  // Output to Widget LED
        analogWrite(blueLEDphysical, blueLEDvalue);  // Output to Physical LED
        delay(1);  // Give a little time for things to settle
        blueLEDvalue += stepLED;  // Increment red step
        if (blueLEDvalue == 256) {  // End of 2nd cycle logic detector
          flashRedBlueLED();  // Repeat main function again
        } // END 1st cycle logic
      }, 256 / stepLED); // END 1st Timer Function - calculation determines timer loop count
    } // END 2nd cycle logic
  }, 256 / stepLED); // END 2nd Timer Function - calculation determines timer loop count
}
8 Likes