#include <Wire.h>
#include <LiquidCrystal.h>
#include <max6675.h>



/* A fully automatic coffee bean roaster (Arduino)
 * By Rutger
 * nightlife31@hotmail.com
 * See http://www.instructables.com/id/A-fully-automatic-coffee-bean-roaster-Arduino/
 * 
 *
 * The program does the following:
 * Display a welcome screen and waiting for you to push the button. Then it turns on the fan but not the heating coil and it allows 
 * you to set the minimal fan speed at which the beans still move a little (you can lower it during the roasting as beans get lighter). 
 * When you press the button again the heating coil is turned on and the roasting starts. The program continuously measures the 
 * temperature and adjusts the fanspeed in order to match the set point. It will lower the fan speed to increase the temperature of the 
 * beans of increase the fan speed to do the opposite. If the beans get more than 3 degrees above the set point the heating coil is 
 * switched of, which will lower the temperature directly. The set point is updated along a profile that is set into the program. 
 * First heat up to 150C and stay there for 1 minute, then slowly increase to 190C and stay there for 1 minute. Then slowly increase 
 * the temperature again until the final temperature is reached. At this point, the fan is set on max and the heating is turned down. 
 * The roaster stops when the beans are lowered to 40C.
 *
 * The roasting profile:
 * phase 1:   heat up directly to 150C
 * phase 2:   keep at 150C for 60s
 * phase 3:   increase in 180s to 190C (13.3C/min)
 * phase 4:   keep at 190C for 60s
 * phase 5:   increase with 3C/min till final roasting temp (205C)
 * phase 6:   cool down to 40C
 *
 */
int Tprofile;
int Sprofile;
int final;


// coffee roasting profile 1
String profilename1 = " Brasil ";
int TP1 [] = {190, 201, 215 };      // Temperature profile (phase 1, 2, 3, etc)
int SP1 [] = {  0, 120, 300 };      // Time profile in seconds (phase 1, 2, 3, etc) first time interval should be 0!
int FT1 = 214;  // define final roasting temperature


// coffee roasting profile 2
String  profilename2 = "Columbia";
int TP2 [] = {195, 201, 215 };      // Temperature profile (phase 1, 2, 3, etc)
int SP2 [] = {  0, 120, 300 };      // Time profile in seconds (phase 1, 2, 3, etc) first time interval should be 0!
int FT2 = 214;  // define final roasting temperature


// coffee roasting profile 3
String profilename3 = "India";
int TP3 [] = {200, 201, 215 };      // Temperature profile (phase 1, 2, 3, etc)
int SP3 [] = {  0, 120, 300 };      // Time profile in seconds (phase 1, 2, 3, etc) first time interval should be 0!
int FT3 = 213;  // define final roasting temperature


// coffee roasting profile 4
String profilename4 = "Ethiopia";
int TP4 [] = {205, 201, 215 };      // Temperature profile (phase 1, 2, 3, etc)
int SP4 [] = {  0, 120, 300 };      // Time profile in seconds (phase 1, 2, 3, etc) first time interval should be 0!
int FT4 = 214;  // define final roasting temperature


int cool  = 40;   // temperature to cool to after roasting
int phase = 0;    // phase
int countdown;    // count down seconds till end of phase
int overshoot = 3;  // max Temp overshoot before turn off heating coil
float slope;      // setpoint slope
int serialTime;   // determine phase

//Calibrated setting temperature sensor
//float a = 1,532;        // y= aX - b
//float b = 45;  


// PID controller
#include <PID_v1.h>
double Input, Setpoint;                          // parameters for PID
double Output = 0;
int P = 75;                                      //P term
int I = 50;                                      //I term
int D = 0;                                       //D term
PID myPID(&Input, &Output, &Setpoint ,P ,I ,D, DIRECT); 

// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 13, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);


//////////////////

int termoSO = 6;
int termoCS = 7;
int termoCLK = 8;

