[SOLVED] DSL Rule with OR and AND conditions

In my OH3 I’m trying to use a rule like so:

(...)
when
   Channel "astro:sun:local:set#event" triggered START OR
   Item RadiacaoSolar.state < 5 AND
   Item Por_Sol.state > now.minusMinutes(30)
then
(...)

Will this work or should I change it somehow?

This will not work in any rules language .

Rules are triggered by events. You will never have a case where Item RadiacaoSolar < 5 AND Item Por_Sol > now.minusMinutes(30) at the exact same instant. Therefore that’s not an event, that’s testing state.

Other issues with the proposed code:

  • you do not use .state in a rule trigger
  • you cannot access variables in a rule trigger (i.e. now)
  • you cannot do comparisons with rule triggers, only exact matches
  • you cannot use > to compare ZonedDateTimes even if comparisons like that were allowed
  • you cannot compare a ZonedDateTime to the state of an Item, you have to pull the ZonedDateTime from the Item’s state

In the UI, and in some of the languages (e.g. jRuby, JS Scripting rule builder) there is a rule condition. This is where you can check for state and only run the rule if the state is as you want it.

Rules DSL does not support rule conditions so you must implement those as if statements inside the rule body.

when
   Channel "astro:sun:local:set#event" triggered START OR
   Item RadiacaoSolar changed OR
   Item Por_Sol changed
then
  if(RadiacaoSolar.state as Number > 5 || (Por_Sol.state as DateTimeType).zonedDateTime.isBefore(now.minusMinutes(30)) {
    return;
  }

Note: this is not the only thing Rules DSL cannot do. I recommend against any new rules development in Rules DSL.

Using JS Scripting’s rule builder it would look like the following:

rules
  .when()
    .channel('"astro:sun:local:set#event").triggered('START')
    .or().item("RadiacaoSolar").changed()
    .or().item("Por_Sol").changed()
  .if(() => items.RadiacaoSolar.numericState < 5 && time.toZDT(items.Por_Sol).isAfter('PT-30M'))
  .then( event => {
    // code goes here
  }).build('Rule Name', 'Rule Description');

If the command is simple, Rule Builder has a bunch of built in “thens”.

If you use JSRule you have to put the condition inside the rule body as an if same as Rules DSL.

In jRuby you’d use “Guards”. I don’t know jRuby enough to try to show an example.

In the UI there’s the “But only if…” section of the rule. Basic conditions are built in, more complicated ones can be implemented as a script, any language is supported.

2 Likes

Thank you so much once again for your quick and detailed answer.

You are a machine! :slight_smile:

1 Like

Unfortunately, I’m getting this weird error message that I cannot understand it’s cause:

2024-02-16 09:55:51.290 [WARN ] [el.core.internal.ModelRepositoryImpl] - Configuration model 'estores.rules' has errors, therefore ignoring it: [39,56]: missing 'then' at 'OR'
[40,9]: no viable alternative at input 'RadiacaoSolar'

This is the code:

rule "Processos no por do sol"
when
   Channel "astro:sun:local:set#event" triggered START OR
   Item RadiacaoSolar changed
then
   if(DesativarAutomatismos.state == ON || (RadiacaoSolar.state as Number > 5 && (Por_Sol.state as DateTimeType).zonedDateTime.isBefore(now.minusMinutes(30)))) return;
(...)

EDIT:
Ok, found problem. I cannot use OR it should instead be or

That’s it! Case sensitive.

Yes and I should have looked it up in the docs before making my example above too. It’s been a long time since I’ve used Rules DSL day-to-day and some stuff like that is getting rusty.

1 Like

Here’s the final conditions all working (it was still left checking for “false” in the last condition):

(...)
when
   Channel "astro:sun:local:set#event" triggered START or
   Item RadiacaoSolar changed
then
if(DesativarAutomatismos.state == ON || now.getHour() < 17 || ((RadiacaoSolar.state as Number).floatValue > 5.0 && (Por_Sol.state as DateTimeType).zonedDateTime.isBefore(now.plusMinutes(30)) == false)) return;

Doing a log right now on the value from Solar Radiation and from that time validation for the Sunset time, this is the result:

Solar as float: 134.1 Time: false

So this is it. It seems to be working finally. :slight_smile:

EDIT: Condition was still wrong, now it’s correct! It should be “plusMinutes” and not “minusMinutes” and the “false” checking was incorrectly placed.

EDIT2: Ok, had to include the now.getHour() because in the early morning this activated due to the fact that sun was rising and therefore there was weak light.