Concept
For this project, I tried to build a simple lighting system using an LDR (light sensor), a push-button, and two LEDs. One LED changes brightness depending on how bright the room is, and the other lights up to show when I’ve manually taken control.
I wanted to manually override the automatic light control with the press of a button—so if I want the light to stay at a fixed brightness no matter how bright it is outside, I just hit the button. Press it again, and the automatic behavior comes back.
I used TinkerCad for the circuit simulation.
Video
How It Works
-
-
The LDR is connected to pin A0 and tells the Arduino how bright the environment is.
-
Based on this reading, the Arduino maps the value to a number between 0 and 255 (for LED brightness).
-
The LED on pin 9 gets brighter when it’s dark and dims when it’s bright—automatically.
-
I also wired a button to pin 2. When I press it, the system switches to manual mod
-
In this mode, the LED stays at medium brightness, no matter the light level.
-
An indicator LED on pin 13 lights up to let me know I’m in manual mode.
-
-
Pressing the button again switches back to automatic mode.
-
Code
// Pin Definitions const int ldrPin = A0; // LDR sensor connected to A0 const int buttonPin = 2; // Push-button connected to digital pin D2 const int pwmLedPin = 9; // PWM LED for the ambient light effect const int overrideLedPin = 13; // Digital LED for manual override indicator // Variables bool manualOverride = false; // Tracks if the override mode is active int lastButtonState = LOW; // With external pull-down, default is LOW unsigned long lastDebounceTime = 0; const unsigned long debounceDelay = 50; // Debounce time in milliseconds void setup() { pinMode(ldrPin, INPUT); pinMode(buttonPin, INPUT); pinMode(pwmLedPin, OUTPUT); pinMode(overrideLedPin, OUTPUT); // Start with manual override off, LED off digitalWrite(overrideLedPin, LOW); Serial.begin(9600); } void loop() { // Read the LDR Sensor int ldrValue = analogRead(ldrPin); // Map the LDR value to PWM brightness (0-255). // Darker environment (low ldrValue) yields a higher brightness. int pwmValue = map(ldrValue, 0, 1023, 255, 0); // Handle the Push-Button for Manual Override with Debouncing int reading = digitalRead(buttonPin); if (reading != lastButtonState) { lastDebounceTime = millis(); } if ((millis() - lastDebounceTime) > debounceDelay) { //Unpressed = LOW, pressed = HIGH. if (reading == HIGH && lastButtonState == LOW) { // button press detected manualOverride = !manualOverride; // Update the indicator LED accordingly digitalWrite(overrideLedPin, manualOverride ? HIGH : LOW); } } lastButtonState = reading; // LED Behavior Based on Mode if (manualOverride) { // In manual override mode, set LED to a fixed brightness. analogWrite(pwmLedPin, 128); } else { // Set brightness according to ambient light measured by the LDR. analogWrite(pwmLedPin, pwmValue); } // Debug output Serial.print("LDR Value: "); Serial.print(ldrValue); Serial.print(" | PWM Brightness: "); Serial.print(pwmValue); Serial.print(" | Manual Override: "); Serial.println(manualOverride ? "ON" : "OFF"); delay(10); }
Challenges
-
-
Balancing Automatic and Manual Modes:
Getting the right balance between automatic brightness adjustments and a satisfying manual override was a fun challenge. I had to fine-tune the mapping of LDR readings to PWM values until the LED’s response felt right in different lighting conditions. -
Debugging with Serial Monitor:
Utilizing the Serial Monitor was incredibly useful. Every time something wasn’t working as expected, I added more Serial prints to understand what was happening.
-