Introduction: HVAC Zoning With Arduino to Improve Cooling Control

Control an HVAC register with a servo to improve room comfort throughout the day

Like most US homes, our 1000sqft house is heated and cooled by forced air in a single zone. There is one thermostat which turns the system on or off, and all areas are fed hot or cold air at the same time.

Ideally, with the airflow to all rooms balanced, every room would reach the temperature set on the thermostat, but this can't work at all times of the day. In summer, the sun's varying angle in the sky means that the east side of the house is heated more in the morning, the south walls receive most at midday, then the west walls in the late afternoon. This heat concentration means rooms facing the sun at a given time of the day will be hottest.

To counteract this effect, zones can be incorporated into the ductwork. These are areas that can receive different airflow to provide greater heating/cooling. So a south facing room could get more cool air in the middle of the day, and less in the morning and evening. In a new installation, zones are created using sections of ductwork with electrically operated dampers, and a thermostat/timer to manage the additional zones.

For my project, I wanted to create a basic, low cost zoning system for warm months. It would keep most of the cool air in the main living areas during the day, and then direct more of it into my west-facing bedroom to provide extra cooling in the evening. As well as balancing the extra heat load of that room, this would bring the bedroom to a cooler sleeping temperature without having to cool the rest of the house quite as much.

Step 1: Finding a Solution

I found that one large register in the living room is on the same section of ductwork as the main bedroom. By manually closing the living room register I could divert a stronger flow of air to the bedroom in the evening. This worked, but I had to close the damper every evening and open it again in the morning. This should be automated!

My solution was to use an Arduino to control a servo added inside the register, which could operate the damper mechanism. To trigger the servo events, I considered temperature monitoring in both areas, but it seemed that a simpler option would be to open and close the damper based on the time of the day. The Arduino does not keep track of time when power is lost, so to use time triggers accurately a real time clock (RTC) module would be needed.

This project has several sections - these are the main topics:

  1. Convert register to operate electrically, using a servo
  2. Accurately control the servo positionusing an Arduino
  3. Configure an RTC to maintain accurate time even if power is lost to Arduino
  4. Configure alarmsto move the servo at set times
  5. Troubleshoot the Arduino software (sketch)

Step 2: Limitations of Zoning

An important consideration when adding zoning to a forced air system is that it will increase the pressure in the ductwork, in a similar way to a dirty air filter.

Decreased airflow/higher pressure

The first problem this creates is more load for the blower, which could shorten its lifespan.

Increased pressure also mean less airflow over the evaporator coil (part of the inside unit/air handler). This can cause the evaporator coil to get too cold and begin to freeze over from humidity in the air. This in turn prevents air from contacting the metal of the coil and cooling down efficiently, so the system just circulates warm air. The refrigerant will also get too hot, increasing the operating temperature of the condenser (outside unit). This may temporarily shut off if it overheats.

The easiest solution to both these issues is to make sure that you don't restrict the airflow too much. The amount will vary, but blowers are designed to withstand some increased pressure from a dirty filter, and will be able to handle the small difference that comes with closing off vents, if you don't close too many.

My project only closes one vent of seven in the house, so there is still plenty of airflow. I also replace the filter regularly (every 14 days in summer) to allow as much air as possible to flow through the evaporator coil.

If you plan to close more than about 20% of your vent area at the same time, you should increase the size of your ductwork and return filter so there is always plenty of airflow even with multiple vents closed. Consult an HVAC technician for recommendations based on your installation.

Noise

When you close a vent, it will make more noise as the air tries to force its way through. You can experiment with the closed angle of the vanes to allow some air through and lower the noise, but this is a tradeoff with the diversion effect you want to achieve.

If you notice that your blower motor itself is making more noise, this is a sign that it is being stressed and the vent should not be closed. Have the motor inspected for wear.

Prevent frozen pipes

Do not block airflow completely in rooms with water pipes that could freeze in winter. Frozen pipes can cause major floods. In this case you could set the close angle to cut down airflow, without allowing room temperature to get too cold. A thermostat could be added to open the vent again, or sound an alarm.

Multi stage compressors

