Build a home thermostat with a Raspberry Pi

The ThermOS project is an answer to the many downsides of off-the-shelf smart thermostats.
121 readers like this.

My wife and I moved into a new home in October 2020. As soon as it started getting cold, we realized some shortcomings of the home's older heating system (including one heating zone that was always on). We had Nest thermostats in our previous home, and the current setup was not nearly as convenient. There are multiple thermostats in our house, and some had programmed heating schedules, others had different schedules, some had none at all.

Old thermostats

The home's previous owner left notes explaining how some of the thermostats worked. (Joseph Truncale, CC BY-SA 4.0)

It was time for a change, but the house has some constraints:

  • It was built in the late 1960s with a renovation during the '90s.
  • The heat is hydronic (hot water baseboard).
  • It has six thermostats for the six heating zones.
  • There are only two wires that go to each thermostat for heat (red and white).

Furnace valves

Taco (pronounced TAY-KO) zone valves at the furnace. (Joseph Truncale, CC BY-SA 4.0)

To buy or to build?

I wanted "smart" thermostat control for all of the heat zones (schedules, automations, home/away, etc.). I had several options if I wanted to buy something off the shelf, but all of them have drawbacks:

Option 1: A Nest or Ecobee

  • It's expensive: No smart thermostat can handle multiple zones, so I would need one for each zone (~$200*6 = $1,200).
  • It's difficult: I would have to rerun the thermostat wire to get the infamous C wire, which enables continuous power to the thermostat. The wires are 20 to 100 feet each, in-wall, and might be stapled to the studs.

Option 2: A battery-powered thermostat such as the Sensi WiFi thermostat

  • The batteries last only a month or two.
  • It's not HomeKit-compatible in battery-only mode.

Option 3: A commercial-off-the-shelf thermostat, but only one exists (kind of): Honeywell's TrueZONE 

  • It's old and poorly supported (it was released in 2008).
  • It's expensive—more than $300 for just the controller, and you need a RedLINK gateway for a shoddy app to work.

And the winner is… 

Option 4: Build my own!

I decided to build my own multizone smart thermostat, which I named ThermOS.

  • It's centralized at the furnace (you need one device, not six).
  • It uses the existing in-wall thermostat wires.
  • It's HomeKit compatible, complete with automation, scheduling, home/away, etc.
  • Anddddd it's… fun? Yeah, fun… I think.

The ThermOS hardware

I knew that I wanted to use a Raspberry Pi. Since they've gotten so inexpensive, I decided to use a Raspberry Pi 4 Model B 2GB. I'm sure I could get by with a Raspberry Pi Zero W, but that will be for a future revision.

Here's a full list of the parts I used:

Name Quantity Price
Raspberry Pi 4 Model B 2GB 1 $29.99
Raspberry Pi 4 official 15W power supply 1 $6.99
Inland 400 tie-point breadboard 1 $2.99
Inland 8 channel 5V relay module for Arduino 1 $8.99
Inland DuPont jumper wire 20cm (3 pack) 1 $4.99
DS18B20 temperature sensor (genuine) from 6 $6.00
3-pin screw terminal blocks (40 pack) 1 $7.99
RPi GPIO terminal block breakout board module for Raspberry Pi 1 $17.99
Alligator clip test leads (10 pack) 1 $5.89
Southwire 18/2 thermostat wire (50ft) 1 $10.89
Shrinkwrap 1 $4.99
Solderable breadboard (5 pack) 1 $11.99
PCB mounting brackets (50 pack) 1 $7.99
Plastic housing/enclosure 1 $27.92

I began drawing out the hardware diagram on and realized I lacked some crucial knowledge about the furnace. I opened the side panel and found the step-down transformer that takes the 120V electrical line and makes it 24V for the heating system. If your heating system is anything like mine, you'll see a lot of jumper wires between the Taco zone valves. Terminal 3 on the Taco is jumped across all of my zone valves. This is because it doesn't matter how many valves are on/open—it just controls the circulator pump. If any combination of one to five valves is open, it should be on; if no valves are open, it should be off… simple!

Furnace wiring architecture

ThermOS architecture using one zone. (Joseph Truncale, CC BY-SA 4.0)

At its core, a thermostat is just a type of switch. Once the thermistor (temp sensor) inside the thermostat detects a lower temperature, the switch closes and completes the 24V circuit. Instead of having a thermostat in every room, this project keeps all of them right next to the furnace so that all six-zone valves can be controlled by a relay module using six of the eight relays. The Raspberry Pi acts as the brains of the thermostat and controls each relay independently.

Manually setting relays using Raspberry Pi and Python

Manually setting the relays using the Raspberry Pi and Python. (Joseph Truncale, CC BY-SA 4.0)

The next problem was how to get temperature readings from each room. I could have a wireless temperature sensor in each room running on an Arduino or Raspberry Pi, but that can get expensive and complicated. Instead, I wanted to reuse the existing thermostat wire in the walls but purely for temperature sensors.

