DIY PIR-Based Night Light with Auto Dimming

Project Overview

This project creates a smart night light that turns on when motion is detected and gradually dims over time. The light uses an RGB LED or LED strip and features smooth fade-out effects, making it perfect for bedrooms, hallways, and children’s rooms.

Difficulty: Beginner
Estimated time: 1-2 hours
Estimated cost: $15-25

How It Works

A PIR sensor detects motion. When motion is detected, the LED turns on at full brightness. After a set period without motion, the light gradually dims over several seconds rather than turning off abruptly. An optional ambient light sensor (LDR) can be added so the light only activates when it’s dark enough.

Materials Needed

  • Arduino Nano or Arduino Uno (1)
  • HC-SR501 PIR sensor (1)
  • RGB LED (common cathode) or WS2812B LED strip (3-5 LEDs)
  • LDR (photoresistor) (optional, for daylight detection)
  • 10kΩ resistor (for LDR voltage divider)
  • 220Ω resistors (3 for RGB LED)
  • Project enclosure (small box or 3D-printed housing)
  • Jumper wires
  • USB power supply (5V 1A)

Circuit Diagram

Option 1: RGB LED (Common Cathode)

Component Pin Arduino Pin
PIR Sensor VCC 5V
PIR Sensor GND GND
PIR Sensor OUT Digital Pin 2
RGB LED (Red) Anode Digital Pin 9 (through 220Ω)
RGB LED (Green) Anode Digital Pin 10 (through 220Ω)
RGB LED (Blue) Anode Digital Pin 11 (through 220Ω)
RGB LED Cathode GND
LDR One leg 5V
LDR Other leg Analog Pin A0 and 10kΩ resistor to GND

Arduino Code

// PIR Night Light with Auto Dimming
// Uses RGB LED with smooth fade-out effect

const int pirPin = 2;
const int redPin = 9;
const int greenPin = 10;
const int bluePin = 11;
const int ldrPin = A0;  // Optional

// Color settings (warm white)
int redValue = 255;
int greenValue = 180;
int blueValue = 100;

// Timing
unsigned long lastMotionTime = 0;
const unsigned long holdTime = 30000; // 30 seconds before dimming
const unsigned long fadeDuration = 5000; // 5 second fade-out

bool lightsOn = false;
int currentBrightness = 0;
unsigned long fadeStartTime = 0;

void setup() {
  Serial.begin(9600);
  
  pinMode(pirPin, INPUT);
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);
  
  // Turn off lights initially
  setBrightness(0);
  
  Serial.println("Night Light Ready");
  Serial.println("Waiting 60 seconds for PIR warm-up...");
  delay(60000);
}

void setColor(int r, int g, int b) {
  analogWrite(redPin, r);
  analogWrite(greenPin, g);
  analogWrite(bluePin, b);
}

void setBrightness(int percent) {
  // percent: 0-100
  int r = map(percent, 0, 100, 0, redValue);
  int g = map(percent, 0, 100, 0, greenValue);
  int b = map(percent, 0, 100, 0, blueValue);
  setColor(r, g, b);
  currentBrightness = percent;
}

bool isDark() {
  int ldrValue = analogRead(ldrPin);
  // Adjust threshold based on your environment
  return ldrValue < 500; // Dark when reading < 500
}

void fadeOut() {
  unsigned long elapsed = millis() - fadeStartTime;
  if (elapsed >= fadeDuration) {
    setBrightness(0);
    lightsOn = false;
  } else {
    int brightness = 100 - (elapsed * 100 / fadeDuration);
    setBrightness(brightness);
  }
}