A better solution would be to use an AC system with a two or three stage compressor in the condenser. These can deliver lower cooling power when the heat load is lower, but can also work efficiently with zones much smaller than the full house and will prevent freezing of the evaporator coil. However, these compressors are not standard yet, and require a multi speed air handler, so replacing an existing system would be very expensive.

Step 3: Parts List

Total project cost is around $60

Arduino
I'm using an old Arduino Duemilanove (from 2009) which has been used in several projects over the years. You could use another Arduino compatible board, as long as it operates at 5V, but the connections for the RTC module might vary.

Real time clock (RTC) module
I chose the DS3231, which is a self-contained accurate clock module supported by Arduino libraries. It uses a 3V lithium button cell to maintain the internal clock time for 2-3 years. You can find them on eBay or other online electronics stores that sell Arduino parts.

Servo
Depending on your register mechanism, you should be able to use a standard full-size servo. I got a metal geared version (Tower Pro MG945) for the extra reliability and resistance to gear stripping. A servo horn (supplied with the servo) is used to push a rod connected to the damper mechanism. Smaller servos will give you more clearance inside the duct, but may not be strong enough to work reliably over time.

Push rod
I tried different materials until I found a steel wire that was thick enough to resist bending under load, but thin enough to be shaped and fitted into the servo horn and the damper mechanism. Some experimentation will be needed.

Servo bracket
A strip of aluminum angle is fixed to the register frame with metal screws. The servo is mounted to this bracket so that it is in the correct position to push and pull the damper mechanism. You will have to custom fit a bracket to fit your own register and servo. The bracket and servo must also fit freely inside the duct opening when fitted - something I didn't plan correctly on my first attempt.

Relay
I found that the Arduino's +5V provided enough power to operate the servo, so it doesn't need a separate power supply. However, during power-on the servo would jump around randomly for a fraction of a second, potentially causing damage to the push rod. I added a relay to prevent power flowing to the servo until it's needed. I used a small 5V relay that could be activated directly from one of the Arduino pins. The relay must have a low activation current to operate reliably from the Arduino pin.

Power supply
I used a spare 12V power supply from another device, plugged into an outlet in the attic. Ideally a 6V supply should be used, because the Arduino's internal regulator drops the supply voltage to a uniform 5V, so anything above that gets divided through a resistance and lost as heat. The power supply must be at least 5.5V to ensure a reliable 5V after voltage loss through the regulator. I didn't measure current draw, but a 500mA supply should work to power most servos.

Breadboard, jumpers and servo switch
I put the circuit together for testing on a breadboard, allowing for quick setup and adjustment. This method requires male-male jumper wires or solid-core wire, to make connections between the Arduino and breadboard. Once I had my circuit worked out I removed the breadboard and soldered anything that didn't plug into the Arduino.

I added a switch to isolate the servo. When testing the mechanism and software, it can be useful to turn the servo off to prevent unintended movements that might damage the push rod or vanes.

Step 4: Upgrading the Register to Servo Operation

This started as a standard 12"x8" ceiling register with manual damper lever. I wanted the modifications to be reversible, if possible, in case the system didn't work.

Lubricate pivot points
This register is made from pressed steel without very precise tolerances. There is some friction in the pivot points of the damper that normally helps to hold the vanes in the correct position. I oiled all these points to make it easier for the servo to open and close the damper.

This does mean that the damper will not always stay in a fixed position without the servo, so if you need to reverse this process you would have to degrease the pivot points, or not lubricate all of them in the first place.

Servo bracket
The bracket is made from a strip of aluminum angle that I had spare. This part was probably the hardest to get right, as it needs to hold the servo in the right position, without jamming in the duct when the register is fitted. My register is fitted to a tapering duct box, so there was just enough space if I moved the servo away from the edge by about 1". When I test fitted the register, the servo was too high, so I bent the bracket to lower the height. This caused a crack on one side, but it still works.

Servo position
The servo has to be positioned so that the servo horn can pull or push a rod connected to one of the linkage points. You will have to experiment with different bracket dimensions to make sure the action works correctly. The vanes of the damper should open and close completely, without running out of servo range.

The following photos show the opened and closed positions. The servo horn should be roughly parallel to the vanes.

For easier adjustment, set up your servo so that you don't need the full range of servo motion to control the vanes. The final angles can then be set by adjustments in the Arduino sketch, rather than by mechanical adjustment.


Servo in open position


