Project tutorial

EnLight (Sunset) v1 © GPL3+

Control your blinds to collect as much sunset light, and eventually closing the blinds for you.

  • 1,899 views
  • 0 comments
  • 6 respects

Components and supplies

Ardgen 101
Arduino 101 & Genuino 101
×1
266 04
Female/Female Jumper Wires
I won't specify how many you need, because everyone's window has different dimensions.
×1
11026 02
Jumper wires (generic)
I won't specify how many you need, because everyone's window has different dimensions.
×1
09067 action 01
SparkFun Serial Enabled 16x2 LCD - White on Black 3.3V
Use the one in the Inventor's kit (Arduino 101)
×1
09457 01b
SparkFun Motor Driver - Dual TB6612FNG (1A)
Use the one in the Inventor's kit (Arduino 101)
×1
Adafruit industries ada161 image 75px
Photo resistor
×5
Omron b3f 1000 image 75px
SparkFun Pushbutton switch 12mm
Requires the two pin version depicted in the Fritzing design
×1
DC motor (generic)
Use the one in the Inventor's kit (Arduino 101)
×1
Mfr 25frf52 10k sml
Resistor 10k ohm
×6

Necessary tools and machines

3drag
3D Printer (generic)

Apps and online services

Ide web
Arduino IDE
Autodesk fusion 360 logo 4szx21llea
Autodesk Fusion 360
This is optional. Only use it to modify the CAD files (if you want)

About this project

What is this?

EnLight is a series of “add-on” devices to help improve and enable regular objects, like blinds, to have efficient energy collecting abilities! This particular EnLight device augments blinds to efficiently collect the setting sun’s sunlight, and close the blinds when it gets dark outside.

This Hackster project will explain with words and pictures/diagrams how to set up your blinds with an EnLight Sunset to collect the sun’s power! EnLight Sunset is a simple stand-alone system that doesn’t require any internet or manual operation (except for the setup)! Feel free to alter the code and CAD enclosures of this device to customize it to your own needs.

A quick note before we start building

This tutorial doesn’t explain how to set up and wire a solar panel, even though it’s technically a part of this system’s product. Rather, this tutorial will explain how to set up a system that will measure a window’s sunlight exposure, and adjust the blinds (which would have solar-panels mounted onto) to have the maximum exposure to the setting sun’s angle. Think of it like the stem of a sunflower, the part that turns to face the sun. This decision was made because everyone’s blinds take a different form/shape, so one solar panel wouldn’t work.

Design considerations

