#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <OneWire.h>
#include <DallasTemperature.h>
// Relay and temperature sensor pins
#define RELAY_PIN 2
#define TEMP_SENSOR_PIN 3
// Button pins
#define SET_BUTTON_PIN 4
#define UP_BUTTON_PIN 5
#define DOWN_BUTTON_PIN 6
#define RESET_BUTTON_PIN 7
#define START_MASH_BUTTON_PIN 8 // New button for starting MASH
// Limits for temperature and time
#define MIN_MASH_TEMP 65
#define MAX_MASH_TEMP 69
#define MIN_MASH_TIME 1 // Minimum mash time in minutes
#define MAX_MASH_TIME 9 // Maximum mash time in minutes
// Default target temperature and time
#define TARGET_TEMP 65 // Default temperature within the mash range
#define TARGET_STIKE 75 // Default Strike Temp
#define TARGET_TIME 1 // Default mash time in minutes
// Strike Water temp and time
// Initialize display and temp sensor
LiquidCrystal_I2C lcd(0x27, 20, 4);
OneWire oneWire(TEMP_SENSOR_PIN);
DallasTemperature sensors(&oneWire);
// Variables to store user input
int targetTemp;
int targetStrike;
int mashTime;
void setup() {
// Initialize display
lcd.init();
lcd.backlight();
// Initialize relay and buttons
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW);
pinMode(SET_BUTTON_PIN, INPUT_PULLUP);
pinMode(UP_BUTTON_PIN, INPUT_PULLUP);
pinMode(DOWN_BUTTON_PIN, INPUT_PULLUP);
pinMode(RESET_BUTTON_PIN, INPUT_PULLUP);
pinMode(START_MASH_BUTTON_PIN, INPUT_PULLUP); // Initialize start mash button
// Initialize temperature sensor
sensors.begin();
// Set initial values
targetTemp = TARGET_TEMP; // Default mash temperature
targetStrike = TARGET_STIKE; // Default Strike Temp
mashTime = TARGET_TIME; // Default mash time
}
void loop() {
// User input for temperature and time
adjustSettings();
// Heat to strike temperature
heatToTemperature(targetStrike, "Heating Strike");
// Wait for the user to press the button to start MASH
waitForMashStart();
// Mash timer
countdownTimer(mashTime, targetTemp, "Mash Temp:");
// Wait for the user to press the button to start Boil
waitForBoilStart();
// Heat to boil temperature
heatToTemperature(99.5, "Heating Boil: ");
// Boil timer (if used)
countdownTimer(mashTime, 99.9, "Boil Temp:");
// End of process
digitalWrite(RELAY_PIN, LOW);
lcd.clear();
lcd.print(" Boil Complete!");
delay(90000); // Hold message for 5 seconds
}
// Function to adjust temperature and time settings
void adjustSettings() {
bool adjusting = true;
int settingIndex = 0; // 0: Temperature, 1: Time
while (adjusting) {
lcd.clear();
lcd.print(settingIndex == 0 ? "Set Mash Temp: " : "Set Mash Time: ");
lcd.print(settingIndex == 0 ? targetTemp : mashTime);
lcd.setCursor(0, 2);
lcd.print("Press SET to Confirm");
delay(300); // Avoid button bouncing
// Check for button presses
if (digitalRead(UP_BUTTON_PIN) == LOW) {
if (settingIndex == 0 && targetTemp < MAX_MASH_TEMP) {
targetTemp++;
} else if (settingIndex == 1 && mashTime < MAX_MASH_TIME) {
mashTime++;
}
delay(200); // Delay to slow down increments
} else if (digitalRead(DOWN_BUTTON_PIN) == LOW) {
if (settingIndex == 0 && targetTemp > MIN_MASH_TEMP) {
targetTemp--;
} else if (settingIndex == 1 && mashTime > MIN_MASH_TIME) {
mashTime--;
}
delay(200); // Delay to slow down decrements
} else if (digitalRead(SET_BUTTON_PIN) == LOW) {
settingIndex++;
delay(500); // Delay to avoid bouncing
if (settingIndex > 1) {
adjusting = false; // Exit the loop when both settings are confirmed
}
}
}
}
// Function to heat to a specified temperature
void heatToTemperature(float targetTemp, const char* label) {
float currentTemp;
do {
sensors.requestTemperatures();
currentTemp = sensors.getTempCByIndex(0);
// Control relay
if (currentTemp < targetTemp) {
digitalWrite(RELAY_PIN, HIGH);
} else {
digitalWrite(RELAY_PIN, LOW);
}
// Display temperature
lcd.clear();
lcd.print(label);
lcd.print(currentTemp);
lcd.setCursor(9,1);
lcd.print(targetTemp);
lcd.setCursor(0,1);
lcd.print("Target:");
lcd.setCursor(0,3);
lcd.print("***^^^HEATING^^^***");
delay(300);
lcd.setCursor(0,3);
lcd.print("***___HEATING___***");
delay(300);
delay(1000);
} while (currentTemp < targetTemp);
}
// Function to wait for the user to press the button to start MASH
void waitForMashStart() {
lcd.clear();
lcd.print("Strike Temp Reached");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Press SET to MASH");
while (digitalRead(SET_BUTTON_PIN) == HIGH) {
// Wait until the start button is pressed
delay(100);
}
lcd.clear();
lcd.print("MASH Starting...");
delay(2000); // Give the user a moment to see the message
}
void waitForBoilStart() {
digitalWrite(RELAY_PIN, LOW);
lcd.clear();
lcd.print("Mash Finnish");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Press SET to BOIL");
while (digitalRead(SET_BUTTON_PIN) == HIGH) {
// Wait until the start button is pressed
delay(100);
}
lcd.clear();
lcd.print("Boil Starting...");
delay(2000); // Give the user a moment to see the message
}
// Function to handle the countdown timer
void countdownTimer(unsigned long targetTime, float targetTemp, const char* label) {
unsigned long startTime = millis();
unsigned long remainingTime = targetTime * 60; // Convert minutes to seconds
while (remainingTime > 0) {
// Update temperature
sensors.requestTemperatures();
float currentTemp = sensors.getTempCByIndex(0);
// Control relay
if (currentTemp < targetTemp) {
digitalWrite(RELAY_PIN, HIGH);
} else {
digitalWrite(RELAY_PIN, LOW);
}
// Display time
lcd.clear();
lcd.print("Time: ");
lcd.print(remainingTime / 60);
lcd.print(":");
lcd.print(remainingTime % 60);
lcd.setCursor(11,2);
lcd.print(currentTemp);
lcd.setCursor(0,2);
lcd.print(label);
// Update remaining time
remainingTime = targetTime * 60 - (millis() - startTime) / 1000;
// Check for reset button press
if (digitalRead(RESET_BUTTON_PIN) == LOW) {
startTime = millis();
remainingTime = targetTime * 60;
}
delay(1000);
}
}