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

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

Sounds good. I am planning to relook at my implementation of your tutorial over the weekend. I have had a few days of messing with JS rules, so feel as if I have a better grasp on them now.

Will post anything I find over there! Only thing so far is what I said in post above about “local” sun when adding via Paper UI.

Thanks for helping make the transition over to JS easier!

1 Like

Just as a second to the why js over jython. I also have coded all of my rules in js and prefer it as that is what I have more experience in. Also seems more intuitive to me when I get stuck to be able to browse the native openhab java classes and work with them directly in js. Just my two cents

1 Like