Servo in closed position

Link rod
I used some steel wire to make a link between the servo horn and one of the damper vane pivots. This will take some trial and error, as you need to bend the wire to fit into the pivot and connect back to the servo. If your servo is not in line with the pivot (because of space restrictions in the ductwork), you will need to add a bend in the wire to translate the movement into the right plane.

The link rod must not interfere with the closing vanes - I attached it through a hole drilled in the top of the frame that carries the top links of the vanes. You could also try fitting the rod inside one of the pivots from the end, but I found this was unreliable and the wire would come loose.

You could use a thin strip of metal rather than a wire for added stiffness.

Step 5: Mechanical System - Inside the Register

My duct opening is 12"x8". Your setup may vary from this, depending on the size of the register and the amount of space available within the duct. Smaller openings will be more restrictive for servo positioning.

The servo bracket needs to be rigid enough to resist the force of the servo pushing and pulling the vanes, otherwise it will not open or close fully. I fixed the bracket to the frame using sheet metal screws. Pre-drill screw holes and avoid having screws too close to the vanes.

Because the servo horn has a limited range of motion where it can push or pull effectively, you need to make sure that the open/close action of the vent fits inside this range.

If the servo comes up to its own limit stops the vanes will not open or close fully. You will need to reposition the servo horn on the servo drive spindle, so that the horn can move freely between the opened and closed positions without hitting the limits.

I attached my link rod to the hole at the end of the servo horn, and measured the rod so that the servo has extra movement on each end of the range. This range will be fine tuned later in the software. If your servo can't open and close the vanes fully you will need a longer servo arm, or to glue on an extension.

Servo wire extension

Installation is easier if you have 2-3' of wire between the servo and the controller. Use a specific servo extension cable or three solid core wires, with similar color coding to the servo wires. Tape the connection to prevent it pulling apart.

For testing you can run this extension wire out into the room and plug it into the Arduino. This makes things a lot easier to adjust than when it is all hidden in the attic.

If space is a problem

When I tested the servo action before installing in the ceiling, it worked properly, but when installed the servo horn would snag on the inside of the duct. I adjusted the bracket by bending one side (cracking it in the process), but still couldn't get enough clearance for full movement. In the end I added a spacer between the register and the ceiling.

The spacer is ½" MDF, painted white. I cut a piece of MDF ¼" wider than the register edges, then cut out a hole to fit around the mechanism. This extra ½" of clearance was enough to allow full servo movement again.

Step 6: Arduino Hardware

I assembled this circuit on breadboard first, but you could use stripboard or a PCB for a more permanent solution. I soldered solid core wires to the RTC so that it could lie flat in the final enclosure. If you insert the RTC in the breadboard it takes up more vertical space. Once I had everything working I removed the breadboard, soldering the connections instead for more reliable connections.

Parts

  • Arduino
  • 6V-12V power supply
  • DS3231 real time clock (RTC) module
  • 5V relay SPST
  • Servo power switch (optional)

Circuit diagram produced using TinkerCAD.

Before connecting the RTC, confirm which Arduino pins should be connected to SCL and SDA, using this reference:

Connect the SCL pin to the I2C clock SCL pin on your Arduino. On an UNO & '328 based Arduino, this is also known as A5, on a Mega it is also known as digital 21 and on a Leonardo/Micro, digital 3
Connect the SDA pin to the I2C data SDA pin on your Arduino. On an UNO & '328 based Arduino, this is also known as A4, on a Mega it is also known as digital 20 and on a Leonardo/Micro, digital 2

- source: Adafruit

The diagram shows the SCL and SDA pins on the current Arduino Uno. You'll see in the photos that I'm using A4 and A5 on my Arduino Duemilanove.

The relay pins will depend on the model you're using, so refer to the technical documentation. Connect the coil to digital pin 9 and ground. The switched, or normally open (NO), pins are connected to 5V and the servo switch.

The power supply should be between 6V and 12V and be able to provide at least 500mA of current. A 6V supply will be most efficient, as it's closest to the Arduino's operating voltage of 5V.

Operation

