Built-in project · Arduino Uno R3

Night light with a light sensor on an Arduino Uno

A light-dependent resistor in a divider fades a lamp up when the room goes dark. Drag the slider on the sensor. The whole build, an Arduino Uno and 6 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.

Teaching? Assign it to your class in one click.

Beginner About 15 minutes to build and run. Runs in your browser. Free, and no account needed.

The parts retail for about $32. On Mokxi they're free.

Step by step, with the wiring and the common mistakes: Arduino LDR Night Light (Photoresistor)

The circuit runs here once the page has loaded.

What you'll learn

  • A light sensor in a voltage divider
  • Hysteresis: two thresholds with a gap
  • Fading an LED with PWM
  • Keeping state between loop passes
  • Printing only when something changes
  • Difficulty: Beginner
  • Time: About 15 minutes
  • Board: Arduino Uno R3
  • Parts: 8

How it works

A light-dependent resistor and a 10k resistor form a voltage divider, and A0 reads its middle. Light lowers the sensor's resistance, so a bright room reads high and a covered sensor reads low.

The sketch uses two thresholds. It switches to night when the reading drops below 380, and back to day only when it rises above 580. In between, nothing changes, so the lamp does not flutter.

At night the lamp on pin 9 fades up to full in steps of 8 every 20 ms. The indicator LED on pin 8 follows the sensor right away.

Wiring table

Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.

Part and pinConnects to
Resistor, 220 Ω (1) pin 1Arduino Uno R3 pin 9
Resistor, 220 Ω (2) pin 1Arduino Uno R3 pin 8
Light sensor pin 1Arduino Uno R3 pin 5V
Resistor, 10k Ω pin 2Arduino Uno R3 pin GND
LED, yellow pin CArduino Uno R3 pin GND
LED, white pin CArduino Uno R3 pin GND
Light sensor pin 2Arduino Uno R3 pin A0
Resistor, 10k Ω pin 1Arduino Uno R3 pin A0
LED, yellow pin AResistor, 220 Ω (1) pin 2
LED, white pin AResistor, 220 Ω (2) pin 2

The code

The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.

sketch.ino · Arduino Uno R3
// Night lamp: a real light sensor fades a lamp up when the room goes dark.
//
//   A0     the middle of the divider: 5 V, the LDR, A0, 10k, GND
//   pin 9  the lamp, through 220 ohm to GND
//   pin 8  the indicator, through 220 ohm to GND
//
// The light-dependent resistor and the fixed 10k make a divider, and A0 reads
// the middle of it. Light on the cell drops its resistance, so the middle goes
// up: a bright room reads high and a covered cell reads low. That is the whole
// sensor, and it is why an LDR always comes with a resistor.
//
// # The threshold, and why there are two of them
//
// One threshold gives a lamp that flutters on and off while the light sits on
// it. Two (switch on below DARK, switch off above LIGHT, and do nothing in
// between) is hysteresis, and it is what every thermostat, every light
// sensor and every comparator circuit with a bit of feedback does. The gap
// here is about a fifth of the range, which is wide enough that a hand moving
// past the cell does not set it off.
//
// # The fade
//
// Pin 9 is one of the PWM outputs, so analogWrite gives any brightness from 0
// to 255. It walks there rather than jumping: a night light that snaps on is a
// torch. Eight counts every twenty milliseconds is about six tenths of a second
// end to end, and the indicator on pin 8 follows the sensor instantly, so the
// two disagree for exactly as long as the ramp takes.

const int SENSOR = A0;
const int LAMP = 9;
const int INDICATOR = 8;

// Out of 1023. Below DARK it is night; above LIGHT it is day.
const int DARK = 380;
const int LIGHT = 580;

const int STEP = 8;
const int FULL = 255;

int level = 0;
bool night = false;
int said = -1;

void setup() {
  pinMode(LAMP, OUTPUT);
  pinMode(INDICATOR, OUTPUT);
  analogWrite(LAMP, 0);
  Serial.begin(115200);
  Serial.println("Mokxi Arduino Uno: night lamp");
  Serial.println("drag the slider on the LDR to change the light in the room");
}

