How I optimized my warm-water tank

we replaced our old oil burner with a new air heat pump and I`ve chosen a product that had some kind of smart home integration. I just had to add the great KM200 Binding from @Markinus to manage the heat pump via OH.
the first thing I optimized was the time when the heat pump heats the warm water tank. by default water is simply heated when a low-temp trigger value is reached. an air heat-pump extracts energy from the outside air, hence the higher the outside temperature the more efficiently the pump works.
the attached rule tries to find the peak of the outside temperature during the day and triggers the heat process.
I can image to adopt the rule also for the heating circuits as well, like stopping the heating in the morning when weather forecast announces warm weather.
anybody else optimizing a heat-pump with OH? I guess this saves some $$$ on heating bills…

val mailActions = getActions("mail","mail:smtp:xxx")
var Number avgtemplast10min = 99

rule "Wärmepumpe daily runtime u starts"
        Time is midnight 
        Buderus_daily_runtime.sendCommand((Buderus_heatS_workingTime_totalSystem.state as Number - Buderus_heatS_workingTime_totalSystem.historicState(now.minusHours(24)).state as Number))
        val Number dailymins = (Buderus_daily_runtime.state as Number / 60)
        logInfo("Buderus.rules: ", "Heatpump Laufzeit: " + dailymins + " Minuten")
        Buderus_daily_starts.sendCommand(Buderus_heatS_numberOfStarts.state as Number - Buderus_heatS_numberOfStarts.historicState(now.minusHours(24)).state as Number)
        logInfo("Buderus.rules: ", "Heatpump täglich " + Buderus_daily_starts.state + " Starts")

rule "find highest temperature"
        Time cron "0 0/10 * 1/1 * ? *"  
        if (Buderus_dwh1_Operationmode.state != "off" && (now.getHourOfDay() >= 9 && now.getHourOfDay() <= 18) && (Buderus_Outsidetemp.averageSince(now.minusMinutes(10)) < avgtemplast10min ) && avgtemplast10min != 99) {
            logInfo("Buderus.rules: ", "Temperatur sinkt, avgtemp last 10min Intervall: " + Buderus_Outsidetemp.averageSince(now.minusMinutes(10)) + " previous 10min Intervall: "+ avgtemplast10min + ", in 3h:"+localForecastTemperature_3hoursN.state + ", in 6h:"+localForecastTemperature_6hoursN.state+ ", in 9h:"+localForecastTemperature_9hoursN.state )
            if ((Buderus_Outsidetemp.state >= localForecastTemperature_3hoursN.state) && (Buderus_Outsidetemp.state >= localForecastTemperature_6hoursN.state) && (Buderus_Outsidetemp.state >= localForecastTemperature_9hoursN.state) && Buderus_WW_run.state == OFF ) { //(Buderus_dwh1_temp.state <= 48|"°C")
                logInfo("Buderus.rules", "WW wird jetzt aufbereitet, Outsidetemp: " + Buderus_Outsidetemp.state + ", WW Zieltemperatur: " + Buderus_dwh1_currentSetpoint.state)
                //Buderus_dwh1_singleChargeSetpoint.sendCommand(Buderus_dwh1_currentSetpoint.state as Number)
                //Buderus_WW_run.sendCommand(ON)   //item mit 12h autooff oder in der früh auf off
        if ((now.getHourOfDay() >= 9 && now.getHourOfDay() <= 18) && (Buderus_Outsidetemp.averageSince(now.minusMinutes(10)) >= avgtemplast10min ) && avgtemplast10min != 99){
            logInfo("Buderus.rules: ", "Temperatur steigt oder konstant, avgtemp last 10min Intervall: " + Buderus_Outsidetemp.averageSince(now.minusMinutes(10)) + " previous 10min Intervall: "+ avgtemplast10min + ", in 3h:"+localForecastTemperature_3hoursN.state + ", in 6h:"+localForecastTemperature_6hoursN.state+ ", in 9h:"+localForecastTemperature_9hoursN.state )
        avgtemplast10min = Buderus_Outsidetemp.averageSince(now.minusMinutes(10))

rule "start water heating at 7pm when forecast temp is still higher then meassured value"
        Time cron "0 0 19 1/1 * ? *"
        if (Buderus_WW_run.state == OFF) {
            logInfo("Buderus.rules", "WW wird jetzt aufbereitet, Outsidetemp: " + Buderus_Outsidetemp.state + ", WW Zieltemperatur: " + Buderus_dwh1_currentSetpoint.state)

rule "WW manuell aufgewärmt"
        Item Buderus_dwh1_Charge received command "start"
        postUpdate(Buderus_WW_LastUpdate, new DateTimeType())
        logInfo("Buderus.rules", "WW wurde manuell aufgewärmt: " + new DateTimeType().format(" %1$td.%1$tm %1$tH:%1$tM"))

rule "reset WW_run"
        Time cron "0 0 8 1/1 * ? *"

rule "Alert on Failure"
        Item Buderus_noti_nbrErrors changed 
        logInfo("Buderus.rules", "Fehlermeldung der Heizungspumpe: " + Buderus_noti_Text.state)
        sendNotification("xxx", "Fehlermeldung der Heizungspumpe: " + Buderus_noti_Text.state)
        mailActions.sendMail("xxx", "ALARM: Wärmepumpe", "Fehlermeldung der Wärmepumpe: \n\n " + Buderus_noti_Text.state + " \n\nAchtung im Winter vor Frostgefahr! \n\nMeldung vom: " +new DateTimeType().format("%1$td.%1$tm.%1$ty %1$tH:%1$tM"))

Yes, I’m even selling an energy management system that does this based on OH (sorry for the advertising break).
It’s got a slightly different approach on run times as it is primarily targeting PV power cost savings.
When you have a PV what’s really determining heat pump start and runtime is (excess) solar production so you can maximize self consumption thus (directly) save $$$ on power cost.
This may be specific to Germany, not sure about other countries.
It more or less boils down to the same heatpump run times (around midday).

I’d be interested to know how do you determine how long to (pre-)heat.
If you know the maximum possible tank temperature, you could consider the tank to be a ‘thermal battery’ with the current temperature being the SoC (state of charge).

Could you elaborate on the Buderus channels you have found out about ? Show the items you use, please. According to the KM200 binding docs there is no documentation on those so a lot of trial & error ahead for anyone with such a system I guess.

My first heat pump died after 8 years and my new one has a Tuya controller built in. I find they (heat pumps) work well, just you have to run to them when the air is hottest and hopefully your solar is producing for best savings.

I have a sensor glued to the shower pipe that knows when the first shower of the day is taken, this starts the heating during winter.

Once it gets to 60 degrees c to kill bacteria the heat pump stops for the day so the pump only starts once to reduce wear and tear.

In winter after not running all night the tank is warm enough for 3 people to have long showers, if it starts heating at the first shower then I get four showers with ease from the 170 litre tank.

1 Like

not sure if I got your question, I don’t care about the heat time. the boiler stops when the setpoint temp is reached. buderus allows to define a chargeduration after which the boiler also stops.

true, thats my future approach when I add PV on the roof. you should use a mixing valve at the outlet of the boiler and set that to eg 60°C. you don’t want to burn yourshelf with 90°C hot water in the shower…
I even plan a step further and want to use the whole house as thermal battery. one could use excess energy from PV to heat the cellar (which I normally don’t do) and maybe even raise the temperature in other rooms by 1-2°C.

I simply added all channels the binding did provide and checked wether values were reported back or not. I then compared these values with the config panel (HMC310 in my case) to figure out what value had which description and purpose.

I can start heating the boiler via OH but I can’t change either chargeduration nor singlechargesetpoint. I can change those values but they’re changed back on the next sampling intervall… does this work in your setup?
those are the items that work with my Buderus Logathem WLW196i.2 AR heat pump with external boiler:

// +++++++++ HEATING related items ++++++++
// +++++++++++++++++++++++++++++++++++++++++
Group                   gHeat               "Heizung"  //{alexa="Endpoint.Thermostat"}
Group                   gHeat_Boiler        "Boiler"
Group                   gHeat_Heizkoerper   "Heizkörper"
Group                   gHeat_Fussboden     "Fussboden"
Group                   gHeat_WP            "Wärmepumpe"                                                                                                        

/******************************************* Heating Buderus items **********************************************/

//WP allgemein
Number:Temperature      Buderus_Aussentemperatur      "Aussentemperatur [%.1f %unit%]"        <temperature>     (gHeat_WP)           {channel="km200:sensor:173432498:temperatures:outdoor_t1"}
Number:Temperature      Buderus_Temp_Setpoint         "Kessel-Solltemperatur [%.1f %unit%]"   <temperature>     (gHeat_WP)           {channel="km200:sensor:173432498:temperatures:supply_t1_setpoint"}
Number:Temperature      Buderus_Temp_Supply_t1        "WP Vorlauftemperatur [%.1f %unit%]"    <temperature>     (gHeat_WP)           {channel="km200:sensor:173432498:temperatures:supply_t1"}
Number:Temperature      Buderus_Temp_Return           "WP Rücklauftemperatur [%.1f %unit%]"   <temperature>     (gHeat_WP)           {channel="km200:sensor:173432498:temperatures:return"}
Number:Temperature      Buderus_System_minOutdoor     "min Outdoor temp [%.1f %unit%]"        <temperature>     (gHeat_WP)           {channel="km200:system:173432498:system:minOutdoorTemp"}
String                  Buderus_System_Health         "WP Healthstatus [%s]"                  <status>          (gHeat_WP)           {channel="km200:system:173432498:system:healthStatus"}
//Number:Temperature    Buderus_Appliance_actualSupply     "Zusatzheizung [%.1f %unit%]"    <temperature>       (gHeat_WP)           {channel="km200:appliance:173432498:appliance:actualSupplyTemperature"} gleich wie Buderus_Temp_Supply_t1

String                  Buderus_dwh1_Status               "Status [%s]"                         <status>          (gHeat_Boiler)                                  {channel="km200:dhwCircuit:173432498:dhw1:status"}
Number:Temperature      Buderus_dwh1_temp                 "Boilertemperatur [%.1f %unit%]"      <temperature>     (gHeat_Boiler)  ["Measurement", "Temperature"]  {channel="km200:dhwCircuit:173432498:dhw1:actualTemp"}
String                  Buderus_dwh1_Charge               "WW Aufheizen [%s]"                   <status>          (gHeat_Boiler)                                  {channel="km200:dhwCircuit:173432498:dhw1:charge"}  //start|stop??
//Number                  Buderus_dwh1_Workingtime          "WorkingTime [%.1f]"                  <temperature>     (gHeat_Boiler)                                  {channel="km200:dhwCircuit:173432498:dhw1:workingTime"}
//Number:Temperature      Buderus_dwh1_eco                  "Temp Eco [%d %unit%]"                <temperature>     (gHeat_Boiler)                                  {channel="km200:dhwCircuit:173432498:dhw1:temperatureLevels_eco"}  //Einschalttemperatur im ECO+, Aussschalttemp: 50°C
//Number:Temperature      Buderus_dwh1_high                 "Temp High [%d %unit%]"               <temperature>     (gHeat_Boiler)                                  {channel="km200:dhwCircuit:173432498:dhw1:temperatureLevels_high"} //Einschalttemperatur im Komfort, Aussschalttemp: 60°C
//Number:Temperature      Buderus_dwh1_low                  "Temp Low [%d %unit%]"                <temperature>     (gHeat_Boiler)                                  {channel="km200:dhwCircuit:173432498:dhw1:temperatureLevels_low"} //Einschalttemperatur im ECO, Aussschalttemp: 55°C
//Number:Temperature      Buderus_dwh1_off                  "Temp Off [%d %unit%]"                <temperature>     (gHeat_Boiler)                                  {channel="km200:dhwCircuit:173432498:dhw1:temperatureLevels_off"}
//Number                  Buderus_dwh1_Waterflow            "Waterflow [%s]"                                        (gHeat_Boiler)                                  {channel="km200:dhwCircuit:173432498:dhw1:waterFlow"}
String                  Buderus_dwh1_Operationmode        "WW Operationmode [%s]"               <status>          (gHeat_Boiler)                                  {channel="km200:dhwCircuit:173432498:dhw1:operationMode"} //Off|low(WW redu-)|high(WW an)|eco(EcoPlus)|ownprogram(Eigen)
Number                  Buderus_dwh1_Chargeduration       "Aufheizdauer [%d Min]"               <time>            (gHeat_Boiler)                                  {channel="km200:dhwCircuit:173432498:dhw1:chargeDuration"}
Number:Temperature      Buderus_dwh1_currentSetpoint      "Boiler Setpoint [%d %unit%]"         <temperature>     (gHeat_Boiler)                                  {channel="km200:dhwCircuit:173432498:dhw1:currentSetpoint"}
Number:Temperature      Buderus_dwh1_singleChargeSetpoint "manuelle Aufheiztemp. [%d %unit%]"   <temperature>     (gHeat_Boiler)                                  {channel="km200:dhwCircuit:173432498:dhw1:singleChargeSetpoint"}

//HC1 Heizkörper
Number:Temperature      Buderus_hc1_actualSupplyTemperature     "Vorlauftemperatur [%.1f %unit%]"           <temperature>   (gHeat_Heizkoerper)     {channel="km200:heatingCircuit:173432498:hc1:actualSupplyTemperature"}
String                  Buderus_hc1_suWiSwitchMode              "Sommer/Winter Switchmode [%s]"             <status>        (gHeat_Heizkoerper)     {channel="km200:heatingCircuit:173432498:hc1:suWiSwitchMode"}   //SummerWinterSwitchMode automatic=automatik, forced=winter, off=summer
Number:Temperature      Buderus_hc1_Setpoint                    "Solltemperatur [%.1f °C]"                  <heating>       (gHeat_Heizkoerper)     {channel="km200:heatingCircuit:173432498:hc1:temperatureRoomSetpoint"}
//Number                  Buderus_hc1_pumpModulation              "Leistung [%.1f]"                           <temperature>   (gHeat_Heizkoerper)     {channel="km200:heatingCircuit:173432498:hc1:pumpModulation"}
String                  Buderus_hc1_currentsuWiSwiMode          "Sommer/Winter Switchmode [%s]"             <status>        (gHeat_Heizkoerper)     {channel="km200:heatingCircuit:173432498:hc1:currentSuWiMode"}    //off|forced|cooling
Number:Temperature      Buderus_hc1_supplyTemperatureSetpoint   "supplyTemperatureSetpoint [%.1f %unit%]"   <temperature>   (gHeat_Heizkoerper)     {channel="km200:heatingCircuit:173432498:hc1:supplyTemperatureSetpoint"}  //heizkurve? abhängig von temproomsetpoint und aussentemp wird diese temp errechnet
String                  Buderus_hc1_OperationMode               "Betriebsmodus [%s]"                        <status>        (gHeat_Heizkoerper)     {channel="km200:heatingCircuit:173432498:hc1:operationMode"}  //auto|manual
Number:Temperature      Buderus_hc1_currentRoomSetpoint         "currentRoomSetpoint [%.1f %unit%]"         <temperature>   (gHeat_Heizkoerper)     {channel="km200:heatingCircuit:173432498:hc1:currentRoomSetpoint"}
Number:Temperature      Buderus_hc1_manualRoomSetpoint          "manualRoomSetpoint [%.1f %unit%]"          <temperature>   (gHeat_Heizkoerper)     {channel="km200:heatingCircuit:173432498:hc1:manualRoomSetpoint"}   //Sollwert im Betriebsmodus Manual
String                  Buderus_hc1_Status                      "Heizkreis Status [%s]"                     <status>        (gHeat_Heizkoerper)     {channel="km200:heatingCircuit:173432498:hc1:status"}
Number:Temperature      Buderus_hc1_suWiThreshold               "Einschalttemp [%.1f %unit%]"               <temperature>   (gHeat_Heizkoerper)     {channel="km200:heatingCircuit:173432498:hc1:suWiThreshold"} //ab dieser Temp ist für die Heizung Sommer

//HC2 Fussbodenheizung
Number:Temperature      Buderus_hc2_actualSupplyTemperature     "Vorlauftemperatur [%.1f %unit%]"           <temperature>   (gHeat_Fussboden)    {channel="km200:heatingCircuit:173432498:hc2:actualSupplyTemperature"}
String                  Buderus_hc2_suWiSwitchMode              "Sommer/Winter Switchmode [%s]"             <status>        (gHeat_Fussboden)    {channel="km200:heatingCircuit:173432498:hc2:suWiSwitchMode"}   //SummerWinterSwitchMode automatic=automatik, forced=winter, off=summer
Number:Temperature      Buderus_hc2_Setpoint                    "Solltemperatur [%.1f °C]"                  <heating>       (gHeat_Fussboden)    {channel="km200:heatingCircuit:173432498:hc2:temperatureRoomSetpoint"}
//Number                  Buderus_hc2_pumpModulation              "Leistung [%.1f]"                           <temperature>   (gHeat_Fussboden)    {channel="km200:heatingCircuit:173432498:hc2:pumpModulation"}
String                  Buderus_hc2_currentsuWiSwiMode          "Sommer/Winter Switchmode [%s]"             <status>        (gHeat_Fussboden)    {channel="km200:heatingCircuit:173432498:hc2:currentSuWiMode"}
Number:Temperature      Buderus_hc2_supplyTemperatureSetpoint   "supplyTemperatureSetpoint [%.1f %unit%]"   <temperature>   (gHeat_Fussboden)    {channel="km200:heatingCircuit:173432498:hc2:supplyTemperatureSetpoint"}  //heizkurve? abhängig von temproomsetpoint und aussentemp wird diese temp errechnet
String                  Buderus_hc2_OperationMode               "Betriebsmodus [%s]"                        <status>        (gHeat_Fussboden)    {channel="km200:heatingCircuit:173432498:hc2:operationMode"}  //auto|manual
Number:Temperature      Buderus_hc2_currentRoomSetpoint         "currentRoomSetpoint [%.1f %unit%]"         <temperature>   (gHeat_Fussboden)    {channel="km200:heatingCircuit:173432498:hc2:currentRoomSetpoint"}
Number:Temperature      Buderus_hc2_manualRoomSetpoint          "manualRoomSetpoint [%.1f %unit%]"          <temperature>   (gHeat_Fussboden)    {channel="km200:heatingCircuit:173432498:hc2:manualRoomSetpoint"}
String                  Buderus_hc2_Status                      "Heizkreis Status [%s]"                     <status>        (gHeat_Fussboden)    {channel="km200:heatingCircuit:173432498:hc2:status"}
Number:Temperature      Buderus_hc2_suWiThreshold               "Einschalttemp [%.1f %unit%]"               <temperature>   (gHeat_Fussboden)    {channel="km200:heatingCircuit:173432498:hc2:suWiThreshold"} //ab dieser Temp ist für die Heizung Sommer

Number                  Buderus_noti_nbrErrors    "Wärmepumpe Anzahl Fehler [%s]"                           <error>       (gHeat_WP)  {channel="km200:notification:173432498:notifications:nbrErrors"}
Number                  Buderus_noti_Errors       "Wärmepumpe Fehlernummer [%s]"                            <error>       (gHeat_WP)  {channel="km200:notification:173432498:notifications:error"}
String                  Buderus_noti_Text         "WP Fehlermeldung [%s]"                                   <error>       (gHeat_WP)  {channel="km200:notification:173432498:notifications:errorString"}

//Number                  Buderus_heatS_nominalCHPower                "Nominale Leistung des Heizsystems [%.1f]"    <energy>        (gHeat_WP)  {channel="km200:heatSource:173432498:heatSources:nominalCHPower"}
Number:Energy           Buderus_heatS_energyMonitoring_consumption  "energyMonitoring_consumption [%.1f W]"         <energy>        (gHeat_WP)  {channel="km200:heatSource:173432498:heatSources:energyMonitoring_consumption"}
//String                Buderus_heatS_hs1_type                      "hs1_type [%.1f]"                               (gHeat_WP)                  {channel=" km200:heatSource:173432498:heatSources:hs1_type"}
Number                  Buderus_heatS_hs1_actualModulation          "aktuelle Leistung [%d %%]"                     <energy>        (gHeat_WP)  {channel="km200:heatSource:173432498:heatSources:hs1_actualModulation"}
Number:Temperature      Buderus_heatS_supplyTemperatureSetpoint     "supplyTemperatureSetpoint [%.1f %unit%]"       <temperature>   (gHeat_WP)  {channel="km200:heatSource:173432498:heatSources:supplyTemperatureSetpoint"}
Number                  Buderus_heatS_numberOfStarts                "Total Starts [%d]"                             <settings>      (gHeat_WP)  {channel="km200:heatSource:173432498:heatSources:numberOfStarts"}
Number                  Buderus_heatS_powerSetpoint                 "powerSetpoint [%d %%]"                         <settings>      (gHeat_WP)  {channel="km200:heatSource:173432498:heatSources:powerSetpoint"}
Number:Temperature      Buderus_heatS_returnTemperature             "Rücklauftemperatur [%.1f %unit%]"              <temperature>   (gHeat_WP)  {channel="km200:heatSource:173432498:heatSources:returnTemperature"}
//Number                  Buderus_heatS_CHpumpModulation              "CHpumpModulation [%.1f]"                                     (gHeat_WP)  {channel="km200:heatSource:173432498:heatSources:CHpumpModulation"}
Number:Temperature      Buderus_heatS_applianceSupplyTemperature    "applianceSupplyTemperature [%.1f %unit%]"      <temperature>   (gHeat_WP)  {channel="km200:heatSource:173432498:heatSources:applianceSupplyTemperature"}
//Number                  Buderus_heatS_workingTime_centralHeating    "workingTime_centralHeating [%.1f]"                           (gHeat_WP)  {channel="km200:heatSource:173432498:heatSources:workingTime_centralHeating"}
Number                  Buderus_heatS_workingTime_totalSystem       "Laufzeit [JS(uptime.js):%s]"                   <settings>      (gHeat_WP)  {channel="km200:heatSource:173432498:heatSources:workingTime_totalSystem"}
Number:Temperature      Buderus_heatS_actualSupplyTemperature       "Vorlauftemperatur [%.1f %unit%]"               <temperature>   (gHeat_WP)  {channel="km200:heatSource:173432498:heatSources:actualSupplyTemperature"}
//Number                  Buderus_heatS_fanSpeed_setpoint             "fanSpeed_setpoint [%.1f]"                                    (gHeat_WP)  {channel="km200:heatSource:173432498:heatSources:fanSpeed_setpoint"}
//Number                Buderus_heatS_actualModulation              "actualModulation [%.1f]"                                       (gHeat_WP)  {channel="km200:heatSource:173432498:heatSources:actualModulation"}
//Number                  Buderus_heatS_nominalDHWPower               "Nominale Leistung des Warmwassersystems [%.1f]" <energy>     (gHeat_WP)  {channel="km200:heatSource:173432498:heatSources:nominalDHWPower"}
//Number                  Buderus_heatS_startDateTime                 "Start [%s]"                                    <settings>      (gHeat_WP)  {channel="km200:heatSource:173432498:heatSources:energyMonitoring_startDateTime"}

Number                  Buderus_daily_runtime                       "Laufzeit gestern [JS(uptime.js):%s]"           <settings>      (gHeat_WP)
Number                  Buderus_daily_starts                        "tägl. Starts [%d]"                             <settings>      (gHeat_WP)
Switch                  Buderus_WW_run                              "WW aufbereitet"                                <settings>      (gHeat_Boiler)  
DateTime                Buderus_WW_LastUpdate                       "WW aufbereitet um: [%1$td.%1$tm %1$tH:%1$tM]"  <time>          (gHeat_Boiler)

I’m not an expert, but what I read is that the amount of starts of the compressor massively influences the heat pumps life-time. if the heat curve is not properly set and produces too much heat such that the thermostat valves are closing, then the compressor starts modulating resulting in many start/stops. best would be to lower the heat curve and find a pleasant room temperature while having all valves fully opened. this should run the compressor on a constant enduring level. less starts with longer runtimes should be the goal:

tuning the heat curve is a long lasting process but monitoring room temp in OH can help…
and it’s interesting too :grin:

Explicit charge duration or setpoint to stop heating is different ways to ultimately achieve the same thing, maximum energy efficiency.
The more heat you generate when it’s the warmest phase of the day (or same while PV excess is available) the more efficient/cheaper your heating will be overall.
So how do you determine the heating stop setpoint ?
It must not be your warm water preset (I assume water from the tank will be downmixed anyway so you don’t get a 90°C shower) as then you’re wasting a big part of your “battery’s” capacity, harming efficiency.

I have three heating circuits, one for floor heating, one for radiators and one for the external hot-water tank. till now I only tuned the hot-water heating process: heat up once a day when max outside temp is reached.
the other two I did not touch yet, they’re fully managed by the buderus logic. as soon as I found the ideal heat curve for my house I’ll start tweaking.
hoped to find others here to share tips/recommendations/experiences etc