#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,20,4);  //LCD i2c adress sometimes 0x3f or 0x27

//Icons
uint8_t Battery[8]  = {0x0E, 0x1B, 0x11, 0x11, 0x1F, 0x1F, 0x1F, 0x1F};
uint8_t Panel[8]  = {0x1F, 0x15, 0x1F, 0x15, 0x1F, 0x15, 0x1F, 0x00};
uint8_t Pwm[8]  = {0x1D, 0x15, 0x15, 0x15, 0x15,0x15, 0x15, 0x17};
uint8_t Flash[8]  = {0x01, 0x02, 0x04, 0x1F, 0x1F, 0x02, 0x04, 0x08};


//Constants
#define bulk_voltage_max 14.5
#define bulk_voltage_min 13
#define absorption_voltage 14.7
#define float_voltage_max 13
#define battery_min_voltage 10
#define solar_min_voltage 19
#define charging_current 2.0
#define absorption_max_current 2.0
#define absorption_min_current 0.1
#define float_voltage_min 13.2
#define float_voltage 13.4
#define float_max_current 0.12
#define LCD_refresh_rate 1000
byte BULK = 0;        //Give values to each mode
byte ABSORPTION = 1;
byte FLOAT = 2;
byte mode = 0;        //We start with mode 0 BULK

//Inputs

//Outputs



//Variables
float bat_voltage = 0;
int e = 0;
float solar_current = 0;
float t = 0.185;       //Value defined by manufacturer ACS712 5A
float o = 0;
float solar_power = 0;
String load_status = "OFF";
int p = 0;
unsigned int before_millis = 0;
unsigned int now_millis = 0;
String mode_str = "BULK";


void setup(){
  pinMode(A1,INPUT);    //Set pins as inputs
  pinMode(A0,INPUT);
  pinMode(A2,INPUT);
  
  pinMode(10,OUTPUT);            //Set pins as OUTPUTS
  digitalWrite(10,0);          //Set PWM to LOW so MSOFET is off
  pinMode(2,OUTPUT);
  digitalWrite(2,0);      //Start with the relay turned off
  TCCR1B = TCCR1B & B11111000 | B00000001; //timer 1 PWM frequency of 31372.55 Hz
  Serial.begin(9600);

  lcd.init();                 //Init the LCD
  lcd.backlight();            //Activate backlight  

  lcd.createChar(0, Battery);
  lcd.createChar(1, Panel);
  lcd.createChar(2, Pwm);
  lcd.createChar(3, Flash);
  before_millis = millis;     //Used for LCD refresh rate
}

