Venetian blinds open and close by turning a rod that tilts all the slats at once. A servo can turn that rod. In this lesson you control the tilt from a slider in the Blynk app, and an automatic mode reads the light outside: it opens the slats in the morning, half-closes them in strong sun and closes them at night.
What you'll learn
- How to drive a real mechanism with a servo
- How to move a servo slowly so the mechanism isn't jerked
- How to combine a manual slider and an automatic rule
- How to keep the app in step when the device moves on its own
What you need
- ESP32 board, expansion board and USB cable (ESP32 IoT Starter Kit)
- Servo motor (ESP32 IoT Starter Kit)
- Photoresistor module (45-in-1 Sensor Kit)
- A free Blynk account and the Blynk IoT app on a phone
- A 2.4 GHz Wi-Fi network
- A model blind: drinking straws taped to a skewer, or a real blind with a tilt rod
- Breadboard and jumper wires (ESP32 IoT Starter Kit)
Make it real: tape six drinking straws side by side onto a wooden skewer, and tape the skewer to the servo horn so the servo tilts all the straws at once. On a real blind, connect the horn to the tilt rod with a piece of plastic tube.
Note: a small servo can only turn light blinds. If the rod is stiff, the servo will buzz and get warm; in that case keep to the model.
Wiring

| From | To |
|---|---|
| Servo orange / yellow wire | ESP32 GPIO 13 |
| Servo red wire | 5V |
| Servo brown / black wire | GND |
| Photoresistor module S | ESP32 GPIO 34 |
| Photoresistor module + and − | 3V3 and GND |
Sensor modules from different makers can label and order their pins differently. Always follow the labels printed on your module.
Place the photoresistor near the window, facing outside, where the blind's own shadow doesn't fall on it.
Set up Blynk
In the Blynk console, create a new template called Window blinds (hardware ESP32, connection type Wi-Fi) and add these datastreams. Lesson 1 of this path shows each step in detail.
| Virtual pin | Name | Data type | Range | Phone widget |
|---|---|---|---|---|
| V0 | Tilt | Integer | 0 – 100, units % | Slider |
| V1 | Auto mode | Integer | 0 – 1 | Button (switch mode) |
| V2 | Daylight | Integer | 0 – 100, units % | Gauge |
| V3 | Status | String | n/a | Value Display |
Save the template, create a new device from it and copy its three BLYNK_… lines. In the phone app, open the device, tap the wrench icon and add a Slider (V0), a Button in switch mode (V1), a Gauge (V2) and a Value Display (V3). Link each widget to its datastream.

The sketch
Install the ESP32Servo library (by Kevin Harrington).
Replace the three BLYNK_… lines at the top with the ones from your device's Device info page, and add your Wi-Fi name and password (2.4 GHz only). The BLYNK_… lines must stay above #include <BlynkSimpleEsp32.h>.
#define BLYNK_TEMPLATE_ID "YOUR_TEMPLATE_ID"
#define BLYNK_TEMPLATE_NAME "Window blinds"
#define BLYNK_AUTH_TOKEN "YOUR_AUTH_TOKEN"
#define BLYNK_PRINT Serial // show connection messages in the Serial Monitor
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
#include <ESP32Servo.h>
char ssid[] = "YOUR_WIFI_NAME";
char pass[] = "YOUR_WIFI_PASSWORD";
const int SERVO_PIN = 13;
const int LIGHT_PIN = 34;
const int CLOSED_ANGLE = 10; // slats closed
const int OPEN_ANGLE = 100; // slats open (horizontal)
Servo blind;
BlynkTimer timer;
bool autoMode = false;
int tilt = 100; // 0 = closed, 100 = open
int currentAngle = OPEN_ANGLE;
void moveTo(int percent) {
tilt = constrain(percent, 0, 100);
int target = map(tilt, 0, 100, CLOSED_ANGLE, OPEN_ANGLE);
blind.attach(SERVO_PIN, 500, 2400);
while (currentAngle != target) { // slowly, so the blind isn't jerked
currentAngle += (target > currentAngle) ? 1 : -1;
blind.write(currentAngle);
delay(12);
}
delay(200);
blind.detach(); // no buzzing while it holds
Blynk.virtualWrite(V0, tilt); // keep the slider in step
}
BLYNK_WRITE(V0) { // slider: manual control
autoMode = false;
Blynk.virtualWrite(V1, 0);
moveTo(param.asInt());
Blynk.virtualWrite(V3, "Manual");
}
BLYNK_WRITE(V1) { autoMode = param.asInt(); }
BLYNK_CONNECTED() {
Blynk.syncVirtual(V1);
Blynk.virtualWrite(V0, tilt);
}
void checkDaylight() {
int light = map(analogRead(LIGHT_PIN), 0, 4095, 100, 0); // bright = high %
Blynk.virtualWrite(V2, light);
if (!autoMode) return;
int wanted = tilt;
if (light < 15) wanted = 0; // night: closed
else if (light > 80) wanted = 40; // strong sun: half closed
else if (light > 25 && light < 70) wanted = 100; // normal daylight: open
// between the limits nothing changes, so the blind doesn't flap
if (wanted != tilt) {
moveTo(wanted);
Blynk.virtualWrite(V3, wanted == 0 ? "Auto: night" : (wanted == 100 ? "Auto: day" : "Auto: sun"));
}
}
void setup() {
Serial.begin(115200);
blind.setPeriodHertz(50);
moveTo(100);
Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);
timer.setInterval(30000L, checkDaylight); // every 30 seconds
}
void loop() {
Blynk.run();
timer.run();
}
How it works
The slider and the automatic rule both end up in moveTo(), which turns a percentage into a servo angle and moves there one degree at a time. Moving slowly protects the blind's mechanism, and switching the servo off with detach() afterwards stops it from buzzing while it holds the slats. Every move writes the new value back to V0, so the slider in the app always shows where the blind really is, even when automatic mode moved it.
Touching the slider switches automatic mode off; otherwise the next daylight check would undo your choice. In automatic mode the rule has gaps between its limits: between 70 and 80 % light, or between 15 and 25 %, it simply leaves the blind where it is. Without those gaps, a passing cloud could open and close the blind again and again. Checking only every 30 seconds helps too.
Try this next
- Close the blinds at a fixed time in the evening with the internet clock.
- Add a temperature sensor and close them when the room gets too warm.
- Add a Blynk event that tells you when automatic mode closed the blinds.
Troubleshooting
-
The device shows "Offline" in the app: check the Serial Monitor at 115200 baud. "Invalid auth token" means the
BLYNK_AUTH_TOKENline is wrong; if it never connects, check the Wi-Fi name and password, and that your network is 2.4 GHz. -
Open and closed are the wrong way round: swap the values of
CLOSED_ANGLEandOPEN_ANGLE. - The servo buzzes and gets warm: the rod is too stiff for the servo. Use the straw model.
- Automatic mode does nothing: it only checks every 30 seconds. Cover the photoresistor and wait.
- The ESP32 restarts when the servo moves: servos draw bursts of current. Use a good USB port or a powered hub, and check that the servo's red wire is on 5V.