[Solved] JSScripting - Channel Trigger without arguments?

hi guys,

while trying to convert some of my rules I’m facing the first problems regarding triggers

in Rule DSL I had some channel based rule triggers:

when
    Channel "harmonyhub:hub:HarmonyHub:activityStarted" triggered or
    Item LightScene received command

I searched for a similar solution in the docs but only found

triggers.ChannelEventTrigger('astro:sun:local:rise#event', 'START')

and

triggers.ItemCommandTrigger('my_item', 'OFF')

the ItemCommand fires the rule without any argument but the ChannelEventTrigger not!

here the full script (ECMAScript 262 Edition 11):

const {log, rules, triggers} = require("openhab");

rules.JSRule({
  name: "Script - DisplayState",
  description: "see if TV is turned on or off",
  triggers: [
    triggers.ChannelEventTrigger('harmonyhub:hub:HarmonyHub:activityStarted'),
    triggers.ItemCommandTrigger('LightScene')
  ],
  execute: data => {
    const display = items.getItem("DisplayState");
    const harmony = items.getItem("HQHub_CurrentActivity");
   
    console.log("Display", "Rule Activated");

    if(harmony.state === "Fernsehen" || harmony.state === "ShieldTV"){
      if(display.state !== "ON"){
        display.sendCommand("ON");
        console.log("Display", "Switching Display State "+display.state);
      }
    }
    if(harmony.state !== "Fernsehen" && harmony.state !== "ShieldTV"){
      if(display.state !== "OFF"){
        display.sendCommand("OFF");
        console.log("Display", "Switching Display State "+display.state);
      }
    }
  },
  tags: []
});

Do I really have to add every argument (state) which the channel offers to get the trigger activated?

And another question is, I realized that the rule is only created when I manually run the script after openHAB restarts - this confuses me a bit, is this normal behavior?

Looking at the code I don’t see any way to not provide the event. It might work to use "*" as the event but that’s just a hunch. "" might work if the wild card does not. I see nothing in the docs nor the code to confirm that either are supported but it’s worth a try.

In the likely event that doesn’t work, I recommend filing an issue on the openhab-js repo to add support for subscribing to all events. I know it must be possible as it works just fine in MainUI Rules.

I don’t know. It used to be the case that any change to the file would be picked up by the file watcher and as the script is loaded it’s executed. It’s the execution of that script that actually creates the rule. I don’t know if that’s changed in some way.

How are you manually running it?

I tried something like that yesterday but give it another try :wink: but I don’t think “*” is a valid wildcard - we will see…

Ok

From the UI using the button under Settings->Scripts->(ScriptName)->Run Now (Ctrl-R)

Screenshot 2022-04-05 at 20-59-46 openHAB

Then I’m a little confused. It’s likely out of ignorance since I’ve long since abandoned text files for rules. But if the rule isn’t created until you run it, and MainUI only shows and give you the option to run rules, what exactly is it that you are running? Does this rule create another rule perhaps?

you have a Rules and a Scripts category in the Settings section…

when I push the mentioned button in the Scripts category a rule is created in the Rules category.
but only then not automatically after OH starts…

Edit: I’m confused too :wink: imitially I thought the script itself is the rule, but after pushing the button not the script is fired but a rule is created…

But the created Rule gets fired (but only with the item trigger so far…)

It’s a little bit like trying to shoot yourself from behind :see_no_evil:

Scripts are just a Rule with no triggers, no conditions, and a single action. But they are still rules.

I’m not sure what’s going on. It’s like it loads your file as a Script (i.e. a rule with no triggers or conditions and the action is the contents of your .js file). When you execute the Script it runs the code to create the rule. That doesn’t seem to be how it’s supposed to work. But I couldn’t offer any explanation for why it’s working that way.

thanks anyway Rich! - maybe someone else has something to offer which explains this confusing behavior…

but the whole so called jsscripting is a little confusing,
there is ECMA11, ECMA5, JSRule (whatever that is), and then jython, js, I don’t really get what is what and where are differences and what is just another name for the same language??? But I haven’t found any documentation for this whole JS thing (regarding OH3) in general…

Ok after reading a little bit deeper, I think I found the error, I saved my files as scripts via UI but after carefully reading I realized that I have to save them as .js under /automation/js/

I’ve changed this now - openhab is just restarting but I think that was the clue…

Edit Ok the rules get added now - that was my fault :see_no_evil:

They are all different rules languages you can write rules, scripts, etc. in.

This is a recent version of JavaScript installable via an add-on. It shows up in the UI as “ECMAScript 2021” (or something like that). It ships with a helper library that abstracts and simplifies what it takes to interact with openHAB from your rules.

This is somewhat legacy. It’s a really old version of JavaScript and implemented with an engine that used to be built into Java. It’s been deprecated for some time and no longer comes with Java by default in newer versions of Java.

