#ifdef FIRMWARE_VARIANT_THERMOSTAT

void thermostat_setup() {
  pinMode(PIN_THERMOSTAT_OUTPUT, OUTPUT);
  digitalWrite(PIN_THERMOSTAT_OUTPUT, !THERMOSTAT_OUTPUT_ONSTATE);
}

void thermostat_updateCurrSetTemp() {
  // set target temp for heating mode
  if (thermostat_heatingMode > 0) { // heating on
    if (thermostat_preset == 0) { // normal/day preset
      thermostat_currSetTemp = thermostat_setTemp;
      thermostat_currActualSetTemp = thermostat_setTemp -  confTherm.setTempDecreaseVal;
    }
    else if (thermostat_preset == 1) { // night/reduction preset
      thermostat_currSetTemp = thermostat_setTempLow;
      thermostat_currActualSetTemp = thermostat_setTempLow - confTherm.setTempDecreaseVal;
    }
    else if (thermostat_preset == 2) { // night/reduction 2 preset
      thermostat_currSetTemp = thermostat_setTempLow2;
      thermostat_currActualSetTemp = thermostat_setTempLow2 - confTherm.setTempDecreaseVal;
    }
  }
  else { // if heatingMode == 0
    thermostat_currSetTemp = DEFAULT_SETTEMP_HEATOFF;
    thermostat_currActualSetTemp = thermostat_currSetTemp;
  }
}



void thermostat_mainFunction() {
  thermostat_updateCurrSetTemp();
  //char tmp_topic_out[50];
  if (thermostat_heatingMode > 0 && thermostat_turnHeatingOn) {
    thermostat_heatingOnTime = (millis() - thermostat_heatingLastOnMillis) / 1000;

    //char buf[101];
    //sprintf(buf, "heating on for %lus", heatingOnTime);
    //sendLog(buf, LOGLEVEL_INFO);
  }
  else if (thermostat_heatingMode > 0 && !thermostat_turnHeatingOn) {
    if(thermostat_heatingLastOnMillis > 0) {
      // prevent locking the heating after a reboot
      thermostat_heatingOffTime = (millis() - thermostat_heatingLastOffMillis) / 1000;
    }

    //char buf[101];
    //sprintf(buf, "heating off for %lus", heatingOffTime);
    //sendLog(buf, LOGLEVEL_INFO);
  }


  //char tmp_topic_out[50];
  //sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "heating");

  if ( sensor_DHT_lastUpdate != 0 && (millis() - sensor_DHT_lastUpdate) <= sensors_maxMeasurementAge ) {
    // thermostat - only active if measured temperature is < 2 min old

#ifdef DEBUG_VERBOSE
    Serial.print("thermostat, lastTempUpdate=");
    Serial.print(sensor_DHT_lastUpdate);
    Serial.print(", lastTempUpdate_delta=");
    long _lastTempUpdateDelta = millis() - sensor_DHT_lastUpdate;
    Serial.println(_lastTempUpdateDelta);
#endif

    // thermostat with hysteresis
    if ( thermostat_turnHeatingOn && sensor_DHT_currTemp >= thermostat_currActualSetTemp ) {
      thermostat_turnHeatingOn = false;
      thermostat_heatingLastOffMillis = millis();
      thermostat_heatingLockTime = confTherm.heatingMinOffTime;
      
      digitalWrite(PIN_THERMOSTAT_OUTPUT, !THERMOSTAT_OUTPUT_ONSTATE);
      
      display_update();

      sprintf_P(logBuf, "TSTAT: %s OFF, on for %lus", PGMStr_switchHeating, thermostat_heatingOnTime);
      sendLog(logBuf, LOGLEVEL_INFO);

      //Serial.println("heating off");
      //mqttclient.publish(tmp_topic_out, "off");
      thermostat_publishCurrentValues();
    }
    else if ( !thermostat_turnHeatingOn && thermostat_heatingMode > 0 && thermostat_heatingLockTime == 0 && thermostat_heatingPause == 0 && ( sensor_DHT_currTemp < (thermostat_currActualSetTemp - confTherm.hysteresis) ) ) {
      //if ( heatingOffTime > confThermAdv.heatingMinOffTime || heatingLastOnMillis == 0) {
        thermostat_turnHeatingOn = true;
        //heatingLockTimeActive = false;
        //heatingLockTime = 0;
        thermostat_heatingLastOnMillis = millis();

        digitalWrite(PIN_THERMOSTAT_OUTPUT, THERMOSTAT_OUTPUT_ONSTATE);
        
        display_update();

        snprintf(logBuf, LOG_BUFFER_SIZE, "TSTAT: switch heating ON, off for %lus", thermostat_heatingOffTime);
        sendLog(logBuf, LOGLEVEL_INFO);

        //Serial.println("heating on");
        //mqttclient.publish(tmp_topic_out, "on");
        thermostat_publishCurrentValues();
      //}
      //else {
      //  // heating should run BUT lock time is active
      //  heatingLockTimeActive = true;
      //  heatingLockTime = confThermAdv.heatingMinOffTime - heatingOffTime;
      //  display_update();
      //}
    }
    else if (thermostat_heatingPause > 0) {
      thermostat_turnHeatingOn = false;
      thermostat_heatingLastOffMillis = millis();
      
      digitalWrite(PIN_THERMOSTAT_OUTPUT, !THERMOSTAT_OUTPUT_ONSTATE);

      display_update();
    }
  }
  else {
    // turn off as no temp reading is available
    if (thermostat_turnHeatingOn) {
      
      digitalWrite(PIN_THERMOSTAT_OUTPUT, !THERMOSTAT_OUTPUT_ONSTATE);
      
      thermostat_turnHeatingOn = false;
      thermostat_heatingLastOffMillis = millis();
    }

    if ( sensor_DHT_lastUpdate != 0 ) sendLog(F("TSTAT: heating OFF, temp reading not yet available"), LOGLEVEL_INFO);
    else if ( (millis() - sensor_DHT_lastUpdate) > sensors_maxMeasurementAge ) sendLog(F("TSTAT: heating OFF, last temp reading too old"), LOGLEVEL_WARN);

    //mqttclient.publish(tmp_topic_out, "off");
    thermostat_publishCurrentValues();
  }

}



