#include <WiFi.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>
#include <RTClib.h>
#include <ESP32Servo.h>
// Pin definitions
#define DHT_PIN 4
#define DHT_TYPE DHT22
#define SWITCH_PIN 34
#define SERVO_PIN 18
#define RELAY_FAN_PIN 19
#define LED_PIN 23
#define RELAY_PUMP_PIN 25
// I2C pins for LCD and RTC (default ESP32)
// SDA = Pin 21, SCL = Pin 22
// Thresholds
#define TEMP_HIGH 35
#define TEMP_LOW 30
// Switch variables
bool switchState = false;
bool lastSwitchState = false;
// Initialize components
LiquidCrystal_I2C lcd(0x27, 16, 2);
DHT dht(DHT_PIN, DHT_TYPE);
RTC_DS3231 rtc;
Servo feedServo;
// Variables
float temperature = 0;
bool fanStatus = false;
bool ledStatus = false;
bool pumpStatus = false;
bool servoActive = false;
// Feeding schedule variables
bool morning_fed = false;
bool evening_fed = false;
void setup() {
Serial.begin(115200);
// Initialize LCD
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("System Starting");
// Initialize DHT sensor
dht.begin();
// Initialize RTC
if (!rtc.begin()) {
Serial.println("RTC not found");
lcd.setCursor(0, 1);
lcd.print("RTC Error!");
while (1);
}
// Set RTC time to 7:00 AM today for testing
rtc.adjust(DateTime(2024, 8, 29, 7, 0, 0));
Serial.println("RTC time set to 7:00 AM for testing");
// Initialize servo
feedServo.attach(SERVO_PIN);
feedServo.write(0); // Initial position
// Initialize pins
pinMode(RELAY_FAN_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
pinMode(RELAY_PUMP_PIN, OUTPUT);
pinMode(SWITCH_PIN, INPUT_PULLUP); // Internal pull-up resistor for switch
// Initial state - all off
digitalWrite(RELAY_FAN_PIN, LOW);
digitalWrite(LED_PIN, LOW);
digitalWrite(RELAY_PUMP_PIN, LOW);
delay(2000);
lcd.clear();
Serial.println("System initialized - Switch mode active");
}
void loop() {
// Read sensors
readSensors();
// Read switch state
readSwitch();
// Control temperature
controlTemperature();
// Control water pump based on switch position
controlWaterPumpSwitch();
// Control feeding schedule
controlFeeding();
// Update LCD display
updateDisplay();
delay(100); // Update every 100ms
}
void readSensors() {
// Read temperature
temperature = dht.readTemperature();
if (isnan(temperature)) {
temperature = 0; // Default value if reading fails
}
}
void readSwitch() {
// Read switch state (LOW when switch is ON due to pull-up)
switchState = !digitalRead(SWITCH_PIN);
// Detect switch state change
if (switchState != lastSwitchState) {
Serial.print("Switch state changed to: ");
Serial.println(switchState ? "ON" : "OFF");
// Remove delay for instant response
}
lastSwitchState = switchState;
}
void controlTemperature() {
if (temperature > TEMP_HIGH) {
// Suhu tinggi → kipas ON, heater OFF
digitalWrite(RELAY_FAN_PIN, HIGH);
fanStatus = true;
digitalWrite(LED_PIN, LOW);
ledStatus = false;
Serial.println("Temp HIGH -> Fan ON, Heater OFF");
}
else if (temperature < TEMP_LOW) {
// Suhu rendah → heater ON, kipas OFF
digitalWrite(RELAY_FAN_PIN, LOW);
fanStatus = false;
digitalWrite(LED_PIN, HIGH);
ledStatus = true;
Serial.println("Temp LOW -> Heater ON, Fan OFF");
}
else {
// Suhu 30–35 → keduanya OFF
digitalWrite(RELAY_FAN_PIN, LOW);
fanStatus = false;
digitalWrite(LED_PIN, LOW);
ledStatus = false;
Serial.println("Temp NORMAL (30-35) -> Fan OFF, Heater OFF");
}
}
void controlWaterPumpSwitch() {
// Control pump relay based on switch position
bool newPumpStatus = switchState; // Pump follows switch state directly
if (newPumpStatus != pumpStatus) {
pumpStatus = newPumpStatus;
digitalWrite(RELAY_PUMP_PIN, pumpStatus ? HIGH : LOW);
Serial.print("Switch control - Pump Relay ");
Serial.println(pumpStatus ? "ON" : "OFF");
}
}
void controlFeeding() {
DateTime now = rtc.now();
// Display current time for monitoring
static unsigned long lastTimeDisplay = 0;
if (millis() - lastTimeDisplay > 5000) { // Display every 5 seconds
Serial.print("Current time: ");
Serial.print(now.hour());
Serial.print(":");
if (now.minute() < 10) Serial.print("0");
Serial.print(now.minute());
Serial.print(":");
if (now.second() < 10) Serial.print("0");
Serial.println(now.second());
lastTimeDisplay = millis();
}
// Morning feeding at 7:00 AM
if (now.hour() == 7 && now.minute() == 0 && !morning_fed) {
activateServo();
morning_fed = true;
Serial.println("Morning feeding activated at 7:00 AM");
}
// Evening feeding at 4:00 PM (16:00)
if (now.hour() == 16 && now.minute() == 0 && !evening_fed) {
activateServo();
evening_fed = true;
Serial.println("Evening feeding activated at 4:00 PM");
}
// Reset feeding flags at midnight
if (now.hour() == 0 && now.minute() == 0) {
morning_fed = false;
evening_fed = false;
Serial.println("Feeding flags reset at midnight");
}
}
void activateServo() {
servoActive = true;
Serial.println("Starting servo feeding cycle...");
feedServo.write(90); // Move to 90 degrees
// Non-blocking delay using millis() to keep display updating
unsigned long startTime = millis();
while (millis() - startTime < 10000) { // 10 seconds
// Update display during servo operation
updateDisplay();
delay(100);
}
feedServo.write(0); // Return to 0 degrees
servoActive = false;
Serial.println("Servo feeding cycle completed");
}
void updateDisplay() {
DateTime now = rtc.now();
// First line: Temperature and time
lcd.setCursor(0, 0);
lcd.print("T:");
lcd.print(temperature, 1);
lcd.print("C ");
// Display current time
if (now.hour() < 10) lcd.print("0");
lcd.print(now.hour());
lcd.print(":");
if (now.minute() < 10) lcd.print("0");
lcd.print(now.minute());
// Second line: Status indicators
lcd.setCursor(0, 1);
// Clear the line first
lcd.print(" ");
lcd.setCursor(0, 1);
// Priority 1: Show feeding status when servo is active
if (servoActive) {
if (now.hour() == 7) {
lcd.print("MORNING FEED");
} else if (now.hour() == 16) {
lcd.print("EVENING FEED");
} else {
lcd.print("MIDNIGHT FEED");
}
}
// Priority 2: Show other active components
else {
bool anyActive = false;
if (fanStatus) {
lcd.print("FAN ");
anyActive = true;
}
if (ledStatus) {
lcd.print("HEAT ");
anyActive = true;
}
if (pumpStatus) {
lcd.print("PUMP ");
anyActive = true;
}
// If nothing is active, show switch status
if (!anyActive) {
lcd.print("SW:");
lcd.print(switchState ? "ON" : "OFF");
}
}
}
// Function to manually test components (call from serial monitor)
void testComponents() {
Serial.println("Testing all components...");
// Test fan relay
Serial.println("Testing Fan Relay...");
digitalWrite(RELAY_FAN_PIN, HIGH);
delay(2000);
digitalWrite(RELAY_FAN_PIN, LOW);
// Test LED
Serial.println("Testing LED...");
digitalWrite(LED_PIN, HIGH);
delay(2000);
digitalWrite(LED_PIN, LOW);
// Test pump relay
Serial.println("Testing Pump Relay...");
digitalWrite(RELAY_PUMP_PIN, HIGH);
delay(2000);
digitalWrite(RELAY_PUMP_PIN, LOW);
// Test servo
Serial.println("Testing Servo...");
feedServo.write(90);
delay(2000);
feedServo.write(0);
Serial.println("Component test completed");
}
// Function to set current time (call from serial monitor if needed)
void setCurrentTime() {
// Set to current time - modify as needed
rtc.adjust(DateTime(2024, 8, 29, 7, 0, 0));
Serial.println("RTC time manually set to 7:00 AM");
}