IoT & Hardware

Automating Stuff at Home with Arduino - My Smart Home Journey

How I turned my regular home into a smart home using Arduino, sensors, and way too much enthusiasm. From automatic plant watering to smart lighting, here's what actually worked (and what spectacularly didn't).

5 min read
arduino iot smart-home automation hardware sensors

It started innocently enough. I bought an Arduino Uno “just to learn electronics.” Six months later, my apartment looked like a mad scientist’s laboratory, with sensors in every corner and wires running along the walls. Here’s the story of how I automated my home, what worked brilliantly, what failed spectacularly, and the lessons learned along the way.

The Vision

Create a smart home that actually makes life easier, not more complicated. No monthly subscriptions, no cloud dependencies, no privacy concerns - just good old Arduino magic making everyday tasks automatic.

Project 1: Smart Plant Watering System

My first victim was my poor neglected plants. I’m a software engineer, not a botanist, and my plants kept dying from inconsistent watering. Time to fix this with technology!

The Hardware Setup

// Components needed:
// - Arduino Uno
// - Soil moisture sensor
// - Water pump (12V)
// - Relay module
// - Water tubes
// - Water reservoir
// - Power supply (12V)
// - Jumper wires

// Pin connections:
const int MOISTURE_SENSOR_PIN = A0;
const int RELAY_PIN = 7;
const int LED_PIN = 13;

// Thresholds
const int DRY_THRESHOLD = 300;    // Soil is dry when reading < 300
const int WET_THRESHOLD = 600;    // Soil is wet when reading > 600
const int PUMP_DURATION = 5000;   // Run pump for 5 seconds

void setup() {
  Serial.begin(9600);
  pinMode(RELAY_PIN, OUTPUT);
  pinMode(LED_PIN, OUTPUT);
  
  // Make sure pump is off initially
  digitalWrite(RELAY_PIN, LOW);
  digitalWrite(LED_PIN, LOW);
  
  Serial.println("Smart Plant Watering System Started!");
}

void loop() {
  int moistureLevel = analogRead(MOISTURE_SENSOR_PIN);
  
  Serial.print("Moisture Level: ");
  Serial.println(moistureLevel);
  
  if (moistureLevel < DRY_THRESHOLD) {
    Serial.println("Soil is dry! Watering plant...");
    
    // Turn on LED to indicate watering
    digitalWrite(LED_PIN, HIGH);
    
    // Turn on water pump
    digitalWrite(RELAY_PIN, HIGH);
    delay(PUMP_DURATION);
    digitalWrite(RELAY_PIN, LOW);
    
    // Turn off LED
    digitalWrite(LED_PIN, LOW);
    
    Serial.println("Watering complete!");
    
    // Wait 30 minutes before checking again
    delay(30 * 60 * 1000);
  } else if (moistureLevel > WET_THRESHOLD) {
    Serial.println("Soil is wet enough!");
  } else {
    Serial.println("Soil moisture is okay.");
  }
  
  // Check every 10 minutes
  delay(10 * 60 * 1000);
}

Results

This worked amazingly well! My plants stayed perfectly hydrated, and I learned that I was actually overwatering them before. The system prevented both drought and waterlogging. Plant survival rate went from 50% to 95%.

Lessons Learned

Project 2: Smart Lighting System

Next up: automatic lighting that responds to motion and ambient light levels. No more fumbling for switches in the dark!

Motion-Activated LED Strip

#include <WiFi.h>
#include <WebServer.h>

// Pin definitions
const int PIR_SENSOR_PIN = 2;
const int LDR_PIN = A0;
const int LED_STRIP_PIN = 9;

// WiFi credentials
const char* ssid = "YourWiFiName";
const char* password = "YourPassword";

// Lighting parameters
int lightThreshold = 300;    // Turn on lights when darker than this
int motionTimeout = 30000;   // Keep lights on for 30 seconds after motion
bool autoMode = true;
int ledBrightness = 255;

WebServer server(80);

void setup() {
  Serial.begin(115200);
  
  // Initialize pins
  pinMode(PIR_SENSOR_PIN, INPUT);
  pinMode(LED_STRIP_PIN, OUTPUT);
  
  // Connect to WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  
  Serial.println("WiFi connected!");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  
  // Set up web server routes
  server.on("/", handleRoot);
  server.on("/toggle", handleToggle);
  server.on("/brightness", handleBrightness);
  server.on("/status", handleStatus);
  server.on("/auto", handleAutoMode);
  server.on("/manual", handleManualMode);
  
  server.begin();
  Serial.println("Web server started!");
}

