Room Light & Temperature Regulator

by 0899670 in Circuits > Sensors

2591 Views, 89 Favorites, 0 Comments

Room Light & Temperature Regulator

DSCN1073_sm.JPG
DSCN1085
stroomschema 03.jpg

The idea behind the room temperature regulator is to maintain a certain temperature in the absence of the user.

The project uses an Arduino Mega as a microcontroller, which will calculate room temperature through the appropriate sensors. In conjunction with these temperature sensors, the will also be sensors that will measure sunlight. A room might heat up fast when under constant direct sunlight, especially if it’s already hot outside. Turning the blinders on early might prevent the user spontaneously combusting when entering a scorching hot room. When the sensor detects sunlight, the microcontroller will tell the servo’s to close the blinds to prevent this.

There will be a set of a photosensor and temperature in front and behind the blinds. The sensors behind the blinds (so between the blinds and the windows) will compare conditions with the sensors in front of the blinds.

When the temperature gets too high, a fan or an air conditioning system will be switched on. It is currently not within my budget to purchase an air conditioning system, so a 5V cooling fan will have to suffice. It goes without saying that the servo’s and the fan need their own power supply. A 9V battery block will be included in the circuit, and will be controlled through a relay module.

Materials :

  • Arduino Uno or higher
  • Relay module with amounts of sockets equal to amount of blinds to be adjusted (4-socket relay in my case)
  • 2 100K Thermistors (Temperature)
  • 2 Photo resistors (Light)
  • Some very light, thin and straight objects (I used rolled-up A4 paper)
  • 3D printer for conversion pieces
  • 1 10ohm resistor, 3 220ohm resistors, 2 10Kohm resistors
  • 9V Battery with hook-up wires to a breadboards
  • 2 Breadboards
  • Many breadboard jumper wires and extension wires... MANY!
  • Preferably some soldering equipment
  • Amount of BYJ48 Stepper Motors equal to amount of blinds to be adjusted (3 in my case)

  • Some duct tape

Components - Closer Look

2404_original.png
9qnbp41g.jpg
FOHF83VIAMCFJPJ.MEDIUM.jpg

100K Thermistor

https://iprototype.nl/products/components/sensors/... (Note that this is a Dutch site)

This is a very, very fragile and small sensor. The sensor at the tip in encased in glass. Due to its small size this sensor is able to measure minor temperature changes at short intervals; it is very sensitive.

BYJ48 Stepper Motor

http://www.dx.com/p/28ybt-48-stepper-motor-with-ul...

This type of motor allows for high precision. There is already an excellent instructable on this component here. This motor comes with a compatible driver, which makes the process all that much easier.

Photoresistor

Nothing too fancy, photoresistors are easy to come by. Current flows through this resistor relative to the amount of light the tip of this component absorb.

Preliminaries

tinker01_sm.png
piece.png
sm_DSCN1057.JPG

Conversion pieces for stepper motor

The stepper motor will adjust the blinds by closing or opening them. As it stands now, the moving component of the motor has a gripping surface that is very narrow. Although not completely necessary, I recommend to print a part that encases the rotating tip of the motor. This will help utilize the rotating capabilities. Clay may also be an alternative, but is would of course be harder to get precise measurements. The whole should be about 3.5mm by 5mm. Don't forget the edges aren't completely straight; they have a slight curvature.

It is also possible to print a conversion piece to the end of the adjustable stick of the blind. This also isn't completely necessary, but should make it easier.

The next step in this process would be to put an object that will be atop the conversion piece described above. This object's purpose will be to connect the moving part of the motor to the adjustable part of the blind. This object should be as light as possible, so the motor doesn't encounter too much resistance. I used 2 A4 papers per motor, which I rolled up until the would encase the printed conversion pieces very tightly, after which I tape (not duct tape) at the end of the papers to hold it in place. I would then connect the two pieces of paper with duct tape, and would also apply the duct tape on either edges of the paper, reinforcing the grip on the conversion pieces. Don't forget to cut the paper if the stick gets too long.