void thermostat_toggleOnOff() {
  if (thermostat_heatingMode > 0) {
    thermostat_heatingMode = 0;
    thermostat_heatingPause = 0;
    thermostat_heatingLockTime = 0;
    thermostat_lastValueChange = millis();
    thermostat_heatingModeAlreadySaved = false;
  }
  else {
    thermostat_heatingMode = 1;
    thermostat_heatingPause = 0;
    thermostat_heatingLockTime = 0;
    thermostat_lastValueChange = millis();
    thermostat_heatingModeAlreadySaved = false;
  }
  thermostat_updateCurrentHeatingModeName();
  display_update();
}



void thermostat_togglePreset() {
  //sendLog(F("switch preset to "));
  if (thermostat_pendingPreset < 0 || thermostat_pendingPreset > 2) thermostat_pendingPreset = thermostat_preset;

  //    if (pendingPresetToggle && preset == 0 && pendingPreset == 0) pendingPreset = 1;
  //    else if (pendingPresetToggle && preset == 1 && pendingPreset == 1) pendingPreset = 0;
  //    else if (pendingPreset == 1 && pendingPresetToggle) pendingPreset = 2;
  //    else if (pendingPreset == 2 && !pendingPresetToggle) pendingPreset = 0;
  //    else if (pendingPreset == 2 && pendingPresetToggle) pendingPreset = 1;

  // pendingPreset 0 => Normal
  // pendingPreset 1 => Reduction 1
  // pendingPreset 2 => Reduction 2

  if(thermostat_preset == 0) {  // Normal > Reduction 1 > Reduction 2
    if (thermostat_pendingPreset == 0) thermostat_pendingPreset = 1;
    else if (thermostat_pendingPreset == 1) thermostat_pendingPreset = 2;
    else if (thermostat_pendingPreset == 2) thermostat_pendingPreset = 0;
  }
  else if(thermostat_preset == 1) {  // Reduction 1 > Normal > Reduction 2
    if (thermostat_pendingPreset == 1) thermostat_pendingPreset = 0;
    else if (thermostat_pendingPreset == 0) thermostat_pendingPreset = 2;
    else if (thermostat_pendingPreset == 2) thermostat_pendingPreset = 1;
  }
  else if(thermostat_preset == 2) {  // Reduction 2 > Normal > Reduction 1
    if (thermostat_pendingPreset == 2) thermostat_pendingPreset = 0;
    else if (thermostat_pendingPreset == 0) thermostat_pendingPreset = 1;
    else if (thermostat_pendingPreset == 1) thermostat_pendingPreset = 2;
  }
  

  //  if (preset == 0 && pendingPreset == 0) pendingPreset = 1;
  //  else if (preset == 0 && pendingPreset == 1) pendingPreset = 2;
  //  else if (preset == 1 && pendingPreset == 0) pendingPreset = 2;
  //  else if (preset == 1 && pendingPreset == 1) pendingPreset = 0;
  //  else if (preset == 1 && pendingPreset == 2) pendingPreset = 1;
  //  else if (preset == 1 && pendingPreset == 0) pendingPreset = 1;
  //  else if (preset == 2 && pendingPreset == 0) pendingPreset = 1;
  //  else if (preset == 2 && pendingPreset == 1) pendingPreset = 0;
  //  else if (preset == 2 && pendingPreset == 2) pendingPreset = 0;


  thermostat_lastValueChange = millis();
  thermostat_presetAlreadySaved = false;

  thermostat_updatePendingPresetName();
  //display_update();
  //pendingPresetToggle = true;
  display_showRow2OverlayMessage(thermostat_pendingPresetName);
  //Serial.print(pendingPreset);
  //Serial.print(" - \"");
  //Serial.print(currentPresetName);
  //Serial.println("\"");
}