void loop() {
  server.handleClient();
  
  if (autoMode) {
    int lightLevel = analogRead(LDR_PIN);
    bool motionDetected = digitalRead(PIR_SENSOR_PIN);
    
    // Only turn on lights if it's dark and motion is detected
    if (lightLevel < lightThreshold && motionDetected) {
      analogWrite(LED_STRIP_PIN, ledBrightness);
      Serial.println("Motion detected - Lights ON");
      
      // Keep lights on for specified duration
      delay(motionTimeout);
      
      // Check if there's still motion before turning off
      if (!digitalRead(PIR_SENSOR_PIN)) {
        analogWrite(LED_STRIP_PIN, 0);
        Serial.println("No motion - Lights OFF");
      }
    }
  }
  
  delay(100);
}

void handleRoot() {
  String html = "<html><head><title>Smart Lighting</title></head><body>";
  html += "<h1>Smart Lighting Control</h1>";
  html += "<p>Light Level: <span id='lightLevel'>--</span></p>";
  html += "<p>Motion: <span id='motion'>--</span></p>";
  html += "<p>Brightness: <span id='brightness'>--</span>%</p>";
  html += "<button onclick='setAutoMode()'>Auto Mode</button>";
  html += "<button onclick='setManualMode()'>Manual Mode</button>";
  html += "<br><br>";
  html += "<input type='range' min='0' max='255' value='255' ";
  html += "onchange='setBrightness(this.value)'>";
  html += "</body></html>";
  
  server.send(200, "text/html", html);
}

void handleStatus() {
  int lightLevel = analogRead(LDR_PIN);
  bool motion = digitalRead(PIR_SENSOR_PIN);
  
  String json = "{";
  json += "\"lightLevel\":" + String(lightLevel) + ",";
  json += "\"motion\":" + String(motion ? "true" : "false") + ",";
  json += "\"brightness\":" + String(ledBrightness);
  json += "}";
  
  server.send(200, "application/json", json);
}

void handleBrightness() {
  if (server.hasArg("value")) {
    ledBrightness = server.arg("value").toInt();
    analogWrite(LED_STRIP_PIN, ledBrightness);
  }
  server.send(200, "text/plain", "OK");
}

Web Interface Benefits

Adding a simple web interface made the system much more user-friendly. I could adjust brightness, switch between auto and manual modes, and monitor sensor readings from my phone.

Project 3: Smart Temperature Control

Living in Nepal, temperature control is crucial. I built a system that monitors temperature and humidity, controls fans, and even sends alerts when it gets too hot or cold.

#include <DHT.h>
#include <LiquidCrystal.h>

// DHT22 sensor for temperature and humidity
#define DHT_PIN 2
#define DHT_TYPE DHT22
DHT dht(DHT_PIN, DHT_TYPE);

// LCD display (16x2)
LiquidCrystal lcd(12, 11, 5, 4, 3, 6);

// Relay pins for controlling devices
const int FAN_RELAY = 7;
const int HEATER_RELAY = 8;
const int BUZZER_PIN = 9;

// Temperature thresholds
const float TEMP_HIGH = 28.0;  // Turn on fan above 28°C
const float TEMP_LOW = 18.0;   // Turn on heater below 18°C
const float TEMP_CRITICAL_HIGH = 35.0;  // Alert above 35°C
const float TEMP_CRITICAL_LOW = 10.0;   // Alert below 10°C

// Humidity thresholds
const float HUMIDITY_HIGH = 80.0;  // High humidity warning
const float HUMIDITY_LOW = 30.0;   // Low humidity warning

