/*-------------------------------------------------------------
Release 1 03/4/2012
Semi-automated HERMS (Heat Exchange Recirculating Mash System)
brewery and sous vide cooker.
Developed with Arduino IDE release 0023 and associated libraries
All code published as open source- do with it what you may!
by Jamie Abbott (j.abbott(at)dsl.pipex.com) 2011-12
--------------------------------------------------------------*/
#include <LiquidCrystal.h>
#include <PID_v1.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Bounce.h>
#include <avr/pgmspace.h>
#define ONE_WIRE_BUS 8 //One-Wire bus for 3 DS18b20 tempreature sensors on pin 8
OneWire oneWire(ONE_WIRE_BUS); //setup a oneWire instance to communicate with any OneWire devices
DallasTemperature sensors(&oneWire); //pass oneWire reference to Dallas Temperature.
float HLTtemp, Mash_CookTemp, BoilTemp,value; //define names of temp. sensors
LiquidCrystal lcd (2,3,4,5,6,7); //setup LCD display pins
const boolean PotPin=A0; //pump speed potentiometer
const boolean button_pin1=A5; //
const boolean button_pin2=A4; //buttons on analogue pins
const boolean button_pin3=A3; //
Bounce button1 = Bounce(button_pin1,5); //
Bounce button2 = Bounce(button_pin2,5); //setup de-bouncing on buttons
Bounce button3 = Bounce(button_pin3,5); //
const boolean HLTrelay=11; //
const boolean Mash_CookRelay=12; //solid State Relays controlling heating elements on analouge pins
const boolean BoilerRelay=13; //
const byte buzzer=9; //buzzer alarm to alert when a brew process has finished
const byte HERMSpumpFET=10; //MOSFET to control solar pump that re-circs wort around HERMS kettle control
unsigned short HLTtarget=78; //default mash liqour target temp. (hot enough to pre-heat mash tun)
unsigned short MashTarget=66; //default target mash temp.
unsigned short BoilTarget=100; //default boil target temp.
unsigned short SpargeTarget=75; //default sparge liqour target temp.
unsigned short MashTime=90; //default mash duration
unsigned short BoilTime=90; //default boil duration
unsigned short ChillTarget=25; //default target cool temp.
unsigned short PotValue; //to hold value from pump potentiometer
unsigned short PumpDisplay; //value as % of pump speed
unsigned short CookTarget=57; //default target cook temp.
unsigned long CookTime; //to store cooking duration
unsigned long CookHrs=2; //default cook time hours
unsigned long CookMins=30; //default cook time minutes
long time;
unsigned long MashStartTime, BrewEndTime, BoilStartTime, BrewStartTime, BrewDuration, CookStartTime; //brewday finish time
unsigned long lastPIDCalculation = 0;
boolean HLTon = true;
boolean BoilOff = true;
boolean ChillOn = true;
boolean set = true;
boolean CookTargetSet = true;
boolean CookHrsSet = true;
boolean CookMinsSet = true;
boolean state = true;
boolean BoilPause = false;
#define COOK 1 //menu mode for cooking sous vide
#define BREW 2 //menu mode for brewing
byte mode=0; //initalise menu mode
byte CookMenu=1; //initalise brew menu
byte BrewMenu=1; //initalise brew menu
double Setpoint, Input, Output; //
PID myPID(&Input, &Output, &Setpoint,5,2,1, DIRECT); //Specifies the PID links and initial tuning parameters
int WindowSize=2500; //
unsigned long windowStartTime; //
byte CustomChar[8]={ //
B00010, //
B01110, //
B10001, //Creates letter 'é'
B11111, //
B10000, //
B01110}; //
int eAcute; // //
//Text strings below stored in flash memory to save sapce in SRAM
const prog_uchar s01[] PROGMEM =" Welcome!";
const prog_uchar s02[] PROGMEM =" what do you want";
const prog_uchar s03[] PROGMEM =" to do?";
const prog_uchar s04[] PROGMEM ="COOK S-V BREW";
const prog_uchar s05[] PROGMEM =" Welcome to Fil's";
const prog_uchar s06[] PROGMEM =" Brewery" ;
const prog_uchar s07[] PROGMEM =" Press any button";
const prog_uchar s08[] PROGMEM =" to go forward ";
const prog_uchar s09[] PROGMEM =" Welcome to Fil's ";
const prog_uchar s10[] PROGMEM =" Sous Vide Cooker! ";
const prog_uchar s11[] PROGMEM =" Press any button ";
const prog_uchar s12[] PROGMEM =" to go forward ";
const prog_uchar s13[] PROGMEM =" HLT: ";
const prog_uchar s14[] PROGMEM =" MT: ";
const prog_uchar s15[] PROGMEM =" Boiler: ";
const prog_uchar s16[] PROGMEM =" PRESS ANY BUTTON";
const prog_uchar s17[] PROGMEM ="Ready to start mash!";
const prog_uchar s18[] PROGMEM ="Prime pump&fill HLT ";
const prog_uchar s19[] PROGMEM =" for sparge liquor ";
const prog_uchar s20[] PROGMEM =" ";
const prog_uchar s21[] PROGMEM =" HLT Setup ";
const prog_uchar s22[] PROGMEM ="Current Temp:";
const prog_uchar s23[] PROGMEM =" UP SET DOWN";
const prog_uchar s24[] PROGMEM =" Mash Setup ";
const prog_uchar s25[] PROGMEM =" Boil Setup ";
const prog_uchar s26[] PROGMEM ="Current Time:";
const prog_uchar s27[] PROGMEM =" Setup compleate";
const prog_uchar s28[] PROGMEM =" Ready to brew!";
const prog_uchar s29[] PROGMEM =" Is HLT Filled? ";
const prog_uchar s30[] PROGMEM ="BACK START";
const prog_uchar s31[] PROGMEM =" Mash liquor heating";
const prog_uchar s32[] PROGMEM ="Mash liquor ready!!!";
const prog_uchar s33[] PROGMEM =" HLT temp:";
const prog_uchar s34[] PROGMEM =" Target:";
const prog_uchar s35[] PROGMEM ="CHANGE OFF MASH";
const prog_uchar s36[] PROGMEM ="CHANGE ON MASH";
const prog_uchar s37[] PROGMEM ="CHANGE ON END";
const prog_uchar s38[] PROGMEM ="CHANGE OFF END";
const prog_uchar s39[] PROGMEM =" Mash temp:";
const prog_uchar s40[] PROGMEM =" Time left:";
const prog_uchar s41[] PROGMEM ="BACK CHANGE STOP";
const prog_uchar s42[] PROGMEM =" Mash Complete! ";
const prog_uchar s43[] PROGMEM =" BACK HLT ON BOIL";
const prog_uchar s44[] PROGMEM =" START ";
const prog_uchar s45[] PROGMEM ="BACK SPARGE";
const prog_uchar s46[] PROGMEM =" Sparge in ";
const prog_uchar s47[] PROGMEM =" Progress ";
const prog_uchar s48[] PROGMEM =" START";
const prog_uchar s49[] PROGMEM =" BACK HLT OFF BOIL";
const prog_uchar s50[] PROGMEM =" Boil temp:";
const prog_uchar s51[] PROGMEM ="BACK CHILL";
const prog_uchar s52[] PROGMEM ="BACK OFF END";
const prog_uchar s53[] PROGMEM ="BACK ON END";
const prog_uchar s54[] PROGMEM =" Boil finished!";
const prog_uchar s55[] PROGMEM ="CHANGE ON CHILL";
const prog_uchar s56[] PROGMEM ="CHANGE OFF CHILL";
const prog_uchar s57[] PROGMEM =" Chilling ";
const prog_uchar s58[] PROGMEM =" Chilling Finished! ";
const prog_uchar s59[] PROGMEM =" Wort temp:";
const prog_uchar s60[] PROGMEM =" Boil Finished! ";
const prog_uchar s61[] PROGMEM =" BREWDAY FINISHED! ";
const prog_uchar s62[] PROGMEM =" Time:";
const prog_uchar s63[] PROGMEM =" Here's to a good ";
const prog_uchar s64[] PROGMEM =" Beer! ";
const prog_uchar s65[] PROGMEM =" Sparge Liquor ";
const prog_uchar s66[] PROGMEM =" Temp:";
const prog_uchar s67[] PROGMEM ="BACK";
const prog_uchar s68[] PROGMEM =" UP HOURS DOWN";
const prog_uchar s69[] PROGMEM =" UP MINS DOWN";
const prog_uchar s70[] PROGMEM =" Cooking Complete ";
const prog_uchar s71[] PROGMEM =" Cook Temp:";
const prog_uchar s72[] PROGMEM =" Cook Time:";
const prog_uchar s73[] PROGMEM =" Change mins";
const prog_uchar s74[] PROGMEM ="BACK CHANGE OFF";
const prog_uchar s75[] PROGMEM ="BACK CHANGE ON";
const prog_uchar s76[] PROGMEM ="Pump";
const prog_uchar s77[] PROGMEM =" Bon app tit! ";
void PrintText (const prog_uchar str[]){ //
char c; //
if(!str) return; //print text stored in ProgMem
while((c = pgm_read_byte(str++))) //
lcd.print(c);} //
//-------------------------------------//
void StartScreen(){
/* Welcome!
what do you want
to do?
COOK S-V BREW */
lcd.clear();
PrintText (s01);
lcd.setCursor (0,1);
PrintText (s02);
lcd.setCursor (0,2);
PrintText (s03);
lcd.setCursor (0,3);
PrintText (s04);
Serial.begin(9600);
sensors.begin();
while (mode==0){ //
i f (button1.update()) { //Initiates Sous Vied cooking mode
Serial.println("into cooking ");
if (button1.read()==HIGH) { //
mode=COOK; //
}
}
if (button3.update()) {
if (button3.read()==HIGH) {
mode=BREW;
Serial.println("into brewing");
}
}
}
}
//-------------------------------------//
void CookWelcome(){
/* Welcome to Fil's
Sous Vide Cooker!
Press any button
to go forward */
lcd.clear();
while (CookMenu==1){
PrintText (s09);
lcd.setCursor(0,1);
PrintText(s10);
lcd.setCursor(0,2);
PrintText (s11);
lcd.setCursor(0,3);
PrintText (s12);
if (button1.update()||button2.update()||button3.update()) {
if ((button1.read()||button2.read()||button3.read())==HIGH){
CookMenu++;
CookStartTime=millis();
}
}
}
}
//-------------------------------------//
void Cooking(){
/* Cook Temp: 56.2°C
Target: 56.0°C
Time Left: 1h 38m
BACK CHANGE OFF */
lcd.clear();
float h,m;
unsigned long over;
CookTime=(CookHrs*3600000)+(CookMins*60000);
CookHrsSet=false;
CookMinsSet=false;
while (CookMenu==2){
if ((sensors.getDeviceCount())==0){ //
Serial.println("Failed device count cook");
Serial.print("num of sensors found = ");
Serial.print(sensors.getDeviceCount());
lcd.setCursor(0,0); //
PrintText (s20); //
lcd.setCursor(0,1); // Display warning
lcd.print(" *temprature probe* "); // if temp probe
lcd.setCursor(0,2); // not attached
lcd.print(" *not attached!* "); //
lcd.setCursor(0,3); //
PrintText (s20); //
}else{
time = CookTime - (millis()-CookStartTime)/60000;
h=int(time/3600000);
over=time%3600000;
m=int(over/60000);
sensors.requestTemperatures();
Mash_CookTemp=sensors.getTempCByIndex(2);
Input = Mash_CookTemp;
Setpoint = CookTarget;
myPID.Compute();
if(millis() - windowStartTime>WindowSize){
windowStartTime += WindowSize;}
if(Output > millis() - windowStartTime) digitalWrite(Mash_CookRelay,HIGH);
else digitalWrite(Mash_CookRelay,LOW);
PrintText(s71);
lcd.print(Mash_CookTemp);
lcd.setCursor(16,0);
degC();
lcd.setCursor(0,1);
PrintText(s34);
lcd.print(CookTarget);
lcd.setCursor(0,2);
PrintText(s40);
lcd.print(h,0);
lcd.print("h ");
lcd.print(m,0);
lcd.print("m ");
lcd.setCursor(0,3);
PrintText(s74);
PumpControl(); //HERMS pump used to recirculate water to maintain uniform water temp.
CookMenuButons(); //back - forward buttons
if (button2.update()){ //
if (button2.read()==HIGH){ //Change target cooking temp.
CookTargetSet=false; //
}
}
/* Cook Temp: 56.2°C
Target: 58.0°C
Time Left: 2h 38m
UP HOURS DOWN */
while (!CookTargetSet){
lcd.setCursor(0,3);
PrintText(s68);
if (button1.update()) {
if (button1.read()) {
CookTarget++;
}
}
if (button3.update()) {
if (button3.read()) {
CookTarget--;
}
}
lcd.setCursor(12,1);
lcd.print(CookTarget);
degCTarget();
if (CookTarget > 100){
CookTarget=0;}
if (CookTarget < 100){
lcd.setCursor(14,1);
degCTarget();}
if (CookTarget < 10){
lcd.setCursor(13,1);
degCTarget();}
if (button2.update()) {
if (button2.read()){
lcd.setCursor(0,3);
PrintText(s68);
CookTargetSet=true;
CookMenu++;
}
}
}
if (time<60000)CookMenu=5;
}
}
}
//-------------------------------------//
void CookTimeSetHours(){
/* Cook Temp: 56.2°C
Target: 56.0°C
Time Left: 3h 8m
UP MINS DOWN */
while (CookMenu==3){
lcd.setCursor(12,2);
lcd.print(CookHrs);
if (CookHrs > 72){
CookHrs=0;}
if (CookHrs < 10){
lcd.setCursor(11,2);}
if (CookHrs < 0){
CookHrs = 72;}
lcd.setCursor(0,3);
PrintText(s69);
if (button1.update()) {
if (button1.read()) {
CookHrs++;
}
}
if (button3.update()) {
if (button3.read()) {
CookHrs--;
}
}
if (button2.update()) {
if (button2.read()){
lcd.setCursor(0,3);
PrintText(s69);
CookMenu++;
}
}
}
}
//-------------------------------------//
void CookTimeSetMins(){
/* Cook Temp: 56.2°C
Target: 56.0°C
Time Left: 3h 15m
UP SET DOWN */
while (CookMenu==4){
lcd.setCursor(15,2);
lcd.print(CookMins);
if (CookMins > 59){
CookMins=0;}
if (CookMins < 1){
CookMins=59;}
if (CookHrs < 10){
lcd.setCursor(14,2);
degCTarget();}
lcd.setCursor(0,3);
PrintText(s23);
if (button1.update()) {
if (button1.read()) {
CookMins++;
}
}
if (button3.update()) {
if (button3.read()) {
CookMins--;
}
}
if (button2.update()) {
if (button2.read()){
CookMenu=2;
}
}
}
}
//-------------------------------------//
void CookFinished(){
/* Cooking Complete
Bon appétit! */
lcd.clear();
digitalWrite(Mash_CookRelay,LOW);
while (CookMenu==5){
PrintText(s70);
lcd.setCursor(0,1);
lcd.print(" ");
lcd.setCursor(0,3);
PrintText(s77);
lcd.setCursor(0,3);
lcd.setCursor(10,3);
lcd.write(eAcute);
}
}
//-------------------------------------//
void BrewWelcome(){
/* Welcome to Fil's
Brewery
Press any button
to go forward */
Serial.println("started brewing");
lcd.clear();
PrintText(s05);
lcd.setCursor(0,1);
PrintText(s06);
lcd.setCursor(0,2);
PrintText(s07);
lcd.setCursor(0,3);
PrintText(s08);
while (BrewMenu==1){
if (button1.update()||button2.update()||button3.update()) {
if ((button1.read()||button2.read()||button3.read())==HIGH){
BrewMenu++;
}
}
}
}
//-------------------------------------//
void BrewStart(){
/* HLT: 22.5°C
MT: 21.8°C
Boiler: 22.1°C
PRESS ANY BUTTON */
BrewStartTime = millis();
lcd.clear();
lcd.setCursor(0,0);
PrintText(s13);
lcd.setCursor(0,1);
PrintText(s14);
lcd.setCursor(0,2);
PrintText(s15);
lcd.setCursor(0,3);
PrintText(s16);
Serial.println("testing sensors?");
Serial.print(" brewmenu?= ");
Serial.print(BrewMenu);
while (BrewMenu==2){
if (sensors.getDeviceCount()<3){ //
Serial.println(sensors.getDeviceCount());
lcd.setCursor(0,0); //
PrintText (s20); //
lcd.setCursor(0,1); // Display warning if
lcd.print("*I HATE DEBUGGIN!"); // all 3 temp probes
lcd.setCursor(0,2); // are not attached
lcd.print("Fil's BrewPuter.. ");
lcd.print(sensors.getDeviceCount()); //
lcd.setCursor(0,3); //
lcd.print("Comming Soon * ");
PrintText (s20); //
}else{
sensors.requestTemperatures();
HLTtemp=sensors.getTempCByIndex(1);
Mash_CookTemp=sensors.getTempCByIndex(2);
BoilTemp=sensors.getTempCByIndex(0);
lcd.setCursor(11,0);
lcd.print (HLTtemp);
if (HLTtemp<10){
lcd.setCursor(14,0);
degC();
}else{
lcd.setCursor(15,0);
degC();}
lcd.setCursor(11,1);
lcd.print(Mash_CookTemp);
if (Mash_CookTemp<10){
lcd.setCursor(14,1);
degC();
}else{
lcd.setCursor(15,1);
degC();}
lcd.setCursor(11,2);
lcd.print(BoilTemp);
if (BoilTemp<10){
lcd.setCursor(14,2);
degC();
}else{
lcd.setCursor(15,2);
degC();}
if (button1.update()||button2.update()||button3.update()) {
if ((button1.read()||button2.read()||button3.read())==HIGH){
BrewMenu++;
}
}
}
}
}
//-------------------------------------//
void MashLiquorHeating(){
/* Mash liquor heating
HLT temp:62.7°C
Target:78.0°C
CHANGE OFF MASH */
digitalWrite(Mash_CookRelay,LOW);
digitalWrite(BoilerRelay,LOW);
analogWrite (HERMSpumpFET,0);
lcd.clear();
while (BrewMenu == 3){
sensors.requestTemperatures();
HLTtemp=sensors.getTempCByIndex(1);
lcd.setCursor(0,1);
PrintText(s33);
lcd.print(HLTtemp);
if (HLTtemp<10){
lcd.setCursor(15,1);
degC();
}else{
lcd.setCursor(16,1);
degC();}
lcd.setCursor(0,2);
PrintText(s34);
lcd.print(HLTtarget);
degCTarget();
if (button3.update()) {
if (button3.read() == HIGH) {
BrewMenu++;
}
}
if (button1.update()) {
if (button1.read() == HIGH) {
set=false;
}
}
while (!set){
lcd.setCursor(0,3);
PrintText(s23);
if (button1.update()) {
if (button1.read()) {
HLTtarget++;
}
}
if (button3.update()) {
if (button3.read()) {
HLTtarget--;
}
}
lcd.setCursor(12,2);
lcd.print(HLTtarget);
if (HLTtarget<10){
lcd.setCursor(14,2);
degCTarget();
}else{
lcd.setCursor(15,2);
degCTarget();}
if (HLTtarget > 100){
HLTtarget=0;}
if (HLTtarget < 100){
lcd.setCursor(14,2);
degCTarget();}
if (HLTtarget < 10){
lcd.setCursor(13,2);
degCTarget();}
if (button2.update()) {
if (button2.read()){
set=true;
}
}
}
if (button2.update()) {
if (button2.read() == HIGH) {
if (!HLTon) HLTon=true;
else HLTon=false;
}
}
HTLcontrol();
}
}
//-------------------------------------//
void HTLcontrol(){
/* Mash liquor ready!!!
HLT temp:78.1°C
Target:78.0°C
CHANGE ON MASH */
lcd.setCursor(0,3);
analogWrite (HERMSpumpFET,0);
if (!HLTon){
PrintText(s36);
digitalWrite(HLTrelay,LOW);
}else{
PrintText(s35);
if (HLTtemp > HLTtarget){
digitalWrite(buzzer,HIGH);
digitalWrite(HLTrelay,LOW);
lcd.setCursor(0,0);
PrintText(s32);
}else{
digitalWrite(HLTrelay,HIGH);
digitalWrite(buzzer,LOW);
lcd.setCursor(0,0);
PrintText(s31);
}
}
}
//-------------------------------------//
void PumpControl(){ // Controls pump speed via MOSFET by reading potentiometer value
PotValue = analogRead(PotPin);
PotValue = map(PotValue, 0, 1023, 0, 255);
analogWrite (HERMSpumpFET,PotValue);
}
//-------------------------------------//
void MashStart(){
/* Ready to start mash!
Prime pump&fill HLT
for sparge liquor
PRESS ANY BUTTON */
lcd.clear();
digitalWrite(buzzer,LOW);
digitalWrite(HLTrelay,LOW);
while (BrewMenu==4){
PrintText(s17);
lcd.setCursor(0,1);
PrintText(s18);
lcd.setCursor(0,2);
PrintText(s19);
lcd.setCursor(0,3);
PrintText(s16);
if (button1.update()||button2.update()||button3.update()) {
if ((button1.read()||button2.read()||button3.read())==HIGH){
BrewMenu++;
}
}
}
}
//-------------------------------------//
void Mashing(){
/* Mash temp:65.8°C
Target:66.0°C
Time left:38mins
BACK CHANGE STOP */
lcd.clear();
MashStartTime=millis();
while (BrewMenu==5){
sensors.requestTemperatures();
Mash_CookTemp=sensors.getTempCByIndex(2);
HLTtemp=sensors.getTempCByIndex(1);
Input = Mash_CookTemp;
Setpoint = MashTarget;
myPID.Compute();
if(millis() - windowStartTime>WindowSize){
windowStartTime += WindowSize;}
if(Output > millis() - windowStartTime) digitalWrite(Mash_CookRelay,HIGH);
else digitalWrite(Mash_CookRelay,LOW);
time = MashTime - (millis()-MashStartTime)/60000;
PrintText(s39);
lcd.setCursor(12,0);
lcd.print(Mash_CookTemp);
lcd.setCursor(16,0);
degC();
lcd.setCursor(0,1);
PrintText(s34);
lcd.print(MashTarget);
degCTarget();
lcd.setCursor(0,2);
PrintText(s40);
lcd.print (time);
lcd.print("mins ");
lcd.setCursor(0,3);
PrintText(s41);
SpargeLiquorHeating(); //heat sarge liquor whilst mashing
PumpControl();
if (time<1)BrewMenu++, analogWrite (HERMSpumpFET,0);
if (button1.update()) {
if (button1.read()) {
digitalWrite (Mash_CookRelay, LOW);
analogWrite (HERMSpumpFET,0);
BrewMenu--;
}
}
if (button3.update()) {
if (button3.read()) {
digitalWrite (Mash_CookRelay, LOW);
analogWrite (HERMSpumpFET,0);
BrewMenu++;
}
}
if (button2.update()) {
if (button2.read() == HIGH) {
set=false;
while (!set){
lcd.setCursor(0,3);
PrintText(s23);
if (button1.update()) {
if (button1.read()) {
MashTarget++;
}
}
if (button3.update()) {
if (button3.read()) {
MashTarget--;
}
}
lcd.setCursor(12,1);
lcd.print(MashTarget);
degCTarget();
if (MashTarget > 100){
MashTarget=0;}
if (MashTarget < 100){
lcd.setCursor(14,1);
degCTarget();
}
if (MashTarget < 10){
lcd.setCursor(13,1);
degCTarget();
}
if (button2.update()) {
if (button2.read()){
lcd.setCursor(0,0);
set=true;
}
}
}
}
}
}
}
//-------------------------------------//
void SpargeLiquorHeating(){
digitalWrite(BoilerRelay,LOW);
sensors.requestTemperatures();
HLTtemp=sensors.getTempCByIndex(1);
if (HLTtemp < SpargeTarget){
digitalWrite (HLTrelay, HIGH);}
if (HLTtemp > SpargeTarget+5){
digitalWrite (HLTrelay, LOW);}
}
//-------------------------------------//
void MashFinished(){
/* Mash Complete!
START
BACK SPARGE */
digitalWrite(buzzer,HIGH);
digitalWrite(Mash_CookRelay,LOW);
digitalWrite(HLTrelay,LOW);
lcd.clear();
while (BrewMenu==6){
PrintText(s42);
lcd.setCursor(0,2);
PrintText(s44);
lcd.setCursor(0,3);
PrintText(s45);
BrewMenuButons();
}
}
//-------------------------------------//
void Sparging(){
/* Sparge in
Progress
START
BACK HLT OFF BOIL */
digitalWrite(buzzer,LOW);
lcd.clear();
while (BrewMenu==7){
SpargeLiquorHeating();
PrintText(s46);
lcd.setCursor(0,1);
PrintText(s47);
lcd.setCursor(0,2);
PrintText(s48);
BrewMenuButons();
SpargeLiquorHeating();
if (button2.update()) {
if (button2.read() == HIGH);{
digitalWrite(HLTrelay, HIGH);
lcd.setCursor(0,3);
PrintText(s49);}
}else{
digitalWrite(HLTrelay, LOW);
lcd.setCursor(0,3);
PrintText(s43);}
}
}
//-------------------------------------//
void Boiling(){
/* Boil temp:88.0°C
Target:100.0°C
Time left:89mins
BACK CHANGE STOP */
digitalWrite(HLTrelay,LOW);
digitalWrite(Mash_CookRelay,LOW);
digitalWrite(buzzer,LOW);
lcd.clear();
while (BrewMenu==8){
digitalWrite(HLTrelay,LOW);
digitalWrite(Mash_CookRelay,LOW);
sensors.requestTemperatures();
BoilTemp=sensors.getTempCByIndex(0);
if (BoilTemp > 95){
BoilStartTime=millis();}
time = BoilTime - (millis()-BoilStartTime)/60000;
PrintText(s50);
lcd.setCursor(12,0);
lcd.print(BoilTemp);
if (BoilTemp >= 100){lcd.setCursor(17,0);
degC();
}else{
lcd.setCursor(16,0);
degC();}
lcd.setCursor(0,1);
PrintText(s34);
lcd.setCursor(12,1);
lcd.print(BoilTarget);
degCTarget();
lcd.setCursor(0,2);
PrintText(s40);
lcd.setCursor(12,2);
lcd.print(time);
lcd.print("mins ");
lcd.setCursor(0,3);
PrintText(s41);
if (time<1)BrewMenu++;
if (BoilTarget>BoilTemp){
digitalWrite(BoilerRelay, HIGH);
}else{
digitalWrite(BoilerRelay,LOW);}
if (button3.update()) {
if (button3.read()) {
BrewMenu++;
}
}
if (button1.update()) {
if (button1.read() == HIGH) {
digitalWrite (BoilerRelay,LOW);
BrewMenu--;
}
}
if (button2.update()) {
if (button2.read() == HIGH) {
set=false;
while (!set){
lcd.setCursor(0,3);
PrintText(s23);
if (button1.update()) {
if (button1.read()) {
BoilTarget++;
}
}
if (button3.update()) {
if (button3.read()) {
BoilTarget--;
}
}
lcd.setCursor(12,1);
lcd.print(BoilTarget);
degCTarget();
if (BoilTarget > 100){
BoilTarget=0;}
if (BoilTarget < 100){
lcd.setCursor(14,1);
degCTarget();}
if (BoilTarget < 10){
lcd.setCursor(13,1);
degCTarget();}
if (button2.update()){
if (button2.read()){
lcd.setCursor(0,0);
set=true;
}
}
}
}
}
}
}
//-------------------------------------//
void BoilFinished(){
/* Boil Finished!
BACK CHILL */
lcd.clear();
while (BrewMenu==9){
digitalWrite(buzzer,HIGH);
digitalWrite(HLTrelay,LOW);
digitalWrite(Mash_CookRelay,LOW);
digitalWrite(BoilerRelay,LOW);
PrintText(s60);
lcd.setCursor(0,3);
PrintText(s51);
BrewMenuButons();
}
}
//-------------------------------------//
void Chilling(){
/* Chilling
Wort temp:28.2°C
Target:25.0°C
BACK CHANGE STOP */
digitalWrite(buzzer,LOW);
lcd.clear();
while (BrewMenu==10){
digitalWrite(HLTrelay,LOW);
digitalWrite(Mash_CookRelay,LOW);
digitalWrite(BoilerRelay,LOW);
sensors.requestTemperatures();
BoilTemp=sensors.getTempCByIndex(0);
PrintText(s57);
lcd.setCursor(0,1);
PrintText(s59);
lcd.print(BoilTemp);
lcd.setCursor(17,1);
degC();
lcd.setCursor(0,2);
PrintText(s34);
lcd.print(ChillTarget);
degCTarget();
lcd.setCursor(0,3);
PrintText(s41);
if (button3.update()) {
if (button3.read() == HIGH) {
BrewMenu++;
}
}
if (button1.update()) {
if (button1.read() == HIGH) {
BrewMenu--;
}
}
if (button2.update()) {
if (button2.read() == HIGH) {
set=false;
while (!set){
lcd.setCursor(0,3);
PrintText(s23);
if (button1.update()) {
if (button1.read()) {
ChillTarget++;
}
}
if (button3.update()) {
if (button3.read()) {
ChillTarget++;
}
}
lcd.setCursor(12,2);
lcd.print(ChillTarget);
degCTarget();
if (ChillTarget > 100){
ChillTarget=0;}
if (ChillTarget < 100){
lcd.setCursor(14,2);
degCTarget();
}
if (ChillTarget < 10){
lcd.setCursor(13,2);
degCTarget();
}
if (button2.update()) {
if (button2.read()){
set=true;
}
}
}
if (button2.update()) {
if (button2.read() == HIGH) {
if (!ChillOn) ChillOn=true;
else ChillOn=false;
}
}
}
}
}
}
//-------------------------------------//
void ChillingControl(){
lcd.setCursor(0,3);
if (!ChillOn){
PrintText(s36);
digitalWrite(HLTrelay,LOW);
}else{
PrintText(s35);
if (BoilTemp > ChillTarget){
digitalWrite(buzzer,HIGH);
lcd.setCursor(0,0);
PrintText(s32);
}else{
digitalWrite(buzzer,LOW);
lcd.setCursor(0,0);
PrintText(s31);
}
}
}
//-------------------------------------//
void BrewdayFinished(){
/* BREWDAY FINISHED!
Time:6hrs 35mins
Here's to a good
Beer! */
float h,m;
unsigned long over;
BrewEndTime=millis();
BrewDuration=BrewEndTime-BrewStartTime;
h=int(BrewDuration/3600000);
over=BrewDuration%3600000;
m=int(over/60000);
lcd.clear();
while (BrewMenu==11){
PrintText(s61);
lcd.setCursor(0,1);
PrintText(s62);
lcd.print(h,0);
lcd.print("hrs ");
lcd.print(m,0);
lcd.print("mins");
lcd.setCursor(0,2);
PrintText(s63);
lcd.setCursor(0,3);
PrintText(s64);
}
}
void CookMenuButons(){ //Back and forward cook menu buttons
if (button1.update()){
if (button1.read() == HIGH){
if (CookMenu>1) CookMenu--;
}
}
if (button3.update()){
if (button3.read()==HIGH){
CookMenu++;
}
}
}
void BrewMenuButons(){ //Back and forward brew menu buttons
if (button1.update()){
if (button1.read()==HIGH){
if (BrewMenu>1) BrewMenu--;
}
}
if (button3.update()){
if (button3.read()==HIGH){
BrewMenu++;
}
}
}
void degC(){ //prints '°C' and masks the two
lcd.print((char)223); //least signigicant figures from
lcd.print("C "); //temp sensor reading
}
void degCTarget(){ //
lcd.print(".0"); //prints '0°C'
lcd.print((char)223); //
lcd.print("C "); //
}
void setup(){
lcd.begin(20,4);
sensors.begin();
pinMode (Mash_CookRelay,OUTPUT);
pinMode(HLTrelay,OUTPUT);
pinMode (BoilerRelay,OUTPUT);
windowStartTime = millis(); //
myPID.SetOutputLimits(0, WindowSize); //PID set-up
myPID.SetMode(AUTOMATIC); //
lcd.createChar(eAcute,CustomChar);//initialse custom letter 'é'
}
void loop(){
switch (mode) {
case 0:
StartScreen();
break;
case 1:
switch (CookMenu){
case 1:
CookWelcome ();
break;
case 2:
Cooking ();
break;
case 3:
CookTimeSetHours();
break;
case 4:
CookTimeSetMins();
break;
case 5:
CookFinished();
break;
}
break;
case 2:
switch (BrewMenu){
case 1:
BrewWelcome ();
break;
case 2:
BrewStart();
case 3:
MashLiquorHeating();
break;
case 4:
MashStart();
break;
case 5:
Mashing();
break;
case 6:
MashFinished();
break;
case 7:
Sparging();
break;
case 8:
Boiling();
break;
case 9:
BoilFinished();
break;
case 10:
Chilling();
break;
case 11:
BrewdayFinished();
break;
}
break;
}
}