void loop(){
  o = x(15);
  bat_voltage =   z(15);
  solar_current = w(15);
  solar_power = bat_voltage * solar_current; 
  p = map(e,0,255,0,100);

  now_millis = millis();
  if(now_millis - before_millis > LCD_refresh_rate)
  {
    before_millis = now_millis;
    lcd.clear();
    lcd.setCursor(0,0);               //Column 0 row 0
    lcd.write(1);                     //Panel icon
    lcd.print(" ");                   //Empty space
    lcd.print(o,2);       //Soalr voltage 
    lcd.print("V");                   //Volts
    lcd.print("    ");                //Empty spaces
    lcd.write(0);                     //Battery icon
    lcd.print(" ");                   //Empty space
    lcd.print(bat_voltage,2);         //Battery voltsge
    lcd.print("V");                   //Volts
  
    lcd.setCursor(0,1);               //Column 0 row 1
    lcd.print("  ");                  //Empty spaces
    lcd.print(solar_current,2);       //Solar current
    lcd.print("A");                   //Ampers
    lcd.print("     LOAD ");           //Print LOAD
    lcd.print(load_status);           //LOAD status
    
    lcd.setCursor(0,2);               //Column 0 row 2
    lcd.print("  ");                  //Empty spaces
    lcd.print(solar_power,2);         //Solar power
    lcd.print("W");                   //Watts
    lcd.print("     PWM ");           //Print PWM
    lcd.print(p);        //PWM value
    lcd.print("%");                   //Percentage

    lcd.setCursor(0,3);               //Column 0 row 3
    lcd.print(mode_str);              //Print the mode
    
  }
  
  if(bat_voltage < battery_min_voltage){
    digitalWrite(2,0);        //We DISABLE the load if battery is undervoltage
    load_status  = "OFF";
  }
  else{
    digitalWrite(2,1);       //We ENABLE the load if battery charged
    load_status  = "ON";
  }

  ///////////////////////////FLOAT///////////////////////////
  ///////////////////////////////////////////////////////////
  if(mode == FLOAT){
    if(bat_voltage < float_voltage_min){
      mode = BULK;
      mode_str = "BULK"; 
    }
    
    else{
      if(solar_current > float_max_current){    //If we exceed max current value, we change mode
        mode = BULK;
        mode_str = "BULK"; 
      }//End if > 
  
      else{
        if(bat_voltage > float_voltage){
          e--;
          e = constrain(e,0,254);
        }
        
        else {
          e++;
          e = constrain(e,0,254);
        }        
      }//End else > float_max_current
      
      analogWrite(10,e);
    }
  }//END of mode == FLOAT



  //Bulk/Absorption
  else{
    if(bat_voltage < bulk_voltage_min){
      mode = BULK;
      mode_str = "BULK";   
    }
    else if(bat_voltage > bulk_voltage_max){
      mode_str = "ABSORPTION"; 
      mode = ABSORPTION;
    }
  
    ////////////////////////////BULK///////////////////////////
    ///////////////////////////////////////////////////////////
    if(mode == BULK){
      if(solar_current > charging_current){
        e--;
        e = constrain(e,0,254);
      }
      
      else {
        e++;
        e = constrain(e,0,254);
      }
      analogWrite(10,e);
    }//End of mode == BULK
  
  
  
    /////////////////////////ABSORPTION/////////////////////////
    ///////////////////////////////////////////////////////////
    if(mode == ABSORPTION){
      if(solar_current > absorption_max_current){    //If we exceed max current value, we reduce duty cycle
        e--;
        e = constrain(e,0,254);
      }//End if > absorption_max_current
  
      else{
        if(bat_voltage > absorption_voltage){
          e++;
          e = constrain(e,0,254);
        }
        
        else {
          e--;
          e = constrain(e,0,254);
        }
        
        if(solar_current < absorption_min_current){
          mode = FLOAT;
          mode_str = "FLOAT"; 
        }
      }//End else > absorption_max_current
      
      analogWrite(10,e);
    }// End of mode == absorption_max_current
    
  }//END of else mode == FLOAT

  
  

  



  
  //Serial.println(bat_voltage);  
}//End void loop





/////////////////////////FUNCTIONS/////////////////////////
///////////////////////////////////////////////////////////
float x(int n)
{
  float v = 0;
  for(int i=0; i < n; i++)
  {
    v += (analogRead(A1) * (5.0 / 1023.0) * 8.0); 
  }
  v = v/n;
  if(v < 0){v = 0;}
  return(v);
}



float z(int n)
{
  float v = 0;
  for(int i=0; i < n; i++)
  {
    v += (analogRead(A2) * (5.0 / 1023.0) * 7.85);     
  }
  v = v/n;
  if(v < 0){v = 0;}
  return(v);
}


float w(int n)
{
  float v;
  float c =0;
  for(int i=0; i < n; i++)
  {
    v = analogRead(A0) * (5.0 / 1023.0);
    c = c + (v-2.5)/t; 
  }
  c = c/n;
  if(c < 0){c = 0;}
  return(c);
}













uno:A5.2
uno:A4.2
uno:AREF
uno:GND.1
uno:13
uno:12
uno:11
uno:10
uno:9
uno:8
uno:7
uno:6
uno:5
uno:4
uno:3
uno:2
uno:1
uno:0
uno:IOREF
uno:RESET
uno:3.3V
uno:5V
uno:GND.2
uno:GND.3
uno:VIN
uno:A0
uno:A1
uno:A2
uno:A3
uno:A4
uno:A5
lcd1:GND
lcd1:VCC
lcd1:SDA
lcd1:SCL
pot1:GND
pot1:SIG
pot1:VCC
pot2:GND
pot2:SIG
pot2:VCC
led1:A
led1:C
r1:1
r1:2
pot3:GND
pot3:SIG
pot3:VCC
led2:A
led2:C
r2:1
r2:2