#include <WiFi.h>
#include <Blynk.h>
#include <Servo.h>
#define BLYNK_TEMPLATE_NAME "Fishhhh"
#define BLYNK_PRINT Serial
#define WOKWI_SIMULATION // Hapus baris ini jika menggunakan hardware nyata
// Deklarasi Servo
Servo myservo;
int servoPin = 13;
// Konfigurasi Waktu
#ifdef WOKWI_SIMULATION
unsigned long virtualSeconds = 0;
int virtualHours = 0;
int virtualMinutes = 0;
#else
#include <NTPClient.h>
#include <WiFiUdp.h>
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 7*3600); // UTC+7
#endif
// Jadwal Pakan
int feedTimes[] = {7, 16}; // 7AM dan 4PM
int lastFeedHour = -1;
bool isEnabled = true;
// Blynk Configuration
char auth[] = "TMPL6TQudCRm9"; // Ganti dengan token Blynk Anda
char ssid[] = "Wokwi-GUEST"; // Untuk Wokwi simulation
char pass[] = "";
BLYNK_WRITE(V0) { // Tombol Enable/Disable
isEnabled = param.asInt();
}
BLYNK_WRITE(V1) { // Tombol Manual Feed
if(param.asInt()) {
feedNow();
}
}
void setup() {
Serial.begin(115200);
myservo.attach(servoPin);
#ifndef WOKWI_SIMULATION
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) delay(500);
timeClient.begin();
#endif
Blynk.begin(auth, ssid, pass, "blynk.cloud", 80);
Serial.println("System Ready");
Serial.println("Kontrol melalui Blynk atau Serial Monitor");
Serial.println("Perintah Serial: FEED, ON, OFF, TIME [HH:MM]");
}
void loop() {
Blynk.run();
updateTime();
if(isEnabled) {
checkFeedingTime();
}
sendStatusToBlynk();
checkSerialCommands();
delay(1000);
}
void updateTime() {
#ifdef WOKWI_SIMULATION
virtualSeconds += 1;
virtualHours = (virtualSeconds / 3600) % 24;
virtualMinutes = (virtualSeconds / 60) % 60;
#else
timeClient.update();
#endif
}
void checkFeedingTime() {
int currentHour = getCurrentHour();
for(int i = 0; i < 2; i++) {
if(currentHour == feedTimes[i] &&
getCurrentMinute() == 0 &&
lastFeedHour != currentHour) {
feedNow();
lastFeedHour = currentHour;
}
}
}
int getCurrentHour() {
#ifdef WOKWI_SIMULATION
return virtualHours;
#else
return timeClient.getHours();
#endif
}
int getCurrentMinute() {
#ifdef WOKWI_SIMULATION
return virtualMinutes;
#else
return timeClient.getMinutes();
#endif
}
void feedNow() {
Serial.println("Memberi pakan...");
myservo.write(180);
delay(1000);
myservo.write(0);
Blynk.virtualWrite(V2, getFormattedTime() + " - Terakhir diberi makan");
}
void sendStatusToBlynk() {
Blynk.virtualWrite(V3, isEnabled ? "AKTIF" : "NON-AKTIF");
Blynk.virtualWrite(V4, getFormattedTime());
}
String getFormattedTime() {
#ifdef WOKWI_SIMULATION
char buf[6];
sprintf(buf, "%02d:%02d", virtualHours, virtualMinutes);
return String(buf);
#else
return timeClient.getFormattedTime();
#endif
}
void checkSerialCommands() {
if(Serial.available()) {
String input = Serial.readStringUntil('\n');
input.trim();
if(input.equalsIgnoreCase("FEED")) {
feedNow();
}
else if(input.equalsIgnoreCase("ON")) {
isEnabled = true;
Blynk.virtualWrite(V0, 1);
}
else if(input.equalsIgnoreCase("OFF")) {
isEnabled = false;
Blynk.virtualWrite(V0, 0);
}
else if(input.startsWith("TIME ")) {
setVirtualTime(input.substring(5));
}
}
}
void setVirtualTime(String timeStr) {
#ifdef WOKWI_SIMULATION
int colonIndex = timeStr.indexOf(':');
if(colonIndex != -1) {
int hh = timeStr.substring(0, colonIndex).toInt();
int mm = timeStr.substring(colonIndex+1).toInt();
virtualSeconds = (hh * 3600) + (mm * 60);
Serial.print("Waktu diatur ke: ");
Serial.println(timeStr);
}
#else
Serial.println("Fitur ini hanya untuk simulasi Wokwi");
#endif
}