#include <DallasTemperature.h>
#include <LiquidCrystal.h>

OneWire oneWire1(52);//room temperature sensor
DallasTemperature sensors1(&oneWire1);

OneWire oneWire2(24);//fridge temperature sensor
DallasTemperature sensors2(&oneWire2);

OneWire oneWire3(22); //freezer temperature sensor
DallasTemperature sensors3(&oneWire3);

const int compressorRelay = 25;
const int defrostRelay = 30;
const int coolfailRelay = 41;

const int pin_RS = 8;
const int pin_EN = 9;
const int pin_d4 = 4;
const int pin_d5 = 5;
const int pin_d6 = 6;
const int pin_d7 = 7;
const int pin_BL = 10;
LiquidCrystal lcd(pin_RS, pin_EN, pin_d4, pin_d5, pin_d6, pin_d7);

int totalColumns  = 16;
int totalRows     = 2;

unsigned long startTime = 0;
unsigned long lastDefrostTime = 0;
const unsigned long defrostInterval = 60000;  // Defrost interval in milliseconds (60 seconds)
const int defrostDuration = 3000;
const int secondsThreshold = 10;
const int monitorTempThreshold = -10;  // Added threshold for monitoring temperature

enum CycleState {
  COOLING,
  DEFROST,
  MONITOR_TEMP,
};

CycleState currentCycleState = COOLING;
unsigned long cycleStartTime = 0;

// Define the interval for automatic reset in milliseconds (2 minutes)
const unsigned long resetInterval = 240000;
unsigned long lastResetTime = 0;

// Global variable to track the time the freezer temperature goes above 5°C
static unsigned long aboveThresholdStartTime = 0;




String scrollingMessage = "Three temperature sensors 10/10/2023;room, fridge, freezer & total operating time controller...";

void scrollMessage(int row, String message, int delayTime, int totalColumns) {
  for (int i=0; i < totalColumns; i++) {
    message = " " + message;  
  } 
  message = message + " "; 
  for (int position = 0; position < message.length(); position++) {
    lcd.setCursor(0, 0);
    lcd.print(message.substring(position, position + totalColumns));
    delay(delayTime);

  }}





void setup(void) {
  Serial.begin(9600);
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);

   lcd.print("SETUP CONTROLLER");


   delay(1000);


lcd.setCursor(0, 1);
 
  lcd.print("......WAIT......");
delay(1000);


  pinMode(compressorRelay, OUTPUT);
  pinMode(defrostRelay, OUTPUT);
  pinMode(coolfailRelay, OUTPUT);
  digitalWrite(coolfailRelay, LOW);

  sensors1.begin();
  sensors2.begin();
  sensors3.begin();

  startTime = millis();
  lastDefrostTime = millis();
  cycleStartTime = millis();
}

