DIY Smart Thermostat with Arduino: A Step‑by‑Step Guide
If you’ve ever watched the thermostat flick between 68 °F and 78 °F while you’re trying to enjoy a hot cup of tea, you know why a reliable, precise heating control matters. A smart thermostat can shave dollars off your energy bill, keep every room comfy, and give you the satisfaction of building something that actually works. In this post I’ll walk you through the whole process – parts list, wiring, code, and testing – so you can finish the project in a weekend and start feeling the difference right away.
What You’ll Need
| Item | Why It’s Needed |
|---|---|
| Arduino Uno (or Nano) | The brain of the thermostat. |
| DHT22 temperature/humidity sensor | Gives accurate room temperature (±0.5 °C). |
| 10 k Ω potentiometer | Lets you set the target temperature manually. |
| Relay module (5 V) | Switches the furnace or electric heater on/off safely. |
| 16 x 2 LCD display (I2C) | Shows current temperature, set point, and status. |
| Breadboard and jumper wires | For prototyping before you solder. |
| 12 V power supply (or wall wart) | Powers the relay and heater circuit. |
| Enclosure (plastic project box) | Keeps everything tidy and safe. |
| Optional: Wi‑Fi module (ESP‑01) | Adds remote control via smartphone. |
All of these parts are cheap and can be found on Amazon, eBay, or a local electronics store. If you already have an Arduino and a sensor lying around, you can skip the purchase and move straight to wiring.
Understanding the Basics
Before you start soldering, let’s clear up a few terms that often cause confusion.
- Thermostat – A device that measures temperature and turns heating or cooling on or off to keep the space at a set point.
- Relay – An electrically operated switch. The Arduino can’t drive a furnace directly, but it can tell a relay to close the circuit and let mains voltage power the heater.
- PID control – A fancy way of saying “adjust heating based on how far off we are from the target”. For a simple thermostat we’ll just use a basic on/off (bang‑bang) control; it’s reliable and easy to code.
With those ideas in mind, the circuit is straightforward: sensor reads temperature, Arduino compares it to the set point, and the relay flips the heater on or off. The LCD and potentiometer give you a user interface.
Wiring the Arduino
1. Connect the DHT22
- VCC to 5 V on the Arduino.
- GND to ground.
- Data pin to digital pin 2.
Add a 10 k Ω pull‑up resistor between VCC and the data line (the sensor usually has one built in, but a spare never hurts).
2. Hook up the LCD (I2C)
- SDA to A4, SCL to A5 on an Uno (or the corresponding pins on a Nano).
- VCC to 5 V, GND to ground.
The I2C backpack reduces the wiring to just four pins, which is a lifesaver on a cramped breadboard.
3. Wire the Potentiometer
- One outer leg to 5 V, the other to ground.
- The middle wiper to analog pin A0.
Turning the knob will give a voltage between 0 and 5 V, which the Arduino reads as a number from 0 to 1023. We’ll map that range to a temperature set point.
4. Attach the Relay Module
- VCC to 5 V, GND to ground.
- IN (control pin) to digital pin 8.
- The relay’s “normally open” (NO) contacts go in series with the heater’s power line. Never connect the heater directly to the Arduino – the relay isolates the high voltage from the low‑voltage side.
5. Power Considerations
The Arduino can be powered via USB while you prototype, but the relay and heater need a separate 12 V supply. Use a small wall wart and plug the relay’s VCC into it; keep the Arduino’s USB power separate to avoid overloading the board.
Programming the Controller
Open the Arduino IDE and install two libraries if you haven’t already: DHT sensor library and LiquidCrystal_I2C. The code below is a minimal, well‑commented sketch that does everything we need.
#include <DHT.h>
#include <LiquidCrystal_I2C.h>
#define DHTPIN 2
#define DHTTYPE DHT22
#define RELAYPIN 8
#define POTPIN A0
DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 16, 2); // adjust address if needed
float setTemp = 22.0; // default 22 °C
void setup() {
pinMode(RELAYPIN, OUTPUT);
digitalWrite(RELAYPIN, LOW); // start with heater off
dht.begin();
lcd.init();
lcd.backlight();
}
void loop() {
// Read temperature
float curTemp = dht.readTemperature();
if (isnan(curTemp)) {
lcd.setCursor(0,0);
lcd.print("Sensor error ");
delay(2000);
return;
}
// Read potentiometer and map to 15‑30 °C range
int potVal = analogRead(POTPIN);
setTemp = map(potVal, 0, 1023, 150, 300) / 10.0;
// Simple on/off control
if (curTemp < setTemp - 0.5) {
digitalWrite(RELAYPIN, HIGH); // heater on
} else if (curTemp > setTemp + 0.5) {
digitalWrite(RELAYPIN, LOW); // heater off
}
// Display info
lcd.setCursor(0,0);
lcd.print("Cur:");
lcd.print(curTemp,1);
lcd.print((char)223); // degree symbol
lcd.print("C ");
lcd.setCursor(0,1);
lcd.print("Set:");
lcd.print(setTemp,1);
lcd.print((char)223);
lcd.print("C ");
delay(1000);
}
A few notes:
- The
map()function converts the raw potentiometer reading into a temperature range that feels comfortable for most homes (15 °C‑30 °C). - The 0.5 °C deadband prevents the heater from flickering on and off rapidly.
- If you add a Wi‑Fi module later, you can expose
setTempvia a simple web page – but that’s a whole other tutorial.
Upload the sketch, power the board, and you should see the current temperature and set point on the LCD. Turn the knob and watch the set point move; the relay will click when the heater turns on.
Testing and Tuning
- Safety first – Keep the heater disconnected while you verify the relay clicks. Use a multimeter to confirm the relay contacts open and close as expected.
- Simulate temperature – If you have a hair dryer, point it at the sensor for a few seconds; the LCD should show a rise and the relay should turn off once the set point is exceeded.
- Fine‑tune the deadband – Some homes have a furnace that takes a minute or two to respond. If you notice the temperature overshooting, increase the deadband to ±1 °C.
- Mount the sensor – Place the DHT22 away from direct sunlight, drafts, or the heater itself. A small wall‑mounted enclosure works well.
Once you’re happy with the behavior, move the circuit from the breadboard to a perf board or solder it inside your project box. Run the wires to the furnace relay, secure everything, and you have a fully functional smart thermostat.
Putting It All Together
Building a thermostat from scratch may sound like a big undertaking, but the parts are cheap and the code is only a few dozen lines. The biggest payoff is the confidence that comes from knowing exactly how your heating system is being controlled. Plus, you can always expand the project: add a temperature logger, integrate with Home Assistant, or swap the potentiometer for a rotary encoder with a nicer UI.
When I first built this for my own apartment, I was amazed at how quickly the temperature settled after I set a new target. The old programmable thermostat would bounce around for hours; my Arduino version steadied within ten minutes. The savings on the electric bill were modest at first, but over a winter they added up, and the sense of ownership is priceless.
If you run into a snag, double‑check the wiring, make sure the relay is rated for your heater’s voltage and current, and verify the sensor is getting clean power. Most problems boil down to a loose jumper or a mis‑wired LCD.
Enjoy the warmth, and happy hacking!
- → How to Build a Voice‑Controlled Smart Light Switch with ESP32 – A Complete DIY Guide @smarthomeharmony
- → How to Build a Voice‑Controlled Smart Light Switch with Raspberry Pi for Under $30 @techdiyhub
- → How to Build a Raspberry Pi-Powered Smart Home Hub from Scratch @techcraftinsights
- → How to Build a Smart Home Hub with a Raspberry Pi for Under $50 @techandtinker
- → Step-by-Step Guide: Build a Raspberry Pi Smart Light Switch for Under $30 @techandtinker