Speaking of different blinds, there were a couple design factors that had to be assumed (because there wouldn't be a product if there were so many conditionals). They are listed below:

  • Your blinds close in an upwards motion
Blinds close upward and open downward
  • Your blinds have/use a pulley system to operate
  • There is a lip/thickness between the glass and the glass-frame

Remember, you are totally at the freedom to change any part of this product so it fits what you want.

Hardware/physical setup

The technical hardware stuff (like wiring) are pretty straight forward. Just use the Fritzing breadboard picture/diagram in the “Schematics” section. There’s really not much else to it. The comments to point out two important things:

  • All resistors used in this design are 10KΩ
  • The wiring of the photoresistors. It is pretty difficult to see because of the coloring, but just follow a standard photoresistor wiring and you’ll get it.

Begin taping

Now comes that part where you have to do some adhering. 3D print the pulley wheel controller joint/wheel (found in the “Custom parts and enclosures” section) and the photoresistor placeholders (also found the “Custom parts and enclosures” section). If your printer’s resolution is high enough, you might be able to see the tiny labels on the placeholders which indicate where to put them on the following diagram. If not, don’t worry! You just have to compare the draft (tilt) of the small square plane to figure out which is which. The draft was put in place to tilt the photoresistor to the sun’s angle when it descends.

There are three drafts: 0º, 5º, and 10º. They are pretty easy to tell apart, so don’t worry.

If the photoresistor doesn’t fit perfectly in the placeholder, you may need to use some form of an adhesive to adjust the fit. You definitely will need to use an adhesive to attach the placeholders to the window border.

The same can also be said for the pulley wheel joint connection with the motor. The motor that comes with the Inventors Kit has a while axle that is controlled by the strapped in dc motor. The joint/axle of the pulley wheel fits over the DC motor’s axle.

Overall setup

Here’s a diagram of the “planned” setup for this system.

I didn’t make an enclosure for this system because the Inventors Kit comes with a base and some users may want to use that instead, but feel free to make one yourself if you desire.

Software

Download all three files in the “Code” section, its very important that you do. Once they are downloaded, put them together in a folder named “enlight” IT IS IMPORTANT THAT YOU NAME IT THAT. Enter the “enlight” folder, and edit the file extension of “constants.txt” and “voids.txt” from “.txt” to “.h” so now they should be “constants.h” and “voids.h”. This is very important because the main Arduino file, “enlight.ino”, relies on these headers for its constants and functions. Once you have accomplished this, simply open enlight.ino in the Arduino IDE and upload it to your Arduino 101. Remember to select the right board! If you don’t have the Arduino 101 (Intel Curie 32 bit) board installed, simply install it through the board manager (board series name: “Intel Curie Boards”).

Operation

The system starts up with a setup process through the serial monitor (the LCD will let you know). The board will still probably be connected to the computer because of the previous section. Open the serial monitor and follow the instructions shown. It is important that you don’t open the serial port again after you have finished the set up process. Reopening the port will cause the program to restart, making you go through the setup process again.

Final notes

That’s it! Pretty simple. Once the system finishes its setup process, your blinds will start angling itself for maximum sunlight absorption for your solar panels.

One of the alternate function of EnLight Sunset that was mentioned in the initial idea pitch was for comfort. By angling itself at the sun, you can reduce the amount/change of direct sunlight hitting your eyes or the room. This can also help conserve energy by helping keep the indoor temperature from rising due to sunlight exposure.

Please leave feedback and comments in the comments section!

Thank you!

Code

EnlightArduino
The main code file that deals with everything.
NOTE: the header files "constants.h" and "voids.h" are both required.
/*
   EnLight v1

   Developer: Microbob 
   Contact: microbob@is88.com
*/
#include <LiquidCrystal.h>
#include <CurieTime.h>
#include "constants.h"

LiquidCrystal lcd(12, 11, 5, 4, 3, 2); //LCD init

unsigned long togg;
unsigned int in;
String instr;

unsigned int temp;
String tempstr;
unsigned long prevMil = millis();

unsigned int timeData[6];
bool dirLeft = true;
unsigned long rotDur;

unsigned int calibP = 0;
unsigned int maxBri = 0;
unsigned int minBri = 1023;

unsigned int unHour, unMin, unSec;

unsigned int pos;
unsigned int turn = 0;

#include "voids.h"
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  lcd.begin(16, 2);

  pinMode(bri, OUTPUT);
  pinMode(func, INPUT);


  lcd.print("Please Open a");
  lcd.setCursor(0, 1);
  lcd.print("Serial Session");
  Serial.println("Type in anything and press <Enter> to continue");
  unsigned int briLev = 0, increment = 5;
  while (Serial.available() == 0) {
    brightness(briLev);
    briLev += increment;
    if (briLev == 255 || briLev < 5)
      increment *= -1;
    delay(25);
  }
  brightness(0);
  lcd.clear();
  serialFlush();

  initHeaders("Introduction");
  Serial.println("Welcome to your EnLight!\n");
  Serial.println("This setup process may run (autonomously) for a max. of 24 hours");
  Serial.println("The user part won't take you more than a few minutes,");
  Serial.println("the rest will be the system calibrating itself to the sun\n");
  Serial.println("Type in \"r\" and press <Enter> when you are ready to continue.");
  Serial.println("Type in anything else and press <Enter> if you want to quit");
  Serial.println("NOTE: Always press <Enter> after you type something in to submit it");
  Serial.println("\nPress the RESET button (if accessible),");
  Serial.println("unplug and replug power to the device,");
  Serial.println("or reopen a serial connection to completely restart/reset at any time");
  while (true) {
    input(false);
    if (in == 114)
      break;
    else if (in == 0)
      continue;
    else {
      Serial.println("\nPress the RESET button (if accessible) to restart,");
      Serial.println("Or unplug and replug power to the device to restart");
      Serial.println("END");
      Serial.flush();
      exit(0);
    }
  }

  calTime();
  calDir();
  calDur();

  while (true) {
    Serial.println("\n\n\n");
    Serial.println("+++++++++++++++++++++++++++++++++++");
    Serial.println("+++++  Manual setup complete  +++++");
    Serial.println("+++++++++++++++++++++++++++++++++++");
    Serial.println("\nHere's your last chance to (re)calibrate anything.");
    Serial.println("1) Time");
    Serial.println("2) Rotation Direction");
    Serial.println("3) Length of Direction");
    Serial.println("\nType in the corresponding number to recalibrate,");
    Serial.println("or type in [y] to continue.");
    input(false);
    if (in == 49)
      calTime();
    else if (in == 50)
      calDir();
    else if (in == 51)
      calDur();
    else if (in == 114)
      break;
  }

  Serial.println("\n\n\n");
  Serial.println("The rest will the device calibrating itself to the sun.");
  Serial.println("This can take up to 24 hours.");
  Serial.println("This is because the system needs to wait for it to be 12:00 PM");
  Serial.println("and start collecting data about the brightness at different");
  Serial.println("points of the suns set.");
  Serial.println("\nPLEASE KEEP POWER TO THIS DEVICE!!!!!");
  Serial.println("The LCD will show the status of the device.");
  Serial.println("\nEnjoy your device and save some power!");
  Serial.println("END");


  brightness(100);
  calibState("Starting...");

  bool from12 = false;
  if (hour() == 12 && minute() == 0 && second() == 0)
    from12 = true;
  else if (hour() < 12) {
    temp = map(hour() * 60 + minute(), 0, 720, 0, 100);
    while (hour() != 12 && minute() != 0 && second() != 0) {
      if (temp > map(hour() * 60 + minute(), 0, 720, 0, 100)) {
        temp = map(hour() * 60 + minute(), 0, 720, 0, 100);
        calibState("Waiting...");
      }
    }
    from12 = true;
  }

  if (from12) {
    while (hour() != 0) {
      if (millis() - prevMil >= 1000) {
        temp = briIn();
        prevMil = millis();
        maxBri = max(temp, maxBri);
        minBri = min(temp, minBri);

        temp = map(hour() * 60 + minute(), 720, 1439, 0, 100);
        if (calibP != temp)
          calibState("Collecting...");
      }
    }
  }
  else {
    unHour = hour();
    unMin = minute();
    unSec = second();

    while (hour() != 0) {
      if (millis() - prevMil >= 1000) {
        temp = briIn();
        prevMil = millis();
        maxBri = max(temp, maxBri);
        minBri = min(temp, minBri);

        temp = map(hour() * 60 + minute(), unHour * 60 + unMin, 1439, 0, 33);
        if (calibP != temp)
          calibState("Collecting...");
      }
    }
    temp = map(hour() * 60 + minute(), 0, 720, 33, 66);
    while (hour() == 12 && minute() == 0 && second() == 0) {
      if (temp > map(hour() * 60 + minute(), 0, 720, 0, 100)) {
        temp = map(hour() * 60 + minute(), 0, 720, 33, 66);
        calibState("Waiting...");
      }
    }
    while (hour() != unHour && minute() != unMin && second() != unSec) {
      if (millis() - prevMil >= 1000) {
        temp = briIn();
        prevMil = millis();
        maxBri = max(temp, maxBri);
        minBri = min(temp, minBri);

        temp = map(hour() * 60 + minute(), 720, 1439, 66, 100);
        if (calibP != temp)
          calibState("Collecting...");
      }
    }
  }

  temp = 100;
  calibState("Complete!");
  delay(1000);

  lcd.clear();
  lcd.print("Starting...");
  delay(1000);

  pos = map(briIn(), 200, 1439, 1, 5);
  drive();
  delay(rotDur / 5 * pos);
  sdrive();
  turn = pos;
}

