API rules runnow: What is the payload for?

Hi everyone,

the REST endpoint /rules/{ruleUID}/runnow includes in the API explorer by default a payload.

What is the payload for? Is it possible to use the data inside the rule?

Thank you for reading this and helping me!
Kind regards
Jan


More details:

I tried this demo rule:

rules.JSRule({
    name: "Test",
    id:"Test",
    triggers: [
        triggers.ItemStateChangeTrigger("no-item", "ON", "OFF"),
    ],
    description: "Regel schreibt nur einen Log-Eintrag",
    execute: (data) => {
        logger.info('Test: ' + JSON.stringify(data));
    }
});

and send this request:

curl -X 'POST' \
  'http://<openhab>/rest/rules/Test/runnow' \
  -H 'accept: */*' \
  -H 'Content-Type: application/json' \
  -d '{
  "additionalProp1": {},
  "additionalProp2": {},
  "additionalProp3": {}
}'

The result is

2023-01-08 13:48:09.751 [INFO ] [.openhab.automation.openhab-js.rules] - Adding rule: Test
2023-01-08 13:48:09.758 [WARN ] [dule.handler.ItemStateTriggerHandler] - Item 'no-item' needed for rule 'Test' is missing. Trigger 'c9d744a8-dc24-49ea-a070-6f389793b375' will not work.
2023-01-08 13:48:23.472 [INFO ] [tomation.openhab-js.rules_nachtlicht] - Test: {}

Notes:

  • I only tried JS rules here, but if required I can use another Rule engine.

  • Triggering the rule with a ItemChange Trigger sets some data to the rule parameter.

  • The trigger in this JS rule is another hack to create rule without trigger. Creating no trigger, prevents the creation of a rule.

  • Using a valid trigger does not change the result regarding this question.

  • Platform information:

    • Hardware: RPi4
    • OS: OpenHABian
    • openHAB version: 3.4

Are you referring to the context (i.e. the request body)?

That is a way to pass name/value pairs to the called rule. In the UI for JS Scripting, they are made available under context. In other rule languages it appears differently (e.g. Nashorn they appear under this, in Rules DSL they just appear as variables).

See also rules - Documentation

You should be able to use triggers: [],. If that doesn’t work, please file an issue on the openhab-js repo.

Thank you @rlkoshak for your help.

I try to use the payload of the POST request. In my example it is the object:

{
  "additionalProp1": {},
  "additionalProp2": {},
  "additionalProp3": {}
}

But I cannot figure out how to get the context of the rule. this.ctx seems empty and context does not exist.

I also tried a UI based rule with no success.

configuration: {}
triggers: []
conditions: []
actions:
  - inputs: {}
    id: "1"
    configuration:
      type: application/javascript;version=ECMAScript-2021
      script: |-
        var logger = log('rules_demo');
        logger.info('Empty: ' + JSON.stringify( Object.keys(this.ctx.values)));
        logger.info('Doe not exist: ' + JSON.stringify(context));
    type: script.ScriptAction

I will do that after some tests with a fresh OH installation.

I’m not sure whether/how the data is accessible from text based JS Scripting rules.

And I was remembering incorrectly. In Nashorn JS the variables are under context. In JS Scripting the variables are just there. So you would access the value of “additionalProp1” just using additionalProp1 in the rule. That definitely works in UI scripts.

NOTE: There’s no JSON. There’s no parsing. You don’t get a long String. Each name/value pair becomes a separate variable. This is the REST API interface to a standard mechanism built into core.

Here’s a JS Scripting script I’m working on that triggers when a Thing changes status in a predefined way and calls another rule to process it.

console.loggerName = 'org.openhab.automation.rules_tools.Thing Status';
console.debug('ThingStatusInfoChangedEvent:' + event.toString());

var parsed = JSON.parse(event.payload);

var data = {};
data['thingID'] = event.topic.split('/')[2];;
data['thing'] = things.getThing(data['thingID']);
data['oldStatus'] = parsed[1].status;
data['oldDetail'] = parsed[1].statusDetail;
data['newStatus'] = parsed[0].status;
data['newDetail'] = parsed[0].statusDetail;

rules.runRule("thing_status_handler_new", data, true);

The script in the thing_status_handler rule:

console.log('Thing ID: ' + thingID);
console.log('Old Status: ' + oldStatus + '(' + oldDetail + ')');
console.log('New Status: ' + newStatus + '(' + newDetail + ')');
console.log('Thing: ' + thing.toString());
console.log('Thing Status : ' + thing.status);
console.log('Raw Thing from JS Thing: ' + thing.rawThing.getUID());

Hi @rlkoshak

Thank you very much!
That works with the REST request as well and I can write my rules using the UI.
Having all rules in the same place/as files would be nice but it is a good solution.

For someone else who is trying the same, my last test rule was:

configuration: {}
triggers: []
conditions: []
actions:
  - inputs: {}
    id: "1"
    configuration:
      type: application/javascript;version=ECMAScript-2021
      script: |-
        var logger = log('rules_demo');
        logger.info('additionalProp1: ' + JSON.stringify(additionalProp1));
    type: script.ScriptAction

and my REST request is

curl -X 'POST' \
  'http://<openhab>/rest/rules/008a6dc2cd/runnow' \
  -H 'accept: */*' \
  -H 'Content-Type: application/json' \
  -d '{
  "additionalProp1": "Demo Text"
}'

This will print

[INFO ] [hab.automation.openhab-js.rules_demo] - additionalProp1: "Demo Text""

I think the JSON.stringify is redundant. You should be able to just use

logger.info('additionalProp1: ' + additionalProp1)

:+1: