Guides · 21 min read

Arduino Smart Home Project: Model House, Sensors, Code and App

Build an Arduino smart home project step by step: model house plan, PIR lights, gas and fire alarm, RFID door, relay lamp, ESP32 phone control and full code.

An Arduino smart home project turns the lights, door, window and alarms of a model house into a system that runs itself on sensors, and you can control all of it from your phone too if you like. It's one of the most popular school projects for good reason. A hallway light that switches on when it detects motion, an alarm that sounds when gas leaks, a fan that starts when it gets warm and a door that opens with a card add up to a small but working copy of a real smart home system. With an Arduino Uno or an ESP32, about ten modules and a weekend, you can build one too.

In this guide we start with the plan of the model house: which module goes in which room, where the budget goes, how to plan the power and how to assign the pins. Then we build and test each module one by one and write the complete Arduino sketch that runs them all at the same time without using delay(). In the final sections you'll learn how to control the house from your phone with an ESP32 web server or Blynk, how to fix the most common mistakes and how to impress the judges at your school presentation.

HC-SR501 PIR
HC-SR501 PIR
MQ-2
MQ-2
DHT11
DHT11
RC522 RFID
RC522 RFID
SG90
SG90
I2C LCD 16x2
I2C LCD 16x2

How does a smart home system work?

Every smart home runs on the same three-part loop. Sensors measure the surroundings: is anyone moving, is it dark, how warm is it, is there gas or a flame in the kitchen, which card was held up to the door? The controller, meaning the Arduino or ESP32, compares this information with rules: "if it's dark and there's motion, turn on the light", "if the temperature goes above 28 °C, start the fan". Actuators carry out the decision: a relay switches the lamp and fan, a servo turns the door and window, the buzzer sounds and the display shows the status. Phone control simply adds another input to this loop; this time your tap makes the decision instead of a rule.

Room / areaModuleWhat it does
Front doorRC522 RFID + SG90 servoOpens the door when an authorised card is scanned and closes it 5 seconds later
Hallway / living roomHC-SR501 PIR + LDR + relayTurns on the lamp when it detects motion in the dark and switches it off after 20 seconds without motion
KitchenMQ-2 gas sensor + flame sensor + buzzerSounds a beeping alarm when it detects gas or a flame
WindowSG90 servoOpens the window for ventilation when gas is detected
BedroomDHT11 + relay + fanStarts the fan when it reaches 28 °C and stops it at 26 °C
Technical roomArduino, I2C LCD, power supplyShows temperature, humidity, the gas reading and status messages

Planning the model house

Design the model around the electronics; don't try to squeeze the electronics in afterwards. A base of about 50×40 cm is enough for two or three rooms and an entrance. For the walls, 5 mm foam board or PVC foam board (such as Forex) cuts easily with a craft knife; 3–4 mm MDF is sturdier but needs a saw or a laser cutter. A 1:20 scale is a good starting point: a 2.6 m ceiling becomes a 13 cm wall and a 90 cm door becomes 4.5 cm wide. Make the roof removable or leave it off altogether; the judges will want to see inside the rooms.

  • Technical room or double floor: put the Arduino, breadboard, relay module and power input in a compartment at the back of the house or under a double floor 3–4 cm high. If you cover it with clear acrylic, the circuit is both protected and visible.
  • Cable channels: drill a 6–8 mm hole under each sensor and run the cables under the base to the technical room. Rather than joining short wires together, choose sensor wires that are long enough from the start.
  • Door: fix the door to the wall with a small hinge or tape and connect the SG90's horn to the door with a wire bent from a paper clip. Glue the RC522 to the inside of the outer wall; the reader usually reads the card through 5 mm board as well.
  • Kitchen: in real homes, a detector for natural gas (methane) goes near the ceiling because it's lighter than air, while one for LPG goes near the floor because LPG is heavier; for a model, a spot near the ceiling is fine. Point the flame sensor at the stove.
  • Other sensors: put the PIR in a corner that sees the entrance path from the side, the LDR on an outside wall or window where it can't see the lamp's light, and the DHT11 away from the lamp and the warm body of the MQ-2.
Before buying anything, draw a bird's-eye plan of the model and mark where each module goes and which route its cable takes to the technical room. In projects like this, the wiring layout takes more time than the code or the soldering; a good plan cuts that time in half.

Parts list and cost

PartQtyPurposePrice level
Arduino Uno R3 (a clone is fine) or ESP32 DevKit1The brain of the houseMedium
Breadboard and jumper wire set (male-male, male-female)1 setConnectionsLow
HC-SR501 PIR motion sensor1Hallway lightLow
LDR and 10 kΩ resistor1 + 1Darkness detectionVery low
MQ-2 gas sensor module1Gas and smoke alarmLow
Flame sensor module (LM393)1Fire alarmLow
DHT11 temperature and humidity module1Fan controlLow
RC522 RFID module (with card and key fob)1Card-operated doorLow
SG90 servo motor2Door and windowLow
2-channel 5 V relay module1Lamp and fanLow
Active buzzer1Alarm soundVery low
I2C 16x2 LCD display1Status displayLow – medium
5 V mini fan and 5 V LED lamp or LED strip1 + 1Loads for the relaysLow
5 V 2–3 A power adapter and DC jack or terminal block1Power for servos, relays and sensorsMedium
Foam board or PVC foam board, craft knife, hot glue–Body of the houseMedium

Prices change often depending on the seller and over time, so we don't give figures; the table shows how much weight each part carries in the budget. The sensors and modules are all cheap on their own; most of the budget goes on the board, the LCD, the power adapter and the model materials. If you have an Arduino starter kit, the board, breadboard, wires, LDR, buzzer and often a servo and an LCD are already covered. On a tight budget you can drop the LCD and the second servo: use the Serial Monitor instead of a display and leave the window for a later stage. A more accurate DHT22 instead of the DHT11 costs a little more but makes your measurements more convincing at the presentation.

