#include <Arduino.h>
#include <DHT.h>
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Encoder.h>
#include <stdio.h>
#define DHTPIN 2 // Digital pin connected to the DHT sensor
#define DHTTYPE DHT22 // DHT22 sensor
#define LEDPIN_green 9 // Green LED pin
#define LEDPIN_red 8 // Red LED pin
#define pinCS 4 // Chip select pin for the SD card module
#define LDRPIN A0 // LDR sensor pin
#define pinA 6 // Encoder pin A
#define pinB 5 // Encoder pin B
// #define BUTTON_PIN A3
// #define BUTTON_PIN A3
DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 20, 4); // Initialize the LCD
Encoder myEnc(pinA, pinB); // Initialize the encoder
Encoder Enc(pinA, pinB); // Initialize the encoder
struct ModeInfo {
String modeName;
int minTemp, maxTemp, minHum, maxHum;
};
float minT = 1000, maxT = -1000, minH = 1000, maxH = -1000; // Min and Max values
#define BUTTON_EDIT_MODE A2
#define BUTTON_EXIT_EDIT_MODE A3
// Variable to track editable mode
bool inEditableMode = false;
static unsigned long lastPressTime = 0;
static bool lastButtonState = LOW; // Track the last button state
const unsigned long debounceTime = 200; // Debounce time in milliseconds
ModeInfo modes[4]; // Array to store the mode data
int currentModeIndex = 0; // Index of the currently selected mode
long oldPosition = -999; // Previous position of the encoder
bool isNight = false; // Current mode flag
unsigned long lastTransitionTime = millis(); // Time of the last transition
unsigned long lastNightDuration = 0, lastDayDuration = 0;
unsigned long previousMillis = 0;
const long interval = 60000;
enum EditState {
EDIT_NONE,
EDIT_TEMP_MIN,
EDIT_TEMP_MAX,
EDIT_HUM_MIN,
EDIT_HUM_MAX
};
EditState currentEditState = EDIT_NONE;
void displayMinMaxValues() {
lcd.setCursor(0, 2);
lcd.print("T:" + String(minT) + "/" + String(maxT) + (char)223 + "C");
lcd.setCursor(0, 3);
lcd.print("H:" + String(minH) + "/" + String(maxH) + "%");
}
float parseValue(String line, String prefix, char suffix) {
int startIndex = line.indexOf(prefix);
if (startIndex != -1) {
startIndex += prefix.length();
int endIndex = line.indexOf(suffix, startIndex);
return line.substring(startIndex, endIndex).toFloat();
}
return NAN;
}
void readMinMaxValues(const char *filename) {
File data = SD.open(filename);
if (data) {
while (data.available()) {
String line = data.readStringUntil('\n');
float temp = parseValue(line, "Temperature: ", '°');
float hum = parseValue(line, "Humidity: ", '%');
minT = min(minT, temp);
maxT = max(maxT, temp);
minH = min(minH, hum);
maxH = max(maxH, hum);
}
data.close();
displayMinMaxValues();
} else {
Serial.println("Error opening data.txt");
}
}
String formatDuration(unsigned long duration) {
unsigned long hours = duration / 3600000;
unsigned long mins = (duration / 60000) % 60;
return String(hours) + "h:" + String(mins) + "m";
}
void displayDuration() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Day: " + formatDuration(lastDayDuration));
lcd.setCursor(0, 1);
lcd.print("Night: " + formatDuration(lastNightDuration));
}
void displayModeDetails(int index) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Mode: " + modes[index].modeName);
readMinMaxValues("data.txt");
}
void handleModeDisplayAndControl() {
int ldrValue = analogRead(LDRPIN);
// Serial.println(ldrValue);
bool newNight = ldrValue > 650;
if (newNight != isNight) {
unsigned long duration = millis() - lastTransitionTime;
if (isNight) {
lastNightDuration = duration;
} else {
lastDayDuration = duration;
}
lastTransitionTime = millis();
isNight = newNight;
displayDuration();
}
if (!isNight) {
long newPosition = myEnc.read() / 4;
if (newPosition != oldPosition) {
oldPosition = newPosition;
currentModeIndex = abs(newPosition) % 4;
displayModeDetails(currentModeIndex);
}
} else {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Night Mode");
readMinMaxValues("data.txt");
}
}
void parseModeLine(String line, ModeInfo &mode) {
int firstSpace = line.indexOf(' ');
int secondSpace = line.indexOf(' ', firstSpace + 1);
int thirdSpace = line.indexOf(' ', secondSpace + 1);
int fourthSpace = line.indexOf(' ', thirdSpace + 1);
mode.modeName = line.substring(0, firstSpace);
mode.minTemp = line.substring(firstSpace + 1, secondSpace).toInt();
mode.maxTemp = line.substring(secondSpace + 1, thirdSpace).toInt();
mode.minHum = line.substring(thirdSpace + 1, fourthSpace).toInt();
mode.maxHum = line.substring(fourthSpace + 1).toInt();
}
void readModesFromSD(const char* filename) {
Serial.println("Reading modes from setup function");
File file = SD.open(filename);
if (file) {
int index = 0;
while (file.available() && index < 4) {
String line = file.readStringUntil('\n');
parseModeLine(line, modes[index++]);
}
file.close();
} else {
Serial.println("Error opening modes.txt");
}
}
void logDataToSD(float h, float t) {
File File = SD.open("data.txt", FILE_WRITE);
if (File) {
File.print("Humidity: ");
File.print(h);
File.print("% Temperature: ");
File.print(t);
File.println("°C");
File.close();
Serial.println("Data logged to SD card.");
} else {
Serial.println("Error opening data.txt while data logging");
}
}
void displayCurrentSettings() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Editing: ");
switch (currentEditState) {
case EDIT_TEMP_MIN:
lcd.print("Temp Min: ");
lcd.print(modes[currentModeIndex].minTemp);
break;
case EDIT_TEMP_MAX:
lcd.print("Temp Max: ");
lcd.print(modes[currentModeIndex].maxTemp);
break;
case EDIT_HUM_MIN:
lcd.print("Hum Min: ");
lcd.print(modes[currentModeIndex].minHum);
break;
case EDIT_HUM_MAX:
lcd.print("Hum Max: ");
lcd.print(modes[currentModeIndex].maxHum);
break;
default:
lcd.print("Select Parameter");
break;
}
}
void setup() {
Serial.begin(9600);
lcd.init(); // Initialize the LCD
lcd.backlight(); // Turn on the backlight
dht.begin();
pinMode(LEDPIN_green, OUTPUT);
pinMode(LEDPIN_red, OUTPUT);
pinMode(LDRPIN, INPUT); // Set the LDR pin as input
pinMode(pinCS, OUTPUT);
pinMode(BUTTON_EDIT_MODE, INPUT_PULLUP);
pinMode(BUTTON_EXIT_EDIT_MODE, INPUT_PULLUP);
if (!SD.begin(pinCS)) {
lcd.clear();
lcd.print("SD Init Failed!");
return;
}
readModesFromSD("modes.txt");
}
void editingEachValue(){
int newPosition = Enc.read() / 4;
int encoderLastPosition = 0;
if (newPosition != encoderLastPosition) {
switch (currentEditState) {
case EDIT_TEMP_MIN:
modes[currentModeIndex].minTemp += (newPosition - encoderLastPosition);
break;
case EDIT_TEMP_MAX:
modes[currentModeIndex].maxTemp += (newPosition - encoderLastPosition);
break;
case EDIT_HUM_MIN:
modes[currentModeIndex].minHum += (newPosition - encoderLastPosition);
break;
case EDIT_HUM_MAX:
modes[currentModeIndex].maxHum += (newPosition - encoderLastPosition);
break;
default:
break;
}
displayCurrentSettings();
encoderLastPosition = newPosition;
}
}
void loop() {
// // Reduce sensitivity of encoder
// if (inEditableMode) {
// }
unsigned long currentMillis = millis();
static bool lastEditButtonState = LOW;
static unsigned long lastDebounceTime = 0; // Last time the output pin was toggled
const unsigned long debounceDelay = 200; // Debounce period in milliseconds
if (!inEditableMode) {
float h = dht.readHumidity();
float t = dht.readTemperature();
bool isWithinRange = (t >= modes[currentModeIndex].minTemp && t <= modes[currentModeIndex].maxTemp) &&
(h >= modes[currentModeIndex].minHum && h <= modes[currentModeIndex].maxHum);
digitalWrite(LEDPIN_green, isWithinRange ? HIGH : LOW);
digitalWrite(LEDPIN_red, isWithinRange ? LOW : HIGH);
handleModeDisplayAndControl(); // Only call this when not in editable mode
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
logDataToSD(h, t);
}
}
// if (digitalRead(BUTTON_EDIT_MODE) == LOW && millis() - lastDebounceTime > debounceDelay) {
// lastDebounceTime = millis();
// inEditableMode = true; // Toggle the editable mode
// Serial.println("rying to edit");
// lcd.clear();
// lcd.setCursor(0, 0);
// lcd.print("Editable Mode");
// }
if (digitalRead(BUTTON_EDIT_MODE) == LOW && millis() - lastDebounceTime > debounceDelay) {
lastDebounceTime = millis();
inEditableMode = true;
editingEachValue();
currentEditState = static_cast<EditState>((currentEditState + 1) % 5); // Cycle through edit states
displayCurrentSettings();
Serial.println("Cycling edit mode");
}
bool exitButtonState = digitalRead(BUTTON_EXIT_EDIT_MODE) == LOW;
if (digitalRead(BUTTON_EXIT_EDIT_MODE) == LOW && millis() - lastDebounceTime > debounceDelay) {
lastDebounceTime = millis();
inEditableMode = false; // Exit editable mode
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Normal Mode");
Serial.println("Exiting Edit Mode");
}
delay(100);
}