#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;
}