Nested IF & AND statements in a Rule OH2.5

Hello

I am finally getting to grips with some concepts on OpenHAB but am encountering an issue with a rule to switch on the heating.

There are several temperature sensors which are linked into OH and I have created rules for each one to create a heat demand on a per room basis with the eventual intention of installing a motorised valve on each radiator so we are only heating rooms which are scheduled to be occupied and the others are at a “setback” value.

One of the devices on the system is an EasyIO BMS controller which has Time schedules in it with a WebUI and sets an occupancy switch in OH via MQTT.

I have a rule with nested OR statements to create a general heat demand to enable the boiler:


when
	Item FF_Masterbedroom_HTDmnd changed
    or 
    Item GF_Dining_HTDmnd changed
    or
    Item GF_Hallway_HTDmnd changed
    or
    Item GF_Lounge_HTDmnd changed
    or
    Item GF_Office_HTDmnd changed
    then    if (FF_Masterbedroom_HTDmnd.state == ON || GF_Dining_HTDmnd.state == ON || GF_Hallway_HTDmnd.state == ON || GF_Lounge_HTDmnd.state == ON || GF_Office_HTDmnd.state == ON) 
{ Boiler_Demand.sendCommand(ON) }

else 

    Boiler_Demand.sendCommand(OFF)

end 

and this is working well however I want to add two AND statements to this. I have tried the following but it just doesn’t work:


when

    Item FF_Masterbedroom_HTDmnd changed
    or 
    Item GF_Dining_HTDmnd changed
    or
    Item GF_Hallway_HTDmnd changed
    or
    Item GF_Lounge_HTDmnd changed
    or
    Item GF_Office_HTDmnd changed
    or 
    Item Heating_OSS changed
    or 
    Item OAT_Heating_Disable changed 

then

    if (Heating_OSS.state == ON && OAT_Heating_Disable == OFF && FF_Masterbedroom_HTDmnd.state == ON || GF_Dining_HTDmnd.state == ON || GF_Hallway_HTDmnd.state == ON || GF_Lounge_HTDmnd.state == ON || GF_Office_HTDmnd.state == ON) 

    { Boiler_Demand.sendCommand(ON) }

else 

    Boiler_Demand.sendCommand(OFF)

    

end

the OR’d heat demand switches switch on the Boiler_Demand but ignore the status or the Heating_OSS and OAT_Heating_Disable switches.

Can anyone point me in the direction of where I am going wrong?

Many thanks

Ian

  • Platform information:
    • Hardware: _Raspberry PI 3 model B Rev 1.2
    • OS: _Raspbian GNU / Linux 9 (strech)
    • Java Runtime Environment: which java platform is used and what version
    • openHAB version: 2.5.11-1 (Release Build)

Depending on what exactly you want to accomplish you have to use round brackets:

if (Heating_OSS.state == ON && OAT_Heating_Disable.state == OFF && (FF_Masterbedroom_HTDmnd.state == ON || GF_Dining_HTDmnd.state == ON || GF_Hallway_HTDmnd.state == ON || GF_Lounge_HTDmnd.state == ON || GF_Office_HTDmnd.state == ON)) 

In this case the if will only be true id “Heating_OSS” is “ON” and “OAT_Heating_Disable” ist “OFF” and one of the OR’d conditions are true.

2 Likes

Like @Dave_K says, use brackets.

A && B || C
is ambiguous for humans to read. Did you mean
A && (B || C)
or did you mean
(A && B) || C
which do quite different things.

The rules interpreter will have a set priority to work to, but we need not guess what that is, just be clear about telling it exactly what we want it to do.
Plus it will save you going mad when you come back to the rule in six months time and wonder what you meant :smiley:

2 Likes

Thank you, @Dave_K and @rossko57

I had tried that but it didn’t seem to work. Having done a little more experimentation, it works if I use one “AND” statement (Heating_OSS AND…), but if I add in the second AND (OAT_Heating_Disable) it stops working.

I now think this is down to the rules interpreter and priorities in rules (but I could be wrong). Heating_OSS (The time signal) is sent by MQTT every 30 seconds from the BMS controller.
OAT_Heating_Disable is generated by a rule. When I look at the item states in VSCode, it looks as though the conditions are met, but the output is not in the correct state. It could also be that for testing I am turning off “virtual switches” on the Basic UI dashboard rather than changing a setpoint to invoke the rule to make the change, if that makes sense.

Simplifying down what I am trying to achieve, it’s

(A && B && (C || D || E…))

I’m going to do a little more digging and research into this. Thank you for your assistance.

Try using “logInfo” to log the states of all your items in the rule (the ones from the if-conditions). Your rule is triggered by many items so the if-condition might be true in one case but not in all cases. You can also log, which item triggered the rule (with “triggeringItem”). Maybe that will help to clear things up.

Keep in mind, that the if-condition will only be true in your case when A and B are true plus one of C, D, E,… is true.

Just saw that. I think you need to change it to:

OAT_Heating_Disable.state == OFF
2 Likes

…and that was the final solution, @Dave_K !

Rule now working as I envisaged.

It could probably be tidied up quite a lot, but it’s working as I envisaged for now. Now to look at adding a “boiler minimum firing time” to the output!!!

Thank you.

Then please mark my first suggestion as the solution. I corrected it there.

We don’t need to guess even without the brackets. Pretty much all programming languages follow the same precedence. Here’s the chart for Java.

https://introcs.cs.princeton.edu/java/11precedence/

Assuming Xtend follows the same pattern, the && will take placed first followed by the || even if you swapped them:

C || B && A

But the primary audience for your code is a human, not a computer. It’s other programmers or your future self. So take pity on your future self and make it clear what order you want the operations to take place by using the parentheses.

As written, that if statement will evaluate to true under the following conditions:

  • Heating_OSS.state == ON && OAT_Heating_Disable == OFF && FF_Masterbedroom_HTDmnd.state == ON
  • GF_Dining_HTDmnd.state == ON
  • GF_Hallway_HTDmnd.state == ON
  • GF_Lounge_HTDmnd.state == ON
  • GF_Office_HTDmnd.state == ON

Thus, if doesn’t matter what state Heating_OSS, OAT_Heating_Disable, or FF_Masterbedroom_HTDmnd are, if GF_Dining, Hallway, Loung, or Office are ON, the statement will evaluate to true.

So what Dave did to make this work is put parens around all the demand Items. So now if Heating_OSS is OFF or OAT_Heating_Disable is ON the if statement will evaluate to false no matter what the demand Items are set to. This is because the all those || are evaluated first thanks to the parens. The statement becomes “if OSS is ON and Disable is OFF and any room is demanding heat”.

Great, but now lets consider future Ian and see if he can help him out. Long if statements like that are hard to write and hard to understand. Maybe we can do it more simply?

  • Add all of your Dmnd Items to a Group:Switch:OR(ON, OFF) Heat_Demand. Once you do that you can change the trigger to your rule to
    Item Heating_OSS changed or
    Item OAT_Heating_Disable changed or
    Item Demand changed

and your if statement becomes:

if(Heating_OSS.state == ON && OAT_Heating_Disable.state == OFF && Demand.state == ON){
2 Likes