void setup() {
  Serial.begin(9600);
  dht.begin();
  lcd.begin(16, 2);
  
  pinMode(FAN_RELAY, OUTPUT);
  pinMode(HEATER_RELAY, OUTPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  
  // Initialize relays to OFF
  digitalWrite(FAN_RELAY, LOW);
  digitalWrite(HEATER_RELAY, LOW);
  
  lcd.print("Smart Climate");
  lcd.setCursor(0, 1);
  lcd.print("System Starting...");
  delay(2000);
}

void loop() {
  // Read temperature and humidity
  float temperature = dht.readTemperature();
  float humidity = dht.readHumidity();
  
  // Check if readings are valid
  if (isnan(temperature) || isnan(humidity)) {
    Serial.println("Failed to read from DHT sensor!");
    lcd.clear();
    lcd.print("Sensor Error!");
    delay(2000);
    return;
  }
  
  // Display on LCD
  lcd.clear();
  lcd.print("Temp: ");
  lcd.print(temperature, 1);
  lcd.print("C");
  lcd.setCursor(0, 1);
  lcd.print("Humidity: ");
  lcd.print(humidity, 1);
  lcd.print("%");
  
  // Serial output for logging
  Serial.print("Temperature: ");
  Serial.print(temperature);
  Serial.print("°C, Humidity: ");
  Serial.print(humidity);
  Serial.println("%");
  
  // Temperature control logic
  controlTemperature(temperature);
  
  // Humidity monitoring
  monitorHumidity(humidity);
  
  // Critical temperature alerts
  checkCriticalConditions(temperature, humidity);
  
  delay(5000); // Update every 5 seconds
}

void controlTemperature(float temp) {
  static bool fanOn = false;
  static bool heaterOn = false;
  
  // Fan control (with hysteresis to prevent rapid switching)
  if (temp > TEMP_HIGH && !fanOn) {
    digitalWrite(FAN_RELAY, HIGH);
    fanOn = true;
    Serial.println("Fan turned ON");
  } else if (temp < (TEMP_HIGH - 2.0) && fanOn) {
    digitalWrite(FAN_RELAY, LOW);
    fanOn = false;
    Serial.println("Fan turned OFF");
  }
  
  // Heater control
  if (temp < TEMP_LOW && !heaterOn) {
    digitalWrite(HEATER_RELAY, HIGH);
    heaterOn = true;
    Serial.println("Heater turned ON");
  } else if (temp > (TEMP_LOW + 2.0) && heaterOn) {
    digitalWrite(HEATER_RELAY, LOW);
    heaterOn = false;
    Serial.println("Heater turned OFF");
  }
}

void checkCriticalConditions(float temp, float humidity) {
  static unsigned long lastAlert = 0;
  unsigned long now = millis();
  
  // Only alert once every 5 minutes to avoid spam
  if (now - lastAlert < 300000) return;
  
  if (temp > TEMP_CRITICAL_HIGH || temp < TEMP_CRITICAL_LOW) {
    // Sound buzzer alert
    for (int i = 0; i < 3; i++) {
      digitalWrite(BUZZER_PIN, HIGH);
      delay(500);
      digitalWrite(BUZZER_PIN, LOW);
      delay(500);
    }
    
    Serial.println("CRITICAL TEMPERATURE ALERT!");
    lastAlert = now;
  }
}

Project 4: Smart Door Lock

This was my most ambitious project - a keypad-controlled door lock with smartphone notifications.

#include <Keypad.h>
#include <Servo.h>
#include <WiFi.h>
#include <HTTPClient.h>

// Keypad setup
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3, 2};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

// Servo for lock mechanism
Servo lockServo;
const int SERVO_PIN = 10;
const int LOCKED_POSITION = 0;
const int UNLOCKED_POSITION = 90;

// Security settings
String correctPassword = "1234";
String enteredPassword = "";
int maxAttempts = 3;
int attemptCount = 0;
unsigned long lockoutTime = 300000; // 5 minutes
unsigned long lastFailedAttempt = 0;

void setup() {
  Serial.begin(9600);
  lockServo.attach(SERVO_PIN);
  
  // Start in locked position
  lockServo.write(LOCKED_POSITION);
  
  Serial.println("Smart Door Lock System Ready");
  Serial.println("Enter password:");
}

void loop() {
  char key = keypad.getKey();
  
  if (key) {
    Serial.print("Key pressed: ");
    Serial.println(key);
    
    if (key == '#') {
      // Check password
      checkPassword();
    } else if (key == '*') {
      // Clear entered password
      enteredPassword = "";
      Serial.println("Password cleared");
    } else {
      // Add to password
      enteredPassword += key;
      Serial.print("Password: ");
      for (int i = 0; i < enteredPassword.length(); i++) {
        Serial.print("*");
      }
      Serial.println();
    }
  }
  
  // Auto-lock after 10 seconds
  static unsigned long lastUnlock = 0;
  if (millis() - lastUnlock > 10000 && lockServo.read() == UNLOCKED_POSITION) {
    lockDoor();
    lastUnlock = 0;
  }
}