void loop() {
  // put your main code here, to run repeatedly:
  do {
    if (millis() - prevMil >= 60000) {
      temp = map(briIn(), 200, 1439, 1, 5);
      if (temp != pos) {
        drive();
        delay(rotDur / 5 * (temp - turn));
        sdrive();
        turn = temp - turn;
      }


      lcd.clear();
      lcd.print("Operating...");
      lcd.setCursor(0,1);
      lcd.print(String(map(hour() * 60 + minute(), 720, 1439, 0, 100))+"%");
    }
  } while (turn != 5 || hour() < 22);

  turn = 0;
  while (hour() != 7 && minute() != 30 && second() != 0) {
    if (millis() - prevMil >= 1000) {
      temp = map(hour() * 60 + minute(), 720, 1439, 0, 50);
      if (calibP != temp)
        calibState("Waiting...");
    }
  }
  odrive();

  temp = map(hour() * 60 + minute(), 0, 720, 0, 100);
  while (hour() != 12 && minute() != 0 && second() != 0) {
    if (temp > map(hour() * 60 + minute(), 0, 720, 0, 100)) {
      temp = map(hour() * 60 + minute(), 0, 720, 50, 100);
      calibState("Waiting...");
    }
  }

  pos = map(briIn(), 200, 1439, 1, 5);
  drive();
  delay(rotDur / 5 * pos);
  sdrive();
  turn = pos;
}
constantsPlain text
Just a header file to hold different constants and variables that won't change, like alt names for pins.
#define topPin A0
#define topMidPin A1
#define midPin A2
#define bottomMidPin A3
#define bottomPin A4