void loop() {
  int light = analogRead(SENSOR);

  // Two thresholds with a gap between them, so the lamp does not flutter.
  if (!night && light < DARK) {
    night = true;
  } else if (night && light > LIGHT) {
    night = false;
  }
  digitalWrite(INDICATOR, night ? HIGH : LOW);

  int want = night ? FULL : 0;
  if (level < want) {
    level += STEP;
    if (level > want) {
      level = want;
    }
  } else if (level > want) {
    level -= STEP;
    if (level < want) {
      level = want;
    }
  }
  analogWrite(LAMP, level);

  if (level == want && level != said) {
    said = level;
    Serial.print(night ? "dark (" : "light (");
    Serial.print(light);
    Serial.print("): lamp at ");
    Serial.println(level);
  }

  delay(20);
}

Code walkthrough

The key functions of the sketch, and what each one does.

setup sketch.ino

Sets the lamp and indicator pins as outputs, makes sure the lamp starts off, and opens serial at 115200 with two hint lines.

void setup() {
  pinMode(LAMP, OUTPUT);
  pinMode(INDICATOR, OUTPUT);
  analogWrite(LAMP, 0);
  Serial.begin(115200);
  Serial.println("Mokxi Arduino Uno: night lamp");
  Serial.println("drag the slider on the LDR to change the light in the room");
}

loop sketch.ino

Reads the light, then updates night using DARK and LIGHT so it changes only when crossing the far threshold. It sets the indicator, then steps level toward 255 or 0 by STEP and writes it to the lamp. When the fade finishes, it prints the reading and the lamp level once. A 20 ms wait ends each pass.

void loop() {
  int light = analogRead(SENSOR);

  // Two thresholds with a gap between them, so the lamp does not flutter.
  if (!night && light < DARK) {
    night = true;
  } else if (night && light > LIGHT) {
    night = false;
  }
  digitalWrite(INDICATOR, night ? HIGH : LOW);

  int want = night ? FULL : 0;
  if (level < want) {
    level += STEP;
    if (level > want) {
      level = want;
    }
  } else if (level > want) {
    level -= STEP;
    if (level < want) {
      level = want;
    }
  }
  analogWrite(LAMP, level);

  if (level == want && level != said) {
    said = level;
    Serial.print(night ? "dark (" : "light (");
  // ... 7 more lines in the editor

Troubleshooting

The usual mistakes with this circuit, and the fix for each.

  • The lamp never turns on This project
    Check the divider: 5 V, the sensor, A0, the 10k resistor, ground. The reading must drop below DARK, 380.
  • The lamp turns on and off at the wrong light level This project
    Adjust DARK and LIGHT. Keep a gap between them.
  • The reading barely changes, or sits stuck near 0 or the top of the range. Light sensor
    An LDR is a resistor, so use it in a divider with a fixed resistor, about 10k, and read the middle node. Without the divider the analog pin sees nothing useful.
  • Readings go the wrong way: higher in the dark. Light sensor
    Which side the LDR sits on decides the direction. LDR on the supply side gives a higher reading in the light. LDR on the ground side gives a lower reading in the light. Swap them if needed.
  • The LED is dim, burns out, or the pin reads wrong because the resistor value is off. Resistor
    Read the color bands again. A 220 ohm to 330 ohm resistor suits a typical LED on 5 V. 10k is a common pull-up or pull-down value. Check with a multimeter if unsure.
  • A pull-up or pull-down resistor is missing, so the input floats and reads random values. Resistor
    Tie the input to 5 V or ground through about 10k. Or use INPUT_PULLUP and wire the switch to ground.
  • The LED does not light, or it lights once and then dies. LED
    LEDs have polarity. The longer leg (anode) goes toward the positive side. Always add a series resistor, about 220 ohms to 1 k ohm on a 5 V pin.
  • A blue or white LED stays dark on 3.3 V. LED
    Blue and white LEDs drop about 3 V, so 3.3 V leaves almost nothing for the resistor. Use a 5 V supply, or a smaller resistor and a red or green LED.

Change it and keep it

Open it in the editor, change the circuit or the code, and keep your version in a free account.