Power plan: why a separate 5 V adapter?

In smart home models, almost every complaint like "it resets now and then", "the servo jitters" or "strange characters appear on the LCD" comes down to power. A computer's USB port supplies about 500 mA, and when the board runs from USB the Uno's 5V pin sits behind that limit too. Add up the values below and you'll see the total current easily goes over 1 A when both servos move at once.

PartApproximate current at 5 V
Arduino Uno45–50 mA
MQ-2 (heater always on)About 150 mA
Relay module (per channel, relay energised)70–80 mA
SG90 servo (moving / under load)100–250 mA / up to 0.5–0.7 A
I2C LCD (backlight on)20–30 mA
RC522 (from the 3.3 V pin)13–26 mA
Active buzzer, DHT11, PIR and flame sensor30–40 mA in total
5 V mini fan and LED lamp100–400 mA depending on the model
Don't power the servos, relay module, MQ-2 or the relay loads from the Arduino's 5V pin. Power them from a separate 5 V 2–3 A adapter and always connect the adapter's GND to the Arduino's GND (common ground). You can power the Arduino separately: from USB while developing and later through its DC jack with its own 7–12 V adapter; don't plug the 5 V adapter into the jack, because it needs at least 7 V. A 470–1000 µF electrolytic capacitor on the servo supply smooths out the brief voltage dip when a servo starts moving. More details in the Arduino power supply guide.

Pin plan: Arduino Uno and ESP32

This many modules almost use up the Uno's pins, so you need to plan them from the start. The RC522 uses hardware SPI, so its MOSI, MISO and SCK lines are tied to D11, D12 and D13. The LCD uses only A4 and A5 over I2C, which is why we chose a display with an I2C module rather than a parallel LCD. Analog pins also work as digital pins when needed, which is how we can connect the window servo to A2. Leave D0 and D1 free: this serial line is used when you upload code and when you read card numbers in the Serial Monitor. You can see your board's pin layout in the Pinout tool.

Module pinArduino UnoESP32
PIR OUTD2GPIO 16
Flame sensor DOD3GPIO 17
DHT11 DATAD4GPIO 13
Active buzzer (+)D5GPIO 25
Door servo (signal)D6GPIO 32
Relay IN1 (lamp)D7GPIO 26
Relay IN2 (fan)D8GPIO 27
RC522 RSTD9GPIO 4
RC522 SDA (SS)D10GPIO 5
RC522 MOSI / MISO / SCKD11 / D12 / D13GPIO 23 / 19 / 18
MQ-2 AOA0GPIO 34 (through a voltage divider)
LDR divider midpointA1GPIO 35 (divider fed from 3V3)
Window servo (signal)A2GPIO 33
I2C LCD SDA / SCLA4 / A5GPIO 21 / 22
On both boards, power the RC522 from the 3.3 V pin; 5 V can damage the module. On the ESP32, watch out for two more rules: ADC2 pins can't take analog readings while Wi-Fi is on, so we connected the MQ-2 and the LDR to ADC1 pins (GPIO 32–39). The analog output of an MQ-2 powered from 5 V can also go above 3.3 V; add a voltage divider, for example 10 kΩ on top and 15 kΩ at the bottom (5 V × 15 / 25 = 3.0 V). For the same reason, power the flame sensor and the DHT11 from 3V3 on the ESP32; both run at 3.3 V, so their digital outputs stay within 3.3 V. The HC-SR501's output is already 3.3 V even when it's powered from 5 V. In the ESP32 column we moved the RC522's RST pin from GPIO 22 to GPIO 4, because GPIO 22 is the LCD's SCL line here.

Putting it together step by step

  1. Build the body of the model and prepare the module positions and cable holes; fit the electronics last.
  2. Set up the power line: connect the 5 V adapter to the breadboard's power rails, join the adapter's GND to the Arduino's GND and check the 5 V with a multimeter.
  3. Connect the I2C LCD and print some text on it. If you can't find the display's address, use the scanner sketch from the I2C LCD article.
  4. Add the sensors one at a time: DHT11, LDR, PIR, MQ-2 and flame sensor. Try each one with a short test sketch in the Serial Monitor and note the readings in clean air, in the dark and in the light.
  5. Add the actuators: first test the relays without a load by watching their click and LED, then the servos on external power, and finally connect the RC522. Scan your cards and note their numbers.
  6. Upload the main sketch and set the GAS_LIMIT, DARK_LIMIT and FAN_ON thresholds based on your notes.
  7. Secure the wires with hot glue and labels, then leave the system on for half an hour and watch for resets, overheating or false alarms.
Don't wire everything at once and try to run it all in one go. When eight modules don't work together, finding the fault can take hours; modules that have been tested one by one usually work first time when you combine them.

Automatic light with a PIR and an LDR

The HC-SR501 PIR sensor detects changes in the infrared radiation given off by the human body and sets its output HIGH when it sees movement. With a PIR alone the lamp would come on during the day as well, so our rule has two conditions: turn it on if there's motion and it's dark. The LDR is wired as a voltage divider with a 10 kΩ resistor (5V → LDR → A1 → 10 kΩ → GND), and the reading on A1 drops as it gets darker. The code stores the time of the last motion and switches the lamp off after 20 seconds without new movement; as long as someone is walking around, the timer restarts each time. Set the sensor's jumper to H (repeat trigger) and its Tx pot to the shortest time, and let the code decide the timing. More details in the PIR motion sensor and LDR light sensor articles.

Gas and fire alarm

