#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
#include <PID_v2.h>
#include <OneWire.h>
#include <DallasTemperature.h>
OneWire oneWire(15);
DallasTemperature ds(&oneWire);

#define ENCODER_CLK 2
#define ENCODER_DT  3
#define ENCODER_SW  11
#define RELAY_PIN 12

#define TEMP_MAX 60.0
#define TEMP_MIN 25.0
#define WindowSize 500

int lastClk = HIGH;
float Temperature;
double Input, Output, Counter = TEMP_MIN;
unsigned long windowStartTime;

double Kp=2, Ki=5, Kd=1.5;
PID mPID(&Input, &Output, &Counter, Kp, Ki, Kd, DIRECT);

void setup() {
  Serial.begin(115200);

  ds.begin();

  pinMode(ENCODER_CLK, INPUT);
  pinMode(ENCODER_DT, INPUT);
  pinMode(ENCODER_SW, INPUT);
  pinMode(RELAY_PIN, OUTPUT);

  lcd.init();
  lcd.backlight();

  mPID.SetOutputLimits(0, WindowSize);
  mPID.SetMode(AUTOMATIC);

  if (EEPROM.read(0) == 255 && EEPROM.read(4) == 255) {
    EEPROM.write(0, 10);
    EEPROM.write(1, 0);
    EEPROM.write(2, 240);
    EEPROM.write(3, 65);
  }
  EEPROM.get(0, Counter);
}

void loop() {
  ds.requestTemperatures();
  Temperature = ds.getTempCByIndex(0);
  Input = Temperature;

  mPID.Compute();

  if (digitalRead(ENCODER_SW) == LOW) {
    int newClk = digitalRead(ENCODER_CLK);
    if (newClk != lastClk) {
      lastClk = newClk;
      int dtValue = digitalRead(ENCODER_DT);
      if (newClk == LOW && dtValue == HIGH) {
        Counter += .1;
        if (Counter > TEMP_MAX) Counter = TEMP_MAX;
      }
      if (newClk == LOW && dtValue == LOW) {
        Counter -= .1;
        if (Counter < TEMP_MIN) Counter = TEMP_MIN;
      }
      EEPROM.put(0, Counter);
    }
    lcd.clear();
    lcd.setCursor(8, 0);
    lcd.print(Counter, 1);
    lcd.print("C  ");
  } else {
      lcd.setCursor(0, 0);
      lcd.print(Temperature, 1);
      lcd.print("C  ");
      lcd.setCursor(8, 0);
      lcd.print(Counter, 1);
      lcd.print("C  ");
      lcd.setCursor(0, 1);
      lcd.print(map(Output, 0, WindowSize, 0, 100));
      lcd.print("%  ");
      lcd.setCursor(8, 1);
      lcd.print(Output);
      lcd.print("mS ");
  }
  if (millis() - windowStartTime >= WindowSize) {
    windowStartTime += WindowSize;
    if (windowStartTime > millis()) windowStartTime = 0;
  }
  if (Output < millis() - windowStartTime) digitalWrite(RELAY_PIN, LOW);
  else digitalWrite(RELAY_PIN, HIGH);
}