This interacts with openHAB through the JSR223 interface. There is a Helper Library but you have to install it separately. Old JavaScript examples you find on the forum will be using this.

JSRule is a part of the JS Scripting add-on’s helper library. It makes it way easier to create a rule in a .js file (you’d never want to use this in a UI created rule, as you’ve discovered). Everything that is part of the helper library is documented at JavaScript Scripting - Automation | openHAB. This is your reference for how to create rules and interact with OH using the JS Scripting addon.

This is a separate automation add-on that lets you write rules using Python 2.7 using the JSR223 interface. It too has a separately installable helper library. Upstream is kind of abandoned so it’s future is not that certain.

JavaScript, either JS Scripting or the older Nashorn. It’s more technically correct to call it ECMAScript.

Except for JSRule, these are all just different programming languages you can use to write your rules.

For now, in MainUI there’s also the option to use Blockly. This currently renders to the old ECMAScript 5.1 but will probably be updated to the newer JS Scripting ECMAScript 2021. But you don’t have to worry about that when using Blockly.

If you are creating rules in MainUI, you don’t have to worry about JSRule or the rule builder or anything like that. You just create the rule and the triggers through MainUI and add a Script Action. There you choose the language to use and the code would be the stuff you’ve added as the execute property in JSRule above.

If you are creating rules in .js files, you have to define the rules like you did above or using the rule builder.

thanks a ton!
…this makes it a lot clearer… I was struggeling what is the difference between ECMA and JSRule but If I got it right this is just a helper part of ECMA… before changing to ECMA I tried converting some of my rules to jython, but since this will be outdated sooner or later, I thought it’s more futureproof to stick with something that is newer and (hopefully) better supported and documented.

For now I will try to figure out, how to get the channel trigger running :wink:
Thanks!

Correct. It’s provided by the JS Scripting helper library which you can find at the openhab-js library.

You might look into Blockly unless you really want to stick with file based rules. It might be easier to ease into.

Checkout jruby scripting. It’s my favourite scripting for openhab. Very succinct and easy to read. It has been quite mature and continues to be improved.

Here’s a quick guide for it

Here’s your script above, translated into JRuby:

rule 'Script - DisplayState' do
  description 'see if TV is turned on or off'
  channel 'harmonyhub:hub:HarmonyHub:activityStarted'
  received_command LightScene
  run do |event|
    logger.info('Display Rule Activated')

    display_command = ['Fernsehen', 'ShieldTV'].include?(HQHub_CurrentActivity)
    DisplayState.ensure.command display_command
    logger.info("Switching Display State #{display_command}")
  end
end

Explanation:

  • Items are referred to like in RulesDSL - you don’t need to call getItem, although if you want to, you can use items['ItemName'] but you can just use ItemName directly in your code
  • You can compare items against states directly. There’s no need call ItemName.state or even do type gymnastics especially with numeric values. You can compare things just like HQHub_CurrentActivity == 'Fernsehen' - this compares the state by default.
  • ItemName.command sends a command to ItemName but there are other ways of sending commands if needed. It can take ON/OFF or a Boolean value for switch items. true means ON, false means OFF. So ItemName.command ON is the same as ItemName.command true.
  • ItemName.ensure.command sends the command only if the item isn’t already in that state.

Note that you can still write your rule in JRuby in the same manner that you would write it in RulesDSL or Jsscripting - i.e. the long winded way - but once you’ve learned the better / simpler way, why would you.

Example of the long version, which will do the same thing:

rule 'Script - DisplayState' do
  description 'see if TV is turned on or off'
  channel 'harmonyhub:hub:HarmonyHub:activityStarted'
  received_command LightScene
  run do |event|
    display = items['DisplayState']
    harmony = items['HQHub_CurrentActivity']

    logger.info('Display Rule Activated')

    if harmony.state == 'Fernsehen' || harmony.state == 'ShieldTV'
      if display.state != ON
        display.command ON
        logger.info "Switching Display State #{display.state}"
      end
    end

    if harmony.state != 'Fernsehen' && harmony.state != 'ShieldTV'
      if display.state != OFF
        display.command OFF
        logger.info "Switching Display State #{display.state}"
      end
    end
  end
end

Thanks Jim I will have a look :wink:

Rich, I don’t think I wan’t to use something like blockly or nodered…

After playing with the syntax for channel triggers I realized that it actually works without any declaration. I think this must have been 'cause of the wrong location and the according strange behavior of the rule… so finally it’s working like expected

triggers.ChannelEventTrigger('astro:sun:local:rise#event')

this syntax now fires the rule :slight_smile: don’t know the exact reason what went wrong before, but I’m glad now…

Edit: ah, ok I see, Jim… thanks for your aditional explanations - I’ll go to bed now it’s 1am here in Germany - tomorrow is another day… :wink:

Thank you guys!