void checkPassword() {
  // Check if in lockout period
  if (attemptCount >= maxAttempts && 
      millis() - lastFailedAttempt < lockoutTime) {
    Serial.println("System locked! Try again later.");
    return;
  }
  
  if (enteredPassword == correctPassword) {
    Serial.println("Access granted!");
    unlockDoor();
    attemptCount = 0; // Reset attempt counter
    sendNotification("Door unlocked successfully");
  } else {
    Serial.println("Access denied!");
    attemptCount++;
    lastFailedAttempt = millis();
    
    if (attemptCount >= maxAttempts) {
      Serial.println("Too many failed attempts! System locked for 5 minutes.");
      sendNotification("Multiple failed unlock attempts detected!");
    }
  }
  
  enteredPassword = ""; // Clear password
}

void unlockDoor() {
  lockServo.write(UNLOCKED_POSITION);
  Serial.println("Door unlocked");
}

void lockDoor() {
  lockServo.write(LOCKED_POSITION);
  Serial.println("Door locked");
}

void sendNotification(String message) {
  // Send notification via webhook or SMS API
  // Implementation depends on your preferred service
  Serial.print("Notification: ");
  Serial.println(message);
}

The Spectacular Failures

Not everything worked as planned. Here are some of my “learning experiences”:

The Great Overwatering Incident

My first plant watering system had no overflow protection. Came home to find my living room floor flooded because the moisture sensor got stuck. Always have failsafes!

The False Alarm Festival

Motion sensors are sensitive. My first security system triggered every time a cat walked by outside. Spent weeks fine-tuning sensitivity and adding time delays.

The WiFi Dependency Disaster

Made everything depend on WiFi initially. When the internet went down, nothing worked. Now all systems have offline modes and local controls.

Lessons Learned and Best Practices

Power Management

// Use sleep modes to save power
#include <avr/sleep.h>
#include <avr/power.h>

void enterSleepMode() {
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  power_adc_disable();
  power_spi_disable();
  power_timer0_disable();
  power_timer1_disable();
  power_timer2_disable();
  power_twi_disable();
  
  sleep_mode(); // Sleep here
  
  // Wake up here
  sleep_disable();
  power_all_enable();
}

Error Handling

// Always check sensor readings
float readTemperature() {
  float temp = dht.readTemperature();
  
  if (isnan(temp)) {
    Serial.println("Temperature sensor error!");
    return -999.0; // Error value
  }
  
  // Sanity check - temperature should be reasonable
  if (temp < -40 || temp > 80) {
    Serial.println("Temperature reading out of range!");
    return -999.0;
  }
  
  return temp;
}

Modularity

// Break code into functions
void updateSensors() {
  temperature = readTemperature();
  humidity = readHumidity();
  lightLevel = analogRead(LDR_PIN);
}

void controlDevices() {
  controlLighting();
  controlTemperature();
  controlWatering();
}

void updateDisplay() {
  displayTemperature();
  displayHumidity();
  displayStatus();
}

Cost Breakdown and ROI

Total Investment

Monthly Savings

The system paid for itself in about 18 months, not counting the satisfaction of building something useful.

Future Improvements

Currently Working On

Wish List

Conclusion

Building a smart home with Arduino taught me more about electronics, programming, and problem-solving than any tutorial ever could. The key insights:

  1. Start small: Begin with one simple project and expand gradually
  2. Plan for failures: Things will break; design for easy debugging and repair
  3. User experience matters: Automation should make life easier, not more complicated
  4. Document everything: Future you will thank present you for good comments
  5. Iterate continuously: Your first version won’t be perfect, and that’s okay

The journey from “blinking LED” to “automated home” was filled with frustration, late nights debugging sensor issues, and the occasional electrical mishap. But seeing your plants thrive, lights automatically adjust to your presence, and temperature stay perfectly comfortable makes every moment worthwhile.

Most importantly, I learned that the best smart home isn’t the one with the most features - it’s the one that seamlessly integrates into your daily routine and just works. Arduino made that possible without breaking the bank or compromising privacy.

My apartment might look like a mad scientist’s laboratory, but it’s MY mad scientist’s laboratory, and I know exactly how every wire and sensor works. That’s worth more than any commercial smart home system.

References