//============================================================ Deklarasi Library ===========================================================
#include <LiquidCrystal_I2C.h> //Pemanggilan Library LiquidCrystal_I2C


//======================================================= Inisialisasi: Constructor ========================================================
LiquidCrystal_I2C lcd(0x27, 16, 2); //Constructor LiquidCrystal_I2C


//===================================================== Deklarasi Variabel: Tipe Data ======================================================
//Tipe data Float
float adc_phSensor, x, a, b;
float y, old_pHValue = 0, pHValue;
float pHair_Upper, pHair_Lower;
float AKU, AKL, ALU, ALL, NU, NL, BLU, BLL, BKU, BKL;
float SigyiMiuMFUpper, SigyiMiuMFLower, SigMiuMFUpper, SigMiuMFLower, yl, yr;
float MiuUMF[5], MiuLMF[5];

//Tipe data Int
int i, yi, ycos, yout, Tarray1, Tarray2; 
int SPK[5]; 

//Tipe data String
String statusPH, statusBuzzer, statusRelaypH; 

//Tipe data Boolean
bool relayON = LOW;
bool relayOFF = HIGH;
bool ispHUpOn = false;
bool ispHDownOn = false;
bool isBuzzerOn = false;
bool ispHUp10SecondFinished = false;
bool ispHUp25SecondFinished = false;
bool ispHDown10SecondFinished = false;
bool ispHDown25SecondFinished = false;
bool isBuzzer2SecondFinished = false;
bool isBuzzer3SecondFinished = false;

//Tipe data Unsigned
unsigned long currentMillis;
unsigned long startTime1 = 0;
unsigned long startTime2 = 0;
const unsigned long delayTime1 = 1000;
const unsigned long delayTime2 = 5000;
unsigned long svalveStartTime1 = 0;
unsigned long svalveStartTime2 = 0;
const unsigned long svalveDuration1 = 10000;
const unsigned long svalveDuration2 = 25000;


//============================================================= Define Variabel ============================================================
#define PBuzzer 2 //Pin Kaki Piezo Buzzer
#define PoPin 35 //Pin Kaki pH Sensor (Po)
#define SValve1 5 //Pin Kaki pH Up
#define SValve2 18 //Pin Kaki pH Down


//============================================================== Method Setup ===============================================================
void setup(){
  RELAYinit(); //Memanggil method RELAYinit
  LCDinit(); //Memanggil method LCDinit
  Serial.begin(9600); //Memulai komunikasi serial dengan baud rate 9600
  Loading(); //LCD view Loading
  pinMode(PBuzzer, OUTPUT); //Inisialisasi pin sebagai OUTPUT

  //Atur waktu agar fungsi millis langsung menyala
  startTime1 = millis() - delayTime1;
  startTime2 = millis() - delayTime2;
  svalveStartTime1 = millis() - svalveDuration1;
  svalveStartTime2 = millis() - svalveDuration2;
}


//============================================================== Method Loop ===============================================================
void loop(){
  //Ambil waktu saat ini
  currentMillis = millis();

  //Jika waktu sekarang dikurangi waktu terakhir lebih besar dari 1 detik maka :
  if ((currentMillis - startTime1) > delayTime1) {
    readPublishPH(); //Memanggil method readPublishPH    
    startTime1 = currentMillis; //Perbarui waktu terakhir dijalankan
  }
}


//============================================================= Method LCD Init ============================================================
void LCDinit(){
  //Memulai komunikasi serial dengan LCD
  lcd.init();
  //Start LCD
  lcd.clear(); lcd.backlight(); lcd.setCursor(1,0); lcd.print("Memulai"); lcd.setCursor(1,1); lcd.print("Sistem pH..."); delay(1000);
  //Welcome LCD
  lcd.clear(); lcd.backlight(); lcd.setCursor(1,0); lcd.print("Welcome to"); lcd.setCursor(1,1); lcd.print("PHIOTNET...."); delay(1000);
}


//============================================================ Method RELAY Init ===========================================================
void RELAYinit(){
  pinMode(SValve1, OUTPUT); //Inisialisasi pin sebagai output
  pinMode(SValve2, OUTPUT); //Inisialisasi pin sebagai output
  all_pH_off(); //Default relay untuk pertama kali harus off
}