Stepper motor placement

The motor itself should be stationed directly below the part rotating part of the blinds. The better directly below stationed, the better the rotation from the motor will translate to the rotating adjustable component of the blinds. The stick placed between these two components should also be as straight as possible.

Setting Up Wiring

inf_DSCN1100.JPG
DSCN1099_rinf.jpg
inf_DSCN1101.JPG
inf_DSCN1103.JPG
inf_DSCN1105.JPG

The wiring could get messy, especially if you won't customize the cable length by cutting and soldering. I personally opted for wiring cable with DuPont extension cable (with a male and female connector). Remember that you could need lots of it, depending how far apart your blinds will be.

9V circuit

Let's start with the circuit of the 9V battery. The flow of this circuit will be regulated through the relay module. If there is more than 1 blind with 1 motor to adjust, I've found it's best to use a breadboard to distribute the cables and keep oversight. The - from the 9V can be plugged directly to the - block to the side of the breadboard. The + from the 9V should be put into the + part of the breadboard through a 10ohm resistor. (If you don't have a 10ohm, use the next smallest resistor available. And don't think about not using a resistor either!) [pic 1] The + from there will be put in the first port of the relay (NOTE: the first port is usually on the left side of the relay, I've mixed it up.). Put the cable in the middle connector, and cable coming from the right connector. [pic 2] This cable will go in the + of the motor driver. Take care of putting this in the right header. The ground will then go directly into the ground of the 9V. This will power the motor, but not control the functions.

For every blind, a compartment of the relay should be utilized, and the above steps should be repeated. The + and - from the circuit will be pulled from the same source; the relay should take care of allowing one circuit to be operational at a time.

Motor control

Next is the motor control. Port 8, 9, 10 and 11 of the Arduino will be utilized. As above, these same pins will be shared across multiple motors (if applicable) (otherwise there wouldn't be enough pins available on the Arduino and you'd be forced to use an Arduino Mega, and the cables would get even messier). Here, a breadboard is also recommended. [pic 3] The cable from the Arduino port 8 will go to the IN1 of the motor driver, port 9 will go to IN2, 10 to IN3 and 11 to IN4.

Sensors

Here, soldering is definitely recommendend. A breadboard will hamper sensor placement, and you'd possibly need even more breadboards per every single sensor. [pic 4]

The sensor should be read through a pull-down registry. That means the + from Arduino should go directly into the sensor, but there should be a ground at the other side of the sensor. Inbetween the outside of the sensor and the effective part of the resistor, a cable should be attached, which would serve as the sensor readout. This is analog output and will go into the analog ports of the Arduino. [example at pic 5] The thermistor (temperature resistor) will use a 10Kohm as the pulldown, and the photoresistor will use a 220ohm resistor. The thermistor output will go to Arduino analog port 0 and 1, and the photoresistor output to analog port 2 and 3.

Relay

The Arduino ports that control the relay module should start a port 3, and ascending up relative to the amount of ports necessary (In my case 3, so 3 through 5). Of course, the relay should also be powered through the + and - headers.

Cooling fan

This one should be in port 12, with a 220ohm resistor.

Calibration 1: Sensors

This part will be more relevant if you're a perfectionist.

Calibration of thermistor

The thermistor is highly sensitive. If you read the raw output you will see much fluctuation. What you want to do is stabilize it to read out the temperature. The resulting equation would be actual_temperate = output * compensation. So is the current room temperature would be 20Celsius, the equation would be 20 = output * compensation. The compensation would then be 20 / output. This variable will be used in the Arduino sketch. In my case, the compensation was (23.5 / 90). Needless to say, this should be a float.

I've yet to test it to extreme temperatures, such as the freezing cold or an oven or something. If you want an accurate reading all around, you'll end up with a second degree equation. Because the temperature range we need is limited, and temperature readout itself won't be directly used, I've opted for a linear equation.

Calibration of photosensor