MAX6675 thermocouple(termoCLK, termoCS, termoSO);

///////////

int vccPin = 3;
int gndPin = 2;

// connections to Arduino
int buttonpin = 9;                // button connected to digital pin 9
int potpin = 0;                   // potmeter connected to analog in pin 0
//int temppin = 2;                  // temperature sensor connected to analog in pin 5
int fanpin = 10;                   // fan motor connected to pwm pin 10
int roastpin = 5;               // heating coil relais connected to pin 5

// variables
int temp;                          // Temperature in Celsius integer version of setpoint for LCD
int SetP;                          // integer version of setpoint for LCD
int readpot;                      // the current reading from the potmeter pin
int fan = 255;                     // speed of fan motor
int minfan=60;                     // minimal speed fanmotor
int Output2;                       // takes the reverse of the output
int readbutton = 0;                // the current reading from the button pin
int readtemp;                      // the current reading from the temp pin

void setup()                       // run once, when the sketch starts
{
  myPID.SetMode(AUTOMATIC);             //turn the PID on
  lcd.clear();                     // clear LCD screen
  Serial.begin(9600);              // open serial communication
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("Prazickavy");
  lcd.setCursor(0,1);
  lcd.print("Verzia 2.0");

  pinMode(vccPin, OUTPUT); digitalWrite(vccPin, HIGH);
  pinMode(gndPin, OUTPUT); digitalWrite(gndPin, LOW);
  pinMode(buttonpin, INPUT);       // sets the digital pin as input
  pinMode(fanpin, OUTPUT);         // sets the digital pin as output
  pinMode(roastpin, OUTPUT);       // sets the digital pin as output


// Press button to start roaster and select min fanspeed
    while (readbutton == LOW)        
{ readbutton = digitalRead(buttonpin);  };
 delay (1000);
  readbutton = LOW;
  readpot = analogRead(potpin);               // read potmeter value to set setpoint

  lcd.clear();                         // clear LCD screen
  lcd.print("Select minimal");
  lcd.setCursor(0,1);
  lcd.print("fan speed ");
  
  
// Select min fanspeed until button press
  while (readbutton == LOW)        
  {
  readpot = analogRead(potpin);              // read potmeter value to set setpoint
  minfan =  map (readpot,0,1023,0,255);       // set minfan as the value determined by the potmeter
  analogWrite (fanpin,minfan);              
  readbutton = digitalRead(buttonpin);  };  
  delay (1000);
  readbutton = LOW;
//  lcd.clear();                                // clear LCD screen
//  lcd.print(readpot);
//  delay (5000);

//select profile

lcd.clear();                         // clear LCD screen
lcd.print("Vyber profil");
lcd.setCursor(0,1);
lcd.print(profilename1);
if (readbutton == LOW) {
  Tprofile = TP1;
  Sprofile = SP1;
  final = FT1;
  delay (5000);
}

else 
lcd.clear();                         // clear LCD screen
lcd.print("Vyber profil");
lcd.setCursor(0,1);
lcd.print(profilename2);

if (readbutton == LOW) {
  Tprofile = TP2;
  Sprofile = SP2;
  final = FT2;
  delay (5000);
}

else 
lcd.clear();                         // clear LCD screen
lcd.print("Vyber profil");
lcd.setCursor(0,1);
lcd.print(profilename3);

if (readbutton == LOW) {
  Tprofile = TP3;
  Sprofile = SP3;
  final = FT3;
  delay (5000);
}

else 
lcd.clear();                         // clear LCD screen
lcd.print("Vyber profil");
lcd.setCursor(0,1);
lcd.print(profilename4);

if (readbutton == LOW) {
  Tprofile = TP4;
  Sprofile = SP4;
  final = FT4;
  delay (5000);
}

}