The "1-wire" DS18B20 temperature sensor appeared to fit the bill:

  • It has an accuracy of +/- 0.5°C or 0.9°F.
  • It uses the "1-wire" protocol for data.
  • Most importantly, the DS18B20 can use "parasitic power" mode where it needs just two wires for power and data. Just a heads up… almost all of the DS18B20s out there are counterfeit. I purchased a few (hoping they were genuine), but they wouldn't work when I tried to use parasitic power. I then bought real ones from, and they worked like a charm!

Temperature sensors

Three DS18B20s connected using parasitic power on the same GPIO bus. (Joseph Truncale, CC BY-SA 4.0)

Starting with a breadboard and all the components locally, I started writing code to interact with all of it. Once I proved out the concept, I added the existing in-wall thermostat wire into the mix. I got consistent readings with that setup, so I set out to make them a bit more polished. With help from my dad, the self-proclaimed "just good enough" solderer, we soldered leads to the three-pin screw terminals (to avoid overheating the sensor) and then attached the sensor into the terminals. Now the sensors can be attached with wire nuts to the existing in-wall wiring.

Attaching temperature sensors

The DS18B20s are attached to the old thermostat location using the existing wires. (Joseph Truncale, CC BY-SA 4.0)

I'm still in the process of "prettifying" my temperature sensor wall mounts, but I've gone through a few 3D printing revisions, and I think I'm almost there.

Wall mounts

I started with a Nest-style mount and made my way to a flush-mount style. (Joseph Truncale, CC BY-SA 4.0)

The ThermOS software

As usual, writing the logic wasn't the hard part. However, deciding on the application architecture and framework was a confusing, multi-day process. I started out evaluating open source projects like PiHome, but it relied on specific hardware and was written in PHP. I'm a Python fan and decided to start from scratch and write my own REST API.

Since HomeKit integration was so important, I figured I would eventually write a HomeBridge plugin to integrate it. I didn't realize that there was an entire Python HomeKit framework called HAP-Python that implements the accessory protocol. It helped me get a proof of concept running and controlled through my iPhone's Home app within 30 minutes.

ThermOS HomeKit integration

Initial version of Apple HomeKit integration, with help from the HAP-Python framework. (Joseph Truncale, CC BY-SA 4.0)

ThermOS software architecture

ThermOS software architecture (Joseph Truncale, CC BY-SA 4.0)

The rest of the "temp" logic is relatively straightforward, but I do want to highlight a piece that I initially missed. My code was running for a few days, and I was working on the hardware, when I noticed that my relays were turning on and off every few seconds. This "short-cycling" isn't necessarily harmful, but it certainly isn't efficient. To avoid that, I added some thresholding to make sure the heat toggles only when it's +/- 0.5C°.

Here is the threshold logic (you can see the rubber-duck debugging in the comments):

# check that we want heat
if self.target_state.value == 1:
    # if heat relay is already on, check if above threshold
    # if above, turn off .. if still below keep on
    if GPIO.input(self.relay_pin):
        if self.current_temp.value - self.target_temp.value >= 0.5:
            GPIO.output(self.relay_pin, GPIO.LOW)
            GPIO.output(self.relay_pin, GPIO.HIGH)
    # if heat relay is not already on, check if below threshold
    elif not GPIO.input(self.relay_pin):
        if self.current_temp.value - self.target_temp.value <= -0.5:
            GPIO.output(self.relay_pin, GPIO.HIGH)
          status = 'HEAT OFF - KEEPING OFF'


Thresholding allows longer stretches of time where the heat is off. (Joseph Truncale, CC BY-SA 4.0)

And I achieved my ultimate goal—to be able to control all of it from my phone.

ThermOS as a HomeKit Hub

ThermOS as a HomeKit Hub (Joseph Truncale, CC BY-SA 4.0)

Putting my ThermOS in a lunchbox

My proof of concept was pretty messy.

Initial ThermOS setup

ThermOS controlling a single zone (before) (Joseph Truncale, CC BY-SA 4.0)

With the software and general hardware design in place, I started figuring out how to package all of the components in a more permanent and polished form. One of my main concerns for a permanent installation was to use a breadboard with DuPont jumper wires. I ordered some solderable breadboards and a screw terminal breakout board (thanks @arduima for the Raspberry Pi GPIO pins).

Here's what the solderable breadboard with mounts and enclosure looked like in progress.

And here it is, mounted in the boiler room.

Now I just need to organize and label the wires, and then I can start swapping the remainder of the thermostats over to ThermOS. And I'll be on to my next project: ThermOS for my central air conditioning.

This originally appeared on Medium and is republished with permission.

