//============================================================ 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;
}