Inside the MQ-2 is a tin dioxide layer kept hot by a heater; LPG, methane, butane, hydrogen, alcohol and smoke change the resistance of this layer. The module's AO pin outputs a voltage that rises as the gas level rises. The sensor needs to warm up every time it's switched on, so the code ignores gas alarms for the first 60 seconds. The flame sensor detects the 760–1100 nm infrared light given off by a fire; on most modules the DO output goes LOW and a second LED on the board lights up when a flame is seen, but always check your own module with a lighter held at a distance. When gas is detected the alarm sounds and the window opens for ventilation; when a flame is detected the window stays shut, because fresh air feeds a fire. Setting the threshold and the other MQ sensors are covered in the MQ-2 gas sensor article.

This alarm is a learning project; never use it as the only protection against a gas leak or fire in a real home, as it's no substitute for certified commercial detectors. Also, during a real gas leak even switching an electrical device on or off or starting a motor can create a spark; that's why real systems use explosion-proof (Ex-certified) equipment. The window servo and relays in the model are only there to demonstrate the idea.

Temperature, humidity and an automatic fan

The DHT11 measures temperature from 0 to 50 °C with ±2 °C accuracy and humidity from 20 to 90 % with ±5 % accuracy, and it can be read at most once per second; the code reads it every two seconds. Instead of a single threshold for the fan we use hysteresis: the fan starts at 28 °C but only stops when the temperature drops to 26 °C. With a single threshold, the relay would keep clicking as the temperature wavered between 27 and 28 °C, wearing out both itself and the fan. If the sensor fails a reading and returns "nan", the code skips that measurement and keeps the last valid value. For more accurate measurements the DHT22 works with the same code; just write DHT22 instead of DHT11. More details in the DHT11 temperature and humidity sensor article.

RFID card door with a servo

The RC522 reads 13.56 MHz MIFARE cards and key fobs from 3–5 cm away. Every card has its own identification number (UID), and the code compares the UID it reads with a list of authorised cards. If there's a match, the servo swings the door to 90 degrees, you hear a short beep and the LCD shows "Hos geldin!" (Turkish for "Welcome!"); 5 seconds later the door closes by itself. An unknown card gets a long beep. To find your own cards' UIDs, upload the code, open the Serial Monitor at 9600 baud and scan a card: you'll see a line like "UID: A1 B2 C3 D4". Write these bytes into the CARDS list in the form 0xA1, adding a leading zero to any byte shown as a single digit (0x05 instead of 5). A lock that only checks the UID is fine for learning but gives no real security; we explain why in the RFID RC522 article.

Window and curtain

A second SG90 is enough for the window: connect a small hinged acrylic window to the servo horn with a wire, where 0 degrees means closed and 90 degrees means open. Calling write(0) before attach() stops the servo from jumping to 90 degrees at power-up and slamming the window. A curtain needs more travel: you wind the fabric onto a thin rod and turn the rod. A 28BYJ-48 stepper motor with a ULN2003 driver is quiet and precise for this, but it needs 4 pins; since the Uno has none left, it makes sense to leave the curtain for the ESP32 version or an Arduino Mega. If one pin has to do, an FS90R continuous rotation servo also works, but because it doesn't know its position you open and close the curtain by timing. Adding a rain sensor to close the window automatically when it rains is a nice extension too.

Lamp and fan with a relay

5 V relay module
Relay module: switches a lamp or fan in a separate circuit on and off with a small signal from the Arduino; the load connects to the COM, NO and NC terminals.

An Arduino pin can safely supply only about 20 mA (the absolute limit is 40 mA), while a fan or lamp needs much more. That's why a relay module sits in between: the signal on its IN pin energises an electromagnet that closes contacts in a separate circuit. Connect the load to the COM and NO terminals so that the lamp stays off while the Arduino is off or restarting. Most of these modules are active LOW, meaning the relay switches on when you write LOW; that's what the RELAY_ON and RELAY_OFF constants in the code are for. In setup(), the code writes HIGH before making the pin an output, so the relay doesn't click on even for a moment as the Arduino starts. We used hysteresis so the fan doesn't switch on and off too often, while the lamp stays on until the PIR timer runs out.

Use 5 V or 12 V LED lamps and fans for the model. Even though the relay says "10 A 250 V AC", mains voltage can kill; in a school project it should only be wired under adult supervision, inside a closed box and with a fuse. The safe wiring rules are in the What is a relay module? article.

The complete sketch (Arduino Uno)

The most important rule in smart home code is that no module waits for another. If you kept the door open for 5 seconds with delay(5000), the gas alarm wouldn't work and the PIR wouldn't be read during that time. That's why we put each module in its own function, and loop() calls these functions one after another hundreds of times a second. Anything involving time is measured with millis(), and the state of each module is kept in variables such as lightOn, fanOn, doorOpen and alarmOn. All the settings sit at the top of the code as constants, so you don't have to dig through the code to change a threshold. You'll find the logic behind this approach in the millis() vs delay() article. To compile the code, install the MFRC522 library, Adafruit's DHT sensor library and Frank de Brabander's LiquidCrystal I2C from the Library Manager, and install all dependencies when asked. Servo, SPI and Wire come with the Arduino IDE.

