[SOLVED] Trigger Names with Javascript in JSR223 - Without optional Params

Converted over most of my rules to JSR223 using JS this weekend.

With JSR, we can name our triggers, which is pretty cool. I hadn’t done with DSL if it was possible.

From the migrating Time of Day to JSR223 JS post, I saw where the triggers could be named like this:

ChannelEventTrigger("astro:sun:local:rise#event", "START", "astroSunriseTrigger")

That astroSunriseTrigger will show in OH logs, which is nice.

My question is it possible to name the trigger without having the optional parameters in between?

For instance, CommandEventTrigger takes 3 params. 1- the item that receives the command, 2 - an optional command to lookout for, 3 - the trigger name, also optional.

ItemCommandTrigger = function(itemName, command, triggerName)

One of my rules is based off of every command sent to an item, so I need it to be all.

I have tried using null, “null”, “”, actually nothing, undefined, “undefined”, “ALL”, “*” and some others.

Is there some sort of wildcard I can pass in place of the second param to still take all commands?

Also, my rule does work as intended if I use just the itemName param and not try to name the trigger.

Yes, this should be possible… it definitely works in Jython. Are you using the helper libraries? Could you please provide an example script? I’ll go test…

Hey Scott - yes, I am using the helper libraries. Downloaded this weekend.

This is the rule I was talking about. In this case, I am trying to trigger this from any command to item “vTimeOfDay”.

As a side note - you will notice I have a sleep(1000), which is a separate JS function in this script file since JS does not have sleep. I can post that, or you can just comment out.