void loop()                           // run over and over again
{


// temp = thermocouple.readCelsius();      // read temperature value
readtemp = thermocouple.readCelsius();      // read temperature value
Input = 1.188 * readtemp - 23.706; // Korekcia čidla
temp = Input;



   readpot = analogRead(potpin);               // read potmeter value to set setpoint
 
 if (readpot < 1022) {
 
 minfan =  map (readpot,0,1023,0,255);       // set minfan as the value determined by the potmeter
}

else {
  

  
if (temp <= 155) {
  minfan = 255;
 }

if (155 < temp && temp <= 188) {
  minfan = 240;
 }

if (188 < temp && temp <= 205) {
  minfan = 230;
 }

 if (205 < temp && temp <= 210) {
  minfan = 215;
 }

if (temp > 210) {
  minfan = 180;
 }

 }
 
// go directly to sp during phase 0
 if (phase == 0) {
  Setpoint = Tprofile [phase];                    // jump directly to setpoint in first phase
  if (temp >= (Setpoint - 2) ) { countdown=-1;}   // start phase 1 when setpoint is reached
 }

// if countdown ends, start new phase and count down
if (countdown < 0) {
phase = phase + 1;
serialTime = millis () / 1000;
serialTime = serialTime + (Sprofile [phase]);
slope =  ( (Tprofile [phase]) - (Tprofile [(phase - 1)]) );
slope =  (slope / (Sprofile [phase]));
}

 // determine setpoint during phase 1+
 if (phase > 0) {
  countdown = serialTime - ((millis ())/1000);
  Setpoint = Tprofile [(phase - 1)] + (slope *  ((Sprofile [phase]) - countdown));
 }


// PID controller adjusts fanspeed
myPID.Compute();
Output2 = 255 - Output;                   //fanspeed needs to be controlled in opposite direction
fan =  map (Output2,0,255,minfan,255); 
analogWrite (fanpin,fan);


// turn heating coil on as long as T is below setpoint + overshoot
 if (temp < (Setpoint + overshoot))   {
  digitalWrite (roastpin,HIGH);
 } else {
  digitalWrite (roastpin,LOW);   }


// write to LCD screen
lcd.clear(); 
lcd.home();
lcd.print("F:");
lcd.print(phase);
lcd.print(" SP:");
lcd.print(int(Setpoint));
lcd.print(" T:");
lcd.print(temp);
//lcd.print(" ");//
//lcd.print(readtemp);//
lcd.setCursor(0,1);
lcd.print("Fan:");
lcd.print(int(fan/2.55));  //give fanspeed in %, rounded
lcd.print("%");
lcd.setCursor(7,1);
lcd.print(" Time:");
lcd.print(countdown);


//send-receive with processing for Front-End PID program
 SerialReceive();
 SerialSend();

// readbutton = digitalRead(buttonpin);    //stop roasting and start cooling beans if the button is pressed

// When final temp is reached of button is pressed, cool beans and end
// if (temp >= final || readbutton == HIGH) {
 if (temp >= final) {
   // turn of heating coil
   readbutton = LOW;
   Setpoint=cool;
   Output=255;
   analogWrite (fanpin,Output);
   digitalWrite (roastpin,LOW);    
   while (Input >= cool) {        // wait untill beans are cooled till ...
  //    Input =   thermocouple.readCelsius(); 
  readtemp = thermocouple.readCelsius();      // read temperature value
  Input = 1.188 * readtemp - 23.706; // Korekcia čidla
  temp = Input;
      lcd.clear(); 
      lcd.home();
      lcd.print("Chladim");
      lcd.setCursor(0,1);
      lcd.print(" Teplota:");
      lcd.print(temp);
  
   SerialReceive();
   SerialSend();
   delay(2000);
        };
   
   analogWrite (fanpin,0);       // fanspeed to zero
   lcd.clear(); 
   lcd.home();
   lcd.print("Prazenie");
   lcd.setCursor(0,1);
   lcd.print("ukoncene :-D");
   while (1 >= 1) {delay(2000);};//eternal loop
   }

// waits for 0.5 second
 delay(500);    
}
