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

| 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
lightin 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, 100to100, 0in the light line.