void loop(void) {
  unsigned long currentMillis = millis();



  sensors1.requestTemperatures();

sensors2.requestTemperatures();

sensors3.requestTemperatures();
float room    = sensors1.getTempCByIndex(0);

  float fridge  = sensors2.getTempCByIndex(0);

  float freezer = sensors3.getTempCByIndex(0);
  // Check if it's time to reset every 2 minutes
  if (currentMillis - lastResetTime >= resetInterval) {
    // Perform any cleanup or actions before resetting, if needed
    delay(1000);  // Wait for stability (optional)
    asm volatile ("  jmp 0");  // Jump to the beginning of the program, resetting it
  }
 


 

lcd.clear();
 lcd.setCursor(0, 0);
  lcd.print("....GOOD DAY....");
delay(200);
lcd.clear();
delay(200);
lcd.print("....GOOD DAY....");
delay(200);
lcd.clear();


lcd.setCursor(0, 0);
  
  scrollMessage(1, scrollingMessage, 250, totalColumns); //scrollMessage(int row, String message, int delayTime, int totalColumns)
  
lcd.setCursor(0,0);
   lcd.print("Time in hours    ");
   lcd.setCursor(14,1);

   //lcd.print((char)223);
   lcd.setCursor(0,1);
lcd.print("Temp.-55to+125 C");
lcd.setCursor(14,1); //column,row
   lcd.print((char)223); // ° symbol
   delay(2000);






   lcd.setCursor(0,0);
   lcd.print("Room   =       C");
   lcd.setCursor(14,0); //column,row
   lcd.print((char)223); // ° symbol
   lcd.setCursor(8,0);
   lcd.print(room);
   
   lcd.setCursor(0,1);
   lcd.print("Fridge =       C");
   lcd.setCursor(14,1);
   lcd.print((char)223);
   lcd.setCursor(8,1);
  lcd.print(fridge);

delay(2000);






  



















  // Update the last reset time if a reset is not triggered
  lastResetTime = currentMillis;

  // Debug statements
  Serial.println("Current Millis: " + String(currentMillis));
  Serial.println("Last Defrost Time: " + String(lastDefrostTime));

  // Check for defrost cycle every 60 seconds
  if ((currentMillis - lastDefrostTime >= defrostInterval) || (currentMillis < lastDefrostTime && (4294967295UL - lastDefrostTime + currentMillis) >= defrostInterval)) {
    startDefrostCycle();
    lastDefrostTime = currentMillis;
  }

  // Perform cooling, defrost, or monitor temperature cycle actions
  if (currentCycleState == COOLING) {
    performCoolingCycle();
  } else if (currentCycleState == DEFROST) {
    performDefrostCycle();
  } else if (currentCycleState == MONITOR_TEMP) {
    monitorFreezerTemperature();
  }

  // Print total running hours to serial monitor
  unsigned long elapsedTime = currentMillis - startTime;
  float totalRunningHours = elapsedTime / (1000.0 * 3600.0);

  Serial.print("Total Running Hours: ");
  Serial.println(totalRunningHours);

  // Print total running hours to LCD
  lcd.setCursor(0, 1);
  lcd.print("Time=         Hr");
  lcd.setCursor(5, 1);
  lcd.print(totalRunningHours, 2);

  // Blinking pattern for pin 41
  if (freezerTemperatureAboveThreshold(15,  10000)) {
    digitalWrite(coolfailRelay, HIGH);

lcd.clear();
                  delay(300);
                  lcd.print("...COOL  FAIL...");
     
     delay(3000);

lcd.setCursor(0, 1);
lcd.print(" FREEZER >15  C");
lcd.setCursor(13,1); //column,row
   lcd.print((char)223); // ° symbol




  } else {
    digitalWrite(coolfailRelay, LOW);
  }

  delay(2000);
}

void performCoolingCycle() {
  sensors1.requestTemperatures();
  sensors2.requestTemperatures();
  sensors3.requestTemperatures();

  float freezer = sensors3.getTempCByIndex(0);
  updateFreezerRelayState(freezer);
}

void updateFreezerRelayState(float freezerTemp) {
  if (freezerTemp >= 0 || freezerTemp >= monitorTempThreshold) {
    if (millis() - cycleStartTime >= secondsThreshold * 1000) {
      digitalWrite(compressorRelay, HIGH);

lcd.setCursor(0,1);
lcd.print("COMPRESSOR START");
delay(5000);
lcd.setCursor(0, 1);
lcd.print("TEMPERATURE DROP");
delay(5000);






      cycleStartTime = millis();
    }
  } else {
    digitalWrite(compressorRelay, LOW);
    currentCycleState = MONITOR_TEMP;  // Set state to monitor temperature when below the threshold
  }
}

void startDefrostCycle() {
  digitalWrite(compressorRelay, LOW);
  digitalWrite(defrostRelay, HIGH);
  currentCycleState = DEFROST;

  unsigned long defrostEndTime = millis() + defrostDuration;
  while (millis() < defrostEndTime) {
    sensors1.requestTemperatures();
    sensors2.requestTemperatures();
    sensors3.requestTemperatures();
    delay(100);
  }

  digitalWrite(defrostRelay, LOW);
  currentCycleState = MONITOR_TEMP;
}

void performDefrostCycle() {
  // Perform actions during defrost cycle, if needed
}

void monitorFreezerTemperature() {
  sensors1.requestTemperatures();
  sensors2.requestTemperatures();
  sensors3.requestTemperatures();

  float freezer = sensors3.getTempCByIndex(0);

  if (freezer >= 0 && (millis() - cycleStartTime >= secondsThreshold * 1000)) {
    digitalWrite(compressorRelay, LOW);
    currentCycleState = COOLING;
    cycleStartTime = millis();  // Update cycle start time
  }
}

bool freezerTemperatureAboveThreshold(float threshold, unsigned long duration) {
  sensors1.requestTemperatures();
  sensors2.requestTemperatures();
  sensors3.requestTemperatures();

  float freezer = sensors3.getTempCByIndex(0);

  if (freezer >= threshold) {
    if (millis() - aboveThresholdStartTime >= duration) {
      aboveThresholdStartTime = millis();
      return true;
    }
  } else {
    aboveThresholdStartTime = millis();
  }

  return false;
}

freezer
fridge
room
cooling
defrosting
alarm