# HG changeset patch # User Michiel Broek # Date 1450814834 -3600 # Node ID 55bcbf92ecab4265c34b0d794561a867fc4603e0 # Parent 1564b60558b189eb816906f3e32c0f8434f0e827 Added initial part of the brew automation. diff -r 1564b60558b1 -r 55bcbf92ecab brewco/brewco.c --- a/brewco/brewco.c Tue Dec 22 15:59:26 2015 +0100 +++ b/brewco/brewco.c Tue Dec 22 21:07:14 2015 +0100 @@ -49,6 +49,7 @@ extern int debug; extern sys_config Config; +extern a_recipe *recipes; extern int lcdHandle; extern int slcdHandle; extern int sock; @@ -197,9 +198,107 @@ -void automatic_brew(units_list *, brew_session *); -void automatic_brew(units_list *unit, brew_session *brew) +void automatic_brew(units_list *, brew_session *, a_recipe *, int); +void automatic_brew(units_list *unit, brew_session *brew, a_recipe *recipe, int dosave) { + int key, save = dosave; + +// if (debug) +// fprintf(stdout, "auto: step %d\n", brew->brewstep); + + 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_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; + } + 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"); + 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 --- " */ + 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" */ + break; + } + + if (save) + wrsession(brew); } @@ -339,18 +438,76 @@ +char *choose_recipe(void); +char *choose_recipe(void) +{ + int total, i, key, choice = 1; + static char uuid[37]; + a_recipe *recipe; + char pmpt[81]; + + strcpy(uuid, (char *)"00000000-0000-0000-0000-000000000000"); + for (;;) { + total = 0; + for (recipe = recipes; recipe; recipe = recipe->next) + total++; + + if (total == 0) + return uuid; + + i = 0; + for (recipe = recipes; recipe; recipe = recipe->next) { + i++; + if (i == choice) + break; + } + + prompt(102, NULL); /* " SETUP MENU " */ + prompt(221, NULL); /* " Select Recipe " */ + if (total) { + snprintf(pmpt, Config.lcd_cols + 1, "%s %s ", recipe->code, recipe->name); + prompt(300, pmpt); + } + if (total == 1) + prompt(405, NULL); /* "--- --- quit ok " */ + else if (choice == 1) + prompt(402, NULL); /* "--- dwn quit ok " */ + else if (choice == total) + prompt(404, NULL); /* " up --- quit ok " */ + else + prompt(403, NULL); /* " up dwn quit ok " */ + + key = keywait(); + if ((key == KEY_RETURN) || my_shutdown) + return uuid; + if (key == KEY_ENTER) { + strcpy(uuid, recipe->uuid); + return uuid; + } + if ((key == KEY_UP) && (total > 1) && (choice > 1)) { + choice--; + } + if ((key == KEY_DOWN) && (total > 1) && (choice < total)) + choice++; + } +} + + + int server(void); int server(void) { - int rc = 0, run = 1, key, temp, MLTp, HLTp, percslot, percfase = PERC_INIT; + int rc = 0, run = 1, dosave, key, temp, MLTp, HLTp, percslot, percfase = PERC_INIT; int do_init = TRUE, seconds = 0, minutes = 0; units_list *unit; + a_recipe *recipe = NULL; brew_session *brew = NULL; #ifndef HAVE_WIRINGPI_H long t = 0; #endif time_t now, last = (time_t)0; long nowmillis, perctimer; + struct tm *tm; prompt(101, NULL); @@ -535,6 +692,7 @@ nowmillis = perctimer = millis(); percslot = 0; percfase = PERC_INIT; + dosave = 0; } /* run_pause code here */ @@ -544,11 +702,7 @@ * the scheduling by themselves. */ rc = PID_compute(unit->PID_hlt); -// if (seconds < 3) -// fprintf(stdout, "hlt rc=%d"); rc = PID_compute(unit->PID_mlt); -// if (seconds < 3) -// fprintf(stdout, " mlt rc=%d\n"); /* * This is the serial heaters schedule loop. The total @@ -612,9 +766,11 @@ */ last = now; seconds++; + if (seconds > 59) { seconds = 0; minutes++; + dosave = 1; } //fprintf(stdout, "%d seconds %d minutes %ld millis\n", seconds, minutes, millis()); @@ -650,7 +806,39 @@ /* * Automate mode */ - automatic_brew(unit, brew); + automatic_brew(unit, brew, recipe, dosave); + dosave = 0; + if (brew->brewstep == -1) { + /* + * Save session and move it + */ + wrsession(brew); + char *fpath, *tpath; + fpath = xstrcpy(etcpath); + fpath = xstrcat(fpath, (char *)"brewing.xml"); + tpath = xstrcpy(varpath); + tpath = xstrcat(tpath, (char *)"old/brewing.xml."); + mkdirs(tpath, 0755); + tpath = xstrcat(tpath, brew->name); + if (debug) + fprintf(stdout, "auto: saving as %s\n", tpath); + file_cp(fpath, tpath); + unlink(fpath); + free(fpath); + free(tpath); + + /* + * Free memory, session is over. + */ + if (brew->name) + free(brew->name); + if (brew->uuid_recipe) + free(brew->uuid_recipe); + if (brew->uuid_unit) + free(brew->uuid_unit); + free(brew); + brew = NULL; + } } else if (manual != MANUAL_NONE) { /* @@ -675,6 +863,79 @@ setup(); prompt(101, NULL); /* " Brewco x.x.x " */ prompt(401, NULL); /* "--- MAN AUTO SETUP" */ + } else if (key == KEY_RETURN && ! brew) { + int i, isOk = TRUE; + char message[41]; + + tm = localtime(&now); + snprintf(message, 40, "%04d%02d%02d-%02d%02d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min); + brew = (brew_session *)malloc(sizeof(brew_session)); + brew->uuid_recipe = xstrcpy(choose_recipe()); + brew->uuid_unit = xstrcpy(unit->uuid); + brew->name = xstrcpy(message); + brew->brewstep = STEP_NA; + brew->mashstep = MASH_NA; + brew->timeout = brew->boiltimer = 0; + brew->starttime = brew->endtime = (time_t)0; + /* + * Now check if everything is sane + */ + if (strcmp(brew->uuid_recipe, (char *)"00000000-0000-0000-0000-000000000000") == 0) { + isOk = FALSE; + snprintf(message, Config.lcd_cols + 1, " No recipe selected "); + if (debug) + fprintf(stdout, "brew init: No recipe selected\n"); + } + if (isOk) { + isOk = FALSE; + for (recipe = recipes; recipe; recipe = recipe->next) { + if (strcmp(recipe->uuid, brew->uuid_recipe) == 0) { + isOk = TRUE; + if (! recipe->boiltime) + isOk = FALSE; + for (i = 0; i < 8; i++) { + if (! recipe->mash[i].skip && ! recipe->mash[i].setpoint) + isOk = FALSE; + } + for (i = 0; i < 3; i++) { + if (! recipe->hopstand[i].skip && recipe->hopstand[i].hold && (recipe->hopstand[i].setpoint == 0)) + isOk = FALSE; + } + break; + } + } + if (isOk == FALSE) { + snprintf(message, Config.lcd_cols + 1, " Recipe error "); + if (debug) + fprintf(stdout, "brew init: recipe error\n"); + } + } + + if (debug) + fprintf(stdout, "init brew: %s\n", isOk ? (char *)"Ok":(char *)"Error"); + + if (isOk) { + wrsession(brew); + } else { + prompt(300, message); + prompt(408, NULL); /* "--- --- Ok --- " */ + key = keywait(); + if (brew->name) + free(brew->name); + if (brew->uuid_recipe) + free(brew->uuid_recipe); + if (brew->uuid_unit) + free(brew->uuid_unit); + free(brew); + brew = NULL; + /* + * Rewrite the display + */ + prompt(101, NULL); /* " Brewco x.x.x " */ + prompt(300, NULL); /* " " */ + prompt(401, NULL); /* "--- MAN AUTO SETUP" */ + } + } else if (key == KEY_DOWN) { manual = MANUAL_SELHLT; manual_prompt(); diff -r 1564b60558b1 -r 55bcbf92ecab brewco/brewco.h --- a/brewco/brewco.h Tue Dec 22 15:59:26 2015 +0100 +++ b/brewco/brewco.h Tue Dec 22 21:07:14 2015 +0100 @@ -316,6 +316,7 @@ typedef struct _brew_session { char *uuid_recipe; /* Brewing this recipe */ char *uuid_unit; /* Brewing unit */ + char *name; /* Session name */ int brewstep; /* Main steps */ int mashstep; /* Mash step */ int timeout; /* Generic time downcouner */ diff -r 1564b60558b1 -r 55bcbf92ecab brewco/rdsession.c --- a/brewco/rdsession.c Tue Dec 22 15:59:26 2015 +0100 +++ b/brewco/rdsession.c Tue Dec 22 21:07:14 2015 +0100 @@ -106,6 +106,10 @@ syslog(LOG_NOTICE, "wrsession: error at xmlTextWriterWriteFormatElement"); return 1; } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "NAME", "%s", brew->name)) < 0) { + syslog(LOG_NOTICE, "wrsession: error at xmlTextWriterWriteFormatElement"); + return 1; + } if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "BREWSTEP", "%s", BREWSTEP[brew->brewstep])) < 0) { syslog(LOG_NOTICE, "wrsession: error at xmlTextWriterWriteElement"); return 1; @@ -234,6 +238,9 @@ 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++) {