Building a Thermostat with the Raspberry Pi

For a long time, I wanted to do something with my original RPi B (the one with 256MB) but never found the time. Now have the RPi2, so I have two of them doing nothing. The RPi2 is more useful in general since it is multi-core and ARMv7 (i.e. linux distributions build officially supported binary packages for ARMv7), but my original RPi just sat around… sad… collecting dust.

A new year brought with it new inspiration and motivation to build a thermostat out of it.

Parts List:
RPi B+ ($25)
Any SD card 2G or more (~$10)
Edimax Wireless-N USB Adapter ($10)
Plugable USB Bluetooth 4.0 Low Energy Micro Adapter ($14)
F/F Jumper Wires ($4)
SainSmart 4-Channel Relay Module ($9)
TI SensorTag CC2650STK ($30)
50′ 5-wire Thermostat Wire ($17)

Total: ~$120

So roughly half the cost of a Nest, which is currently $250.

Install Raspbian

The first thing to do is download the lastest Raspbian Lite image from the Raspberry Pi website. The torrent is MUCH faster than the direct download, so I recommend doing that.

Once downloaded, decompress the image. The filename might be different.


Now insert your SD card into the card reader. Determine the device path of the SD card by looking at the kernel log after you plug in the card reader

$ dmesg | tail -n 20
[11201.184676] usb 1-3.4: new high-speed USB device number 3 using xhci_hcd
[11201.273099] usb 1-3.4: New USB device found, idVendor=0951, idProduct=1624
[11201.273104] usb 1-3.4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[11201.273106] usb 1-3.4: Product: DataTraveler G2
[11201.273109] usb 1-3.4: Manufacturer: Kingston
[11201.273111] usb 1-3.4: SerialNumber: 000AEBFEF59CA931C64C0033
[11201.297086] usb-storage 1-3.4:1.0: USB Mass Storage device detected
[11201.297206] scsi host6: usb-storage 1-3.4:1.0
[11201.297332] usbcore: registered new interface driver usb-storage
[11201.301072] usbcore: registered new interface driver uas
[11202.296377] scsi 6:0:0:0: Direct-Access     Kingston DataTraveler G2  1.00 PQ: 0 ANSI: 2
[11202.297220] sd 6:0:0:0: Attached scsi generic sg4 type 0
[11202.297866] sd 6:0:0:0: [sdd] 7835648 512-byte logical blocks: (4.01 GB/3.73 GiB)
[11202.298152] sd 6:0:0:0: [sdd] Write Protect is off
[11202.298156] sd 6:0:0:0: [sdd] Mode Sense: 23 00 00 00
[11202.298443] sd 6:0:0:0: [sdd] No Caching mode page found
[11202.298446] sd 6:0:0:0: [sdd] Assuming drive cache: write through

From the output, I can see that my SD card is a /dev/sdd. MAKE SURE YOU GET THIS RIGHT, YOU CAN BLOW AWAY YOUR MACHINE.

Now copy the image to the SD card, replacing /dev/sdX with the device name of your SD card.

dd if=2015-11-21-raspbian-jessie-lite.img of=/dev/sdX bs=1M

Eject the card

sync; eject /dev/sdX

Insert the card, the wifi adapter, and the bluetooth adapter into the Raspberry Pi and power it on. The default user/password is pi/raspberry. Use sudo to gain root access.

Network Configuration

Configuring a static IP address is necessary for logging remotely and set up a DNS record so you can address it by name (DNS is optional).

Edit /etc/network/interfaces to look like this, adjusting the address and gateway to be appropriate for your network.

source-directory /etc/network/interfaces.d

auto lo
iface lo inet loopback

iface eth0 inet dhcp

allow-hotplug wlan0
iface wlan0 inet static
    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

Edit /etc/wpa_supplicant/wpa_supplicant.conf to look like this, adjusting ssid, key_mgmt, and psk (password) to be appropriate for you network.

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev


Enable the wireless interface

ifup wlan0

Make sure the wlan0 interface configured properly

$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether b8:27:eb:f6:d2:7c brd ff:ff:ff:ff:ff:ff
105: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 74:da:38:5b:d5:9c brd ff:ff:ff:ff:ff:ff
    inet brd scope global wlan0
       valid_lft forever preferred_lft forever
    inet6 fe80::76da:38ff:fe5b:d59c/64 scope link 
       valid_lft forever preferred_lft forever

$ ip r
default via dev wlan0 dev wlan0  proto kernel  scope link  src

$ ping -c 1
PING ( 56(84) bytes of data.
64 bytes from ( icmp_seq=1 ttl=54 time=13.7 ms

--- ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 13.785/13.785/13.785/0.000 ms


I wrote the thermostat software myself in Go. Nice libraries for for communicating the the SensorTag (GATT) and RPi GPIO already exist for Go so it made development quick and easy. It is by no means robust to certain failures (namely communication loss to the SensorTag), but it gets the job done and you are free to extend it. I wanted a simple feature set.

Option 1: Download the binary tarball

Download, decompress and run (as root)

tar xf rpi-thermostat.tar.gz

Option 2: Compile from source

Cross compile the rpi-thermostat binary for the RPi on your desktop machine

mkdir rpi-thermostat
cd rpi-thermostat
export GOPATH=$PWD
go get
cd src/
GOOS=linux GOARCH=arm go build

Connecting the Relays

Thermostats are not that complex. The following in a crash course.

R – 24VAC
G – Fan/Blower
Y – Cool/Compressor
W – Heat
B – Common (not used here)

The following are connections made for the different modes. R-G, for example, denotes that the Red and Green wires are connected via a relay.

Fan = R-G
Cool = R-G, R-Y
Heat = R-G, R-W

For this software, the mappings of GPIO pins to relay controls are

Relay for Fan (G) is controlled by pin 17
Relay for Cool (Y) is controlled by pin 21
Relay for Heat (B) is controlled by pin 22

You can see the pinout for all RPi models here

Connect the relays as follows

5V -> Vcc
17 -> IN1
21 -> IN2
22 -> IN3
Gnd -> Gnd
(the pin for IN4 on the relays will not be connected)

IN1 relays G (Fan)
IN2 relays Y (Cool)
IN3 relays W (Heat)

The R wire is the one the the relays connect to the various other wires. I connected the R wire coming in from the unit to the first relay, on the active side, and used small jumpers to connect R to the active side of all the other relays.



This setup uses the TI SensorTag, communicating over Bluetooth Low Energy (BTLE), to obtain the current temperature. Unfortunately the marketing material for the SensorTag is not completely honest.

It claims that the tag will run for a year or so on a single 240mAh-ish CR2032 coin battery. However, the device draws about 0.5mA continuously ( unless you turn the motion sensor on, in which case it uses almost 5mA!) So a little maths (240mAh/0.5mA) results in 480 hours (20 days) of life.

I, for one, did not want to be changing out the battery on the tag every 3 weeks. The tag has solder points for an 2xAAA battery pack. I got this on Amazon. The solder points are here.


Starting on boot

Copy the systemd unit file to /etc/systemd/system/rpi-thermostat.service then start and enable on boot

systemctl start rpi-thermostat
systemctl enable rpi-thermostat

All Done

Just go to, adjusting the IP for your setup and you should get the web UI for thermostat controls!


Leave a Reply

Your email address will not be published. Required fields are marked *