void thermostat_updateCurrentHeatingModeName() {
  if (thermostat_heatingMode == 0) strlcpy(thermostat_currentModeName, confTherm.modeName0, 14);
  else if (thermostat_heatingMode == 1) strlcpy(thermostat_currentModeName, confTherm.modeName1, 14);
}



void thermostat_updateCurrentPresetName() {
  if (thermostat_preset == 0) strlcpy(thermostat_currentPresetName, confTherm.psetName0, 14);
  else if (thermostat_preset == 1) strlcpy(thermostat_currentPresetName, confTherm.psetName1, 14);
  else if (thermostat_preset == 2) strlcpy(thermostat_currentPresetName, confTherm.psetName2, 14);
}



void thermostat_updatePendingPresetName() {
  if (thermostat_pendingPreset == 0) strlcpy(thermostat_pendingPresetName, confTherm.psetName0, 14);
  else if (thermostat_pendingPreset == 1) strlcpy(thermostat_pendingPresetName, confTherm.psetName1, 14);
  else if (thermostat_pendingPreset == 2) strlcpy(thermostat_pendingPresetName, confTherm.psetName2, 14);
}



void thermostat_setTempStepUp() {
  if (thermostat_heatingMode == 1) {
    sendLog(F("TSTAT: setTemp +0.5"));
    if ( thermostat_setTemp <= (confTherm.setTempMax - 0.5)) {
      thermostat_setTemp += 0.5;
      thermostat_lastValueChange = millis();
      thermostat_setTempAlreadySaved = false;
    }
    thermostat_mainFunction();
    display_update();
  }
}



void thermostat_setTempStepDown() {
  if (thermostat_heatingMode == 1) {
    sendLog(F("TSTAT: setTemp -0.5"));
    if ( thermostat_setTemp >= (confTherm.setTempMin + 0.5)) {
      thermostat_setTemp -= 0.5;
      thermostat_lastValueChange = millis();
      thermostat_setTempAlreadySaved = false;
    }
    thermostat_mainFunction();
    display_update();
  }
}



void thermostat_setTempTo(float _setTo) {
  bool _changed = false;
  if(_setTo != thermostat_setTemp) {
    if (_setTo >= confTherm.setTempMin && _setTo <= confTherm.setTempMax) {
      _changed = true;
    }
    else if (_setTo > confTherm.setTempMax) {
      _setTo = confTherm.setTempMax;
      _changed = true;
    }
    else if (_setTo < confTherm.setTempMin) {
      _setTo = confTherm.setTempMin;
      _changed = true;
    }
    if (_changed) {
        thermostat_setTemp = _setTo;
        thermostat_lastValueChange = millis();
        thermostat_setTempAlreadySaved = false;

        thermostat_mainFunction();
        display_update();
        thermostat_publishCurrentValues();

        sprintf_P(logBuf, "%s: %s %s %2.1f", PGMStr_thermostat, PGMStr_setTemp, PGMStr_changedTo, thermostat_setTemp);
        sendLog(logBuf);
      }
    }
}



