#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "uRTCLib.h"
#include <EEPROM.h>
// Define the EEPROM address where you want to store the parameters
int eepromAddress = 0;
// uRTCLib rtc;
uRTCLib rtc(0x68);
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
unsigned long previousMillis2 = 0;
const long interval2 = 1000; // Update interval in milliseconds
LiquidCrystal_I2C lcd(0x27, 16, 2);
unsigned long lastInputTime = 0;
const unsigned long idleTimeout = 3000; // Set the idle timeout to 30 seconds (adjust as needed)
char isRunning_state = 0; // Example condition, true for "RUN," false for "STOP"
const int relayPin = 12; // Specificați pinul la care este conectat releul
unsigned long previousIrrigationTime = 0;
bool irrigationInProgress = false;
boolean save_the_state=false;
// Input & Button Logic
const int numOfInputs = 4;
const int inputPins[numOfInputs] = { 8, 9, 10, 11 };
int inputState[numOfInputs];
int lastInputState[numOfInputs] = { LOW, LOW, LOW, LOW };
bool inputFlags[numOfInputs] = { LOW, LOW, LOW, LOW };
long lastDebounceTime[numOfInputs] = { 0, 0, 0, 0 };
long debounceDelay = 5;
// LCD Menu Logic
const int numOfScreens = 7;
int currentScreen = 0;
String screens[numOfScreens][2] = { { "Pornire fortata", "" }, { "Duratie", "min" }, { "Interval", "min" }, { "Ora pornire", "h" }, { "Ora Oprire", "h" }, { "Setare ora", "h" }, { "Setare min", "Mins" } };
int parameters[numOfScreens];
int parameters_min_max[numOfScreens][2] = { { 0, 2 }, { 1, 59 }, { 1, 59 }, { 0, 23 }, { 0, 23 }, { 0, 23 }, { 0, 59 } };
void setInputFlags();
void resolveInputFlags();
void inputAction(int input);
void parameterChange(int key);
void printScreen();
int plusHour();
int plusMinute();
byte decToBcd(byte val);
byte bcdToDec(byte val);
void setup() {
// Initialize the EEPROM
// EEPROM.begin(sizeof(parameters));
// Read the parameters from EEPROM and check if they are valid
bool parametersValid = readParameters();
// If the parameters are not valid, set default values or take appropriate action
if (!parametersValid) {
// Set default values or handle the error as needed
initializeDefaultParameters();
}
Serial.begin(115200);
pinMode(relayPin, OUTPUT);
for (int i = 0; i < numOfInputs; i++) {
pinMode(inputPins[i], INPUT);
digitalWrite(inputPins[i], HIGH); // pull-up 20k
}
// Serial.begin(9600);
lcd.begin(16, 2);
lcd.backlight();
URTCLIB_WIRE.begin();
// RTCLib::set(byte second, byte minute, byte hour, byte dayOfWeek, byte dayOfMonth, byte month, byte year)
rtc.set(0, 56, 12, 7, 10, 1, 23);
parameters[1]=1;
parameters[2]=3;
parameters[3]=10;
parameters[4]=15;
int value =1*60*1000;
Serial.println(String(value));
}
void loop() {
/* // Obțineți valorile pentru durată, interval, oră de pornire și oră de oprire de undeva
int durataIrigatie = parameters[1]; // Exemplu: Valoarea pentru durată a irigației
int intervalIrigatie = parameters[2]; // Exemplu: Valoarea pentru intervalul de irigație
int oraPornire = parameters[3]; // Exemplu: Valoarea pentru oră de pornire
int oraOprire = parameters[4]; // Exemplu: Valoarea pentru oră de oprire
setInputFlags();
resolveInputFlags();
// Check for inactivity and go to the idle screen if needed
unsigned long currentMillis = millis();
if (currentMillis - lastInputTime >= idleTimeout) {
currentScreen = 0; // Set the current screen to the idle screen
if(save_the_state){
save_the_state=false;
saveParameters();
}
idle_screen(); // Update the idle screen
}
unsigned long currentMillis2 = millis();
if (currentMillis2 - previousMillis2 >= interval2) {
previousMillis2 = currentMillis2;
controlIrigatie(oraPornire, oraOprire, intervalIrigatie, durataIrigatie);
updateDateTime();
}
*/
}
void setInputFlags() {
for (int i = 0; i < numOfInputs; i++) {
int reading = digitalRead(inputPins[i]);
if (reading != lastInputState[i]) {
lastDebounceTime[i] = millis();
}
if ((millis() - lastDebounceTime[i]) > debounceDelay) {
if (reading != inputState[i]) {
inputState[i] = reading;
if (inputState[i] == HIGH) {
inputFlags[i] = HIGH;
}
}
}
lastInputState[i] = reading;
}
}
void resolveInputFlags() {
for (int i = 0; i < numOfInputs; i++) {
if (inputFlags[i] == HIGH) {
save_the_state=true;
lastInputTime = millis(); // Update the last input time
inputAction(i);
inputFlags[i] = LOW;
printScreen();
}
}
}
void inputAction(int input) {
if (input == 0) {
if (currentScreen == 0) {
currentScreen = numOfScreens - 1;
} else {
currentScreen--;
}
} else if (input == 1) {
if (currentScreen == numOfScreens - 1) {
currentScreen = 0;
} else {
currentScreen++;
}
} else if (input == 2) {
if (currentScreen == 5) {
parameters[currentScreen]=plusHour(); // Call the function to increment the hour
}
if (currentScreen == 6) {
parameters[currentScreen]=plusMinute(); // Call the function to increment the minute
}
if (currentScreen == 0) {
parameterChange(0);
if(parameters[currentScreen]==0)
screens[0][1]="AUTO";
if(parameters[currentScreen]==1)
screens[0][1]="FORTAT ON";
if(parameters[currentScreen]==2)
screens[0][1]="FORTAT OFF";
}
else
parameterChange(0);
} else if (input == 3) {
if (currentScreen == 5) {
parameters[currentScreen]=plusHour(); // Call the function to increment the hour
}
if (currentScreen == 6) {
parameters[currentScreen]=plusMinute(); // Call the function to increment the minute
}
if (currentScreen == 0) {
parameterChange(1);
if(parameters[currentScreen]==0)
screens[0][1]="AUTO";
if(parameters[currentScreen]==1)
screens[0][1]="FORTAT ON";
if(parameters[currentScreen]==2)
screens[0][1]="FORTAT OFF";
}
else
parameterChange(1);
}
Serial.println(currentScreen);
}
void parameterChange(int key) {
int minVal = parameters_min_max[currentScreen][0];
int maxVal = parameters_min_max[currentScreen][1];
if (key == 0) {
// Increment the parameter value with wrap-around to the minimum value
parameters[currentScreen] = (parameters[currentScreen] + 1) > maxVal ? minVal : (parameters[currentScreen] + 1);
} else if (key == 1) {
// Decrement the parameter value with wrap-around to the maximum value
parameters[currentScreen] = (parameters[currentScreen] - 1) < minVal ? maxVal : (parameters[currentScreen] - 1);
}
}
void printScreen() {
lcd.clear();
lcd.print(screens[currentScreen][0]);
lcd.setCursor(0, 1);
lcd.print(parameters[currentScreen]);
lcd.print(" ");
lcd.print(screens[currentScreen][1]);
}
void idle_screen() {
String runStopVariable = irrigationInProgress ? "RUN " : "STOP";
// Display the first row with variable values
lcd.setCursor(0, 0);
lcd.print("M:");
lcd.print(parameters[0]);
lcd.print(" D:");
lcd.print(addLeadingZero(parameters[1]));
lcd.print(" I:");
lcd.print(addLeadingZero(parameters[2]));
lcd.print(" ");
// Display the second row with the "RUN-STOP" variable
lcd.setCursor(0, 1);
lcd.print(addLeadingZero(parameters[3]));
lcd.print("-");
lcd.print(addLeadingZero(parameters[4]));
lcd.print(" ");
lcd.print(rtc.hour());
lcd.print(":");
lcd.print(rtc.minute());
lcd.print(" ");
lcd.print(runStopVariable);
/*
}
}*/
}
void controlIrigatie(int oraPornire, int oraOprire, int intervalIrigatie, int durataIrigatie) {
int oraCurenta = rtc.hour();
int minuteCurente = rtc.minute();
if (parameters[0] == 1) {
// Modul "Pornire Fortată"
if (!irrigationInProgress) {
irrigationInProgress = true;
digitalWrite(relayPin, HIGH); // Activează releul pentru irigație
}
} else if (parameters[0] == 2) {
// Modul "Oprire Fortată"
if (irrigationInProgress) {
irrigationInProgress = false;
digitalWrite(relayPin, LOW); // Dezactivează releul pentru a încheia irigația
}
} else {
// Verificați dacă sunteți în intervalul de oră de pornire și oprire
if (oraCurenta >= oraPornire && oraCurenta < oraOprire) {
// Sunteți în intervalul de irigare, verificați dacă trebuie să începeți irigația
if (!irrigationInProgress && minuteCurente % intervalIrigatie == 0) {
// A trecut intervalul specificat, porniți irigația
irrigationInProgress = true;
digitalWrite(relayPin, HIGH); // Activează releul pentru irigație
previousIrrigationTime = millis();
}
// Verificați dacă trebuie să opriți irigația după durata specificată
if (irrigationInProgress) {
unsigned long currentTime = millis();
unsigned long elapsedTime = currentTime - previousIrrigationTime;
Serial.print("elapsedTime:");
Serial.println(elapsedTime);
Serial.println("calculat:");
Serial.println(((int)durataIrigatie * 60 * 1000));
if (elapsedTime >= ((int)durataIrigatie * 60 * 1000)) {
irrigationInProgress = false;
digitalWrite(relayPin, LOW); // Dezactivează releul pentru a încheia irigația
}
}
} else {
// În afara intervalului de oră de pornire și oprire, opriți irigația (dacă este pornită)
irrigationInProgress = false;
digitalWrite(relayPin, LOW);
}
}
}
String addLeadingZero(int value) {
if (value < 10) {
return "0" + String(value);
} else {
return String(value);
}
}
void updateDateTime() {
rtc.refresh();
Serial.print("Current Date & Time: ");
Serial.print(rtc.year());
Serial.print('/');
Serial.print(rtc.month());
Serial.print('/');
Serial.print(rtc.day());
Serial.print(" (");
Serial.print(daysOfTheWeek[rtc.dayOfWeek() - 1]);
Serial.print(") ");
Serial.print(rtc.hour());
Serial.print(':');
Serial.print(rtc.minute());
Serial.print(':');
Serial.print(rtc.second());
Serial.print('-');
Serial.print(irrigationInProgress);
Serial.print('-');
Serial.println(screens[0][1]);
}
#define DS3231_I2C_ADDRESS 0x68
int plusHour() {
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(2); // set DS3231 register pointer to 02h
Wire.endTransmission();
Wire.requestFrom(DS3231_I2C_ADDRESS, 1);
char hour = bcdToDec(Wire.read() & 0x3f);
if (++hour >= 24) {
hour = 0;
}
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(2);
Wire.write(decToBcd(hour));
Wire.endTransmission();
updateDateTime();
return hour;
}
int plusMinute() {
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(1); // set DS3231 register pointer to 01h (minutes)
Wire.endTransmission();
Wire.requestFrom(DS3231_I2C_ADDRESS, 1);
char minute = bcdToDec(Wire.read() & 0x7f);
Serial.println(minute);
if (++minute >= 60) {
minute = 0;
}
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(1); // set DS3231 register pointer to 01h (minutes)
Wire.write(decToBcd(minute));
Wire.endTransmission();
updateDateTime();
return minute;
}
byte decToBcd(byte val) {
return (val / 10 * 16) + (val % 10);
}
byte bcdToDec(byte val) {
return (val / 16 * 10) + (val % 16);
}
bool readParameters() {
// Read the parameters from EEPROM
for (int i = 0; i < numOfScreens; i++) {
parameters[i] = EEPROM.read(eepromAddress + i);
}
// Calculate the checksum of the parameters
uint8_t storedChecksum = EEPROM.read(eepromAddress + numOfScreens);
uint8_t calculatedChecksum = calculateChecksum(parameters, numOfScreens);
// Check if the calculated checksum matches the stored checksum
if (storedChecksum != calculatedChecksum) {
return false; // Data integrity check failed
}
// Check if the parameters are within valid ranges
if (parameters[5] < 0 || parameters[5] > 23 || parameters[6] < 0 || parameters[6] > 59) {
return false; // Invalid parameter values
}
return true;
}
void saveParameters() {
// Check if the parameters are within valid ranges
if (parameters[5] < 0 || parameters[5] > 23 || parameters[6] < 0 || parameters[6] > 59) {
// Handle the error (e.g., set default values)
initializeDefaultParameters();
} else {
// Calculate the checksum of the parameters
uint8_t checksum = calculateChecksum(parameters, numOfScreens);
// Save the parameters and checksum to EEPROM
for (int i = 0; i < numOfScreens; i++) {
EEPROM.write(eepromAddress + i, parameters[i]);
}
EEPROM.write(eepromAddress + numOfScreens, checksum); // Store the checksum
//EEPROM.commit(); // Commit the changes to EEPROM
}
}
uint8_t calculateChecksum(int* data, int length) {
uint8_t checksum = 0;
for (int i = 0; i < length; i++) {
checksum ^= data[i];
}
return checksum;
}
void initializeDefaultParameters() {
// Set default values for the parameters or handle the error as needed
// For example:
for (int i = 0; i < numOfScreens; i++) {
parameters[i] = 0;
}
saveParameters();
}