Introduction: Motorized Pulldown Curtain (Phone & Radio Controlled)

I pull my curtain up and down a couple of times a day. If I watch a movie I pull it down and then, I pull it up to get better lighting. I also pull it down when I go to sleep and I pull it up again when I wake up. I want this process to be automatic, if my curtain rises before I wake up, it will be easier for me to wake up when the clock goes off. Just like those night lights that lights up before you wake up this can do the same but with the sun as a source.

If you are like me and would like to have your home automated, you might also have considered buying motorized Curtains. But if you have, then you have also realized that they cost a considerable amount.

Therefore, I have decided to make my own motorized curtain. This project will be about modding an existing IKEA curtain, adding a motor to it and writing some code. Without further ado, let's begin!

Step 1: How It Should Work

These two pictures should give you an idea about how I wanted it to work. What they do not tell you is that the manual-control for up and down can be used at any time (even in the initial phase). And the external control sends "requests", you might not always be able to see the curtain, or you might have made it so the phone sends requests automatically.

For example you push on the phone that you want it to go up, it will move up if it is in the down position and it will do nothing if it is already up. This makes it so you won't need to think about witch button you push and you can also make it so it sends a request to move up at 8:30 in the morning for example.

In this case the external control is a NodeMCU controlled by a phone. But you could choose to use another Arduino with an SMS-shield instead if that would be a better solution for you.

The curtain will work with only a remote controller so if you do not need the "phone control" feature you could skip it, the code that I provide will still work.

Step 2: Tools & Supplies

For this project we will need some tools.

Tools

  • Drill-bit
  • Screwdriver
  • Computer
  • Soldering Iron
  • Crimp tool
  • Wire Strippers
  • Glue gun
  • Electrical tape

Step 3: Parts

Parts

  • 1: Pulldown Curtain (that fits the window, IKEA is one supplier of these).

  • 1: Motor(The one I use is a servo-motor, with the servo
    functionality removed. It is supplied with good plastic mounts, this makes it easy to mount it to the curtain).

  • 2: Relays (You could also use power transistors for this if you want).

  • 1: 5V power supply. (Do not buy a "fake" power supply of ebay
    [or any other seller], instead wait for a sale in one of your local stores).

  • 1: Arduino

  • 1: NodeMCU
  • 1: Reflective IR Sensor
  • 1: 433MHz Reciever(will be used to take commands from remote).

  • 1: Radio remote. (I recommend "Livolo Mini Remote Controller"
    only because it is the one I will be using in this project and I will provide code that support this remote).

  • 1: Project Box

  • 1: Switch (For manual control).

  • 2: Zip Ties (Used to hold the motor onto the L-shaped mounts)

Step 4: Code for the Curtain

You do not have to change anything in the code for the Arduino (RullgardinV3.3English) but if you want to be able to use your phone to control the curtain and set timers for when it should rise in the morning and roll down in the evening. Then you will need to change at least two things in the code for the NodeMCU board (ESP8266_CurtainCompanion) I have marked these two rows and one of them is the authentication token for your project in the Blynk app on your phone. The other one is the name and password of your Wi-Fi connection.

The code for this project is quite long, please download them if you want to take a look.

/**
 * This code is for controlling a curtain with a 433MHz radio controller and optionally,
 * also with the help of an external requesting source.
 * 
 * The communication with requests will use pin 5 & 6 on the micro controller,
 * remember to connect both devices grounds together, or the requests won’t work.
 */

//---------------------Buzzer------------------
//These defines sets the notes, with its corresponding frequencies.

