March 26, 2019

Building a Thermostat

I hate my thermostat

The interface sucks, the settings aren't consistent, and all the "smart" functionality requires signing up for an account through the manufacturer's website and using the thermostat through that. Bleh.

After a few months of dealing with this thing and not only hating the experience, but also hating that it was even possible to hate the experience of something that should be so simple, I decided to build my own thermostat. It can't be that hard right?

Design

I figure I need a few basic parts. A microcontroller, a display, a temperature sensor, some buttons, and some relays for actually switching the HVAC lines.

I would like the option to use smart features, but the thermostat needs to support basic functionality without a network connection. If my network goes down one night, I do not want to wake up freezing. I'm not gonna worry a whole lot yet about what smart functionality the device should provide, because giving it a simple API will let me write external applications to control it without needing to modify and reflash its firmware.

Other than that, the basic functionality is just going to be remembering a target temperature that can be changed either by buttons or API requests, periodically checking the ambient temperature, and connecting HVAC lines as appropriate. HVAC stuff seems pretty simple. There's a control line for each of the heat, AC, and fan that turn on when tied high. So far this seems even more straight forward than I expected.

Selecting Parts

I already have a couple ESP-12E modules in the form of knockoff NodeMCU boards laying around, so I'll make that work as the microcontroller.

Google reveals some small OLED displays that are ideal for arduino-style projects because you draw to them over I2C, saving a lot of pins. Grabbed one of those.

A DHT11 or DHT22 sensor should work fine for reading the ambient temperature. I picked up a DHT22 because querying it takes less time, but the DHT11 should work just as well.

That's about it for parts really. Found some push buttons and crappy relays laying around that'll work for their respective jobs. In general, I'd want to use decent relays with optoisolators and coils that are energized with high control signals, but the optoisolator-less low-energized relays marked almost exclusively with chinese characters that I found (where did I even get these) will work well enough.

Building

This should be simple enough that I'm just gonna be pretty gung-ho about it. I'm just going to start connecting things and hacking away at firmware until something happens, and then iterate from there.

Priority number one: get the display working so I can put debug information on it and not have to send it over serial. The documentation is really straight forward, just connect the display to power and two of the ESP-12E's GPIO pins and call any of a number of drawing functions included in its library.

Display showing hello world

Well that went smoothly. Next I'll connect the temperature sensor, which also just needs to use power and a GPIO pin, and call the similarly simple library functions to query the temperature from it. The "Hello world" string ended up replaced with the temperature data that's being read to see if it works.

Display showing current temperature

Alright! That's all of the complex device interfacing that needs to be done, finished without a hitch thanks to the magic of dead-simple libraries. These jumpers are getting a little unwieldly though, so I'm going to recklessly solder everything directly to a protoboard before the basic connection layout is even finished.

Core parts on a protoboard

Now it needs buttons to change the target temperature, but first there needs to be a target temperature to change. Pretty simple to create that in the software and draw it to the screen. When the buttons are pressed, the firmware will just change the target temperature variable and the screen should update to show the new value.

Buttons added

For reliability's sake, I added some pull down resistors on the GPIO pins being driven by the buttons (they're on the back of the board). I also made it so a short press of the button changes the target temperature by 0.2 degrees, and a regular press changes it by a full 1 degree.

All that's left to add now are the relays, but they have these annoying LEDs on them that make them harder to attach to the board.

Relays with LEDs

I don't really want the thermostat lighting up like a christmas tree anyway, so a removal is in order.

Relays with LEDs removed

Then I just connect them to the board's 5V power supply, ground, and each one to a GPIO pin, and-

Board not booting

Oh no! The board doesn't boot now! This was bound to happen sooner or later - I can't just keep connecting things willy-nilly and expect to never have a problem. This doesn't seem bad though; no magic smoke or sizzling noises. Disconnecting the relays from the GPIO pins makes the board boot again, so I probably just accidentally used one of the GPIO pins that the board uses for boot settings, and tied it the wrong way so it wouldn't boot normally. Looking at the specs for the ESP8266, GPIO pin 15 must be pulled low for normal boot. Let's see, GPIO 15 corresponds to pin D8 on this board, and- yep, I was using it for one of the relays. Well, there are no extra GPIO pins at this point, but maybe I can swap pins with something that's normally pulled low? The buttons all have pull-down resistors to ground, so it's worth a shot to try swapping the pins for this relay and a button and redefining them appropriately in the software.

Board booting again

It works!

But now I've discovered one last problem. All the relays are energized all the time, regardless of the mode. My multimeter says the control signals to the relays that are supposed to be on are low, and the ones to relays that should be off are high, as expected (for these oddball relays, at least) - so the relays aren't switching for some reason. I remember something about these relays needing approximately the same control signal voltage as VCC to register a high, but I already tested these things with a 5V VCC and a 3.3V test control signal and they worked fine despite the warnings. What gives?

Turns out the 3.3V source I was using to test the relays was "close enough" to 5V to count, but the GPIO pins drive a little under 3.3V - just barely not enough. Oh well, I can just power the relays off of a 3.3V VCC, and then the GPIO pins should be plenty of voltage. Why didn't I do that in the first place?

We now have a functioning thermostat. Running the HVAC neutral line to each of the relays' normally-closed terminals, hot to each normally-open, and the heater, compressor, and fan control lines to the rest of the relay terminals puts this little project in charge of climate control. Some day soon I'll add a simple API and start working on automation and smart features, but that's for a future post see this post for the addition of the API!

Here is the final schematic:
Final schematic

And here is the code for the firmware