#include <DHT.h>
#include <LiquidCrystal.h>
#include <Fuzzy.h>

#define DHTPIN 8  
#define DHTTYPE DHT22 

DHT dht(DHTPIN, DHTTYPE);

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

Fuzzy *fuzzy = new Fuzzy();

float h;
float t;
float output;

const int switch1 = 6;
const int switch2 = 7;
const int kipas_pin = 9;
const int lampu_pin = 10;

const long interval = 30000; 
unsigned long prev_millis = 0;

void fuzzyInit();

void printInit();

int count1 = 0;

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

  fuzzyInit();

  pinMode(switch1, INPUT_PULLUP);
  pinMode(switch2, INPUT_PULLUP);
  pinMode(kipas_pin, OUTPUT);
  pinMode(lampu_pin, OUTPUT);

  dht.begin();
  h = dht.readHumidity();
  t = dht.readTemperature();

  lcd.begin(16, 2);
    
  printInit();

  fuzzy->setInput(1, t);
  fuzzy->setInput(2, h);
  fuzzy->fuzzify();
  output = fuzzy->defuzzify(1);
  analogWrite(kipas_pin, (unsigned char)output);
}

void loop() {
  unsigned long current_millis = millis();
  output = fuzzy->defuzzify(1);

  h = dht.readHumidity();
  t = dht.readTemperature();

  if (current_millis - prev_millis >= interval) {
    prev_millis = current_millis;

    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Stabilkan suhu ...");

    fuzzy->setInput(1, t);
    fuzzy->setInput(2, h);
    fuzzy->fuzzify();
    output = fuzzy->defuzzify(1);

    lcd.setCursor(0, 1);
    lcd.print("Done!!!");

    analogWrite(kipas_pin, (unsigned char)output);

    lcd.clear();
  }

  lcd.setCursor(0, 0);
  lcd.print(t);
  lcd.setCursor(5, 0);
  lcd.print((char)223);
  lcd.setCursor(8, 0);
  lcd.print(h);
  lcd.setCursor(13, 0);
  lcd.print("%");

  lcd.setCursor(0, 1);
  lcd.print("output :  ");
  lcd.setCursor(9, 1);
  lcd.print(output);
}

void printInit() {
  unsigned char time_out = 0;
  unsigned long current_mill = millis();
  lcd.setCursor(5, 0);
  lcd.print("Proyek");
  lcd.setCursor(2, 1);
  lcd.print("Penetas Telur");
  delay(3000);
  lcd.clear();
  while(digitalRead(6)) { 
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Suhu   : ");
      lcd.setCursor(9, 0);
      lcd.print(t);
      lcd.setCursor(14, 0);
      lcd.print((char)223);
      lcd.setCursor(0, 1);
      lcd.print("Lembab :");
      lcd.setCursor(9, 1);
      lcd.print(h);
      lcd.setCursor(14, 1);
      lcd.print("%");
      delay(3000);
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Start tekan[PB1]");
      lcd.setCursor(0, 1);
      lcd.print("Reset tekan[RST]");
      delay(1000);
  }
  lcd.clear();
}

