123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536 |
- #ifdef FIRMWARE_VARIANT_HEATCONTROL
- void heatcontrol_switchPump(bool _state) {
- if (heatcontrol_out_pump && !_state) {
- // pump is running and is now switched off
- // -> set heatcontrol_pump_lastRunMillis
- heatcontrol_pump_lastRunMillis = millis();
- heatcontrol_pump_inForceRunMode = false;
- }
- heatcontrol_out_pump = _state;
- pcf8574.digitalWrite(P6, !_state); // output active low!
- char _statName[5];
- if (_state) sprintf(_statName, PGMStr_ON);
- else sprintf(_statName, PGMStr_OFF);
- sprintf_P(logBuf, PGMStr_heatc_pumpSwitchedTo, PGMStr_heatc_logName, _statName);
- sendLog(logBuf, LOGLEVEL_INFO);
- heatcontrol_publish_out_pump();
- }
- void heatcontrol_switchHeating(bool _state) {
- heatcontrol_out_heat = _state;
- pcf8574.digitalWrite(P7, !_state); // output active low!
- char _statName[5];
- if (_state) sprintf(_statName, PGMStr_ON);
- else sprintf(_statName, PGMStr_OFF);
- sprintf_P(logBuf, PGMStr_heatc_heatingSwitchedTo, PGMStr_heatc_logName, _statName);
- sendLog(logBuf, LOGLEVEL_INFO);
- heatcontrol_publish_out_heat();
- }
- // Pump Backlash
- void heatcontrol_pumpBacklash_begin() {
- heatcontrol_pumpBacklash_startMillis = millis();
- heatcontrol_state_pumpBacklash_active = true;
- sprintf_P(logBuf, PGMStr_heatc_pumpBacklashStarted, PGMStr_heatc_logName);
- sendLog(logBuf, LOGLEVEL_INFO);
- heatcontrol_publish_pumpBacklash();
- }
- void heatcontrol_pumpBacklash_cancel() {
- heatcontrol_pumpBacklash_startMillis = 0;
- heatcontrol_state_pumpBacklash_active = false;
- heatcontrol_publish_pumpBacklash();
- sprintf_P(logBuf, PGMStr_heatc_pumpBacklashCanceled, PGMStr_heatc_logName);
- sendLog(logBuf, LOGLEVEL_INFO);
- }
- void heatcontrol_pumpBacklash_handleTimeout() {
- // switch off pump after backlash time has exceeded
- if (heatcontrol_pumpBacklash_startMillis > 0) {
- unsigned long _pumpBacklashMillis;
-
- if (heatcontrol_pump_inForceRunMode) {
- _pumpBacklashMillis = confHeatc.pumpTime_forceRun * 60000;
- }
- else {
- _pumpBacklashMillis = confHeatc.pumpBacklash * 60000;
- }
- if ((millis() - heatcontrol_pumpBacklash_startMillis) > _pumpBacklashMillis) {
- sprintf_P(logBuf, PGMStr_heatc_pumpBacklashFinished, PGMStr_heatc_logName);
- sendLog(logBuf, LOGLEVEL_INFO);
- heatcontrol_switchPump(false); // pump OFF
-
- heatcontrol_pumpBacklash_startMillis = 0;
- heatcontrol_state_pumpBacklash_active = false;
- heatcontrol_publish_pumpBacklash();
- display_updateImmediately = true;
- }
- }
- }
- uint8_t heatcontrol_pumpBacklash_getRemainingMins() {
- if(heatcontrol_pumpBacklash_startMillis > 0) {
- unsigned long _pumpBacklashMillis = confHeatc.pumpBacklash * 60000;
- unsigned long _elapsedMillis = (millis() - heatcontrol_pumpBacklash_startMillis);
- unsigned long _remainingMinutes = (_pumpBacklashMillis - _elapsedMillis) / 60000;
- return _remainingMinutes + 1;
- }
- else return 0;
- }
- void heatcontrol_lockTime_begin() {
- if (heatcontrol_skipLocktimeOnce) {
- // if last turned on by test mode -> no lock time after that
- heatcontrol_skipLocktimeOnce = false;
- }
- else {
- uint8_t _lockTimeMinutes;
-
- pcf8574.digitalWrite(P1, LOW); // output active low!
- // get current lock time depending on outside temp
- int _tOut = (int)owTemp_out;
- if (_tOut <= -20) _lockTimeMinutes = confHeatc.heatLocktime[0];
- else if (_tOut <= -15) _lockTimeMinutes = confHeatc.heatLocktime[1];
- else if (_tOut <= -10) _lockTimeMinutes = confHeatc.heatLocktime[2];
- else if (_tOut <= -5) _lockTimeMinutes = confHeatc.heatLocktime[3];
- else if (_tOut <= 0) _lockTimeMinutes = confHeatc.heatLocktime[4];
- else if (_tOut <= 5) _lockTimeMinutes = confHeatc.heatLocktime[5];
- else if (_tOut <= 10) _lockTimeMinutes = confHeatc.heatLocktime[6];
- else if (_tOut <= 15) _lockTimeMinutes = confHeatc.heatLocktime[7];
- else if (_tOut <= 20) _lockTimeMinutes = confHeatc.heatLocktime[8];
- else if (_tOut > 20) _lockTimeMinutes = confHeatc.heatLocktime[8]; // also use value for <=20 for >20
- else _lockTimeMinutes = 0;
-
- #ifdef DEBUGMODE
- // i dont like to wait during development
- if (_lockTimeMinutes == 0) _lockTimeMinutes = 1;
- #endif
- heatcontrol_lockTime_startMillis = millis();
- heatcontrol_lockTime_totalMillis = _lockTimeMinutes * 60000;
- heatcontrol_lastState_lockActive = true;
- sprintf_P(logBuf, PGMStr_heatc_locktimeStart, PGMStr_heatc_logName, _lockTimeMinutes);
- sendLog(logBuf, LOGLEVEL_INFO);
- heatcontrol_publish_lockTime();
- heatcontrol_publish_lockActive();
- display_updateImmediately = true;
- }
- }
- void heatcontrol_lockTime_handleTimeout() {
- // handle lock time
- if (heatcontrol_lockTime_startMillis > 0) {
- if ((millis() - heatcontrol_lockTime_startMillis) > heatcontrol_lockTime_totalMillis) {
- // locktime is over
- heatcontrol_lockTime_startMillis = 0;
- heatcontrol_lockTime_totalMillis = 0;
- heatcontrol_lock_release();
- sprintf_P(logBuf, PGMStr_heatc_locktimeStop, PGMStr_heatc_logName);
- sendLog(logBuf, LOGLEVEL_INFO);
- heatcontrol_publish_lockTime();
- heatcontrol_publish_lockActive();
-
- display_updateImmediately = true;
- }
- }
- else {
- heatcontrol_lock_release();
- }
- }
- uint8_t heatcontrol_lockTime_getRemainingMins() {
- if(heatcontrol_lockTime_startMillis > 0) {
- unsigned long _elapsedMillis = (millis() - heatcontrol_lockTime_startMillis);
- unsigned long _remainingMinutes = (heatcontrol_lockTime_totalMillis - _elapsedMillis) / 60000;
- return _remainingMinutes + 1;
- }
- else return 0;
- }
- void heatcontrol_lock_release() {
- bool _currStat = heatcontrol_getLockActive();
- if(!_currStat) {
- pcf8574.digitalWrite(P1, HIGH); // output active low!
- if (_currStat != heatcontrol_lastState_lockActive) {
- heatcontrol_publish_lockActive();
- heatcontrol_lastState_lockActive = _currStat;
- }
- }
- }
- bool heatcontrol_getLockActive() {
- if (heatcontrol_lockTime_startMillis == 0 && !heatcontrol_lockTemp_active()) return false;
- else return true;
- }
- bool heatcontrol_lockTemp_active() {
- int _tFeed = (int)owTemp_feed;
- if (!confHeatc.useHeatCurve) return false;
- else if (_tFeed <= (heatcontrol_currentHeatCurveValue - confHeatc.hystereseOn)) {
- return false;
- }
- else {
- pcf8574.digitalWrite(P1, LOW); // output active low!
- // achtung published zu oft
- //////if (!heatcontrol_lastState_lockActive) {
- ////// heatcontrol_publish_lockActive();
- ////// heatcontrol_lastState_lockActive = true;
- //////}
- return true;
- }
- }
- void heatcontrol_mainFunction() {
- // stop testmode after timeout
- if (heatcontrol_testmode_startMillis > 0) {
- unsigned long _testmodeMillis = HEATCONTROL_TESTMODE_MINUTES * 60000;
- if ((millis() - heatcontrol_testmode_startMillis) > _testmodeMillis) {
- heatcontrol_testMode_off();
- //heatcontrol_testmode_startMillis = 0; // is already done in heatcontrol_testMode_off()
- }
- }
- // really start testmode if it was set
- // MUST be separate if and not included above, or it will instantly switch back on after timeout!!
- if (heatcontrol_testmode_startMillis > 0) {
- if ((millis() - heatcontrol_testmode_startMillis) > 2800 && !heatcontrol_state_testmode_active) {
- heatcontrol_testMode_reallyStart();
- //heatcontrol_testmode_startMillis = 0; // is already done in heatcontrol_testMode_reallyStart()
- }
- }
- heatcontrol_lockTime_handleTimeout();
- int _tOut = (int)owTemp_out;
- int _tFeed = (int)owTemp_feed;
- //int _tReturn = (int)owTemp_return;
- // heat curve - get current value if enabled
- if (confHeatc.useHeatCurve) {
- if (_tOut <= -20) heatcontrol_currentHeatCurveValue = confHeatc.heatCurve[0];
- else if (_tOut <= -15) heatcontrol_currentHeatCurveValue = confHeatc.heatCurve[1];
- else if (_tOut <= -10) heatcontrol_currentHeatCurveValue = confHeatc.heatCurve[2];
- else if (_tOut <= -5) heatcontrol_currentHeatCurveValue = confHeatc.heatCurve[3];
- else if (_tOut <= 0) heatcontrol_currentHeatCurveValue = confHeatc.heatCurve[4];
- else if (_tOut <= 5) heatcontrol_currentHeatCurveValue = confHeatc.heatCurve[5];
- else if (_tOut <= 10) heatcontrol_currentHeatCurveValue = confHeatc.heatCurve[6];
- else if (_tOut <= 15) heatcontrol_currentHeatCurveValue = confHeatc.heatCurve[7];
- else if (_tOut <= 20) heatcontrol_currentHeatCurveValue = confHeatc.heatCurve[8];
- else if (_tOut > 20) heatcontrol_currentHeatCurveValue = confHeatc.heatCurve[8]; // also use value for <=20 for >20
- else heatcontrol_currentHeatCurveValue = 0;
- }
- else heatcontrol_currentHeatCurveValue = 0;
- #ifdef DEBUGMODE
- // during development i prefer working in a heated room
- // so i need this to be able to do some tests ;-)
- if (confHeatc.useHeatCurve && heatcontrol_currentHeatCurveValue == 0) heatcontrol_currentHeatCurveValue = 35;
- #endif
-
- // switch heating and pump if requested
- // only if currently heating is inactive
- if (!heatcontrol_out_heat) {
- // check pre conditions
- bool _switchOnPreCondition = false;
- // no locktime is currently active (and usage of lock time is not disabled)
- if (heatcontrol_lockTime_startMillis == 0) _switchOnPreCondition = true;
- // overrule precondition to false if outside temp is above limit
- if ( _tOut >= confHeatc.disableAboveTOut) _switchOnPreCondition = false;
-
- // overrule precondition if testmode is requested
- if (heatcontrol_state_testmode_active) _switchOnPreCondition = true;
- if (_switchOnPreCondition) {
- // check if any switch-on condition is met
- bool _switchOnCondition = false;
- // test mode has been activated
- if (heatcontrol_state_testmode_active) {
- sprintf_P(logBuf, PGMStr_heatc_switchOnCondition, PGMStr_heatc_logName, PGMStr_heatc_switchOnCondition_heatTestmode);
- sendLog(logBuf);
- _switchOnCondition = true;
- }
- // heat request, heat curve enabled AND temp_feed has fallen below treshold
- else if (heatcontrol_in_heat_request && confHeatc.useHeatCurve && !heatcontrol_lockTemp_active() ) {
- sprintf_P(logBuf, PGMStr_heatc_switchOnCondition, PGMStr_heatc_logName, PGMStr_heatc_switchOnCondition_heatRequestHeatcurve);
- sendLog(logBuf);
- _switchOnCondition = true;
- }
- // heat request, heat curve disabled
- else if (heatcontrol_in_heat_request && !confHeatc.useHeatCurve) {
- sprintf_P(logBuf, PGMStr_heatc_switchOnCondition, PGMStr_heatc_logName, PGMStr_heatc_switchOnCondition_heatRequest);
- sendLog(logBuf);
- _switchOnCondition = true;
- }
- // heat curve forced / heat request ignored
- // and current feed-temperature <= (currentHeatCurveValue - hystereseOn)
- else if ( confHeatc.useHeatCurve && confHeatc.forceHeatCurve && confHeatc.forceHeatCurveAlsoForSwitchOn && confHeatc.hystereseOn >= 3 && _tFeed <= (heatcontrol_currentHeatCurveValue - confHeatc.hystereseOn) ) {
- sprintf_P(logBuf, PGMStr_heatc_switchOnCondition, PGMStr_heatc_logName, PGMStr_heatc_switchOnCondition_heatCurveForced);
- sendLog(logBuf);
- _switchOnCondition = true;
- }
- if(_switchOnCondition) {
- if (!heatcontrol_out_pump && !heatcontrol_in_sw_disableControl_heating) heatcontrol_switchPump(true); // pump ON
- if (!heatcontrol_out_heat && !heatcontrol_in_sw_disableControl_pump) heatcontrol_switchHeating(true); // heating ON
- if (!heatcontrol_in_sw_disableControl_pump) heatcontrol_pumpBacklash_cancel(); // if pump is in backlash - avoid it going off during heating is running
- display_updateImmediately = true;
- }
- }
-
- }
- // heating is currently switched on
- else if ( heatcontrol_out_heat ) {
- // check if any switch-off condition is met
- bool _switchOffCondition = false;
- // heat request and/or testmode has stopped and
- // useHeatCurve and/or at least forceHeatCurve is disabled
- // note - if confHeatc.forceHeatCurve == true switching off is ONLY handled when heat curve target is reached!
- if ( (!confHeatc.useHeatCurve || (confHeatc.useHeatCurve && !confHeatc.forceHeatCurve) ) && !heatcontrol_in_heat_request && !heatcontrol_state_testmode_active) {
- sprintf_P(logBuf, PGMStr_heatc_switchOffCondition, PGMStr_heatc_logName, PGMStr_heatc_switchOffCondition_heatRequest);
- sendLog(logBuf);
- _switchOffCondition = true;
- }
-
- // test mode is NOT active,
- // heatcurve is enabled and
- // feed temperature exceeds heat curve value ( + confHeatc.hystereseOff)
- else if (!heatcontrol_state_testmode_active && confHeatc.useHeatCurve && _tFeed >= (heatcontrol_currentHeatCurveValue + confHeatc.hystereseOff) ) {
- sprintf_P(logBuf, PGMStr_heatc_switchOffCondition, PGMStr_heatc_logName, PGMStr_heatc_switchOffCondition_heatCurve);
- sendLog(logBuf);
- _switchOffCondition = true;
- }
- // feed temperature exceeds safety limit
- else if ((int)owTemp_feed >= confHeatc.tempFeedLimit) {
- sprintf_P(logBuf, PGMStr_heatc_switchOffCondition, PGMStr_heatc_logName, PGMStr_heatc_switchOffCondition_tempFeedLimit);
- sendLog(logBuf);
- _switchOffCondition = true;
- }
- if (_switchOffCondition) {
- // --> switch heating off
- // --> switch pump in backlash
- heatcontrol_switchHeating(false); // heating OFF
- heatcontrol_pumpBacklash_begin(); // pump - enable backlash
- heatcontrol_lockTime_begin();
- display_updateImmediately = true;
- }
- }
- else {
- // just for safety --> switch heating off in all other cases
- if(heatcontrol_out_heat) heatcontrol_switchHeating(false); // heating OFF
- }
- // pump off if in backlash mode after timeout
- if (heatcontrol_state_pumpBacklash_active) {
- heatcontrol_pumpBacklash_handleTimeout();
- }
- }
- // TEST MODE
- void heatcontrol_testMode_toggle() {
- if(!heatcontrol_state_testmode_started) {
- heatcontrol_testMode_on();
- }
- else {
- heatcontrol_testMode_off();
- }
- }
- void heatcontrol_testMode_on() {
- heatcontrol_state_testmode_started = true;
- heatcontrol_state_testmode_active = false; // will be set by heatcontrol_testMode_reallyStart()
- heatcontrol_testmode_startMillis = millis();
- // Status-LED TESTMODE -> ON
- heatcontrol_out_stat_testmode = LOW; // LOW = LED ON
- pcf8574.digitalWrite(P0, heatcontrol_out_stat_testmode);
- heatcontrol_publish_testMode();
- char _dispMsg[17];
- snprintf_P(_dispMsg, 17, PGMStr_heatc_display_testModeON);
- display_showRow2OverlayMessage((char*)_dispMsg);
- }
- void heatcontrol_testMode_off() {
- heatcontrol_state_testmode_started = false;
- heatcontrol_state_testmode_active = false;
- heatcontrol_testmode_startMillis = 0;
- heatcontrol_skipLocktimeOnce = true;
- // Status-LED TESTMODE -> OFF
- heatcontrol_out_stat_testmode = HIGH; // HIGH = LED OFF
- pcf8574.digitalWrite(P0, heatcontrol_out_stat_testmode);
- heatcontrol_publish_testMode();
- //heatcontrol_switchPump(false);
- //heatcontrol_switchHeating(false);
- char _dispMsg[17];
- snprintf_P(_dispMsg, 17, PGMStr_heatc_display_testModeOFF);
- display_showRow2OverlayMessage((char*)_dispMsg);
- sprintf_P(logBuf, PGMStr_heatc_testmodeStop, PGMStr_heatc_logName);
- sendLog(logBuf);
- }
- void heatcontrol_testMode_reallyStart() {
- heatcontrol_state_testmode_started = true;
- heatcontrol_state_testmode_active = true;
- heatcontrol_testmode_startMillis = millis();
- display_updateImmediately = true;
- sprintf_P(logBuf, PGMStr_heatc_testmodeStart, PGMStr_heatc_logName);
- sendLog(logBuf);
- }
- uint8_t heatcontrol_testMode_getRemainingMins() {
- if(heatcontrol_testmode_startMillis > 0) {
- unsigned long _testmodeMillis = HEATCONTROL_TESTMODE_MINUTES * 60000;
- unsigned long _elapsedMillis = (millis() - heatcontrol_testmode_startMillis);
- unsigned long _remainingMinutes = (_testmodeMillis - _elapsedMillis) / 60000;
- return _remainingMinutes + 1;
- }
- else return 0;
- }
- void heatcontrol_pump_forceRunAfterTimeout() {
- if (!heatcontrol_pump_inForceRunMode) {
- bool _runCondition = false;
- #ifdef DEBUGMODE // use minutes rather than hours for testing
- // pump has not run since system start and forceRunInterval is exceeded
- if (heatcontrol_pump_lastRunMillis == 0 && millis() >= (confHeatc.pump_forceRunInterval * 60000) ) {
- _runCondition = true;
- }
- // pump last run longer ago than forceRunInterval
- if (heatcontrol_pump_lastRunMillis > 0 && (millis() - heatcontrol_pump_lastRunMillis) >= (confHeatc.pump_forceRunInterval * 60000) ) {
- _runCondition = true;
- }
- #else // normal operation - interval is set in hours
- // pump has not run since system start and forceRunInterval is exceeded
- if (heatcontrol_pump_lastRunMillis == 0 && millis() >= (confHeatc.pump_forceRunInterval * 3600000) ) {
- _runCondition = true;
- }
- // pump last run longer ago than forceRunInterval
- if (heatcontrol_pump_lastRunMillis > 0 && (millis() - heatcontrol_pump_lastRunMillis) >= (confHeatc.pump_forceRunInterval * 3600000) ) {
- _runCondition = true;
- }
- #endif
- bool _runCondition_inTimeWindow = false;
- if (_runCondition) {
- sprintf_P(logBuf, PGMStr_heatc_pumpForceRun, PGMStr_heatc_logName);
- sendLog(logBuf);
- #ifdef ENABLE_FEATURE_NTP_TIME
- if (confTime.ntpEnable && confHeatc.pump_forceRunTimeBegin != 0 && confHeatc.pump_forceRunTimeBegin != 0)
- {
- updateTime();
- if (lt.tm_year > 70) { // check if time has been synced
- // check if we are in the configured time window
- if (lt.tm_hour >= confHeatc.pump_forceRunTimeBegin && lt.tm_hour < confHeatc.pump_forceRunTimeBegin) {
- _runCondition_inTimeWindow = true;
- }
- }
- else {
- // NTP time is not synced so always assume we are in the time window
- _runCondition_inTimeWindow = true;
- }
- }
- else {
- // NTP is disabled in so always assume we are in the time window
- _runCondition_inTimeWindow = true;
- }
- #else
- // NTP is not compiled in so always assume we are in the time window
- _runCondition_inTimeWindow = true;
- #endif
- if (_runCondition_inTimeWindow) {
- heatcontrol_pump_inForceRunMode = true;
- heatcontrol_switchPump(true);
- heatcontrol_pumpBacklash_begin();
- }
- }
- }
- }
- #endif // FIRMWARE_VARIANT_HEATCONTROL
|