Main-UI Rules - comparison (`but only if`) not working?

Tags: #<Tag:0x00007f433cc7e9e0> #<Tag:0x00007f433cc7e850> #<Tag:0x00007f433cc7e670>

Hi guys,

I try to use Main-UI defined Rules for some simpler rules - but somehow if doesn’t work as expected for me. Am I missing something or is it a bug?

Situation:

  • StateAlarmClock has the state 600 (Number)
  • the rule should trigger, check the value of StateAlarmClock and should only execute for a state of 530

RuleDSL Syntax has been:

rule "Wake Up At 05:30"
when
    Time cron "0 15 5 * * ?"
then
    if( StateAlarmClock.state == 530 ) {
        SceneWakeUp.sendCommand(ON)
    }
end

(Do not worry about the cron trigger, the quarter hour time difference is intentional)

Main-UI generated code:

triggers:
  - id: "1"
    configuration:
      cronExpression: 0 15 5 * * ?
    type: timer.GenericCronTrigger
conditions:
  - inputs: {}
    id: "2"
    configuration:
      itemName: StateAlarmClock
      state: "530"
      operator: =
    type: core.ItemStateCondition
actions:
  - inputs: {}
    id: "3"
    configuration:
      itemName: SceneWakeUp
      command: ON
    type: core.ItemCommandAction

Screenshot

So according to my understanding, when the rule is triggered nothing should happen since StateAlarmClock doesn’t equal 530 (see situation).
Instead, regardless of the value of StateAlarmClock, the command is send to SceneWakeUp.
Why?

Edit: fixed the old naming schema in the Rules DSL Snippet to avoid confusion (State_Alarm_ClockStateAlarmClock)

What type of Item is State_Alarm_Clock?

What happens if you remove the quotes from 530 in the code tab?

You can always use a Rules DSL Script Condition with

Scene_Alarm_Clock.state == 530

or ECMAScript with

items["Scene_Alarm_Clock"] == 530

But these all assume the Item is of type Number without any units.

Number StateAlarmClock (gState)

When I delete the quotes in the code tab (good to know that that is possible), the change is accepted and I can save the rule. But when I go back and open the rule/code tab again, the quotes are back and the value is now a float value ("530.0").
The behavior during execution doesn’t change, the But only if part is still ignored.

How would that work? Of course, I could forgo the Main-UI Rules and either write a script or just use file based rules. Or is there a way to use Rules DSL Syntax inside a Main-UI Rule? At least replacing the whole code with Rules DSL code does not work :sweat_smile::thinking:

correct

  1. Click on the + sign to create a new condition
  2. Select “Script Condition” from the four options
  3. Choose the language
  4. Type in the code or copy/paste it as I wrote it above.

Well of course not because a whole Rules DSL rule in a .rules file includes all sorts of stuff that is already defined for you in the UI like the triggers and rule name. But if you create the rule in the UI, add the triggers, then paste the code between the “then” and the “end” into a Script Action (assuming Rules DSL) then it should work. The only limitation is you can’t use “global” variables and imports. For imports you have to use the full class name.

I tried Python - again: good to know that that is possible - but still the same result:

triggers:
  - id: "1"
    configuration:
      cronExpression: 0 15 5 * * ?
    type: timer.GenericCronTrigger
conditions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/python
      script: if ir.getItem("StateAlarmClock").state == DecimalType(530)
    type: script.ScriptCondition
actions:
  - inputs: {}
    id: "3"
    configuration:
      itemName: SceneWakeUp
      command: ON
    type: core.ItemCommandAction

The result is always the same, regardless of the value of StateAlarmClock.
It seems like the conditions gets completely ignored. Can anyone confirm that? Is that only the case for Number items?

Do you have the Python add-on installed?

I have many rules with conditions and most of those are working with Numbers. But most of them are using a Script Condition.

I do notice you didn’t write your script correctly though. It’s a conditional. It’s expecting the last line of the script to be True or False. if ir.getItem("StateAlarmClock").state == DecimalType(530) returns nothing, void. Get rid of the if, just like my Rules DSL and JavaScript examples above.

Furthermore, you only need and should only use the Item Registry when you need something besides the state of an Item. There is a nice dict available to you called items which uses the Item name as the key and the Item’s current state as the value.

So your Script Condition should be

items["StateAlarmClock"] == DecimalType(530)

or

items["StateAlarmClock"].intValue() == 530

Note, above in the original post the Item’s name was “State_Alarm_Clock”. I assume you changed it when you moved to OH 3?

Correct, sorry for the confusion.

Oha - some error message / exception would be helpful :thinking:

Did that and still no change - the rule is always executed without caring about the conditional…

Yes, and my Python / Jython (file based) rules are running just fine. It’s just that I was thinking it would be nice to have simpler / cron-triggered rules created via Main-UI to make it easier to change them on the go…
And I would really like to know why the Main-UI conditions are not working for me - is there any way to get more detailed log output?

It’s not an error though. Python in particular can treat just about anything as a boolean. If it has content or otherwise isn’t None or empty string or what ever, it’s True.

You’ll have to add some logging to see what StateAlarmClock actually is. You can add as many lines and logging and such to a Script Condition as you can to a Script Action. Just make sure the last line is or resolves to a boolean.

You can import and use anything from the Helper Libraries as well so getting a logger that way would probably be the easiest. It’s been awhile so I don’t remember what logging stuff it offers. In JavaScript you have a couple of options (which should translate to Python easily).

var Log = Java.type("org.openhab.core.model.script.actions.Log");
Log.logError("Experiments", "This is an OH error log");
Log.logWarn("Experiments", "This is an OH warn log");
Log.logInfo("Experiments", "This is an OH info log");
Log.logDebug("Experiments", "This is an OH debug log");

You’ll use Python import instead of Java.type. Those are the openHAB logging actions.

Or you can get the raw logger directly

var logger = Java.type("org.slf4j.LoggerFactory").getLogger("org.openhab.model.script.Scratch");
logger.info("This is an info log");

And as an example of a working condition I have in my setup.

var alert_threshold = items[event.itemName + "_Setpoint"] - 11;

oldState.class !== UnDefType.class 
&& alert_threshold !== undefined 
&& alert_threshold.class !== UnDefType.class 
&& event.itemState < alert_threshold 
&& oldState > event.itemState;

The rule this is attached to only runs when the Item changes from something other than UNDEF or NULL, the corresponding setpoint has a non UNDEF and NULL state, the current state is below the threshold and the Item itself is moving in the negative direction.

This is a rule that sends me an alert when the humidity is dropping, indicating that I need to add water to one of the humidifiers.

A simpler rule with a couple of conditions

triggers:
  - id: "1"
    configuration:
      itemName: vCloudiness
    type: core.ItemStateChangeTrigger
conditions:
  - inputs: {}
    id: "2"
    configuration:
      itemName: vCloudiness
      state: "50"
      operator: <
    type: core.ItemStateCondition
  - inputs: {}
    id: "4"
    configuration:
      itemName: vIsCloudy
      state: OFF
      operator: "!="
    type: core.ItemStateCondition
actions:
  - inputs: {}
    id: "3"
    configuration:
      itemName: vIsCloudy
      command: OFF
    type: core.ItemCommandAction

There is a corresponding rule to turn vIsCloudy ON.