void fuzzyInit() {
  FuzzyInput *suhu = new FuzzyInput(1);

  FuzzySet *dingin = new FuzzySet(0, 0, 15, 25);
  suhu->addFuzzySet(dingin);
  FuzzySet *sejuk = new FuzzySet(20, 23.5, 26.5, 30);
  suhu->addFuzzySet(sejuk);
  FuzzySet *normal = new FuzzySet(25, 28.5, 31.5, 35);
  suhu->addFuzzySet(normal);
  FuzzySet *hangat = new FuzzySet(30, 33.5, 36.5, 40);
  suhu->addFuzzySet(hangat);
  FuzzySet *panas = new FuzzySet(35, 40, 50, 50);
  suhu->addFuzzySet(panas);

  fuzzy->addFuzzyInput(suhu);

  FuzzyInput *kelembaban = new FuzzyInput(2);

  FuzzySet *kering = new FuzzySet(0, 0, 20, 45);
  kelembaban->addFuzzySet(kering);
  FuzzySet *kelembaban_normal = new FuzzySet(25, 45, 55, 75);
  kelembaban->addFuzzySet(kelembaban_normal);
  FuzzySet *basah = new FuzzySet(55, 80, 100, 100);
  kelembaban->addFuzzySet(basah);

  fuzzy->addFuzzyInput(kelembaban);

  FuzzyOutput *kecepatan_kipas = new FuzzyOutput(1);

  FuzzySet *mati = new FuzzySet(5, 5, 5, 5);
  kecepatan_kipas->addFuzzySet(mati);
  FuzzySet *pelan = new FuzzySet(70, 70, 70, 70);
  kecepatan_kipas->addFuzzySet(pelan);
  FuzzySet *sedang = new FuzzySet(160, 160, 160, 160);
  kecepatan_kipas->addFuzzySet(sedang);
  FuzzySet *cepat = new FuzzySet(255, 255, 255, 255);
  kecepatan_kipas->addFuzzySet(cepat);

  fuzzy->addFuzzyOutput(kecepatan_kipas);

  //IF THEN RULES
  FuzzyRuleConsequent *kecepatan_mati = new FuzzyRuleConsequent();
  kecepatan_mati->addOutput(mati);
  FuzzyRuleConsequent *kecepatan_pelan = new FuzzyRuleConsequent();
  kecepatan_pelan->addOutput(pelan);
  FuzzyRuleConsequent *kecepatan_sedang = new FuzzyRuleConsequent();
  kecepatan_sedang->addOutput(sedang);
  FuzzyRuleConsequent *kecepatan_cepat = new FuzzyRuleConsequent();
  kecepatan_cepat->addOutput(cepat);

  FuzzyRuleAntecedent *dinginKering = new FuzzyRuleAntecedent();
  dinginKering->joinWithAND(dingin, kering);
  FuzzyRuleAntecedent *sejukKering = new FuzzyRuleAntecedent();
  sejukKering->joinWithAND(sejuk, kering);
  FuzzyRuleAntecedent *normalKering = new FuzzyRuleAntecedent();
  normalKering->joinWithAND(normal, kering);
  FuzzyRuleAntecedent *hangatKering = new FuzzyRuleAntecedent();
  hangatKering->joinWithAND(hangat, kering);
  FuzzyRuleAntecedent *panasKering = new FuzzyRuleAntecedent();
  panasKering->joinWithAND(panas, kering);
  FuzzyRuleAntecedent *dinginNormal = new FuzzyRuleAntecedent();
  dinginNormal->joinWithAND(dingin, kelembaban_normal);
  FuzzyRuleAntecedent *sejukNormal = new FuzzyRuleAntecedent();
  sejukNormal->joinWithAND(sejuk, kelembaban_normal);
  FuzzyRuleAntecedent *normalNormal = new FuzzyRuleAntecedent();
  normalNormal->joinWithAND(normal, kelembaban_normal);
  FuzzyRuleAntecedent *hangatNormal = new FuzzyRuleAntecedent();
  hangatNormal->joinWithAND(hangat, kelembaban_normal);
  FuzzyRuleAntecedent *panasNormal = new FuzzyRuleAntecedent();
  panasNormal->joinWithAND(panas, kelembaban_normal);
  FuzzyRuleAntecedent *dinginBasah = new FuzzyRuleAntecedent();
  dinginBasah->joinWithAND(dingin, basah);
  FuzzyRuleAntecedent *sejukBasah = new FuzzyRuleAntecedent();
  sejukBasah->joinWithAND(sejuk, basah);
  FuzzyRuleAntecedent *normalBasah = new FuzzyRuleAntecedent();
  normalBasah->joinWithAND(normal, basah);
  FuzzyRuleAntecedent *hangatBasah = new FuzzyRuleAntecedent();
  hangatBasah->joinWithAND(hangat, basah);
  FuzzyRuleAntecedent *panasBasah = new FuzzyRuleAntecedent();
  panasBasah->joinWithAND(panas, basah);

  FuzzyRule *rule00 = new FuzzyRule(1, dinginKering, kecepatan_mati);
  fuzzy->addFuzzyRule(rule00);
  FuzzyRule *rule01 = new FuzzyRule(2, sejukKering, kecepatan_pelan);
  fuzzy->addFuzzyRule(rule01);
  FuzzyRule *rule02 = new FuzzyRule(3, normalKering, kecepatan_sedang);
  fuzzy->addFuzzyRule(rule02);
  FuzzyRule *rule03 = new FuzzyRule(4, hangatKering, kecepatan_cepat);
  fuzzy->addFuzzyRule(rule03);
  FuzzyRule *rule04 = new FuzzyRule(5, panasKering, kecepatan_cepat);
  fuzzy->addFuzzyRule(rule04);
  FuzzyRule *rule10 = new FuzzyRule(6, dinginNormal, kecepatan_mati);
  fuzzy->addFuzzyRule(rule10);
  FuzzyRule *rule11 = new FuzzyRule(7, sejukNormal, kecepatan_pelan);
  fuzzy->addFuzzyRule(rule11);
  FuzzyRule *rule12 = new FuzzyRule(8, normalNormal, kecepatan_pelan);
  fuzzy->addFuzzyRule(rule12);
  FuzzyRule *rule13 = new FuzzyRule(9, hangatNormal, kecepatan_sedang);
  fuzzy->addFuzzyRule(rule13);
  FuzzyRule *rule14 = new FuzzyRule(10, panasNormal, kecepatan_sedang);
  fuzzy->addFuzzyRule(rule14);
  FuzzyRule *rule20 = new FuzzyRule(11, dinginBasah, kecepatan_mati);
  fuzzy->addFuzzyRule(rule20);
  FuzzyRule *rule21 = new FuzzyRule(12, sejukBasah, kecepatan_mati);
  fuzzy->addFuzzyRule(rule21);
  FuzzyRule *rule22 = new FuzzyRule(13, normalBasah, kecepatan_pelan);
  fuzzy->addFuzzyRule(rule22);
  FuzzyRule *rule23 = new FuzzyRule(14, hangatBasah, kecepatan_sedang);
  fuzzy->addFuzzyRule(rule23);
  FuzzyRule *rule24 = new FuzzyRule(15, panasBasah, kecepatan_sedang);
  fuzzy->addFuzzyRule(rule24);
}