//============================================================== Method Read pH ============================================================
void readPublishPH(){
  adc_phSensor = analogRead(PoPin); //Membaca ADC Sensor pH
  x = adc_phSensor * (5.0 / 4095.0); //Nilai tegangan murni
  a = 21.84; b = -5.27; //Linear Regression Value
  y = a + b * x; //pH Value

  //Set point atas dan bawah
  if(y > 14.00) { y = 14.00; } 
  else if (y < 0.00) { y = 0.00; }
  
  pHValue = y; //Menyimpan nilai ke variabel pHValue

  //Cek nilai pH ada perubahan atau tidak, jika ada perubahan maka:
  if(pHValue != old_pHValue){
    IT2FL_pH(); //Memanggil method IT2FL_pH
    old_pHValue = pHValue; //Menyimpan nilai pH saat ini ke variabel old_pHValue
  }
}


//============================================================ Method Output LCD ===========================================================
void Loading(){
  lcd.clear(); lcd.backlight(); lcd.setCursor(1,0); lcd.print("Loading...."); delay(5000); Waiting();
}
void Waiting(){
  lcd.clear(); lcd.backlight(); lcd.setCursor(1,0); lcd.print("Menunggu"); lcd.setCursor(1,1); lcd.print("Perintah..."); delay(1000);
}
void LCDfailIoT(){
  lcd.clear(); lcd.backlight(); lcd.setCursor(1,0); lcd.print("IoT Gagal"); lcd.setCursor(1,1); lcd.print("Tersambung..."); delay(5000);
}
void LCDfailBot(){
  lcd.clear(); lcd.backlight(); lcd.setCursor(1,0); lcd.print("Bot Gagal"); lcd.setCursor(1,1); lcd.print("Tersambung..."); delay(5000);
}
void Viewnow(){
  //Jika waktu sekarang dikurangi waktu terakhir lebih besar sama dengan 1 detik maka :
  if ((currentMillis - startTime1) >= delayTime1) {
    lcd.clear(); lcd.backlight(); lcd.setCursor(2,0); lcd.print("pH Air : "+ String(pHValue));
    startTime1 = currentMillis; //Perbarui waktu terakhir dijalankan
  } Waiting();
}
void LCDAllpHON(){
  //Jika waktu sekarang dikurangi waktu terakhir lebih besar sama dengan 5 detik maka :
  if ((currentMillis - startTime2) >= delayTime2) {
    lcd.clear(); lcd.backlight(); lcd.setCursor(4,0); lcd.print("All pH :"); lcd.setCursor(6,1); lcd.print("(ON)");
    startTime2 = currentMillis; //Perbarui waktu terakhir dijalankan
  } Waiting();
}
void LCDAllpHOFF(){
  //Jika waktu sekarang dikurangi waktu terakhir lebih besar sama dengan 5 detik maka :
  if ((currentMillis - startTime2) >= delayTime2) {
    lcd.clear(); lcd.backlight(); lcd.setCursor(4,0); lcd.print("All pH :"); lcd.setCursor(5,1); lcd.print("(OFF)");
    startTime2 = currentMillis; //Perbarui waktu terakhir dijalankan
  } Waiting();
}
void LCDpHUpON(){
  //Jika waktu sekarang dikurangi waktu terakhir lebih besar sama dengan 5 detik maka :
  if ((currentMillis - startTime2) >= delayTime2) {
    lcd.clear(); lcd.backlight(); lcd.setCursor(4,0); lcd.print("pH Up :"); lcd.setCursor(6,1); lcd.print("(ON)");
    startTime2 = currentMillis; //Perbarui waktu terakhir dijalankan
  } Waiting();
}
void LCDpHUpOFF(){
  //Jika waktu sekarang dikurangi waktu terakhir lebih besar sama dengan 5 detik maka :
  if ((currentMillis - startTime2) >= delayTime2) {
    lcd.clear(); lcd.backlight(); lcd.setCursor(4,0); lcd.print("pH Up :"); lcd.setCursor(5,1); lcd.print("(OFF)");
    startTime2 = currentMillis; //Perbarui waktu terakhir dijalankan
  } Waiting();
}
void LCDpHDownON(){
  //Jika waktu sekarang dikurangi waktu terakhir lebih besar sama dengan 5 detik maka :
  if ((currentMillis - startTime2) >= delayTime2) {
    lcd.clear(); lcd.backlight(); lcd.setCursor(4,0); lcd.print("pH Down:"); lcd.setCursor(6,1); lcd.print("(ON)");
    startTime2 = currentMillis; //Perbarui waktu terakhir dijalankan
  } Waiting();
}
void LCDpHDownOFF(){
  //Jika waktu sekarang dikurangi waktu terakhir lebih besar sama dengan 5 detik maka :
  if ((currentMillis - startTime2) >= delayTime2) {
    lcd.clear(); lcd.backlight(); lcd.setCursor(4,0); lcd.print("pH Down:"); lcd.setCursor(6,1); lcd.print("(OFF)");
    startTime2 = currentMillis; //Perbarui waktu terakhir dijalankan
  } Waiting();
}


