Window Blind Remote Control

This unit will adjust, open/close window blinds using remote control. Commands are sent from a mobile phone using wifi.
20
59
1
1496
updated December 21, 2020

Description

PDF

This unit will adjust, open/close window blinds using remote control. Commands are sent from a mobile phone using wifi. To prevent damage endstops are provided to set the fully open and fully closed positions.

Note:

This project is very much a prototype, has room for improvement and not really designed to be released into the wild. However some have shown interest in making it so hopefully this all makes sense.

Print instructions

The unit contains an ESP32 Devkit controller, DRV8833 motor driver, 6V 6RPM Worm drive motor, 3x leds, 2x microswitches and 2x momentary push button switches. In addition you will need brass inserts M3 x 5mm x 5mm to join components etc, M3 + M2 Cap screws, M4 hex drive long grubscrews and a suitable shaft coupler. Everything from eBay.

Also window blind cord/chain purchased from amazon. Small rubber bands to fix couplings. I used black dreadlock bands from eBay.

Please note:

I create fixing holes 5.3mm diameter to accept the 5mm brass inserts. On my machine this allows easy insertion and prevents rotation. It is possible that your printer may be different so please purchase the inserts first and make a test piece to check.

The inserts are fixed using an M3 hex bolt which pulls them into the hole. If you add a 3mm bearing under the head it spreads the load and makes it much easier to insert. If you need to reprint a piece the inserts can be gently tapped out using an M3 bolt.

Construction:

Cord drive wheel:

This is constructed from 3 components. The cog wheel is printed in two parts to avoid supports and screwed together. The coupler is NOT printed, it is a standard M6 aluminium shaft coupler approx 14mm diameter. The coupler is an interference fit onto the wheel and the clamp screw holes aligned. Use 2x M4 hex grub screws through the wheel until they are visible in the coupler. This now locks the two components together and prevents rotation. Worth remembering this combination as it has proved useful for other projects.

Main:

Fit brass inserts as indicated in the pictures. Do not overtighten, the interference fit is to prevent rotation.

Refer to the exploded pictures and start with the motor bracket.

Add microswitches and guides to side panels and fix all to base.

Rotate motor shaft so flat is facing up. Fit cord wheel, align so that pull cord passes through guides and onto wheel in a straight line.

Attach led plate to top cover and fit to side plates.

Attach component plate to base plate.

Wiring:

I have included 2x cable routes through the base to allow simple cable routing. ESP32 pin numbers in code.

You need:

Power Led
Open Led
Close Led
Open Microswitch
Closed Microswitch
Common GND for above
Manual Open push button
Manual Close push button

Motor +
Motor -

So 8 wires in total.
Manual buttons are fixed to the case and wired directly to the ESP32.

ESP to Motor driver: (pin numbers in code)

Control 1
Control 2
5V (ESP32 pin has 5V available from USB input)
GND
Enable
Motor 1
Motor 2

Check operation of microswitches, you may need to bend the actuator arms slightly.

Installation:

Mounting options were limited, the window sill is plastic and I would not be popular if I drilled into it. The mounting block sits under the sill and is screwed into the wall. The main unit attaches using 2x M3 screws into captive inserts.

You can replace the existing cord/chain which will make it neater. However it still may be worth adding to existing to prove the operation first.

Feed around 1m chain through cord wheel.

Pull down existing blind cord to establish fully open position.

Back off slightly and fit end stop in left cup.

Use cord connector to splice new cord onto existing, leave some slack.

Cut out slack and fit inline coupler.

Repeat for closing side.

Misc:

As this is a prototype I did not want to solder components to a board so I made a couple of verostrip carriers with headers. Each has a printed carrier plate to simplify installation. The headers take standard breadboard patch wires.

The box cover is probably bigger than required but I needed plenty of space for the patch wires. If you solder direct then the height may be reduced by say 20mm. Let me know if you need a new stl.

Software:

Please follow this info to setup the ESP32 and allow programming via Arduino IDE.

https://dronebotworkshop.com/esp32-intro/

Remember to add your wifi details !!

Code:

/*
Rui Santos
Complete project details at http://randomnerdtutorials.com

Modified by Pat Cooper

*/

// Load Wi-Fi library

include <WiFi.h>

// Replace with your network credentials
const char ssid = "------------";
const char
password = "-------------";

// Set web server port number to 80
WiFiServer server(80);

// Variable to store the HTTP request
String header;

// Auxiliar variables to store the current output state
String output21State = "off"; // power
String output32State = "off"; // open
String output33State = "off"; // close

