Tilt window blinds from your phone

A servo turns the rod of a venetian blind (or a model of one): set the angle with a slider in Blynk, or let automatic mode follow the daylight.
  • Level:Advanced
  • Duration: 1 h
  • Ages 13+
  • Platform: ESP32

Tools for this lesson

Helpful for this build. Open a tool to see tips and more projects that use it.

Tilt window blinds from your phone – EEMENTOR STEM™ lesson

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

Breadboard wiring diagram: Tilt window blinds from your phone
Breadboard view. Check each connection against the wiring table below.
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.

Example screen for: Tilt window blinds from your phone
Example screen with sample values. Yours may look different.

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_TOKEN line 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_ANGLE and OPEN_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.

Build it yourself

Everything used in this lesson comes in one kit, with parts tested by our engineers.

ESP32 IoT Starter Kit | Arduino IDE Compatible | Free Tutorials $57.00

Shop the kit