Raspberry Pi thermostat - Python Controller
This is a continuation of the Raspberry Pi thermostat series. The hardware part can be found here.
With the hardware built, now we need software to control the thermostat.
I decided to use Python for its simplicity. At first, I put up a simple website where I can control the thermostat using my phone. Soon, I realized it's actually easy to integrate with Apple Home via Homebridge so I implemented the interfaces required to get that working as well. Doing that let me do things like "hey siri, set the thermostat to 26 degrees".
The following is the overview of the solution:
The code is here, but it has lots of features that are not necessarily used today.
- RPi.GPIO for controlling GPIO pins. This comes with the Raspbian OS already.
- Flask to put up a simple HTTP interface for homebridge.
- DHT11 for interfacing with DHT11 sensor.
- Adafruit_Python_CharLCD to control the 1602 display.
The server just spins up a bunch of servers (implemented as threads) that polls sensors and carry out actions. Whether Python performs well with multi-threading is irrelevant here since the CPU is mostly idle.
There are 5 parts:
pconfig - for persistent configuration
Since Raspberry Pi can lose power or need to restart for updates, you need to save the configuration on the main disk.
The code is dead-simplee. It just reads from and writes to a JSON file every time you ask. Because the call volume is so low, there is no performance impact to worry about.
Stuff that is saved: * Target temperature day & night - I find that I always want the temperature to be 2 degrees C higher than during the day, so I have a separate profile for that. * Target humidity * Current Governor (see below)
temphumids - temperature & humidity sensor
temphumids records the temperature & humidity every second.
You can also query for the latest sampled temperature & humidity. In reality, I take an average of all the samples collected in the last 30 seconds because DHT11 measurements fluctuate a bit.
display - displays two lines
Display literally accepts two lines to display and just forwards it to the LCD.
oracle - tells controller what to do based on your preference
is simply to run what I call a 'governor' periodically (30s)
carry out actions. Definitely not the best design but the program is small
enough that it does not really matter much.
I have three governors:
|Governor||What they do|
|off||This governor just leaves everything off.|
This governor makes sure that your home is cool and dry. The interesting thing
I learned is that leaving the fan ON makes your home very humid even with the
cooling coil on. Apparently the reason is that if the fan is on, the water has
no chance to condense on the coil.
|heat||This is pretty simple, it just turns heat on whenever it's cold. It doesn't really care about humidity because there is nothing you can do in winter to improve the situation.|
server - interface for homebridge-thermostat
Homebridge is an open-source NodeJS server that interfaces with Apple Home via HomeKit API.
Using the homebridge plugin homebridge-thermostat, you can just provide the HTTP interface for the thermostat and let your iOS devices control your thermostat. The plugin is poorly documented but I was able to read the source code to find out what APIs you need to implement.
Interfaces you have to implement: * /status return the governor, temperature and humidity information * /targetTemperature/t - set the target temperature * /targetRelativeHumidity/rh - set the target humidity * /off - set governor to off * /comfort - set govenor to heat * /no-frost - set governor to cool
Make the server run on boot
Of course, we want this service to be running all the time. The best way to achieve this is to make it into a systemd service. Making a simple systemd service is very easy. First, write a service definition file like this:
[Unit] Description=Raspberry Pi Theromostat After=syslog.target [Service] Type=simple User=pi Group=pi WorkingDirectory=/home/pi/src/rpi-repo ExecStart=/bin/bash -c "FLASK_APP=rpithermostat.server ./venv/bin/flask run --with-threads -h 0.0.0.0" StandardOutput=syslog StandardError=syslog [Install] WantedBy=multi-user.target
This works great because all the standard out and error just gets redirected to syslog, which is what you want normally anyway.
To install this, just copy the file into
/etc/systemd/system/. Then run
systemd enable servicename
to make it run when booted up. Run
systemd start servicename to start the service right away.
The homebridge would randomly stop working. I never bothered to figure out why, but I "solved"
the issue by just creating a cron job that restarts every hour (
0 * * * * systemctl reboot).
It has been working well for many months now without any issues.
I could improve the heat governor by making it control the power outlet attached to a humidifer in winter. That way I can make the humidity just right.
Raspberry Pi thermostat - Building the hardware
This blog is about building my own thermostat with Raspberry Pi. This is part 1 where I explain the hardware. Part 2 talks about how I build the software that controls it.
What did I not like about the mercury thermostat?
I didn't like my old mercury-based thermostat for a couple reasons. First, the temperature fluctuation was pretty significant, up to 3 degrees C because mercury takes a while to react to the temperature change, Also I didn't like having to go to the living room to adjust the thermostat all the time.
Why did I not just use Ecobee or Nest? This was for fun & to learn how to build basic electronics using RPi ;)
The interface to the HVAC is a simple single stage 4-wire control.
heatresistive heat strips - white - not used
- fan - green
coolingheat pump - orange
- power - red
Basically, you just need to connect the power wire to what you want to turn on.
Connecting power to
cooling will heat/cool your coil.
Since I live in an apartment equipped with a heat pump, connecting power to heat pump will cool in summer and heat in winter.
Then you also need to run the fan for the air to circulate.
- Raspberry Pi - it can be any model really, but you want wifi for remote control.
- You need 3v, 5v, GND, and 4 GPIO pins minimum. 7 more for a 1602 display.
- Soldering equipments (example)
- Lots (10~20) of female to male jumper cables (example)
- Wires - I just used a 22 gauge wire
- Prototyping board (example)
- 3 x 2.2k and 3 x 10k Resistors
- 3 x 2n2222 NPN transistors
- DHT11 digital temperature & humidity sensor
- Minimum 3 channel relay (this is what I used)
- A 1602 display, if you want to display status also. It's named 1602 because it displays 2 rows of 16 characters.
Here's the schematic for the core parts:
Solid lines denote where I had to use a wire. Dotted lines denote where I didn't have to use a separate wire thanks to either the board or existing wires.
P4 denote any free GPIO pins.
- 3.3v to power DHT11.
- 5v to power the relay.
P1communicates with DHT11 (both read/write).
P4controls the three relay outputs.
Communicating with DHT11
DHT11 needs only one data pin because it both handles input and output through the same pin.
Controlling the relay
This was the only non-straightforward part that required a bit of thinking. When the relay is powered, the switches are simply disconnected. In order to 'close' (or, connect) the switch, you need to drain the current from the relay pins.
This is where the NPN transistor helps. It has 3 parts:
current (C) and
emitter (E). Electricity flows from
E, only if voltage is
In this case,
C accepts current from the relay, but it doesn't let it go through
B has voltage. And we control the voltage by setting the line high
from the Rpi.
So in my circuit, asserting
P1 high connects power to
controls fan and cooling
Here's a ghetto looking finished thermostat in action:
Due to my lack of any real hardware skills, I could not put together in a more polished way.
Check out the part 2 for the software that runs this thermostat.