#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Fonts/FreeSansBold18pt7b.h>
#include <Fonts/FreeSansBold9pt7b.h>
#include <ESP32Servo.h>
#include <HX711.h>
//#include "pitches.h" //audio

const int servoPin = 18;
const long LOADCELL_OFFSET = 50682624;
const long LOADCELL_DIVIDER = 5895655;

Servo servo;
HX711 scale;

#define SCREEN_WIDTH 128 // OLED width,  in pixels
#define SCREEN_HEIGHT 64 // OLED height, in pixels
#define SPEAKER_PIN  27 // buzzer pin

// create an OLED display object connected to I2C
Adafruit_SSD1306 oled(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

int pos = 0; //proměná serva
int ventil = 0; //proměná serva 180 otevřen 0 zavřen
int cil = 950; // požadovaná váha
int cilx = 0;
long stara_vaha = 1000;
int tara = 0;
int prodleva = cil;
boolean auto_c;
int auto_dif = 0;


int text_x = 60;
int text_y = 23;

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


  // initialize OLED display with I2C address 0x3C
  if (!oled.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("failed to start SSD1306 OLED"));
    while (1);
  }
  delay(2000);         // wait two seconds for initializing


  servo.attach(servoPin, 500, 2400); // nastavení serva
  scale.begin(13, 15);

  // load cell factor 5 KG
  scale.set_scale(420.0983);       // TODO you need to calibrate this yourself.
  // reset the scale to zero = 0
  scale.tare(20);

  hlavni_panel();

  pinMode(34, INPUT);    // sets
  pinMode(32, INPUT);    // sets
  pinMode(35, INPUT);    // sets
  pinMode(27, OUTPUT);    // sets
  // pinMode(13, INPUT);    // sets
  //  pinMode(12, OUTPUT);    // sets
  // pinMode(15, OUTPUT);    // sets

  servo_off(0);
  buzzer1();

}


