#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>


#define L1_out  9
#define L1_up   8
#define L1_down 7
#define L1_in   6

#define L2_out  5
#define L2_up   4
#define L2_down 3
#define L2_in   2

#define STOP_LED 13

#define BTN_STARTSTOP A0
#define BTN_EEPROM_RESET A1

#define TOUT    10000   //ms
#define TUP     15000
#define TDOWN   15000
#define TIN     10000  


LiquidCrystal_I2C lcd(0x27,20,4);

enum States {
  STOPPED,
  BOTTOM_OUT,
  UP,
  TOP_IN,
  TOP_OUT,
  DOWN,
  BOTTOM_IN,
};

States state;

bool stateChangedFlag = false;
bool ButtonPressed = false;

uint32_t t_out = TOUT;
uint32_t t_up = TUP;
uint32_t t_down = TDOWN;
uint32_t t_in = TIN;
uint32_t currentTime;
uint32_t stateTime = 0;
float restTime = 0;
uint32_t stateDur;
int counter;
int counterZero = 0;
uint32_t displayRefresh = 200;  //ms
uint32_t lastDisplayRefresh = 0; 

void setup() {
  Serial.begin(9600);
  EEPROM.begin();
  lcd.init();  
  lcd.backlight();
  pinMode(L1_out, OUTPUT);
  pinMode(L1_up, OUTPUT);
  pinMode(L1_down, OUTPUT);
  pinMode(L1_in, OUTPUT);
  pinMode(L2_out, OUTPUT);
  pinMode(L2_up, OUTPUT);
  pinMode(L2_down, OUTPUT);
  pinMode(L2_in, OUTPUT);
  pinMode(STOP_LED, OUTPUT);
  pinMode(BTN_STARTSTOP, INPUT);
  
  // EEPROM read / reset
  if(digitalRead(BTN_EEPROM_RESET) == LOW)
    EEPROM.put(1020, counterZero);
  else
    EEPROM.get(1020, counter);
  
  switchOffRelais();
  changeState(STOPPED);
  digitalWrite(STOP_LED, HIGH);

}

void loop() {

  currentTime = millis();

  if (digitalRead(BTN_STARTSTOP) == LOW) {                            
    ButtonPressed = true;
    delay(10);
  }
  if (digitalRead(BTN_STARTSTOP) == HIGH && ButtonPressed == true) {
    ButtonPressed = false;
      if(state == STOPPED) {
        changeState(BOTTOM_OUT);
        digitalWrite(STOP_LED, LOW);
        Serial.println("Start");
      }
      else {
        changeState(STOPPED);
        digitalWrite(STOP_LED, HIGH);
        Serial.println("Stopped");
      }
    }

  


  switch (state) {
    case STOPPED:
      if(stateChangedFlag) {  //Execute once
        lcd.setCursor(0,0);
        stateChangedFlag = false;
      }
    break;

    case BOTTOM_OUT:
      if(stateChangedFlag) {  //Execute once
        digitalWrite(L1_out, HIGH);
        digitalWrite(L2_out, HIGH);
        stateDur = t_out;
        stateChangedFlag = false;
      }
      if(currentTime - stateTime >= t_out)
        changeState(UP);
    break;

    case UP:
      if(stateChangedFlag) {  //Execute once
        digitalWrite(L1_up, HIGH);
        digitalWrite(L2_up, HIGH);
        stateDur = t_up;
        stateChangedFlag = false;
      }
      if(currentTime - stateTime >= t_up)
        changeState(TOP_IN);
    break;

    case TOP_IN:
      if(stateChangedFlag) {  //Execute once
        digitalWrite(L1_in, HIGH);
        digitalWrite(L2_in, HIGH);
        stateDur = t_in;
        stateChangedFlag = false;
      }
      if(currentTime - stateTime >= t_in)
        changeState(TOP_OUT);
    break;

    case TOP_OUT:
      if(stateChangedFlag) {  //Execute once
        digitalWrite(L1_out, HIGH);
        digitalWrite(L2_out, HIGH);
        stateDur = t_out;
        stateChangedFlag = false;
      }
      if(currentTime - stateTime >= t_out)
        changeState(DOWN);
    break;

    case DOWN:
      if(stateChangedFlag) {  //Execute once
        digitalWrite(L1_down, HIGH);
        digitalWrite(L2_down, HIGH);
        stateDur = t_down;
        stateChangedFlag = false;
      }
      if(currentTime - stateTime >= t_down)
        changeState(BOTTOM_IN);
    break;

    case BOTTOM_IN:
      if(stateChangedFlag) {  //Execute once
        digitalWrite(L1_in, HIGH);
        digitalWrite(L2_in, HIGH);
        stateDur = t_in;
        stateChangedFlag = false;
      }
      if(currentTime - stateTime >= t_in) {
        changeState(BOTTOM_OUT);
        counter+=2;
        writeEEPROM();    // write counter to EEPROM
        updateDisplay();
        Serial.print("Counter: ");
        Serial.println(counter);
      }
    break;
  }

  if(millis()-lastDisplayRefresh >= displayRefresh){
    lastDisplayRefresh = millis();
    updateDisplay();
    }
}


void changeState(States nextState) {
  // Switch off all relays
  switchOffRelais();
  state = nextState;
  stateTime = currentTime;
  stateChangedFlag = true;

  updateDisplay();
}


void switchOffRelais() {
  digitalWrite(L1_out, LOW);
  digitalWrite(L1_up, LOW);
  digitalWrite(L1_down, LOW);
  digitalWrite(L1_in, LOW);
  digitalWrite(L2_out, LOW);
  digitalWrite(L2_up, LOW);
  digitalWrite(L2_down, LOW);
  digitalWrite(L2_in, LOW);
}


void updateDisplay() {
  lcd.clear();
  
  //State
  lcd.setCursor(0,0);
  switch(state) {
  case STOPPED:
  lcd.print("Stop");
  break;
  case BOTTOM_OUT:
  lcd.print("Raus");
  break;
  case UP:
  lcd.print("Hoch");
  break;
  case TOP_IN:
  lcd.print("Rein");
  break;
  case TOP_OUT:
  lcd.print("Raus");
  break;
  case DOWN:
  lcd.print("Runter");
  break;
  case BOTTOM_IN:
  lcd.print("Rein");
  break;
  }

  switch(state) {
  case STOPPED:
    lcd.setCursor(7,0);
    lcd.print("R:-");
  break;
  default:
    lcd.setCursor(7,0);
    lcd.print("R:");
    restTime = (stateDur - (currentTime - stateTime))/1000.0;
    lcd.setCursor(9,0);
    lcd.print(restTime);
    lcd.print("s");
    break;
  }

  lcd.setCursor(0,1);
  lcd.print("Zaehler: ");
  lcd.setCursor(9,1);
  lcd.print(counter);

}

void writeEEPROM() {
  EEPROM.put(1020, counter);
}
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module