# HG changeset patch # User Michiel Broek # Date 1414264127 -7200 # Node ID d810df0df36ad3f5b1d0411ad45298fa250a1fd8 # Parent 8b99ab77262bc0bc1bdab91c3d1916933d790f1b Added code to detect primary fermentation diff -r 8b99ab77262b -r d810df0df36a thermferm/rdconfig.c --- a/thermferm/rdconfig.c Wed Oct 22 12:42:20 2014 +0200 +++ b/thermferm/rdconfig.c Sat Oct 25 21:08:47 2014 +0200 @@ -442,6 +442,18 @@ syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROF_PEAK_ABS", "%.3f", tmp3->prof_peak_abs)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROF_PEAK_REL", "%.3f", tmp3->prof_peak_rel)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROF_PRIMARY_DONE", "%d", (unsigned int)tmp3->prof_primary_done)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } } if ((rc = xmlTextWriterEndElement(writer)) < 0) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterEndElement"); @@ -849,7 +861,7 @@ unit->version = 1; unit->uuid = unit->name = unit->air_address = unit->beer_address = unit->heater_address = \ unit->cooler_address = unit->fan_address = unit->door_address = unit->profile = NULL; - unit->volume = 0.0; + unit->volume = unit->prof_peak_abs = unit->prof_peak_rel = 0.0; unit->air_temperature = unit->beer_temperature = unit->beer_set = unit->fridge_set = 20.0; unit->air_state = unit->beer_state = 1; // missing unit->heater_state = unit->cooler_state = unit->fan_state = unit->door_state = unit->mode = unit->prof_state = 0; @@ -859,7 +871,7 @@ unit->temp_set_max = 30.0; unit->idle_rangeH = 1.0; unit->idle_rangeL = -1.0; - unit->prof_started = unit->prof_paused = (time_t)0; + unit->prof_started = unit->prof_paused = unit->prof_primary_done = (time_t)0; unit->prof_percent = 0; unit->PID_err_old = unit->PID_I_err = 0.0; @@ -1017,6 +1029,24 @@ } xmlFree(key); } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROF_PEAK_ABS"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->prof_peak_abs = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROF_PEAK_REL"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->prof_peak_rel = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROF_PRIMARY_DONE"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%d", &ival) == 1) + unit->prof_primary_done = ival; + xmlFree(key); + } cur = cur->next; } diff -r 8b99ab77262b -r d810df0df36a thermferm/server.c --- a/thermferm/server.c Wed Oct 22 12:42:20 2014 +0200 +++ b/thermferm/server.c Sat Oct 25 21:08:47 2014 +0200 @@ -1447,7 +1447,7 @@ unit->name = xstrcpy(param); unit->air_address = unit->beer_address = unit->heater_address = unit->cooler_address = \ unit->fan_address = unit->door_address = unit->profile = NULL; - unit->volume = 0.0; + unit->volume = unit->prof_peak_abs = unit->prof_peak_rel = 0.0; unit->air_state = unit->beer_state = 1; unit->air_temperature = unit->beer_temperature = 20000; unit->beer_set = unit->fridge_set = 20.0; @@ -1458,7 +1458,7 @@ unit->temp_set_max = 30.0; unit->idle_rangeH = 1.0; unit->idle_rangeL = -1.0; - unit->prof_started = unit->prof_paused = (time_t)0; + unit->prof_started = unit->prof_paused = unit->prof_primary_done = (time_t)0; unit->prof_percent = 0; unit->PID_err_old = unit->PID_I_err = 0.0; @@ -1554,6 +1554,9 @@ srv_send((char *)"PROF_STATE,%s", PROFSTATE[unit->prof_state]); } srv_send((char *)"PROF_TARGET,%.3f", unit->prof_target); + srv_send((char *)"PROF_PEAK_ABS,%.3f", unit->prof_peak_abs); + srv_send((char *)"PROF_PEAK_REL,%.3f", unit->prof_peak_rel); + srv_send((char *)"PROF_PRIMARY_DONE,%d", (int)unit->prof_primary_done); srv_send((char *)"TEMP_SET_MIN,%.1f", unit->temp_set_min); srv_send((char *)"TEMP_SET_MAX,%.1f", unit->temp_set_max); srv_send((char *)"IDLE_RANGE_L,%.1f", unit->idle_rangeL); @@ -1827,7 +1830,8 @@ case PROFILE_RUN: if (unit->prof_state == PROFILE_OFF) { unit->prof_state = PROFILE_RUN; unit->prof_started = time(NULL); - unit->prof_paused = 0; + unit->prof_paused = unit->prof_primary_done = 0; + unit->prof_peak_abs = unit->prof_peak_rel = 0.0; syslog(LOG_NOTICE, "Fermenter unit %s profile to RUN", unit->uuid); } break; diff -r 8b99ab77262b -r d810df0df36a thermferm/thermferm.c --- a/thermferm/thermferm.c Wed Oct 22 12:42:20 2014 +0200 +++ b/thermferm/thermferm.c Sat Oct 25 21:08:47 2014 +0200 @@ -605,7 +605,8 @@ if (key == KEY_ENTER) { current_unit->prof_state = PROFILE_RUN; current_unit->prof_started = time(NULL); - current_unit->prof_paused = 0; + current_unit->prof_paused = current_unit->prof_primary_done = 0; + current_unit->prof_peak_abs = current_unit->prof_peak_rel = 0.0; syslog(LOG_NOTICE, "Profile started from the panel"); go_menu(MENU_MODE_PROFILE); } @@ -1105,6 +1106,9 @@ * unit->prof_state - PROFILE_OFF|PROFILE_PAUSE|PROFILE_RUN|PROFILE_DONE * unit->prof_target - Calculated target temperature. * unit->prof_paused - Internal pause counter. + * unit->prof_peak_abs - Peak temperature of the beer. + * unit->prof_peak_rel - Peak temperature between beer and fridge. + * unit->prof_primary_done - time when primary fermentation was over the peak. */ for (profile = Config.profiles; profile; profile = profile->next) { if (strcmp(unit->profile, profile->uuid) == 0) { @@ -1134,6 +1138,35 @@ fprintf(stdout, "run_HMS=%d,%d,%d ", run_hours, run_minutes, run_seconds); /* + * Primary fermentation tests + */ + if ((unit->beer_temperature / 1000.0) > unit->prof_peak_abs) + unit->prof_peak_abs = unit->beer_temperature / 1000.0; + if (((unit->beer_temperature - unit->air_temperature) / 1000.0) > unit->prof_peak_rel) + unit->prof_peak_rel = (unit->beer_temperature - unit->air_temperature) / 1000.0; + if (unit->prof_primary_done == 0) { + if (unit->cooler_address) { + /* + * There is a cooler. If the difference between the beer and air temperature + * drops we assume the primary fermentation is done. + */ + if (((unit->beer_temperature - unit->air_temperature) / 1000.0) < (unit->prof_peak_rel - 0.5)) { + unit->prof_primary_done = time(NULL); + syslog(LOG_NOTICE, "Profile `%s' primary fermentation is ready (cooler mode)", profile->name); + } + } else { + /* + * This method works if the unit has no cooling or if the profile allowd the + * beer temperature to rise freely. + */ + if ((unit->beer_temperature / 1000.0) < (unit->prof_peak_abs - 0.5)) { + unit->prof_primary_done = time(NULL); + syslog(LOG_NOTICE, "Profile `%s' primary fermentation is ready (free rise mode)", profile->name); + } + } + } + + /* * See how long this profile will take */ tot_minutes = 0; diff -r 8b99ab77262b -r d810df0df36a thermferm/thermferm.h --- a/thermferm/thermferm.h Wed Oct 22 12:42:20 2014 +0200 +++ b/thermferm/thermferm.h Sat Oct 25 21:08:47 2014 +0200 @@ -139,6 +139,9 @@ float prof_target; /* Profile current target temp */ time_t prof_paused; /* Profile total pause time */ int prof_percent; /* Profile percentage done */ + float prof_peak_abs; /* Profile absolute peak temp */ + float prof_peak_rel; /* Profile relative peak temp */ + time_t prof_primary_done; /* Profile primary is done */ float PID_I_err; /* PID Intergal error */ float PID_err_old; /* PID old error value */ } units_list;