//========================================================= Method Output Relay pH =======================================================
void pH_up_onlm() { //Method pH Up On 25 detik -> dengan fungsi millis
  //Jika Valve pH Up belum menyala, maka :
  if (!ispHUpOn) {
    pH_up_on(); //Memanggil fungsi untuk menyalakan pH Up
    svalveStartTime2 = currentMillis; //Perbarui waktu terakhir pH Up dinyalakan
    ispHUpOn = true; //Perbarui status pH Up
  } else {
    //Periksa apakah durasinya sudah berlalu
    if ((currentMillis - svalveStartTime2) >= svalveDuration2) {
      pH_up_off(); //Memanggil fungsi untuk mematikan pH Up
      ispHUpOn = false; //Perbarui status pH Up
      ispHUp25SecondFinished = true; //Tandai fungsi millis pH Up selesai
    }
  }
}
void pH_up_onsd() { //Method pH Up On 10 detik -> dengan fungsi millis
  //Jika Valve pH Up belum menyala, maka :
  if (!ispHUpOn) {
    pH_up_on(); //Memanggil fungsi untuk menyalakan pH Up
    svalveStartTime1 = currentMillis; //Perbarui waktu terakhir pH Up dinyalakan
    ispHUpOn = true; //Perbarui status pH Up
  } else {
    //Periksa apakah durasinya sudah berlalu
    if ((currentMillis - svalveStartTime1) >= svalveDuration1) {
      pH_up_off(); //Memanggil fungsi untuk mematikan pH Up
      ispHUpOn = false; //Perbarui status pH Up
      ispHUp10SecondFinished = true; //Tandai fungsi millis pH Up selesai
    }
  }
}
void pH_up_on() { //Method pH Up on : On/Off Controller
  digitalWrite(SValve1, relayON);    //Nyalakan Solenoid Valve 1
}
void pH_up_off() { //Method pH Up off : On/Off Controller
  digitalWrite(SValve1, relayOFF);   //Matikan Solenoid Valve 1
}
void all_pH_on() { //Method pH Up dan pH Down on : On/Off Controller
  digitalWrite(SValve1, relayON); digitalWrite(SValve2, relayON);     //Nyalakan Semua Solenoid Valve
}
void all_pH_off() { //Method pH Up dan pH Down off : On/Off Controller
  digitalWrite(SValve1, relayOFF); digitalWrite(SValve2, relayOFF);   //Matikan Semua Solenoid Valve
}
void pH_down_on() { //Method pH Down on : On/Off Controller
  digitalWrite(SValve2, relayON);    //Nyalakan Solenoid Valve 2
}
void pH_down_off() { //Method pH Down off : On/Off Controller
  digitalWrite(SValve2, relayOFF);   //Matikan Solenoid Valve 2
}
void pH_down_onsd() { //Method pH Down On 10 detik -> dengan fungsi millis
  //Jika Valve pH Down belum menyala, maka :
  if (!ispHDownOn) {
    pH_down_on(); //Memanggil fungsi untuk menyalakan pH Down
    svalveStartTime1 = currentMillis; //Perbarui waktu terakhir pH Down dinyalakan
    ispHDownOn = true; //Perbarui status pH Down
  } else {
    //Periksa apakah durasinya sudah berlalu
    if ((currentMillis - svalveStartTime1) >= svalveDuration1) {
      pH_down_off(); //Memanggil fungsi untuk mematikan pH Down
      ispHDownOn = false; //Perbarui status pH Down
      ispHDown10SecondFinished = true; //Tandai fungsi millis pH Down selesai
    }
  }
}
void pH_down_onlm() { //Method pH Down On 25 detik -> dengan fungsi millis
  //Jika Valve pH Down belum menyala, maka :
  if (!ispHDownOn) {
    pH_down_on(); //Memanggil fungsi untuk menyalakan pH Down
    svalveStartTime2 = currentMillis; //Perbarui waktu terakhir pH Down dinyalakan
    ispHDownOn = true; //Perbarui status pH Down
  } else {
    //Periksa apakah durasinya sudah berlalu
    if ((currentMillis - svalveStartTime2) >= svalveDuration2) {
      pH_down_off(); //Memanggil fungsi untuk mematikan pH Down
      ispHDownOn = false; //Perbarui status pH Down
      ispHDown25SecondFinished = true; //Tandai fungsi millis pH Down selesai
    }
  }
}