void loop() {
  // Check if it's dark enough (optional)
  if (!isDark() && lightsOn) {
    // It's daytime, turn off lights immediately
    setBrightness(0);
    lightsOn = false;
  }
  
  bool motionDetected = digitalRead(pirPin) == HIGH;
  
  if (motionDetected && isDark()) {
    lastMotionTime = millis();
    
    if (!lightsOn) {
      // Turn on lights immediately
      setBrightness(100);
      lightsOn = true;
      Serial.println("Motion detected - Lights ON");
    } else if (currentBrightness < 100) {
      // Fade back up if dimming was in progress
      setBrightness(100);
      Serial.println("Motion detected - Fade cancelled");
    }
  }
  
  if (lightsOn) {
    // Check if it's time to dim
    if (millis() - lastMotionTime > holdTime) {
      if (fadeStartTime == 0) {
        fadeStartTime = millis();
        Serial.println("No motion - Starting fade-out");
      }
      fadeOut();
    } else {
      // Reset fade timer if motion occurs during fade
      fadeStartTime = 0;
    }
  }
  
  delay(50);
}

Code for WS2812B LED Strip

#include <FastLED.h>

#define LED_PIN     6
#define NUM_LEDS    5
#define BRIGHTNESS  128

CRGB leds[NUM_LEDS];

const int pirPin = 2;
const int ldrPin = A0;

unsigned long lastMotionTime = 0;
const unsigned long holdTime = 30000;
const unsigned long fadeDuration = 5000;

bool lightsOn = false;
int currentBrightness = 0;
unsigned long fadeStartTime = 0;

void setup() {
  FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
  FastLED.setBrightness(0);
  
  pinMode(pirPin, INPUT);
  
  Serial.begin(9600);
  delay(60000);
}

void setBrightness(int percent) {
  int brightness = map(percent, 0, 100, 0, BRIGHTNESS);
  FastLED.setBrightness(brightness);
  FastLED.show();
  currentBrightness = percent;
}

void setColor(CRGB color) {
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = color;
  }
  FastLED.show();
}

void loop() {
  int ldrValue = analogRead(ldrPin);
  bool isDark = ldrValue < 500;
  bool motionDetected = digitalRead(pirPin) == HIGH;
  
  if (motionDetected && isDark) {
    lastMotionTime = millis();
    
    if (!lightsOn) {
      setColor(CRGB::White);
      setBrightness(100);
      lightsOn = true;
    } else if (currentBrightness < 100) {
      setBrightness(100);
    }
    fadeStartTime = 0;
  }
  
  if (lightsOn) {
    if (millis() - lastMotionTime > holdTime) {
      if (fadeStartTime == 0) {
        fadeStartTime = millis();
      }
      unsigned long elapsed = millis() - fadeStartTime;
      if (elapsed >= fadeDuration) {
        setBrightness(0);
        lightsOn = false;
      } else {
        int brightness = 100 - (elapsed * 100 / fadeDuration);
        setBrightness(brightness);
      }
    }
  }
  
  delay(50);
}

Installation Steps

  1. Assemble circuit: Build on breadboard and test with USB power.
  2. Upload code: Load code to Arduino and adjust color values as desired.
  3. Calibrate LDR: Read ambient light values in dark and bright conditions, adjust threshold accordingly.
  4. Test motion detection: Walk past sensor and verify light turns on.
  5. Enclose components: Place Arduino and wiring in a small enclosure. Drill holes for PIR sensor lens and LED.
  6. Position sensor: Place unit at 0.5-1m height (night lights are typically placed low) facing the area to monitor.
  7. Final test: Verify fade-out effect and daylight detection.

Customizing Colors

Adjust the RGB values for different color temperatures:

  • Warm white (2700K): R=255, G=180, B=100
  • Cool white (4000K): R=255, G=235, B=205
  • Soft amber: R=255, G=140, B=50
  • Night vision safe (red): R=255, G=0, B=0
  • RGB cycle mode: Add code to cycle through colors

Project Extensions

  • Multiple LEDs: Use addressable LED strip for longer runs.
  • Color temperature sensing: Add a color sensor to match room lighting.
  • Bluetooth control: Add HC-05 module to control color and brightness from phone.
  • Sleep mode: Use deep sleep to reduce power consumption during the day.
  • Music sync: Add microphone module for sound-reactive lighting.

Conclusion

This smart night light provides gentle illumination when you need it and automatically fades out, making it perfect for bedrooms and hallways. The gradual dimming effect is much more pleasant than abrupt switching off.

Leave a Reply

Your email address will not be published. Required fields are marked *