From 4f1ff9acde527b423f1cf661753cab9314d9cf6d Mon Sep 17 00:00:00 2001 From: acaca6 Date: Wed, 13 Aug 2025 11:11:02 +0700 Subject: [PATCH] Upload Project catfeeder --- catfeeder.ino | 191 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 catfeeder.ino diff --git a/catfeeder.ino b/catfeeder.ino new file mode 100644 index 0000000..aac0c55 --- /dev/null +++ b/catfeeder.ino @@ -0,0 +1,191 @@ +#include +#include +#include +#include +#include +#include +#include + +// === WiFi === +#define WIFI_SSID "iPhone pasa" +#define WIFI_PASSWORD "caca2004" + +// === Firebase === +#define API_KEY "AIzaSyAkcK-nMUY8AcQRpOyrb0xACIgq9Er31Fk" +#define DATABASE_URL "https://petfeeder-e9908-default-rtdb.asia-southeast1.firebasedatabase.app" +#define USER_EMAIL "tkk@gmail.com" +#define USER_PASSWORD "123456" + +FirebaseData fbdo; +FirebaseAuth auth; +FirebaseConfig config; + +// === Servo === +Servo myservo; +const int servoPin = 18; + +// === RTC === +RTC_DS3231 rtc; + +// === NTP === +WiFiUDP ntpUDP; +NTPClient timeClient(ntpUDP, "pool.ntp.org", 25200, 60000); // UTC+7 + +// === Manual Feed State === +bool manualFeedingInProgress = false; +unsigned long lastScheduleCheck = 0; +const unsigned long scheduleInterval = 5000; + +// === Fungsi WiFi === +void connectWiFi() { + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + Serial.print("WiFi connecting"); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println("\nāœ… WiFi connected"); +} + +// === Fungsi log riwayat === +void logFeedingHistory(String type, int duration) { + DateTime now = rtc.now(); + String timeString = String(now.day()) + "-" + String(now.month()) + "-" + String(now.year()) + " " + String(now.hour()) + ":" + String(now.minute()); + + FirebaseJson log; + log.set("type", type); + log.set("duration", duration); + log.set("timestamp", now.unixtime()); + log.set("time", timeString); + + String path = "/feed_history/" + String(now.unixtime()); + if (Firebase.RTDB.setJSON(&fbdo, path.c_str(), &log)) { + Serial.println("šŸ“ Riwayat pakan disimpan."); + } else { + Serial.printf("āŒ Gagal simpan riwayat: %s\n", fbdo.errorReason().c_str()); + } +} + +// === Fungsi feedNow === +void feedNow(int duration, String type = "manual") { + Serial.printf("šŸ– Servo ON selama %d detik (%s)\n", duration, type.c_str()); + myservo.write(180); + delay(duration * 1000); + myservo.write(0); + Serial.println("šŸ– Servo OFF"); + + logFeedingHistory(type, duration); +} + +// === Cek manual feed === +void checkManualFeed() { + if (manualFeedingInProgress) return; + + if (Firebase.RTDB.getJSON(&fbdo, "/manual_feeder")) { + FirebaseJson &json = fbdo.jsonObject(); + FirebaseJsonData result; + + int duration = 0; + bool active = false; + + if (json.get(result, "duration") && result.type == "int") { + duration = result.intValue; + } + + if (json.get(result, "active") && result.type == "boolean") { + active = result.boolValue; + } + + if (active && duration > 0) { + manualFeedingInProgress = true; + feedNow(duration, "manual"); + + FirebaseJson update; + update.set("active", false); + Firebase.RTDB.updateNode(&fbdo, "/manual_feeder", &update); + + manualFeedingInProgress = false; + } + } +} + +// === Cek jadwal === +void checkScheduleFeed() { + if (millis() - lastScheduleCheck < scheduleInterval) return; + lastScheduleCheck = millis(); + + DateTime now = rtc.now(); + int currentHour = now.hour(); + int currentMinute = now.minute(); + + if (Firebase.RTDB.getJSON(&fbdo, "/schedules")) { + FirebaseJson &schedules = fbdo.jsonObject(); + FirebaseJsonData result; + size_t count = schedules.iteratorBegin(); + + static String lastFeedKey = ""; + static int lastFeedMinute = -1; + + for (size_t i = 0; i < count; i++) { + String key, value; + int type; + schedules.iteratorGet(i, type, key, value); + + FirebaseJson child; + schedules.get(result, key); + child.setJsonData(result.stringValue); + + int hour = -1, minute = -1, duration = 0; + bool enabled = false; + + if (child.get(result, "hour") && result.type == "int") hour = result.intValue; + if (child.get(result, "minute") && result.type == "int") minute = result.intValue; + if (child.get(result, "duration") && result.type == "int") duration = result.intValue; + if (child.get(result, "enabled") && result.type == "boolean") enabled = result.boolValue; + + if (enabled && hour == currentHour && minute == currentMinute) { + if (key != lastFeedKey || currentMinute != lastFeedMinute) { + feedNow(duration, "schedule"); + lastFeedKey = key; + lastFeedMinute = currentMinute; + } + } + } + + schedules.iteratorEnd(); + } +} + +// === Setup === +void setup() { + Serial.begin(115200); + Wire.begin(); + connectWiFi(); + + myservo.attach(servoPin); + myservo.write(0); + + if (!rtc.begin()) { + Serial.println("RTC tidak ditemukan!"); + while (1); + } + + // Sync waktu dari NTP ke RTC + timeClient.begin(); + timeClient.update(); + rtc.adjust(DateTime(timeClient.getEpochTime())); + + config.api_key = API_KEY; + config.database_url = DATABASE_URL; + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + + Firebase.begin(&config, &auth); + Firebase.reconnectWiFi(true); +} + +// === Loop utama === +void loop() { + checkManualFeed(); + checkScheduleFeed(); +} \ No newline at end of file