Doing it smarter - help with rule code rollershutter automation

Personally, putting parens around things that don’t need parens is asking for trouble and it makes the code harder to read. So, for example,

var Number TempAussenVorne = (TemperatureAussenVorne.state)

would be

var Number TempAussenVorne = TemperatureAussenVorne.state

Review Design Pattern: How to Structure a Rule. I think this Rule might benefit from this. It could at least make it shorter a bit. But beyond that there isn’t a whole lot you can do to simplify this using normal straight forward means.

There might be something clever we can do here though to split up the complexity. For example, separate the calculation of the Azimuth/Elevation into it’s own Rules as described in Design Pattern: Separation of Behaviors and Design Pattern: Time Of Day. Create a name for each of the six states represented by the elevation and azimuth (perhaps seven states for when the elevation/azimuth doesn’t fit one of the states you care about). This goes into it’s own Rule triggered by changes to the Elevation and Azimuth.

In your “Temperatur Differenz Aussen” Rule, you only need to test the temp and use a switch statement for the state calculated above.

Next you can use clever naming and Groups to further simplify the Rule. Create two Groups for each state calculated above, one for ON and one for OFF. Then you can use Design Pattern: Associated Items to send the ON and OFF commands based on the calculated state. Put the appropriate Items into each Group.

It will look something like this.

Since I don’t know appropriate names that make sense I’ll just use “ONE”, “TWO” etc for the elevation/azimuth states.

Items:

String EleAzm

Group:Switch EleAzm_ONE_ON
Group:Switch EleAzm_ONE_OFF
Group:Switch EleAzm_TWO_ON
Group:Switch EleAzm_TWO_OFF
// and so on
Group:Switch All_RS // all Azi Items are members of this Group

Switch AziOGSued ... (All_RS, EleAzm_ONE_ON, EleAzm_TWO_ON, EleAzm_THREE_OFF, EleAzm_FOUR_OFF, EleAzm_Five_OFF, EleAzm_SIX_OFF) ...
Switch AziEGSued ... (All_RS, EleAzm_ONE_ON, EleAzm_TWO_ON, EleAzm_THREE_OFF, EleAzm_FOUR_ON, EleAzm_FIVE_ON, EleAzm_SIX_ON) ...
// and so on
rule "Calculate EleAzm state"
when
    Item Elevatio changed or
    Item Aziuth changed
then
    val newState = "NONE"
    if(Elevation.state < 45 && Elevation.state > 0) {
        if(Azimuth.state > 105 && Azimuth.state < 196) newState = "ONE"
        if(Azimuth.state >196 && Azimuth.state < 270) newState = "TWO"
        if(Azimuth.state >270 && Azimuth.state < 350) newState = "THREE"
    }
    else if(Elevation.state > 45 && Elevation.state > 80) {
        if(Azimuth.state > 105 && Azimuth.state < 196) newState = "FOUR"
        if(Azimuth.state >196 && Azimuth.state < 270) newState = "FIVE"
        if(Azimuth.state >270 && Azimuth.state < 350) newState = "SIX"
    }

    // NOTE: We could be clever here to avoid the duplicated code but I don't 
    // see the need for it here.

    if(EleAzm.state != newState) EleAzm.postUpdate(newState)
end

rule "Temperatur Differenz Aussen"
when
    Item TemperatureAussenHinten received update or
    Item TemperatureAussenVorne received update or
    Item HeatPump_Temperature_1 received update or
    Item RolloAutomatik changed to ON
then
    // all the calculations at the top remain the same only you don't need 
    // AzimuthNow and ElevationNow any longer

    if (TempAussDiff >= 6 && 
        RolloAutomatik.state == ON && 
        TemperatureAussenHinten.state > aussentempschwelle && 
        sonne == false || 
        sonne && 
        TempAussDiff >= 3 && 
        RolloAutomatik.state == ON && 
        TemperatureAussenHinten.state > aussentempschwelle || 
        development ) {
        sonne = true 
        Sun.postUpdate(ON) 

        // Here is the clever part that takes advantage of the Groups and the state we set up above
        if(EleAzm.state.toString != "NONE") {
            sendCommand("EleAzm_"+EleAzm.state.toString+"_ON", "ON")
            sendCommand("EleAzm_"+EleAzm.state.toString+"_OFF", "OFF")
        }
    }

    else if (TempAussDiff < 3 && sonne) {
        createTimer(now.plusMinutes(5), [ | // Never sleep for more than 500 msec. If you need to delay the execution of some commands, create a Timer instead.

            if (TempAussDiff < 3) { // woudn't you want to recalculate the temp diff now that it's five minutes later?
                sonne = false
                Sun.postUpdate(OFF)
                All_RS.sendCommand(OFF) // sends OFF to all the Azi Items
            }
        ])
    }

    else All_RS.sendCommand(OFF) // sends OFF to all Azi Items
end

You can consolidate your ON and OFF Rules but I’m not sure it buys you much.

NOTE: I just typed in the above without even using VSCode. It’s not complete (see the … and comments) and likely has errors.

2 Likes