// NB: ALL NOTES DEFINED WITH STANDARD ENGLISH NAMES, EXCEPT FROM "A" 
//THAT IS CALLED WITH THE ITALIAN NAME "LA" BECAUSE A0,A1...ARE THE ANALOG PINS ON ARDUINO.
// (Ab IS CALLED Ab AND NOT LAb)
#define	C0 16.35
#define	Db0	17.32
#define	D0	18.35
#define	Eb0	19.45
#define	E0	20.60
#define	F0	21.83
#define	Gb0	23.12
#define	G0	24.50
#define	Ab0	25.96
#define	LA0	27.50
#define	Bb0	29.14
#define	B0	30.87
#define	C1	32.70
#define	Db1	34.65
#define	D1	36.71
#define	Eb1	38.89
#define	E1	41.20
#define	F1	43.65
#define	Gb1	46.25
#define	G1	49.00
#define	Ab1	51.91
#define	LA1	55.00
#define	Bb1	58.27
#define	B1	61.74
#define	C2	65.41
#define	Db2	69.30
#define	D2	73.42
#define	Eb2	77.78
#define	E2	82.41
#define	F2	87.31
#define	Gb2	92.50
#define	G2	98.00
#define	Ab2	103.83
#define	LA2	110.00
#define	Bb2	116.54
#define	B2	123.47
#define	C3	130.81
#define	Db3	138.59
#define	D3	146.83
#define	Eb3	155.56
#define	E3	164.81
#define	F3	174.61
#define	Gb3	185.00
#define	G3	196.00
#define	Ab3	207.65
#define	LA3	220.00
#define	Bb3	233.08
#define	B3	246.94
#define	C4	261.63
#define	Db4	277.18
#define	D4	293.66
#define	Eb4	311.13
#define	E4	329.63
#define	F4	349.23
#define	Gb4	369.99
#define	G4	392.00
#define	Ab4	415.30
#define	LA4	440.00
#define	Bb4	466.16
#define	B4	493.88
#define	C5	523.25
#define	Db5	554.37
#define	D5	587.33
#define	Eb5	622.25
#define	E5	659.26
#define	F5	698.46
#define	Gb5	739.99
#define	G5	783.99
#define	Ab5	830.61
#define	LA5	880.00
#define	Bb5	932.33
#define	B5	987.77
#define	C6	1046.50
#define	Db6	1108.73
#define	D6	1174.66
#define	Eb6	1244.51
#define	E6	1318.51
#define	F6	1396.91
#define	Gb6	1479.98
#define	G6	1567.98
#define	Ab6	1661.22
#define	LA6	1760.00
#define	Bb6	1864.66
#define	B6	1975.53
#define	C7	2093.00
#define	Db7	2217.46
#define	D7	2349.32
#define	Eb7	2489.02
#define	E7	2637.02
#define	F7	2793.83
#define	Gb7	2959.96
#define	G7	3135.96
#define	Ab7	3322.44
#define	LA7	3520.01
#define	Bb7	3729.31
#define	B7	3951.07
#define	C8	4186.01
#define	Db8	4434.92
#define	D8	4698.64
#define	Eb8	4978.03
// DURATION OF THE NOTES 
#define BPM 120    //  you can change this value changing all the others
#define H 2*Q //half 2/4
#define Q 60000/BPM //quarter 1/4 
#define E Q/2   //eighth 1/8
#define S Q/4 // sixteenth 1/16
#define W 4*Q // whole 4/4
//---------------------Buzzer End-----------------


//---------------------For Radio------------------
#define SIGNAL_IN 0 // INTERRUPT 0 = DIGITAL PIN 2 - use the interrupt number in attachInterrupt

volatile byte impulse = 0; // kolejny puls
volatile int bufor[53];
volatile boolean header = false;
volatile unsigned long StartPeriod = 0; // set in the interrupt
volatile boolean stop_ints = false;
//---------------------For Radio End---------------

// The pins for the relays, controlls the motors
int relay1 =  9;
int relay2 =  10;

// The IR sensor, registers when the curtain is up/down.
int sensor  = 8;

// The buzzer, it plays sounds when buttons on the radio is pushed,
// it also playes the imperial march from star wars.
int Buzzer  = 11;

// Variables to keep track of the buzzer.
int ShouldBuzzerPlay = 0;
int CButtonUsed =0;

// This is for the manual-control, activates when pulled low.
int relay1Activate = 3;
int relay2Activate = 4;

// These is for the external requesting source,
// It could be an SMS-shield or an NodeMCU for example.
int SmsUp = 5; //want to go up
int SmsDown = 6; //want to go down

// These are more variables to help keep track of
// what is happening and what has hapened.
int UpOrDown = 0;
int ChooseUpOrDown = 0;
int CButtonArmed = 0;
int CButtonPushedTimes = 0;

long previousMillis = 0;

// This variable will stop the motor if it takes
// to long time to reach the sensor.
long interval = 12000;

int BreakIfNotOne = 1;

/**
 * Set inputs and outputs.
 */
