#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#include <Keypad.h>
#include <SD.h>
#define BUZZER_PIN 8
#define SD_CS_PIN 10 // Chip select pin for SD card
LiquidCrystal_I2C lcd(0x27, 16, 2); // Initialize LCD with address 0x27
RTC_DS1307 rtc; // Initialize DS1307 RTC
// Keypad setup
const byte ROWS = 4; // Four rows
const byte COLS = 4; // Four columns
char keys[ROWS][COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {9, 8, 7, 6}; // Connect to row pinouts
byte colPins[COLS] = {5, 4, 3, 2}; // Connect to column pinouts
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
File dataFile;
void setup() {
Serial.begin(9600);
// Initialize LCD
lcd.begin(16, 2);
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Smart Fridge 2.0");
// Initialize RTC
if (!rtc.begin()) {
Serial.println("RTC Error");
lcd.setCursor(0, 1);
lcd.print("RTC Error!");
while (1); // Stop if RTC is not found
}
if (!rtc.isrunning()) {
rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // Set time to compile time
}
// Initialize SD card
if (!SD.begin(SD_CS_PIN)) {
Serial.println("SD Card Initialization Failed!");
lcd.setCursor(0, 1);
lcd.print("SD Error!");
delay(5000);
lcd.clear();
return; // Allow program to run even if SD card fails
} else {
Serial.println("SD Card Initialized.");
}
// Open or create the data file
dataFile = SD.open("fridge.csv", FILE_WRITE);
if (dataFile) {
Serial.println("Successfully opened fridge.csv.");
if (dataFile.size() == 0) {
dataFile.println("ID,ExpiryDate,Location");
Serial.println("Added headers to fridge.csv.");
}
dataFile.close();
} else {
Serial.println("Error opening fridge.csv during setup.");
lcd.setCursor(0, 1);
lcd.print("File Error!");
delay(5000);
lcd.clear();
}
pinMode(BUZZER_PIN, OUTPUT); // Configure buzzer pin
lcd.setCursor(0, 0);
lcd.print("Smart Fridge Ready");
delay(2000);
lcd.clear();
}
void loop() {
lcd.setCursor(0, 0);
lcd.print("Enter Item ID...");
String inputID = getInput("ID:");
if (inputID != "") {
if (isDuplicateID(inputID)) {
lcd.clear();
lcd.print("Item Exists!");
activateBuzzer();
delay(2000);
return;
}
lcd.clear();
lcd.print("Enter Exp Date");
lcd.setCursor(0, 1);
lcd.print("DDMMYY:");
String expiryDateStr = getInput("Date:");
DateTime expiryDate = parseExpiryDate(expiryDateStr);
if (expiryDate.unixtime() == 0 || !isValidDate(expiryDate)) {
lcd.clear();
lcd.print("Invalid Date!");
activateBuzzer();
} else {
lcd.clear();
lcd.print("Enter Location:");
String location = getInput("Loc:");
addItemToCSV(inputID, expiryDate, location); // Add item to the CSV file
checkExpirations(); // Check for items nearing expiration
}
}
delay(1000);
}
bool isDuplicateID(String id) {
dataFile = SD.open("fridge.csv", FILE_READ);
if (dataFile) {
while (dataFile.available()) {
String line = dataFile.readStringUntil('\n');
if (line.startsWith("ID")) continue; // Skip header line
int firstComma = line.indexOf(',');
String existingID = line.substring(0, firstComma);
if (existingID == id) {
dataFile.close();
return true;
}
}
dataFile.close();
} else {
Serial.println("Error reading fridge.csv");
lcd.clear();
lcd.print("Read Error!");
delay(2000);
}
return false;
}
String getInput(String prompt) {
String input = "";
char key;
lcd.setCursor(0, 1);
lcd.print("Press # to end");
while (true) {
key = keypad.getKey();
if (key) {
if (key == '#') {
return input; // End input on '#'
} else if (key == '*') {
input = ""; // Reset input on '*'
lcd.setCursor(0, 1);
lcd.print(prompt + " ");
} else {
input += key; // Append key to the input
lcd.setCursor(0, 1);
lcd.print(prompt + input);
}
}
}
}
DateTime parseExpiryDate(String dateStr) {
// Parse expiry date in DDMMYY format
if (dateStr.length() != 6) return DateTime(2000, 1, 1, 0, 0, 0);
int day = dateStr.substring(0, 2).toInt();
int month = dateStr.substring(2, 4).toInt();
int year = 2000 + dateStr.substring(4, 6).toInt(); // Assuming year is YY format (e.g., 23 -> 2023)
if (day < 1 || day > 31 || month < 1 || month > 12) return DateTime(2000, 1, 1, 0, 0, 0);
return DateTime(year, month, day, 0, 0, 0);
}
bool isValidDate(DateTime date) {
DateTime placeholder(2000, 1, 1, 0, 0, 0);
if (date == placeholder) return false;
DateTime now = rtc.now();
return date >= now; // Date must be today or in the future
}
void addItemToCSV(String id, DateTime expiryDate, String location) {
String expiryDateStr = String(expiryDate.year()) + "-" + String(expiryDate.month()) + "-" + String(expiryDate.day());
dataFile = SD.open("fridge.csv", FILE_WRITE);
if (dataFile) {
dataFile.println(id + "," + expiryDateStr + "," + location);
dataFile.close();
lcd.clear();
lcd.print("Added: " + id);
lcd.setCursor(0, 1);
lcd.print("Loc: " + location);
delay(2000);
} else {
Serial.println("Error writing to fridge.csv");
lcd.clear();
lcd.print("Write Error!");
delay(2000);
}
}
void checkExpirations() {
DateTime now = rtc.now();
dataFile = SD.open("fridge.csv", FILE_READ);
if (dataFile) {
while (dataFile.available()) {
String line = dataFile.readStringUntil('\n');
if (line.startsWith("ID")) continue; // Skip header line
int firstComma = line.indexOf(',');
int secondComma = line.indexOf(',', firstComma + 1);
String id = line.substring(0, firstComma);
String expiryDateStr = line.substring(firstComma + 1, secondComma);
DateTime expiryDate = parseExpiryDateFromString(expiryDateStr);
if ((expiryDate - now).days() <= 1) {
lcd.clear();
lcd.print(id);
lcd.setCursor(0, 1);
lcd.print("Expires Soon!");
activateBuzzer();
delay(2000);
}
}
dataFile.close();
} else {
Serial.println("Error reading fridge.csv");
}
}
DateTime parseExpiryDateFromString(String dateStr) {
int firstDash = dateStr.indexOf('-');
int secondDash = dateStr.indexOf('-', firstDash + 1);
int year = dateStr.substring(0, firstDash).toInt();
int month = dateStr.substring(firstDash + 1, secondDash).toInt();
int day = dateStr.substring(secondDash + 1).toInt();
return DateTime(year, month, day);
}
void activateBuzzer() {
digitalWrite(BUZZER_PIN, HIGH);
delay(2000);
digitalWrite(BUZZER_PIN, LOW);
}