The RTC keeps track of the time of day, even if power has been lost. An alarm will be triggered at 7pm and at 6am, to close and open the vent respectively. The Arduino uses these alarm triggers to send a defined angular movement to the servo. The relay is used to control the +5V supply to the servo, disabling it unless an alarm is activated. Without the relay the servo will jump around when the Arduino is first powered on, because a steady servo signal has not yet been sent to the servo.

The servo switch can be used to prevent any servo movement during testing. If you reset the Arduino it can prevent the servo moving to its default position.

Step 7: Calibrate Servo Range

Operating the Arduino is not covered here, but there are online resources to help you get started, such as this one from Adafruit. You will need to have the Arduino IDE installed on your computer, and the Arduino connected and configured to use a USB port.

Disconnect register mechanism

I recommend removing the servo horn and fitting a spare for this testing. This disconnects the link rod until you're confident the servo is moving roughly in a safe range to operate the vent. If you keep the rod in place and the servo moves too far it will bend the rod or damage the bracket. Upload the following code (copy and paste, or download the .ino file above).

The Arduino will reset and begin sweeping the servo through the full range of motion. If this goes well, move on to the next step.

Upload this sketch to the Arduino (copy and paste, or download the Servo_calibrate.ino file above). The servo should move back and forth, but not very far in either direction. Note where the mid-point of the movement is - this represents 90° in the software.

#include <Servo.h> 

int servoPin = 9;
int relayPin = 6;
int closedAngle = 70;
int openAngle = 110;
 
Servo servo;  
 
int angle = 0;   // servo position in degrees 
 
void setup() 
{ 
  servo.attach(servoPin);
  pinMode(relayPin,OUTPUT); 
} 
 
 
void loop() 
{ 
  digitalWrite(relayPin, HIGH); // turn on relay (connects servo)
  // move from closed to open
  for(angle = closedAngle; angle < openAngle; angle++)  
  {                                  
    servo.write(angle);               
    delay(10);                   
  } 
  // move from open to closed
  for(angle = openAngle; angle > closedAngle; angle--)    
  {                                
    servo.write(angle);           
    delay(10);       
  } 
  digitalWrite(relayPin, LOW); // turn off relay
}  


Configure the servo angles to match your register mechanism

Unplug the Arduino and reconnect the servo horn with link rod. Position the servo horn on the spindle so that the 90° point is roughly halfway between the opened and closed positions of the vent. This doesn't have to be perfect, it just helps to keep the servo movement between the internal end stops.

Now you will need to widen the range of the servo movement, so that the end positions (or servo angles) match the opened and closed positions of the vent.

The code above allows the servo to move in the middle of the range (between 70° and 110°). You will need to adjust the two variables 'openAngle' and 'closedAngle' at the top of the script to match the final opened and closed angles of the vent. Angles can be specified between 0 and 180. This will involve some trial and error - increase the range of the variables and upload to the Arduino, check, and repeat.

Note down the two variable values for the next step.

Step 8: Install Arduino Libraries to Interface With the RTC

The final code for this project requires four libraries that control the RTC, the alarms (open/close times), and the servo. The Servo library comes with the Arduino IDE, so you don't need to add it. Download the additional three libraries as zip files from the Github links below.

  • TimeLib
  • TimeAlarms
  • Servo - already included with the Arduino IDE
  • DS3232RTC - manages communications with the RTC (this works with the DS3231, despite the name)

Click 'Clone or download', then 'Download ZIP'. Import the libraries into the Arduino IDE using Sketch > Include Library > Add .ZIP Library. You may have to restart the IDE before the libraries are usable.

Further installation help is available here.

The libraries will be referenced (or 'included') in the final Arduino sketch with the following code.

#include <TimeLib.h>
#include <TimeAlarms.h>
#include <Servo.h>
#include <DS3232RTC.h>

The next step will use the time and RTC libraries to set the time on the RTC.

Step 9: Set the Time on the RTC

The RTC needs to be set to the actual time before it can be used. The time is programmed with the following script, which needs to be uploaded and run once. The code will then be replaced with the final project code.

