Introduction: Cheap Programmable Water Heater Timer

My power company offers a power plan that is cheaper than average during the morning and night but much more expensive during peak day hours. So to save some money from the water heater turning on from noon to 7pm I created this programmable relay. The water heater probably doesn't turn on much during those hours, but it should save me a bit. Additionally, I really don't need hot water during the hours that I am not home, so I don't see any point to having the water heater store 140 degree water for half of a day. Although there is probably not much heat loss due to the 3 inch foam insulation.

The list of parts and price is as follows:

IX442N dual MOSFET gate driver $1.57 (glued to relay on bottom)

RT314A05 SPDT latching relay 5vdc $6.63 -> currently 3.71 (orange box in picture)

Mini USB charger $3

Trinket 5v 8Mhz $7 (glued to relay on the right)

47ohm resistor

Bike repair kit box to hold everything (green box)

6 inches of 10 gauge wire

Step 1: The Ugly Details

My water heater has 2 heating elements, each of which use 3800 watts. So double breaker 240V, 15.8 amps. Each element has its own thermostat and only one is able to be turned on at any given time. I believe this is typical of most standard tank water heaters.

Now, the hard part was to figure out how to create a switch for 16 amps. There are many types of relays that are capable of acting as a switch for any amount of power. I wanted something that would use very little power and would not require a constant output from the microcontroller. A latching relay does exactly that. Input a voltage through the switch coil and it will move the switch into one position, input the voltage in the opposite direction and the switch moves back to the starting position. It takes a few milliseconds to switch, then afterwards, the power can be turned off and the switch will remain in the same place. Non-latching relays go back to the NC (normally closed) position once power is cut, so you would have to leave 5V power to the coil for 7 hours. My relay has a 62 ohm coil so that would suck up a massive 0.4W.... Super small, but I wanted the least amount of power possible. The relay I picked from mouser.com is RT314A05. It runs on 5VDC with a 62ohm coil resistance, and can switch a max of 250VAC and 20 amps. It is a single pole-double throw (SPDT) form C.

Next you have to find a way to power the coil in either direction. This was the hardest part for me because I don't understand many electronic components. Nevertheless I discovered that a mosfet gate driver could do the job. You need a dual gate driver to control 2 outputs. Then you have 2 gate driver inputs driven by a microcontroller. Turn one input on and the corresponding output will go to a voltage high while the other output acts as the ground. Thus you create a way to power the coil with current in either direction. I used the IX442N dual gate driver.

Finally, the for programmable hardware I chose Adafruit's 5V Trinket (https://www.adafruit.com/products/1501). It has 5 I/O pins and only uses around 12mA. I was already familiar with the Arduino Uno platform,
so it made sense.

Step 2: Programming the Trinket

To program the Trinket, I followed the Adafruit help guide at https://learn.adafruit.com/introducing-trinket

The language is the same as Arduino, but the setup for the programmer is different.

I wrote the code to keep track of time, turn the power on from 7PM -11:59AM and the weekend, and turn the power off from noon -6:59PM. There is a complication with the Trinket's time keeping, so you basically have to double check it and get it as close as possible. Each time crystal used may vary so simply saying 1000 millis = a second may not be accurate. The number that worked for my Trinket was 30235 millis = one minute. I guess the processor rate runs at half of what it is designed to so 1 minute = 30000 milliseconds rather than 60000, plus 235 extra to account for the error I found.

See my code below, and attached:

///Currently programmed to be plugged in on Saturday at 10am.
///To change this modify day and/or hour below int day = 7; //1=sunday...7=saturday int hour = 10; //requires plug in at noon /// int relayPinoff = 1; // the number of the LED pin, INA int relayPin = 0; // the number of the relay pin, INB //OUTA to bottom left, OUTB to right int minute = 0; int power = 1; //0=off 1=on(NC) relay will start in NC mode, power on unsigned long previousMillis = 0; // the follow variables is a long because the time, measured in miliseconds, // will quickly become a bigger number than can be stored in an int. long interval = 30235; // interval of one minute. millis not very accurate

