#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>
#include <RTClib.h>
// Pin configuration
#define DHTPIN 2
#define MQ2PIN 8 // Digital pin for MQ2 sensor
#define BUZZERPIN 3
#define BUTTON1PIN 4
#define BUTTON2PIN 5
#define BUTTON3PIN 6
// DHT setup
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
// LCD setup
LiquidCrystal_I2C lcd(0x27, 20, 4); // Adjust the address if needed
// RTC setup
RTC_DS3231 rtc;
// Thresholds
const int temperatureThresholds[] = {80, 85, 95}; // Example thresholds, replace as needed
const int MQ2Threshold = 500;
// Variables
int currentPage = 1;
unsigned long lastButtonPress = 0;
const unsigned long debounceDelay = 200;
bool buzzerActive = false;
bool buzzerMQ2Active = false;
unsigned long buzzerStartTime = 0;
int currentThresholdIndex = 0;
unsigned long lastHourlyBeep = 0;
// Cached sensor values to reduce unnecessary updates
float cachedTemperature = NAN;
float cachedHumidity = NAN;
int cachedMQ2Value = -1;
DateTime cachedTime;
// Function declarations
void updateDisplay(float temperature = NAN, float humidity = NAN, int mq2Value = -1);
void togglePage();
void manageBuzzer(float temperature, int mq2Value);
void checkHourlyBeep();
void scrollPresets();
bool detectSensor(int pin);
bool checkAndUpdate(float& cache, float newValue);
bool checkAndUpdate(int& cache, int newValue);
bool checkAndUpdate(DateTime& cache, DateTime newValue);
String formatTime12Hour(DateTime now);
void displayWelcomeMessage();
// Setup function
void setup() {
// Initialize the LCD
lcd.begin(20, 4); // Specify the number of columns and rows
lcd.backlight(); // Turn on the backlight
// Initialize the DHT sensor
dht.begin();
// Initialize the RTC
if (!rtc.begin()) {
lcd.print("RTC failed");
while (1);
}
// Set pin modes
pinMode(MQ2PIN, INPUT);
pinMode(BUZZERPIN, OUTPUT);
pinMode(BUTTON1PIN, INPUT_PULLUP);
pinMode(BUTTON2PIN, INPUT_PULLUP);
pinMode(BUTTON3PIN, INPUT_PULLUP);
// Display welcome message
displayWelcomeMessage();
// Display initial page
updateDisplay();
}
void loop() {
// Read button states
if (digitalRead(BUTTON1PIN) == LOW) {
delay(debounceDelay); // Debounce delay
if (digitalRead(BUTTON1PIN) == LOW) {
tone(BUZZERPIN, 250); // Sound buzzer for 0.5 seconds
delay(500);
noTone(BUZZERPIN);
togglePage();
}
}
if (digitalRead(BUTTON2PIN) == LOW) {
delay(debounceDelay); // Debounce delay
if (digitalRead(BUTTON2PIN) == LOW) {
tone(BUZZERPIN, 250); // Sound buzzer for 0.5 seconds
delay(500);
noTone(BUZZERPIN);
lcd.clear(); // Clear the display
}
}
if (digitalRead(BUTTON3PIN) == LOW) {
delay(debounceDelay); // Debounce delay
if (digitalRead(BUTTON3PIN) == LOW) {
tone(BUZZERPIN, 250); // Sound buzzer for 0.5 seconds
delay(500);
noTone(BUZZERPIN);
scrollPresets(); // Scroll through presets
}
}
// Read sensors
float temperature = dht.readTemperature(true); // Temperature in Fahrenheit
float humidity = dht.readHumidity();
int mq2Value = digitalRead(MQ2PIN);
// Check if sensor values have changed
bool tempChanged = checkAndUpdate(cachedTemperature, temperature);
bool humidityChanged = checkAndUpdate(cachedHumidity, humidity);
bool mq2Changed = checkAndUpdate(cachedMQ2Value, mq2Value);
bool timeChanged = checkAndUpdate(cachedTime, rtc.now());
// Update display only if values have changed
if (tempChanged || humidityChanged || mq2Changed || timeChanged) {
updateDisplay(cachedTemperature, cachedHumidity, cachedMQ2Value);
}
// Check thresholds and manage buzzer
manageBuzzer(cachedTemperature, cachedMQ2Value);
// Check hourly beep
checkHourlyBeep();
delay(500); // Update every 0.5 seconds
}
void togglePage() {
currentPage = (currentPage == 1) ? 2 : 1;
lcd.clear(); // Clear the display to avoid overlapping content
updateDisplay(); // Update display based on the new page
}
void manageBuzzer(float temperature, int mq2Value) {
unsigned long currentTime = millis();
if (temperature > temperatureThresholds[currentThresholdIndex]) {
if (!buzzerActive) {
buzzerActive = true;
buzzerStartTime = currentTime;
}
if (buzzerActive && (currentTime - buzzerStartTime >= 1000)) {
tone(BUZZERPIN, 1000); // 1 kHz frequency
delay(1000); // Buzzer on for 1 second
noTone(BUZZERPIN);
delay(4000); // Wait for 4 seconds
buzzerStartTime = millis(); // Reset buzzer start time
}
} else {
noTone(BUZZERPIN);
buzzerActive = false;
}
if (mq2Value > MQ2Threshold) {
if (!buzzerMQ2Active) {
buzzerMQ2Active = true;
buzzerStartTime = currentTime;
}
if (buzzerMQ2Active && (currentTime - buzzerStartTime >= 1500)) {
tone(BUZZERPIN, 1000); // 1 kHz frequency
delay(1500); // Buzzer on for 1.5 seconds
noTone(BUZZERPIN);
delay(3500); // Wait for 3.5 seconds
buzzerStartTime = millis(); // Reset buzzer start time
}
} else {
noTone(BUZZERPIN);
buzzerMQ2Active = false;
}
}
void checkHourlyBeep() {
DateTime now = rtc.now();
unsigned long currentTime = millis();
if (now.minute() == 0 && now.second() == 0) { // On the hour
if (currentTime - lastHourlyBeep >= 3600000) { // 1 hour in milliseconds
tone(BUZZERPIN, 1000); // Beep for 0.75 seconds
delay(750);
noTone(BUZZERPIN);
lastHourlyBeep = currentTime; // Update the last beep time
}
}
}
void updateDisplay(float temperature, float humidity, int mq2Value) {
DateTime now = rtc.now();
if (currentPage == 1) {
lcd.setCursor(0, 0);
lcd.print("Temp: ");
if (isnan(temperature)) {
lcd.print("NA");
} else {
lcd.print(temperature);
lcd.print(" F ");
}
lcd.setCursor(0, 1);
lcd.print("Humidity: ");
if (isnan(humidity)) {
lcd.print("NA ");
} else {
lcd.print(humidity);
lcd.print(" % ");
}
lcd.setCursor(0, 2);
lcd.print("MQ2 Value: ");
if (mq2Value == LOW) {
lcd.print("NA");
} else {
lcd.print(mq2Value);
lcd.print(" ");
}
lcd.setCursor(0, 3);
lcd.print("Time: ");
lcd.print(formatTime12Hour(now));
} else if (currentPage == 2) {
lcd.setCursor(0, 0);
lcd.print("Time: ");
lcd.print(formatTime12Hour(now));
lcd.setCursor(0, 1);
lcd.print("Date: ");
lcd.print(now.month());
lcd.print("/");
lcd.print(now.day());
lcd.print("/");
lcd.print(now.year());
lcd.setCursor(0, 2);
lcd.print("Preset Temp: ");
lcd.print(temperatureThresholds[currentThresholdIndex]);
lcd.setCursor(0, 3);
lcd.print("Temp: ");
if (isnan(temperature)) {
lcd.print("NA");
} else {
lcd.print(temperature);
lcd.print(" F");
}
}
}
String formatTime12Hour(DateTime now) {
String period = "AM";
int hour = now.hour();
if (hour >= 12) {
period = "PM";
if (hour > 12) {
hour -= 12;
}
} else if (hour == 0) {
hour = 12;
}
String formattedTime = String(hour) + ":" + String(now.minute()) + " " + period;
return formattedTime;
}
void scrollPresets() {
currentThresholdIndex = (currentThresholdIndex + 1) % (sizeof(temperatureThresholds) / sizeof(temperatureThresholds[0]));
updateDisplay(cachedTemperature, cachedHumidity, cachedMQ2Value);
}
bool detectSensor(int pin) {
return digitalRead(pin) != LOW; // Adjust according to your sensor's logic
}
bool checkAndUpdate(float& cache, float newValue) {
if (cache != newValue) {
cache = newValue;
return true;
}
return false;
}
bool checkAndUpdate(int& cache, int newValue) {
if (cache != newValue) {
cache = newValue;
return true;
}
return false;
}
bool checkAndUpdate(DateTime& cache, DateTime newValue) {
if (cache.unixtime() != newValue.unixtime()) {
cache = newValue;
return true;
}
return false;
}
void displayWelcomeMessage() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Welcome to your");
lcd.setCursor(0, 1);
lcd.print("Smart 3D Enclose");
lcd.setCursor(0, 2);
lcd.print("Version 1.0.0");
delay(5000); // Display for 5 seconds
lcd.clear();
}