/*
================================================================================
Project: Smart Night Light
Author: Jordan Craig
Date: 20/11/24
ENGR 2200
================================================================================
This project implements a smart night light system using an Arduino, a photoresistor,
an LED, an LCD display, and two buttons (system on/off and timer). The system
functions as follows:
1. **Automatic LED Control**:
- The LED automatically turns on when the ambient light level drops below a
predefined threshold (indicating a dark room).
- The LED turns off when the ambient light level exceeds the threshold.
2. **Fade Effect**:
- The LED brightness changes smoothly with a fade effect when turning on or off.
3. **System On/Off Control**:
- A push button is used to toggle the entire system on or off.
- When the system is off, all operations (LED control, timer, etc.) stop, and
the LCD displays "Night Light OFF".
4. **Timer Functionality**:
- A separate push button is used to activate a 5-minute timer.
- When the timer is activated, the system stops other operations and displays the
countdown on the LCD in minutes and seconds format.
- The timer can be canceled by pressing the timer button again.
This night light is designed to be used in bedrooms, where the light would turn on automatically,
depending on if the lights are on or off in the room.
================================================================================
*/
#include <LiquidCrystal.h> //Library allows connection to the LCD
// Initialize the LCD with pin connections
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
// Pin connections
const int photoresistorPin = A0; // Pin connected to the photoresistor
const int ledPin = 9; // Pin connected to the LED
const int buttonPin = 12; // Pin connected to the on/off button
const int timerButtonPin = 13; // Pin connected to the timer button
// Threshold and delay values
const int lightThreshold = 400; // Threshold for turning the LED on
const int fadeDelay = 5; // Delay for fade effect
const unsigned long timerDuration = 300000; // 5 minutes in milliseconds (300,000 ms)
// State tracking variables
bool isSystemOn = false; // System starts in "off" state
bool timerActivated = false; // Flag to check if timer is activated
int currentBrightness = 0; // Track the current LED brightness
unsigned long timerStartTime = 0; // Timer start time
void setup() {
lcd.begin(16, 2); // Set LCD dimensions (16 columns, 2 rows)
pinMode(photoresistorPin, INPUT); //set photoresistor pin (A0) to input
pinMode(ledPin, OUTPUT); //set LED pin connection (pin 9) to output
pinMode(buttonPin, INPUT_PULLUP); // Use internal pull-up for button
pinMode(timerButtonPin, INPUT_PULLUP); // Timer button input with pull-up
Serial.begin(9600); // Initialize Serial Monitor for debugging
}
void fadeLED(int targetBrightness) { //fadeLED function
if (targetBrightness > currentBrightness) { //if the target brightness is more than the current LED brightness
// Fade in
for (int brightness = currentBrightness; brightness <= targetBrightness; brightness++) { //increase the LED brightness until fully illuminated
analogWrite(ledPin, brightness);
delay(fadeDelay); //short delay in between each increase in brightness level
}
} else {
// Fade out
for (int brightness = currentBrightness; brightness >= targetBrightness; brightness--) { //decrease the LED brightness until fully off
analogWrite(ledPin, brightness);
delay(fadeDelay); //short delay in between each decrease in brightness level
}
}
currentBrightness = targetBrightness; //set current brightness as target brightness once complete
}
void controlLED(int lightLevel) { //controlLED function
if (lightLevel < lightThreshold) { //if the light level in the room is less than pre-determined light threshold
fadeLED(255); // Turn LED on when room is dark
} else {
fadeLED(0); // Turn LED off when room is light
}
}
void displayStatus() { //displayStatus function which displays text on the LCD
int lightLevel = analogRead(photoresistorPin); //assign the lgiht level value read by the photoresistor to the lightLevel variable as an integer value
Serial.print("Detected Light Level: "); //display "Detected Light Level: " in the serial monitor for debugging
Serial.println(lightLevel); //displays light level read by photoresistor
lcd.clear(); //clear the LCD screen
lcd.setCursor(0, 0); //reset the LCD cursor
lcd.print("Light Level: "); // display "Light Level: " on the screen
lcd.print(lightLevel); //displays light level read by photoresistor
}
void toggleSystem() { //system on function. default state is that the system is off.
if (digitalRead(buttonPin) == LOW) { //if the button is pressed, system is on
delay(50); // Debounce delay
if (digitalRead(buttonPin) == LOW) { //if button pressed again, turn system off
isSystemOn = !isSystemOn;
while (digitalRead(buttonPin) == LOW); // Wait for button release
}
}
}
void startOrCancelTimer() { //timer function
if (digitalRead(timerButtonPin) == LOW) { //if button is pressed, turn timer on
delay(50); // Debounce delay
if (digitalRead(timerButtonPin) == LOW) { //if the button is pressed again
if (timerActivated) {
// If the timer is already running, cancel it
timerActivated = false;
lcd.clear(); //clear LCD
lcd.setCursor(0, 0); //reset LCD cursor
lcd.print("Timer Canceled"); //display "Timer Canceled" on LCD
delay(1000); // Show "Timer Canceled" for a second
} else {
// If the timer is not running, start it
timerActivated = true;
timerStartTime = millis(); // Record the time when button is pressed
lcd.clear(); //clear LCD
lcd.setCursor(0, 0); //reset LCD cursor
lcd.print("Timer Started"); //display "Timer Started" on LCD
}
while (digitalRead(timerButtonPin) == LOW); // Wait for button release
}
}
}
void displayTimerCountdown(unsigned long remainingTime) { //display the remaining seconds of timer on LCD as Minutes and Seconds (ex: 3:38)
// Calculate minutes and seconds
unsigned long minutes = remainingTime / 60000; // Minutes are the total milliseconds divided by 60000 (milliseconds in a minute)
unsigned long seconds = (remainingTime % 60000) / 1000; // Seconds are the remaining milliseconds divided by 1000
// Clear LCD and display the remaining time
lcd.clear();
lcd.print("Timer: ");
lcd.print(minutes); // Display minutes
lcd.print(":");
if (seconds < 10) {
lcd.print("0"); // Display leading zero for seconds if less than 10
}
lcd.print(seconds); // Display seconds
}
void checkTimer() { //check if timer working function
if (timerActivated) { //if the timer has been activated
unsigned long elapsedTime = millis() - timerStartTime;
displayTimerCountdown(timerDuration - elapsedTime); // Display remaining time in minutes and seconds
if (elapsedTime >= timerDuration) { //if the time elapsed if longer than the duration of time the timer was set for
timerActivated = false; // Reset the timer state
lcd.clear(); //clear LCD
lcd.setCursor(0, 0); //reset the LCD cursor
lcd.print("Timer Done"); //diaplay "Timer Done" on screen
delay(1000); // Wait for a moment before resuming
}
}
}
void loop() {
toggleSystem(); // Handle system on/off toggle button
startOrCancelTimer(); // Handle timer button (start or cancel)
if (timerActivated) { //if the timer is pressed
// Stop all activities and only display the timer countdown
checkTimer(); // Display timer countdown and handle timer
} else {
// Normal operation when the system is on and no timer is running
if (isSystemOn) { //if the system is turned on
displayStatus(); // Display light level and battery
controlLED(analogRead(photoresistorPin)); // Ensure the LED is being controlled based on light level
} else {
analogWrite(ledPin, 0); // Ensure LED is off
lcd.clear(); //clear LCD
lcd.print("Night Light OFF"); //display "Night Light off" on LCD
}
}
delay(500); // Wait before checking again
}