thermferm/thermferm.c

changeset 570
1e0192b295b9
parent 569
9c69d43bfb06
child 571
6f8eda55ec2c
equal deleted inserted replaced
569:9c69d43bfb06 570:1e0192b295b9
47 extern sys_config Config; 47 extern sys_config Config;
48 extern int lcdHandle; 48 extern int lcdHandle;
49 extern int slcdHandle; 49 extern int slcdHandle;
50 int setupmenu = MENU_NONE; 50 int setupmenu = MENU_NONE;
51 units_list *current_unit = NULL; /* In panel editor this points to the current unit. */ 51 units_list *current_unit = NULL; /* In panel editor this points to the current unit. */
52 profiles_list *current_profile = NULL;
53 float temp_temp = 20.0; 52 float temp_temp = 20.0;
54 53
55 #ifndef HAVE_WIRINGPI_H 54 #ifndef HAVE_WIRINGPI_H
56 pthread_t threads[5]; 55 pthread_t threads[5];
57 #endif 56 #endif
272 lcdPuts(lcdHandle, "New mode PROFILE"); 271 lcdPuts(lcdHandle, "New mode PROFILE");
273 #endif 272 #endif
274 slcdPuts(slcdHandle, "New mode PROFILE"); 273 slcdPuts(slcdHandle, "New mode PROFILE");
275 break; 274 break;
276 275
277 case MENU_PROFILE_SELECT: snprintf(buf, Config.lcd_cols, "%s", current_profile->name); 276 case MENU_PROFILE_START: snprintf(buf, Config.lcd_cols, "%s", current_unit->profile_name);
278 #ifdef HAVE_WIRINGPI_H
279 lcdPuts(lcdHandle, buf);
280 lcdPosition(lcdHandle, 0, 1);
281 lcdPuts(lcdHandle, "Select profile");
282 #endif
283 slcdPuts(slcdHandle, buf);
284 slcdPosition(slcdHandle, 0, 1);
285 slcdPuts(slcdHandle, "Select profile");
286 break;
287
288 case MENU_PROFILE_START: snprintf(buf, Config.lcd_cols, "%s", current_profile->name);
289 #ifdef HAVE_WIRINGPI_H 277 #ifdef HAVE_WIRINGPI_H
290 lcdPuts(lcdHandle, buf); 278 lcdPuts(lcdHandle, buf);
291 lcdPosition(lcdHandle, 0, 1); 279 lcdPosition(lcdHandle, 0, 1);
292 lcdPuts(lcdHandle, "Start profile"); 280 lcdPuts(lcdHandle, "Start profile");
293 #endif 281 #endif
294 slcdPuts(slcdHandle, buf); 282 slcdPuts(slcdHandle, buf);
295 slcdPosition(slcdHandle, 0, 1); 283 slcdPosition(slcdHandle, 0, 1);
296 slcdPuts(slcdHandle, "Start profile"); 284 slcdPuts(slcdHandle, "Start profile");
297 break; 285 break;
298 286
299 case MENU_PROFILE_PAUSE: snprintf(buf, Config.lcd_cols, "%s", current_profile->name); 287 case MENU_PROFILE_PAUSE: snprintf(buf, Config.lcd_cols, "%s", current_unit->profile_name);
300 #ifdef HAVE_WIRINGPI_H 288 #ifdef HAVE_WIRINGPI_H
301 lcdPuts(lcdHandle, buf); 289 lcdPuts(lcdHandle, buf);
302 lcdPosition(lcdHandle, 0, 1); 290 lcdPosition(lcdHandle, 0, 1);
303 lcdPuts(lcdHandle, "Pause profile"); 291 lcdPuts(lcdHandle, "Pause profile");
304 #endif 292 #endif
305 slcdPuts(slcdHandle, buf); 293 slcdPuts(slcdHandle, buf);
306 slcdPosition(slcdHandle, 0, 1); 294 slcdPosition(slcdHandle, 0, 1);
307 slcdPuts(slcdHandle, "Pause profile"); 295 slcdPuts(slcdHandle, "Pause profile");
308 break; 296 break;
309 297
310 case MENU_PROFILE_ABORT: snprintf(buf, Config.lcd_cols, "%s", current_profile->name); 298 case MENU_PROFILE_ABORT: snprintf(buf, Config.lcd_cols, "%s", current_unit->profile_name);
311 #ifdef HAVE_WIRINGPI_H 299 #ifdef HAVE_WIRINGPI_H
312 lcdPuts(lcdHandle, buf); 300 lcdPuts(lcdHandle, buf);
313 lcdPosition(lcdHandle, 0, 1); 301 lcdPosition(lcdHandle, 0, 1);
314 lcdPuts(lcdHandle, "Abort profile"); 302 lcdPuts(lcdHandle, "Abort profile");
315 #endif 303 #endif
316 slcdPuts(slcdHandle, buf); 304 slcdPuts(slcdHandle, buf);
317 slcdPosition(slcdHandle, 0, 1); 305 slcdPosition(slcdHandle, 0, 1);
318 slcdPuts(slcdHandle, "Abort profile"); 306 slcdPuts(slcdHandle, "Abort profile");
319 break; 307 break;
320 308
321 case MENU_PROFILE_RESUME: snprintf(buf, Config.lcd_cols, "%s", current_profile->name); 309 case MENU_PROFILE_RESUME: snprintf(buf, Config.lcd_cols, "%s", current_unit->profile_name);
322 #ifdef HAVE_WIRINGPI_H 310 #ifdef HAVE_WIRINGPI_H
323 lcdPuts(lcdHandle, buf); 311 lcdPuts(lcdHandle, buf);
324 lcdPosition(lcdHandle, 0, 1); 312 lcdPosition(lcdHandle, 0, 1);
325 lcdPuts(lcdHandle, "Resume profile"); 313 lcdPuts(lcdHandle, "Resume profile");
326 #endif 314 #endif
327 slcdPuts(slcdHandle, buf); 315 slcdPuts(slcdHandle, buf);
328 slcdPosition(slcdHandle, 0, 1); 316 slcdPosition(slcdHandle, 0, 1);
329 slcdPuts(slcdHandle, "Resume profile"); 317 slcdPuts(slcdHandle, "Resume profile");
330 break; 318 break;
331 319
332 case MENU_PROFILE_GOOFF: snprintf(buf, Config.lcd_cols, "%s", current_profile->name); 320 case MENU_PROFILE_GOOFF: snprintf(buf, Config.lcd_cols, "%s", current_unit->profile_name);
333 #ifdef HAVE_WIRINGPI_H 321 #ifdef HAVE_WIRINGPI_H
334 lcdPuts(lcdHandle, buf); 322 lcdPuts(lcdHandle, buf);
335 lcdPosition(lcdHandle, 0, 1); 323 lcdPosition(lcdHandle, 0, 1);
336 lcdPuts(lcdHandle, "Set profile OFF"); 324 lcdPuts(lcdHandle, "Set profile OFF");
337 #endif 325 #endif
340 slcdPuts(slcdHandle, "Set profile OFF"); 328 slcdPuts(slcdHandle, "Set profile OFF");
341 break; 329 break;
342 330
343 case MENU_TOP_SYS: 331 case MENU_TOP_SYS:
344 #ifdef HAVE_WIRINGPI_H 332 #ifdef HAVE_WIRINGPI_H
345 lcdPuts(lcdHandle, "System menu"); 333 lcdPuts(lcdHandle, "System menu");
346 #endif 334 #endif
347 slcdPuts(slcdHandle, "System menu"); 335 slcdPuts(slcdHandle, "System menu");
348 break; 336 break;
349 337
350 case MENU_SYS_HALT: 338 case MENU_SYS_HALT:
351 #ifdef HAVE_WIRINGPI_H 339 #ifdef HAVE_WIRINGPI_H
352 lcdPuts(lcdHandle, "Halt system"); 340 lcdPuts(lcdHandle, "Halt system");
353 #endif 341 #endif
411 if (current_unit->mode == UNITMODE_PROFILE) { 399 if (current_unit->mode == UNITMODE_PROFILE) {
412 /* 400 /*
413 * Set a sane default until it will be overruled by the 401 * Set a sane default until it will be overruled by the
414 * main processing loop. 402 * main processing loop.
415 */ 403 */
416 current_unit->prof_target_lo = 19.8; 404 current_unit->prof_target_lo = 20.0;
417 current_unit->prof_target_hi = 20.2; 405 current_unit->prof_target_hi = 20.0;
418 current_unit->prof_fridge_mode = 0; 406 current_unit->prof_fridge_mode = 0;
419 } 407 }
420 } 408 }
421 409
422 410
425 * Handle panel key events 413 * Handle panel key events
426 */ 414 */
427 void panel_key_events(int key) 415 void panel_key_events(int key)
428 { 416 {
429 units_list *unit; 417 units_list *unit;
430 profiles_list *profile;
431 int rc; 418 int rc;
432 419
433 switch (setupmenu) { 420 switch (setupmenu) {
434 case MENU_NONE: 421 case MENU_NONE:
435 if ((key == KEY_DOWN) || (key == KEY_UP)) 422 if ((key == KEY_DOWN) || (key == KEY_UP))
503 case MENU_MODE_OFF: 490 case MENU_MODE_OFF:
504 if (key == KEY_ESCAPE) 491 if (key == KEY_ESCAPE)
505 go_menu(MENU_UNITS); 492 go_menu(MENU_UNITS);
506 if (key == KEY_DOWN) 493 if (key == KEY_DOWN)
507 go_menu(MENU_MODE_NONE); 494 go_menu(MENU_MODE_NONE);
508 if (key == KEY_UP) 495 if (key == KEY_UP) {
509 go_menu(MENU_MODE_PROFILE); 496 if (current_unit->profile_uuid)
497 go_menu(MENU_MODE_PROFILE);
498 else
499 go_menu(MENU_MODE_BEER);
500 }
510 if (key == KEY_ENTER) { 501 if (key == KEY_ENTER) {
511 change_mode(UNITMODE_OFF); 502 change_mode(UNITMODE_OFF);
512 go_menu(MENU_MODE_OFF); 503 go_menu(MENU_MODE_OFF);
513 } 504 }
514 break; 505 break;
620 break; 611 break;
621 612
622 case MENU_MODE_BEER: 613 case MENU_MODE_BEER:
623 if (key == KEY_ESCAPE) 614 if (key == KEY_ESCAPE)
624 go_menu(MENU_UNITS); 615 go_menu(MENU_UNITS);
625 if (key == KEY_DOWN) 616 if (key == KEY_DOWN) {
626 go_menu(MENU_MODE_PROFILE); 617 if (current_unit->profile_uuid)
618 go_menu(MENU_MODE_PROFILE);
619 else
620 go_menu(MENU_MODE_OFF);
621 }
627 if (key == KEY_UP) 622 if (key == KEY_UP)
628 go_menu(MENU_MODE_FRIDGE); 623 go_menu(MENU_MODE_FRIDGE);
629 if (key == KEY_ENTER) { 624 if (key == KEY_ENTER) {
630 if (current_unit->mode == UNITMODE_BEER) { 625 if (current_unit->mode == UNITMODE_BEER) {
631 temp_temp = current_unit->beer_set; 626 temp_temp = current_unit->beer_set;
659 go_menu(MENU_MODE_BEER); 654 go_menu(MENU_MODE_BEER);
660 } 655 }
661 break; 656 break;
662 657
663 case MENU_MODE_PROFILE: 658 case MENU_MODE_PROFILE:
664 if (current_unit->profile) {
665 for (current_profile = Config.profiles; current_profile; current_profile = current_profile->next) {
666 if (strcmp(current_profile->uuid, current_unit->profile) == 0)
667 break;
668 }
669 } else {
670 current_profile = NULL;
671 }
672 if (key == KEY_ESCAPE) 659 if (key == KEY_ESCAPE)
673 go_menu(MENU_UNITS); 660 go_menu(MENU_UNITS);
674 if (key == KEY_DOWN) 661 if (key == KEY_DOWN)
675 go_menu(MENU_MODE_OFF); 662 go_menu(MENU_MODE_OFF);
676 if (key == KEY_UP) 663 if (key == KEY_UP)
677 go_menu(MENU_MODE_BEER); 664 go_menu(MENU_MODE_BEER);
678 if (key == KEY_ENTER) { 665 if (key == KEY_ENTER) {
679 if (current_unit->mode == UNITMODE_PROFILE) { 666 if (current_unit->mode == UNITMODE_PROFILE) {
680 switch (current_unit->prof_state) { 667 switch (current_unit->prof_state) {
681 case PROFILE_OFF: if (current_unit->profile) 668 case PROFILE_OFF: go_menu(MENU_PROFILE_START);
682 go_menu(MENU_PROFILE_START);
683 else
684 go_menu(MENU_PROFILE_SELECT);
685 break; 669 break;
686 case PROFILE_PAUSE: go_menu(MENU_PROFILE_RESUME); 670 case PROFILE_PAUSE: go_menu(MENU_PROFILE_RESUME);
687 break; 671 break;
688 case PROFILE_RUN: go_menu(MENU_PROFILE_PAUSE); 672 case PROFILE_RUN: go_menu(MENU_PROFILE_PAUSE);
689 break; 673 break;
695 go_menu(MENU_MODE_PROFILE); 679 go_menu(MENU_MODE_PROFILE);
696 } 680 }
697 } 681 }
698 break; 682 break;
699 683
700 case MENU_PROFILE_SELECT:
701 if (key == KEY_ESCAPE)
702 go_menu(MENU_MODE_PROFILE);
703 if (key == KEY_DOWN) {
704 if (current_profile->next) {
705 current_profile = current_profile->next;
706 go_menu(MENU_PROFILE_SELECT);
707 } else {
708 go_menu(MENU_PROFILE_START);
709 }
710 }
711 if (key == KEY_UP) {
712 for (profile = Config.profiles; profile; profile = profile->next) {
713 if (profile->next && profile->next == current_profile) {
714 current_profile = profile;
715 go_menu(MENU_PROFILE_SELECT);
716 break;
717 }
718 }
719 go_menu(MENU_PROFILE_START);
720 }
721 if (key == KEY_ENTER) {
722 current_unit->profile = current_profile->uuid;
723 syslog(LOG_NOTICE, "Profile %s selected from panel", current_profile->name);
724 go_menu(MENU_PROFILE_START);
725 }
726 break;
727
728 case MENU_PROFILE_START: 684 case MENU_PROFILE_START:
729 if (key == KEY_ESCAPE) 685 if (key == KEY_ESCAPE)
730 go_menu(MENU_MODE_PROFILE); 686 go_menu(MENU_MODE_PROFILE);
731 if ((key == KEY_DOWN) || (key == KEY_UP))
732 go_menu(MENU_PROFILE_SELECT);
733 if (key == KEY_ENTER) { 687 if (key == KEY_ENTER) {
734 current_unit->prof_state = PROFILE_RUN; 688 current_unit->prof_state = PROFILE_RUN;
735 current_unit->prof_started = time(NULL); 689 current_unit->prof_started = time(NULL);
736 current_unit->prof_paused = current_unit->prof_primary_done = 0; 690 current_unit->prof_paused = current_unit->prof_primary_done = 0;
737 current_unit->prof_peak_abs = current_unit->prof_peak_rel = 0.0; 691 current_unit->prof_peak_abs = current_unit->prof_peak_rel = 0.0;
979 { 933 {
980 char buf[1024], *filename, target_lo[40], target_hi[40], heater[40], cooler[40], fan[40], door[40]; 934 char buf[1024], *filename, target_lo[40], target_hi[40], heater[40], cooler[40], fan[40], door[40];
981 char use_heater[40], use_cooler[40], use_fan[40], room_temp[40]; 935 char use_heater[40], use_cooler[40], use_fan[40], room_temp[40];
982 time_t now, last = (time_t)0, ndata = (time_t)0;; 936 time_t now, last = (time_t)0, ndata = (time_t)0;;
983 units_list *unit; 937 units_list *unit;
984 profiles_list *profile;
985 prof_step *step; 938 prof_step *step;
986 int row, rc, run = 1, seconds = 0, minutes = 0, temp, deviation; 939 int row, rc, run = 1, seconds = 0, minutes = 0, temp, deviation;
987 int run_seconds, run_minutes, run_hours, tot_minutes, key; 940 int run_seconds, run_minutes, run_hours, tot_minutes, key;
988 struct tm *tm; 941 struct tm *tm;
989 #ifndef HAVE_WIRINGPI_H 942 #ifndef HAVE_WIRINGPI_H
1076 */ 1029 */
1077 unit->mqtt_flag = unit->alarm_flag = unit->alarm_last = 0; 1030 unit->mqtt_flag = unit->alarm_flag = unit->alarm_last = 0;
1078 unit->heater_state = unit->cooler_state = unit->fan_state = unit->door_state = unit->light_state = 0; 1031 unit->heater_state = unit->cooler_state = unit->fan_state = unit->door_state = unit->light_state = 0;
1079 unit->heater_wait = unit->cooler_wait = unit->fan_wait = unit->light_wait = 0; 1032 unit->heater_wait = unit->cooler_wait = unit->fan_wait = unit->light_wait = 0;
1080 if (unit->mode == UNITMODE_PROFILE) { 1033 if (unit->mode == UNITMODE_PROFILE) {
1081 if (!unit->profile) 1034 if (!unit->profile_uuid)
1082 syslog(LOG_NOTICE, "Starting unit `%s' in profile mode, no profile defined.", unit->alias); 1035 syslog(LOG_NOTICE, "Starting unit `%s' in profile mode, no profile defined.", unit->alias);
1083 else { 1036 else {
1084 syslog(LOG_NOTICE, "Starting unit `%s' in profile state %s.", unit->alias, PROFSTATE[unit->prof_state]); 1037 syslog(LOG_NOTICE, "Starting unit `%s' in profile state %s.", unit->alias, PROFSTATE[unit->prof_state]);
1085 } 1038 }
1086 } else if (unit->mode == UNITMODE_BEER) { 1039 } else if (unit->mode == UNITMODE_BEER) {
1388 } 1341 }
1389 1342
1390 /* 1343 /*
1391 * Handle profile 1344 * Handle profile
1392 */ 1345 */
1393 if ((unit->mode == UNITMODE_PROFILE) && (unit->profile)) { 1346 if ((unit->mode == UNITMODE_PROFILE) && (unit->profile_uuid)) {
1394 /* 1347 /*
1395 * unit->profile - uuid of the selected profile.
1396 * unit->prof_started - start time or 0 if not yet running. 1348 * unit->prof_started - start time or 0 if not yet running.
1397 * unit->prof_state - PROFILE_OFF|PROFILE_PAUSE|PROFILE_RUN|PROFILE_DONE 1349 * unit->prof_state - PROFILE_OFF|PROFILE_PAUSE|PROFILE_RUN|PROFILE_DONE
1398 * unit->prof_target - Calculated target temperature. 1350 * unit->prof_target - Calculated target temperature.
1399 * unit->prof_paused - Internal pause counter. 1351 * unit->prof_paused - Internal pause counter.
1400 * unit->prof_peak_abs - Peak temperature of the beer. 1352 * unit->prof_peak_abs - Peak temperature of the beer.
1401 * unit->prof_peak_rel - Peak temperature between beer and fridge. 1353 * unit->prof_peak_rel - Peak temperature between beer and fridge.
1402 * unit->prof_primary_done - time when primary fermentation was over the peak. 1354 * unit->prof_primary_done - time when primary fermentation was over the peak.
1403 */ 1355 */
1404 for (profile = Config.profiles; profile; profile = profile->next) { 1356
1405 if (strcmp(unit->profile, profile->uuid) == 0) { 1357 /*
1406 1358 * Safe defaults
1407 /* 1359 */
1408 * Safe defaults 1360 unit->prof_target_lo = unit->profile_inittemp_lo;
1409 */ 1361 unit->prof_target_hi = unit->profile_inittemp_hi;
1410 unit->prof_target_lo = profile->inittemp_lo; 1362 unit->prof_fridge_mode = 0;
1411 unit->prof_target_hi = profile->inittemp_hi; 1363
1412 unit->prof_fridge_mode = 0; 1364 switch (unit->prof_state) {
1413 1365 case PROFILE_OFF:
1414 switch (unit->prof_state) { 1366 unit->prof_percent = 0;
1415 case PROFILE_OFF: 1367 break;
1416 unit->prof_percent = 0; 1368 case PROFILE_PAUSE:
1417 break; 1369 /*
1418 case PROFILE_PAUSE: 1370 * Keep current temperature, measure pause time. For
1371 * temperature fall thru.
1372 */
1373 unit->prof_paused++;
1374 case PROFILE_RUN:
1375 /*
1376 * Calculate current profile step and desired temperature.
1377 * When all steps are done, set state to PROFILE_DONE.
1378 */
1379 previous_target_lo = unit->profile_inittemp_lo;
1380 previous_target_hi = unit->profile_inittemp_hi;
1381 previous_fridge_mode = unit->profile_fridge_mode;
1382 time_until_now = current_step = 0;
1383 run_seconds = (int)(now - unit->prof_started - unit->prof_paused);
1384 run_minutes = run_seconds / 60;
1385 run_hours = run_minutes / 60;
1386 if (debug)
1387 fprintf(stdout, "run_HMS=%d,%d,%d ", run_hours, run_minutes, run_seconds);
1388
1389 /*
1390 * Primary fermentation tests
1391 */
1392 if ((unit->beer_temperature / 1000.0) > unit->prof_peak_abs)
1393 unit->prof_peak_abs = unit->beer_temperature / 1000.0;
1394 if (((unit->beer_temperature - unit->air_temperature) / 1000.0) > unit->prof_peak_rel)
1395 unit->prof_peak_rel = (unit->beer_temperature - unit->air_temperature) / 1000.0;
1396 if (unit->prof_primary_done == 0) {
1397 if (unit->cooler_address) {
1419 /* 1398 /*
1420 * Keep current temperature, measure pause time. For 1399 * There is a cooler. If the difference between the beer and air temperature
1421 * temperature fall thru. 1400 * drops we assume the primary fermentation is done.
1422 */ 1401 */
1423 unit->prof_paused++; 1402 if (((unit->beer_temperature - unit->air_temperature) / 1000.0) < (unit->prof_peak_rel - 0.5)) {
1424 case PROFILE_RUN: 1403 unit->prof_primary_done = time(NULL);
1404 syslog(LOG_NOTICE, "Profile `%s' primary fermentation is ready (cooler mode)", unit->profile_name);
1405 }
1406 } else {
1407 /*
1408 * This method works if the unit has no cooling or if the profile allowed the
1409 * beer temperature to rise freely.
1410 */
1411 if ((unit->beer_temperature / 1000.0) < (unit->prof_peak_abs - 0.5)) {
1412 unit->prof_primary_done = time(NULL);
1413 syslog(LOG_NOTICE, "Profile `%s' primary fermentation is ready (free rise mode)", unit->profile_name);
1414 }
1415 }
1416 }
1417
1418 /*
1419 * See how long this profile will take
1420 */
1421 tot_minutes = 0;
1422 for (step = unit->profile_steps; step; step = step->next) {
1423 tot_minutes += ((step->steptime + step->resttime) * 60);
1424 }
1425 if ((tot_minutes == 0) && unit->profile_totalsteps) {
1426 syslog(LOG_NOTICE, "Profile `%s' steps disappeared", unit->profile_name);
1427 unit->prof_state = PROFILE_OFF;
1428 break;
1429 }
1430
1431 valid_step = FALSE;
1432 for (step = unit->profile_steps; step; step = step->next) {
1433 /*
1434 * step->steptime
1435 * step->resttime
1436 * step->target
1437 */
1438 current_step++;
1439 if ((run_hours >= time_until_now) && (run_hours < (time_until_now + step->steptime + step->resttime))) {
1425 /* 1440 /*
1426 * Calculate current profile step and desired temperature. 1441 * This is our current step
1427 * When all steps are done, set state to PROFILE_DONE.
1428 */ 1442 */
1429 previous_target_lo = profile->inittemp_lo; 1443 valid_step = TRUE;
1430 previous_target_hi = profile->inittemp_hi; 1444 // if (debug)
1431 previous_fridge_mode = profile->fridge_mode; 1445 // fprintf(stdout, "step=%d step_pos=%d step=%d/%d target=%.1f..%.1f ",
1432 time_until_now = current_step = 0; 1446 // current_step, run_hours - time_until_now,
1433 run_seconds = (int)(now - unit->prof_started - unit->prof_paused); 1447 // step->steptime, step->resttime, step->target_lo, step->target_hi);
1434 run_minutes = run_seconds / 60; 1448 if ((run_hours - time_until_now) < step->steptime) {
1435 run_hours = run_minutes / 60; 1449 unit->prof_target_lo = previous_target_lo + (((run_minutes - (time_until_now * 60.0)) / (step->steptime * 60.0)) * (step->target_lo - previous_target_lo));
1436 if (debug) 1450 unit->prof_target_hi = previous_target_hi + (((run_minutes - (time_until_now * 60.0)) / (step->steptime * 60.0)) * (step->target_hi - previous_target_hi));
1437 fprintf(stdout, "run_HMS=%d,%d,%d ", run_hours, run_minutes, run_seconds); 1451 if (step->fridge_mode > previous_fridge_mode) {
1438 1452 unit->prof_fridge_mode = (((run_minutes - (time_until_now * 60)) * 100) / (step->steptime * 60));
1439 /* 1453 } else if (step->fridge_mode < previous_fridge_mode) {
1440 * Primary fermentation tests 1454 unit->prof_fridge_mode = 100 - (((run_minutes - (time_until_now * 60)) * 100) / (step->steptime * 60));
1441 */
1442 if ((unit->beer_temperature / 1000.0) > unit->prof_peak_abs)
1443 unit->prof_peak_abs = unit->beer_temperature / 1000.0;
1444 if (((unit->beer_temperature - unit->air_temperature) / 1000.0) > unit->prof_peak_rel)
1445 unit->prof_peak_rel = (unit->beer_temperature - unit->air_temperature) / 1000.0;
1446 if (unit->prof_primary_done == 0) {
1447 if (unit->cooler_address) {
1448 /*
1449 * There is a cooler. If the difference between the beer and air temperature
1450 * drops we assume the primary fermentation is done.
1451 */
1452 if (((unit->beer_temperature - unit->air_temperature) / 1000.0) < (unit->prof_peak_rel - 0.5)) {
1453 unit->prof_primary_done = time(NULL);
1454 syslog(LOG_NOTICE, "Profile `%s' primary fermentation is ready (cooler mode)", profile->name);
1455 }
1456 } else { 1455 } else {
1457 /* 1456 unit->prof_fridge_mode = step->fridge_mode;
1458 * This method works if the unit has no cooling or if the profile allowed the
1459 * beer temperature to rise freely.
1460 */
1461 if ((unit->beer_temperature / 1000.0) < (unit->prof_peak_abs - 0.5)) {
1462 unit->prof_primary_done = time(NULL);
1463 syslog(LOG_NOTICE, "Profile `%s' primary fermentation is ready (free rise mode)", profile->name);
1464 }
1465 } 1457 }
1466 } 1458 if (debug)
1467 1459 fprintf(stdout, "prof_fridge_mode=%d run_minutes=%d steptime=%d time_until_now=%d\n",
1468 /* 1460 unit->prof_fridge_mode, run_minutes, step->steptime, time_until_now);
1469 * See how long this profile will take 1461 // if (debug)
1470 */ 1462 // fprintf(stdout, "tempshift=%.1f..%.1f minutes=%d duration=%d temp_move=%.3f..%.3f ",
1471 tot_minutes = 0; 1463 // step->target_lo - previous_target_lo,
1472 for (step = profile->steps; step; step = step->next) { 1464 // step->target_hi - previous_target_hi,
1473 tot_minutes += ((step->steptime + step->resttime) * 60); 1465 // run_minutes - (time_until_now * 60),
1474 } 1466 // step->steptime * 60, unit->prof_target_lo, unit->prof_target_hi);
1475
1476 valid_step = FALSE;
1477 for (step = profile->steps; step; step = step->next) {
1478 /*
1479 * step->steptime
1480 * step->resttime
1481 * step->target
1482 */
1483 current_step++;
1484 if ((run_hours >= time_until_now) && (run_hours < (time_until_now + step->steptime + step->resttime))) {
1485 /*
1486 * This is our current step
1487 */
1488 valid_step = TRUE;
1489 if (debug)
1490 fprintf(stdout, "step=%d step_pos=%d step=%d/%d target=%.1f..%.1f ",
1491 current_step, run_hours - time_until_now,
1492 step->steptime, step->resttime, step->target_lo, step->target_hi);
1493 if ((run_hours - time_until_now) < step->steptime) {
1494 unit->prof_target_lo = previous_target_lo + (((run_minutes - (time_until_now * 60.0)) / (step->steptime * 60.0)) * (step->target_lo - previous_target_lo));
1495 unit->prof_target_hi = previous_target_hi + (((run_minutes - (time_until_now * 60.0)) / (step->steptime * 60.0)) * (step->target_hi - previous_target_hi));
1496 if (step->fridge_mode > previous_fridge_mode) {
1497 unit->prof_fridge_mode = (((run_minutes - (time_until_now * 60)) * 100) / (step->steptime * 60));
1498 } else if (step->fridge_mode < previous_fridge_mode) {
1499 unit->prof_fridge_mode = 100 - (((run_minutes - (time_until_now * 60)) * 100) / (step->steptime * 60));
1500 } else {
1501 unit->prof_fridge_mode = step->fridge_mode;
1502 }
1503 if (debug)
1504 fprintf(stdout, "tempshift=%.1f..%.1f minutes=%d duration=%d temp_move=%.3f..%.3f ",
1505 step->target_lo - previous_target_lo,
1506 step->target_hi - previous_target_hi,
1507 run_minutes - (time_until_now * 60),
1508 step->steptime * 60, unit->prof_target_lo, unit->prof_target_hi);
1509 } else {
1510 unit->prof_target_lo = step->target_lo;
1511 unit->prof_target_hi = step->target_hi;
1512 unit->prof_fridge_mode = step->fridge_mode;
1513 if (debug)
1514 fprintf(stdout, "resting target=%.1f..%.1f ", step->target_lo, step->target_hi);
1515 }
1516 break;
1517 }
1518 time_until_now += step->steptime + step->resttime;
1519 previous_target_lo = step->target_lo;
1520 previous_target_hi = step->target_hi;
1521 previous_fridge_mode = step->fridge_mode;
1522 }
1523 if (debug)
1524 fprintf(stdout, " %s %02d:%02d\n", valid_step ? "TRUE":"FALSE", minutes, seconds);
1525
1526 if (valid_step == TRUE) {
1527 unit->prof_percent = (100 * run_minutes) / tot_minutes;
1528 if (((minutes == 10) || (minutes == 40)) && (seconds == 1)) {
1529 syslog(LOG_NOTICE, "Profile `%s' running %dd %02d:%02d in step %d, %d%% done, target %s %.3f..%.3f degrees",
1530 profile->name, run_hours / 24, run_hours % 24, run_minutes % 60, current_step,
1531 unit->prof_percent, unit->prof_fridge_mode ? (char *)"air":(char *)"beer",
1532 unit->prof_target_lo, unit->prof_target_hi);
1533 unit->mqtt_flag |= MQTT_FLAG_DATA;
1534 }
1535 } else { 1467 } else {
1536 /* 1468 unit->prof_target_lo = step->target_lo;
1537 * No more steps to do 1469 unit->prof_target_hi = step->target_hi;
1538 */ 1470 unit->prof_fridge_mode = step->fridge_mode;
1539 unit->prof_state = PROFILE_DONE; 1471 // if (debug)
1540 unit->prof_percent = 100; 1472 // fprintf(stdout, "resting target=%.1f..%.1f ", step->target_lo, step->target_hi);
1541 syslog(LOG_NOTICE, "Profile `%s' is done", profile->name);
1542 unit->mqtt_flag |= MQTT_FLAG_DATA;
1543 } 1473 }
1544 break; 1474 break;
1545 1475 }
1546 case PROFILE_DONE: 1476 time_until_now += step->steptime + step->resttime;
1547 /* 1477 previous_target_lo = step->target_lo;
1548 * Keep this state, set target temperature to the last step. 1478 previous_target_hi = step->target_hi;
1549 */ 1479 previous_fridge_mode = step->fridge_mode;
1550 previous_target_lo = profile->inittemp_lo; 1480 }
1551 previous_target_hi = profile->inittemp_hi; 1481 // if (debug)
1552 previous_fridge_mode = profile->fridge_mode; 1482 // fprintf(stdout, " %s %02d:%02d\n", valid_step ? "TRUE":"FALSE", minutes, seconds);
1553 for (step = profile->steps; step; step = step->next) { 1483
1554 if ((step->steptime + step->resttime) == 0) 1484 if (valid_step == TRUE) {
1555 break; 1485 unit->prof_percent = (100 * run_minutes) / tot_minutes;
1556 previous_target_lo = step->target_lo; 1486 if (((minutes == 10) || (minutes == 40)) && (seconds == 1)) {
1557 previous_target_hi = step->target_hi; 1487 syslog(LOG_NOTICE, "Profile `%s' running %dd %02d:%02d in step %d, %d%% done, target %s %.3f..%.3f degrees",
1558 previous_fridge_mode = step->fridge_mode; 1488 unit->profile_name, run_hours / 24, run_hours % 24, run_minutes % 60, current_step,
1559 1489 unit->prof_percent, unit->prof_fridge_mode ? (char *)"air":(char *)"beer",
1560 } 1490 unit->prof_target_lo, unit->prof_target_hi);
1561 unit->prof_target_lo = previous_target_lo; 1491 unit->mqtt_flag |= MQTT_FLAG_DATA;
1562 unit->prof_target_hi = previous_target_hi; 1492 }
1563 unit->prof_fridge_mode = previous_fridge_mode; 1493 } else {
1564 unit->prof_percent = 100; 1494 /*
1495 * No more steps to do
1496 */
1497 unit->prof_state = PROFILE_DONE;
1498 unit->prof_percent = 100;
1499 syslog(LOG_NOTICE, "Profile `%s' is done", unit->profile_name);
1500 unit->mqtt_flag |= MQTT_FLAG_DATA;
1501 }
1502 break;
1503
1504 case PROFILE_DONE:
1505 /*
1506 * Keep this state, set target temperature to the last step.
1507 */
1508 previous_target_lo = unit->profile_inittemp_lo;
1509 previous_target_hi = unit->profile_inittemp_hi;
1510 previous_fridge_mode = unit->profile_fridge_mode;
1511 for (step = unit->profile_steps; step; step = step->next) {
1512 if ((step->steptime + step->resttime) == 0)
1565 break; 1513 break;
1566 } /* switch */ 1514 previous_target_lo = step->target_lo;
1567 } 1515 previous_target_hi = step->target_hi;
1568 } 1516 previous_fridge_mode = step->fridge_mode;
1517 }
1518 unit->prof_target_lo = previous_target_lo;
1519 unit->prof_target_hi = previous_target_hi;
1520 unit->prof_fridge_mode = previous_fridge_mode;
1521 unit->prof_percent = 100;
1522 break;
1523 } /* switch */
1569 } else { 1524 } else {
1570 /* 1525 /*
1571 * Set some sane values 1526 * Set some sane values
1572 */ 1527 */
1573 unit->prof_target_lo = 19.8; 1528 unit->prof_target_lo = 19.8;
1626 /* 1581 /*
1627 * Set both PID's to their input values. 1582 * Set both PID's to their input values.
1628 */ 1583 */
1629 unit->PID_cool->Mode = unit->PID_heat->Mode = PID_MODE_NONE; 1584 unit->PID_cool->Mode = unit->PID_heat->Mode = PID_MODE_NONE;
1630 if (unit->mode == UNITMODE_FRIDGE) { 1585 if (unit->mode == UNITMODE_FRIDGE) {
1631 unit->PID_cool->SetP = unit->fridge_set; // + unit->PID_cool->idleRange; 1586 unit->PID_cool->SetP = unit->fridge_set;
1632 unit->PID_heat->SetP = unit->fridge_set; // - unit->PID_heat->idleRange; 1587 unit->PID_heat->SetP = unit->fridge_set;
1633 unit->PID_cool->Input = unit->PID_heat->Input = unit->air_temperature / 1000.0; 1588 unit->PID_cool->Input = unit->PID_heat->Input = unit->air_temperature / 1000.0;
1634 unit->PID_cool->Mode = unit->PID_heat->Mode = PID_MODE_BOO; 1589 unit->PID_cool->Mode = unit->PID_heat->Mode = PID_MODE_BOO;
1635 } else if (unit->mode == UNITMODE_BEER) { 1590 } else if (unit->mode == UNITMODE_BEER) {
1636 unit->PID_cool->SetP = unit->beer_set; 1591 unit->PID_cool->SetP = unit->beer_set;
1637 unit->PID_heat->SetP = unit->beer_set; 1592 unit->PID_heat->SetP = unit->beer_set;
1792 device_out(unit->cooler_address, unit->cooler_state); 1747 device_out(unit->cooler_address, unit->cooler_state);
1793 } else { 1748 } else {
1794 device_out(unit->cooler_address, 0); 1749 device_out(unit->cooler_address, 0);
1795 } 1750 }
1796 } 1751 }
1797 // if (debug)
1798 // fprintf(stdout, "Final: PIDheat=%.2f PWRheat=%d PIDcool=%.2f PWRcool=%d\n",
1799 // unit->PID_heat->OutP, unit->heater_state, unit->PID_cool->OutP, unit->cooler_state);
1800 1752
1801 /* 1753 /*
1802 * If there is a fan, and the unit door is closed, and the unit should be doing 1754 * If there is a fan, and the unit door is closed, and the unit should be doing
1803 * something, then turn on the global fan. 1755 * something, then turn on the global fan.
1804 * But if there is a chiller, do not turn it on if cooling. 1756 * But if there is a chiller, do not turn it on if cooling.

mercurial