Build a colour-changing night lamp

A night lamp with four modes, chosen with a button: off, warm light, a slow rainbow, and automatic, which switches on by itself when the room gets dark.
  • Level:Beginner
  • Duration: 40 min
  • Ages 10+
  • Platform: Arduino

Tools for this lesson

Helpful for this build. Open a tool to see tips and more projects that use it.

Build a colour-changing night lamp – EEMENTOR STEM™ lesson

A good night lamp is soft, never harsh, and only on when you need it. In this lesson you build one with the RGB LED module, a photoresistor and a button. Each press of the button switches to the next mode: off, warm light, a slow rainbow, and automatic, which fades the warm light in when the room gets dark and out again in the morning.

What you'll learn

  • How to cycle through modes with one button
  • How to fade light smoothly without stopping the program
  • How to use a photoresistor with two limits so the lamp doesn't flicker
  • How to mix a warm white from red, green and blue

What you need

  • UNO R3 board and USB cable (UNO R3 Starter Kit)
  • RGB LED module (45-in-1 Sensor Kit)
  • Photoresistor module (45-in-1 Sensor Kit)
  • Button module (45-in-1 Sensor Kit)
  • 3 resistors, 220 Ω (UNO R3 Starter Kit)
  • A sheet of baking paper or a white plastic cup as a shade
  • Breadboard and jumper wires (UNO R3 Starter Kit)

Make it real: put an upside-down white plastic cup or a tube of baking paper over the RGB LED. It softens the light, so you see one glowing colour instead of three bright dots.

Wiring

Breadboard wiring diagram: Build a colour-changing night lamp
Breadboard view. Check each connection against the wiring table below.
From Through To
UNO pin 9 220 Ω resistor RGB module R
UNO pin 10 220 Ω resistor RGB module G
UNO pin 11 220 Ω resistor RGB module B
RGB module − GND
Photoresistor module S UNO pin A0
Photoresistor module + and − 5V and GND
Button module S UNO pin 2
Button module + and − 5V and GND

Sensor modules from different makers can label and order their pins differently. Always follow the labels printed on your module.

Keep the photoresistor away from the lamp itself, or the lamp will see its own light and switch off again.

The sketch

const int RED_PIN = 9;
const int GREEN_PIN = 10;
const int BLUE_PIN = 11;
const int LIGHT_PIN = A0;
const int BUTTON_PIN = 2;

const int DARK_BELOW = 25;     // automatic mode: on below this light level (%)
const int BRIGHT_ABOVE = 40;   // ... and off again above this one

const byte OFF = 0, WARM = 1, RAINBOW = 2, AUTO = 3;
const char* const MODE_NAMES[] = {"off", "warm", "rainbow", "automatic"};
byte mode = WARM;
int buttonRest;
float level = 0;               // current brightness, 0.0 ... 1.0, for smooth fading
bool autoOn = false;

void setColour(int r, int g, int b, float brightness) {
  analogWrite(RED_PIN, r * brightness);
  analogWrite(GREEN_PIN, g * brightness);
  analogWrite(BLUE_PIN, b * brightness);
}

void rainbow(float brightness) {
  float t = millis() / 4000.0;                     // one full cycle every ~25 s
  int r = 127 + 127 * sin(t);
  int g = 127 + 127 * sin(t + 2.09);
  int b = 127 + 127 * sin(t + 4.19);
  setColour(r, g, b, brightness);
}

void setup() {
  Serial.begin(9600);
  pinMode(RED_PIN, OUTPUT);
  pinMode(GREEN_PIN, OUTPUT);
  pinMode(BLUE_PIN, OUTPUT);
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  buttonRest = digitalRead(BUTTON_PIN);           // works with modules that idle HIGH or LOW
}

void loop() {
  if (digitalRead(BUTTON_PIN) != buttonRest) {     // next mode
    mode = (mode + 1) % 4;
    Serial.print("Mode: ");
    Serial.println(MODE_NAMES[mode]);
    while (digitalRead(BUTTON_PIN) != buttonRest) delay(10);
    delay(50);
  }

  int light = map(analogRead(LIGHT_PIN), 0, 1023, 0, 100);     // bright = high %
  if (light < DARK_BELOW) autoOn = true;
  if (light > BRIGHT_ABOVE) autoOn = false;

  float target = 0;
  if (mode == WARM || mode == RAINBOW) target = 1.0;
  if (mode == AUTO && autoOn) target = 0.6;
  level += (target - level) * 0.03;                // fade a little closer every loop

  if (mode == RAINBOW) rainbow(level);
  else setColour(255, 120, 30, level);             // warm white
  delay(20);
}

How it works

The lamp has four modes, numbered 0 to 3. Each button press adds one, and % 4 brings it back to 0 after the last one. The sketch waits until the button is released before going on, so one press moves exactly one mode.

Instead of jumping on and off, the lamp fades. Every 20 ms, level moves 3 % of the way towards the brightness the current mode wants. That gives a soft fade of about two seconds, and it works in every mode without any extra code.

Automatic mode uses two limits. It switches on when the light falls below 25 % but only switches off when it rises above 40 %. With a single limit, a light level hovering around it would make the lamp flicker; the gap between the limits, called hysteresis, prevents that. The rainbow uses three sine waves, a third of a circle apart, for red, green and blue, which slide smoothly through every colour.

Try this next

  • Add a "candle" mode that flickers the warm light a little at random.
  • Remember the last mode in EEPROM so the lamp starts in it after a power cut.
  • Switch the lamp off by itself after one hour in warm mode.

Troubleshooting

  • Automatic mode flickers or never switches on: print light in the Serial Monitor and adjust the two limits for your room.
  • The mode changes by itself: check the button wire on pin 2.
  • The warm light looks pink or green: LEDs differ. Change the numbers in setColour(255, 120, 30, …) until it looks warm white.
  • The light value is the wrong way round: swap 0, 100 to 100, 0 in the light line.

Build it yourself

Everything used in this lesson comes in one kit, with parts tested by our engineers.

UNO R3 Starter Kit | Arduino IDE Compatible | Free Tutorials $56.00

Shop the kit