If this code remains on the Arduino it will reset the time on the RTC every time the Arduino is restarted. You must run the code on this page and then - without disconnecting the Arduino - upload the final project code on the next page.

  1. You can copy paste this code into an Arduino IDE window, or download the RTC_set_time.ino sketch above.
  2. Configure the correct time in the code (line which starts 'setTime'). The time is specifed in 24 hour h,m,s format. For example, 2:29pm would be 14,29,0. You can change the date too, but it is not used for this project.
  3. Upload the code at the set time, so for this example, click Upload at 2:29pm.
  4. Run the Serial Monitor - the Arduino should be reporting the correct time once per second.
  5. Keep the Arduino plugged in. If power is interrupted the RTC will be set back to 2:29pm again.
  6. Upload the code in the next step to disable the time set feature.

#include <TimeLib.h>
#include <TimeAlarms.h>
#include <DS3232RTC.h>

AlarmId id;

void setup() {

  Serial.begin(9600);
  
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
 if(timeStatus()!= timeSet)
 Serial.println("Unable to sync with the RTC");
 else
 Serial.println("RTC has set the Arduino time");
 

  while (!Serial) ;   // wait for Arduino Serial Monitor

  setTime(14,29,0,9,19,17);   // set time in 24 hour h,m,s,m,d,y format to 2:29:00pm Sep 19 2017 (if comments are removed)
  // re-comment and upload sketch again to prevent RTC being reset every time Arduino is powered on
  
}

void loop() {
  digitalClockDisplay();   // prints time to Serial Monitor
  Alarm.delay(1000);   // wait one second between clock display
}


void digitalClockDisplay() {
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.println();
}