This will be more subjective. This will encompass how much sunlight is necessary to prompt an action, which will vary by situation and person. I've found a readout of 700 to be enough to prompt an action. Note that direct sunlight should be used for calibration, artificial light does not emit enough photons for proper calibration. Direct sunlight coupled with very temporary cloudedness would be ideal to observe the readouts.

Some code for calibration of the sensors

Typing in "A" in the serial monitor will get you the photosensor readouts. Type "B" will get the thermistor results, with compensation next to it. When in either clause, input any singular value and hit enter to get back into the loop.

#define TEMP1 54 //thermistor 1
#define TEMP2 55 //thermistor 2
#define PHOTO1 56 //photosensor 1
#define PHOTO2 57 //photosensor 2
float compensation = 23.5 / 90;
void setup() {
  Serial.begin(9600);
  pinMode(TEMP1, INPUT);
  pinMode(TEMP2, INPUT);
  pinMode(PHOTO1, INPUT);
  pinMode(PHOTO2, INPUT);}
void loop() {
  if (Serial.available() > 0) {
    char chr = (char)Serial.read();
    Serial.println(chr);
    if (chr == 'A') {
      while ((Serial.available() < 1)) {
        //String output = analogRead(PHOTO1) + "\t";
        Serial.print(analogRead(PHOTO1));
        Serial.print("\t");
        Serial.println(analogRead(PHOTO2));
        delay(250);
      }
    }
    if (chr == 'B') {
      while ((Serial.available() < 1)) {
        float tmp1 = (float)analogRead(TEMP1);
        float tmp2 = (float)analogRead(TEMP2);
        Serial.print((int)tmp1);
        Serial.print("\t, compensation:\t");
        Serial.print(tmp1 * compensation);
        Serial.print("\t");
        Serial.print((int)tmp2);
        Serial.print("\t, compensation:\t");
        Serial.println(tmp2 * compensation);
        delay(250);
      }
    }
  }
  delay(500);
}

Calibration 2: Motors

The motors need to know how much to turn to successfully close or open the blinds. This amount will be set in the final sketch as a variable. I've somewhat reconfigured the original motor sketch for it to turn to actual degrees instead of just a given number.

Note that the same amount of degrees will have the same effect across multiple blinds. A discrepancy herein could by due to the conversion stick not being straight enough or the conversion pieces being too loose from the conversion stick or the turning components themselves. Or it could be the blinds themselves, I'm sure they didn't calibrate every blind to close at exactly the same amount of turning during fabrication.

Code

Below is the code for calibrating. The syntax should be a capital letter ("A", "B", "C" or "D") (corresponding with the relay and motor number) directly followed by the amount of degrees to turn. This also includes negative amounts. So if you'd type "B-420" and hit enter, relay port 2 will open and the motor will turn minus 420 degrees. Make note when the blinds are opening and closing, does it need to rotate clockwise or counter-clockwise? This can be important to detect immediately, it's possible you can tell it to turn an amount of degrees open while the blinds are at maximum open, which can cause damage to your stepper motor, your conversion stick/pieces of even the blind itself. Also try not to give too high a number to turn at the beginning, there's no way to manually stop this when executing, the only thing you could do is pull the USB-plug.

Try adding smaller amounts that you tell it to turn together, so you know how much to turn at once. Then try to put that same number in the negative to see if it will fully open when closed or vice versa. Beware this all this could actually take some time.

