#define BLYNK_TEMPLATE_ID "TMPL6-koCiZAA" #define BLYNK_TEMPLATE_NAME "Projek TA" #define BLYNK_AUTH_TOKEN "pOhzyHxD1TKgFF-pJ7TZYoS0HOfUyVPK" #include #include #include #include #include #include #include #include #define SERVO_PIN 2 #define BUTTON_SERVO_PIN 15 #define BUTTON_PENGURAS_PIN 13 #define TDS_SENSOR_PIN 34 #define BUZZER_PIN 5 #define PENGURAS_PIN 26 #define PENGISI_PIN 27 #define WATERLEVEL_PENGURAS_PIN 32 #define WATERLEVEL_PENGISI_PIN 33 #define LCD_COLS 16 #define LCD_ROWS 2 #define TDS_THRESHOLD 300 #define PIN_BUTTON_SERVO V0 #define PIN_BUTTON_PENGURAS V1 #define PIN_TDS_READING V2 #define PIN_TIME_MORNING V3 #define PIN_TIME_NOON V4 #define PIN_TIME_NIGHT V5 RTC_DS3231 rtc; Servo feeder; LiquidCrystal_I2C lcd(0x27, LCD_COLS, LCD_ROWS); unsigned long lastSlideChangeTime = 0; int currentSlide = 0; int WaterLevelPengurasStatus; int WaterLevelPengisiStatus; const char* ssid = "Safirudin 2"; const char* password = "safirudin54321"; char auth[] = BLYNK_AUTH_TOKEN; bool notificationSent = false; WiFiUDP ntpUDP; NTPClient timeClient(ntpUDP, "pool.ntp.org", 7 * 3600, 60000); int feedTimeMorningHour; int feedTimeMorningMinute; int feedTimeNoonHour; int feedTimeNoonMinute; int feedTimeNightHour; int feedTimeNightMinute; void setup() { feeder.attach(SERVO_PIN); pinMode(BUTTON_SERVO_PIN, INPUT_PULLUP); pinMode(BUZZER_PIN, OUTPUT); pinMode(PENGURAS_PIN, OUTPUT); pinMode(PENGISI_PIN, OUTPUT); pinMode(WATERLEVEL_PENGURAS_PIN, INPUT_PULLUP); pinMode(WATERLEVEL_PENGISI_PIN, INPUT_PULLUP); pinMode(BUTTON_PENGURAS_PIN, INPUT_PULLUP); Serial.begin(9600); Wire.begin(); lcd.init(); lcd.backlight(); connectToWiFi(); if (!rtc.begin()) { Serial.println("Tidak dapat menemukan RTC"); while (1); } if (rtc.lostPower()) { Serial.println("RTC kehilangan daya, mengatur waktu!"); rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); } timeClient.begin(); Blynk.begin(auth, ssid, password, "blynk.cloud", 80); } void loop() { unsigned long currentTime = millis(); bool servoButtonState = digitalRead(BUTTON_SERVO_PIN); bool pengurasButtonState = digitalRead(BUTTON_PENGURAS_PIN); Blynk.run(); timeClient.update(); DateTime now = rtc.now(); if (abs((long)(now.unixtime() - timeClient.getEpochTime())) > 10) { rtc.adjust(DateTime(timeClient.getEpochTime())); } if (servoButtonState == LOW) { openFeeder(); delay(500); } if (pengurasButtonState == LOW) { activatePenguras(); delay(500); } if (currentTime - lastSlideChangeTime >= 2000) { currentSlide = (currentSlide + 1) % 3; lastSlideChangeTime = currentTime; switch (currentSlide) { case 1: showFeederScreen(); break; case 2: showNextFeedingTimeScreen(); break; case 0: unsigned int tdsValue = readTDS(); showTDSReadingScreen(tdsValue); break; } } unsigned int tdsValue = readTDS(); updateBuzzer(tdsValue); updateRelayAndWaterLevel(); if (tdsValue > TDS_THRESHOLD && !notificationSent) { sendTDSNotification(); notificationSent = true; } else if (tdsValue <= TDS_THRESHOLD) { notificationSent = false; } checkFeedingTime(now.hour(), now.minute(), now.day()); delay(100); } void checkFeedingTime(int currentHour, int currentMinute, int currentDay) { static int lastFedDay = -1; static bool fedMorning = false; static bool fedNoon = false; static bool fedNight = false; if (lastFedDay != currentDay) { fedMorning = false; fedNoon = false; fedNight = false; lastFedDay = currentDay; } if (currentHour == feedTimeMorningHour && currentMinute == feedTimeMorningMinute && !fedMorning) { openFeeder(); showFeedingStatus(); fedMorning = true; } else if (currentHour == feedTimeNoonHour && currentMinute == feedTimeNoonMinute && !fedNoon) { openFeeder(); showFeedingStatus(); fedNoon = true; } else if (currentHour == feedTimeNightHour && currentMinute == feedTimeNightMinute && !fedNight) { openFeeder(); showFeedingStatus(); fedNight = true; } } void showWiFiStatus(const char* statusMessage) { lcd.clear(); lcd.setCursor(0, 0); lcd.print(statusMessage); } void connectToWiFi() { showWiFiStatus("Connecting WiFi"); Serial.println("Menghubungkan WiFi..."); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Mencoba terhubung ke WiFi..."); } Serial.println("Tersambung ke jaringan WiFi"); Serial.print("Alamat IP: "); Serial.println(WiFi.localIP()); showWiFiStatus("Connect to WiFi."); } void showFeederScreen() { DateTime now = rtc.now(); lcd.clear(); lcd.setCursor((LCD_COLS - 11) / 2, 0); lcd.print("Ikan Feeder"); lcd.setCursor((LCD_COLS - 5) / 2, 1); lcd.print(now.hour()); lcd.print(":"); if (now.minute() < 10) { lcd.print("0"); } lcd.print(now.minute()); } void showNextFeedingTimeScreen() { lcd.clear(); lcd.setCursor(0, 0); lcd.print("Pakan Berikutnya:"); lcd.setCursor(0, 1); DateTime now = rtc.now(); if (now.hour() < feedTimeMorningHour || (now.hour() == feedTimeMorningHour && now.minute() < feedTimeMorningMinute)) { lcd.print("Pagi "); lcd.print(feedTimeMorningHour); lcd.print(":"); if (feedTimeMorningMinute < 10) { lcd.print("0"); } lcd.print(feedTimeMorningMinute); } else if (now.hour() < feedTimeNoonHour || (now.hour() == feedTimeNoonHour && now.minute() < feedTimeNoonMinute)) { lcd.print("Siang "); lcd.print(feedTimeNoonHour); lcd.print(":"); if (feedTimeNoonMinute < 10) { lcd.print("0"); } lcd.print(feedTimeNoonMinute); } else if (now.hour() < feedTimeNightHour || (now.hour() == feedTimeNightHour && now.minute() < feedTimeNightMinute)) { lcd.print("Malam "); lcd.print(feedTimeNightHour); lcd.print(":"); if (feedTimeNightMinute < 10) { lcd.print("0"); } lcd.print(feedTimeNightMinute); } else { lcd.print("Pagi "); lcd.print(feedTimeMorningHour); lcd.print(":"); if (feedTimeMorningMinute < 10) { lcd.print("0"); } lcd.print(feedTimeMorningMinute); } } void showTDSReadingScreen(unsigned int tdsValue) { String quality; if (tdsValue <= TDS_THRESHOLD) { quality = "Baik"; digitalWrite(BUZZER_PIN, LOW); } else { quality = "Buruk"; digitalWrite(BUZZER_PIN, HIGH); digitalWrite(PENGURAS_PIN, HIGH); } if (WaterLevelPengurasStatus == LOW) { digitalWrite(PENGURAS_PIN, LOW); digitalWrite(PENGISI_PIN, HIGH); } if (WaterLevelPengisiStatus == HIGH) { digitalWrite(PENGISI_PIN, LOW); } lcd.clear(); lcd.setCursor(0, 0); lcd.print("TDS : "); lcd.print(tdsValue); lcd.print(" ppm"); lcd.setCursor(0, 1); lcd.print("Kualitas : "); lcd.print(quality); } unsigned int readTDS() { int sensorValue = analogRead(TDS_SENSOR_PIN); unsigned int tdsValue = map(sensorValue, 0, 1023, 0, 1000); WaterLevelPengurasStatus = digitalRead(WATERLEVEL_PENGURAS_PIN); WaterLevelPengisiStatus = digitalRead(WATERLEVEL_PENGISI_PIN); sendTDSReadingToBlynk(tdsValue); return tdsValue; } void feedFish() { showFeedingStatus(); feeder.write(22); delay(1000); feeder.write(0); delay(500); feeder.write(18); delay(500); feeder.write(0); } void openFeeder() { feedFish(); } void showFeedingStatus() { lcd.clear(); lcd.setCursor((LCD_COLS - 16) / 2, 0); lcd.print("-Sedang Memberi-"); lcd.setCursor((LCD_COLS - 16) / 2, 1); lcd.print("-----Pakan-----"); } void updateBuzzer(unsigned int tdsValue) { if (tdsValue <= TDS_THRESHOLD) { digitalWrite(BUZZER_PIN, LOW); } else { digitalWrite(BUZZER_PIN, HIGH); } } void updateRelayAndWaterLevel() { if (WaterLevelPengurasStatus == LOW) { digitalWrite(PENGURAS_PIN, LOW); digitalWrite(PENGISI_PIN, HIGH); } if (WaterLevelPengisiStatus == HIGH) { digitalWrite(PENGISI_PIN, LOW); } } void activatePenguras() { digitalWrite(PENGURAS_PIN, HIGH); } void sendTDSReadingToBlynk(unsigned int tdsValue) { Blynk.virtualWrite(PIN_TDS_READING, tdsValue); } void sendTDSNotification() { Blynk.logEvent("notify","Kualitas air akuarium Buruk! Mohon segera cek!"); } BLYNK_WRITE(PIN_BUTTON_SERVO) { int pinValue = param.asInt(); if (pinValue == 1) { openFeeder(); } } BLYNK_WRITE(PIN_BUTTON_PENGURAS) { int pinValue = param.asInt(); if (pinValue == 1) { activatePenguras(); } } // Blynk handlers for time inputs BLYNK_WRITE(PIN_TIME_MORNING) { TimeInputParam t(param); if (t.hasStartTime()) { feedTimeMorningHour = t.getStartHour(); feedTimeMorningMinute = t.getStartMinute(); Serial.print("Waktu Pagi diatur ke: "); Serial.print(feedTimeMorningHour); Serial.print(":"); Serial.println(feedTimeMorningMinute); } } BLYNK_WRITE(PIN_TIME_NOON) { TimeInputParam t(param); if (t.hasStartTime()) { feedTimeNoonHour = t.getStartHour(); feedTimeNoonMinute = t.getStartMinute(); Serial.print("Waktu Siang diatur ke: "); Serial.print(feedTimeNoonHour); Serial.print(":"); Serial.println(feedTimeNoonMinute); } } BLYNK_WRITE(PIN_TIME_NIGHT) { TimeInputParam t(param); if (t.hasStartTime()) { feedTimeNightHour = t.getStartHour(); feedTimeNightMinute = t.getStartMinute(); Serial.print("Waktu Malam diatur ke: "); Serial.print(feedTimeNightHour); Serial.print(":"); Serial.println(feedTimeNightMinute); } }