// seperate value:
#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_INCREMENT_PIN A1
#define BUTTON_DECREMENT_PIN A2
#define BUTTON_NEXT_PIN A3
#define BUTTON_ENCODER_PIN 7
#define BUTTON_EXIT_EDIT_MODE 3
bool isEditableMode = false;
// Parameters for user settings
struct UserSettings {
int minTemp = 0;
int maxTemp = 40;
int minHum = 0;
int maxHum = 100;
} settings;
// Current edit state
enum EditState {
EDIT_MIN_TEMP,
EDIT_MAX_TEMP,
EDIT_MIN_HUM,
EDIT_MAX_HUM,
EDIT_DONE
} currentEditState = EDIT_MIN_TEMP;
// Debouncing
static unsigned long lastDebounceTime = 0;
unsigned long lastButtonPress = 0;
const unsigned long debounceDelay = 200;
// unsigned long encoderDebounceDelay = 200;
DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 20, 4); // Initialize the LCD
Encoder myEnc(pinA, pinB); // Initialize the encoder
#define MAX_MODES 10
struct ModeInfo {
String modeName;
int minTemp, maxTemp, minHum, maxHum;
};
float minT = 1000, maxT = -1000, minH = 1000, maxH = -1000; // Min and Max values
bool doneEditing = false;
// int numberOfModes = 4;
ModeInfo modes[] = {
{"Winter", 0, 15, 0, 30},
{"Germinating", 18, 32, 70, 95},
{"Vegetative", 20, 25, 60, 70},
{"Fruiting", 10, 28, 40, 50},
{"New", settings.minTemp, settings.maxTemp, settings.minHum, settings.maxHum}
};
int numberOfModes = sizeof(modes)/ sizeof(modes[0]) ; // 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;
// String = var;
char var[15] = "Initial Value"; // Array of chars
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) % numberOfModes;
if (currentModeIndex != 4 || modes[currentModeIndex].minTemp != 0){
Serial.println(currentModeIndex);
displayModeDetails(currentModeIndex);
File data = SD.open("data.txt");
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();
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) + "%");
}
}
}
} else {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Night Mode");
// readMinMaxValues("data.txt");
File data = SD.open("data.txt");
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();
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) + "%");
}
}
}
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 readingfile = SD.open(filename);
// // numberOfModes = 0;
// if (readingfile) {
// int index = 0;
// while (readingfile.available()) {
// String line = readingfile.readStringUntil('\n');
// parseModeLine(line, modes[numberOfModes++]);
// }
// readingfile.close();
// } else {
// Serial.println("Error opening modes.txt");
// }
// }
void displayCurrentSetting() {
lcd.clear();
switch (currentEditState) {
case EDIT_MIN_TEMP:
lcd.print("Min Temp: " + String(settings.minTemp) + "C");
break;
case EDIT_MAX_TEMP:
lcd.print("Max Temp: " + String(settings.maxTemp) + "C");
break;
case EDIT_MIN_HUM:
lcd.print("Min Hum: " + String(settings.minHum) + "%");
break;
case EDIT_MAX_HUM:
lcd.print("Max Hum: " + String(settings.maxHum) + "%");
break;
case EDIT_DONE:
Serial.println("inside edit done");
lcd.print("done");
break;
}
}
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 exitEditableMode() {
isEditableMode = false;
// displayNormalMode(); // This function should set the LCD to show normal mode info
Serial.println("Exited editable mode");
}
void moveToNextSetting() {
currentEditState = static_cast<EditState>((currentEditState + 1) % EDIT_DONE);
// displayCurrentSetting();
if (currentEditState == EDIT_DONE) {
// Automatically exit editable mode when done editing
exitEditableMode();
} else {
displayCurrentSetting();
}
}
void incrementSetting() {
switch (currentEditState) {
case EDIT_MIN_TEMP:
if (settings.minTemp < settings.maxTemp) settings.minTemp++;
break;
case EDIT_MAX_TEMP:
if (settings.maxTemp < 40) settings.maxTemp++;
break;
case EDIT_MIN_HUM:
if (settings.minHum < settings.maxHum) settings.minHum++;
break;
case EDIT_MAX_HUM:
if (settings.maxHum < 100) settings.maxHum++;
break;
default:
break;
}
displayCurrentSetting();
}
void decrementSetting() {
switch (currentEditState) {
case EDIT_MIN_TEMP:
if (settings.minTemp > 0) settings.minTemp--;
break;
case EDIT_MAX_TEMP:
if (settings.maxTemp > settings.minTemp) settings.maxTemp--;
break;
case EDIT_MIN_HUM:
if (settings.minHum > 0) settings.minHum--;
break;
case EDIT_MAX_HUM:
if (settings.maxHum > settings.minHum) settings.maxHum--;
break;
default:
break;
}
displayCurrentSetting();
}
void setup() {
// int numberOfModes = 0;
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_INCREMENT_PIN, INPUT_PULLUP);
pinMode(BUTTON_DECREMENT_PIN, INPUT_PULLUP);
pinMode(BUTTON_NEXT_PIN, INPUT_PULLUP);
pinMode(BUTTON_ENCODER_PIN, INPUT_PULLUP);
pinMode(BUTTON_EXIT_EDIT_MODE, INPUT_PULLUP);
if (!SD.begin(pinCS)) {
lcd.clear();
lcd.print("SD Init Failed!");
return;
}
// readModesFromSD("modes.txt");
// handleModeDisplayAndControl();
}
void loop() {
doneEditing=false;
// isEditableMode= false;
unsigned long currentMillis = millis();
if(!isEditableMode){
float h = dht.readHumidity();
float t = dht.readTemperature();
if (currentModeIndex != 4 || modes[currentModeIndex].minTemp != 0){
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);
}
if(!isEditableMode){
handleModeDisplayAndControl();
}
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
logDataToSD(h, t);
}
}
static unsigned long lastEncoderButtonPress = 0;
static unsigned long lastNextButtonPress = 0;
static unsigned long lastIncrementButtonPress = 0;
static unsigned long lastDecrementButtonPress = 0;
static unsigned long lastExitButtonPress = 0;
const unsigned long debounceDelay = 200;
if (digitalRead(BUTTON_ENCODER_PIN) == LOW && millis() - lastEncoderButtonPress > debounceDelay) {
lastEncoderButtonPress = millis();
isEditableMode = !isEditableMode; // Toggle editable mode
if (isEditableMode) {
// Show editable settings if we're entering edit mode
displayCurrentSetting();
}else{
handleModeDisplayAndControl();
}
}
if (isEditableMode) {
if (digitalRead(BUTTON_NEXT_PIN) == LOW && millis() - lastNextButtonPress > debounceDelay) {
lastNextButtonPress = millis();
moveToNextSetting();
}
// Check Increment Button
if (digitalRead(BUTTON_INCREMENT_PIN) == LOW && millis() - lastIncrementButtonPress > debounceDelay) {
lastIncrementButtonPress = millis();
incrementSetting();
}
// Check Decrement Button
if (digitalRead(BUTTON_DECREMENT_PIN) == LOW && millis() - lastDecrementButtonPress > debounceDelay) {
lastDecrementButtonPress = millis();
decrementSetting();
}
if (digitalRead(BUTTON_EXIT_EDIT_MODE) == LOW && millis() - lastExitButtonPress > debounceDelay) {
lastExitButtonPress = millis();
isEditableMode=!isEditableMode;
Serial.println("exit button");
modes[4] = {"New", settings.minTemp, settings.maxTemp, settings.minHum, settings.maxHum}; // Example new mode
doneEditing = true; // Exit editable mode
}
}
// handleModeDisplayAndControl();
// delay(100);
}
// void addNewMode(String name, int minTemp, int maxTemp, int minHum, int maxHum) {
// // if (numberOfModes < MAX_MODES) {
// modes[4] = {"New", settings.minTemp, settings.maxTemp, settings.minHum, settings.maxHum};
// // Serial.println("New mode added: " + name);
// // } else {
// // Serial.println("Max modes reached. Cannot add new mode.");
// // }
// }