#define RELAY1 3
#define RELAY2 4 #define RELAY3 5 #define RELAY4 6
#define OPEN true
#define CLOSE false
#define IN1  8
#define IN2  9
#define IN3  10
#define IN4  11
int Steps = 0;
boolean Direction = true;// gre
unsigned long last_time;
unsigned long currentMillis ;
int steps_left = 4095;
long time;
int tempDegrees = 0;
String tempString = "";
void setup() {
  Serial.begin(9600);
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
  pinMode(RELAY1, OUTPUT);
  pinMode(RELAY2, OUTPUT);
  pinMode(RELAY3, OUTPUT);
}
void loop() {
  if (Serial.available() > 0) {
    char chr = (char)Serial.read();
    Serial.println(chr);
    if (chr == 'A') {
      while (Serial.available() > 0) {
        tempString += (char)Serial.read();
      }
      tempDegrees = tempString.toInt();
      Serial.println(tempString + ",\ttmpDegrees: " + tempDegrees + "\t");
      tempString = "";
      delay (500);
      digitalWrite(RELAY1, OPEN);
      delay(100);
      turnDegrees(tempDegrees);
      digitalWrite(RELAY1, CLOSE);
      tempDegrees = 0;
      closeRelays();
    }
    if (chr == 'B') {
      while (Serial.available() > 0) {
        tempString += (char)Serial.read();
      }
      tempDegrees = tempString.toInt();
      Serial.println(tempString + ",\ttmpDegrees: " + tempDegrees + "\t");
      tempString = "";
      delay (500);
      digitalWrite(RELAY2, OPEN);
      delay(100);
      turnDegrees(tempDegrees);
      digitalWrite(RELAY2, CLOSE);
      tempDegrees = 0;
      closeRelays();
    }
    if (chr == 'C') {
      while (Serial.available() > 0) {
        tempString += (char)Serial.read();
      }
      tempDegrees = tempString.toInt();
      Serial.println(tempString + ",\ttmpDegrees: " + tempDegrees + "\t");
      tempString = "";
      delay (500);
      digitalWrite(RELAY3, OPEN);
      delay(100);
      turnDegrees(tempDegrees);
      digitalWrite(RELAY3, CLOSE);
      tempDegrees = 0;
      closeRelays();
    }
    if (chr == 'D') {
      while (Serial.available() > 0) {
        tempString += (char)Serial.read();
      }
      tempDegrees = tempString.toInt();
      Serial.println(tempString + ",\ttmpDegrees: " + tempDegrees + "\t");
      tempString = "";
      delay (500);
      digitalWrite(RELAY4, OPEN);
      delay(100);
      turnDegrees(tempDegrees);
      digitalWrite(RELAY4, CLOSE);
      tempDegrees = 0;
      closeRelays();
    }
  }
}
void turnDegrees(int degrees) {
  float tmpDegree = (float)degrees;
  degrees = (int)(tmpDegree * 11.38);
  Direction = degrees > 0 ? false : true;
  if (degrees < 0)
    degrees *= -1;
  while (degrees > 0) {
    currentMillis = micros();
    if (currentMillis - last_time >= 1000) {
      stepper(1);
      time = time + micros() - last_time;
      last_time = micros();
      degrees--;
    }
  }
  delay(2000);
}
void stepper(int xw) {
  for (int x = 0; x < xw; x++) {
    switch (Steps) {
      case 0:
        digitalWrite(IN1, LOW);
        digitalWrite(IN2, LOW);
        digitalWrite(IN3, LOW);
        digitalWrite(IN4, HIGH);
        break;
      case 1:
        digitalWrite(IN1, LOW);
        digitalWrite(IN2, LOW);
        digitalWrite(IN3, HIGH);
        digitalWrite(IN4, HIGH);
        break;
      case 2:
        digitalWrite(IN1, LOW);
        digitalWrite(IN2, LOW);
        digitalWrite(IN3, HIGH);
        digitalWrite(IN4, LOW);
        break;
      case 3:
        digitalWrite(IN1, LOW);
        digitalWrite(IN2, HIGH);
        digitalWrite(IN3, HIGH);
        digitalWrite(IN4, LOW);
        break;
      case 4:
        digitalWrite(IN1, LOW);
        digitalWrite(IN2, HIGH);
        digitalWrite(IN3, LOW);
        digitalWrite(IN4, LOW);
        break;
      case 5:
        digitalWrite(IN1, HIGH);
        digitalWrite(IN2, HIGH);
        digitalWrite(IN3, LOW);
        digitalWrite(IN4, LOW);
        break;
      case 6:
        digitalWrite(IN1, HIGH);
        digitalWrite(IN2, LOW);
        digitalWrite(IN3, LOW);
        digitalWrite(IN4, LOW);
        break;
      case 7:
        digitalWrite(IN1, HIGH);
        digitalWrite(IN2, LOW);
        digitalWrite(IN3, LOW);
        digitalWrite(IN4, HIGH);
        break;
      default:
        digitalWrite(IN1, LOW);
        digitalWrite(IN2, LOW);
        digitalWrite(IN3, LOW);
        digitalWrite(IN4, LOW);
        break;
    }
    SetDirection();
  }
}
void SetDirection() {
  if (Direction == 1) {
    Steps++;
  }
  if (Direction == 0) {
    Steps--;
  }
  if (Steps > 7) {
    Steps = 0;
  }
  if (Steps < 0) {
    Steps = 7;
  }
}
void closeRelays() {
  digitalWrite(RELAY1, CLOSE);
  digitalWrite(RELAY2, CLOSE);
  digitalWrite(RELAY3, CLOSE);
  digitalWrite(RELAY4, CLOSE);
}

