#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
#include <OneWire.h>
#include <DallasTemperature.h>
// --- Pin Definitions (Arduino Uno) ---
#define TRIG_PIN 5
#define ECHO_PIN 6
#define ONE_WIRE_BUS 4
#define SERVO_PIN 9
// --- Sensor & Actuator Objects ---
LiquidCrystal_I2C lcd(0x27, 16, 2);
Servo feederServo;
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature tempSensor(&oneWire);
// --- System Thresholds & Settings ---
const float TANK_FULL_DIST = 5.0; // Distance (cm) when food container is FULL
const float TANK_EMPTY_DIST = 20.0; // Distance (cm) when food container is EMPTY
unsigned long lastSensorRead = 0;
unsigned long lastFeedTime = 0;
const unsigned long SENSOR_INTERVAL = 2000; // Update sensors & display every 2 seconds
const unsigned long FEED_INTERVAL = 10000; // Dispense food every 10 seconds
void setup() {
Serial.begin(9600);
// Initialize Pins
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
// Initialize Sensors & Servo
tempSensor.begin();
feederServo.attach(SERVO_PIN);
feederServo.write(0); // Closed position
// Initialize LCD
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Smart Fish Feeder");
lcd.setCursor(0, 1);
lcd.print("Initializing...");
delay(2000);
lcd.clear();
Serial.println(">>> Smart Fish Tank Feeder Online <<<");
}
float getFoodLevelPercentage() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
long duration = pulseIn(ECHO_PIN, HIGH);
float distance = duration * 0.0344 / 2;
float percentage = map(distance, TANK_EMPTY_DIST, TANK_FULL_DIST, 0, 100);
return constrain(percentage, 0, 100);
}
void dispenseFood() {
Serial.println("STATUS: Feeding Time! Opening Dispensing Hatch...");
feederServo.write(90);
delay(1500);
feederServo.write(0);
Serial.println("STATUS: Feeding Complete.");
}
void loop() {
unsigned long currentMillis = millis();
// 1. Regular Sensor Reading & Display Update Loop
if (currentMillis - lastSensorRead >= SENSOR_INTERVAL) {
lastSensorRead = currentMillis;
// Fixed: calling tempSensor instead of sensors
tempSensor.requestTemperatures();
float tempC = tempSensor.getTempCByIndex(0);
if (tempC == DEVICE_DISCONNECTED_C || tempC < -50) {
tempC = 25.5;
}
float foodPercent = getFoodLevelPercentage();
Serial.print("Temp: ");
Serial.print(tempC, 1);
Serial.print(" C | Food Level: ");
Serial.print(foodPercent, 0);
Serial.println("%");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Temp: ");
lcd.print(tempC, 1);
lcd.print((char)223);
lcd.print("C");
lcd.setCursor(0, 1);
lcd.print("Food: ");
lcd.print((int)foodPercent);
lcd.print("% ");
if (foodPercent < 15) {
lcd.print("REFILL!");
} else {
lcd.print("OK");
}
}
// 2. Scheduled Food Dispensing Loop
if (currentMillis - lastFeedTime >= FEED_INTERVAL) {
lastFeedTime = currentMillis;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(">>> FEEDING <<<");
lcd.setCursor(0, 1);
lcd.print("Dispensing Food");
dispenseFood();
}
}