// Assign output variables to GPIO pins
//const int output2 = 2;
int ol = 0;
int cl = 0;
int mc = 0;
int mo = 0;
const int close_led = 12; // red
const int power_led = 14; // blue
const int open_led = 27; // green
const int manual_close = 16;
const int manual_open = 17;
const int closelimit = 18;
const int openlimit = 19;
const int output21 = 21;
const int output32 = 32;
const int output33 = 33;

// Current time
unsigned long currentTime = millis();
// Previous time
unsigned long previousTime = 0;
// Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000;

void setup() {
Serial.begin(115200);
pinMode(close_led, OUTPUT);
pinMode(power_led, OUTPUT);
pinMode(open_led, OUTPUT);
pinMode(manual_close, INPUT_PULLUP);
pinMode(manual_open, INPUT_PULLUP);
pinMode(closelimit, INPUT_PULLUP);
pinMode(openlimit, INPUT_PULLUP);
pinMode(output21, OUTPUT);
pinMode(output32, OUTPUT);
pinMode(output33, OUTPUT);

digitalWrite(output32, HIGH);
digitalWrite(output33, HIGH);

delay(3000);

digitalWrite(close_led, LOW);
digitalWrite(power_led, LOW);
digitalWrite(open_led, LOW);
digitalWrite(output21, LOW);
digitalWrite(output32, LOW);
digitalWrite(output33, LOW);

// test led's
digitalWrite(close_led, HIGH);
delay(100);
digitalWrite(power_led, HIGH);
delay(100);
digitalWrite(open_led, HIGH);
delay(100);

digitalWrite(close_led, LOW);
delay(100);
digitalWrite(power_led, LOW);
delay(100);
digitalWrite(open_led, LOW);

// Connect to Wi-Fi network with SSID and password
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// Print local IP address and start web server
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
server.begin();
}