void loop() {
  String vaha;
  int hladina = 62; //dno sklenice
  int poz; // = 45 pozice textu čísel hmotnosti
  int n = 0;
  //Serial.println("OK");
  if (digitalRead(32) == HIGH) {
    Serial.println("Servo 0 OFF");
    Serial.print(ventil);
    buzzer1();
    menu();
  }
  if (digitalRead(35) == HIGH) { // tata
    Serial.println("TARA");
    buzzer1();
    scale.tare(20); // tarra
    delay (1500);
  }
  // start napouštění
  if (digitalRead(34) == HIGH) {
    buzzer1();
    Serial.println("Vaha ON");
    tara = scale.get_units() * 1000;
    // kontrola petížení
    if (tara + cil >= 4990) {
      buzzer1();
      Serial.println("Vaha bude přetižena");
      oled.fillRect(0, 16, 128, 30, BLACK);
      oled.setCursor((0), text_y + 18); // set position to display (x,y)
      oled.print("Max5kg"); // set text
      oled.display();
      for (n = 0; n <= 5; n++) {
        buzzer1();
        delay(100);
      }
      oled.fillRect(0, 16, 128, 30, BLACK);
      hlavni_panel();
      goto konec;
    }
    sklenice();
    scale.tare(20); // tarra
    // cilx = (cil / 100) * prodleva;
    // Serial.print("cilx = ");
    // Serial.println(cilx );
    Serial.println("auto_dif = " + String(auto_dif));
    Serial.println("Prodleva = " + String(prodleva));
    vaha = String(stara_vaha);
    poz = text_x - 25;
    poz = (poz + 18 * 4) - (vaha.length() * 18);
    oled.setCursor(poz, text_y + 20); // smazat starou hodnotu na oled
    oled.setTextColor(BLACK);    // set text color
    oled.setFont(&FreeSansBold18pt7b);
    oled.print(vaha);
    oled.setFont(&FreeSansBold9pt7b);
    oled.setTextSize(1);         // set text size
    oled.setTextColor(WHITE);    // set text color
    oled.setCursor((text_x + 18 * 3), text_y + 18); // set position to display (x,y)
    oled.print("g"); // set text
    oled.setCursor((text_x - 20), text_y + 40);   // set position to display (x,y)
    oled.print("cil " + String(cil)); // set text
    servo_on(180); // otevřít ventil
    ventil = 0;
    //važení do nastavené hodnoty pprodleva
    while (n < prodleva) {
      n = scale.get_units() * 1000; // načítá nové hodnoty
      if (ventil == 0) oled.fillTriangle(6, 0, 25, 0, 15, 10, WHITE); //znak plnění
      poz = text_x - 25; //pozice textu čísel hmotnosti
      hladina = 60 - (n / (cil / 35)); // cíl/ počet linek hladiny
      if (hladina <= 22) hladina = 20;
      oled.fillRect(2, hladina, 29, 62, WHITE);
      //oled.drawLine(1, hladina, 31, hladina, WHITE); //hladina sklenice
      oled.setTextColor(WHITE);    // set text color
      vaha = String(n);
      poz = (poz + 18 * 4) - (vaha.length() * 18);
      oled.setFont(&FreeSansBold18pt7b);
      oled.setCursor(poz, text_y + 20);     // set position to display (x,y)
      Serial.print("v_sen= ");
      Serial.println(scale.get_units(), 2); // čtení váhy na senzoru
      oled.print(vaha); // aktualní váha
      oled.display();
      delay (100);
      oled.setCursor(poz, text_y + 20);
      oled.setTextColor(BLACK);    // set text color
      oled.print(vaha);
      oled.fillTriangle(6, 0, 25, 0, 15, 10, BLACK); //znak plnění
      delay (100);
      oled.display();
      // pauza ve vážení
      if (digitalRead(35) == HIGH) {
        buzzer1();
        if (ventil == 0) {
          servo_off(0); // zavřít ventil
          ventil = 180;
          delay (500);
        }
        else {
          servo_on(180); // otevřít ventil
          ventil = 0;
          delay (500);
        }
      } //

      if (digitalRead(34) == HIGH) {
        buzzer1();
        goto konec;
      }
    }
    // konec vážení

    Serial.println("Vaha OFF");
    servo_off(0); // zavřít ventil
    ventil = 180;
    Serial.println(" AUTO " + String(auto_c));
    delay (1000);
    if (auto_c == true) {
      auto_dif = (scale.get_units() * 1000) - cil;
      prodleva = cil - auto_dif;
      Serial.println("auto_dif = " + String(auto_dif) + "vaha = " + String(scale.get_units() * 1000));
      Serial.println("Prodleva = " + String(prodleva));
      delay (5000);
    }
    else {
      auto_dif = 0;
      prodleva = cil;
    }
konec:
    sklenice_cls();
    stara_vaha = scale.get_units() * 1000;
    // oled.clearDisplay();
    // delay (1000);
  }
  // vaha
  if (stara_vaha != (int (scale.get_units() * 1000))) {
    // oled.fillRect(0, 18, 128, 30, BLACK);
    Serial.print("stara_vaha= "); //
    Serial.println(stara_vaha);
    vaha = String(stara_vaha); //
    poz = text_x - 25;
    poz = (poz + 18 * 4) - (vaha.length() * 18);
    oled.setFont(&FreeSansBold18pt7b);
    oled.setCursor(poz, text_y + 20); // smazat starou hodnotu na oled
    oled.setTextColor(BLACK);    // set text color
    oled.print(vaha);
    oled.display();
    stara_vaha = scale.get_units() * 1000; // načítá nové hodnoty
    vaha = String(stara_vaha);
    poz = text_x - 25;
    poz = (poz + 18 * 4) - (vaha.length() * 18);
    oled.setTextColor(WHITE);
    oled.setCursor(poz, text_y + 20);     // set position to display (x,y)
    Serial.print("sen= ");
    Serial.println(scale.get_units() * 1000); // čtení váhy na senzoru
    Serial.println(vaha); //
    oled.print(vaha); // aktualní váha
    oled.display();
    delay (200);
  }
  delay (200);
}