#define bri 10

#define dirA 7
#define dirB 8
#define spd 6

#define func A5

const char* setTimeHeader[] = {"Month (MM)", "Day (DD)", "Year (YYYY)", "Hour (24-HH)", "Minute (MM)"};
voidsPlain text
The file that holds all of the functions to the program, like time calibration.
// I/O
void brightness(const unsigned int b) {
  analogWrite(bri, b);
}
void off() {
  digitalWrite(spd, LOW);
}
void sped(const unsigned int s) {
  analogWrite(spd, s);
}

int briIn() {
  unsigned int top = analogRead(topPin);
  unsigned int topMid = analogRead(topMidPin);
  unsigned int mid = analogRead(midPin);
  unsigned int bottomMid = analogRead(bottomMidPin);
  unsigned int bottom = analogRead(bottomPin);

  return (top + topMid + mid + bottomMid + bottom) / 5;
}
// Motor dir
void drive() {
  if (dirLeft) {
    digitalWrite(dirA, HIGH);
    digitalWrite(dirB, LOW);
  } else {
    digitalWrite(dirA, LOW);
    digitalWrite(dirB, HIGH);
  }

  analogWrite(spd, 125);
}
void sdrive() {
  digitalWrite(spd, LOW);
}
void odrive() {
  if (!dirLeft) {
    digitalWrite(dirA, HIGH);
    digitalWrite(dirB, LOW);
  } else {
    digitalWrite(dirA, LOW);
    digitalWrite(dirB, HIGH);
  }

  analogWrite(spd, 125);
  delay(rotDur);
  sdrive();
}

// LCD Interface
void calibState(String msg) {
  lcd.clear();
  calibP = temp;
  lcd.print("Calibrating: " + String(calibP) + "%");
  lcd.setCursor(0, 1);
  lcd.print(">> " + msg);
}

// Serial Interface
void serialFlush() {
  while (Serial.available())
    Serial.read();
}
void input(bool str) {
  while (true) {
    if (Serial.available() > 0) {
      if (str)
        in = Serial.readString().toInt();
      else
        in = Serial.read();
      break;
    }
  }
}
void initHeaders(const String& header) {
  const unsigned int hh = header.length();
  Serial.println("\n\n\n===== (Initial) Setup Process =====");
  Serial.print(">>>>>");

  for (unsigned int l = 0; l < (25 - hh) / 2 + (hh % 2); l++) {
    Serial.print(" ");
  }
  Serial.print(header);
  for (unsigned int l = 0; l < (25 - hh) / 2; l++) {
    Serial.print(" ");
  }

  Serial.print("<<<<<\n\n");
}
void convert(unsigned int num) { //trailing zero
  if (num >= 0 && num < 10)
    Serial.print("0");
  Serial.print(num);
}

