#define BLYNK_PRINT Serial
#define BLYNK_TEMPLATE_ID "TMPL6aBswiFM9"
#define BLYNK_TEMPLATE_NAME "cahaya"
#define BLYNK_AUTH_TOKEN "z-sSd6QQXdfXtl_01_LXFTfHRELFbAQc"
#define VTIMER V5 // Misalkan menggunakan pin virtual V5 untuk timer di Blynk

#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
#include <DHTesp.h> // Tambahkan pustaka DHTesp
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <RTClib.h> // Tambahkan pustaka RTClib

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

const int DHT_PIN = 26;
DHTesp dhtSensor;
const float FEEDING_TEMP_HIGH = 28; // Suhu tinggi, berikan pakan
const float FEEDING_TEMP_LOW = 25;  // Suhu rendah, berikan pakan
const int FEEDING_SERVO_PIN = 5;   // Pin untuk mengendalikan servo pakan
const int FEEDING_ANGLE = 90;       // Sudut servo saat memberi pakan

char auth[] = "z-sSd6QQXdfXtl_01_LXFTfHRELFbAQc";
char ssid[] = "Wokwi-GUEST";
char pass[] = "";

BlynkTimer timer;
RTC_DS3231 rtc; // Objek RTC

// Waktu pemberian makan yang ditentukan (jam, menit)
const int feedingTimes[][2] = {
  {7, 0},   // Pagi: 7:00 AM
  {12, 0},  // Siang: 12:00 PM
  {16, 0},  // Sore: 4:00 PM
  {20, 0}   // Malam: 8:00 PM
};

// Variabel untuk menyimpan waktu terakhir pemberian pakan
DateTime lastFeedingTime;

void sendSensorAndControl()
{
  // Baca data suhu dan kelembaban
  TempAndHumidity data = dhtSensor.getTempAndHumidity();
  
  // Kirim data suhu dan kelembaban ke Blynk
  Blynk.virtualWrite(V1, data.temperature);
  Blynk.virtualWrite(V2, data.humidity);

  // Tampilkan data suhu dan kelembaban di layar OLED
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.print("Temperature: ");
  display.println(data.temperature, 2);
  display.print("Humidity: ");
  display.println(data.humidity, 1);
  display.display();

  // Kontrol pemberian pakan berdasarkan suhu
  if (data.temperature >= FEEDING_TEMP_HIGH || data.temperature <= FEEDING_TEMP_LOW) {
    // Aktifkan servo pakan
    digitalWrite(FEEDING_SERVO_PIN, HIGH);
    delay(1000); // Tunggu servo bergerak
    digitalWrite(FEEDING_SERVO_PIN, LOW);
    delay(500); // Tunggu sebelum memberikan pakan lagi
    
    // Dapatkan waktu saat ini dari RTC
    DateTime now = rtc.now();

    // Tampilkan pesan pakan telah diberikan bersama dengan waktu di layar OLED
    display.setCursor(0, 25);
    display.print("Pakan Telah diberikan: ");
    display.setCursor(0, 30);
    display.print(now.hour());
    display.print(":");
    if (now.minute() < 10) {
      display.print("0");
    }
    display.println(now.minute());
    display.display();
    
    // Kirim pesan pakan telah diberikan ke serial
    Serial.print("Pakan Telah diberikan: ");
    Serial.print(now.hour());
    Serial.print(":");
    if (now.minute() < 10) {
      Serial.print("0");
    }
    Serial.println(now.minute());

    // Kirim status pemberian pakan ke Blynk
    Blynk.virtualWrite(V4, 1); // Mengirim nilai 1 ke pin virtual V4 sebagai indikator pemberian pakan

    // Update waktu timer di Blynk
    Blynk.virtualWrite(VTIMER, now.hour(), now.minute()); // Mengatur timer di Blynk dengan waktu pemberian pakan terakhir
  }
}

BLYNK_WRITE(V3) {
  int feedingSwitchStatus = param.asInt(); // Mendapatkan status switch dari Blynk

  if (feedingSwitchStatus == 1) { // Jika switch dalam posisi ON
    // Beri makan secara manual
    giveFood();

    // Perbarui waktu terakhir pemberian makan
    lastFeedingTime = rtc.now();
  }
}

void setup() {
  Serial.begin(115200);
  dhtSensor.setup(DHT_PIN, DHTesp::DHT22);

  // Set pin servo sebagai output
  pinMode(FEEDING_SERVO_PIN, OUTPUT);

  Blynk.begin(auth, ssid, pass);
  timer.setInterval(5000L, sendSensorAndControl); // Kecamatan pengiriman data
  
  // Inisialisasi layar OLED
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { 
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
  delay(2000);
  display.clearDisplay();

  // Inisialisasi RTC
  if (!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }

  if (rtc.lostPower()) {
    Serial.println("RTC lost power, let's set the time!");
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }

  // Inisialisasi waktu terakhir pemberian makan pada waktu pemberian makan pertama
  lastFeedingTime = rtc.now();
}

void loop() {
  Blynk.run();
  timer.run();

  DateTime now = rtc.now();

  // Periksa apakah waktu sekarang sudah melewati waktu pemberian makan yang ditentukan
  for (int i = 0; i < sizeof(feedingTimes) / sizeof(feedingTimes[0]); i++) {
    int hour = feedingTimes[i][0];
    int minute = feedingTimes[i][1];

    if (now.hour() == hour && now.minute() == minute && (now.hour() != lastFeedingTime.hour() || now.minute() != lastFeedingTime.minute())) {
      // Beri makan
      giveFood();

      // Perbarui waktu terakhir pemberian makan
      lastFeedingTime = now;

      break; // Keluar dari loop setelah memberi makan
    }
  }
}

void giveFood() {
  // Buka servo untuk memberikan pakan
  digitalWrite(FEEDING_SERVO_PIN, HIGH);
  delay(1000); // Tunggu servo bergerak

  // Catat waktu saat ini untuk menghitung durasi bukaan servo
  unsigned long startTime = millis();
  while (millis() - startTime < 2000) { // Tunggu 2 detik sebelum menutup servo
    // Tambahkan apapun yang perlu dilakukan saat menunggu
    // Misalnya, Anda dapat memperbarui nilai sensor atau menangani perintah Blynk
    Blynk.run();
  }

  // Tutup servo setelah 2 detik
  digitalWrite(FEEDING_SERVO_PIN, LOW);

  // Dapatkan waktu saat ini dari RTC
  DateTime now = rtc.now();
  
  // Tampilkan pesan pakan telah diberikan bersama dengan waktu di layar OLED
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 25);
  display.print("Pakan Telah diberikan");
  display.setCursor(0, 40);
  display.print(now.hour());
  display.print(":");
  if (now.minute() < 10) {
    display.print("0");
  }
  display.setCursor(0, 40);
  display.println(now.minute());
  display.display();
  
  // Kirim pesan pakan telah diberikan ke serial
  Serial.print("Pakan Telah diberikan: ");
  Serial.print(now.hour());
  Serial.print(":");
  if (now.minute() < 10) {
    Serial.print("0");
  }
  Serial.println(now.minute());

  // Kirim status pemberian pakan ke Blynk
  Blynk.virtualWrite(V4, 1); // Mengirim nilai 1 ke pin virtual V4 sebagai indikator pemberian pakan

  // Update waktu timer di Blynk
  Blynk.virtualWrite(VTIMER, now.hour(), now.minute()); // Mengatur timer di Blynk dengan waktu pemberian pakan terakhir
}

GND5VSDASCLSQWRTCDS1307+