#include <LiquidCrystal_I2C.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <EEPROM.h>
// LCD Setup
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Data wire is plugged into digital pin 4 on the Arduino
#define ONE_WIRE_BUS1 6
#define ONE_WIRE_BUS2 7
OneWire oneWire1(ONE_WIRE_BUS1);
OneWire oneWire2(ONE_WIRE_BUS2);
DallasTemperature sensor1(&oneWire1);
DallasTemperature sensor2(&oneWire2);
// Pins for buttons
#define MENU_BTN 2
#define SET_BTN 3
#define UP_BTN 4
#define DOWN_BTN 5
// Pin for relay
#define RELAY_PIN 8 // Relay connected to pin 8
#define EEPROM_MAGIC 0x42 // Arbitrary value to signify valid EEPROM data
#define MAGIC_ADDR 0 // EEPROM address to store the magic number
// Variables
float iceTemp = 0.0;
float ambientTemp = 0.0;
unsigned long timerStart = 0;
bool timerRunning = false;
bool dropCycle = false;
// Timers (in milliseconds)
unsigned long lowIceTimer = 10 * 60 * 1000; // 10 minutes default
unsigned long highIceTimer = 16 * 60 * 1000; // 16 minutes default
unsigned long lowDropTimer = 30 * 1000; // 30 seconds default
unsigned long highDropTimer = 60 * 1000; // 60 seconds default
// Temperature bounds
float ambientLow = 15.0;
float ambientHigh = 35.0;
float iceLow = -10.0;
float iceHigh = -5.0;
// Menu variables
int menuState = 0; // 0 = normal display, 1+ = menu
bool settingValue = false;
void setup() {
lcd.init();
lcd.backlight();
lcd.print("System Initializing");
delay(2000);
lcd.clear();
pinMode(MENU_BTN, INPUT_PULLUP);
pinMode(SET_BTN, INPUT_PULLUP);
pinMode(UP_BTN, INPUT_PULLUP);
pinMode(DOWN_BTN, INPUT_PULLUP);
pinMode(RELAY_PIN, OUTPUT); // Relay pin as output
digitalWrite(RELAY_PIN, LOW); // Ensure relay starts off
sensor1.begin();
sensor2.begin();
// First-time setup check
if (EEPROM.read(MAGIC_ADDR) != EEPROM_MAGIC) {
initializeEEPROMDefaults();
} else {
loadSettingsFromEEPROM();
}
}
void loop() {
handleButtons();
if (menuState == 0) {
readTemperatures();
manageTimers();
displayStatus();
} else {
handleMenu();
}
delay(200);
}
// Handle button inputs
void handleButtons() {
if (digitalRead(MENU_BTN) == LOW) {
menuState = (menuState + 1) % 8; // Cycle through menu states
settingValue = false;
delay(300);
}
if (digitalRead(SET_BTN) == LOW) {
settingValue = !settingValue; // Toggle between viewing and setting
if (!settingValue) saveSettingsToEEPROM();
delay(300);
}
if (settingValue) {
if (digitalRead(UP_BTN) == LOW) {
adjustMenuValue(1);
delay(200);
}
if (digitalRead(DOWN_BTN) == LOW) {
adjustMenuValue(-1);
delay(200);
}
}
}
// Read temperatures
void readTemperatures() {
sensor1.requestTemperatures();
sensor2.requestTemperatures();
iceTemp = sensor1.getTempCByIndex(0);
ambientTemp = sensor2.getTempCByIndex(0);
}
// Manage timers and drop cycle
void manageTimers() {
unsigned long iceMakingDuration = map(ambientTemp, ambientLow, ambientHigh, lowIceTimer, highIceTimer);
unsigned long dropDuration = map(ambientTemp, ambientLow, ambientHigh, lowDropTimer, highDropTimer);
// Ice-making cycle
if (!timerRunning && !dropCycle && iceTemp <= iceLow) {
timerStart = millis();
timerRunning = true;
}
// If in ice-making mode
if (timerRunning) {
if (millis() - timerStart >= iceMakingDuration) {
timerRunning = false;
dropCycle = true;
timerStart = millis();
// Activate relay to trigger solenoid
digitalWrite(RELAY_PIN, HIGH);
}
}
// If in drop cycle
else if (dropCycle) {
if (millis() - timerStart >= dropDuration) {
dropCycle = false;
// Deactivate relay to stop solenoid
digitalWrite(RELAY_PIN, LOW);
}
}
}
// Display status in normal mode
void displayStatus() {
lcd.setCursor(0, 0);
lcd.print("Ice:");
lcd.print(iceTemp, 1);
lcd.print("C ");
lcd.setCursor(0, 1);
lcd.print("Amb:");
lcd.print(ambientTemp, 1);
lcd.print("C ");
if (timerRunning) {
lcd.setCursor(10, 0);
lcd.print("IceForm");
lcd.setCursor(10, 1);
unsigned long remaining = map(ambientTemp, ambientLow, ambientHigh, lowIceTimer, highIceTimer) - (millis() - timerStart);
displayTimer(remaining, 10, 1);
} else if (dropCycle) {
lcd.setCursor(10, 0);
lcd.print("Droping");
lcd.setCursor(10, 1);
unsigned long remaining = map(ambientTemp, ambientLow, ambientHigh, lowDropTimer, highDropTimer) - (millis() - timerStart);
displayTimer(remaining, 10, 1);
}
}
// Display timer in minutes:seconds format
void displayTimer(unsigned long duration, int cursorX, int cursorY) {
int minutes = duration / 60000;
int seconds = (duration % 60000) / 1000;
lcd.setCursor(cursorX, cursorY);
lcd.print(minutes);
lcd.print(":");
if (seconds < 10) lcd.print("0");
lcd.print(seconds);
}
// Handle menu navigation
void handleMenu() {
lcd.clear();
switch (menuState) {
case 1:
lcd.print("Amb Low: ");
lcd.print(ambientLow, 1);
break;
case 2:
lcd.print("Amb High: ");
lcd.print(ambientHigh, 1);
break;
case 3:
lcd.print("Ice Low: ");
lcd.print(iceLow, 1);
break;
case 4:
lcd.print("Ice High: ");
lcd.print(iceHigh, 1);
break;
case 5:
lcd.print("Low Ice Time: ");
displayTimer(lowIceTimer, 0, 1);
break;
case 6:
lcd.print("High Ice Time: ");
displayTimer(highIceTimer, 0, 1);
break;
case 7:
lcd.print("Low Drop Time: ");
displayTimer(lowDropTimer, 0, 1);
break;
case 8:
lcd.print("High Drop Time: ");
displayTimer(highDropTimer, 0, 1);
break;
}
}
// Adjust menu value
void adjustMenuValue(int direction) {
switch (menuState) {
case 1: ambientLow += direction * 0.5; break;
case 2: ambientHigh += direction * 0.5; break;
case 3: iceLow += direction * 0.5; break;
case 4: iceHigh += direction * 0.5; break;
case 5: lowIceTimer += direction * 10000; break; // Adjust by 10 seconds
case 6: highIceTimer += direction * 10000; break;
case 7: lowDropTimer += direction * 5000; break; // Adjust by 5 seconds
case 8: highDropTimer += direction * 5000; break;
}
}
// Save settings to EEPROM
void saveSettingsToEEPROM() {
EEPROM.put(1, ambientLow);
EEPROM.put(5, ambientHigh);
EEPROM.put(9, iceLow);
EEPROM.put(13, iceHigh);
EEPROM.put(17, lowIceTimer);
EEPROM.put(21, highIceTimer);
EEPROM.put(25, lowDropTimer);
EEPROM.put(29, highDropTimer);
}
// Load settings from EEPROM
void loadSettingsFromEEPROM() {
EEPROM.get(1, ambientLow);
EEPROM.get(5, ambientHigh);
EEPROM.get(9, iceLow);
EEPROM.get(13, iceHigh);
EEPROM.get(17, lowIceTimer);
EEPROM.get(21, highIceTimer);
EEPROM.get(25, lowDropTimer);
EEPROM.get(29, highDropTimer);
}
void initializeEEPROMDefaults() {
lcd.print("First Time Setup");
delay(2000);
lcd.clear();
// Default values
ambientLow = 10.0;
ambientHigh = 28.0;
iceLow = -10.0;
iceHigh = -7.0;
lowIceTimer = 600000; // 10 minutes
highIceTimer = 960000; // 16 minutes
lowDropTimer = 30000; // 30 seconds
highDropTimer = 901000; // 90 seconds
// Save values to EEPROM
saveSettingsToEEPROM();
// Write the magic number
EEPROM.write(MAGIC_ADDR, EEPROM_MAGIC);
lcd.print("Defaults Loaded");
delay(2000);
lcd.clear();
}