How to combine AND and OR in an IF

Hey guys,

I have some doubts about the correct use of AND and OR in one IF part of a rule.

I want my rule to do something but only if some variables all are true and one variable can have two states. So typically combining && and II but it’s not working.

Here is the rule:

rule "Automatisches Badlicht Wochentags"
when
	Item OG_Ankleidezimmer_Licht changed to ON
then
	if (Daemmerung.state <= 250 && (Tagesart.state == "Wochentag" || Tagesart.state == "Homeoffice") && now.getHourOfDay >= 5 && now.getHourOfDay <= 8 && OG_Flur_Licht.state == OFF){
	sendCommand (OG_Bad_Licht, ON)
    sendCommand (OG_Bad_SpiegelLicht, ON)
    sendCommand (OG_Bad_Rolladen, UP)
	}
end

I guess putting the OR in brackets isn’t the right way to do?

By the way (so I dont have to create another topic :wink: ) is it possible to add an IF in an IF?
And multiple IFs in a rule aren’t possible because I have to use “else if” because if the first IF wasn’t true the rule wouldn’t even come to the second IF, right?

I personally find it hard (for my future self) to understand complex IF statements.

I recommend therefore this approach:

if (Daemmerung.state > 250 ){
  return;
}
if (Tagesart.state <> "Wochentag" && Tagesart.state <> "Homeoffice"){
return;
}
if (now.getHourOfDay < 5){
   return;
}
if ( now.getHourOfDay > 8 ){
return;
}

OF_Flur_Licht.state == OFF)
sendCommand (OG_Bad_Licht, ON)
sendCommand (OG_Bad_SpiegelLicht, ON)
sendCommand (OG_Bad_Rolladen, UP)

this way, you can also easily track (logInfo( ) ) which rule has a problem

1 Like

Thanks for your suggestion
To be honest I dont know what “return” does here.

I try to describe my understanding:
First if state is true
It “returns” the next if. Is the state of that also true next if will be returend. Correct?
If a one of them is not true the rule doesnt continue and so the wished result won’t happen.

What would happen if is would just write the different ifs without the “return”?

"returns; " leaves/exits the rule. so the sendCommands are only reached if all those returns are never reached. See the statement in detail, i Switched <= to > 250…

those are little “prerequisits” in the rule, they all must be false, only than, the action is triggered.

I see no (obvious) problem with the code. I would use some logInfo lines in order to show the states of the different items when the rule is running.

Yes, nested if statements ard possible.

Why should multiple if statement be not possible? The need of an elseif depends on what you want to check.

Without a return command the following if will, be prosecuted.
Look into the example of @papaPhiL, when reaching the return command the executing exit this rule, otherwise it would continue with the next if statement.

Philipp’s solution is the best one. Avoid long complicated conditionals like this as they are very hard to read and understand for others and for future you. Always remember that future you needs to be able to read and understand the code too. For further discussion on that approach see Design Pattern: How to Structure a Rule.

First, to answer some of your specific questions:

  • Yes you can have nested if statements:
if(Dammerung.state < 250){
  if(Tagestart.state == "Wochentag" || Tagersart.state == "Homeoffice") {
    // and so on
  }
}
  • Putting the or clause in the parentheses is exactly correct in this case. They work the same way as in math. The operations inside the parens are evaluated first which is what you want here.
  • But that’s what you want. As written everything in that conditional has to be true for the code in the if to execute. So if you are using nested ifs you only execute the code if all of the ifs evaluate to true. However, when using else if, the second if would only be reached if the first if was false.

I’m pretty sure you mean to use == and not <> here. The diamond operator is used to do stuff with generics, not equivalence comparisons. Also, it looks like the fourth to the last line had the first part of it cut off. It’s missing the if( and it;s missing the return.

In OH 3, the list of conditions would be placed in the “But only if” clause of the rule. All but the Tagesart conditions could be handled without actually writing the code for it through the UI. The Tagesart would be handled using a script conditional.

I think this every time I find an old Post-It note that has something like “jen 9” written on it. Is that my sister or coworker? Was I supposed to do something at 9am or 9pm? Does one of us owe the other $9? Has this already happened?

And yet, I still leave myself silly notes like this, and still don’t add descriptive comments to my items/rules to explain to Future Russ what Past Russ was thinking when he was Present Russ.

2 Likes

I’m wondering this does still work with OH4 and new JavaScripting.
All my if rules using || or && are not working anylonger :frowning:
Has the syntax being changed?

Update:
I found the error.
In OH3, the syntax without the brackets worked fine:

if (this.event.itemName = this.BereichName + "_Schalter" && this.event.itemCommand = 'ON')
{
}

in OH4 I need to separate the different expressions with brackets:

if ((this.event.itemName = this.BereichName + "_Schalter") && (this.event.itemCommand = 'ON'))
{
}

Update:

This stopped the error messages only.
However, the 2nd expression this.event.itemCommand = 'ON' seems not to be checked, as the commands inside the if condition are executed even the itemCommand is OFF :frowning:

No clue what is wrong, but it freaked all my scripts :frowning:

If this is your code, as written in your rule, you need to use ==, not = to test for equality. But that is also the case for 3.4 so either this code never worked in the first place or the copy and paste into the forum post introduced an error.

= is the assignment operator. this.event.itemName = this.BereichName + "_Schalter" means set the variable this.event.itemName to be this.BereichName + "_Schalter".

== is the equals operator. This returns true if this.event.itemName is the same as this.BereichName + "_Schalter".

That’s because the = operator always evaluates to true.

Hello Rich,
thanks a lot for your explanation - much appreciated as usual :slight_smile:
I have double checked my code and it seems I fool myself :woozy_face:

I always use === operator in if clauses. However, when troubleshooting this issue I changed it and the error disappeared when using = operator, which is wrong of course.

I found finally the root cause of the problem, but not sure about the best approach to solve it.

In OH3 I used the following syntax to check an item state:

if (items["HmIPFCI6FullstandanzeigeTank_STATE"] === ON)
 {
}

In OH4 I updated the code to:

if (items.getItem("HmIPFCI6FullstandanzeigeTank_STATE").state === "ON") 
{
}

Using ON or OFF without the "" did raise an error, but "ON" or "OFF" was working fine.

I changed all my code from ON to “ON” and OFF to “OFF”.
This worked for above code, but didn’t work for event.itemCommand
I had to convert this to String using event.itemCommand.toString() to make it work.
I changed my code to

this.event.itemCommand.toString() === 'ON'

and this solved the problem. However, I’m not sure it was the correct approach, or just another ugly workaround. :thinking:

Does this work?
items.getItem(event.itemName).state

This does work as well, but using "" is required as well.

However, I think the behavior of the two approaches can be different.
The event.itemCommand does give the current state. With the approach you mentioned the item state could result in a different value if not updated. If the item state hasn’t been changed yet, then it will return the previous state.

Isn’t it the state of the event that caused the rule to run?

It’s there correct approach for now. The state of an Item in JS Scripting is always a String. There is a separate method to get numeric state or quantity state but everything else is a String.

However, ‘event’ is the raw Java Object and not a JS Scripting wrapper to make it consistent with JS and the rest of the JS library. Calling .toString is exactly what you want to do here.

There is an issue to fix this but the already approach isn’t straight forward.

No, items.getItem(event.itemName).state gives what ever state the Item happens to be in now. It might have changed before the rule was triggered or while it was running.

1 Like