Arduino (C++)
1#include <SPI.h>
2#include <MFRC522.h>
3#include <Servo.h>
4#include <DHT.h>
5#include <Wire.h>
6#include <LiquidCrystal_I2C.h>
7
8// Pinler / Pins
9const byte PIR_PIN = 2, FLAME_PIN = 3, DHT_PIN = 4, BUZZER_PIN = 5, DOOR_PIN = 6;
10const byte LAMP_RELAY = 7, FAN_RELAY = 8, RST_PIN = 9, SS_PIN = 10;
11const byte GAS_PIN = A0, LDR_PIN = A1, WINDOW_PIN = A2;
12
13// Ayarlar / Settings
14const byte RELAY_ON = LOW, RELAY_OFF = HIGH;     // aktif LOW röle / active-LOW relay
15const byte FLAME_ACTIVE = LOW;                   // alev görünce DO LOW olur / DO goes LOW on flame
16const int GAS_LIMIT = 400;                       // temiz havaya göre ayarla / tune in clean air
17const int DARK_LIMIT = 300;                      // bunun altı karanlık / below this is dark
18const float FAN_ON = 28.0, FAN_OFF = 26.0;       // fan histerezisi (°C) / fan hysteresis (°C)
19const unsigned long LIGHT_MS = 20000;            // son hareketten sonra ışık / light after last motion
20const unsigned long DOOR_MS = 5000;              // kapı açık kalma süresi / door open time
21const unsigned long WARMUP_MS = 60000;           // MQ-2 ve PIR ısınması / MQ-2 and PIR warm-up
22
23const byte CARDS[][4] = {                        // yetkili kart UID'leri / authorised card UIDs
24  {0xA1, 0xB2, 0xC3, 0xD4},
25  {0x12, 0x34, 0x56, 0x78}
26};
27
28MFRC522 rfid(SS_PIN, RST_PIN);
29Servo door, window;
30DHT dht(DHT_PIN, DHT11);
31LiquidCrystal_I2C lcd(0x27, 16, 2);
32
33float tempC = 0, hum = 0;
34int gas = 0;
35bool lightOn = false, fanOn = false, doorOpen = false, alarmOn = false;
36unsigned long lastMotion = 0, doorAt = 0, lastDht = 0, lastLcd = 0, beepUntil = 0;
37
38void setup() {
39  Serial.begin(9600);
40  digitalWrite(LAMP_RELAY, RELAY_OFF); pinMode(LAMP_RELAY, OUTPUT);  // açılışta kapalı / off at boot
41  digitalWrite(FAN_RELAY, RELAY_OFF);  pinMode(FAN_RELAY, OUTPUT);
42  pinMode(PIR_PIN, INPUT);
43  pinMode(FLAME_PIN, INPUT);
44  pinMode(BUZZER_PIN, OUTPUT);
45  door.write(0);   door.attach(DOOR_PIN);        // önce açı, sonra attach / angle first, then attach
46  window.write(0); window.attach(WINDOW_PIN);
47  dht.begin();
48  SPI.begin();
49  rfid.PCD_Init();
50  lcd.init();
51  lcd.backlight();
52  lcd.print(F("BlueGrays Ev"));
53}
54
55void loop() {
56  unsigned long now = millis();
57  handleLight(now);
58  handleClimate(now);
59  handleSafety(now);
60  handleDoor(now);
61  bool beep = (long)(beepUntil - now) > 0;
62  digitalWrite(BUZZER_PIN, beep || (alarmOn && (now / 250) % 2));   // alarmda kesik bip / pulsed beep on alarm
63  updateLcd(now);
64}
65
66// 1) Hareketle ışık / motion light
67void handleLight(unsigned long now) {
68  if (now < WARMUP_MS) return;                   // PIR ısınıyor / PIR warming up
69  if (digitalRead(PIR_PIN) == HIGH) {
70    lastMotion = now;
71    if (analogRead(LDR_PIN) < DARK_LIMIT) lightOn = true;   // yalnız karanlıkta yak / only when dark
72  }
73  if (lightOn && now - lastMotion > LIGHT_MS) lightOn = false;
74  digitalWrite(LAMP_RELAY, lightOn ? RELAY_ON : RELAY_OFF);
75}
76
77// 2) Sıcaklık ve fan / temperature and fan
78void handleClimate(unsigned long now) {
79  if (now - lastDht < 2000) return;              // DHT11'i sık okuma / don't read DHT11 too often
80  lastDht = now;
81  float t = dht.readTemperature();
82  float h = dht.readHumidity();
83  if (isnan(t) || isnan(h)) return;              // okuma hatası / read error
84  tempC = t;
85  hum = h;
86  if (tempC >= FAN_ON) fanOn = true;
87  if (tempC <= FAN_OFF) fanOn = false;
88  digitalWrite(FAN_RELAY, fanOn ? RELAY_ON : RELAY_OFF);
89}
90
91// 3) Gaz ve yangın / gas and fire
92void handleSafety(unsigned long now) {
93  gas = analogRead(GAS_PIN);
94  bool gasAlarm = now > WARMUP_MS && gas > GAS_LIMIT;
95  bool fire = digitalRead(FLAME_PIN) == FLAME_ACTIVE;
96  alarmOn = gasAlarm || fire;
97  window.write(gasAlarm && !fire ? 90 : 0);      // gazda aç, yangında kapalı tut / open on gas, shut on fire
98}
99
100// 4) RFID kapı / RFID door
101void handleDoor(unsigned long now) {
102  if (doorOpen && now - doorAt > DOOR_MS) {
103    door.write(0);                               // süre dolunca kapat / close when time is up
104    doorOpen = false;
105  }
106  if (!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) return;
107  Serial.print(F("UID:"));                       // yeni kartın UID'sini öğren / learn a new card's UID
108  for (byte i = 0; i < rfid.uid.size; i++) {
109    Serial.print(' ');
110    Serial.print(rfid.uid.uidByte[i], HEX);
111  }
112  Serial.println();
113  if (isAllowed(rfid.uid.uidByte)) {
114    door.write(90);
115    doorOpen = true;
116    doorAt = now;
117    beepUntil = now + 100;                       // kısa bip: hoş geldin / short beep: welcome
118  } else {
119    beepUntil = now + 800;                       // uzun bip: yetkisiz kart / long beep: unknown card
120  }
121  rfid.PICC_HaltA();
122}
123
124bool isAllowed(const byte *uid) {
125  for (byte i = 0; i < sizeof(CARDS) / 4; i++) {
126    if (memcmp(uid, CARDS[i], 4) == 0) return true;
127  }
128  return false;
129}
130
131// 5) Ekran / display
132void updateLcd(unsigned long now) {
133  if (now - lastLcd < 1000) return;
134  lastLcd = now;
135  lcd.setCursor(0, 0);
136  lcd.print(F("T:"));
137  lcd.print(tempC, 0);
138  lcd.print(F("C Nem:%"));
139  lcd.print(hum, 0);
140  lcd.print(F("   "));
141  lcd.setCursor(0, 1);
142  if (alarmOn) {
143    lcd.print(F("!! ALARM !!     "));
144  } else if (doorOpen) {
145    lcd.print(F("Hos geldin!     "));
146  } else {
147    lcd.print(F("Gaz:"));
148    lcd.print(gas);
149    lcd.print(F("        "));
150  }
151}
FunctionJobHow often?
handleLight()Switches the lamp relay on based on the PIR and LDR, and off after 20 seconds without motionEvery loop (except the first 60 seconds)
handleClimate()Reads the DHT11 and drives the fan with 28/26 °C hysteresisEvery 2 seconds
handleSafety()Reads the MQ-2 and flame sensor and manages the alarm and windowEvery loop
handleDoor()Reads the card, prints the UID to the Serial Monitor, opens and closes the doorEvery loop
updateLcd()Shows temperature, humidity, the gas reading or a status messageOnce a second
Buzzer line inside loop()Produces the card beep and the pulsing alarm soundEvery loop

When compiled, this code uses about 38 % of the Uno's program memory and 28 % of its RAM, so there's room left in memory, but only A3 remains free among the pins. You can connect a button or a rain sensor to A3; for anything more you'll need to move to an Arduino Mega or an ESP32. Putting fixed text inside F() is the easiest way to keep RAM usage low.

Phone control: ESP32 web server

ESP32 development board
ESP32: Wi-Fi and Bluetooth are built in, so no extra module is needed to control the smart home from your phone.

The Uno has no Wi-Fi; the easiest way to control the smart home from your phone is to swap the brain for an ESP32. The code below connects the ESP32 to your home network and starts a small web server. With your phone on the same Wi-Fi network, open the IP address shown in the Serial Monitor in the browser and you'll see four big buttons for the lamp, fan, door and window plus the current temperature, humidity and gas reading; the page refreshes itself every 10 seconds. Each button sends the ESP32 a short request saying which device to switch; the ESP32 changes the state and redirects you back to the main page. For the servos, install the ESP32Servo library from the Library Manager, because the standard Servo library doesn't work on the ESP32.

Arduino (C++)
1#include <WiFi.h>
2#include <WebServer.h>
3#include <ESP32Servo.h>
4#include <DHT.h>
5
6const char* ssid = "AgAdi";                 // Wi-Fi adın / your Wi-Fi name
7const char* password = "Sifre123";          // Wi-Fi şifren / your Wi-Fi password
8
9const int LAMP_RELAY = 26, FAN_RELAY = 27;
10const int DOOR_PIN = 32, WINDOW_PIN = 33;
11const int DHT_PIN = 13, GAS_PIN = 34;       // GPIO 34: ADC1, bölücüyle / ADC1, through a divider
12const int RELAY_ON = LOW, RELAY_OFF = HIGH; // aktif LOW röle / active-LOW relay
13
14WebServer server(80);
15Servo door, window;
16DHT dht(DHT_PIN, DHT11);
17
18bool lamp = false, fan = false, doorOpen = false, windowOpen = false;
19float tempC = NAN, hum = NAN;
20unsigned long lastDht = 0;
21
22void apply() {                              // durumu donanıma uygula / push the state to the hardware
23  digitalWrite(LAMP_RELAY, lamp ? RELAY_ON : RELAY_OFF);
24  digitalWrite(FAN_RELAY, fan ? RELAY_ON : RELAY_OFF);
25  door.write(doorOpen ? 90 : 0);
26  window.write(windowOpen ? 90 : 0);
27}
28
29String button(const char* id, const char* label, bool on) {
30  return String("<a class='b ") + (on ? "on" : "off") + "' href='/set?d=" + id +
31         "&v=" + (on ? "0" : "1") + "'>" + label + (on ? ": ON" : ": OFF") + "</a>";
32}
33
34void handleRoot() {
35  String html = "<!DOCTYPE html><html><head><meta charset='utf-8'>"
36                "<meta name='viewport' content='width=device-width,initial-scale=1'>"
37                "<meta http-equiv='refresh' content='10'><title>BlueGrays Ev</title>"
38                "<style>body{font-family:sans-serif;text-align:center}"
39                ".b{display:block;margin:12px auto;padding:18px;max-width:320px;border-radius:10px;"
40                "color:#fff;text-decoration:none;font-size:20px}"
41                ".on{background:#2e7d32}.off{background:#607d8b}</style></head><body>"
42                "<h2>BlueGrays Akıllı Ev</h2>";
43  html += "<p>" + String(tempC, 1) + " °C | %" + String(hum, 0) +
44          " | Gaz/Gas: " + String(analogRead(GAS_PIN)) + "</p>";
45  html += button("lamp", "Lamba / Lamp", lamp);
46  html += button("fan", "Fan", fan);
47  html += button("door", "Kapı / Door", doorOpen);
48  html += button("window", "Pencere / Window", windowOpen);
49  html += "</body></html>";
50  server.send(200, "text/html", html);
51}
52
53void handleSet() {                          // /set?d=lamp&v=1
54  String d = server.arg("d");
55  bool v = server.arg("v") == "1";
56  if (d == "lamp") lamp = v;
57  else if (d == "fan") fan = v;
58  else if (d == "door") doorOpen = v;
59  else if (d == "window") windowOpen = v;
60  apply();
61  server.sendHeader("Location", "/");       // ana sayfaya dön / back to the main page
62  server.send(303);
63}
64
65void setup() {
66  Serial.begin(115200);
67  door.attach(DOOR_PIN, 500, 2400);
68  window.attach(WINDOW_PIN, 500, 2400);
69  pinMode(LAMP_RELAY, OUTPUT);
70  pinMode(FAN_RELAY, OUTPUT);
71  apply();                                  // her şey kapalı başlar / everything starts off
72  dht.begin();
73  WiFi.begin(ssid, password);
74  while (WiFi.status() != WL_CONNECTED) {
75    delay(500);
76    Serial.print('.');
77  }
78  Serial.println();
79  Serial.println(WiFi.localIP());           // bu adresi telefonda aç / open this address on your phone
80  server.on("/", handleRoot);
81  server.on("/set", handleSet);
82  server.begin();
83}
84
85void loop() {
86  server.handleClient();
87  if (millis() - lastDht > 2000) {          // 2 sn'de bir ölç / measure every 2 s
88    lastDht = millis();
89    float t = dht.readTemperature();
90    float h = dht.readHumidity();
91    if (!isnan(t) && !isnan(h)) {
92      tempC = t;
93      hum = h;
94    }
95  }
96}