void thermostat_setTempLowStepUp() {
  sendLog(F("TSTAT: setTempLow +0.5"));
  if ( thermostat_setTempLow <= (thermostat_setTempLowMax - 0.5)) {
    thermostat_setTempLow += 0.5;
    thermostat_lastValueChange = millis();
    thermostat_setTempLowAlreadySaved = false;
  }
  display_update();
}



void thermostat_setTempLowStepDown() {
  sendLog(F("TSTAT: setTempLow -0.5"));
  if ( thermostat_setTempLow >= (thermostat_setTempLowMin + 0.5)) {
    thermostat_setTempLow -= 0.5;
    thermostat_lastValueChange = millis();
    thermostat_setTempLowAlreadySaved = false;
  }
  display_update();
}



void thermostat_setTempLowTo(float _setTo) {
  bool _changed = false;
  if(_setTo != thermostat_setTempLow) {
    if (_setTo >= thermostat_setTempLowMin && _setTo <= thermostat_setTempLowMax) {
      _changed = true;
    }
    else if (_setTo > thermostat_setTempLowMax) {
      _setTo = thermostat_setTempLowMax;
      _changed = true;
    }
    else if (_setTo < thermostat_setTempLowMin) {
      _setTo = thermostat_setTempLowMin;
      _changed = true;
    }
    if (_changed) {
      thermostat_setTempLow = _setTo;
      thermostat_lastValueChange = millis();
      thermostat_setTempLowAlreadySaved = false;

      display_update();
      thermostat_publishCurrentValues();
      
      sprintf_P(logBuf, "%s: %s %s %2.1f", PGMStr_thermostat, PGMStr_setTempLow, PGMStr_changedTo, thermostat_setTempLow);
      sendLog(logBuf);
    }
  }
}



void thermostat_setTempLow2StepUp() {
  sendLog(F("TSTAT: setTempLow2 +0.5"));
  if ( thermostat_setTempLow2 <= (thermostat_setTempLowMax - 0.5)) {
    thermostat_setTempLow2 += 0.5;
    thermostat_lastValueChange = millis();
    thermostat_setTempLow2AlreadySaved = false;
  }
  display_update();
}



void thermostat_setTempLow2StepDown() {
  sendLog(F("TSTAT: setTempLow2 -0.5"));
  if ( thermostat_setTempLow2 >= (thermostat_setTempLowMin + 0.5)) {
    thermostat_setTempLow2 -= 0.5;
    thermostat_lastValueChange = millis();
    thermostat_setTempLow2AlreadySaved = false;
  }
  display_update();
}



void thermostat_setTempLow2To(float _setTo) {
  bool _changed = false;
  if(_setTo != thermostat_setTempLow2) {
    if (_setTo >= thermostat_setTempLowMin && _setTo <= thermostat_setTempLowMax) {
      _changed = true;
    }
    else if (_setTo > thermostat_setTempLowMax) {
      _setTo = thermostat_setTempLowMax;
      _changed = true;
    }
    else if (_setTo < thermostat_setTempLowMin) {
      _setTo = thermostat_setTempLowMin;
      _changed = true;
    }
    if (_changed) {
      thermostat_setTempLow2 = _setTo;
      thermostat_lastValueChange = millis();
      thermostat_setTempLow2AlreadySaved = false;
      
      display_update();
      
      thermostat_publishCurrentValues();
      
      sprintf_P(logBuf, "%s: %s %s %2.1f", PGMStr_thermostat, PGMStr_setTempLow2, PGMStr_changedTo, thermostat_setTempLow2);
      sendLog(logBuf);
    }
  }
}



void thermostat_setHeatingmodeTo(unsigned char _setTo) {
  if(_setTo != thermostat_heatingMode) {
    thermostat_heatingMode = _setTo;
    thermostat_heatingPause = 0;
    thermostat_heatingLockTime = 0;
    thermostat_updateCurrSetTemp();
    thermostat_lastValueChange = millis();
    thermostat_heatingModeAlreadySaved = false;
    
    thermostat_updateCurrentHeatingModeName();
    thermostat_mainFunction();

    display_update();

    thermostat_publishCurrentValues();

    sprintf_P(logBuf, "%s: %s %s %u", PGMStr_thermostat, PGMStr_heatingMode, PGMStr_changedTo, thermostat_heatingMode);
    sendLog(logBuf);
  }
}