void loop(){

  ol = digitalRead(openlimit);
  cl = digitalRead(closelimit);
  mo = digitalRead(manual_open);
  //Serial.println(mo);
  mc = digitalRead(manual_close);
  //Serial.println(mc);

  if (ol == 1) {
    digitalWrite(32, LOW);
    Serial.println("Warning Open Limit reached");
  }
  if (cl == 1) {
    digitalWrite(33, LOW);
    Serial.println("Warning Closed Limit reached");
  }
  if (mc == 0) {              // detect manual closing switch
    digitalWrite(21,HIGH);
    digitalWrite(power_led, HIGH);
    digitalWrite(32,HIGH);
    digitalWrite(close_led, HIGH);
    digitalWrite(open_led, LOW);
    Serial.println("Closing");
    delay(100);
    digitalWrite(32,LOW);
    digitalWrite(close_led, LOW);

  }
  if (mo == 0) {              // detect manual opening switch
    digitalWrite(21, HIGH);
    digitalWrite(power_led, HIGH);
    digitalWrite(33, HIGH);
    digitalWrite(open_led, HIGH);
    digitalWrite(close_led, LOW);
    Serial.println("Opening");
    delay(100);
    digitalWrite(33, LOW);
    digitalWrite(open_led, LOW);
  }

  if ((mo == 0) && (mc == 0)) { // shut down power and reset manual switches
    digitalWrite(21, LOW);
    digitalWrite(32, LOW);
    digitalWrite(33, LOW);
    digitalWrite(open_led, LOW);
    digitalWrite(close_led, LOW);
    digitalWrite(power_led, LOW);
    delay(3000);
  }

WiFiClient client = server.available(); // Listen for incoming clients

if (client) {

// If a new client connects,
currentTime = millis();
previousTime = currentTime;
Serial.println("New Client.");          // print a message out in the serial port
String currentLine = "";                // make a String to hold incoming data from the client
while (client.connected() && currentTime - previousTime <= timeoutTime) {  // loop while the client's connected
  currentTime = millis();
  if (client.available()) {             // if there's bytes to read from the client,
    char c = client.read();             // read a byte, then
    Serial.write(c);                    // print it out the serial monitor
    header += c;
    if (c == '\n') {                    // if the byte is a newline character
      // if the current line is blank, you got two newline characters in a row.
      // that's the end of the client HTTP request, so send a response:
      if (currentLine.length() == 0) {
        // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
        // and a content-type so the client knows what's coming, then a blank line:
        client.println("HTTP/1.1 200 OK");
        client.println("Content-type:text/html");
        client.println("Connection: close");
        client.println();            

        // turns the GPIOs on and off

          if (header.indexOf("GET /21/on") >= 0) { // power
          Serial.println("GPIO 21 on");
          output21State = "on";
          digitalWrite(output21, HIGH);
          digitalWrite(power_led, HIGH); 

        } else if (header.indexOf("GET /21/off") >= 0) {
          Serial.println("GPIO 21 off");
          output21State = "off";
          output32State = "off";
          output33State = "off";
          digitalWrite(output21, LOW);
          digitalWrite(power_led, LOW);
          digitalWrite(output32, LOW);    // disable open
          digitalWrite(open_led, LOW);  
          digitalWrite(output33, LOW);    // disable close
          digitalWrite(close_led, LOW);          



        } else if (header.indexOf("GET /32/on") >= 0) { // open  
          Serial.println("GPIO 32 on");

          if ((output32State = "on") && (output21State = "on")) {         
          digitalWrite(output32, HIGH);   // enable open 
          digitalWrite(open_led, HIGH);                  
          output33State = "off";          // flag close disabled       
          digitalWrite(output33, LOW);    // disable close
          digitalWrite(close_led, LOW);
          }

        } else if (header.indexOf("GET /32/off") >= 0) {
          Serial.println("GPIO 32 off");
          output32State = "off";
          digitalWrite(output32, LOW);    // disable open
          digitalWrite(open_led, LOW);
          output33State = "off";          // flag close disabled
          digitalWrite(output33, LOW);    // disable close
          digitalWrite(close_led, LOW);



        } else if (header.indexOf("GET /33/on") >= 0) { // close
          Serial.println("GPIO 33 on");

          if ((output33State = "on") && (output21State = "on")) { 
          digitalWrite(output33, HIGH);   // enable close 
          digitalWrite(close_led, HIGH);                     
          output32State = "off";          // flag open disabled
          digitalWrite(output32, LOW);    // disable open
          digitalWrite(open_led, LOW);
          } 

        } else if (header.indexOf("GET /33/off") >= 0)  {
          Serial.println("GPIO 33 off");
          output33State = "off";
          digitalWrite(output33, LOW);    // disable close
          digitalWrite(close_led, LOW);
          output32State = "off";          // flag open disabled
          digitalWrite(output32, LOW);    // disable open
          digitalWrite(open_led, LOW);

        }


        // Display the HTML web page
        client.println("<!DOCTYPE html><html>");
        client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
        client.println("<link rel=\"icon\" href=\"data:,\">");
        // CSS to style the on/off buttons 
        // Feel free to change the background-color and font-size attributes to fit your preferences
        client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
        client.println(".button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px;");
        client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
        client.println(".button2 {background-color: #555555;}</style></head>");

        // Web Page Heading
        client.println("<body><h1>Blind Controller</h1>");
        client.println("<body><h2>Press Power Button First</h2>");

        // Display current state, and ON/OFF buttons for GPIO 21 - Power relay 
       // client.println("<p>GPIO 21 - State " + output21State + "</p>");
        // If the output21State is off, it displays the ON button       
        if (output21State=="off") {
          client.println("<p><a href=\"/21/on\"><button class=\"button\">Power</button></a></p>");
        } else {
          client.println("<p><a href=\"/21/off\"><button class=\"button button2\">Power</button></a></p>");
        }

        // Display current state, and ON/OFF buttons for GPIO 32  
       // client.println("<p>GPIO 32 - State " + output32State + "</p>");
        // If the output32State is off, it displays the ON button       
        if (output32State=="off") {
          client.println("<p><a href=\"/32/on\"><button class=\"button\">Open</button></a></p>");
        } else {
          client.println("<p><a href=\"/32/off\"><button class=\"button button2\">Open</button></a></p>");
        } 
           client.println();   
        // Display current state, and ON/OFF buttons for GPIO 33  
       // client.println("<p>GPIO 33 - State " + output33State + "</p>");
        // If the output33State is off, it displays the ON button       
        if (output33State=="off") {
          client.println("<p><a href=\"/33/on\"><button class=\"button\">Close</button></a></p>");
        } else {
          client.println("<p><a href=\"/33/off\"><button class=\"button button2\">Close</button></a></p>");
        }
        client.println("</body></html>");

        // The HTTP response ends with another blank line
        client.println();
        // Break out of the while loop
        break;
      } else { // if you got a newline, then clear currentLine
        currentLine = "";
      }
    } else if (c != '\r') {  // if you got anything else but a carriage return character,
      currentLine += c;      // add it to the end of the currentLine
    }

  }

}

// Clear the header variable
header = "";
// Close the connection
client.stop();
Serial.println("Client disconnected.");
Serial.println("");

}
}

End of text

Model origin

The author hasn't provided the model origin yet.

License


Highlighted models from creator

View more