This code only includes the parts you control remotely. You can also move the handleLight(), handleSafety() and handleDoor() functions from the Uno sketch here: change the pin numbers to match the ESP32 column in the table, use ESP32Servo instead of Servo, and re-measure the GAS_LIMIT and DARK_LIMIT thresholds because the ESP32's ADC returns values from 0 to 4095. The page has no password, so anyone on your home network could open the door; adding a simple password with the WebServer library's authenticate() function is a good habit. For a panel that updates in real time, see the ESP32 WebSocket article.

The ESP32's pins output 3.3 V. On an active-LOW 5 V relay module with an optocoupler, a 3.3 V HIGH signal may not always release the relay fully; if the relay never switches off, choose a module that can be triggered at 3.3 V, or on modules with a JD-VCC jumper, remove the jumper and power VCC from 3.3 V and JD-VCC from 5 V. If there's no Wi-Fi at school, replace the connection lines with WiFi.softAP("BlueGrays-Ev", "12345678") to let the ESP32 create its own network; your phone joins that network and opens 192.168.4.1.

Control from anywhere with Blynk

You can only reach the ESP32 web server from the same network. If you also want control from outside the house over mobile data, a cloud platform like Blynk IoT makes it easy: you build the interface by drag and drop in the phone app, and the ESP32 connects to the Blynk server. Create a template in Blynk.Cloud, add three datastreams called V0 (integer, 0–1, lamp), V1 (double, temperature) and V2 (double, humidity), add a device and paste the Template ID, Template Name and Auth Token you're given at the top of the code. In the app, just link a Switch to V0 and a Gauge each to V1 and V2. The free plan limits the number of devices, datastreams and messages per month, which is why we send the sensor data every five seconds rather than every second. The full setup is in the Blynk IoT with ESP32 guide.

Arduino (C++)
1#define BLYNK_TEMPLATE_ID "TMPLxxxxxxx"     // Blynk konsolundan kopyala / copy from the Blynk console
2#define BLYNK_TEMPLATE_NAME "Akilli Ev"
3#define BLYNK_AUTH_TOKEN "TokenBuraya"
4
5#include <WiFi.h>
6#include <BlynkSimpleEsp32.h>
7#include <DHT.h>
8
9const int LAMP_RELAY = 26;                  // aktif LOW röle / active-LOW relay
10DHT dht(13, DHT11);
11BlynkTimer timer;
12
13BLYNK_WRITE(V0) {                           // uygulamadaki anahtar / switch widget in the app
14  digitalWrite(LAMP_RELAY, param.asInt() ? LOW : HIGH);
15}
16
17BLYNK_CONNECTED() {
18  Blynk.syncVirtual(V0);                    // bağlanınca son durumu al / restore the last state
19}
20
21void sendSensors() {
22  float t = dht.readTemperature();
23  float h = dht.readHumidity();
24  if (isnan(t) || isnan(h)) return;
25  Blynk.virtualWrite(V1, t);                // sıcaklık / temperature
26  Blynk.virtualWrite(V2, h);                // nem / humidity
27}
28
29void setup() {
30  pinMode(LAMP_RELAY, OUTPUT);
31  digitalWrite(LAMP_RELAY, HIGH);           // açılışta kapalı / off at boot
32  dht.begin();
33  Blynk.begin(BLYNK_AUTH_TOKEN, "AgAdi", "Sifre123");
34  timer.setInterval(5000L, sendSensors);    // 5 sn'de bir: mesaj kotasını korur / every 5 s saves quota
35}
36
37void loop() {
38  Blynk.run();
39  timer.run();
40}

Which control method should you choose?