//============================================================= Method Alarm =============================================================
void B2() { //Method alarm 2x bunyi : On/Off Controller
  if (!isBuzzerOn) { //Jika Buzzer belum menyala, maka :
    if (i < 2) { //Pastikan Buzzer belum berbunyi 2 kali dan lakukan :
      isBuzzerOn = !isBuzzerOn; //Penukaran status buzzer
      digitalWrite(PBuzzer, isBuzzerOn ? HIGH : LOW); //Nyalakan atau Matikan buzzer
      if (!isBuzzerOn) { //Jika buzzer baru saja mati, maka lakukan :
        i++; //Increment
      }
      startTime1 = currentMillis; //Perbarui waktu terakhir Buzzer dinyalakan
    }
  } else {
    //Periksa apakah durasinya sudah berlalu
    if ((currentMillis - startTime1) >= delayTime1) {      
      digitalWrite(PBuzzer, LOW); //Matikan buzzer
      isBuzzer2SecondFinished = true; //Tandai fungsi millis Buzzer selesai
    }
  }
}
void B3() { //Method alarm 3x bunyi : On/Off Controller
  if (!isBuzzerOn) { //Jika Buzzer belum menyala, maka :
    if (i < 3) { //Pastikan Buzzer belum berbunyi 3 kali dan lakukan :
      isBuzzerOn = !isBuzzerOn; //Penukaran status buzzer
      digitalWrite(PBuzzer, isBuzzerOn ? HIGH : LOW); //Nyalakan atau Matikan buzzer
      if (!isBuzzerOn) { //Jika buzzer baru saja mati, maka lakukan :
        i++; //Increment
      }
      startTime1 = currentMillis; //Perbarui waktu terakhir Buzzer dinyalakan
    }
  } else {
    //Periksa apakah durasinya sudah berlalu
    if ((currentMillis - startTime1) >= delayTime1) {      
      digitalWrite(PBuzzer, LOW); //Matikan buzzer
      isBuzzer3SecondFinished = true; //Tandai fungsi millis Buzzer selesai
    }
  }
}
    

//================================================== Method Interval Type 2 Fuzzy Logic ==================================================
void IT2FL_pH(){
  Serial.println("\n[Interval Type 2 Fuzzy Logic]\nproses fuzzifikasi :"); 
  Serial.println("\nDeteksi pH: " + String(pHValue, 2));
  pHair_Upper = float(pHValue); //Memasukkan nilai pH ke Himpunan atas
  pHair_Lower = float(pHValue); //Memasukkan nilai pH ke Himpunan bawah
  fuzz_it2fl(); //Memanggil Method Fuzzifikasi
  Serial.println("\nproses inferensi :"); 
  infer_it2fl(); //Memanggil Method Inferensi
  Serial.println("\nproses reduksi tipe & defuzzifikasi :"); 
  redukdefuzz_it2fl(); //Memanggil Method Reduksi Tipe dan Defuzzifikasi
  Serial.println("\n==================================================================================");
  reset_redukdeffuzz();
}

//========================================================= Method Fuzzifikasi ===========================================================
void MF_AsamKuat(){ //Fungsi Keanggotaan Asam Kuat
  //MF-Upper : Asam Kuat
  if(pHair_Upper <= 0){
    AKU = 1; Serial.print("Nilai AK-Upper: " + String(AKU));
  }
  else if(pHair_Upper > 0 && pHair_Upper < 3){
    AKU = (3 - pHair_Upper)/(3 - 0); Serial.print("Nilai AK-Upper: " + String(AKU));
  }
  else if(pHair_Upper >= 3){
    AKU = 0; Serial.print("Nilai AK-Upper: " + String(AKU));
  } 

  //MF-Lower : Asam Kuat
  if(pHair_Lower <= 0){
    AKL = 1; Serial.println(" , Nilai AK-Lower: " + String(AKL));
  }
  else if(pHair_Lower > 0 && pHair_Lower < 2.8){
    AKL = (2.8 - pHair_Lower)/(2.8 - 0); Serial.println(" , Nilai AK-Lower: " + String(AKL));
  }
  else if(pHair_Lower >= 2.8){
    AKL = 0; Serial.println(" , Nilai AK-Lower: " + String(AKL));
  } 
}