What to read next
User profile image.
Joe Truncale is software engineer and all-around tinkerer. He's currently a Cloud Solutions Architect at Red Hat focusing on Kubernetes and OpenShift. He's spends a lot of his time crafting overly complicated solutions to comically simple problems.


Really amazing hack!!!
Thanks a lot for this step-by-step guide to follow the project!!!


Make sure you verify with your home insurance carrier that they are Ok with a DIY thermostat.

In most US jurisdictions, the insurance company is allowed to deny coverage for frozen pipes and other heating failure claims when a DIY thermostat is used without their express written consent.

This is a great project, one that I would like to replicate at some point. But I probably have counterfeit DS18B20 probes! (Thanks for that link.)

I'm a little concerned that you don't appear to have any failsafe mechanism. When I've fiddled with DIY thermostats, I've always had a mechanical thermostat set at 40-45 F in-parallel with the experimental thermostat. That way the heat will still kick on and keep the pipes from freezing if the project goes kaput and I'm not home.

For your project, I'd recommend a mechanical thermostat (low temperature range) in the coldest room of the house, set at 40-45 F, and wired to activate at least one heating loop valve and the pump. I would also add an external watchdog timer to reboot the Pi if it stops sending a heartbeat every few minutes.

I appreciate that! Let me know if you end up pursuing a project.

I've been thinking about implementing some alerting/failsafe mechanisms and I like your pragmatic approach of keeping the system running at a bare minimum in case of a failure. I've been thinking about exactly that.. a deadman's switch/heartbeat or maybe an external IOT sensor to alert me.

In reply to by Digitalis

This is a great project, but I'm a little concerned about two things:
1. Missing fail save mechanism
2. Insurance iddues.
Do you save really money by DIY? I counted briefly the money you have spent. I don't think you have really saved money.
Have a look on the Homematic IP system.
For almost the same money you could have a proven solution, running on nice looking wireless thermostats, accessible via your mobile phone, having a ready to use Homematic up server hosted at home.
The Homematic up server is based on raspberry pi. There are two versions, one ready to use, the other one you can use your own raspberry pi with their SW.
And you can extend the Homematic ip system with much more devices Homematic ip devices like connectors, security stuff, watering systems, whether sensors, fingerprint lock, etc.
And on the Homematic ip server every registered device is programmable, either visually by clicking on blocks or for more advanced guys using a script language.

Thanks for the questions! The situation mentioned isn't unique to the ThermOS project. If a thermostat's batteries die or there is a power loss, a home heating system will already fail. I'm currently working on some alerting/failsafe support for the project as well, but the fact that it can be monitored remotely and controlled provides more stability than the existing heating solution.

I looked into Homematic and this is why I didn't use them:
- They're not readily available in the US
- They're battery powered
- They're not Apple HomeKit compatible (without homebridge)
- Homematic costs $60 per thermostat (x7 in my case = $420) with $180 base station =~ $600 as opposed to $150 for my DIY setup

If I misunderstood any of that, I'd be happy to learn!

plus.. DIY was fun to build :)

In reply to by KoK

I built a similar thermostat a couple of years ago, also based on a Raspberry Pi and multiple ds18B20 sensors.(It doesn't have a nice interface.)
Mine works in addition to the house thermostat to call for heating or cooling when there is a big imbalance in the rooms, like when we are using the fireplace.

Some things I learned:
1) Turn the relays off as well as on, because the outputs from the rPi are maintained during crashes and reboots. (i.e. heat is not needed, turn the relay off anyway)
2) The ds18B20 can get stuck in an init state, returning 85000 which must not be used as a valid temperature
3) dht11's are not worth buying, humidity values are not very accurate. The bme280 works much better

Agreed on those lessons learned.

1. I should probably add some termination/sighandling to turn off the relays as they do persist in whatever state they're set to.

2. I was running into that 85000 state really often once I added my 4th ds18b20. I ended up decreasing the resistor from 4.7kOhm to 1.0kOhm since I believe that there was too much resistance (long wires to each room) that were causing an influx of 85000 errors. Once I swapped the resistors, the errors decreased by 90% and I've come to realize that about 0.05% error rate seems to be normal.

In reply to by Guy at Home

hello, great project, my compliments. I have one question about the parastite connection: in your schematic you have connected the vcc pin to the data pin, but at the link you provided they say to connect vcc and gnd

moreover, the datasheet also sais vcc-gnd connection at page 7 fig.6
and there is also a DS18B20-PAR version that just left the vcc pin disconnected:
is just an error in your schematic?
thank you!

Great catch! You're correct. At the ds18b20 the VCC/Ground are connected, while its Data pin goes to the connected VCC/Data pins at the Pi.

Thanks for finding that error!

In reply to by peppeg85

Not sure if you've already looked into PID control. I used to work for an industrial oven manufacturer and the way you described expanding your temperature tolerances so your valves weren't clicking on and off reminded me of it. Might help smooth out your heating cycles.

Creative Commons LicenseThis work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License.