[SOLVED] Rule with if else condition not working properly

Hi Everyone,

So I have the following rule that only half works and I can’t seem to figure out my error…


rule "Energy Cost"
when
    Item Energy_Watts received update
then
    val hour = now.getHour()
    var cost = Energy_Watts.state as DecimalType
    var Number OFFrate = 0.074
    var Number ONrate = 0.152
    var Number MIDrate = 0.102
    AnnounceStatus.sendCommand(hour)
    
    //Off-Peak on Holidays
    if (Ephemeris.isBankHoliday()) {
        e_cost.sendCommand((cost)/1000 * (OFFrate))
        rate.sendCommand("Holiday (7.4¢/kWh)")
    }    
    else {
        //Off-Peak on Weekend
        if (Ephemeris.isWeekend()) {
            e_cost.sendCommand((cost)/1000 * (OFFrate))
            rate.sendCommand("Weekend (7.4¢/kWh)")
        }
        else{
            //Off-Peak from 7PM to 7AM
            if (hour >= 19 && hour < 7) {
                e_cost.sendCommand((cost)/1000 * (OFFrate))
                rate.sendCommand("OFF-Peak (7.4¢/kWh)")
            }
            //On-Peak from 11AM to 5PM
            else if (hour >= 11 && hour < 17) {
                e_cost.sendCommand((cost)/1000 * (ONrate))
                rate.sendCommand("ON-Peak (15.2¢/kWh)")
            }
            //Other times are MidPeak (7AM to 11AM & 5PM to 7PM)
            else if (hour >= 7 && hour < 11) {
                e_cost.sendCommand((cost)/1000 * (MIDrate))
                rate.sendCommand("MID-Peak (10.2¢/kWh)")
            }
            else if (hour >= 17 && hour < 19) {
                e_cost.sendCommand((cost)/1000 * (MIDrate))
                rate.sendCommand("MID-Peak (10.2¢/kWh)")
            }
        }
    }
end 

So the ON Peak and OFF peak is working correctly, but for whatever reason the MID peak rate never seems to fire. (7AM to 11 AM & 5PM to 7PM) It just keeps showing as ON-Peak during this time window.

I’ve tried several combinations, like changing the AND to OR conditions (&& to ||) and nothing seems to work.
I also originally just tried multiple IF conditions and not ELSE IF, which also didn’t work.

I know this is just a stupid syntax error but I’ve been struggling with this all week and I’m hoping a smarter mind will be able to catch my stupid error.

Thank you in advance :slight_smile:

The first thing I notice, there’s not logging. You have a bunch of variables and calls out to stuff like Ephemeris and Item states and such and you don’t know what any of it is.

Log out everything used in the rule, particularly hour. When it doesn’t work, using pen and paper and run down the code line by line and see what it actually did.

One thing I notice, hour >= 19 && hour < 7 will never be true. You’ll never have a number that is both larger than 19 and less than 7. That’s an impossibility so it can never be true.

This rule would greatly benefit from Design Pattern: How to Structure a Rule. There is a lot of duplicated code here and it’s overly complicated.

rule "Energy Cost"
when
    Item Energy_Watts received update
then
    // Constants
    val COST = Energy_Watts.state as DecimalType
    val OFF_RATE = 0.074
    val ON_RATE = 0.152
    val MID_RATE = 0.102
    val HOUR = now.getHour()

    // 1. Determine if the rule needs to run at all
    // always run the rule

    // 2. Calculate what needs to be done.
    var currRate = OFF_RATE; // initialize to OFF
    var rateMessage = "OFF_Peak (7.4¢/kWh)"

    if(Ephemeris.isBankHoliday()) rateMessage = "Holiday (7.4¢/kWh)"
    else if(Ephemeris.isWeekend()) rateMessage = " Weekend (7.4¢/kWh)"
    else {
        switch(HOUR) {
            // Mid peak
            case HOUR >= 7 && HOUR < 11,
            case HOUR >= 17 && HOUR < 19: {
                currRate = MID_RATE
                rateMessage = "MID-Peak (10.2¢/kWh)"
            }
            // On peak
            case HOUR >= 11 && HOUR < 17: {
                currRate = ON_RATE
                rateMessage = "ON-Peak (15.2¢/kWh)"
            }
        }
    }

    // 3. Do it
    val totalCost = (COST)/1000 * (currRate)
    logInfo('Energy Cost', rateMessage + ' ' + totalCost + ' at hour ' + HOUR)
    e_cost.sendCommand(totalCost)
    rate.sendCommand(rateMessage)
end

Note, the switch is a way to make a more compact set of if/else statements. But the general approach is to set some variables to a default. The OFF_RATE is the most common and dealing with figuring out if now is between two times that cross midnight is harder, so we choose that. That way we don’t need to explicitly test for OFF_RATE any more. Only if it’s ON_RATE or MID_RATE do we need to test. That completely gets rid of one case and reduces two states to a one liner.

I don’t know why you command rate with a different message for weekend and holiday but I preserved that in the first two if, else if statements. In both cases the rate is OFF_RATE so we don’t need to do anything there.

That leaves the else which includes a switch. The first two cases fall through and set the variables based on the midrate. Then we have the case for the ON_RATE.

We don’t actually send the commands to the two Items until the end where we log out all the important stuff which will tell you what the rule did and why.

Note, I just typed in the above, it could have errors.

@rlkoshak There are some CaSe Typos (COST vs. cost, HOUR vs. Hour)

1 Like

should be fixed now

1 Like

@rlkoshak Thank you so much!
That worked beautifully :smiley:

I also bookmarked that link on Design Patterns.
Use of cases makes so much sense I feel stupid not thinking of that earlier.

I actually use switch cases in some of my other rules so I feel silly.
BTW: your code had no errors either.

Thank you again!