MethodWhat you needFrom outside the houseDifficultyBest for
ESP32 web serverESP32 and home Wi-FiNo, same network onlyMediumSchool presentations, demos without internet, fully your own code
Blynk IoTESP32, internet and a Blynk accountYesEasyReady-made interface, charts and notifications
Bluetooth (HC-05)Uno, HC-05 and an Android appNo, about 10 mEasyStaying with the Uno (doesn't work with iPhone)
Telegram botESP32 and internetYesMediumAlarm notifications and short commands
MQTT + Home AssistantESP32 and a local server (e.g. Raspberry Pi)Yes, needs setting upAdvancedReal home automation

For a school presentation, the ESP32 web server is the safest choice: it doesn't depend on the internet or a cloud and works on its own network even if there's no Wi-Fi in the hall. If you want to stay with the Uno and just add Bluetooth, you can make your own Android app with App Inventor; but since the Uno has no pins left, you'll have to give up the LCD or the window servo to make room for the HC-05. You can get a message on your phone when the alarm goes off with an ESP32 Telegram bot, and connect the house to real devices with MQTT and Home Assistant.

Smart home with the Raspberry Pi Pico

You can also build the same system in MicroPython with a Raspberry Pi Pico, and the Pico W with Wi-Fi can be controlled from your phone just like the ESP32 (see the Pico W web server). Because the Pico runs at 3.3 V, the ESP32 rules apply here too: feed the LDR divider from 3V3, bring 5 V analog outputs down with a divider and choose a relay module that can be triggered at 3.3 V. The only analog inputs are GP26, GP27 and GP28. The code below is the MicroPython version of the motion-activated light module:

MicroPython
1from machine import Pin, ADC
2import time
3
4pir = Pin(15, Pin.IN)                  # PIR OUT (3,3 V çıkış / 3.3 V output)
5ldr = ADC(26)                          # GP26: bölücü 3V3'ten / divider fed from 3V3
6relay = Pin(14, Pin.OUT, value=1)      # aktif LOW röle, kapalı başla / active-LOW relay, start off
7
8LIGHT_MS = 20000                       # son hareketten sonra ışık / light after last motion
9DARK = 20000                           # bunun altı karanlık / below this is dark
10last = time.ticks_ms()
11on = False
12
13while True:
14    now = time.ticks_ms()
15    if pir.value():
16        last = now
17        if ldr.read_u16() < DARK:      # yalnız karanlıkta yak / only when dark
18            on = True
19    if on and time.ticks_diff(now, last) > LIGHT_MS:
20        on = False
21    relay.value(0 if on else 1)
22    time.sleep_ms(50)

Tips for your school presentation

  • Start with a problem: describe a real issue in one sentence, such as "lights left on in an empty house, a gas leak nobody notices, elderly people who lose their keys", then show how your model answers it.
  • Prepare a block diagram: sensors on the left, the Arduino in the middle and actuators on the right; label the arrows with the rules ("dark + motion → lamp"). The judges won't read your code, but they'll remember this diagram.
  • Script a live demo: scan the card and show the door opening, wave your hand in front of the PIR, bring a cotton pad soaked in rubbing alcohol near the MQ-2 (alcohol triggers the sensor too) and warm the DHT11 with your fingers. Keep each demo to 10–20 seconds.
  • No open flames: don't light a lighter or candle inside a cardboard model. Most flame sensors also react to the infrared light of a TV remote held close; test it beforehand and use that in the demo.
  • Adjust thresholds for the room: if the hall is 22 °C on the day, waiting for 28 °C will ruin the fan demo; set FAN_ON 2–3 degrees above room temperature so the fan starts when you warm the sensor with your fingers.
  • Measure and use numbers: for example, log how many minutes the lamp is on in a day with and without the PIR and give the saving as a percentage. A result with numbers is much stronger than saying "it works".
  • Have a backup plan: record a video of the working system, bring spare wires, a servo and an adapter, and write the card numbers and Wi-Fi settings on a piece of paper.
  • Prepare for the judges' questions: for "How would it work in a real house?", have short answers ready on mains safety, certified detectors, RFID security and what the door does in a power cut.
If you're preparing the project for a science fair, set a measurable research question instead of saying "I built a smart home", for example: "How much energy does lighting with a PIR and an LDR save compared with a lamp that's always on?" For ideas and judging criteria, see the Arduino science fair project ideas article.

Common mistakes and how to fix them

SymptomLikely causeFix
The Arduino resets or the LCD goes haywire when a servo movesServos and relays are powered from the Arduino's 5V pinSeparate 5 V 2–3 A adapter, common GND, 470–1000 µF capacitor on the servo supply
The relay works the wrong way round and is on at power-upThe module is active LOWSwap the RELAY_ON and RELAY_OFF values
The alarm goes off every time it's switched onThe MQ-2 is warming up and the PIR is learning its surroundingsKeep the WARMUP_MS delay; leave the MQ-2 on for a long time before first use
The lamp comes on in daylight or switches off and straight back onDARK_LIMIT is wrong or the LDR sees the lamp's lightSet the threshold from the Serial Monitor readings and move the LDR to an outside wall
Cards aren't readThe RC522 wiring is wrong or the module is connected to 5 VCheck the SPI pins and test the module with the DumpInfo example
The DHT11 returns nanThe DATA wire is on the wrong pin or a bare sensor has no pull-up resistorCheck the pin, use a module or add 10 kΩ between DATA and VCC
The servo jitters now and thenWeak power supply; interrupts pause briefly while the DHT11 is readImprove the power supply; if needed, detach() the servo once it has finished moving
On the ESP32 the gas reading is always 0 or 4095An ADC2 pin clashes with Wi-Fi or there's no dividerUse an ADC1 pin such as GPIO 34 or 35 and a voltage divider
The phone won't open the ESP32's pageThe phone is on a guest network or mobile data, or the network is 5 GHzJoin the same 2.4 GHz network and get the IP address from the Serial Monitor

An Arduino smart home project brings together reading sensors, making decisions, driving motors and relays, planning power and wireless control in a single build, which makes it a great topic both to learn from and to present. Start with one module, test every step and grow the system bit by bit. In the BlueGrays app you'll find the smart stair lighting, smart lighting with a PIR and LDR, flame and gas alarm, RFID door lock and ESP32 web server projects step by step, with circuit diagrams and code.

Frequently asked questions

What do I need to build an Arduino smart home project?

For a basic model, an Arduino Uno or ESP32, a PIR motion sensor, an LDR, an MQ-2 gas sensor, a flame sensor, a DHT11, an RC522 RFID module, two SG90 servos, a 2-channel relay module, a buzzer and an I2C LCD are enough. Add a breadboard, jumper wires, a 5 V 2–3 A power adapter and model-making materials. Most modules are cheap; the board, display, adapter and the model itself make up most of the budget.

Is Arduino or ESP32 better for a smart home project?

If you don't need phone control, the Arduino Uno is easier: it works directly with 5 V modules and most examples are written for it. Choose the ESP32 if you need Wi-Fi control from your phone, notifications or more pins, but because its pins run at 3.3 V you'll need to take extra care with relay modules and 5 V analog sensors.

How do I control an Arduino smart home from my phone?

The easiest way is to use an ESP32 and set up a web server; you then control the lamp, fan and door with buttons in the browser of a phone on the same Wi-Fi network. For access from outside the house you can use a cloud app such as Blynk IoT, or if you want to stay with the Arduino Uno, an HC-05 Bluetooth module and an Android app.

What is the best material for a smart home model?

The most practical material is 5 mm foam board or PVC foam board; it cuts with a craft knife and sticks with hot glue. For a sturdier body you can use 3–4 mm MDF. A base of about 50×40 cm, a removable roof and a separate technical compartment for the electronics make the job much easier.

Can an Arduino switch a mains lamp on and off?

Yes, with a 5 V relay module, which keeps the mains circuit electrically separate from the Arduino. But mains voltage can kill: make connections only with the plug pulled out, put the circuit in a closed, insulated box and never work on it in a student project without adult supervision. For a model, 5 V or 12 V lamps are all you need.

Is an Arduino smart home a good science fair project?

Smart homes are a very common topic, so a working model on its own is often not enough. If you link the project to a measurable research question, for example how much energy motion-activated lighting saves or how quickly the gas alarm responds, it becomes far stronger in the eyes of the judges.

See all projects
Temperature and Humidity with DHT11
#55Intermediate

Temperature and Humidity with DHT11

How warm is your room, and is the air humid or dry? The DHT11 sensor measures temperature and humidity, and the Arduino writes the values on a two-line LCD screen, refreshing every couple of seconds.

4.7(47)
64
Smart Stair and Corridor Lighting
#82Intermediate
Premium

Smart Stair and Corridor Lighting

Step onto the stairs or into the hallway and the lights come on one step at a time in the direction you are walking. There is a distance sensor at each end; whichever one you pass, the eight LEDs ligh

5.0(35)
51
ESP32 Smart Lighting (PIR + LDR + Relay + OLED)
#141Advanced
Premium

ESP32 Smart Lighting (PIR + LDR + Relay + OLED)

Turn your hallway, bathroom, or pantry into smart lighting with ESP32! Using a PIR motion sensor, LDR light sensor, and a relay module, we build the classic "light turns on when motion is detected in the dark" scenario — if the environment is already bright, motion does NOT trigger the light, saving energy during the day. The light stays on for 30 seconds; if motion continues, the timer resets and the light stays on longer. The SSD1306 OLED shows large-font status (ON / DAYTIME / WAITING), a cou

4.3(6)
11
Doorbell and Light with Motion Sensor
#25Intermediate
Premium

Doorbell and Light with Motion Sensor

When someone comes up to your door, you know before they even ring. As soon as the motion sensor spots someone, the LED lights up and the buzzer plays a three-note chime from high to low; when the tun

4.7(54)
71
Flame and Gas Sensor Alarm
#52Advanced
Premium

Flame and Gas Sensor Alarm

A little guard that warns you right away when gas leaks or a flame appears somewhere. The gas sensor watches the air for gas and the flame sensor watches for the light of a fire; while everything is f

4.8(52)
67
ESP32 RFID Door Lock (RC522 + Servo + OLED + Buzzer + LED)
#137Advanced
Premium

ESP32 RFID Door Lock (RC522 + Servo + OLED + Buzzer + LED)

We’re building a smart door lock using an ESP32, an RC522 RFID module, an SG90 servo motor, an SSD1306 OLED display, an active buzzer, and 2 LEDs. When a card is scanned, its UID is compared to the list of authorized cards stored in the code—if authorized, the servo motor rotates to unlock the door (green LED + 2 short beeps), and the door automatically locks again after 5 seconds. For an unauthorized card, the red LED lights up, a warning is given with 3 rapid beeps, and the captured UID is dis

4.8(9)
15
Lighting 220V Bulb with Remote Control
#21Advanced
Premium

Lighting 220V Bulb with Remote Control

Switch a real light bulb in your home on and off with a TV remote, without getting up from the sofa. The Arduino reads the invisible light signal from the remote; the power button clicks the relay and

4.4(22)
30
ESP32 Asynchronous Web Server (with IP Display on LCD)
#129Advanced
Premium

ESP32 Asynchronous Web Server (with IP Display on LCD)

In this project, we’re turning the ESP32 into an **asynchronous web server** that you can control from your phone or computer on the same Wi-Fi network. Thanks to the ESPAsyncWebServer library, the server can process multiple requests simultaneously (unlike the classic `WebServer.h`, which blocks on a single request). You’ll be able to open the ESP32’s IP address in a browser and click the ON/OFF buttons (the `/on` and `/off` routes) to turn the LED connected to GPIO 5 on and off.

4.8(16)
26