void setup()
{
  pinMode(Buzzer, OUTPUT);
  pinMode(12, OUTPUT);       
  digitalWrite(12,LOW);
  
  attachInterrupt(SIGNAL_IN, calcInput, CHANGE);
  pinMode(13, OUTPUT);
  pinMode(relay1, OUTPUT);
  pinMode(relay2, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(sensor, INPUT);
  pinMode(SmsUp, INPUT);
  pinMode(SmsDown, INPUT);
  pinMode(relay1Activate, INPUT);
  pinMode(relay2Activate, INPUT);
  
  Serial.begin(9600);
  digitalWrite(relay1,HIGH);
  digitalWrite(relay2,HIGH);
  digitalWrite(relay1Activate,HIGH);
  digitalWrite(relay2Activate,HIGH);
  digitalWrite(7,HIGH);
  digitalWrite(SmsUp,HIGH);
  digitalWrite(SmsDown,HIGH);

  Serial.print("Starting up");
}

/**
 * The main loop
 */
void loop()
{
    //Listen for requests from external source, sms or phone.
      if(digitalRead(SmsDown) == LOW){
        while(digitalRead(SmsDown) == LOW);
        Serial.print("Got a 1 in buffer");
        if(UpOrDown == 1){ //If curtain is up, go down.
          Serial.print("Changing position");
          changePosition(0);
         }
      }
      if(digitalRead(SmsUp) == LOW){
        while(digitalRead(SmsUp) == LOW);
        Serial.print("Got a 0 in buffer");
        if(UpOrDown == 2){ //If curtain is down, go up.
          Serial.print("Changing position");
          changePosition(0);
         }
      }


  // Code for manual control.
  if(digitalRead(relay1Activate) == LOW){// Relay1
    digitalWrite(relay1,LOW);
  }
  else{
    digitalWrite(relay1,HIGH);
  }
  if(digitalRead(relay2Activate) == LOW){// Relay2
    digitalWrite(relay2,LOW);
  }
  else{
    digitalWrite(relay2,HIGH);
  }

    
  // Code for handeling the radio controller.
  if (stop_ints) //data in buffer
  {
    unsigned long binary = 1;
    //byte i = 0;
    for (byte j = 0; j < 46; j++)
    {
      //Serial.print(binary);
      if ((bufor[j] > 220) &&
          (bufor[j] < 400))
      {
        binary <<= 1;
        //binary |= 1;
        //i++;
        bitSet(binary,0);
      }
      else if ((bufor[j] > 90) &&
               (bufor[j] < 220) && (bufor[j + 1] > 90) &&
               (bufor[j + 1] < 220)) {
        binary <<= 1;
        j++;
      }
      else if ((bufor[j] > 90) &&
               (bufor[j] < 220) && (bufor[j + 1] > 220) &&
               (bufor[j + 1] < 400)) {
        binary <<= 1;
        bitSet(binary,0);
        //i += 2;
        j++;
      }
      else break;
    }
    //Serial.println(bitRead(binary,4)); For debugging.
    if (bitRead(binary,23))
    {
      bitClear(binary,23);
      Serial.print("remoteID:");
      Serial.print((binary / 128) & 65535);
      Serial.print(" - ");
      Serial.print("key code:");
      Serial.println(binary & 127);
      
      //A Button
      if(!((binary & 127)-8)){
        Serial.println("A Button");
        changePosition(0);
      }
      //A Button End
      
      //B Button
      if(!((binary & 127)-16)){
        Serial.println("B Button");
        if(CButtonArmed == 1 && CButtonUsed == 0){
          UpOrDown = 1;
          ChooseUpOrDown = 1;
          CButtonArmed = 0;
          CButtonUsed = 1;
          digitalWrite(13,LOW);
          
          //sound rising
          tone(Buzzer,C5,Q);
          delay(1+S);
          tone(Buzzer,D5,Q);
          delay(1+S);
          tone(Buzzer,E5,Q);
          delay(1+S);
        }
      }
      //B Button End
      
      //C Button
      if(!((binary & 127)-56)){
        if(CButtonUsed == 0){
          Serial.println("C Button");
          if(CButtonPushedTimes == 0){
            CButtonPushedTimes++;
            tone(Buzzer,G4,S+S);
          }
          else if(CButtonPushedTimes == 1){
            if(ChooseUpOrDown == 0){
              CButtonArmed = 1;
              digitalWrite(13,HIGH);
              tone(Buzzer,G4,S);
              delay(2+S);
              tone(Buzzer,G4,S);
              delay(2+S);
              tone(Buzzer,G4,S);
              delay(2+S);
            }
            CButtonPushedTimes = 0;
          }
        }
        else{
          PlayBuzzer();
        }
      }
      //C Button End
      
      //D Button
      if(!((binary & 127)-42)){
        Serial.println("D Button");
        if(CButtonArmed == 1 && CButtonUsed == 0){
          UpOrDown = 2;
          ChooseUpOrDown = 1;
          CButtonArmed = 0;
          CButtonUsed = 1;
          digitalWrite(13,LOW);
          
          //sound falling
          tone(Buzzer,E5,Q);
          delay(1+S);
          tone(Buzzer,D5,Q);
          delay(1+S);
          tone(Buzzer,C5,Q);
          delay(1+S);
        }
      }
      //D Button End
    }
    else {
      Serial.println("wrong code  ");
      Serial.println(binary, BIN);
    }
    delay (1000);
    header = false;
    impulse = 0;
    stop_ints = false;
  }
}


// interrupt below...



/**
 * This function will calculate
 * the input of the radio remote.
 */
void calcInput()
{
  // get the time using micros
  unsigned int duration = (int)(micros() - StartPeriod); // save pulse length to bufor
  StartPeriod = micros(); //begin next impulse
  //Serial.println(StartPeriod);
  if (stop_ints) return;
  if ((duration < 90) || (duration > 600)) goto reset; //impulse not right
  bufor[impulse++] = duration;
  if (duration < 415) return;
  if (!header)
  {
    header = true;
    impulse = 0;
    return;
  }
  else
  {
    if ((impulse < 23) || (impulse > 52)) goto reset; //too long or too short info
    stop_ints = true;
    return;
  }
reset:
  header = false;
  impulse = 0;
  return;
}



/**
 * This function will change the position of the curtain.
 * If the input is 0 then the function will change the
 * state right away. If the input is 1,2 or 3. it will
 * wait some time before moving the curtain.
 * (1,2&3 will mostly be usefull if you do not use an external input source.)
 */
//Change position function
void changePosition(int TimeIsMoney){
  unsigned long currentMillis = millis();
  if(UpOrDown != 0){
    if(TimeIsMoney == 1){
      delay(120000);
    }
    if(TimeIsMoney == 2){
      delay(7200000);
    }
    if(TimeIsMoney == 3){
      delay(10800000);
    }
  }
        // Roll Down------------------------------------
        if(UpOrDown == 1){
        digitalWrite(relay1, LOW); // Starts the motor
        delay(700);
       currentMillis = millis();
       previousMillis = currentMillis;
       digitalWrite(13,HIGH);
      while(BreakIfNotOne == 1)
      {
        currentMillis = millis();
        if(currentMillis - previousMillis > interval)
        {
          BreakIfNotOne = 0;
        }
        if(digitalRead(sensor)== HIGH)
        {
          BreakIfNotOne = 0;
        }
      }
      digitalWrite(13,LOW);
      BreakIfNotOne = 1;
      UpOrDown = 2;
      digitalWrite(relay1, HIGH);
      delay(10);
      digitalWrite(relay1, LOW);
      delay(100);
      digitalWrite(relay1, HIGH);

        }
        // Roll Up------------------------------------
        else if(UpOrDown == 2){
        Serial.println("Reverse");
        digitalWrite(relay2, LOW); // Starts the motor
        delay(700);
       currentMillis = millis();
       previousMillis = currentMillis;
       digitalWrite(13,HIGH);
      while(BreakIfNotOne == 1)
      {
        currentMillis = millis();
        if(currentMillis - previousMillis > interval)
        {
          BreakIfNotOne = 0;
        }
        if(digitalRead(sensor)== HIGH)
        {
          BreakIfNotOne = 0;
        }
      }
      digitalWrite(13,LOW);
      BreakIfNotOne = 1;
      UpOrDown = 1;
      digitalWrite(relay2, HIGH);
      // We start the relay1 to stop the motors momentum
      // If we use small motors they might not have enough
      // internal friction to make the curtain stop quickly enough.
      digitalWrite(relay1, LOW);
      delay(100);
      digitalWrite(relay1, HIGH);
      }
  return;
}



/**
 * This function plays the song imperial march from starwars
 * on the piezzo buzzer. The function calles the function
 * tone(pin, note, duration), to make each individual sound.
 */
void PlayBuzzer() {
    tone(Buzzer,LA3,Q); 
    delay(1+Q); //delay duration should always be 1 ms more than the note in order to separate them.
    tone(Buzzer,LA3,Q);
    delay(1+Q);
    tone(Buzzer,LA3,Q);
    delay(1+Q);
    tone(Buzzer,F3,E+S);
    delay(1+E+S);
    tone(Buzzer,C4,S);
    delay(1+S);
    
    tone(Buzzer,LA3,Q);
    delay(1+Q);
    tone(Buzzer,F3,E+S);
    delay(1+E+S);
    tone(Buzzer,C4,S);
    delay(1+S);
    tone(Buzzer,LA3,H);
    delay(1+H);
    
    tone(Buzzer,E4,Q); 
    delay(1+Q); 
    tone(Buzzer,E4,Q);
    delay(1+Q);
    tone(Buzzer,E4,Q);
    delay(1+Q);
    tone(Buzzer,F4,E+S);
    delay(1+E+S);
    tone(Buzzer,C4,S);
    delay(1+S);
    
    tone(Buzzer,Ab3,Q);
    delay(1+Q);
    tone(Buzzer,F3,E+S);
    delay(1+E+S);
    tone(Buzzer,C4,S);
    delay(1+S);
    tone(Buzzer,LA3,H);
    delay(1+H);
    
    tone(Buzzer,LA4,Q);
    delay(1+Q);
    tone(Buzzer,LA3,E+S);
    delay(1+E+S);
    tone(Buzzer,LA3,S);
    delay(1+S);
    tone(Buzzer,LA4,Q);
    delay(1+Q);
    tone(Buzzer,Ab4,E+S);
    delay(1+E+S);
    tone(Buzzer,G4,S);
    delay(1+S);
    
    tone(Buzzer,Gb4,S);
    delay(1+S);
    tone(Buzzer,E4,S);
    delay(1+S);
    tone(Buzzer,F4,E);
    delay(1+E);
    delay(1+E);//PAUSE
    tone(Buzzer,Bb3,E);
    delay(1+E);
    tone(Buzzer,Eb4,Q);
    delay(1+Q);
    tone(Buzzer,D4,E+S);
    delay(1+E+S);
    tone(Buzzer,Db4,S);
    delay(1+S);
    
    tone(Buzzer,C4,S);
    delay(1+S);
    tone(Buzzer,B3,S);
    delay(1+S);
    tone(Buzzer,C4,E);
    delay(1+E);
    delay(1+E);//PAUSE QUASI FINE RIGA
    tone(Buzzer,F3,E);
    delay(1+E);
    tone(Buzzer,Ab3,Q);
    delay(1+Q);
    tone(Buzzer,F3,E+S);
    delay(1+E+S);
    tone(Buzzer,LA3,S);
    delay(1+S);
    
    tone(Buzzer,C4,Q);
    delay(1+Q);
     tone(Buzzer,LA3,E+S);
    delay(1+E+S);
    tone(Buzzer,C4,S);
    delay(1+S);
    tone(Buzzer,E4,H);
    delay(1+H);
    
     tone(Buzzer,LA4,Q);
    delay(1+Q);
    tone(Buzzer,LA3,E+S);
    delay(1+E+S);
    tone(Buzzer,LA3,S);
    delay(1+S);
    tone(Buzzer,LA4,Q);
    delay(1+Q);
    tone(Buzzer,Ab4,E+S);
    delay(1+E+S);
    tone(Buzzer,G4,S);
    delay(1+S);
    
    tone(Buzzer,Gb4,S);
    delay(1+S);
    tone(Buzzer,E4,S);
    delay(1+S);
    tone(Buzzer,F4,E);
    delay(1+E);
    delay(1+E);//PAUSE
    tone(Buzzer,Bb3,E);
    delay(1+E);
    tone(Buzzer,Eb4,Q);
    delay(1+Q);
    tone(Buzzer,D4,E+S);
    delay(1+E+S);
    tone(Buzzer,Db4,S);
    delay(1+S);
    
    tone(Buzzer,C4,S);
    delay(1+S);
    tone(Buzzer,B3,S);
    delay(1+S);
    tone(Buzzer,C4,E);
    delay(1+E);
    delay(1+E);//PAUSE QUASI FINE RIGA
    tone(Buzzer,F3,E);
    delay(1+E);
    tone(Buzzer,Ab3,Q);
    delay(1+Q);
    tone(Buzzer,F3,E+S);
    delay(1+E+S);
    tone(Buzzer,C4,S);
    delay(1+S);
    
    tone(Buzzer,LA3,Q);
    delay(1+Q);
     tone(Buzzer,F3,E+S);
    delay(1+E+S);
    tone(Buzzer,C4,S);
    delay(1+S);
    tone(Buzzer,LA3,H);
    delay(1+H);
    
    delay(2*H);
    return;
}

Step 5: Schematics

This is the schematics that the build is based upon. Use this when reproducing the project.

Step 6: Building the Curtain

Now it’s time to attach the motor to the curtain. We will do this by
removing the “plug” on the side of the curtain, the rope that one would pull the curtain up or down were attached to this “plug” before it was removed. If you have a 3D-Printer, print this part instead, it would make the construction easier.

It is possible to break down the plastic side into smaller parts, we will only need the biggest part (the part that has contact with the curtain).

As a mount we use L shaped plastic mounts, and hold them in place with zip ties. It should be noted that this was not my first attempt. I pulled the curtain down from the wall once before making this decision.

The zip ties does not grip the motor that hard it just holds it in place. This allows the motor to wiggle a bit and this helps with the problems I had, with creaking noise. When I had the motor firmly mounted it was not completely straight and it bent the metal rod in the curtain ever so slightly to make an irritating creaking noise.

Step 7: Testing the Motor

Servo motors are usually high torque motors and works well for the purpose we will use it for. These motors got an internal feedback controller inside of the housing that we do not really need. It is a good thing to open up the enclosure and remove the board, then we can solder the cables directly to the motor instead.

Step 8: Mounting the Curtain on the Wall

Insert the motor into the curtain and screw it back to the wall. As you can see it does stand out quite a lot on these pictures when compared to the white background. As fortunate as I am, it is impossible to see the motor when you are in the room and from the outside (if you do not move your head, so you face the window). If you have smaller
drapes then me or none at all you would want to make the motor prettier.

Step 9: Adding the Sensor to the Curtain

The sensor that I choose to use is a reflective infrared sensor, there is an infrared emitter next to a receiver. The receiver will measure how much information is lost. If the object is black the loss is great and if the item is white, there is almost no loss. We will use the digital output and trim the potentiometer so that it triggers nicely on the black electrical tape that we will put on the curtain at the top and bottom.

Step 10: Adding Fast Connectors to Sensor & Motor.

I wanted to have the sensor cable easily removable. For a fast connector I decided to use a USB-connector. They are widely available and are usually very cheap. USB-connectors is also made for 5volts and that is the voltage the sensor uses.

Step 11: Setting Up the Phone With Blynk

First of all download the Blynk app to your phone and make an account. I have provided a QR icon in the pictures that you can scan from the app, that way you do not have to setup the app more than edit your own authentication code into the code for the NodeMCU that you will program.

Step 12: ​Thoughts on Choosing Enclosure.

If you think that my choice of enclosure is weird than you might be right. I chose that box because it will look good in the environment that I am in. If you decide to build something like this then you might what to choose some other enclosure entirely. You might even want to have the enclosure up on the wall next to the motor. The second picture that I am showing here is an old version of this curtain. It does have another enclosure though, it might give you some ideas.

Step 13: Make the Necessary Holes for the Connectors.

The USB-connector is for the IR-sensor and the "black and red" cable is for the motor. The jack in the middle is for an external power source.

Step 14: Thoughts on Cable Management.

To fit all the electronics in the enclosure I decided to make my own cables. If cable management is if great importance to you, then you can always choose a bigger enclosure to help with the cable management. Or If you like to etch your own pcb's than that is a nice thing to do.

Step 15: Fit the Electronics in the Enclosure.

Trying to fit all the electronics in a small space is a nice feeling. You might ask why I use relays that takes up a lot of space when I could have used power-transistors instead. I did actually use power transistors before I went with relays, I did have a problem with too much of a voltage drop over the transistors and I did not want to use a boost converter to accumulate for the drop. The motor is somewhat sensitive to changes in voltage and does get much weaker if the voltage drops.

Step 16: Base-Station Done

This is how the base station came to look in the end. It is not necessary to have it easily removable in a permanent solution but it helps with cable management and just makes your life easier.

Step 17: ​Power Consumption

These pictures speaks for them self's. If you are interested in the power consumption of this device please take a look.

Step 18: It's Alive!

What is a project that is supposed to move, if you could not see it actually move? This is a 2.5 min clip showing the build of the curtain and the curtain moving, (with input from the radio control and from the phone).

Thanks for reading my instructable!