📥 Required Software & Downloads
Before starting the training, ensure you have downloaded and installed the following tools based on your operating system.
USB Drivers (CH340 & CP210x)
Essential drivers so your computer can recognize the ESP32 board.
Blynk IoT App
The IoT cloud app for your phone. Required for remote control and monitoring of your ESP32 projects.
🛠️ Initial Arduino IDE Setup
Configure Arduino IDE to communicate with ESP IoT boards.
- Open Arduino IDE. Go to File → Preferences.
- In the Additional Board Manager URLs field, paste this configuration URL:
- Go to Tools → Board → Boards Manager. Search for
esp32and click Install. - Go to Sketch → Include Library → Manage Libraries. Search for
Blynkand install "Blynk by Volodymyr Shymanskyy". - Plug your board in. Select ESP32 Dev Module from Tools → Board. Then select the correct COM Port.
☁️ Day 3: ESP32 & Blynk IoT Cloud
Session 3.1: Wi-Fi Provisioning & Cloud Connection
Before coding, we must create a virtual bridge (Template) on Blynk to communicate with our ESP board.
- Go to blynk.cloud and log in. Navigate to Templates.
- Click + New Template. Name it "SmartGreenhouse", select ESP32, and choose WiFi as the connection type.
- Click on Devices → + New Device → From Template. Select your "SmartGreenhouse" template and name your device (e.g., "Group-1-ESP").
- In the device info page, copy the
BLYNK_TEMPLATE_ID,BLYNK_TEMPLATE_NAME, andBLYNK_AUTH_TOKENinto the code below.
"Write a C++ code for an ESP32 using the BlynkSimpleEsp32 library to connect to Wi-Fi. It should define BLYNK_TEMPLATE_ID, BLYNK_TEMPLATE_NAME, and BLYNK_AUTH_TOKEN at the top. Setup should include Serial.begin(115200) and Blynk.begin(). The void loop should just run Blynk.run()."
#define BLYNK_TEMPLATE_ID "TMPLxxxxxx"
#define BLYNK_TEMPLATE_NAME "Device"
#define BLYNK_AUTH_TOKEN "YourAuthToken"
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
char ssid[] = "NetworkName";
char pass[] = "Password";
void setup() {
Serial.begin(115200);
Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);
}
void loop() {
Blynk.run();
}
Change your Wi-Fi credentials in ssid and pass, then upload. Open the Serial Monitor (115200 baud) and you should see "Ready (ping: ...)".
Session 3.2: Level 1 Remote Control (Relays & Pumps)
Now we will control a physical 5V Relay (GPIO 5) using a Virtual Pin (V0) triggered from your phone.
Never power motors or relays directly from the ESP's 3.3V pin. Output pins must receive power from the VIN (5V) pin to avoid burning out the microcontroller.
| Component | Pin | ESP32 Pin | Notes |
|---|---|---|---|
| 5V Relay Module | VCC | VIN (5V) | Requires 5V external power |
| 5V Relay Module | GND | GND | - |
| 5V Relay Module | IN (Signal) | GPIO 5 | digitalWrite(5, HIGH) |
"Extend the previous ESP32 Blynk code. Add a BLYNK_WRITE function for Virtual Pin V0. When V0 receives a '1' from the mobile app, it should turn a 5V Relay connected to GPIO 5 ON (digitalWrite HIGH). When it receives '0', turn it OFF. Remember to set pinMode to OUTPUT in setup()."
#define BLYNK_TEMPLATE_ID "TMPLxxxxxx"
#define BLYNK_TEMPLATE_NAME "Device"
#define BLYNK_AUTH_TOKEN "YourAuthToken"
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
char ssid[] = "NetworkName";
char pass[] = "Password";
#define RELAY_PIN 5 // GPIO 5 on ESP32
// This function triggers instantly when the V0 switch on your phone is pressed
BLYNK_WRITE(V0) {
int buttonState = param.asInt(); // Get value from phone (0 or 1)
if (buttonState == 1) {
digitalWrite(RELAY_PIN, HIGH); // Turn Relay ON
} else {
digitalWrite(RELAY_PIN, LOW); // Turn Relay OFF
}
}
void setup() {
Serial.begin(115200);
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW); // Safe default state: OFF
Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);
}
void loop() {
Blynk.run();
}
- Go to Templates → Datastreams in Blynk Web. Create a new Virtual Pin (V0). Set type to Integer (0-1).
- Go to Web Dashboard, drag a Switch widget, and assign it to Datastream V0.
- Now you can turn the water pump on and off from anywhere in the world!
Session 3.3: Level 2 Analog Data & Visualization (BlynkTimer)
Now we'll read Soil Moisture or Gas Sensor data and visualize it on a Gauge widget on the app. We MUST use BlynkTimer instead of delay() to prevent our device from disconnecting from the cloud.
| Component | Pin | ESP32 Pin | Notes |
|---|---|---|---|
| Soil Moisture Sensor | VCC | 3.3V | — |
| Soil Moisture Sensor | GND | GND | — |
| Soil Moisture Sensor | Analog Out | GPIO 34 (ADC1) | 12-bit: 0–4095 |
"I am using an ESP32 with BlynkSimpleEsp32. I want to read an analog soil moisture sensor connected to GPIO 34. Since I cannot use delay(), write a code using BlynkTimer that reads the analog sensor every 2 seconds using a custom function, and sends that value to Virtual Pin V1 using Blynk.virtualWrite. Include all necessary SSID, Wifi, and Blynk setup."
#define BLYNK_TEMPLATE_ID "TMPLxxxxxx"
#define BLYNK_TEMPLATE_NAME "Device"
#define BLYNK_AUTH_TOKEN "YourAuthToken"
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
char ssid[] = "NetworkName";
char pass[] = "Password";
#define SENSOR_PIN 34 // GPIO 34 (ADC)
BlynkTimer timer;
void sendSoilData() {
int moistureLevel = analogRead(SENSOR_PIN); // Read 0-4095
Blynk.virtualWrite(V1, moistureLevel); // Send to V1 Channel
}
void setup() {
Serial.begin(115200);
Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);
// Timer runs the function every 2000 milliseconds (2 seconds)
// NEVER use delay(2000) inside loop(), it will disconnect Blynk!
timer.setInterval(2000L, sendSoilData);
}
void loop() {
Blynk.run();
timer.run(); // Keeps the timer ticking
}
- Go to Templates → Datastreams. Create a Virtual Pin (V1) named "Soil Moisture", type Integer, Min/Max 0-4095 .
- On the Web Dashboard, drag a Gauge widget and assign it to V1. Put the sensor in dry and wet soil to see the needle move live!
Session 3.4: Level 3 Sensors & Push Notifications
Read from DHT11 (Temp/Humidity) and Flame sensors. Create logic (If/Else) to trigger a physical Buzzer and send a Push Notification to your phone in case of fire or extreme heat.
| Component | Pin | ESP Pin | Notes |
|---|---|---|---|
| DHT11 Temp Module | DATA | GPIO 4 | Code: #define DHTPIN 4 |
| Flame Sensor | DO | GPIO 14 | Returns LOW when flame detected |
| Active Buzzer | + (Long Leg) | GPIO 12 | Code: #define BUZZER_PIN 12 — Note: GPIO 12 is a bootstrap pin. Starts LOW so no boot issues; GPIO 13 is a safe alternative. |
| Sensors/Buzzer | VCC/GND | 3.3V/GND | Provide common grounding |
"Can you create an ESP32 Blynk code that acts as a fire alarm? It should use a DHT11 sensor on GPIO 4 to read temperature and a Flame sensor on GPIO 14 (returns LOW on fire). Use a BlynkTimer running every 2 seconds. In the timer function, if temperature > 35.0 OR flame is LOW, turn ON a buzzer on GPIO 12 and push a notification using Blynk.logEvent('fire_alert', 'Fire!'). Send the temperature to Virtual Pin V2. Include the full Blynk C++ setup."
#define BLYNK_TEMPLATE_ID "TMPLxxxxxx"
#define BLYNK_TEMPLATE_NAME "Device"
#define BLYNK_AUTH_TOKEN "YourAuthToken"
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
#include <DHT.h>
char ssid[] = "NetworkName";
char pass[] = "Password";
#define DHTPIN 4 // GPIO 4
#define DHTTYPE DHT11
#define FLAME_PIN 14 // GPIO 14 (Digital Input)
#define BUZZER_PIN 12 // GPIO 12 (Digital Output)
DHT dht(DHTPIN, DHTTYPE);
BlynkTimer timer;
void sensorAlgorithm() {
float temp = dht.readTemperature();
int flameStatus = digitalRead(FLAME_PIN); // LOW means FIRE
Blynk.virtualWrite(V2, temp); // Send Temp to V2 channel on dashboard
// If temp > 35 OR flame is detected:
if (temp > 35.0 || flameStatus == LOW) {
digitalWrite(BUZZER_PIN, HIGH); // Sound Alarm!
Blynk.logEvent("fire_alert", "Warning! Fire or Extreme Heat!"); // Phone Notification
} else {
digitalWrite(BUZZER_PIN, LOW); // Safe
}
}
void setup() {
Serial.begin(115200);
pinMode(FLAME_PIN, INPUT);
pinMode(BUZZER_PIN, OUTPUT);
dht.begin();
Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);
timer.setInterval(2000L, sensorAlgorithm);
}
void loop() {
Blynk.run();
timer.run();
}
- Create a V2 Datastream (Double, 0-60 Min/Max) for Temperature and show it on a Labeled Value widget.
- Go to Templates → Events. Create a new event. Name: Fire Alert, Event Code:
fire_alert, Type: Warning. Enable Push notifications. - Rate Limit: Blynk Free plan allows max 100 events/day. Each
Blynk.logEvent()call consumes 1 event. Our 2-second timer means the alarm fires repeatedly — in production you should add a cooldown flag.
🌿 Day 4: Autonomous IoT Systems
Session 4.1 & 4.2: Smart Greenhouse & Autonomous Logic
Combine DHT11, Soil Moisture, LDR, Relay, and Pump into one system. We will code an "Auto/Manual" state machine. If on Auto, the ESP decides when to water the plant based on soil readings. If Manual, you control it from the phone. All data is logged in a SuperChart.
| Component | Pin | ESP32 Pin | Notes |
|---|---|---|---|
| DHT11 Data | DATA | GPIO 4 | Temp + Humidity |
| Soil Moisture | Analog Out | GPIO 34 | Analog Reading |
| 5V Relay | IN | GPIO 5 | Pump trigger |
| 5V Relay Power | VCC | VIN (5V) | NEVER power from 3.3V |
"Write an advanced ESP32 Blynk code for an autonomous greenhouse. It must use a 5V relay (Pump/GPIO 5) and an analog soil moisture sensor (GPIO 34). Implement an Auto/Manual state machine using Blynk Virtual Pin V2 as a mode switch. When V2=1 (Auto Mode), check soil every 3 seconds using BlynkTimer; if moisture < 1500, turn pump ON, else OFF. When V2=0 (Manual Mode), the pump is only controlled by a button on Virtual Pin V0. Send soil moisture to Virtual Pin V1."
#define BLYNK_TEMPLATE_ID "TMPLxxxxxx"
#define BLYNK_TEMPLATE_NAME "Device"
#define BLYNK_AUTH_TOKEN "YourAuthToken"
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
char ssid[] = "NetworkName";
char pass[] = "Password";
#define PUMP_PIN 5 // GPIO 5
BlynkTimer timer;
int modeStatus = 0; // 0=Manual, 1=Auto
int dryThreshold = 1500;
// V2 Switch (Auto/Manual Mode Selector)
BLYNK_WRITE(V2) {
modeStatus = param.asInt();
}
// V0 Manual Watering Button
BLYNK_WRITE(V0) {
if (modeStatus == 0) { // ONLY works in Manual mode
digitalWrite(PUMP_PIN, param.asInt());
}
}
void autoGreenhouseLogic() {
int soilMoisture = analogRead(34);
Blynk.virtualWrite(V1, soilMoisture); // Send data to SuperChart on V1
if (modeStatus == 1) { // If system is in AUTO mode, let the code decide
if (soilMoisture < dryThreshold) {
digitalWrite(PUMP_PIN, HIGH); // Soil is dry: Turn pump ON
} else {
digitalWrite(PUMP_PIN, LOW); // Soil is wet: Turn pump OFF
}
}
}
void setup() {
Serial.begin(115200);
pinMode(PUMP_PIN, OUTPUT);
digitalWrite(PUMP_PIN, LOW);
Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);
timer.setInterval(3000L, autoGreenhouseLogic);
}
void loop() {
Blynk.run();
timer.run();
}
- Create a V2 Datastream (Integer, 0-1) named "Mode Selector". Put a Switch widget on it. (On = AUTO, Off = MANUAL).
- Add a SuperChart widget and add Datastreams V1, V3, V4 into it to log history.
Session 4.3: Edge Cases - The Connection Watchdog
What happens if your WiFi router dies while the relay is ON? The pump will run forever and flood your greenhouse. We must build fail-safes.
"Add a fail-safe 'connection watchdog' function to my ESP32 Blynk code. Create a BlynkTimer running every 10 seconds. If Blynk.connected() is false (WiFi routing failed), immediately turn the water pump (GPIO 5) OFF so it doesn't flood the greenhouse while offline, then attempt Blynk.connect()."
void connectionWatchdog() {
if(!Blynk.connected()){
// CRITICAL: WiFi dropped, cannot receive commands from phone.
// Turn off dangerous hardware (pumps, heaters) to prevent disasters.
digitalWrite(PUMP_PIN, LOW);
Serial.println("Connection lost, motors stopped! Reconnecting...");
Blynk.connect();
}
}
// Inside your main setup():
void setup() {
// ... other setups ...
timer.setInterval(10000L, connectionWatchdog);
}