void MF_AsamLemah(){ //Fungsi Keanggotaan Asam Lemah
  //MF-Upper : Asam Lemah
  if(pHair_Upper <= 3 || pHair_Upper >= 6){
    ALU = 0; Serial.print("Nilai AL-Upper: " + String(ALU));
  }
  else if(pHair_Upper > 3 && pHair_Upper <= 4.5){
    ALU = (pHair_Upper - 3)/(4.5 - 3);
    Serial.print("Nilai AL-Upper: " + String(ALU));
  }
  else if(pHair_Upper > 4.5 && pHair_Upper < 6){
    ALU = (6 - pHair_Upper)/(6 - 4.5);
    Serial.print("Nilai AL-Upper: " + String(ALU));
  } 

  //MF-Lower : Asam Lemah
  if(pHair_Lower <= 3.2 || pHair_Lower >= 5.8){
    ALL = 0; Serial.println(" , Nilai AL-Lower: " + String(ALL));
  }
  else if(pHair_Lower > 3.2 && pHair_Lower <= 4.5){
    ALL = (pHair_Lower - 3.2)/(4.5 - 3.2);
    Serial.println(" , Nilai AL-Lower: " + String(ALL));
  }
  else if(pHair_Lower > 4.5 && pHair_Lower < 5.8){
    ALL = (5.8 - pHair_Lower)/(5.8 - 4.5);
    Serial.println(" , Nilai AL-Lower: " + String(ALL));
  } 
}

void MF_Netral(){ //Fungsi Keanggotaan Netral
  //MF-Upper : Netral
  if(pHair_Upper <= 6 || pHair_Upper >= 8){
    NU = 0; Serial.print("Nilai N-Upper: " + String(NU));
  }
  else if(pHair_Upper > 6 && pHair_Upper <= 7){
    NU = (pHair_Upper - 6)/(7 - 6);
    Serial.print("Nilai N-Upper: " + String(NU));
  }
  else if(pHair_Upper > 7 && pHair_Upper < 8){
    NU = (8 - pHair_Upper)/(8 - 7);
    Serial.print("Nilai N-Upper: " + String(NU));
  } 

  //MF-Lower : Netral
  if(pHair_Lower <= 6.2 || pHair_Lower >= 7.8){
    NL = 0; Serial.println(" , Nilai N-Lower: " + String(NL));
  }
  else if(pHair_Lower > 6.2 && pHair_Lower <= 7){
    NL = (pHair_Lower - 6.2)/(7 - 6.2);
    Serial.println(" , Nilai N-Lower: " + String(NL));
  }
  else if(pHair_Lower > 7 && pHair_Lower < 7.8){
    NL = (7.8 - pHair_Lower)/(7.8 - 7);
    Serial.println(" , Nilai N-Lower: " + String(NL));
  } 
}

void MF_BasaLemah(){ //Fungsi Keanggotaan Basa Lemah
  //MF-Upper : Basa Lemah
  if(pHair_Upper <= 8 || pHair_Upper >= 10){
    BLU = 0; Serial.print("Nilai BL-Upper: " + String(BLU));
  }
  else if(pHair_Upper > 8 && pHair_Upper <= 9){
    BLU = (pHair_Upper - 8)/(9 - 8);
    Serial.print("Nilai BL-Upper: " + String(BLU));
  }
  else if(pHair_Upper > 9 && pHair_Upper < 10){
    BLU = (10 - pHair_Upper)/(10 - 9);
    Serial.print("Nilai BL-Upper: " + String(BLU));
  } 

  //MF-Lower : Basa Lemah
  if(pHair_Lower <= 8.2 || pHair_Lower >= 9.8){
    BLL = 0; Serial.println(" , Nilai BL-Lower: " + String(BLL));
  }
  else if(pHair_Lower > 8.2 && pHair_Lower <= 9){
    BLL = (pHair_Lower - 8.2)/(9 - 8.2);
    Serial.println(" , Nilai BL-Lower: " + String(BLL));
  }
  else if(pHair_Lower > 9 && pHair_Lower < 9.8){
    BLL = (9.8 - pHair_Lower)/(9.8 - 9);
    Serial.println(" , Nilai BL-Lower: " + String(BLL));
  } 
}

