#define BLYNK_TEMPLATE_ID "TMPL64iz3GTw2"
#define BLYNK_TEMPLATE_NAME "Automated Cat Feeding System"
#define BLYNK_AUTH_TOKEN "u5j8Dj8GOlg05rv8M2UQXwkPkNnHX8wh"

#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
#include <ESP32Servo.h>
#include <TimeLib.h>
#include <WidgetRTC.h>

char ssid[] = "Wokwi-GUEST";
char pass[] = "";


// กำหนดพิน
#define SERVO_PIN 13
#define TRIG_PIN 5   // พินสำหรับ Ultrasonic Trigger
#define ECHO_PIN 18  // พินสำหรับ Ultrasonic Echo
#define MANUAL_BUTTON_PIN 4  // พินสำหรับปุ่ม manual บนบอร์ด
#define LED_PIN 2  // พินสำหรับ LED แสดงสถานะ

Servo foodDispenser;
WidgetRTC rtc;

// ตัวแปรสำหรับการตั้งค่า
int feedingHours[3] = {8, 12, 18};
int feedingMinutes[3] = {0, 0, 0};
int feedingDuration = 1000; // ระยะเวลาในการเปิดให้อาหาร (มิลลิวินาที)
int foodLevelThreshold = 20; // เปอร์เซ็นต์ขั้นต่ำของอาหารที่เหลือ

BlynkTimer timer;

// ตัวแปรสำหรับการอ่านค่าปุ่ม
int lastButtonState = HIGH;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;

BLYNK_CONNECTED() {
  rtc.begin();
  Blynk.syncAll();
}

// ฟังก์ชันรับค่าเวลาให้อาหารจาก Blynk (V1, V2, V3) ยังคงเหมือนเดิม

// ฟังก์ชันรับค่าระยะเวลาการให้อาหารจาก Blynk
BLYNK_WRITE(V4) {
  feedingDuration = param.asInt();
}

// เพิ่มฟังก์ชันสำหรับปุ่ม Manual Feed ใน Blynk
BLYNK_WRITE(V6) {
  if (param.asInt() == 1) {
    dispenseFood();
  }
}

void setup() {
  Serial.begin(115200);
  
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  pinMode(MANUAL_BUTTON_PIN, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);
  
  // เริ่มต้นการเชื่อมต่อ WiFi
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("WiFi connected");
  
  Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);
  
  // กำหนดค่า PWM สำหรับ Servo
  ESP32PWM::allocateTimer(0);
  ESP32PWM::allocateTimer(1);
  ESP32PWM::allocateTimer(2);
  ESP32PWM::allocateTimer(3);
  foodDispenser.setPeriodHertz(50);    // standard 50 hz servo
  foodDispenser.attach(SERVO_PIN, 500, 2400);
  foodDispenser.write(0); // ตำแหน่งปิด

  timer.setInterval(1000L, checkFeedingTime);
  timer.setInterval(30000L, checkFoodLevel);
  timer.setInterval(100L, checkManualButton);
}

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

void checkFeedingTime() {
  if (year() != 1970) {
    for (int i = 0; i < 3; i++) {
      if (hour() == feedingHours[i] && minute() == feedingMinutes[i] && second() == 0) {
        dispenseFood();
      }
    }
  }
}

void dispenseFood() {
  Serial.println("กำลังให้อาหาร...");
  Blynk.logEvent("feeding_started", "เริ่มให้อาหารแมว");
  digitalWrite(LED_PIN, HIGH);
  foodDispenser.write(90); // เปิดช่องให้อาหาร
  delay(feedingDuration);
  foodDispenser.write(0); // ปิดช่องให้อาหาร
  digitalWrite(LED_PIN, LOW);
  Serial.println("ให้อาหารเสร็จสิ้น");
  Blynk.logEvent("feeding_completed", "ให้อาหารแมวเสร็จสิ้น");
}

void checkFoodLevel() {
  long duration, distance;
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);
  duration = pulseIn(ECHO_PIN, HIGH);
  distance = (duration/2) / 29.1; // แปลงเป็นเซนติเมตร
  
  // สมมติว่าความสูงของถังอาหารคือ 30 ซม.
  int foodPercentage = map(distance, 0, 30, 100, 0);
  foodPercentage = constrain(foodPercentage, 0, 100);
  
  Blynk.virtualWrite(V5, foodPercentage);
  if (foodPercentage < foodLevelThreshold) {
    Serial.println("อาหารเหลือน้อย กรุณาเติมอาหาร!");
    Blynk.logEvent("low_food", "อาหารแมวเหลือน้อย กรุณาเติม");
    digitalWrite(LED_PIN, HIGH); // เปิด LED เมื่ออาหารเหลือน้อย
  } else {
    digitalWrite(LED_PIN, LOW);
  }
}

void checkManualButton() {
  int reading = digitalRead(MANUAL_BUTTON_PIN);
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }
  
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading == LOW) {
      dispenseFood();
    }
  }
  
  lastButtonState = reading;
  }