# HG changeset patch # User Michiel Broek # Date 1451162744 -3600 # Node ID fdd30e9350793b3bce095a6d6ab797ac8956412c # Parent 55bcbf92ecab4265c34b0d794561a867fc4603e0 The brew state machine is complete, works but is not bugfree diff -r 55bcbf92ecab -r fdd30e935079 brewco/Makefile --- a/brewco/Makefile Tue Dec 22 21:07:14 2015 +0100 +++ b/brewco/Makefile Sat Dec 26 21:45:44 2015 +0100 @@ -58,8 +58,9 @@ setup.o: brewco.h slcd.h setup.h prompt.h xutil.h keyboard.h rdconfig.h rdrecipes.h devices.o: brewco.h devices.h util.h xutil.h keyboard.h slcd.h xutil.o: brewco.h xutil.h -brewco.o: brewco.h rdconfig.h rdsession.h rdrecipes.h util.h xutil.h lcd-pcf8574.h slcd.h lock.h devices.h keyboard.h simulator.h prompt.h setup.h +brewco.o: brewco.h rdconfig.h rdsession.h rdrecipes.h util.h xutil.h lcd-pcf8574.h slcd.h lock.h devices.h keyboard.h simulator.h prompt.h setup.h logger.h lock.o: lock.h brewco.h +logger.o: logger.h brewco.h util.h xutil.h lcd-pcf8574.o: brewco.h lcd-pcf8574.h slcd.h pid.o: brewco.h pid.h util.h util.o: brewco.h util.h slcd.h diff -r 55bcbf92ecab -r fdd30e935079 brewco/brewco.c --- a/brewco/brewco.c Tue Dec 22 21:07:14 2015 +0100 +++ b/brewco/brewco.c Sat Dec 26 21:45:44 2015 +0100 @@ -34,11 +34,12 @@ #include "simulator.h" #include "prompt.h" #include "setup.h" +#include "logger.h" int my_shutdown = FALSE; -int man_mlt_pump = 0; +int mlt_pump_state = 0; double hltInput; /* HLT PID variables */ double hltOutput; @@ -139,7 +140,7 @@ -void tempstatus(double hlttemp, double mlttemp) +void tempstatus(void) { char text[81]; @@ -198,107 +199,608 @@ -void automatic_brew(units_list *, brew_session *, a_recipe *, int); -void automatic_brew(units_list *unit, brew_session *brew, a_recipe *recipe, int dosave) +/* + * Third line during boil, only MLT status + */ +void mltstatus(void) +{ + char text[21]; + + snprintf(text, 20, "MLT %3d%% %6.2f\002 ", (int)mltOutput, mltSetpoint); +#ifdef HAVE_WIRINGPI_H + piLock(LOCK_LCD); + lcdPosition(lcdHandle, 0, 2); + lcdPuts(lcdHandle, text); +#endif + slcdPosition(slcdHandle, 0, 2); + slcdPuts(slcdHandle, text); +} + + + +void timestatus(int row, int timeval) +{ + char text[21]; + int hours, mins, val = timeval; + + hours = val / 3600; + val -= (hours * 3600); + mins = val / 60; + val -= (mins * 60); + + snprintf(text, 20, " %02d:%02d:%02d ", hours, mins, val); +#ifdef HAVE_WIRINGPI_H + piLock(LOCK_LCD); + lcdPosition(lcdHandle, 0, row); + lcdPuts(lcdHandle, text); +#endif + slcdPosition(slcdHandle, 0, row); + slcdPuts(slcdHandle, text); +} + + + +int set_HLT_heater(units_list *unit, int state, double val) { - int key, save = dosave; + if (strcmp(unit->hlt_heater.uuid, (char *)"00000000-0000-0000-0000-000000000000") == 0) + return 0; + + hltSetpoint = val; + + if (state && (PID_getMode(unit->PID_hlt) == P_MANUAL)) { + hlt_status(1); + PID_setMode(unit->PID_hlt, P_AUTOMATIC); + return 1; + } + if (! state && (PID_getMode(unit->PID_hlt) == P_AUTOMATIC)) { + hlt_status(0); + PID_setMode(unit->PID_hlt, P_MANUAL); + return 1; + } + + return 0; +} + + + +int set_MLT_heater(units_list *unit, int state, double val) +{ + if (strcmp(unit->mlt_heater.uuid, (char *)"00000000-0000-0000-0000-000000000000") == 0) + return 0; + + mltSetpoint = val; -// if (debug) -// fprintf(stdout, "auto: step %d\n", brew->brewstep); + if (state && (PID_getMode(unit->PID_mlt) == P_MANUAL)) { + mlt_status(1); + PID_setMode(unit->PID_mlt, P_AUTOMATIC); + return 1; + } + if (! state && (PID_getMode(unit->PID_mlt) == P_AUTOMATIC)) { + mlt_status(0); + PID_setMode(unit->PID_mlt, P_MANUAL); + return 1; + } + + return 0; +} + + + +int set_MLT_pump(units_list *unit, int state) +{ + if (strcmp(unit->mlt_pump.uuid, (char *)"00000000-0000-0000-0000-000000000000") == 0) + return 0; + + if (state && ! mlt_pump_state) { + device_out(unit->mlt_pump.uuid, 1); + mlt_pump_state = 1; + return 1; + } + if (! state && mlt_pump_state) { + device_out(unit->mlt_pump.uuid, 0); + mlt_pump_state = 0; + return 1; + } + + return 0; +} + + + +void automatic_brew(units_list *, brew_session *, a_recipe *, int, int); +void automatic_brew(units_list *unit, brew_session *brew, a_recipe *recipe, int dosave, int seconds) +{ + int key, save = dosave, i; + char data[128]; + static int mash_fase = MASH_NA, hopstand = 0, last_step = -1, last_fase = -1, oldsec = 75, startdelay = 0; switch (brew->brewstep) { case STEP_NA: if (debug) fprintf(stdout, "auto: init recipe: %s-%s unit: %s\n", recipe->code, recipe->name, unit->name); syslog(LOG_NOTICE, "AUTO: starting new brew, recipe: %s-%s unit: %s", recipe->code, recipe->name, unit->name); + brew->brewstep = STEP_BREWINIT; + break; + + case STEP_BREWINIT: prompt(103, NULL); /* " AUTOMATIC MODE " */ + prompt(207, NULL); /* " Delay start? " */ + prompt(300, NULL); /* " " */ + prompt(407, NULL); /* "--- --- No Yes " */ + if (debug) + fprintf(stdout, "step brewinit\n"); + key = keywait(); + if (key == KEY_RETURN) { + brew->brewstep = STEP_WATERCHECK; + startdelay = 0; + syslog(LOG_NOTICE, "AUTO: brew initialize, direct start selected"); + break; + } + if (key == KEY_ENTER) { + startdelay = 30; + editInteger(&startdelay, 10, 960, 10, (char *)"Start delay", (char *)"mins"); + } + syslog(LOG_NOTICE, "AUTO: brew initialize"); + brew->brewstep = STEP_WATERCHECK; + break; + + case STEP_WATERCHECK: if (brew->brewstep != last_step) { + prompt(111, NULL); /* "AUTO --> Mash In " */ + prompt(209, NULL); /* " Water Added? " */ + prompt(300, NULL); + prompt(410, NULL); /* " Continue: Yes No " */ + last_step = brew->brewstep; + } + slcdDummy(slcdHandle); + key = keycheck(); + if (key == KEY_RETURN) { + brew->brewstep = STEP_PUMPPRIME; + syslog(LOG_NOTICE, "AUTO: confirmed water added"); + } + if (key == KEY_ENTER) { + syslog(LOG_NOTICE, "AUTO: aborted water added"); + brew->brewstep = STEP_CLEANUP; + } + break; + + case STEP_PUMPPRIME: if (brew->brewstep != last_step) { + prompt(111, NULL); /* "AUTO --> Mash In " */ + prompt(210, NULL); /* " Pump Prime " */ + prompt(300, NULL); /* " " */ + prompt(400, NULL); /* " " */ + last_step = brew->brewstep; + } + brew->brewstep = STEP_WAITSTART; + break; + + case STEP_WAITSTART: if (startdelay == 0) { + brew->brewstep = STEP_PREMASH; + break; + } + if (brew->brewstep != last_step) { + brew->timeout = startdelay * 60; + prompt(111, NULL); /* "AUTO --> Mash In " */ + prompt(212, NULL); /* " To be started in " */ + prompt(410, NULL); /* " Continue: Yes No " */ + last_step = brew->brewstep; + } + if (oldsec != seconds) { + timestatus(2, brew->timeout); + brew->timeout--; + if (brew->timeout <= 0) { + syslog(LOG_NOTICE, "AUTO: delayed start time reached"); + brew->brewstep = STEP_PREMASH; + } + oldsec = seconds; + } + slcdDummy(slcdHandle); + key = keycheck(); + if (key == KEY_RETURN) { + syslog(LOG_NOTICE, "AUTO: delayed start skipped by user"); + brew->brewstep = STEP_PREMASH; + } + break; + + case STEP_PREMASH: if (brew->brewstep != last_step) { + prompt(111 + brew->mashstep, NULL); /* "AUTO --> [mashname] " */ + prompt(300, NULL); /* " " */ + prompt(418, NULL); /* "--- --- Pause --- " */ + tempstatus(); + hlt_status(1); + mlt_status(1); + pump_status(unit->pump_premash); + last_step = brew->brewstep; + } + initlog(brew->name); + if (set_HLT_heater(unit, 1, 85.0)) + syslog(LOG_NOTICE, "AUTO: premash turn on HLT at %6.2f", hltSetpoint); + if (set_MLT_heater(unit, 1, recipe->mash[0].setpoint)) + syslog(LOG_NOTICE, "AUTO: premash turn on MLT at %6.2f", mltSetpoint); + if (set_MLT_pump(unit, unit->pump_premash)) + syslog(LOG_NOTICE, "AUTO: premash turn %s MLT pump", mlt_pump_state ? "on":"off"); + brew->brewstep = STEP_MASHING; + brew->mashstep = 0; + mash_fase = MASH_NA; + save = TRUE; + break; + + case STEP_MASHING: if (brew->brewstep != last_step) { + prompt(111 + brew->mashstep, NULL); /* "AUTO --> [mashname] " */ + prompt(300, NULL); /* " " */ + prompt(418, NULL); /* "--- --- Pause --- " */ + tempstatus(); + hlt_status(1); + mlt_status(1); + pump_status(unit->pump_onmash); + last_step = brew->brewstep; + } + if (set_HLT_heater(unit, 1, 85.0)) + syslog(LOG_NOTICE, "AUTO: mash turn on HLT at %6.2f", hltSetpoint); + if (set_MLT_heater(unit, 1, recipe->mash[brew->mashstep].setpoint)) + syslog(LOG_NOTICE, "AUTO: mash turn on MLT at %6.2f", mltSetpoint); + if ((mash_fase != MASH_REST) && set_MLT_pump(unit, unit->pump_onmash)) + syslog(LOG_NOTICE, "AUTO: mash turn %s MLT pump", mlt_pump_state ? "on":"off"); + + switch (mash_fase) { + case MASH_NA: if (recipe->mash[brew->mashstep].skip) { + syslog(LOG_NOTICE, "AUTO: skipping mash step %d", brew->mashstep); + brew->mashstep++; + } else { + mltSetpoint = recipe->mash[brew->mashstep].setpoint; + brew->timeout = recipe->mash[brew->mashstep].duration * 60; + if ((brew->mashstep == 0) && ! unit->skip_add) { + mash_fase = MASH_PROMPT; + } else + mash_fase = MASH_HEATING; + syslog(LOG_NOTICE, "AUTO: mash step %d fase NA, setpoint %6.2f, duration %d", + brew->mashstep, mltSetpoint, brew->timeout); + } + if (brew->mashstep == 0) { + brew->starttime = time(NULL); + save = TRUE; + } + break; + + case MASH_PROMPT: if (last_fase != mash_fase) { + prompt(111 + brew->mashstep, NULL); /* "AUTO --> [mashname] " */ + prompt(219, NULL); /* " Mash added? " */ + prompt(300, NULL); + prompt(410, NULL); /* " Continue: Yes No " */ + last_fase = mash_fase; + } + slcdDummy(slcdHandle); + key = keycheck(); + if (key == KEY_RETURN) { + mash_fase = MASH_HEATING; + syslog(LOG_NOTICE, "AUTO: confirmed mash added"); + } + if (key == KEY_ENTER) { + syslog(LOG_NOTICE, "AUTO: aborted mash added"); + brew->brewstep = STEP_CLEANUP; + brew->mashstep = 0; + } + break; + + case MASH_IODINE: if (last_fase != mash_fase) { + prompt(118, NULL); /* "AUTO --> Mash Out " */ + prompt(213, NULL); /* " Iodine test " */ + timestatus(2, brew->timeout); + prompt(410, NULL); /* " Continue: Yes No " */ + last_fase = mash_fase; + } + if (oldsec != seconds) { + brew->timeout--; + timestatus(2, brew->timeout); + if (brew->timeout <= 0) { + syslog(LOG_NOTICE, "AUTO: mash IODINE test timeout"); + mash_fase = MASH_NA; + brew->mashstep++; + } + oldsec = seconds; + } + slcdDummy(slcdHandle); + key = keycheck(); + if (key == KEY_RETURN) { + syslog(LOG_NOTICE, "AUTO: mash IODINE test confirmed"); + mash_fase = MASH_NA; + brew->mashstep++; + } + if (key == KEY_ENTER) { + syslog(LOG_NOTICE, "AUTO: mash IODINE test declined"); + mash_fase = MASH_REST; + brew->timeout = 600; /* Add 10 more minutes */ + } + break; + + case MASH_HEATING: if (last_fase != mash_fase) { + prompt(111 + brew->mashstep, NULL); /* "AUTO --> [mashname] " */ + prompt(200, NULL); + prompt(300, NULL); + prompt(418, NULL); /* "--- --- Pause --- " */ + hlt_status(1); + mlt_status(1); + pump_status(unit->pump_onmash); + last_fase = mash_fase; + } + if (oldsec != seconds) { + tempstatus(); + percstatus((seconds / 2) % 4); + oldsec = seconds; + } + if (mltInput > mltSetpoint) { + syslog(LOG_NOTICE, "AUTO: mash step %d fase HEATING reached %6.2f", brew->mashstep, mltSetpoint); + mash_fase = MASH_REST; + } + break; + + case MASH_REST: if (last_fase != mash_fase) { + prompt(111 + brew->mashstep, NULL); /* "AUTO --> [mashname] " */ + prompt(300, NULL); + prompt(418, NULL); /* "--- --- Pause --- " */ + hlt_status(1); + mlt_status(1); + pump_status(unit->pump_onmash); + last_fase = mash_fase; + } + if (oldsec != seconds) { + tempstatus(); + timestatus(2, brew->timeout); + if (brew->mashstep == 7) { + /* + * During mash-out rest, allow the grain to sink + */ + if (set_MLT_pump(unit, unit->pump_mashout)) + syslog(LOG_NOTICE, "AUTO: mash-out turn %s MLT pump", mlt_pump_state ? "on":"off"); + } else { + if (set_MLT_pump(unit, unit->pump_onmash)) + syslog(LOG_NOTICE, "AUTO: mash turn %s MLT pump", mlt_pump_state ? "on":"off"); + } + brew->timeout--; + if (brew->timeout <= 0) { + syslog(LOG_NOTICE, "AUTO: mash step %d fase REST done", brew->mashstep); + if ((brew->mashstep == 6) && ! unit->skip_iodine) { + mash_fase = MASH_IODINE; + brew->timeout = unit->iodine_time * 60; + } else if (brew->mashstep == 7) { + mash_fase = MASH_DONE; + } else { + mash_fase = MASH_NA; + brew->mashstep++; + } + } + oldsec = seconds; + } + break; + + case MASH_DONE: syslog(LOG_NOTICE, "AUTO: mash step %d fase DONE", brew->mashstep); + if (set_MLT_heater(unit, 1, recipe->mash[7].setpoint)) + syslog(LOG_NOTICE, "AUTO: mash done turn MLT off"); + if (set_MLT_pump(unit, 0)) + syslog(LOG_NOTICE, "AUTO: mash done turn %s MLT pump", mlt_pump_state ? "on":"off"); + brew->mashstep = 0; + brew->brewstep = STEP_MASHREMOVE; + break; + } + break; + + case STEP_MASHREMOVE: if (unit->skip_remove) { + syslog(LOG_NOTICE, "AUTO: skipping Mash remove"); + brew->brewstep = STEP_PREBOIL; + } else { + if (brew->brewstep != last_step) { + prompt(118, NULL); /* "AUTO --> Mash Out " */ + prompt(220, NULL); /* " Mash Removed? " */ + prompt(300, NULL); + prompt(410, NULL); /* " Continue: Yes No " */ + last_step = brew->brewstep; + } + slcdDummy(slcdHandle); + key = keycheck(); + if (key == KEY_RETURN) { + syslog(LOG_NOTICE, "AUTO: Confirmed Mash removed"); + brew->brewstep = STEP_PREBOIL; + } + } + break; + + case STEP_PREBOIL: if (brew->brewstep != last_step) { + prompt(119, NULL); /* "AUTO --> Boil " */ + prompt(200, NULL); + prompt(300, NULL); + tempstatus(); + mltstatus(); + prompt(418, NULL); /* "--- --- Pause --- " */ + hlt_status(0); + mlt_status(1); + pump_status(unit->pump_onboil && (mltInput < unit->pump_stop)); + last_step = brew->brewstep; + } + if (oldsec != seconds) { + tempstatus(); + mltstatus(); + oldsec = seconds; + } + if (set_HLT_heater(unit, 0, 10.0)) + syslog(LOG_NOTICE, "AUTO: preboil turn off HLT"); + if (set_MLT_heater(unit, 1, 100.0)) + syslog(LOG_NOTICE, "AUTO: preboil turn on MLT to boil"); + if (set_MLT_pump(unit, unit->pump_onboil && (mltInput < unit->pump_stop))) + syslog(LOG_NOTICE, "AUTO: preboil turn %s MLT pump", mlt_pump_state ? "on":"off"); + if (mltInput > 99.2) { + syslog(LOG_NOTICE, "AUTO: reached boil temperature %.2f, start %d minutes boil", mltInput, recipe->boiltime); + brew->brewstep = STEP_BOILING; + brew->boiltimer = recipe->boiltime * 60; + } + break; + + case STEP_BOILING: if (set_HLT_heater(unit, 0, 10.0)) + syslog(LOG_NOTICE, "AUTO: boil turn off HLT"); + if (set_MLT_heater(unit, 1, 100.0)) + syslog(LOG_NOTICE, "AUTO: boil turn on MLT to boil"); + if (set_MLT_pump(unit, unit->pump_onboil && (mltInput < unit->pump_stop))) + syslog(LOG_NOTICE, "AUTO: boil turn %s MLT pump", mlt_pump_state ? "on":"off"); + if (brew->brewstep != last_step) { + prompt(119, NULL); /* "AUTO --> Boil " */ + prompt(200, NULL); + prompt(300, NULL); + tempstatus(); + mltstatus(); + prompt(418, NULL); /* "--- --- Pause --- " */ + hlt_status(0); + mlt_status(1); + pump_status(unit->pump_onboil && (mltInput < unit->pump_stop)); + last_step = brew->brewstep; + } + if (oldsec != seconds) { + tempstatus(); + if ((seconds / 2) % 4) { + timestatus(2, brew->boiltimer); + } else { + mltstatus(); + } + if (brew->boiltimer >= 0) { + brew->boiltimer--; + } else { + brew->brewstep = STEP_BOILDONE; + syslog(LOG_NOTICE, "AUTO: boil is done"); + } + oldsec = seconds; + } + break; + + case STEP_BOILDONE: if (set_MLT_heater(unit, 0, 10.0)) + syslog(LOG_NOTICE, "AUTO: after boil turn off MLT heater"); + if (set_MLT_pump(unit, 0)) + syslog(LOG_NOTICE, "AUTO: after boil turn %s MLT pump", mlt_pump_state ? "on":"off"); + if (brew->brewstep != last_step) { + prompt(120, NULL); /* "AUTO --> Cooling " */ + prompt(214, NULL); /* " START COOLING " */ + prompt(300, NULL); + prompt(410, NULL); /* " Continue: Yes No " */ + last_step = brew->brewstep; + } + slcdDummy(slcdHandle); + key = keycheck(); + if (key == KEY_ENTER) { + brew->brewstep = STEP_CLEANUP; + syslog(LOG_NOTICE, "AUTO: user skipped cooling"); + } + if (key == KEY_RETURN) { + brew->brewstep = STEP_COOLING; + syslog(LOG_NOTICE, "AUTO: user started cooling"); + } + break; + + case STEP_COOLING: for (i = 0; i < 3; i++) { + if ((recipe->hopstand[i].skip == 0) && (mltInput <= recipe->hopstand[i].max) && (mltInput >= recipe->hopstand[i].min)) { + brew->brewstep = STEP_HOPSTAND; + hopstand = i; + syslog(LOG_NOTICE, "AUTO: starting hopstand %d", i+1); + } + } + if (brew->brewstep == STEP_HOPSTAND) + break; + // hot whirlpool start at 85 degrees + // cold whirlpool start at 30 degrees + + if (brew->brewstep != last_step) { + prompt(120, NULL); /* "AUTO --> Cooling " */ + prompt(200, NULL); + tempstatus(); + prompt(300, NULL); + prompt(418, NULL); /* "--- --- Pause --- " */ + hlt_status(0); + mlt_status(0); + pump_status(0); + last_step = brew->brewstep; + } + if (oldsec != seconds) { + tempstatus(); + oldsec = seconds; + } + if (mltInput <= recipe->coolto) { + syslog(LOG_NOTICE, "AUTO: cool temperture %.2f reached", recipe->coolto); + brew->brewstep = STEP_CLEANUP; + } + break; + + case STEP_HOPSTAND: if (brew->brewstep != last_step) { + prompt(122 + hopstand, NULL); /* "AUTO --> Hopstand n " */ + tempstatus(); + timestatus(2, brew->timeout); + prompt(418, NULL); /* "--- --- Pause --- " */ + brew->boiltimer = recipe->hopstand[hopstand].duration * 60; + last_step = brew->brewstep; + } + + if (recipe->hopstand[hopstand].hold) { + if (set_MLT_heater(unit, 1, recipe->hopstand[hopstand].setpoint)) + syslog(LOG_NOTICE, "AUTO: hopstand 1 turn on MLT at %6.2f", mltSetpoint); + } + if (set_MLT_pump(unit, 1)) + syslog(LOG_NOTICE, "AUTO: hopstand 1 turn %s MLT pump", mlt_pump_state ? "on":"off"); + if (oldsec != seconds) { + tempstatus(); + timestatus(2, brew->timeout); + brew->boiltimer--; + if (brew->boiltimer <= 0) { + syslog(LOG_NOTICE, "AUTO: hopstand %d done", hopstand+1); + if (set_MLT_heater(unit, 0, 10.0)) + syslog(LOG_NOTICE, "AUTO: hopstand 1 turn off MLT at %6.2f", mltSetpoint); + brew->brewstep = STEP_COOLING; + } + oldsec = seconds; + } + break; + + case STEP_WHIRLPOOL: prompt(121, NULL); /* "AUTO --> Whirlpool " */ + break; + + case STEP_CLEANUP: if (brew->brewstep != last_step) { + prompt(101, NULL); /* " Brewco x.x.x " */ + prompt(200, NULL); /* " " */ + prompt(300, NULL); /* " " */ + prompt(400, NULL); /* " " */ + last_step = brew->brewstep; + } + syslog(LOG_NOTICE, "AUTO: cleanup"); + if (set_HLT_heater(unit, 0, 10.0)) + syslog(LOG_NOTICE, "AUTO: cleanup turn on HLT at %6.2f", hltSetpoint); + if (set_MLT_heater(unit, 0, 10.0)) + syslog(LOG_NOTICE, "AUTO: cleanup turn on MLT at %6.2f", mltSetpoint); + if (set_MLT_pump(unit, 0)) + syslog(LOG_NOTICE, "AUTO: cleanup turn %s MLT pump", mlt_pump_state ? "on":"off"); brew->brewstep = STEP_BREWDONE; break; - case STEP_BREWINIT: - break; - case STEP_WATERCHECK: prompt(111, NULL); /* "AUTO --> Mash In " */ - prompt(209, NULL); /* " Water Added? " */ - break; - case STEP_PUMPPRIME: prompt(111, NULL); /* "AUTO --> Mash In " */ - prompt(210, NULL); /* " Pump Prime " */ - break; - case STEP_WAITSTART: prompt(111, NULL); /* "AUTO --> Mash In " */ - prompt(212, NULL); /* " To be started in " */ - break; - case STEP_PREMASH: prompt(111, NULL); /* "AUTO --> Mash In " */ - /* Heatup until strike temp reached */ - break; - case STEP_MASHING: switch (brew->mashstep) { - case 0: prompt(111, NULL); - break; - case 1: prompt(112, NULL); - break; - case 2: prompt(113, NULL); - break; - case 3: prompt(114, NULL); - break; - case 4: prompt(115, NULL); - break; - case 5: prompt(116, NULL); - break; - case 6: prompt(117, NULL); - break; - case 7: prompt(118, NULL); - break; + case STEP_BREWDONE: if (brew->brewstep != last_step) { + prompt(101, NULL); /* " Brewco x.x.x " */ + prompt(200, NULL); /* " " */ + prompt(301, NULL); /* " Finished " */ + prompt(408, NULL); /* "--- --- Ok --- " */ + last_step = brew->brewstep; } - break; - case STEP_IODINE: prompt(118, NULL); /* "AUTO --> Mash Out " */ - prompt(213, NULL); /* " Iodine test " */ - break; - case STEP_MASHREMOVE: prompt(118, NULL); /* "AUTO --> Mash Out " */ - break; - case STEP_PREBOIL: - break; - case STEP_BOILING: prompt(119, NULL); /* "AUTO --> Boil " */ - break; - case STEP_BOILDONE: - break; - case STEP_HOPSTAND1: - break; - case STEP_COOLING1: prompt(120, NULL); /* "AUTO --> Cooling " */ - prompt(214, NULL); /* " START COOLING " */ - break; - case STEP_WHIRLPOOL1: prompt(121, NULL); /* "AUTO --> Whirlpool " */ - break; - case STEP_COOLING2: prompt(120, NULL); /* "AUTO --> Cooling " */ - break; - case STEP_HOPSTAND2: - break; - case STEP_COOLING3: prompt(120, NULL); /* "AUTO --> Cooling " */ - break; - case STEP_HOPSTAND3: - break; - case STEP_COOLING: prompt(120, NULL); /* "AUTO --> Cooling " */ - break; - case STEP_WHIRLPOOL: prompt(121, NULL); /* "AUTO --> Whirlpool " */ - break; - case STEP_CLEANUP: - break; - case STEP_BREWDONE: syslog(LOG_NOTICE, "AUTO: brew done"); + syslog(LOG_NOTICE, "AUTO: brew done"); brew->brewstep = -1; brew->endtime = time(NULL); - prompt(101, NULL); /* " Brewco x.x.x " */ - prompt(200, NULL); /* " " */ - prompt(301, NULL); /* " Finished " */ - prompt(408, NULL); /* "--- --- Ok --- " */ + save = TRUE; do { key = keywait(); } while (key != KEY_RETURN); /* * Rewrite the display */ - prompt(101, NULL); /* " Brewco x.x.x " */ - prompt(300, NULL); /* " " */ - prompt(401, NULL); /* "--- MAN AUTO SETUP" */ + prompt(101, NULL); /* " Brewco x.x.x " */ + tempstatus(); + prompt(300, NULL); /* " " */ + prompt(401, NULL); /* "--- MAN AUTO SETUP" */ break; } - if (save) + if (save) { + snprintf(data, 127, "%d,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f", brew->brewstep, + hltInput, hltOutput, hltSetpoint, mltInput, mltOutput, mltSetpoint); + logger(brew->name, data); wrsession(brew); + } } @@ -344,12 +846,12 @@ } if (key == KEY_RETURN) { manual = MANUAL_NONE; - man_mlt_pump = 0; + mlt_pump_state = 0; PID_setMode(unit->PID_mlt, P_MANUAL); PID_setMode(unit->PID_hlt, P_MANUAL); hlt_status(0); mlt_status(0); - device_out(unit->mlt_pump.uuid, man_mlt_pump); + device_out(unit->mlt_pump.uuid, mlt_pump_state); } if (key == KEY_ENTER) { // TODO: prompt for water @@ -365,12 +867,12 @@ } if (key == KEY_RETURN) { manual = MANUAL_NONE; - man_mlt_pump = 0; + mlt_pump_state = 0; PID_setMode(unit->PID_mlt, P_MANUAL); PID_setMode(unit->PID_hlt, P_MANUAL); hlt_status(0); mlt_status(0); - device_out(unit->mlt_pump.uuid, man_mlt_pump); + device_out(unit->mlt_pump.uuid, mlt_pump_state); } if (key == KEY_ENTER) { // TODO: prompt for water @@ -378,7 +880,7 @@ manual_prompt(); } break; - case MANUAL_HLT: tempstatus(*unit->PID_hlt->myInput, *unit->PID_mlt->myInput); + case MANUAL_HLT: tempstatus(); percstatus((seconds / 2) % 4); slcdDummy(slcdHandle); @@ -401,7 +903,7 @@ manual_prompt(); } break; - case MANUAL_MLT: tempstatus(*unit->PID_hlt->myInput, *unit->PID_mlt->myInput); + case MANUAL_MLT: tempstatus(); percstatus((seconds / 2) % 4); slcdDummy(slcdHandle); @@ -420,16 +922,16 @@ if ((key == KEY_UP) && (mltSetpoint < 100)) mltSetpoint += 1.0; if (key == KEY_ENTER) { - if (man_mlt_pump) - man_mlt_pump = 0; - else - man_mlt_pump = 1; + if (mlt_pump_state) + set_MLT_pump(unit, 0); + else + set_MLT_pump(unit, 1); } if (key == KEY_ESCAPE) { manual = MANUAL_SELMLT; manual_prompt(); } - device_out(unit->mlt_pump.uuid, man_mlt_pump); + device_out(unit->mlt_pump.uuid, mlt_pump_state); break; } @@ -627,14 +1129,30 @@ * If this file is present, there has been a crash. */ brew = (brew_session *)malloc(sizeof(brew_session)); - if (rdsession(brew) == 0) { - } else { - /* - * No active brew session, make that permanent. - */ + rc = rdsession(brew); + syslog(LOG_NOTICE, "rdsession: rc=%d", rc); + if (debug) + fprintf(stdout, "rdsession: rc=%d\n", rc); + + char *mypath = xstrcpy(etcpath); + mypath = xstrcat(mypath, (char *)"brewing.xml"); + if (rc == 0) { + if (debug) + fprintf(stdout, "Active brew session found\n"); + } else if (rc == -1) { free(brew); brew = NULL; + if (debug) + fprintf(stdout, "No active brew session found\n"); + } else { + unlink(mypath); + free(brew); + brew = NULL; + if (debug) + fprintf(stdout, "Error brew session found\n"); } + free(mypath); + mypath = NULL; do { if (my_shutdown) { @@ -677,10 +1195,10 @@ */ hltInput = hltSetpoint = mltInput = mltSetpoint = 20.0; hltOutput = mltOutput = 0; - PID_init(unit->PID_hlt, &hltInput, &hltOutput, &hltSetpoint, unit->PID_hlt->dispKd, unit->PID_hlt->dispKi, unit->PID_hlt->dispKd, unit->PID_hlt->Direction); + PID_init(unit->PID_hlt, &hltInput, &hltOutput, &hltSetpoint, unit->PID_hlt->dispKp, unit->PID_hlt->dispKi, unit->PID_hlt->dispKd, unit->PID_hlt->Direction); PID_setOutputLimits(unit->PID_hlt, 0, 100); PID_setSampleTime(unit->PID_hlt, unit->PID_hlt->SampleTime); - PID_init(unit->PID_mlt, &mltInput, &mltOutput, &mltSetpoint, unit->PID_mlt->dispKd, unit->PID_mlt->dispKi, unit->PID_mlt->dispKd, unit->PID_mlt->Direction); + PID_init(unit->PID_mlt, &mltInput, &mltOutput, &mltSetpoint, unit->PID_mlt->dispKp, unit->PID_mlt->dispKi, unit->PID_mlt->dispKd, unit->PID_mlt->Direction); PID_setOutputLimits(unit->PID_mlt, 0, 100); PID_setSampleTime(unit->PID_mlt, unit->PID_mlt->SampleTime); hlt_status(0); @@ -693,6 +1211,21 @@ percslot = 0; percfase = PERC_INIT; dosave = 0; + + if (brew) { + /* + * Restore session + */ + if (debug) + fprintf(stdout, "loop_init: restoring brew session\n"); + for (recipe = recipes; recipe; recipe = recipe->next) { + if (strcmp(recipe->uuid, brew->uuid_recipe) == 0) { + break; + } + } + if (debug) + fprintf(stdout, "loop_init: brewstep=%d mashstep=%d recipe=%s\n", brew->brewstep, brew->mashstep, recipe->code); + } } /* run_pause code here */ @@ -734,8 +1267,8 @@ device_out(unit->hlt_heater.uuid, 0); device_out(unit->mlt_heater.uuid, 0); } - if (debug) - fprintf(stdout, " perslot=%d MLT=%d%% HLT=%d%% fase=%d\n", percslot, MLTp, HLTp, percfase); +// if (debug) +// fprintf(stdout, " perslot=%d MLT=%d%% HLT=%d%% fase=%d\n", percslot, MLTp, HLTp, percfase); } else if (percfase == PERC_MLT) { if (percslot > MLTp) { device_out(unit->mlt_heater.uuid, 0); @@ -773,8 +1306,6 @@ dosave = 1; } -//fprintf(stdout, "%d seconds %d minutes %ld millis\n", seconds, minutes, millis()); - rc = device_in(unit->hlt_sensor.uuid, &temp); if (rc == DEVPRESENT_YES) { hltInput = temp / 1000.0; @@ -806,7 +1337,7 @@ /* * Automate mode */ - automatic_brew(unit, brew, recipe, dosave); + automatic_brew(unit, brew, recipe, dosave, seconds); dosave = 0; if (brew->brewstep == -1) { /* @@ -857,7 +1388,7 @@ /* * Not running. */ - tempstatus(hltInput, mltInput); + tempstatus(); key = keycheck(); if (key == KEY_ENTER) { setup(); diff -r 55bcbf92ecab -r fdd30e935079 brewco/brewco.h --- a/brewco/brewco.h Tue Dec 22 21:07:14 2015 +0100 +++ b/brewco/brewco.h Sat Dec 26 21:45:44 2015 +0100 @@ -227,6 +227,7 @@ char *code; /* Recipe code */ char *name; /* Recipe name */ int boiltime; /* 1..240 minutes */ + float coolto; /* Cooling target */ time_t starttime; /* Start time */ time_t endtime; /* Ending time */ mash_step mash[8]; /* 8 mash steps */ @@ -288,28 +289,22 @@ #define STEP_WAITSTART 4 /* Wait for starttime */ #define STEP_PREMASH 5 /* Pre-mash */ #define STEP_MASHING 6 /* Mash steps */ -#define STEP_IODINE 7 /* Iodine test */ -#define STEP_MASHREMOVE 8 /* Remove mash */ -#define STEP_PREBOIL 9 /* Heating before boil */ -#define STEP_BOILING 10 /* Boil */ -#define STEP_BOILDONE 11 /* Boil done, hopstand */ -#define STEP_HOPSTAND1 12 /* Hopstand 88..100 */ -#define STEP_COOLING1 13 /* Cooling to whirlpool hot */ -#define STEP_WHIRLPOOL1 14 /* Whirlpool hot */ -#define STEP_COOLING2 15 /* Cooling to hopstand 2 */ -#define STEP_HOPSTAND2 16 /* Hopstand 71..77 */ -#define STEP_COOLING3 17 /* Cooling to hopstand 3 */ -#define STEP_HOPSTAND3 18 /* Hopstand 60..66 */ -#define STEP_COOLING 19 /* Final cooling */ -#define STEP_WHIRLPOOL 20 /* Final whirlpool */ -#define STEP_CLEANUP 21 /* Cleanup */ -#define STEP_BREWDONE 22 /* Final step */ +#define STEP_MASHREMOVE 7 /* Remove mash */ +#define STEP_PREBOIL 8 /* Heating before boil */ +#define STEP_BOILING 9 /* Boil */ +#define STEP_BOILDONE 10 /* Boil done, hopstand */ +#define STEP_COOLING 11 /* Cooling */ +#define STEP_HOPSTAND 12 /* Hopstand */ +#define STEP_WHIRLPOOL 13 /* Final whirlpool */ +#define STEP_CLEANUP 14 /* Cleanup */ +#define STEP_BREWDONE 15 /* Final step */ #define MASH_NA 0 /* Not in any state yet */ -#define MASH_PROMPT 1 /* Prompt the user */ -#define MASH_HEATING 2 /* Heating phase */ -#define MASH_REST 3 /* Rest phase */ -#define MASH_DONE 4 /* This step is done */ +#define MASH_PROMPT 1 /* Prompt for mash */ +#define MASH_IODINE 2 /* Prompt for iodine test */ +#define MASH_HEATING 3 /* Heating phase */ +#define MASH_REST 4 /* Rest phase */ +#define MASH_DONE 5 /* This step is done */ diff -r 55bcbf92ecab -r fdd30e935079 brewco/devices.c --- a/brewco/devices.c Tue Dec 22 21:07:14 2015 +0100 +++ b/brewco/devices.c Sat Dec 26 21:45:44 2015 +0100 @@ -251,11 +251,6 @@ if ((strcmp((char *)"SimHLTheater", device->address) == 0) || (strcmp((char *)"SimMLTheater", device->address) == 0) || (strcmp((char *)"SimMLTpump", device->address) == 0)) { - if (value != device->value) { - syslog(LOG_NOTICE, "SIM %s value=%d", device->address, value); - if (debug) - fprintf(stdout, "SIM %s value=%d\n", device->address, value); - } device->value = value; if (strcmp((char *)"SimHLTheater", device->address) == 0) { SIM_hlt_value = value; diff -r 55bcbf92ecab -r fdd30e935079 brewco/logger.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/brewco/logger.c Sat Dec 26 21:45:44 2015 +0100 @@ -0,0 +1,72 @@ +/***************************************************************************** + * Copyright (C) 2014-2015 + * + * Michiel Broek + * + * This file is part of the mbsePi-apps + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * mbsePi-apps is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ThermFerm; see the file COPYING. If not, write to the Free + * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + *****************************************************************************/ + +#include "logger.h" +#include "brewco.h" +#include "util.h" +#include "xutil.h" + +extern char *varpath; + + +void initlog(char *name) +{ + char buf[128]; + + snprintf(buf, 127, "Fase,hltInput,hltOutput,hltSetpoint,mltInput,mltOutput,mltSetpoint"); + logger(name, buf); +} + + + +void logger(char *name, char *data) +{ + struct timeval now; + struct tm ptm; + char *outstr = NULL, *logfile = NULL; + FILE *fp; + + logfile = xstrcpy(varpath); + logfile = xstrcat(logfile, (char *)"log/brew-"); + logfile = xstrcat(logfile, name); + mkdirs(logfile, 0755); + logfile = xstrcat(logfile, (char *)".log"); + + gettimeofday(&now, NULL); + localtime_r(&now.tv_sec, &ptm); + outstr = calloc(10240, sizeof(char)); + snprintf(outstr, 10239, "%04d-%02d-%02d %02d:%02d,%s\n", ptm.tm_year + 1900, ptm.tm_mon + 1, ptm.tm_mday, ptm.tm_hour, ptm.tm_min, data); + + if ((fp = fopen(logfile, "a+"))) { + fprintf(fp, outstr); + fclose(fp); + } else { + syslog(LOG_NOTICE, "logger: cannot open %s for writing", logfile); + } + + free(outstr); + outstr = NULL; + free(logfile); + logfile = NULL; +} + + diff -r 55bcbf92ecab -r fdd30e935079 brewco/logger.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/brewco/logger.h Sat Dec 26 21:45:44 2015 +0100 @@ -0,0 +1,9 @@ +#ifndef LOGGER_H +#define LOGGER_H + + +void logger(char *, char *); +void initlog(char *); + + +#endif diff -r 55bcbf92ecab -r fdd30e935079 brewco/pid.c --- a/brewco/pid.c Tue Dec 22 21:07:14 2015 +0100 +++ b/brewco/pid.c Sat Dec 26 21:45:44 2015 +0100 @@ -66,6 +66,11 @@ pid->ITerm = pid->outMax; else if (pid->ITerm < pid->outMin) pid->ITerm = pid->outMin; + /* + * If turned to manual, turn output off. + */ + if (Mode == P_MANUAL) + *pid->myOutput = pid->outMin; } pid->inAuto = newAuto; } diff -r 55bcbf92ecab -r fdd30e935079 brewco/prompt.c --- a/brewco/prompt.c Tue Dec 22 21:07:14 2015 +0100 +++ b/brewco/prompt.c Sat Dec 26 21:45:44 2015 +0100 @@ -156,7 +156,10 @@ break; case 218: snprintf(message, Config.lcd_cols + 1, " Add Brewsystem? "); break; - + case 219: snprintf(message, Config.lcd_cols + 1, " Mash added? "); + break; + case 220: snprintf(message, Config.lcd_cols + 1, " Mash Removed? "); + break; case 221: snprintf(message, Config.lcd_cols + 1, " Select Recipe "); break; case 222: snprintf(message, Config.lcd_cols + 1, " Select Brewsystem "); @@ -215,6 +218,11 @@ break; case 417: snprintf(message, Config.lcd_cols + 1, " up dwn next ok "); break; + case 418: snprintf(message, Config.lcd_cols + 1, "--- --- Pause --- "); + break; + case 419: snprintf(message, Config.lcd_cols + 1, "--* *-- --- pmp "); + break; + // 12345678901234567890 default: snprintf(message, Config.lcd_cols + 1, " N/A N/A"); } diff -r 55bcbf92ecab -r fdd30e935079 brewco/rdconfig.c --- a/brewco/rdconfig.c Tue Dec 22 21:07:14 2015 +0100 +++ b/brewco/rdconfig.c Sat Dec 26 21:45:44 2015 +0100 @@ -395,46 +395,46 @@ } if (unit->PID_hlt) { - if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_KP", "%.2lf", unit->PID_hlt->dispKp)) < 0) { + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_KP", "%lf", PID_getKp(unit->PID_hlt))) < 0) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } - if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_KI", "%.2lf", unit->PID_hlt->dispKi)) < 0) { + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_KI", "%lf", PID_getKi(unit->PID_hlt))) < 0) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } - if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_KD", "%.2lf", unit->PID_hlt->dispKd)) < 0) { + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_KD", "%lf", PID_getKd(unit->PID_hlt))) < 0) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } - if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_SAMPLETIIME", "%ld", unit->PID_hlt->SampleTime)) < 0) { + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_SAMPLETIME", "%d", PID_getSampleTime(unit->PID_hlt))) < 0) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } - if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_DIRECTION", "%s", PIDDIRECTION[unit->PID_hlt->Direction])) < 0) { + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_DIRECTION", "%s", PIDDIRECTION[PID_getDirection(unit->PID_hlt)])) < 0) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } } if (unit->PID_mlt) { - if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_KP", "%.2lf", unit->PID_mlt->dispKp)) < 0) { + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_KP", "%lf", PID_getKp(unit->PID_mlt))) < 0) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } - if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_KI", "%.2lf", unit->PID_mlt->dispKi)) < 0) { + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_KI", "%lf", PID_getKi(unit->PID_mlt))) < 0) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } - if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_KD", "%.2lf", unit->PID_mlt->dispKd)) < 0) { + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_KD", "%lf", PID_getKd(unit->PID_mlt))) < 0) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } - if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_SAMPLETIIME", "%ld", unit->PID_mlt->SampleTime)) < 0) { + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_SAMPLETIME", "%d", PID_getSampleTime(unit->PID_mlt))) < 0) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } - if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_DIRECTION", "%s", PIDDIRECTION[unit->PID_mlt->Direction])) < 0) { + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_DIRECTION", "%s", PIDDIRECTION[PID_getDirection(unit->PID_mlt)])) < 0) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } @@ -609,9 +609,6 @@ mypath = xstrcpy(etcpath); mypath = xstrcat(mypath, (char *)"brewco.xml"); - if (debug) - fprintf(stdout, "Writing %s\n", mypath); - if ((fp = fopen(mypath, "w")) == NULL) { syslog(LOG_NOTICE, "could not rewrite %s", mypath); free(mypath); diff -r 55bcbf92ecab -r fdd30e935079 brewco/rdrecipes.c --- a/brewco/rdrecipes.c Tue Dec 22 21:07:14 2015 +0100 +++ b/brewco/rdrecipes.c Sat Dec 26 21:45:44 2015 +0100 @@ -118,6 +118,10 @@ syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement"); return 1; } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLTO", "%f", recipe->coolto)) < 0) { + syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement"); + return 1; + } if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "STARTTIME", "%d", (int)recipe->starttime)) < 0) { syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement"); return 1; @@ -333,6 +337,7 @@ recipe = (a_recipe *)malloc(sizeof(a_recipe)); memset(recipe, 0, sizeof(a_recipe)); recipe->next = NULL; + recipe->coolto = 20.0; cur = cur->xmlChildrenNode; while (cur != NULL) { @@ -351,6 +356,12 @@ recipe->boiltime = ival; xmlFree(key); } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"COOLTO"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &fval) == 1) + recipe->coolto = fval; + xmlFree(key); + } if ((!xmlStrcmp(cur->name, (const xmlChar *)"STARTTIME"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%d", &ival) == 1) diff -r 55bcbf92ecab -r fdd30e935079 brewco/rdsession.c --- a/brewco/rdsession.c Tue Dec 22 21:07:14 2015 +0100 +++ b/brewco/rdsession.c Sat Dec 26 21:45:44 2015 +0100 @@ -29,12 +29,11 @@ extern char *etcpath; -const char BREWSTEP[23][11] = { "NA", "INIT", "WATEROK", "PRIME", "WAITSTART", - "PREMASH", "MASHING", "IODINE", "REMOVE", "PREBOIL", - "BOIL", "BOILDONE", "HOPSTAND1", "COOLING1", "WHIRLPOOL1", - "COOLING2", "HOPSTAND2", "COOLING3", "HOPSTAND3", "COOLING", - "WHIRLPOOL", "CLEANUP", "DONE" }; -const char MASHSTEP[5][8] = { "NA", "PROMPT", "HEATING", "REST", "DONE" }; +const char BREWSTEP[16][10] = { "NA", "INIT", "WATEROK", "PRIME", "WAITSTART", + "PREMASH", "MASHING", "REMOVE", "PREBOIL", "BOIL", + "BOILDONE", "COOLING", "HOPSTAND", "WHIRLPOOL", "CLEANUP", + "DONE" }; +const char MASHSTEP[8][11] = { "MASH-IN", "PHYTASE", "GLUCANASE", "PROTEASE", "B-AMYLASE", "A-AMYLASE1", "A-AMYLASE2", "MASH-OUT" }; #define MY_ENCODING "utf-8" @@ -86,7 +85,11 @@ * Start an element named "BREWCO". Since thist is the first * element, this will be the root element of the document. */ - if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "BREWCO_BREW")) < 0) { + if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "BREWCO")) < 0) { + syslog(LOG_NOTICE, "wrsession: error at xmlTextWriterStartElement"); + return 1; + } + if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "BREW")) < 0) { syslog(LOG_NOTICE, "wrsession: error at xmlTextWriterStartElement"); return 1; } @@ -135,6 +138,14 @@ return 1; } + /* + * Close the element named BREW. + */ + if ((rc = xmlTextWriterEndElement(writer)) < 0) { + syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterEndElement"); + return 1; + } + /* * All done, close any open elements */ @@ -191,7 +202,7 @@ int i, ival; char *mypath; xmlDocPtr doc; - xmlNodePtr cur; + xmlNodePtr cur, s1cur; xmlChar *key; /* @@ -232,58 +243,66 @@ */ cur = cur->xmlChildrenNode; while (cur != NULL) { - if ((!xmlStrcmp(cur->name, (const xmlChar *)"UUID_RECIPE"))) { - brew->uuid_recipe = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - } - if ((!xmlStrcmp(cur->name, (const xmlChar *)"UUID_UNIT"))) { - brew->uuid_unit = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - } - if ((!xmlStrcmp(cur->name, (const xmlChar *)"NAME"))) { - brew->name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - } - if ((!xmlStrcmp(cur->name, (const xmlChar *)"BREWSTEP"))) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - for (i = 0; i < 23; i++) { - if (! xmlStrcmp(key, (const xmlChar *)BREWSTEP[i])) { - brew->brewstep = i; - break; + + if ((! xmlStrcmp(cur->name, (const xmlChar*)"BREW"))) { + s1cur = cur->xmlChildrenNode; + while (s1cur != NULL) { + + if ((!xmlStrcmp(s1cur->name, (const xmlChar *)"UUID_RECIPE"))) { + brew->uuid_recipe = (char *)xmlNodeListGetString(doc, s1cur->xmlChildrenNode, 1); + } + if ((!xmlStrcmp(s1cur->name, (const xmlChar *)"UUID_UNIT"))) { + brew->uuid_unit = (char *)xmlNodeListGetString(doc, s1cur->xmlChildrenNode, 1); } - } - xmlFree(key); - } - if ((!xmlStrcmp(cur->name, (const xmlChar *)"MASHSTEP"))) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - for (i = 0; i < 5; i++) { - if (! xmlStrcmp(key, (const xmlChar *)MASHSTEP[i])) { - brew->mashstep = i; - break; + if ((!xmlStrcmp(s1cur->name, (const xmlChar *)"NAME"))) { + brew->name = (char *)xmlNodeListGetString(doc, s1cur->xmlChildrenNode, 1); + } + if ((!xmlStrcmp(s1cur->name, (const xmlChar *)"BREWSTEP"))) { + key = xmlNodeListGetString(doc, s1cur->xmlChildrenNode, 1); + for (i = 0; i < 15; i++) { + if (! xmlStrcmp(key, (const xmlChar *)BREWSTEP[i])) { + brew->brewstep = i; + break; + } + } + xmlFree(key); } + if ((!xmlStrcmp(s1cur->name, (const xmlChar *)"MASHSTEP"))) { + key = xmlNodeListGetString(doc, s1cur->xmlChildrenNode, 1); + for (i = 0; i < 8; i++) { + if (! xmlStrcmp(key, (const xmlChar *)MASHSTEP[i])) { + brew->mashstep = i; + break; + } + } + xmlFree(key); + } + if ((!xmlStrcmp(s1cur->name, (const xmlChar *)"TIMEOUT"))) { + key = xmlNodeListGetString(doc, s1cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%d", &ival) == 1) + brew->timeout = ival; + xmlFree(key); + } + if ((!xmlStrcmp(s1cur->name, (const xmlChar *)"BOILTIMER"))) { + key = xmlNodeListGetString(doc, s1cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%d", &ival) == 1) + brew->boiltimer = ival; + xmlFree(key); + } + if ((!xmlStrcmp(s1cur->name, (const xmlChar *)"STARTTIME"))) { + key = xmlNodeListGetString(doc, s1cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%d", &ival) == 1) + brew->starttime = (time_t)ival; + xmlFree(key); + } + if ((!xmlStrcmp(s1cur->name, (const xmlChar *)"ENDTIME"))) { + key = xmlNodeListGetString(doc, s1cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%d", &ival) == 1) + brew->endtime = (time_t)ival; + xmlFree(key); + } + s1cur = s1cur->next; } - xmlFree(key); - } - if ((!xmlStrcmp(cur->name, (const xmlChar *)"TIMEOUT"))) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - if (sscanf((const char *)key, "%d", &ival) == 1) - brew->timeout = ival; - xmlFree(key); - } - if ((!xmlStrcmp(cur->name, (const xmlChar *)"BOILTIMER"))) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - if (sscanf((const char *)key, "%d", &ival) == 1) - brew->boiltimer = ival; - xmlFree(key); - } - if ((!xmlStrcmp(cur->name, (const xmlChar *)"STARTTIME"))) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - if (sscanf((const char *)key, "%d", &ival) == 1) - brew->starttime = (time_t)ival; - xmlFree(key); - } - if ((!xmlStrcmp(cur->name, (const xmlChar *)"ENDTIME"))) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - if (sscanf((const char *)key, "%d", &ival) == 1) - brew->endtime = (time_t)ival; - xmlFree(key); } cur = cur->next; } diff -r 55bcbf92ecab -r fdd30e935079 brewco/setup.c --- a/brewco/setup.c Tue Dec 22 21:07:14 2015 +0100 +++ b/brewco/setup.c Sat Dec 26 21:45:44 2015 +0100 @@ -1055,22 +1055,24 @@ case 3: snprintf(pmpt, Config.lcd_cols + 1, "Boil time: %3d mins", recipe->boiltime); prompt(200, pmpt); break; - case 4: + case 4: snprintf(pmpt, Config.lcd_cols + 1, " Cool to: %5.1f\001", recipe->coolto); + prompt(200, pmpt); + break; case 5: case 6: case 7: case 8: case 9: case 10: - case 11: snprintf(pmpt, Config.lcd_cols + 1, "Mash: %s", recipe->mash[idx - 4].name); + case 11: + case 12: snprintf(pmpt, Config.lcd_cols + 1, "Mash: %s", recipe->mash[idx - 5].name); prompt(200, pmpt); - if (recipe->mash[idx - 4].skip) + if (recipe->mash[idx - 5].skip) snprintf(pmpt, Config.lcd_cols + 1, " Skipped"); else - snprintf(pmpt, Config.lcd_cols + 1, " Sv %4.1f\001 %3d mins", recipe->mash[idx - 4].setpoint, recipe->mash[idx - 4].duration); + snprintf(pmpt, Config.lcd_cols + 1, " Sv %4.1f\001 %3d mins", recipe->mash[idx - 5].setpoint, recipe->mash[idx - 5].duration); prompt(300, pmpt); break; - case 12: case 13: case 14: case 15: @@ -1079,28 +1081,29 @@ case 18: case 19: case 20: - case 21: snprintf(pmpt, Config.lcd_cols + 1, "Add: %s", recipe->hops[idx - 12].name); + case 21: + case 22: snprintf(pmpt, Config.lcd_cols + 1, "Add: %s", recipe->hops[idx - 13].name); prompt(200, pmpt); - if (recipe->hops[idx - 12].skip) + if (recipe->hops[idx - 13].skip) snprintf(pmpt, Config.lcd_cols + 1, " Skipped"); else { - if (recipe->hops[idx - 12].boiltime == -1) + if (recipe->hops[idx - 13].boiltime == -1) snprintf(pmpt, Config.lcd_cols + 1, " First Wort Hop"); else - snprintf(pmpt, Config.lcd_cols + 1, " Boil for %3d mins", recipe->hops[idx - 12].boiltime); + snprintf(pmpt, Config.lcd_cols + 1, " Boil for %3d mins", recipe->hops[idx - 13].boiltime); } prompt(300, pmpt); break; - case 22: - case 23: - case 24: snprintf(pmpt, Config.lcd_cols + 1, "Hopstand: %s", recipe->hopstand[idx - 22].name); + case 23: + case 24: + case 25: snprintf(pmpt, Config.lcd_cols + 1, "Hopstand: %s", recipe->hopstand[idx - 23].name); prompt(200, pmpt); - if (recipe->hopstand[idx - 22].skip) + if (recipe->hopstand[idx - 23].skip) snprintf(pmpt, Config.lcd_cols + 1, " Skipped"); - else if (recipe->hopstand[idx - 22].hold) - snprintf(pmpt, Config.lcd_cols + 1, "Hold at %4.1f %3d mins", recipe->hopstand[idx - 22].setpoint, recipe->hopstand[idx - 22].duration); + else if (recipe->hopstand[idx - 23].hold) + snprintf(pmpt, Config.lcd_cols + 1, "Hold at %4.1f %3d mins", recipe->hopstand[idx - 23].setpoint, recipe->hopstand[idx - 23].duration); else - snprintf(pmpt, Config.lcd_cols + 1, "Hold for %3d mins", recipe->hopstand[idx - 22].duration); + snprintf(pmpt, Config.lcd_cols + 1, "Hold for %3d mins", recipe->hopstand[idx - 23].duration); prompt(300, pmpt); break; } @@ -1147,16 +1150,17 @@ break; case 3: editInteger(&recipe->boiltime, 60, 240, 5, (char *)"Boil time:", (char *)"mins"); break; - case 4: + case 4: editFloat(&recipe->coolto, 10.0, 30.0, (char *)" Cool to"); + case 5: case 6: case 7: case 8: case 9: case 10: - case 11: editMash(&recipe->mash[idx-4]); + case 11: + case 12: editMash(&recipe->mash[idx-5]); break; - case 12: case 13: case 14: case 15: @@ -1165,11 +1169,12 @@ case 18: case 19: case 20: - case 21: editHopaddition(&recipe->hops[idx-12], recipe->boiltime); + case 21: + case 22: editHopaddition(&recipe->hops[idx-13], recipe->boiltime); break; - case 22: case 23: - case 24: editHopstand(&recipe->hopstand[idx-22]); + case 24: + case 25: editHopstand(&recipe->hopstand[idx-23]); break; } } @@ -1195,6 +1200,7 @@ snprintf(name, 21, "%04d", number); recipe->code = xstrcpy(name); recipe->boiltime = 90; + recipe->coolto = 20.0; recipe->starttime = recipe->endtime = (time_t)0; /* * Initial mash schedule, set a single-step 67 degr. mash diff -r 55bcbf92ecab -r fdd30e935079 brewco/setup.h --- a/brewco/setup.h Tue Dec 22 21:07:14 2015 +0100 +++ b/brewco/setup.h Sat Dec 26 21:45:44 2015 +0100 @@ -2,6 +2,7 @@ #define _SETUP_H +void editInteger(int *, int, int, int, char *, char *); void editUnit(units_list *); void addUnit(int); void setup(void); diff -r 55bcbf92ecab -r fdd30e935079 brewco/simulator.c --- a/brewco/simulator.c Tue Dec 22 21:07:14 2015 +0100 +++ b/brewco/simulator.c Sat Dec 26 21:45:44 2015 +0100 @@ -81,20 +81,20 @@ if (SIM_hlt_value) { Config.simulator->hlt_heater_temp += (250 - Config.simulator->hlt_heater_temp) / 2000; } else { - Config.simulator->hlt_heater_temp -= (Config.simulator->hlt_heater_temp - Config.simulator->hlt_temperature) / 500; + Config.simulator->hlt_heater_temp -= (Config.simulator->hlt_heater_temp - Config.simulator->hlt_temperature) / 250; } Config.simulator->mlt_heater_state = SIM_mlt_value; if (SIM_mlt_value) { Config.simulator->mlt_heater_temp += (250 - Config.simulator->mlt_heater_temp) / 2000; } else { - Config.simulator->mlt_heater_temp -= (Config.simulator->mlt_heater_temp - Config.simulator->mlt_temperature) / 500; + Config.simulator->mlt_heater_temp -= (Config.simulator->mlt_heater_temp - Config.simulator->mlt_temperature) / 250; } /* * If cooling, bring down the MLT temperature. Assume 14 degrees coolwater. */ if (SIM_cooler) { - Config.simulator->mlt_temperature -= (Config.simulator->mlt_temperature - 14) / (250 * Config.simulator->hlt_heater_volume); + Config.simulator->mlt_temperature -= (Config.simulator->mlt_temperature - 14) / (175 * Config.simulator->hlt_heater_volume); } /*