Hi!

This is my page on home automation, nothing fancy, just my own creations to my life easier.

My curtains project

Home Automation

Parts that I used to make this happen.

  • EtherTen Ethernet Arduino Compatibele Microcontroller
  • 12 Volt Power Supply - 5.0 Amp Single Output
  • AIWAN LEZHI 10 Meters GT2 Timing Belt Width 6mm
  • GT2 Pulley 20 Teeth 5mm bore 6mm Width
  • Stepper Motor - Stepper Motor 17HS24-2104S
  • Optical Photosensitive LDR light sensor Module
  • GeeekPi I2C 20x4 LCD Module
  • 5Volt Solid State Relay Module
  • Various hooks, screws, bolts and other mounting materials
  • I wrote my own arduino code, I am sure it can be done better and cleaner, but this works for me. I am still thinking about adding more Homekit compatibility, but I am not an programmer/coder. I would like to have some kind of status report back to Homekit/Homebridge so I can tell if the curtains are open or closed but that might never happen as longs as this code does what it needs to do.
    The curtains close when it gets dark outside and they open again when it gets light outside, no manual actions required there. I added some kind of Homekit support by means of a webserver setup with two embedded links, one to open and one to close the curtains by manual override the light sensor.

                                        
    #include 
    #include 
    #include  
    #include 
    
    AccelStepper stepper(1, 5, 6); //setup the steppermotor
    LiquidCrystal_I2C lcd(0x27, 20, 4); //setup LCD screen
    
    boolean CURTAIN_STATE = false; //state of the curtains, open or closed
    boolean CURTAIN_MAN = false; //state of control, automatic or manually
    
    int DRIVER_ENABLE = 9; //pin to enable or disable the stepper driver
    int RELAY1_PIN = 8; //pin for the relay to activate the sensor for the back curtains
    //int RELAY2_PIN = 7; //pin for the relay to activate the sensor for the back curtains
    int SENSOR_PIN = A3; //pin for the LDR sensor
    int LIGHT_THRESHOLD = 125; //threshold for opening the curtains
    int DARK_THRESHOLD = 25; //threshold for closing the curtains
    
    unsigned int SENSOR_VALUE = 0;
    unsigned int MAPPED_VALUE = 0;
    unsigned int RELAY1_VALUE = 0;
    //unsigned int RELAY2_VALUE = 0;
    
    unsigned long CURRENT_TIME = 0;
    long PREVIOUS_MILLIS = 0;
    long INTERVAL = 5000; //time between LDR readings
    
    byte mac[] = {  0x86, 0xB4, 0xEF, 0x8E, 0xA3, 0x17 }; //network MAC address
    byte myip[] = { 192, 168, 1, 2 };//network IP address
    byte gwip[] = { 192, 168, 1, 1 };//network gateway IP address
    byte dnsip[] = { 192, 168, 1, 1 }; //network DNS server address
    
    EthernetServer server(80); //setup webserver TCP Port
    
    void setup() {
      pinMode(RELAY1_PIN, OUTPUT); //setup the relay-pin as output
      //pinMode(RELAY2_PIN, OUTPUT); //setup the relay-pin as output
      digitalWrite(RELAY1_PIN, LOW); //make sure the relay-pin is LOW
      //digitalWrite(RELAY2_PIN, LOW); //make sure the relay-pin is LOW
      pinMode(DRIVER_ENABLE, OUTPUT); //setup the driver-pin as output
      digitalWrite(DRIVER_ENABLE, LOW); //make sure the driver is set to disabled, the curtains can run free now
      Serial.begin(9600); //setup the serial connection for troubleshooting
      lcd.init(); // initialiseer het LCD scherm
      lcd.backlight(); // zet de backlight aan
      lcd.clear(); // wis het scherm
      lcd.setCursor(3, 0); // zet de cursor op positie 1, regel 1
      lcd.print("Curtain status"); // schrijf op scherm
      lcd.setCursor(1, 1); // zet de cursor op positie 1, regel 2
      lcd.print("LDR value:"); // schrijf op scherm
      lcd.setCursor(1, 2); // zet de cursor op positie 1, regel 3
      lcd.print("Curtains mode "); // schrijf op scherm
      lcd.setCursor(1, 3); // zet de cursor op positie 1, regel 4
      lcd.print("Curtains are "); // schrijf op scherm
      Ethernet.begin(mac, myip, gwip, dnsip); //start the ethernet connection
      server.begin(); //start the webserver for remote control by Homebridge
      stepper.setMaxSpeed(5500); //set the speed of the steppermotor
      stepper.setAcceleration(4000); //set the acceleration for the steppermotor
    }
    
    void loop() {
      read_ldr();
      if (MAPPED_VALUE > LIGHT_THRESHOLD && CURTAIN_STATE == false) {
        auto_open(); //if it is light outside and the cutains are closed, open the curtains automatically
      }
      if (MAPPED_VALUE < DARK_THRESHOLD && CURTAIN_STATE == true) {
        auto_close(); //if it is dark outside and the curtains are open, close the curtains automatically
      }
      EthernetClient client = server.available();
      if (client) {
        Serial.println("new client");
        boolean currentLineIsBlank = true;
        String postText = "";
        while (client.connected()) {
          if (client.available()) {
            char c = client.read();
            if (postText.length() < 10) {
              postText += c;
            }
            if (c == '\n' && currentLineIsBlank) {
              client.println("HTTP/1.1 200 OK");
              client.println("Content-Type: text/html");
              client.println("Connection: close");
              client.println();
              client.println("");
              client.println("");
              client.println("");
              client.println(" ArduinoLeonardoCurtains ");
              client.println("");
              client.println("");
              break;
            }
            if (c == '\n') {
              currentLineIsBlank = true;
            }
            else if (c != '\r') {
              currentLineIsBlank = false;
            }
          }
        }
        if (postText.indexOf("?on1") > 0) {
          if (MAPPED_VALUE < DARK_THRESHOLD && CURTAIN_STATE == false && CURTAIN_MAN == false) {
            manual_open();
          }
          if (MAPPED_VALUE > LIGHT_THRESHOLD && CURTAIN_STATE == true && CURTAIN_MAN == false) {
            manual_close();
          }
        }
        if (postText.indexOf("?off1") > 0 ) {
          if (MAPPED_VALUE > LIGHT_THRESHOLD && CURTAIN_STATE == true && CURTAIN_MAN == true) {
            auto_open();
          }
          if (MAPPED_VALUE < DARK_THRESHOLD && CURTAIN_STATE == false && CURTAIN_MAN == true) {
            auto_close();
          }
        }
        delay(1);
        client.stop();
        Serial.println("client disconnected");
      }
    }
    
    //gordijn open Homekit
    void manual_open() {
      digitalWrite(DRIVER_ENABLE, LOW);
      Serial.println("Manually Opening");
      delay(200);
      stepper.moveTo(000);
      while (stepper.distanceToGo() != 0)
      {
        stepper.run();
      }
      CURTAIN_MAN = true;
      CURTAIN_STATE = false;
      digitalWrite(DRIVER_ENABLE, HIGH);
    }
    
    //gordijn dicht Homekit
    void manual_close() {
      digitalWrite(DRIVER_ENABLE, LOW);
      Serial.println("Manually Closing");
      delay(200);
      stepper.moveTo(48500);
      while (stepper.distanceToGo() != 0)
      {
        stepper.run();
      }
      CURTAIN_MAN = true;
      CURTAIN_STATE = true;
      digitalWrite(DRIVER_ENABLE, HIGH);
    }
    
    //gordijn open LDR
    void auto_open() {
      digitalWrite(DRIVER_ENABLE, LOW);
      digitalWrite(RELAY1_PIN, LOW);
      Serial.println("Opening by LDR");
      delay(200);
      stepper.moveTo(000);
      while (stepper.distanceToGo() != 0)
      {
        stepper.run();
      }
      CURTAIN_MAN = false;
      CURTAIN_STATE = true;
      digitalWrite(DRIVER_ENABLE, HIGH);
    }
    
    //gordijn dicht LDR
    void auto_close() {
      digitalWrite(DRIVER_ENABLE, LOW);
      digitalWrite(RELAY1_PIN, HIGH);
      Serial.println("Closing by LDR");
      delay(200);
      stepper.moveTo(48500);
      while (stepper.distanceToGo() != 0)
      {
        stepper.run();
      }
      CURTAIN_MAN = false;
      CURTAIN_STATE = false;
      digitalWrite(DRIVER_ENABLE, HIGH);
    }
    
    //read LDR value
    void read_ldr() {
      unsigned long currentMillis = millis();
      if (currentMillis - PREVIOUS_MILLIS > INTERVAL) {
        PREVIOUS_MILLIS = currentMillis;
        SENSOR_VALUE = analogRead(SENSOR_PIN);
        MAPPED_VALUE = map(SENSOR_VALUE, 0, 1023, 1023, 0);
        RELAY1_VALUE = digitalRead(RELAY1_PIN);
        //RELAY2_VALUE = digitalRead(RELAY2_PIN);
        lcd.setCursor(16, 1); // zet de cursor op positie 17, regel 2
        lcd.print(MAPPED_VALUE); // schrijf op scherm
        lcd.print(" ");
        Serial.println("");
        Serial.print("SENSOR_VALUE: ");
        Serial.println(MAPPED_VALUE);
        Serial.print("RELAY1_VALUE: ");
        Serial.println(RELAY1_VALUE);
        //Serial.print("RELAY2_VALUE: ");
        //Serial.println(RELAY2_VALUE);
        if (CURTAIN_MAN == true) {
          Serial.println("curtains in manual mode");
          lcd.setCursor(16, 2); // zet de cursor op positie 16, regel 3
          lcd.print("MAN"); // schrijf op scherm
          lcd.print(" ");
        }
        else {
          Serial.println("curtains in automatic mode");
          lcd.setCursor(16, 2); // zet de cursor op positie 16, regel 3
          lcd.print("AUTO"); // schrijf op scherm
          lcd.print(" ");
        }
        if (CURTAIN_STATE == true) {
          Serial.println("curtains are open");
          lcd.setCursor(15, 3); // zet de cursor op positie 15, regel 4
          lcd.print("OPEN"); // schrijf op scherm
          lcd.print(" ");
        }
        else {
          Serial.println("curtains are closed");
          lcd.setCursor(15, 3); // zet de cursor op positie 15, regel 4
          lcd.print("CLOSE"); // schrijf op scherm
          lcd.print(" ");
        }
      }
    }