void thermostat_setHeatingPause(uint8_t _setTo) {
  bool _changed = false;
  if(_setTo == 0) {
    thermostat_heatingPause = 0;
    _changed = true;
    sprintf_P(logBuf, "%s: %s %s", PGMStr_thermostat, PGMStr_heatingPause, PGMStr_disabled);
  }
  else if (_setTo == 1 && thermostat_heatingPause == 0) {
    thermostat_heatingPause = confTherm.pauseTout;
    _changed = true;
    sprintf_P(logBuf, "%s: %s %s", PGMStr_thermostat, PGMStr_heatingPause, PGMStr_enabled);
  }

  if(_changed) {
    thermostat_lastValueChange = millis();
    thermostat_mainFunction();
    
    display_update();

    thermostat_publishCurrentValues();

    sendLog(logBuf);
  }
}



void thermostat_setPresetTo(unsigned char _setTo) {
  if(_setTo != thermostat_preset) {
    if(_setTo >= 0 && _setTo <=2) {
      thermostat_preset = _setTo;
      thermostat_pendingPreset = _setTo;
      thermostat_updateCurrSetTemp();
      thermostat_lastValueChange = millis();
      thermostat_presetAlreadySaved = false;
      
      thermostat_updateCurrentPresetName();
      thermostat_mainFunction();

      display_update();

      thermostat_publishCurrentValues();
      
      sprintf_P(logBuf, "%s: %s %s %u", PGMStr_thermostat, PGMStr_preset, PGMStr_changedTo, thermostat_preset);
      sendLog(logBuf);
    }
  }
}



void thermostat_checkValuesChanged() { // called every second by everySecond() / scheduler.ino
  if ( !thermostat_setTempAlreadySaved || !thermostat_heatingModeAlreadySaved || !thermostat_presetAlreadySaved || !thermostat_setTempLowAlreadySaved || !thermostat_setTempLow2AlreadySaved ) {
    if ( (millis() - thermostat_lastValueChange) > thermostat_saveValuesTimeout ) { // value was changed 5s ago. now save if auto-save enabled
      if (!thermostat_setTempAlreadySaved) {
        thermostat_lastUpdate_setTemp = millis();
        if (confTherm.autoSaveSetTemp && thermostat_setTemp != thermostat_setTempSaved) {
          thermostat_saveSetTemp();
          sendLog(F("TSTAT: setTemp autosave done"));
        }
        thermostat_setTempAlreadySaved = true;
      }
      if (!thermostat_setTempLowAlreadySaved) {
        thermostat_lastUpdate_setTempLow = millis();
        if (confTherm.autoSaveSetTemp && thermostat_setTempLow != thermostat_setTempLowSaved) {
          thermostat_saveSetTempLow();
          sendLog(F("TSTAT: setTempLow autosave done"));
        }
        thermostat_setTempLowAlreadySaved = true;
      }
      if (!thermostat_setTempLow2AlreadySaved) {
        thermostat_lastUpdate_setTempLow2 = millis();
        if (confTherm.autoSaveSetTemp && thermostat_setTempLow2 != thermostat_setTempLow2Saved) {
          thermostat_saveSetTempLow2();
          sendLog(F("TSTAT: setTempLow2 autosave done"));
        }
        thermostat_setTempLow2AlreadySaved = true;
      }
      if (!thermostat_heatingModeAlreadySaved) {
        thermostat_lastUpdate_heatingMode = millis();
        if (confTherm.autoSaveHeatingMode && thermostat_heatingMode != thermostat_heatingModeSaved) {
          thermostat_saveHeatingMode();
          sendLog(F("TSTAT: heatingMode autosave done"));
        }
        thermostat_heatingModeAlreadySaved = true;
      }
      if (!thermostat_presetAlreadySaved) {
        thermostat_lastUpdate_preset = millis();
        thermostat_preset = thermostat_pendingPreset;
        if (confTherm.autoSaveHeatingMode && thermostat_preset != thermostat_presetSaved) {
          thermostat_savePreset();
          sendLog(F("TSTAT: preset autosave done"));
        }
        thermostat_presetAlreadySaved = true;
      }
      thermostat_publishCurrentValues();
    }
  }
}

#endif