void sklenice() {
  oled.drawRoundRect(3, 12, 26, 9, 2, WHITE);
  oled.drawRoundRect(1, 20, 30, 43, 3, WHITE);
  oled.drawRoundRect(0, 20, 32, 42, 3, WHITE);
  oled.display();
  Serial.println("Sklenice OK");
}

void sklenice_cls() {
  oled.fillRect(0, 0, 32, 64, BLACK);
  oled.display();
}

void servo_off(int pos) {
  // int pos = 0;
  //servo.write(0);
  Serial.println("servo pos off= " + String(pos));
  for (pos = 0; pos <= 180; pos += 1) {
    servo.write(pos);
    ventil = 180;
    // Serial.print(pos);
    delay(15);
  }
  delay (2000);
}

void servo_on(int pos) {
  //int pos = 180;
  //servo.write(180);
  Serial.println("servo pos on= " + String(pos));
  for (pos = 180; pos >= 0; pos -= 1) {
    servo.write(pos);
    ventil = 0;
    delay(15);
  }
  delay (2000);
}

void hlavni_panel() {
  oled.clearDisplay(); // clear display
  // uvodní obrazovka
  oled.setFont(&FreeSansBold9pt7b);
  oled.setTextSize(1);         // set text size
  oled.setTextColor(WHITE);    // set text color
  oled.setCursor((text_x + 18 * 3), text_y + 18); // set position to display (x,y)
  oled.print("g"); // set text
  oled.setCursor((text_x - 20), text_y + 40);   // set position to display (x,y)
  oled.print("cil " + String(cil)); // set text
  oled.display();
  oled.setFont(&FreeSansBold9pt7b);
  oled.setTextSize(1);         // set text size
  oled.setTextColor(WHITE);    // set text color
  oled.setCursor(55, 12);       // set position to display (x,y)
  oled.println("Vaha"); // set text
  oled.setTextSize(1);         // set text size
  oled.setCursor(55, 22);       // set position to display (x,y)
  oled.display();              // display on OLED
}
void buzzer1() {
  // tone(SPEAKER_PIN, 127, 200);
  // delay(300);
  //for (byte i = 0; i < 10; i++) {
  for (int pitch = 0; pitch <= 255; pitch++) {
    //tone(SPEAKER_PIN, NOTE_C5 + pitch);
    analogWrite(SPEAKER_PIN, pitch);
    delay(1);
  }
  noTone(SPEAKER_PIN);
}
void menu() {
  int menu_p = 1;
  int hodnota = 0;
  int menu_s = 2;
  int hodnota_max = 4900; //maximum vážení
  long cas1 = millis();
  long cas2 = cas1;
  String str_hodnota = "0";
  oled.clearDisplay(); // clear display
  oled.fillRoundRect(0, 0, 128, 18, 6, WHITE);
  oled.setFont(&FreeSansBold9pt7b);
  oled.setTextSize(1);         // set text size
  oled.setTextColor(BLACK);    // set text color
  oled.setCursor(40, 14);       // set position to display (x,y)
  oled.println("MENU"); // set text
  oled.setTextColor(WHITE);
  oled.setCursor(10, 33);       // set position to display (x,y)
  oled.display();
  while (menu_p != 0) { // 0=navrat; 1= cílová váha; 2 = zavírání % z cíle ; 3 = ventil on/off
    cas2 = millis();
    if (digitalRead(34) == HIGH && digitalRead(35) == HIGH ) { //reset na AUTO
      if (menu_p == 2) {
        buzzer1();
        oled.fillRect(0, 35, 128, 64, BLACK);
        oled.setCursor(3, 62);
        buzzer1();
        str_hodnota = " AUTO ";
        hodnota = 0;
        auto_c = true;
        Serial.println(" AUTO dabl " + auto_c);
        delay(3000);
      }
    }
    if (digitalRead(34) == HIGH) { // hodnota -1
      oled.fillRect(0, 35, 128, 64, BLACK);
      if (cas2 - cas1 <= 200) {
        Serial.println(cas1);
        Serial.println(cas2);
        Serial.println(cas2 + cas1);
        hodnota = hodnota - 25;
      }
      else {
        buzzer1();
        hodnota = hodnota - 1;
      }
      if (menu_p == 3 && ventil == 0) {
        servo_off(0); // zavřít ventil
        ventil = 180;
      }
      if (hodnota <= -1) hodnota = hodnota_max;
      Serial.print("hodnota - ");
      Serial.println(hodnota);
      delay (200);
      cas1 = millis();
      //cas2 = millis();
    }
    if (digitalRead(35) == HIGH) {  // hodnota +1
      oled.fillRect(0, 35, 128, 64, BLACK);
      if (cas2 - cas1 <= 200) {
        Serial.println(cas1);
        Serial.println(cas2);
        Serial.println(cas2 + cas1);
        hodnota = hodnota + 25;
      }
      else {
        buzzer1();
        hodnota = hodnota + 1;
      }
      if (menu_p == 3 && ventil == 180) {
        servo_on(180); // otevřít ventil
        ventil = 0;
      }
      if (hodnota >= hodnota_max + 1) hodnota = 0;
      Serial.print("hodnota + ");
      Serial.println(hodnota);
      delay (200);
      cas1 = millis();
    }
    //delay(500);
    if (digitalRead(32) == HIGH) { // přepínání v MENU
      buzzer1();
      menu_p = menu_p + 1;
      // if (menu_p >= 5) menu_p = 1;
      Serial.print("menu = ");
      Serial.println(menu_p);
      oled.display();
    }
    if (menu_s != menu_p) {
      Serial.println(menu_p);
      oled.setFont(&FreeSansBold9pt7b);
      oled.fillRect(0, 20, 128, 64, BLACK);
      oled.setCursor(10, 33);       // set position to display (x,y)
      // oled.setTextColor(WHITE);
      oled.setCursor(10, 33);       // set position to display (x,y)
      switch (menu_p) {
        case 1:
          hodnota = cil;
          // hodnota_max = 4900;
          //Serial.println(menu_p);
          oled.println("cilova vaha"); // set text
          break;
        case 2:
          cil = hodnota;
          if (hodnota != 0) auto_c = false;
          hodnota = prodleva;
          // hodnota_max = cil;
          oled.println("zavirani pri"); // set text
          break;
        case 3:
          if (hodnota != 0) prodleva = hodnota;
          hodnota = ventil;
          oled.println("ventil"); // set text
          //if (ventil==0) oled.println("ZAVREN"); // set text
          // else oled.println("OTEVREN");
          break;
      }
      menu_s = menu_p;
      oled.display();
    }
    if (menu_p >= 4) menu_p = 0;
    oled.setFont(&FreeSansBold18pt7b); //zpět na velký font
    oled.setCursor(3, 62);       // set position to display (x,y)
    str_hodnota = String(hodnota);
    if (menu_p == 3) {
      oled.setTextSize(1);         // set text size
      oled.setFont(&FreeSansBold9pt7b); //zpět na velký font
      if (ventil == 180) str_hodnota = "ZAVREN " + String(ventil); // set text
      else str_hodnota = "OTEVREN " + String(ventil);
    }
    if (menu_p == 2 && hodnota == 0) {
      oled.fillRect(0, 35, 128, 64, BLACK);
      oled.setCursor(3, 62);
      str_hodnota = " AUTO ";
      auto_c = true;
      auto_dif = 0;
      prodleva = cil;
      Serial.println(" AUTO " + String(auto_c));
      Serial.println("auto_dif = " + String(auto_dif));
      Serial.println("Prodleva_menu = " + String(prodleva));
    }
    oled.println(str_hodnota); // set text
    oled.display();
  }
  oled.clearDisplay(); // clear display
  hlavni_panel();
  stara_vaha = 10;
  // oled.println("konec MENU"); // set text
}

//hrdlo david 38mm vnitřní 34,6mm
// the SDA (D6/GPIO14) and SCL (D5/GPIO12) pins.