void calTime() {
  initHeaders("Setting the Time");
  for (unsigned int l = 0; l < 4; l++) {
    while (true) {
      Serial.println("Type in the " + String(setTimeHeader[l]) + " number");
      input(true);
      temp = in;
      Serial.println(String(setTimeHeader[l]) + ": " + String(temp));
      Serial.println("Was that what you wanted? [y/n]");
      input(false);
      if (in == 121) {
        timeData[l] = temp;
        Serial.println(String(setTimeHeader[l]) + " has been set to " + String(timeData[l]));
        break;
      }
    }
  }
  while (true) {
    Serial.println("Type in the current Seconds (SS). When you press enter, it will set to what was entered.");
    input(true);
    temp = in + 4;
    setTime(timeData[3], timeData[4], temp, timeData[1], timeData[0], timeData[2]);

    for (unsigned int l = 0; l < 5; l++) {
      convert(hour());
      Serial.print(":");
      convert(minute());
      Serial.print(":");
      convert(second());
      delay(1000);
    }

    Serial.println("\nLooks good? [y/n]");
    input(false);
    if (in == 121) {
      timeData[5] = temp;
      Serial.println("\nThe time has been set!");
      break;
    }
  }
}
void calDir() {
  initHeaders("Rotation Direction");
  Serial.println("For your device and blind's safety,");
  Serial.println("plase make sure the pully controller is removed.");
  Serial.println("Ready to continue? [y]\n");
  while (true) {
    input(false);
    if (in == 121)
      break;
  }

  drive();
  Serial.println("Is this the direction your blind's close if turned? [y/n]");
  input(false);
  if (in == 121)
    Serial.println("Blinds close in oposite direction.\n Direction Set");
  else
    dirLeft = false;
}
void calDur() {
  initHeaders("Length of Rotation");
  while (true) {
    Serial.println("1) Open your blinds to full extent.");
    Serial.println("2) Reinstall the pully controller.");
    Serial.println("3) Locate the function button, it will be used to control the motor.");
    Serial.println("\nWhen you are ready, the motor will start closing your blinds.");
    Serial.println("Press the function button when your blinds fully close.");
    Serial.println("Submit [y] when you are ready to continue.");
    while (true) {
      input(false);
      if (in == 121)
        break;
    }

    prevMil = millis();
    drive();
    while (func != HIGH);
    rotDur = millis() - prevMil;
    sdrive();

    Serial.println("Rotation recorded.");
    delay(1000);
    odrive();
    drive();
    delay(rotDur);
    sdrive();

    Serial.println("Looks good? [y/n]");
    input(false);
    if (in == 121) {
      odrive();
      break;
    }
  }
}

Custom parts and enclosures

Photoresistor placeholder
use these placeholders to help guide the angle o set of the photoresistors if the opening is too large you can edit the file to make it smaller, or use tape to connect the photoresistor.
Photoresistor placeholder -f3d
Fusion 360 archive version of the Photoresistor placeholder file
photoresistor_placeholders_wCFyAAM1Fl.f3d
Pully Controller
The wheel that controls the blinds
Pully Controller -f3d
Fusion 360 archive version of Pully Controller
pully_wheel_cw2D0WrF03.f3d

Schematics

The main bread board design. It's a little difficult to see because of the wires, but all resistors used are 10K and the photoresistors are connected to power and the pin between the power-bus and the resistors (that are next to the analog input wires).
Fritz bb jsplrpusjo
Main - LCD
Same file as Main except without the LCD so you can see where the wires go underneath.
Fritz bb2 yvbfbscfx7

Comments

Similar projects you might like

Raspberry Pi - Powered Candy Dispenser

Project tutorial by Arduino “having11” Guy

  • 7,082 views
  • 1 comment
  • 13 respects

GPS Datalogger, Spatial Analysis, and Azure IoT Hub.

Project tutorial by Shawn Cruise

  • 21,525 views
  • 4 comments
  • 79 respects

“It’s For The Birds!”

Project tutorial by Team 101

  • 8,235 views
  • 38 comments
  • 31 respects

Azure Stream Analytics saving lives!

Project tutorial by Asad Zia

  • 7,275 views
  • 3 comments
  • 28 respects

Light Intensity and Solar Panel Energy Detector

Project tutorial by Kutluhan Aktar

  • 3,249 views
  • 3 comments
  • 14 respects

Easy Thermometer v1

Project tutorial by hixel

  • 1,424 views
  • 1 comment
  • 4 respects
Add projectSign up / Login