void MF_BasaKuat(){ //Fungsi Keanggotaan Basa Kuat
  //MF-Upper : Basa Kuat
  if(pHair_Upper <= 10){
    BKU = 0; Serial.print("Nilai BK-Upper: " + String(BKU));
  }
  else if(pHair_Upper > 10 && pHair_Upper < 14){
    BKU = (pHair_Upper - 10)/(14 - 10);
    Serial.print("Nilai BK-Upper: " + String(BKU));
  }
  else if(pHair_Upper >= 14){
    BKU = 1; Serial.print("Nilai BK-Upper: " + String(BKU));
  } 

  //MF-Lower : Basa Kuat
  if(pHair_Lower <= 10.2){
    BKL = 0; Serial.println(" , Nilai BK-Lower: " + String(BKL));
  }
  else if(pHair_Lower > 10.2 && pHair_Lower < 14){
    BKL = (pHair_Lower - 10.2)/(14 - 10.2);
    Serial.println(" , Nilai BK-Lower: " + String(BKL));
  }
  else if(pHair_Lower >= 14){
    BKL = 1; Serial.println(" , Nilai BK-Lower: " + String(BKL));
  } 
}

void fuzz_it2fl(){
  MF_AsamKuat(); //Memanggil Method Fungsi Keanggotaan Asam Kuat
  MF_AsamLemah(); //Memanggil Method Fungsi Keanggotaan Asam Lemah
  MF_Netral(); //Memanggil Method Fungsi Keanggotaan Netral
  MF_BasaLemah(); //Memanggil Method Fungsi Keanggotaan Basa Lemah
  MF_BasaKuat(); //Memanggil Method Fungsi Keanggotaan Basa Kuat
}


//=========================================================== Method Inferensi ===========================================================
void infer_it2fl(){
  //Proposisi Tunggal Upper => Penalaran Monoton
  MiuUMF[0] = AKU; MiuUMF[1] = ALU; MiuUMF[2] = NU; MiuUMF[3] = BLU; MiuUMF[4] = BKU;

  //Proposisi Tunggal Lower => Penalaran Monoton
  MiuLMF[0] = AKL; MiuLMF[1] = ALL; MiuLMF[2] = NL; MiuLMF[3] = BLL; MiuLMF[4] = BKL;

  //Cetak MF-Upper dan MF-Lower
  Serial.print("AK-Upper terkecil = " + String(MiuUMF[0])); Serial.println(" , AK-Lower terkecil = " + String(MiuLMF[0]));
  Serial.print("AL-Upper terkecil = " + String(MiuUMF[1])); Serial.println(" , AL-Lower terkecil = " + String(MiuLMF[1]));
  Serial.print("N-Upper terkecil = " + String(MiuUMF[2])); Serial.println(" , N-Lower terkecil = " + String(MiuLMF[2]));
  Serial.print("BL-Upper terkecil = " + String(MiuUMF[3])); Serial.println(" , BL-Lower terkecil = " + String(MiuLMF[3]));
  Serial.print("BK-Upper terkecil = " + String(MiuUMF[4])); Serial.println(" , BK-Lower terkecil = " + String(MiuLMF[4]));
  
  //Pengambilan Keputusan yang ditentukan
  SPK[0] = 0; //untuk : ON Relay pH Up Lama (25 detik)
  SPK[1] = 1; //untuk : ON Relay pH Up Sedang (10 detik)
  SPK[2] = 2; //untuk : OFF semua Relay pH (0 detik)
  SPK[3] = 3; //untuk : ON Relay pH Down Sedang (10 detik) 
  SPK[4] = 4; //untuk : ON Relay pH Down Lama (25 detik)
}


