Michael Hentges Blog

Raspberry Pi Wireless Thermostat - in Rust

Oct 04, 2022

I recently stepped away from the full-time work rat race and found myself with some time on my hands. Being a life-long technologist, I naturally started looking into what new things have come along that I didn’t have time for when consumed by a full-time job.

Rust popped up on a short list of new technologies that looked interesting. I started programming in C/C++ on DOS/Windows/Mac/Unix many moons ago – so a new statically typed compiled language that is heralded as the “new C/C++” was a natural choice. Going through the Rust Book, I absorbed the concepts pretty quickly – but found myself in that “what next” stage. This is always the most challenging stage when learning new technology – you understand the basics but don’t know where to start to build something “real.”

In search of a solution to this problem, I ran across an excellent book by Luca Palmieri: Zero to Production in Rust. The book walks through the building of a non-trivial, production-quality web application in Rust. Many useful concepts are built out and illustrated, including:

After working through the book, I felt I had a decent handle on how this stuff works. As a bonus, I haven’t done a lot of production-level web server development in other languages – and seeing the normal challenges in this environment solved was interesting. But I’ve never claimed to be proficient in a tool until I’ve used it to build something. About this time, an outside inspiration popped up – I wanted a way to control a thermostat in a detached workshop remotely. The heater for my workshop is a simple 2-wire control – not nearly as complicated as a home furnace. A Google Nest is overkill, I’ve done some programming for Arduino and Raspberry Pi devices in the past, so this project was born.

In laying out the architecture for my new project, I decided on the following initial scope:

  1. I’m only worried about heating – so a single control and simplified logic for either turning on the heat or turning it off.
  2. For the main control platform, the Raspberry Pi is an easy choice. It runs a Unix OS, has Wi-Fi networking support, and has easy access to the physical devices needed for temperature measurement and relays to work as a thermostat.
  3. I would use Rust as the development language and take advantage of the following Rust features:
    1. Cross-compile to a native executable (ARM processor).
    2. Use the Actix-Web framework to expose REST interfaces for remotely setting the thermostat and retrieving the current temperature.
    3. Utilize the Tokio run time for a multi-threaded application that can read temperatures, decide whether to turn the thermostat on or off, receive commands to set the thermostat, and send data externally.
    4. Gain programmatic access to physical devices on the Raspberry Pi for reading temperature and controlling a relay to turn the heater on or off.
  4. I wanted external visibility into how the thermostat was working. I decided to push data to the cloud instead of keeping it on the device so that an external “watcher” can send an alarm if something isn’t working correctly. I wouldn’t want a thermostat not to turn on when it’s supposed to (freezing things is bad) or stay on too long (100 degrees is also bad and a potential fire hazard).
  5. I chose a REST interface for controlling the thermostat – making it easy to connect something to it later. I might make a Flutter app for my phone (more new things to figure out!) or a web interface.
  6. I chose to address security through physical network access and firewalls and not implement a security layer on the API. I am saving implementing security for the 2.0 version, which keeps the initial development cleaner and easier.
  7. I would follow the main principles from Zero to Production in organizing the project and utilize many of the same external Rust packages. I liked the coding style and choices made in the book and consider it a best practices reference.

I intended this to be a hobby project – not a commercial production-ready implementation. When I install this for actual use, I will have a backup system to ensure nothing bad happens. Things work in the project’s current state – but I don’t profess to have the system hardened. More testing is needed before I’ll trust this with anything important.

The following diagram depicts the system architecture for the solution:

DTMF IVR

The subsystems of the application are as follows:

The GitHub link for the source code is here. I’m still fiddling with things and working on a GUI client. I plan on diving into the details of the application in a series of follow-on posts – follow me to get an update when the next in the series is published.

hero image by Jainath Ponnala on Unsplash

Want to encourage more content like this? Please consider buying me a cup of coffee!