/****************************Smart Home Environment Monitor****************************/
#include <DHT.h>
#include <LiquidCrystal.h>
#include <ArduinoJson.h>
#include <TimeLib.h>
// Pin Definitions
#define PIR_PIN 13 // PIR motion sensor pin
#define DHT_PIN 12 // DHT sensor data pin
#define LCD_RS 11 // LCD Register Select pin
#define LCD_EN 10 // LCD Enable pin
#define LCD_D4 9 // LCD data pin D4
#define LCD_D5 8 // LCD data pin D5
#define LCD_D6 7 // LCD data pin D6
#define LCD_D7 6 // LCD data pin D7
#define RED_LED_PIN 5 // Red LED pin
#define GREEN_LED_PIN 4 // Green LED pin
#define BLUE_LED_PIN 3 // Blue LED pin
#define BUZZER_PIN 2 // Buzzer pin
#define PHOTORESISTOR_PIN A0 // Photoresistor analog pin
#define BUTTON_PIN A1 // Button pin
// Constants
#define DHT_TYPE DHT22 // DHT sensor type (DHT22)
#define TEMP_HIGH 30 // High temperature threshold in Celsius
#define TEMP_LOW 20 // Low temperature threshold in Celsius
#define DARK_THRESHOLD 300 // Light level threshold for "dark" conditions
#define LCD_UPDATE_INTERVAL 1000 // Interval for updating LCD in milliseconds
#define SERIAL_UPDATE_INTERVAL 10000 // Interval for sending data via serial in milliseconds
#define MOTION_TIMEOUT 30000 // Timeout for detecting no motion (for power-saving) in milliseconds
#define ALARM_DURATION 3000 // Duration for the alarm in milliseconds
#define BUTTON_DEBOUNCE_DELAY 1000 // Debounce delay for the button in milliseconds
// Global variables
DHT dht(DHT_PIN, DHT_TYPE);
LiquidCrystal lcd(LCD_RS, LCD_EN, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
float temperature = 0; // Variable to store temperature
float humidity = 0; // Variable to store humidity
int lightLevel = 0; // Variable to store light level
bool motionDetected = false; // Flag for motion detection
unsigned long lastLCDUpdate = 0; // Timestamp of last LCD update
unsigned long lastSerialUpdate = 0; // Timestamp of last serial data transmission
unsigned long lastMotionTime = 0; // Timestamp of last detected motion
unsigned long alarmStartTime = 0; // Timestamp of alarm start
unsigned long lastButtonPress = 0; // Timestamp of last button press
bool alarmActive = false; // Flag for alarm state
bool lcdBacklightOn = true; // Flag for LCD backlight state
int displayMode = 0; // Current display mode
bool nightMode = false; // Flag for night mode
//Function declarations
void readSensors();
void checkButton();
void updateLCD();
void updateLEDs();
void checkAlarm();
void sendSerialData();
void checkPowerSaving();
void updateNightMode();
String formatTime(time_t );
void setup()
{
Serial.begin(9600);
dht.begin(); // Initialize DHT sensor
lcd.begin(16, 2); // Initialize 16X2 LCD
// Display initial message on LCD
lcd.clear();
lcd.print(" SMART HOME ");
lcd.setCursor(0, 1);
lcd.print(" ENVIRONMENT! ");
lcd.print("Initializing...");
pinMode(PIR_PIN, INPUT);
pinMode(RED_LED_PIN, OUTPUT);
pinMode(GREEN_LED_PIN, OUTPUT);
pinMode(BLUE_LED_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP); // Enable internal pull-up resistor for button
// Set initial time (10:00 PM for testing night mode)
setTime(22, 0, 0, 1, 1, 2024);
delay(2000); // Wait for 2 seconds before starting main loop
lcd.clear(); // Clear LCD after initial message
}
void loop()
{
readSensors(); // Read sensor data
checkAlarm(); // Handle alarm activation and deactivation
checkButton(); // Check button state and handle button press
sendSerialData(); // Send sensor data via serial communication
updateNightMode(); // Update night mode based on time
updateLCD(); // Update LCD with the current data
updateLEDs(); // Update LED states based on temperature
checkPowerSaving(); // Check and handle power-saving mode
updateNightMode(); // Update night mode based on time
}
void readSensors()
{
// Declare the previous values at the beginning of the function
float previous_temperature = temperature;
float previous_humidity = humidity;
int previous_lightLevel = lightLevel;
bool previous_motionDetected = motionDetected;
// Read temperature and humidity from DHT sensor
temperature = dht.readTemperature();
humidity = dht.readHumidity();
// Read light level from photoresistor
lightLevel = analogRead(PHOTORESISTOR_PIN);
// Read motion sensor state
motionDetected = digitalRead(PIR_PIN) == HIGH;
// Error Handling for DHT sensor
if (isnan(temperature) || isnan(humidity))
{
Serial.println("Failed to read from DHT sensor!");
temperature = NAN; // Set to NAN on error
humidity = NAN; // Set to NAN on error
}
// If motion is detected, update the last motion time
if (motionDetected)
{
lastMotionTime = millis();
}
// Check if any of the sensor values have changed, if is so immediately displayed at serial monitor
if (previous_temperature != temperature || previous_humidity != humidity || previous_lightLevel != lightLevel || previous_motionDetected != motionDetected)
{
lastSerialUpdate = 0;
sendSerialData(); // Send updated sensor data
}
}
void checkButton()
{
// Debounced button press handling
if (digitalRead(BUTTON_PIN) == LOW && (millis() - lastButtonPress) > BUTTON_DEBOUNCE_DELAY)
{
displayMode = (displayMode + 1) % 3; // Cycle through 3 display modes
lastButtonPress = millis(); // Update last button press time
}
}
void updateLCD()
{
// Update LCD at regular intervals
unsigned long currentMillis = millis();
if (currentMillis - lastLCDUpdate >= LCD_UPDATE_INTERVAL)
{
lcd.clear();
lcd.setCursor(0, 0);
// Display data based on the current display mode
switch (displayMode)
{
case 0: // Temperature and Humidity
lcd.print("Temp: ");
if (isnan(temperature))
{
lcd.print("Error");
}
else
{
lcd.print(temperature, 1);
lcd.print("C");
}
lcd.setCursor(0, 1);
lcd.print("Humidity: ");
if (isnan(humidity))
{
lcd.print("Error");
}
else
{
lcd.print(humidity, 1);
lcd.print("%");
}
break;
case 1: // Light and Motion
lcd.print("Light: ");
lcd.print(lightLevel);
lcd.setCursor(0, 1);
lcd.print("Motion: ");
lcd.print(motionDetected ? "Detected" : "None");
break;
case 2: // Time and Mode
DateTime now = rtc.now(); // Get current time from RTC
lcd.print("Time: ");
if(now.hour()<10)
lcd.print('0');
lcd.print(now.hour());
lcd.print(':');
if(now.minute()<10)
lcd.print('0');
lcd.print(now.minute());
lcd.print(':');
if(now.second()<10)
lcd.print('0');
lcd.print(now.second());
lcd.setCursor(0, 1);
lcd.print("Mode: ");
lcd.print(nightMode ? "Night" : "Day");
break;
}
lastLCDUpdate = currentMillis; // Update the last LCD update time
}
}
void updateLEDs()
{
// Update LED states based on temperature thresholds
digitalWrite(RED_LED_PIN, temperature > TEMP_HIGH); // Red LED on if temperature is high
digitalWrite(GREEN_LED_PIN, temperature >= TEMP_LOW && temperature <= TEMP_HIGH); // Green LED on if temperature is normal
digitalWrite(BLUE_LED_PIN, temperature < TEMP_LOW); // Blue LED on if temperature is low
}
void checkAlarm()
{
// Activate alarm if motion is detected and it's dark, unless in night mode
if (motionDetected && lightLevel < DARK_THRESHOLD && !alarmActive && !nightMode)
{
alarmActive = true;
alarmStartTime = millis(); // Record the start time of the alarm
tone(BUZZER_PIN, 1000); // Activate buzzer with a 1000 Hz tone
}
// Deactivate alarm after the duration or if night mode is active
if (alarmActive && (millis() - alarmStartTime >= ALARM_DURATION || nightMode))
{
alarmActive = false;
noTone(BUZZER_PIN); // Turn off buzzer
}
}
void sendSerialData()
{
// Send sensor data via serial communication at regular intervals
if (millis() - lastSerialUpdate >= SERIAL_UPDATE_INTERVAL)
{
StaticJsonDocument<200> doc;
doc["temperature"] = temperature;
doc["humidity"] = humidity;
doc["lightLevel"] = lightLevel;
doc["motionDetected"] = motionDetected;
char buffer[200];
serializeJson(doc, buffer);
Serial.println(buffer);
lastSerialUpdate = millis(); // Update last serial transmission time
}
}
void checkPowerSaving()
{
// Check if motion timeout has occurred for power saving
if (millis() - lastMotionTime >= MOTION_TIMEOUT)
{
if (lcdBacklightOn)
{
lcdBacklightOn = false;
lcd.noDisplay(); // Turn off LCD display to save power
}
}
else
{
if (!lcdBacklightOn)
{
lcdBacklightOn = true;
lcd.display(); // Turn on LCD display if motion is detected
}
}
}
void updateNightMode()
{
// Update night mode based on the current time
int currentHour = hour(now());
nightMode = (currentHour >= 22 || currentHour < 6);
}
String formatTime(time_t t)
{
// Format time into a "HH:MM:SS" string
char buffer[9];
sprintf(buffer, "%02d:%02d:%02d", hour(t), minute(t), second(t));
return String(buffer);
}