//============================================= Method Reduksi Tipe & Defuzzifikasi ======================================================
void redukdefuzz_it2fl(){
  //Menjumlah total array yang ada pada MF-Upper dan MF-Lower
  Tarray1 = sizeof(MiuUMF) / sizeof(int);
  Tarray2 = sizeof(MiuLMF) / sizeof(int);

  //Perhitungan himpunan atas
  for(i=0; i<Tarray1; i++){
    yi += SPK[i];
    SigyiMiuMFUpper += SPK[i] * MiuUMF[i];
    SigMiuMFUpper += MiuUMF[i];
  }

  //Perhitungan himpunan bawah
  for(i=0; i<Tarray2; i++){
    yi += SPK[i];
    SigyiMiuMFLower += SPK[i] * MiuLMF[i];
    SigMiuMFLower += MiuLMF[i];
  }

  //Perhitungan reduksi tipe
  //Interval kiri
  yl = ((SigyiMiuMFUpper + SigyiMiuMFLower)/(SigMiuMFLower + SigMiuMFUpper));
  Serial.println("yl = (" + String(SigyiMiuMFUpper) + " + " + String(SigyiMiuMFLower) + ") / (" + String(SigMiuMFLower) + " + " + String(SigMiuMFUpper) + ") = " + yl);
  //Interval kanan
  yr = ((SigyiMiuMFLower + SigyiMiuMFUpper)/(SigMiuMFUpper + SigMiuMFLower));
  Serial.println("yr = (" + String(SigyiMiuMFLower) + " + " + String(SigyiMiuMFUpper) + ") / (" + String(SigMiuMFUpper) + " + " + String(SigMiuMFLower) + ") = " + yr);

  //Perhitungan deffuzifikasi
  ycos = yl + yr;
  yout = floor((ycos)/2);
  Serial.println("yout = (" + String(yl) + " + " + String(yr) + ") / 2 = " + String(yout));

  //Nilai crips berdasarkan pengambilan keputusan
  if(yout == 0){
    statusPH = "Darurat (Asam Kuat)"; statusBuzzer = "Menyala (3x)";
    statusRelaypH = "pH-Up (ON lama: 25 detik)";
    Serial.println("\nStatus pH: " + statusPH + "\nBuzzer: " + statusBuzzer + "\nRelay: " + statusRelaypH);
    if (!ispHUp25SecondFinished) { pH_up_onlm(); }
    else if (!isBuzzer3SecondFinished) { B3(); }
    else { return; }
  }
  else if(yout == 1){
    statusPH = "Waspada (Asam Lemah)"; statusBuzzer = "Menyala (2x)";
    statusRelaypH = "pH-Up (ON sedang: 10 detik)";
    Serial.println("\nStatus pH: " + statusPH + "\nBuzzer: " + statusBuzzer + "\nRelay: " + statusRelaypH);
    if (!ispHUp10SecondFinished) { pH_up_onsd(); }
    else if (!isBuzzer2SecondFinished) { B2(); }
    else { return; }
  }
  else if(yout == 2){
    statusPH = "Aman (Netral)"; statusBuzzer = "Tidak Menyala"; 
    statusRelaypH = "All-pH (OFF: diam)";
    Serial.println("\nStatus pH: " + statusPH + "\nBuzzer: " + statusBuzzer + "\nRelay: " + statusRelaypH);
    all_pH_off();
  }
  else if(yout == 3){
    statusPH = "Waspada (Basa Lemah)"; statusBuzzer = "Menyala (2x)"; 
    statusRelaypH = "pH-Down (ON sedang: 10 detik)"; 
    Serial.println("\nStatus pH: " + statusPH + "\nBuzzer: " + statusBuzzer + "\nRelay: " + statusRelaypH);
    if (!ispHDown10SecondFinished) { pH_down_onsd(); }
    else if (!isBuzzer2SecondFinished) { B2(); }
    else { return; }
  }
  else if(yout == 4){
    statusPH = "Darurat (Basa Kuat)"; statusBuzzer = "Menyala (3x)";
    statusRelaypH = "pH-Down (ON lama: 25 detik)"; 
    Serial.println("\nStatus pH: " + statusPH + "\nBuzzer: " + statusBuzzer + "\nRelay: " + statusRelaypH);
    if (!ispHDown25SecondFinished) { pH_down_onlm(); }
    else if (!isBuzzer3SecondFinished) { B3(); }
    else { return; }
  }
}

//Method untuk mereset perhitungan agar tetap optimal
void reset_redukdeffuzz(){
  yi = 0;
  SigyiMiuMFUpper = 0;
  SigyiMiuMFLower = 0;
  SigMiuMFUpper = 0;
  SigMiuMFLower = 0;
}
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module