//Milligan Engineering Low Voltage Disconnect Arduino Code

  //Specify Libraries
  #include <EEPROM.h> //This library is necesary for memory management
  #include <LiquidCrystal_I2C.h> //This library is necesary for memory management
	#include <Encoder.h> //This library is necessary for encoder functionality
  LiquidCrystal_I2C lcd(0x27,20,4);  // set the LCD address to 0x27 for a 20 chars and 4 line display
  const int EEPROM_ADDR = 0; // EEPROM address to store the user input
  const int MAX_INPUT_LENGTH = 32; // Maximum length of user input
  char userInput[MAX_INPUT_LENGTH] = {0}; // Buffer to store user input
 
//Liquid crystal display related variables
 
int scrollPosition = 0;     //First Line
 
bool selectPressed = false; // Select button latch
 
//Voltage Probe related variables
  const float Resistor1 = 1.35e6; //ohms
  const float Resistor2 = 750e3; //ohms
 
//Global Variables:
  float NominalVoltage = 24;
  bool EnableNominalVoltageInterface = true;
  float ShutOffVoltage = 12;
  bool EnableShutOffVoltageInterface = false;
  float TurnBackOnVoltage = 10;
  bool EnableTurnBackOnVoltageInterface = false;
  bool Override = false;
  unsigned long OverrideDelay = 20*60000; //milliseconds
  bool EnableTimerOffsetBoolean = false;
  unsigned long TimerOffset = 0*1000; //milliseconds
  int TimeDelay = 30000; //Delay for turning back on or off
  int LanguageSetting = 1;
  bool EnableLanguageInterface = false;
  int DeviceSetting = 3;
 
  //Timer-related variables
  unsigned long previousMillis = 0;
  unsigned long RolloverTime = (pow(2,32)-1);// Set an interval in milliseconds to ensure that millis() rollover (happens once approximately every 50 days when millis() resets to zero) is never an issue for more than 10 minutes
 
 
 
 
//Get Pin Assignments:
  int VoltageProbe= 7;
  int lcdSDA= 27;
  int lcdSCL= 19;
  int EncoderCLK = 2;
  int EncoderDT = 3;
  int EncoderSW = 8;
  int PushButton = 13;
  int RelayOutput = 4;
  int InputUp = 12;
  int InputDown = 13;
  int InputRight = 10;
  int InputLeft = 5;
  int InputSelect = 6;

  //Encoder
  int CLKNow;
  int CLKPrevious;

  int DTNow;
  int DTPrevious;

 //Initialize States
//All Possible Screens
  void Screens(int scrollPosition)
  {
  switch(scrollPosition)
  {
  case 0:
  {
  lcd.setCursor(0,0);
  lcd.print(">Batt. V        ");
  lcd.print(NominalVoltage,1);
  lcd.setCursor(0,1);
  lcd.print(" CutOff V       ");
  lcd.print(ShutOffVoltage,1);
  lcd.setCursor(0,2);
  lcd.print(" CutOn V        ");
  lcd.print(TurnBackOnVoltage,1);
  lcd.setCursor(0,3);
  lcd.print(" Override T:   ");
  lcd.print(OverrideDelay/60000);
	lcd.print("min");
  break;
  }
  case 1:
  {
  lcd.setCursor(0,0);
  lcd.print(" Batt. V        ");
  lcd.print(NominalVoltage,1);
  lcd.setCursor(0,1);
  lcd.print(">CutOff V       ");
  lcd.print(ShutOffVoltage,1);
  lcd.setCursor(0,2);
  lcd.print(" CutOn V        ");
  lcd.print(TurnBackOnVoltage,1);
  lcd.setCursor(0,3);
  lcd.print(" Override T:   ");
  lcd.print(OverrideDelay/60000);
	lcd.print("min");
  break;
  }
  case 2:
  {
  lcd.setCursor(0,0);
  lcd.print(" Batt. V        ");
  lcd.print(NominalVoltage,1);
  lcd.setCursor(0,1);
  lcd.print(" CutOff V       ");
  lcd.print(ShutOffVoltage,1);
  lcd.setCursor(0,2);
  lcd.print(">CutOn V        ");
  lcd.print(TurnBackOnVoltage,1);
  lcd.setCursor(0,3);
  lcd.print(" Override T:   ");
  lcd.print(OverrideDelay/60000);
	lcd.print("min");
  break;
  }
  case 3:
  {
  lcd.setCursor(0,0);
  lcd.print(" Batt. V        ");
  lcd.print(NominalVoltage,1);
  lcd.setCursor(0,1);
  lcd.print(" CutOff V       ");
  lcd.print(ShutOffVoltage,1);
  lcd.setCursor(0,2);
  lcd.print(" CutOn V        ");
  lcd.print(TurnBackOnVoltage,1);
	lcd.setCursor(0,3);
  lcd.print(">Override T:   ");
  lcd.print(OverrideDelay/60000);
	lcd.print("min");
  break; //The reason I didn't just have cases to only change the position of the arrow is the screen will have to be cleared to get rid of the arrows or a space would be needed to overwrite this.  It was just as easy to do this.
  } //end of case 3
  } 
  }
 
  void Scroll()
  {
  Screens(scrollPosition);
  } // end void Scroll()


