#include <Wire.h> // I2C communication
#include <RTClib.h> // RTC library for DS1307
#include <DHT.h> // DHT sensor library
#include <Fuzzy.h> // Fuzzy logic library

#define DHTPIN 8  // DHT sensor pin
#define DHTTYPE DHT22 // Change to DHT11 if needed
DHT dht(DHTPIN, DHTTYPE); // Instance for DHT sensor

RTC_DS1307 rtc; // Instance for RTC

Fuzzy *fuzzy = new Fuzzy(); // Instance for Fuzzy logic

// Pump pins
#define POMPA1 6 // Pin for Pump 1 (controlled by fuzzy logic)
#define POMPA2 7 // Pin for Pump 2 (controlled by time logic)

// Timing variables
unsigned long previousMillisPump1 = 0;
unsigned long previousMillisPump2 = 0;
unsigned long intervalPump1 = 0; // Will be set by fuzzy logic
unsigned long intervalPump2 = 10000; // Pump 2 runs for 10 seconds
bool isPump1On = false;
bool isPump2On = false;
// Function to set up fuzzy logic rules
void setupFuzzyLogic() {
    FuzzyInput *humidityInput = new FuzzyInput(1);

    FuzzySet *lowHumidity = new FuzzySet(20, 40, 40, 60); // Low humidity range
    FuzzySet *mediumHumidity = new FuzzySet(50, 70, 70, 90); // Medium humidity range
    FuzzySet *highHumidity = new FuzzySet(80, 100, 100, 101); // High humidity range

    humidityInput->addFuzzySet(lowHumidity);
    humidityInput->addFuzzySet(mediumHumidity);
    humidityInput->addFuzzySet(highHumidity);

    fuzzy->addFuzzyInput(humidityInput);

    FuzzyOutput *wateringOutput = new FuzzyOutput(1);

    FuzzySet *shortWatering = new FuzzySet(0, 5, 5, 10);
    FuzzySet *mediumWatering = new FuzzySet(10, 15, 15, 20);
    FuzzySet *longWatering = new FuzzySet(20, 30, 30, 40);

    wateringOutput->addFuzzySet(shortWatering);
    wateringOutput->addFuzzySet(mediumWatering);
    wateringOutput->addFuzzySet(longWatering);

    fuzzy->addFuzzyOutput(wateringOutput);

    FuzzyRuleConsequent *shortWateringConsequent = new FuzzyRuleConsequent();
    shortWateringConsequent->addOutput(shortWatering);

    FuzzyRuleConsequent *mediumWateringConsequent = new FuzzyRuleConsequent();
    mediumWateringConsequent->addOutput(mediumWatering);

    FuzzyRuleConsequent *longWateringConsequent = new FuzzyRuleConsequent();
    longWateringConsequent->addOutput(longWatering);

    FuzzyRuleAntecedent *lowHumidityAntecedent = new FuzzyRuleAntecedent();
    lowHumidityAntecedent->joinSingle(lowHumidity);

    FuzzyRule *fuzzyRule01 = new FuzzyRule(1, lowHumidityAntecedent, longWateringConsequent);
    fuzzy->addFuzzyRule(fuzzyRule01);

    FuzzyRuleAntecedent *mediumHumidityAntecedent = new FuzzyRuleAntecedent();
    mediumHumidityAntecedent->joinSingle(mediumHumidity);

    FuzzyRule *fuzzyRule02 = new FuzzyRule(2, mediumHumidityAntecedent, mediumWateringConsequent);
    fuzzy->addFuzzyRule(fuzzyRule02);

    FuzzyRuleAntecedent *highHumidityAntecedent = new FuzzyRuleAntecedent();
    highHumidityAntecedent->joinSingle(highHumidity);

    FuzzyRule *fuzzyRule03 = new FuzzyRule(3, highHumidityAntecedent, shortWateringConsequent);
    fuzzy->addFuzzyRule(fuzzyRule03);
}

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

  dht.begin(); // Initialize the DHT sensor

  Wire.begin(); // Start I2C communication
  rtc.begin(); // Initialize RTC

  pinMode(POMPA1, OUTPUT);
  pinMode(POMPA2, OUTPUT);

  if (!rtc.isrunning()) {
    Serial.println("RTC is not running. Setting to compile-time.");
    rtc.adjust(DateTime(__DATE__, __TIME__)); // Set the RTC time if not running
  }

  setupFuzzyLogic(); // Set up fuzzy logic rules
}

void loop() {
  unsigned long currentMillis = millis();

  // Read humidity from DHT sensor
  float humidity = dht.readHumidity();
  float temperature = dht.readTemperature();
   Serial.print("humidity: ");
  Serial.println(humidity);
  Serial.print("temperature: ");
  Serial.println(temperature);

  if (isnan(humidity) || isnan(temperature)) {
    Serial.println("Failed to read from DHT sensor.");
    return; // Exit the loop if the reading fails
  }

  // Fuzzy logic for Pump 1
  fuzzy->setInput(1, humidity); // Set fuzzy logic input for humidity
  fuzzy->fuzzify(); // Run fuzzy logic
  float wateringTime = fuzzy->defuzzify(1); // Get the watering duration
 Serial.print("Waktu penyiraman: ");
    Serial.print(intervalPump1);
    Serial.println(" detik.");
 DateTime now = rtc.now();
    intervalPump1 = wateringTime * 1000; // Set the interval in milliseconds

   if ((now.hour() == 9 && now.minute() == 0) || (now.hour() == 15 && now.minute() == 0)) {
    if (!isPump1On) {
      digitalWrite(POMPA1, LOW); // Aktifkan Pompa 1
      previousMillisPump1 = currentMillis; // Setel ulang timer
      isPump1On = true; // Tandai Pompa 1 sebagai ON
    }
  }

  // Matikan pompa setelah interval fuzzy logic berakhir
  if (isPump1On && (currentMillis - previousMillisPump1) >= intervalPump1) {
    digitalWrite(POMPA1, HIGH); // Matikan Pompa 1
    isPump1On = false; // Tandai Pompa 1 sebagai OFF
  }

  // Time-based logic for Pump 2
 
  if (now.hour() == 6 && now.minute() == 0 && !isPump2On) {
    digitalWrite(POMPA2, HIGH); // Activate Pump 2 at 6:00 AM
    previousMillisPump2 = currentMillis; // Reset the timer
    isPump2On = true; // Mark Pump 2 as ON
  }

  if ((currentMillis - previousMillisPump2) >= intervalPump2 && isPump2On) {
    digitalWrite(POMPA2, LOW); // Deactivate Pump 2
    isPump2On = false; // Mark Pump 2 as OFF
  }

  delay(2000); // Delay before the next loop iteration
}
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
GND5VSDASCLSQWRTCDS1307+