Project Overview
This project creates an energy-saving HVAC control system that automatically adjusts temperature settings based on room occupancy. When a room is occupied, the system maintains normal temperature; when the room is empty for a set period, it enters an energy-saving mode with a temperature setback. This can reduce heating and cooling costs by 10-20% annually.
Difficulty: Intermediate
Estimated time: 3-4 hours
Estimated cost: $30-50
How It Works
PIR sensors placed in key rooms detect occupancy. When no motion is detected for a set period (e.g., 30 minutes), the system sends a signal to the HVAC system to adjust the temperature setpoint (higher for cooling, lower for heating). When occupancy is detected again, the system returns to the normal setpoint. Multiple sensors can be networked for whole-home occupancy tracking.
This project assumes you have a smart thermostat with API access (Nest, Ecobee) or an HVAC system with remote control capability.
Materials Needed
- ESP32 or ESP8266 (1)
- HC-SR501 PIR sensors (1-5, depending on rooms)
- Jumper wires
- Power supply (5V 2A)
- Project enclosure
- Smart thermostat with API (Nest, Ecobee, or Home Assistant)
Thermostat Compatibility
This project can integrate with various smart thermostats:
- Nest Thermostat: Use Google Nest API or Home Assistant integration.
- Ecobee: Use Ecobee API.
- Home Assistant: If you have a local Home Assistant instance, use its API to control any connected thermostat.
- IR-controlled AC units: Add an IR LED to control mini-split AC systems.
This tutorial uses Home Assistant as the central controller for simplicity.
Home Assistant Setup
- Install Home Assistant on a Raspberry Pi or server.
- Add your thermostat integration (Nest, Ecobee, etc.).
- Note the entity ID for your thermostat (e.g., climate.living_room).
- Enable the ESPHome integration for the PIR sensors.
ESPHome Configuration for PIR Sensors
# ESPHome configuration for multiple PIR sensors
esphome:
name: occupancy_sensors
esp32:
board: esp32dev
# Wi-Fi configuration
wifi:
ssid: "YourWiFiSSID"
password: "YourWiFiPassword"
fast_connect: true
# API for Home Assistant
api:
password: "YourAPIPassword"
ota:
password: "YourOTAPassword"
# Binary sensors for each PIR
binary_sensor:
- platform: gpio
pin: GPIO4
name: "Living Room Motion"
device_class: motion
filters:
- delayed_on: 100ms
- delayed_off: 60000ms # Stay on for 1 minute after last motion
- platform: gpio
pin: GPIO5
name: "Bedroom Motion"
device_class: motion
filters:
- delayed_on: 100ms
- delayed_off: 60000ms
- platform: gpio
pin: GPIO6
name: "Kitchen Motion"
device_class: motion
filters:
- delayed_on: 100ms
- delayed_off: 60000ms
Home Assistant Automations
Create the following automations in Home Assistant:
Automation 1: Enter Away Mode When No Motion
# configuration.yaml or via UI
automation:
- alias: "HVAC - Enter Away Mode"
trigger:
- platform: state
entity_id:
- binary_sensor.living_room_motion
- binary_sensor.bedroom_motion
- binary_sensor.kitchen_motion
to: "off"
for: "00:30:00" # 30 minutes of no motion
condition:
- condition: state
entity_id: binary_sensor.house_occupied
state: "on"
action:
- service: climate.set_temperature
target:
entity_id: climate.main_thermostat
data:
temperature: 62 # Heating setback
hvac_mode: heat
- service: input_boolean.turn_off
target:
entity_id: input_boolean.house_occupied
Automation 2: Return to Normal Mode When Motion Detected
automation:
- alias: "HVAC - Return to Normal"
trigger:
- platform: state
entity_id:
- binary_sensor.living_room_motion
- binary_sensor.bedroom_motion
- binary_sensor.kitchen_motion
to: "on"
condition:
- condition: state
entity_id: binary_sensor.house_occupied
state: "off"
action:
- service: climate.set_temperature
target:
entity_id: climate.main_thermostat
data:
temperature: 68 # Normal heating temperature
- service: input_boolean.turn_on
target:
entity_id: input_boolean.house_occupied
Input Boolean for Occupancy Status
input_boolean:
house_occupied:
name: House Occupied
initial: true
icon: mdi:home
Arduino Code (Standalone Version without Home Assistant)
If you don’t have Home Assistant, you can use an ESP32 to control a relay that directly interfaces with a simple thermostat:
// Standalone HVAC Controller with PIR
#include <WiFi.h>
const int pirPin = 4;
const int relayPin = 5; // Controls setback circuit
// Wi-Fi for logging (optional)
const char* ssid = "YourWiFiSSID";
const char* password = "YourWiFiPassword";
unsigned long lastMotionTime = 0;
const unsigned long setbackDelay = 1800000; // 30 minutes
bool inSetback = false;
void setup() {
Serial.begin(115200);
pinMode(pirPin, INPUT);
pinMode(relayPin, OUTPUT);
digitalWrite(relayPin, LOW); // Normal mode (relay off)
WiFi.begin(ssid, password);
delay(60000); // PIR warm-up
}
void loop() {
bool motion = digitalRead(pirPin) == HIGH;
if (motion) {
lastMotionTime = millis();
if (inSetback) {
// Return to normal mode
digitalWrite(relayPin, LOW);
inSetback = false;
Serial.println("Motion detected - returning to normal mode");
}
}
if (!inSetback && (millis() - lastMotionTime > setbackDelay)) {
// Enter setback mode
digitalWrite(relayPin, HIGH);
inSetback = true;
Serial.println("No motion - entering setback mode");
}
delay(100);
}
Multiple Room Occupancy Tracking
For whole-house control, create a template sensor that aggregates all PIR sensors:
# template.yaml
template:
- binary_sensor:
- name: "Any Motion"
state: >
{{ is_state('binary_sensor.living_room_motion', 'on') or
is_state('binary_sensor.bedroom_motion', 'on') or
is_state('binary_sensor.kitchen_motion', 'on') }}
delay_off:
minutes: 30
Installation Steps
- Place PIR sensors: Position sensors in key rooms (living room, bedrooms, kitchen) at 2m height, covering main activity areas.
- Connect sensors to ESP32: Wire sensors with long cables if needed.
- Configure Home Assistant: Add ESPHome integration and thermostat.
- Create automations: Add occupancy-based setback rules.
- Test: Verify system enters setback after no motion and returns when motion detected.
- Adjust timing: Set setback delay to avoid short cycling (30 minutes is typical).
Energy Savings Calculation
According to DOE, setting thermostats back 7-10°F for 8 hours per day can save 10% on heating and cooling costs. This system can achieve similar savings by automatically managing setbacks based on actual occupancy.
Project Extensions
- Room-level zoning: Use motorized dampers to heat/cool only occupied rooms.
- Geofencing integration: Combine with phone location for even better occupancy detection.
- Window sensors: Add window contact sensors to disable HVAC when windows are open.
- Energy monitoring: Track energy usage and savings over time.
- Voice control: Use Alexa/Google to check occupancy status and adjust temperature.
Troubleshooting
- System enters setback while occupied: Increase motion detection range. Ensure sensors cover all activity areas. Increase setback delay time.
- System doesn’t return from setback: Check PIR sensors are detecting motion. Verify wiring.
- Too frequent cycling: Increase setback delay. Add delay_off filter in ESPHome.
- No connection to thermostat: Check Home Assistant integration and API credentials.
Conclusion
This occupancy-based HVAC control system automatically reduces energy waste when rooms are empty, lowering utility bills without sacrificing comfort. With proper installation, it can pay for itself within one heating or cooling season.