/*
  void Select()
  {
  int RIGHT_State = digitalRead(InputRight);
  int LEFT_State = digitalRead(InputLeft);
  //I think I should add a timer to get out of select state in case user leaves it, battery voltage would not be updated on LCD
  if (scrollPosition == 1)
  {
  Screens(scrollPosition);    // Keep updating the screen
  if (RIGHT_State == HIGH)
  {
  ShutOffVoltage = ShutOffVoltage + 0.1;
  } //end if(RIGHT_State == HIGH)
  if (LEFT_State == HIGH)
  {
  ShutOffVoltage = ShutOffVoltage - 0.1;
  } // end if(LEFT_State == HIGH)
  } //end (if ScrollPosition==1)
  else if (scrollPosition == 2)
  {
  Screens(scrollPosition);
  if (RIGHT_State == HIGH)
  {
  TurnBackOnVoltage = TurnBackOnVoltage + 0.1;
  } //if (RIGHT_State == HIGH)
  if (LEFT_State == HIGH)
  {
  TurnBackOnVoltage = TurnBackOnVoltage - 0.1;
  } //end of  if(LEFT_State == HIGH)
  } //end of else if (scrollPosition == 2)
  else if (scrollPosition == 3)
  {
  Screens(scrollPosition);
  if (RIGHT_State == HIGH)
  {
  OverrideDelay = OverrideDelay + (5*60000);
  }
  if (LEFT_State == HIGH && (OverrideDelay > 0))
  {
  OverrideDelay = OverrideDelay - (5*60000);
  } //end of if (LEFT_State == HIGH)
  }   
 */

void setup()
{
  // Initialize serial communication
  lcd.init(); // initialize the lcd
  lcd.backlight();
 
  //Button Initialization
  pinMode(InputUp, INPUT);
  pinMode(InputDown, INPUT);
  pinMode(InputLeft, INPUT);
  pinMode(InputRight, INPUT);
  pinMode(InputSelect, INPUT);
  selectPressed = false;
  Serial.begin(9600);
  Serial.println("Basic Encoder Test:");
  
  //Encoder Initialization - Ideally, the pins should be interrupt pins
  pinMode(EncoderCLK, INPUT); //RotaryCLK          //I added this
  pinMode(EncoderDT, INPUT); //RotaryDT            //I added this
  pinMode(EncoderSW, INPUT_PULLUP); //Button        

  CLKPrevious = digitalRead(EncoderCLK);
  DTPrevious = digitalRead(EncoderDT);      //Must be in setup
} //End of void setup
 
void loop()
{

  
	CLKNow = digitalRead(EncoderCLK);
  DTNow = digitalRead(EncoderDT)
  //User Input:
  //EncoderScroll();
  
  if (CLKNow != CLKPrevious && CLKNow == 1)   //Change has been detected in encoder
  {
    // If the DT state is different than the CLK state then
    // the encoder is rotating in A direction, so we increase
  if (DTNow != CLKNow)           // IF DT and CLK are different, turning clockwise (Scroll DOWN)
  {
    if (scrollPosition < 0) // we do not go below 0
    {
      scrollPosition++;  
    }
  } 
  else                                          //IF DT and CLK are the same, turning counter clockwise (Scroll UP)
  {
    if (scrollPosition < 3) // we do not go above 3
    {
      scrollPosition++;  
    }
    else
    {
      scrollPosition = 0;
    }      
  }    
  }
  CLKPrevious = CLKNow;  // Store last CLK state
  Scroll();
  Serial.print("Clk Now: ");
  Serial.println(CLKNow);
  Serial.print("\n");
  Serial.print("DT Now: ");
  Serial.println(DTNow);
  Serial.print("\n");
  Serial.print("Clk Prev: ");
  Serial.println(CLKPrevious);
  Serial.print("\n");
  Serial.print("DT Prev: ");
  Serial.println(DTPrevious);
  Serial.print("\n");
  }



  

/*
  if (newPosition >&& scrollPosition < 3) {
    scrollPosition++;
  } else if (newPosition < oldPosition && scrollPosition > 0) {
    scrollPosition--;
  }
  if (newPosition != oldPosition) {
    oldPosition = newPosition;
    Serial.println(newPosition);
    Serial.print("\n");
    Serial.print("ScrollPosition: ");
    Serial.println(scrollPosition);
    Serial.print("\n");
  }
 
 */


  //End of Void Loop
$abcdeabcde151015202530fghijfghij