void printDigits(int digits) {
  Serial.print(":");
  if (digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

Step 10: Set Alarm Times - Arduino 'RTC Servo Control With Alarms' Sketch

This is the final sketch that will remain on the Arduino. It contains the servo limit angles, the alarm times, and a startup test sequence.

Enter alarm times

The sketch uses "alarms" to trigger events, in this case servo motion.

Time is specified in 24 hour h,m,s format. For example, 7pm would be 19,00,00 as shown in the following example. This code shows the alarm set to close the vent at 7pm and open it at 6am. The alarms are referenced by name later in the sketch (MorningAlarm, EveningAlarm). This project uses one alarm to open the vent and one to close, but you could add more events by adding another line and changing the alarm name.

  Alarm.alarmRepeat(6,0,0,MorningAlarm);  // 6:00am every day
  Alarm.alarmRepeat(19,0,0,EveningAlarm);  // 7:00pm every day


Enter servo limit angles

Update the code with your specific servo angles from the previous step (closedAngle and openAngle).

int closedAngle = 73;
int openAngle = 140;

Final project code

You can copy and paste this code, or download as an Arduino sketch file (.ino) above.

#include <TimeLib.h>
#include <TimeAlarms.h>
#include <Servo.h>
#include <DS3232RTC.h>

int servoPin = 9;
int relayPin = 4;
int closedAngle = 73;
int openAngle = 140;
int servospeed = 40;   // Lower values will make servo faster but louder
 
Servo servo;  
 
int angle = 0;   // servo position in degrees 

AlarmId id;

void setup() {

  pinMode(relayPin,OUTPUT);
  
  Serial.begin(9600);
  
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
 if(timeStatus()!= timeSet)
 Serial.println("Unable to sync with the RTC");
 else
 Serial.println("RTC has set the Arduino time");
 

   while (!Serial) ;   // wait for Arduino Serial Monitor

  // setTime(14,29,0,1,19,17);   // set time to Saturday 2:29:00pm Jan 19 2017 (if comments are removed)
  // re-comment and upload sketch again to prevent RTC being reset every time Arduino is powered on
  
  // create the alarms, to trigger at specific times
  Alarm.alarmRepeat(6,0,0,MorningAlarm);   // 6:00am every day
  Alarm.alarmRepeat(19,0,0,EveningAlarm);   // 7:00pm every day
  // Alarm.alarmRepeat(dowSaturday,8,30,30,WeeklyAlarm);   // 8:30:30 every Saturday

  // create timers, to trigger relative to when the Arduino is powered on
  //Alarm.timerRepeat(6, Repeats);           // timer for every 6 seconds
  //id = Alarm.timerRepeat(2, Repeats2);      // timer for every 2 seconds
  Alarm.timerOnce(1, OnceOnly);            // called once after 1 second
}

void loop() {

  digitalWrite(relayPin, LOW);   // turn off relay
 
  digitalClockDisplay();   // prints time to Serial Monitor
  Alarm.delay(1000);   // wait one second between clock display
}

// functions to be called when an alarm triggers:

void MorningAlarm() {
  servo.attach(servoPin);   // turn on servo PWM pin
    servo.write(closedAngle);   // set start position
    Alarm.delay(250);   // delay to settle PWM signal
    digitalWrite(relayPin, HIGH);   // turn on relay (connects servo +5V)
      for(angle = closedAngle; angle < openAngle; angle++)   // Open vent    
      {                                
      servo.write(angle);           
      Alarm.delay(servospeed);       
      }
      Alarm.delay(600);   // Allow servo to reach end position
    digitalWrite(relayPin, LOW);   // turn off relay (disconnects servo power)
  servo.detach();   // turn off servo pin
}

void EveningAlarm() {
  servo.attach(servoPin);   // turn on servo PWM pin
    servo.write(openAngle);   // set start position
    Alarm.delay(250);   // delay to settle PWM signal
      digitalWrite(relayPin, HIGH);   // turn on relay (connects servo +5V)
        for(angle = openAngle; angle > closedAngle; angle--)    // Close vent
        {                                  
        servo.write(angle);               
        Alarm.delay(servospeed);                   
        }
      Alarm.delay(600);   // Allow servo to reach end position
      digitalWrite(relayPin, LOW);   // turn off relay (disconnects servo power)
  servo.detach();   // turn off servo pin
}

void OnceOnly() {
  Serial.println("Motion test (open -> close -> open");  // Power on self-test

  servo.attach(servoPin);   // turn on servo PWM pin
    servo.write(openAngle);   // set start position
    Alarm.delay(250);   // delay to settle PWM signal
      digitalWrite(relayPin, HIGH);   // turn on relay (connects servo +5V)
        for(angle = openAngle; angle > closedAngle; angle--)   // Close vent
        {                                  
        servo.write(angle);               
        Alarm.delay(servospeed);                   
        }
      
          Alarm.delay(300);
        
        for(angle = closedAngle; angle < openAngle; angle++)   // Open vent    
        {                                
        servo.write(angle);           
        Alarm.delay(servospeed);       
        }   
    
          Alarm.delay(300);
        
        for(angle = openAngle; angle > closedAngle; angle--)   // Close vent
        {                                  
        servo.write(angle);               
        Alarm.delay(servospeed);                   
        }
    
          Alarm.delay(300);
    
        for(angle = closedAngle; angle < openAngle; angle++)   // Open vent    
        {                                
        servo.write(angle);           
        Alarm.delay(servospeed);       
        }  
    
        Alarm.delay(600);   // Allow servo to reach end position
      digitalWrite(relayPin, LOW);   // turn off relay (disconnects servo power)
  servo.detach();   // turn off servo pin
}

void digitalClockDisplay() {
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.println();
}

void printDigits(int digits) {
  Serial.print(":");
  if (digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

You will see that the setTime feature has been commented out (with '//'). If you need to update the time on the RTC you can uncomment this line, edit the time and upload. Then immediately comment the line again and re-upload.

The servo speed can be configured with the servospeed variable. Lower values are faster, but make the servo louder when the register closes. A setting of 40 takes about 3 seconds to close with my relay.

You can now unplug the Arduino from your computer and try it with the power supply.

Startup servo test sequence

The script includes a test sequence so you can check everything works smoothly. In normal operation there are no indicators that the Arduino is active until one of the alarms is activated.

When the Arduino is first powered on, the servo will sweep open and closed two times, and stop in the open position. It will then wait until an alarm is activated.

If the servo sounds like it is not running smoothly, it may be jammed against the inside of the duct. If there is no servo movement, check that the servo switch is on, and that the relay doesn't have a loose connection. You should hear the click of the relay before the servo moves.

Step 11: Final Installation

Once the software has been tested, it's a good idea to put the electronics into an enclosure for protection. I used an old external hard drive case.

For an invisible finish, you will need to hide all the wiring. Move the controller into the attic, or a suitable space next to the ductwork. You will need an electrical outlet near the Arduino to provide power. If the air handler is in the attic there should be an outlet next to it, otherwise you will need to have an electrician install a new one. This is relatively simple if power can be taken from a ceiling light fitting.

Drill a small hole through the duct into the attic/adjacent space. Fit the spacer onto the register.

Run the servo wire, with extension, through the hole, being careful not to damage the cable on the sheet metal. Leave enough wire visible to be able to access the servo for maintenance, and then tape the hole closed with aluminum duct tape. Replace the register.

Place the controller on the other side of the duct and reconnect the servo wires. Tape the connection to prevent it pulling apart. Plug in the power supply and listen for the servo test sequence. It helps to have someone else watch the servo to make sure it is still working properly. The sequence should end in the open position and will close when the next close alarm arrives (7pm in the example).

If you power on the controller after 7pm it will not close on the first evening, because the alarm is only triggered once, exactly at 7pm. The next day it will close at 7pm.

Step 12: Maintenance

Updating the current time

After a few months you may need to reset the time on the RTC as it will gradually drift. Connect the Arduino back to your computer and upload the 'RTC time set' sketch, with the new current time. Then, without disconnecting the Arduino, upload the 'RTC servo control with alarms' sketch. You will also need to carry out this process if you change the RTC battery.

Change alarm times

Connect the Arduino to your computer and upload the final sketch, with the alarm times adjusted. The RTC current time does not need to be adjusted.

Adjust servo angles

Over time the vent may not close exactly, as materials stretch and wear. You can re-upload the 'RTC servo control with alarms' sketch, modifying the servo limit variables 'openAngle' and 'closedAngle'. You may also need to adjust the link rod if the servo can't fully close the vanes.

Step 13: Overcoming Project Difficulties

This project began as a simple idea, with a seemingly simple solution. In the end it took much longer than I expected, with much frustration and many hours working out solutions to problems I didn't expect. These sections were the most problematic, so I've added some tips.

Link rod position and shape

It took a lot of experimentation to get the right wire for the link rod and to get it bent into just the right shape. This process is trial and error but you'll get there with enough persistence!

Fitting servo and bracket into duct space

The restrictive space inside the duct was just slightly the wrong size for my servo and bracket. It took lots of adjustment and eventually an extra spacer to get this to work. I'd recommend keeping the servo as low as possible to give it plenty of space, and moving it in from the edge by an inch or so.

Programming RTC - libraries, alarms, setting time

The real time clock works well once configured, but getting it going was a learning curve. It did not come with any instructions, but I eventually found a library that was compatible and then had to learn how to download, install, and use it. Part of this involves editing the sample sketches and uploading them several different times to get things set correctly. Fortunately the sketches were well annotated, and once this is done the Arduino works without any further input.

Servo control - power on jitter and signal jitter

The Arduino does not control the signal to the servo reliably by itself. At power on there is a violent movement and the movement is not always smooth when servo angles are sent. This is why I had to add the relay and the code in the sketch to switch the servo control on and off. I also slowed the movement by adding delays.

Testing - access to location

You really need to thoroughly test and finish the project before installing in the ceiling as you will find problems. I had to take the register down multiple times for adjustment, and crawl in and out of a very hot attic to position the control box. When you're testing the mechanism with the register in place, use long extension wires so the Arduino is inside the room. You will need to make small adjustments to get it all working accurately. Allow it to run for a few days to make sure you are happy with the operation. Once setup you can expect it to work for a long period without any maintenance.

Step 14: Potential Upgrades

For my situation, this project solves the problem, but the same mechanics and Arduino system could be used for more complex zoning requirements.

Multiple zones

You could quite easily add more servo mechanisms to other vents, to allow different zones to operate through the day. The zones would be programmed within the Arduino sketch to come on and off based on different RTC alarms. In my scenario, a second closer in the bedroom could shut to prevent it being cooled during the day time, so more air flow goes to the main living areas where it's needed. Again, do not restrict the air flow too much by closing multiple vents at once as you could cause damage to the blower or inefficiency at the evaporator.

Sensor based zoning

This project is based on time, but it could be enhanced with temperature sensors to open or close based on actual demand.

Variable vent opening

The servo could be controlled with various degrees of closure, rather than opened or closed. Part-opened will still supply some air to the first space, and may help with air flow if you are closing multiple vents

Remote programming

The ability to adjust time and servo angle remotely would make maintenance much easier.

Automation Contest 2017

Runner Up in the
Automation Contest 2017