There's no "elseif" in Rules API, but depth limit is causing server overloads

I was porting a WebCoRE automation to Rules API

It was originally like this.

if button gets pressed {
  if (A) {
     do_1
  } else if (B) {
     do_2
  } else if (C) {
     do_3
  } else if (D) {
     do_4
}

But problem is, since there’s no “elseif” in Rules API, so it should be like this in Rules API.

if button gets pressed {
  if (A) {
     do_1
  } else{
     if (B) {
        do_2
     } else {
        if (C) {
          do_3
       } else {
         if (D) {
          do_4
         }
      }
    }
  }
}

But the problem is…
If I port this psedocode into Rules API, I get following error message

"message":"Nested action depth limit (5) exceeded"

Duh…

So I did the workaround like below for the depth limit.

if button gets pressed {
  if (A) {
     do_1
  }
  if ((not A) and B) {
     do_2
  } 
  if ((not A) and (not B) and C) {
     do_3
  } 
  if ((not A) and (not B) and (not C) and D) {
     do_4
}

Now it works well though…
But it takes MUCH MORE server resource than the original logic.

Let’s say when condition A is met, original code just exits after do_1
but, after the workaround, it needs to go over every useless following if statements, which contain a lot more comparison logics than the original one.

I know you guys need depth limits to alleviate server overloads,
but in the real world situation, not only it makes hassle in coding in rules API, but the depth limit is actually causing much more overload to server resources.

I suggest one of the solutuion to this problem.

  • Implementing “elseif” in the Rules API
  • or increasing the depth limit.

Thank you.

Couldn’t you just use an additional local bool variable, init that to false and use that to determine whether you already have evaluated a previous condition to true? Something along the lines of

if button gets pressed {
  processed = false
  if (A) {
    do_1
    processed = true
  }
  if ((not processed) and B) {
    do_2
    processed = true
  }
  if ((not processed) and C) {
    do_3
    processed = true
  }
  if ((not processed) and D) {
    do_4
    processed = true
  }
1 Like

There’s no variable in rules api.

Hi! Not all conditions must be nested to be used, you can apply the trigger property to set them as a precondition so they don’t trigger independently.
For example, the Rule below follows this workflow:

  1. IF the Dimmer 1 is turned ON
  2. IF the Dimmer 2 is “OFF”, then the Dimmer 3 is turned ON
  3. IF the Dimmer 3 has a level of 75%, then the Dimmer 2 is turned ON

Points two and three are executed only when the condition of one is TRUE.

1 Like

First,
with this method, I can reduce 1 depth with my code with the first condition, like below

if button gets pressed :
if (A) {
  do_1
}
if ((not A) and B) {
   do_2
} 

However, there’s still problem persists with the provided rules code, because of absence of elseif.

Let’s say “Dimmer Bulb 3” was turned off with it’s brightness 75% just before turning off, and "Dimmer 2 is already turned OFF.

If I turn on the Dimmer 1 to trigger the automation
then following happens

  1. IF the Dimmer 1 is turned ON
    → It triggers the automation

  2. IF the Dimmer 2 is “OFF”, then the Dimmer 3 is turned ON
    → since the dimmer 2 is off, Dimmer 3 is turned ON.
    and because Dimmer 3 was 75% just before turning off, it is turned on with brighness 75%

  3. IF the Dimmer 3 has a level of 75%, then the Dimmer 2 is turned ON
    → this condition is also met because Dimmer 3 just got turned on with 75%, dimmer 2 is getting turned on, which is not an expected behavior, and waste of useless computation.

    If it were “else if” or “else+if (with one more depth)”, instead of just “if”, Dimmer 2 would not turned on as expected.

I already had this problem with my rules with the workaround. I had to use else + if.

Problem is the depth limit.

@nayelyz A few questions pertaining to your post:

From your example I gather that the top level (if)action conditions form an implicit and? I would have expected that the and sub section of the if action would be be used for this otherwise.

Thanks for more information on use of the trigger value. Is it sole use to create pre-conditions by specifying “Never” as the value? I note that the default value is “Auto” - what is the logic for that?

In general, is there more documentation to be found for the rules in general? I found an earlier post about a beta program for the rules API that supposedly would include some more docs and have submitted an application, but without receiving an answer so far.

Sorry for the delay, I was verifying some details about this with the engineering team.

trigger is a feature that allows users to customize the behavior of the events subscriptions for the Rule.
Auto is designed to best match the user’s intention but this is not always achieved so that’s why the value Always is available, to force the subscription to certain events in order to trigger the Rule.

I’m not sure if I understood correctly your question, but it’s something similar to:

if(A){
    if(B){...}
    if(C){...}
}

If it had the and operand, the conditions defined inside would have to be True to execute the Rule (otherwise, it’ll just run the else part if you included it). In my sample, only the first condition triggers the Rule but both conditions are evaluated as well.

I found “sequence” in rules API documentation.
If I write the code using “sequence” with “Parallel” like below, would it solve the problem that I mentioned above?

The problem was the result of the command by the second “if” affecting condition of 3rd “if” statement.

name: Rule with several conditions using sequence
actions:
- if:
    sequence:
      then: Parallel
    equals:
      right:
        device:
          devices:
          - Dimmer1-ID
          component: main
          capability: switch
          attribute: switch
      left:
        string: 'on'
    then:
      - if:
          equals:
            right:
              device:
                devices:
                - Dimmer2-ID
                component: main
                capability: switch
                attribute: switch
                trigger: Never
            left:
              string: 'off'
          then:
          - command:
              devices:
              - Dimmer3-ID
              commands:
              - component: main
                capability: switch
                command: 'on'
      - if:
          equals:
            right:
              device:
                devices:
                - Dimmer3-ID
                component: main
                capability: switchLevel
                attribute: level
                trigger: Never
            left:
              integer: 75
          then:
          - command:
              devices:
              - Dimmer2-ID
              commands:
              - component: main
                capability: switch
                command: 'on'