Yet another Heating Setup

NOTE: some of these suggestions are mutually exclusive.

  • You could benefit from the trinary operator.

  • Avoid the use of primitives unless absolutely necessary. Use of primitives is known to greatly extend the amount of time it takes .rules files to parse on an RPi. Just case Item states to Numbers and you can safely do all the necessary operations (comparisons, addition, etc) without problem.

    val actualTemp = (if(Heating_Style.state == ON) HeatingHouseMin.state else HeatingHouseTemp.state) as Number
  • This is more of a style thing, but I find the code easier to follow and shorter if you initialize your variables to a reasonable default to start and then your conditions are checking whether the default values need to be changed. Often you can eliminate 30% or more of if/else or switch cases by doing this. Using switch statements can also help with code clarity.
    // Initialized to summer values
    var targetTemp = 17
    var lowerTemp = 15
...
    // No longer require the summer else case
  • If you assign a value to a variable when you create it instead of null, you do not and should not supply the Type. as with the use of primitives, over specifying the Type is known to extend .rules file parsing by minutes.

  • Look at Design Pattern: How to Structure a Rule

  • Name your Heating_Temp Items the same as your modes and you can use Design Pattern: Associated Items to get the right Temp Item.

import org.eclipse.smarthome.model.script.ScriptServiceUtil

rule "Heating logic"
when
    Item HeatingHouseTemp changed or
    Item Heating_Temp_Manual changed or
    Item Heating_Mode changed or
    Item Heating_Plan changed
then
    // 1. See if you need to run the Rule at all
    // You should add some checks for UNDEF and NULL for all your Items used in this Rule here
    // and return; if so. Exercise left to the student.

    // 2. Calculate what needs to be done.
    var actualTemp = (if(Heating_Style.state == ON) HeatingHouseMin.state else HeatingHouseTemp.state) as Number

    var baseTemp = 0
    var upper = 0
    var lower = 0

    if(Heating_Mode.state == ON){
        baseTemp = Heating_Temp_Manual.state as Number
        if(vTimeOfDay.state.toString == "BED") { upper = -1.5; lower = -3.5 }
        else                                   { upper = 0.3; lower = -0.5 }
    }

    // auto mode
    else {
        switch(Heating_Plan.state.toString){
            case "WINTER": {
                baseTemp = ScriptServiceUtil.getItemRegistry.getItem("Heating_Temp_"+Heating_AutoState.state.toString).state as Number
                if(Heating_AutoState.state.toString == "Heating") { upper = 0.3; lower = -0.5 }
                else                                              { upper = 0.2; lower = -0.7 }
            }
            case "AWAY": { baseTemp = 15; upper = 0; lower = -1.5 }
            default:     { baseTemp = 17; upper = 0; lower = -2 }
        }
    }

    val targetTemp = baseTemp + upper
    val lowerTemp = baseTemp + lower

    // 3. Do it
    Heating_Visibility.sendCommand(Heating_Mode.state) // consider just using Heating_Mode to control visibility on your sitemap

    // temp is higher, switch OFF
    var newState = "STAY"
    
    if(actualTemp > targetTemp) newState = "OFF"
    else if(actualTemp <= lowerTemp) newState = "ON"

    if(newState != "STAY && Heating.state.toString != newState)
        Heating.sendCommand(newState)
        logInfo("Heating", "Current temp is " + actualTemp + " and target temp is " + targetTemp + " so switching Heating to " + newState)
    }
end