#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <RTClib.h>
#include <Servo.h> // Library untuk motor servo
// Inisialisasi LCD I2C
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Inisialisasi Sensor Suhu
#define ONE_WIRE_BUS 2
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
// Inisialisasi RTC
RTC_DS1307 rtc;
// Inisialisasi Servo
Servo servoPakan;
const int servoPin = 7; // Pin untuk servo
// Pin Sensor Ultrasonik
const int trigPin = 3;
const int echoPin = 4;
// Pin Relay dan Push Button
const int relayPin = 5;
const int buttonPin = 6;
// Variabel suhu dan jarak
float suhuAir;
long duration;
int distance;
// Rentang Membership Function
float suhuCold = 22.0;
float suhuHot = 30.0;
int jarakNear = 30;
int jarakFar = 70;
// Variabel untuk push button
bool buttonState = false;
bool lastButtonState = false;
bool manualFeed = false;
unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 50;
// Variabel waktu untuk pemberian pakan otomatis
bool hasFedMorning = false;
bool hasFedEvening = false;
void setup() {
Serial.begin(9600);
lcd.init();
lcd.backlight();
sensors.begin();
if (!rtc.begin()) {
lcd.setCursor(0, 0);
lcd.print("RTC Error!");
while (1);
}
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(relayPin, OUTPUT);
pinMode(buttonPin, INPUT_PULLUP);
// Inisialisasi Servo
servoPakan.attach(servoPin);
servoPakan.write(0); // Tutup dispenser pakan
digitalWrite(relayPin, LOW);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("System Ready");
delay(2000);
}
void loop() {
DateTime now = rtc.now();
// Reset status pemberian pakan harian pada tengah malam
if (now.hour() == 0 && now.minute() == 0) {
hasFedMorning = false;
hasFedEvening = false;
}
// Pemberian pakan otomatis pada pukul 07:00 dan 17:00
if (!hasFedMorning && now.hour() == 7 && now.minute() == 0) {
automaticFeeding(5);
hasFedMorning = true;
}
if (!hasFedEvening && now.hour() == 17 && now.minute() == 0) {
automaticFeeding(5);
hasFedEvening = true;
}
// Membaca Suhu
sensors.requestTemperatures();
suhuAir = sensors.getTempCByIndex(0);
if (suhuAir == -127.0) {
suhuAir = 25.0; // Nilai default jika pembacaan gagal
}
// Membaca Jarak
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = duration * 0.034 / 2;
if (distance == 0 || distance > 400) {
distance = 100; // Nilai default jika pembacaan gagal
}
// Membaca Push Button untuk kontrol manual
buttonState = debounceButton();
if (buttonState && !lastButtonState) {
manualFeed = true;
}
lastButtonState = buttonState;
// Jika mode manual aktif, beri pakan selama durasi tertentu (5 detik)
if (manualFeed) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Manual Feeding");
bukaDispenser();
delay(5000);
tutupDispenser();
manualFeed = false;
} else {
// Fuzzy Logic: Durasi Pakan
int durasiPakan = fuzzyLogicPakan(suhuAir, distance);
// Tampilkan di LCD
lcd.setCursor(0, 0);
lcd.print("Suhu: ");
lcd.print(suhuAir);
lcd.print(" C ");
lcd.setCursor(0, 1);
lcd.print("Dist: ");
lcd.print(distance);
lcd.print(" cm ");
// Memberi Pakan berdasarkan hasil Fuzzy Logic
if (durasiPakan > 0) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Feeding: ");
lcd.print(durasiPakan);
lcd.print(" s");
bukaDispenser();
delay(durasiPakan * 1000);
tutupDispenser();
}
}
delay(1000);
}
// Fungsi Pemberian Pakan Otomatis
void automaticFeeding(int durasi) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Auto Feeding");
bukaDispenser();
delay(durasi * 1000);
tutupDispenser();
}
// Fungsi Debounce Push Button
bool debounceButton() {
bool currentState = !digitalRead(buttonPin);
if (currentState != lastButtonState) {
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
if (currentState != buttonState) {
buttonState = currentState;
}
}
return buttonState;
}
// Fungsi untuk membuka dispenser
void bukaDispenser() {
servoPakan.write(90);
}
// Fungsi untuk menutup dispenser
void tutupDispenser() {
servoPakan.write(0);
}
// Fungsi Fuzzy Logic
int fuzzyLogicPakan(float suhu, int jarak) {
float durasiPakan = 0;
float cold = (suhu <= suhuCold) ? 1 : (suhu < suhuHot ? (suhuHot - suhu) / (suhuHot - suhuCold) : 0);
float optimal = (suhu > suhuCold && suhu < suhuHot) ? 1 : 0;
float hot = (suhu >= suhuHot) ? 1 : (suhu > suhuCold ? (suhu - suhuCold) / (suhuHot - suhuCold) : 0);
float near = (jarak <= jarakNear) ? 1 : (jarak < jarakFar ? (jarakFar - jarak) / (jarakFar - jarakNear) : 0);
if (cold > 0 && near > 0) durasiPakan = 2;
else if (optimal > 0 && near > 0) durasiPakan = 5;
else if (optimal > 0) durasiPakan = 3;
else if (hot > 0 && near > 0) durasiPakan = 1;
else durasiPakan = 0;
return int(durasiPakan);
}