JSRule({
    name: "JM Blinds and Curtains Control",
    description: "Opens + Closes on Schedule",
    triggers: [
        CommandEventTrigger("vTimeOfDay")
    ],
    execute: function (module, input) {
        sleep(1000);
        var currentTimeOfDay = items["vTimeOfDay"].toString();
        if (items["JM_Sleeping_In"] !== ON) {
            switch (currentTimeOfDay) {
                case 'BED':
                    sendCommand("JohnSBlinds_", 0);
                    sendCommand("JM_Curtains_CommandString", "CLOSE");
                    logInfo("Blinds Control - Bed Complete");
                    break;
                case 'MORNING':
                    sendCommand("JohnSBlinds_", 85);
                    sendCommand("JM_Curtains_CommandString", "OPEN");
                    logInfo("Blinds Control - Morning Complete");
                    break;
                case 'NOON':
                    sendCommand("JohnSBlinds_", 30);
                    logInfo("Blinds Control - Noon Complete");
                    break;
                case 'AFTERNOON':
                    sendCommand("JohnSBlinds_", 50);
                    logInfo("Blinds Control - Afternoon Complete");
                    break;
                case 'NIGHT':
                    sendCommand("JohnSBlinds_", 85);
                    logInfo("Blinds Control - Night Complete");
                    break;
                default:
                    logInfo(currentTimeOfDay + " - I did nothing.");
                    return;
            }
            logInfo("Blinds Control - vTime is " + currentTimeOfDay);
            return;
        } else {
            logInfo("John is sleeping in.");
        }       
    }
});```
1 Like

Looks like you missed a few lines at the top.

Please post it or submit a PR. This would be a good utility function for the JS HLs!

1 Like

Updated previous post to correct missing JSRule part.

Had pasted correctly, but did not do a line break after the code fence, so it was cut off.

Here is super simple sleep function.

function sleep(millisecondsToWait) {
    var now = new Date().getTime();
    while (new Date().getTime() < now + millisecondsToWait) {}
}
2 Likes

I suggest you do this to avoid recalculating the same value over and over.

var then = new Date().getTime()
then += millisecondsToWait
1 Like

This is working for me…

'use strict';
var OPENHAB_CONF = Java.type("java.lang.System").getenv("OPENHAB_CONF");
load(OPENHAB_CONF + '/automation/lib/javascript/core/rules.js');
load(OPENHAB_CONF + '/automation/lib/javascript/core/actions.js');

JSRule({
    name: "JM Blinds and Curtains Control",
    description: "Opens + Closes on Schedule",
    triggers: [
        CommandEventTrigger("Virtual_Switch_1", null, "Test_Trigger_Name")
    ],
    execute: function (module, input) {
        LogAction.logWarn("Rules", "Test")
    }
});

Out of curiousity, why did you chose to use JS over Jython?

@CrazyIvan359 - Tried this and it wasn’t actually waiting X milliseconds.

@5iver - I am an absolute idiot. I am so sorry for sending you on this goose chase. But THANK YOU!

As soon as I saw your post, I realized what I did… I had a space in the trigger name and wasn’t paying enough attention to the logs. Feel like an absolute idiot.

You are correct, that does work. I just tested as well.

JS v Jython - Only experience I have coding at all is coding scripts for Google Sheets, which uses JS. Simply chose it because it was familiar, despite having some limitations.

Edit @5iver - Should event.itemCommand be working in the JS libraries? Was only able to get it work using input[‘event’].itemCommand

If this is a bug, will happily raise issue on GitHub.

1 Like

No worries at all! I needed a break and I like getting into the JS libraries now and then. Just shout if there’s anything else giving you trouble!

I suggest trying Jython. It is surprisingly easy to pickup. There’s still a lot of work in triggers.js and rules.js to make the functionality similar to Jython, but I’ll probably wait until jdk11 with es6 works with OH. In the Jython libraries I do a validation of the trigger names. Make sure the names are unique within the rule and only use alphanumerics and underscores.

No, not yet! You’ll need to use input[‘event’].itemCommand.

1 Like

Appreciate you helping!

If Jython features are more fully fleshed out than JS, may def be worth looking into for sure. There are a lot of goofy things about JS. Will definitely take a look!

Thanks again!

Edit - Thanks for clarification on the event.itemCommand. I got it working via the other method working, so just wanted to make sure!

1 Like

Please post that to the DP posting as well when it’s working.

Wouldn’t a timer be more appropriate for JS, not because of threading issues like in Rules DSL but because, from what I’ve read, blocking like that is considered erroneous behavior in JS, hence the lack of a sleep function in the first place.

In formulating my reply, I remembered that I’m already using a sleep in the startup delay

var Thread = Java.type("java.lang.Thread");
Thread.sleep(10000);

No need to create a utility function when Java provides one!

1 Like

Smacks head. Of course, all the Java stuff is available too. The question still arises, is it strictly correct to block like that in JS? What is correct and what is expedient may not be the same thing in the openHAB context, but I’ve read lots of postings from people who feel very strongly that even in Nashorn JS should never block like that.

I really don’t have the experience with JS or Nashorn to answer. Maybe @lewie can help with this one?

@rlkoshak and @5iver - IIRC, the lack of JS Sleep is due to being so heavily used in websites. A JS function sleeping could miss user clicks, cause major delays in page loads, etc. That is why it relies on stuff such as setTimeout since it is Async, while sleep is sync.

Will definitely switch to the Java sleep since that is already built in! Hadn’t even thought of that…

Rich - Can you clarify this statement? I am not sure what you are asking me to post :confused:

You are migrating your implementation of the Time of Day Design Pattern to JavaScript. The current post as a Rules DSL and Jython example, but no JavaScript version. I’d appreciate the opportunity to add a JavaScript example. You can add your JS example as a reply and I’ll put it in the OP.

Ahh gotcha. I just followed this topic, which is very detailed write up of JS Time of Day: Migrating DSL Rules to JSR223/Javascript with a case example

This is all still a work in progress FYI.

My version:

JSRule({
    name: "Time of day",
    description: "Calculates the time of day, depending on several triggers",
    triggers: [
        ChannelEventTrigger("astro:sun:local:rise#event", "START", "astroSunriseTrigger"),
        ChannelEventTrigger("astro:sun:local:noon#event", "START", "astroNoonTrigger"),
        ChannelEventTrigger("astro:sun:local:set#event", "START", "astroSunsetTrigger"),
        ChannelEventTrigger("astro:sun:minus90:set#event", "START", "astroSunsetDelayTrigger"),
        TimerTrigger("0 1 0 * * ? *"), // one minute after midnight so give Astro time to calculate the new day's times
        TimerTrigger("0 0 8 * * ? *"),
        TimerTrigger("0 0 23 * * ? *")
    ],
    execute: function( module, input){
        // Get the current time as number
        var now = new Date().getTime();
        //Get the vTimeOfDay item as json object
        var currentTimeOfDay = getItem("vTimeOfDay");

        logInfo("Calculating time of day...");

        // Calculate the times for the static times
        var morning_start = new Date().setHours(7, 59, 59, 0); // .setHours(Hour, Minute, Second, Millisecond)
        var bed_start = new Date().setHours(0, 0, 0, 0);

        // Get the astro calculated times as numbers for comparison
        var day_start = new Date(getItem("vSunrise_Time").state).getTime();
        var noon_start = new Date(getItem("vNoon_Time").state).getTime();
        var afternoon_start = new Date(getItem("vEvening_Time").state).getTime();
        var evening_start = new Date(getItem("vSunset_Time").state).getTime();

        // Calculate the current time of day
        var curr = "UNKNOWN"

        if(now > bed_start)         curr = "BED";
        if(now > morning_start)     curr = "MORNING";
        //if(now > day_start)         curr = "DAY";
        if(now > noon_start)        curr = "NOON";
        if(now > afternoon_start)   curr = "AFTERNOON";
        if(now > evening_start)     curr = "NIGHT";

        // Publish the current state
        if(currentTimeOfDay.state != curr) {
           logInfo("Current time of day is now " + curr);
           sendCommand(currentTimeOfDay, curr);
        }
    }
});

And here is a rule based on update to the vTimeOfDay Event. IIRC, there is no “noon” in the Time of Day and that is something I added.

JSRule({
    name: "JM Blinds and Curtains Control",
    description: "Opens + Closes on Schedule",
    triggers: [
        CommandEventTrigger("vTimeOfDay", null, "TOD_Trigger")
    ],
    execute: function (module, input) {
        var currentTimeOfDay = items["vTimeOfDay"].toString();
        if (items["JM_Sleeping_In"] !== ON) {
            switch (currentTimeOfDay) {
                case 'BED':
                    sendCommand("JohnSBlinds_", 0);
                    sendCommand("JM_Curtains_CommandString", "CLOSE");
                    logInfo("Blinds Control - Bed Complete");
                    break;
                case 'MORNING':
                    sendCommand("JohnSBlinds_", 85);
                    sendCommand("JM_Curtains_CommandString", "OPEN");
                    logInfo("Blinds Control - Morning Complete");
                    break;
                case 'NOON':
                    sendCommand("JohnSBlinds_", 30);
                    logInfo("Blinds Control - Noon Complete");
                    break;
                case 'AFTERNOON':
                    sendCommand("JohnSBlinds_", 50);
                    logInfo("Blinds Control - Afternoon Complete");
                    break;
                case 'NIGHT':
                    sendCommand("JohnSBlinds_", 85);
                    logInfo("Blinds Control - Night Complete");
                    break;
                default:
                    logInfo(currentTimeOfDay + " - I did nothing.");
                    return;
            }
            logInfo("Blinds Control - vTime is " + currentTimeOfDay);
            return;
        } else {
            logInfo("John is sleeping in.");
        }       
    }
});

I forgot about that post. That might be the example I need right there. Thanks! I’ll get someone’s JavaScript example in the DP.

1 Like

Oh - Something that really tripped me up… In that other post, his Astro Sun Thing is called “home”, which therefore, affects the channels in that example.

When Astro Sun is added via Paper UI, it defaults to calling it “local” instead of home.

That may be worth mentioning in your post as it got me GOOD for awhile.

Just jumping in here:

If there’s something additional to improve in my tutorial, feel free to give me some feedback over there.

I have to add/change some things anyway now since the libraries can be pulled from GitHub now.

1 Like