void setup() { // set the digital pins as outputs: pinMode(relayPinoff, OUTPUT); pinMode(relayPin, OUTPUT); digitalWrite(relayPinoff, LOW); digitalWrite(relayPin, HIGH); //switch the relay to NC (heater on) delay(25); //for relay time of 7ms digitalWrite(relayPin, LOW); } void loop() { //rollover at 4,294,967,295ms =4,294,967s =71582.78m =1193.046h =49.7day //even if after rollover current - previous will calculate the correct difference // 7302 - 4,294,967,255 = 7342ms //1hr=60min=3600s=3600000ms, 1m=60s=60000ms // check to see if it's time to switch the relay; that is, if the time // is between noon or 1900 hrs the relay/power to heater should be off. // if the difference between the current time and last time you updated // the minute is bigger than the interval, i.e. it has been another minute // then update the minute counter, and hour counter if needed. unsigned long currentMillis = millis(); if(currentMillis - previousMillis > interval) { //this section runs every minute if (minute ==59) { minute = 0; if (hour ==23) { hour = 0; //midnight if (day < 7) { day = day +1; } else { day =1; } } else { hour = hour +1; } } else { minute = minute +1; } previousMillis = currentMillis;

if (day >= 2 && day <=6) { //weekdays if (hour >= 12 && hour < 19 && power == 1) { //power off during peak hrs noon-7pm digitalWrite(relayPinoff, HIGH); //switch the relay to NO (heater off) //digitalWrite(LEDPin, LOW); //mark that heater is off delay(25); //for relay time of 7ms digitalWrite(relayPinoff, LOW); //latching relay requires no power after switching power = 0; } else if (hour >= 19 || hour < 12 && power == 0) { digitalWrite(relayPin, HIGH); //switch the relay to NC (heater on) //digitalWrite(LEDPin, HIGH); //mark that heater is on delay(25); //for relay time of 7ms digitalWrite(relayPin, LOW); power = 1; } } else if (day == 1 || day == 7 && power == 0) { //unnecessary elseif, but demonstrates point digitalWrite(relayPin, HIGH); //switch the relay to NC (heater on) //digitalWrite(LEDPin, HIGH); //mark that heater is on delay(25); //for relay time of 7ms digitalWrite(relayPin, LOW); power = 1; } } }

Step 3: Assembling the Hardware

My assembly was very Jerry rigged, but it has mostly worked, and I do have a few tips. Tip 1: be careful with the relay pins as they tend to completely break off very easily. Tip 2: buy some type of mounting board for the gate driver - hand soldering the wires to these insanely small pins is a nightmare (I used 872-204-0006-01 for a smaller gate driver. It converts SIOC to DIP which is much more manageable and could even fit the Trinket pins directly.) Tip 3: Buy a terminal block for the large water heater wires (like the 651-1714955).

So I glued the gate driver to a rubber mount on the side of the relay. From there I soldered the Trinket's pin to the gate drivers pins, and the gate drivers output pins to the relay coil. See below

Trinket --------------- gate driver ----------------------relay

usb -------------->47ohm res. to Vcc (6)

gnd --------------------> gnd (3)

I/O #0 -----------------> in B (4)

I/O #1 -----------------> in A (2)

----------------------------out A -----------------------> coil pin #A

----------------------------out B ----------------------> coil pin #B

The gate driver pins count from the divot, counter-clockwise :

1 not connected ---- 8 not connected

2 in A ---- 7 out A

3 Gnd ---- 6 Vcc

4 in B ---- 5 Out B

relay pins

1 coil pin #B ---- 2 coil pin #A

-------space--------

3 switch pos. a ---- 4 internal connection to 3

5 common switch base ---- 6 conected to 5

7 switch pos. b ---- 8 connected to 7

In hindsight I think I would have reserved the Trinket pin 1 to turn on the red led when the water heater is on or off, because I don't currently have an indicator.

Basically you want the switch to cut off power in the positive line going to the water heater. The power cable from the house was connected to the power cable to the water heater using a wire nut, so I stuck this relay switch in between. So house power is connected to pin 3 or 4 (or 7/8 depending on which arduino output connects which relay pins, but that can be changed in the code). Then the water heater hot wire is connected to pin 5 or 6. Because the wire is so thick, I attached the wires on opposite sides rather than next to each other because there is more space. I.e. house power to pin 4 and water heater hot wire to pin 5. For myself out A connects to the top right pin of the relay as viewed from the bottom. When the Trinket I/O #1 is turned on, this creates a connection between relay pin 5 and 7 (as well as 5 and 8, or 6 and 8). In the code this is "relayPinoff".

Step 4: Finishing Touches

Once you have the Trinket, relay and gate driver attached and soldered you can do a few final things.

1. Upload the code to the Trinket

2. Plug in a mini usb charger (old charger type, the new ones for phones are micro USB)

3. Figure out if you need to modify the millis constant based on timing when the relay switches. Since it is running at 8MHz millis is about double an actual millisecond (one millis=2 milliseconds). I actually just wrote a quick program to switch every hour and timed how close it was. Solve for "corrected millis" in the following equation if the measured time in not an hour: coded millis/hr = corrected millis/measured time

4. Once you have the time down well enough, figure out which relay pins are in contact during which time block to figure out how to connect the water heater.

5. Make hard connections to the water heater and try to cover the assembly box up. My water heater has a small compartment where the wire connections are, but my box is barely too big to put the cover on, and I dont want to force it because that already broke two of the relay pins off.

6. Plug the mini usb charger into the wall at the designated start time in the code.

7. Check to make sure that the switch changes when you intended it to and you're good to go.

Step 5: Summary

You can build a water heater timer for about 15 bucks with some patience. Just grab a relay and an Adafruit Trinket.

For part specs go to mouser.com and for Trinket specs go to adafruit.com

Let me know if anything is unclear, or flat out wrong. I am definitely no electrical engineer.

I am considering some type of solar water heater add-on for the next project.

-> Jesse James <-

Automation Contest 2016

Participated in the
Automation Contest 2016

Beyond the Comfort Zone Contest

Participated in the
Beyond the Comfort Zone Contest