Final Code

Temperature1 and Light1 should be placed between the blinds and the window, temperature2 somewhere in the shadow en light2 directly in front of the blinds. Also, the blinds should already be open when running this program. Don't forget to fill in all variables from previous calibrations. The code seems a bit of chopped up here, sorry. It's the autoformat of Instructables.

#define RELAY1 3
#define RELAY2 4 #define RELAY3 5 #define RELAY4 6 #define TEMP1 54 //A0 #define TEMP2 55 //A1 #define LIGHT1 56 //A2 #define LIGHT2 57 //A3 #define LIGHT3 58 //A4 #define LIGHT4 59 //A5 #define OPEN true #define CLOSE false #define COOLER 12 float compensation; float temperature1, temperature2; float upper_temp_threshold = 30; float lower_temp_threshold = 20; float light1, light2; float lower_light_threshold = 50; float upper_light_threshold = 700; int adjustBlindsBy = 2500; boolean blindsAreOpen = true; boolean isCooling = false; int tempDegrees = 0; String tempString = "";
int amountToOpenBlind1;
int amountToCloseBlind1;
int amountToOpenBlind2;
int amountToCloseBlind2;
int amountToOpenBlind3;
int amountToCloseBlind3;
int amountToOpenBlind4;
int amountToCloseBlind4;
/**
   Motor
*/
#define IN1  8
#define IN2  9
#define IN3  10
#define IN4  11
int Steps = 0;
boolean Direction = true;// gre
unsigned long last_time;
unsigned long currentMillis ;
int steps_left = 4095;
long time;
void setup() {
  Serial.begin(9600);
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
  pinMode(RELAY1, OUTPUT);
  pinMode(RELAY2, OUTPUT);
  pinMode(RELAY3, OUTPUT);
  pinMode(TEMP1, INPUT);
  pinMode(TEMP2, INPUT);
  pinMode(LIGHT1, INPUT);
  pinMode(LIGHT2, INPUT);
  pinMode(LIGHT3, INPUT);
  pinMode(LIGHT4, INPUT);
  pinMode(COOLER, OUTPUT);
  compensation = 23.5 / 90;
}
void loop() {
  temperature1 = getTemp(TEMP1);
  temperature2 = getTemp(TEMP2);
  light1 = analogRead(LIGHT1);
  light2 = analogRead(LIGHT2);
  if ((temperature1 >= upper_temp_threshold && blindsAreOpen) ||
      light1 > upper_light_threshold) {
    adjustBlinds(OPEN);
    if (!isCooling) {
      coolDown(true);
    }
  }
  if (temperature2 >= temperature1 && !blindsAreOpen) {
    adjustBlinds(CLOSE);
    if (isCooling) {
      coolDown(false);
    }
  }
  if (temperature1 <= lower_temp_threshold && isCooling) {
    coolDown(false);
  }
  Serial.println(temperature1);
  delay(1000);
}
float getTemp(int nr) {
  float tmp = 0;
  for (float i = 0; i < 5; i++) {
    tmp += analogRead(nr) * compensation;
    delay(100);
  }
  return tmp /= 5.0;
}
void adjustBlinds(boolean openIt) {
  closeRelays();
  delay (200);
  digitalWrite(RELAY1, OPEN);
  turnDegrees(openIt ? amountToOpenBlind1 : amountToCloseBlind1);
  digitalWrite(RELAY1, CLOSE);
  delay(1000);
  digitalWrite(RELAY2, OPEN);
  turnDegrees(openIt ? amountToOpenBlind2 : amountToCloseBlind2);
  digitalWrite(RELAY2, CLOSE);
  delay(1000);
  digitalWrite(RELAY3, OPEN);
  turnDegrees(openIt ? amountToOpenBlind3 : amountToCloseBlind3);
  digitalWrite(RELAY3, CLOSE);
  blindsAreOpen = !blindsAreOpen;
  closeRelays();
}
void coolDown(boolean cool) {
  digitalWrite(COOLER, cool);
}
void turnDegrees(int degrees) {
  float tmpDegree = (float)degrees;
  degrees = (int)(tmpDegree * 11.38);
  Direction = degrees > 0 ? false : true;
  if (degrees < 0)
    degrees *= -1;
  while (degrees > 0) {
    currentMillis = micros();
    if (currentMillis - last_time >= 1000) {
      stepper(1);
      time = time + micros() - last_time;
      last_time = micros();
      degrees--;
    }
  }
  delay(2000);
}
void stepper(int xw) {
  for (int x = 0; x < xw; x++) {
    switch (Steps) {
      case 0:
        digitalWrite(IN1, LOW);
        digitalWrite(IN2, LOW);
        digitalWrite(IN3, LOW);
        digitalWrite(IN4, HIGH);
        break;
      case 1:
        digitalWrite(IN1, LOW);
        digitalWrite(IN2, LOW);
        digitalWrite(IN3, HIGH);
        digitalWrite(IN4, HIGH);
        break;
      case 2:
        digitalWrite(IN1, LOW);
        digitalWrite(IN2, LOW);
        digitalWrite(IN3, HIGH);
        digitalWrite(IN4, LOW);
        break;
      case 3:
        digitalWrite(IN1, LOW);
        digitalWrite(IN2, HIGH);
        digitalWrite(IN3, HIGH);
        digitalWrite(IN4, LOW);
        break;
      case 4:
        digitalWrite(IN1, LOW);
        digitalWrite(IN2, HIGH);
        digitalWrite(IN3, LOW);
        digitalWrite(IN4, LOW);
        break;
      case 5:
        digitalWrite(IN1, HIGH);
        digitalWrite(IN2, HIGH);
        digitalWrite(IN3, LOW);
        digitalWrite(IN4, LOW);
        break;
      case 6:
        digitalWrite(IN1, HIGH);
        digitalWrite(IN2, LOW);
        digitalWrite(IN3, LOW);
        digitalWrite(IN4, LOW);
        break;
      case 7:
        digitalWrite(IN1, HIGH);
        digitalWrite(IN2, LOW);
        digitalWrite(IN3, LOW);
        digitalWrite(IN4, HIGH);
        break;
      default:
        digitalWrite(IN1, LOW);
        digitalWrite(IN2, LOW);
        digitalWrite(IN3, LOW);
        digitalWrite(IN4, LOW);
        break;
    }
    SetDirection();
  }
}
void SetDirection() {
  if (Direction == 1) {
    Steps++;
  }
  if (Direction == 0) {
    Steps--;
  }
  if (Steps > 7) {
    Steps = 0;
  }
  if (Steps < 0) {
    Steps = 7;
  }
}
void print(String str) {
  Serial.println(str);
}
void closeRelays() {
  digitalWrite(RELAY1, CLOSE);
  digitalWrite(RELAY2, CLOSE);
  digitalWrite(RELAY3, CLOSE);
  digitalWrite(RELAY4, CLOSE);
}
void openRelays() {
  digitalWrite(RELAY1, LOW);
  //digitalWrite(RELAY2,LOW);
}