JavaScript examples that have worked for you. Put them here for others to use

No, that’s the representation of a Rule created in the UI with a JavaScript Script Action.

There are three syntaxes:

  1. ECMAScript 5.1 in .js files; the Helper Libraries help make this easier but is not required (though it’d be foolish not to use them).
  2. ECMAScript 5.1 in the UI for Script Actions and Script Conditions
  3. GraalVM ECMAScript 9 (i think) which is a separate add-on to install, note as of this writing installing it will break the build in ECMAScript 5.1 stuff.

In OH 3 almost everyone who is using JS is doing so through the UI. Those who are using file based rules are doing so using Jython or Rules DSL or one of the other rules languages.

Rules development in OH 3 is in my opinion hopelessly fragmented right now and I see no path forward. So I’m focusing on preparing myself for when we have a marketplace (OH 3.2 is the target for it right now) so I can make libraries installable like an add-on.

1 Like

Yep, it seems to be getting worse rather than better.

I’m going to plow on with my files.

I’m going to post some complete examples of simple functions here that I could have done with myself. All this is OH3 - a lot doesn’t work in OH2.5, works badly, or requires modifications.

function DoHttpGetRequest(sURL, sDesc, headers)
{
  //logInfo("DoHttpGetRequest " + sDesc + ": URL: " + sURL);

  var bAPICallOK = true;
  var response;
  var parsedResponse;

  try 
  {
    var HTTP = Java.type("org.openhab.core.model.script.actions.HTTP");    
    response = HTTP.sendHttpGetRequest(sURL, headers, 1000);      
    parsedResponse = JSON.parse(response);

    //logInfo("DoHttpGetRequest: " + sDesc + ": result: " + parsedResponse + "; unparsed result: " + response);
  } 

  catch(exception) 
  { 
    HandleHTTPException("DoHttpGetRequest", sDesc, exception, response);
    bAPICallOK = false;
  }     

  if (bAPICallOK)
  {
    return parsedResponse;
  }
  else
  {
    return null;
  }
}

POST is similar:

    var HTTP = Java.type("org.openhab.core.model.script.actions.HTTP");
    var result = HTTP.sendHttpPostRequest(sURL, sContentType, "", 10*1000);
    var objResult = JSON.parse(result);

HandleHTTPException is just a generic error-handling function I use to write a log entry.

This wait function is probably identical to one posted in another thread somewhere, possibly by Rich (which is where I got it from), but for completeness I’ll include it:

function Wait(fSeconds) 
{
  var ZonedDateTime = Java.type("java.time.ZonedDateTime");
  var ChronoUnit = Java.type("java.time.temporal.ChronoUnit");
  var CompletableFuture = Java.type("java.util.concurrent.CompletableFuture");
  var ScriptExecution = Java.type("org.openhab.core.model.script.actions.ScriptExecution");  

  var future = new CompletableFuture();
  var timer = ScriptExecution.createTimer(ZonedDateTime.now().plus(fSeconds*1000, ChronoUnit.MILLIS), function() 

  {
    future.complete(null);
  });

  future.get();
}

This tests whether a thing is online or not:

OpenHabHelpers.prototype.IsThingOnline =

function IsThingOnline(sThingUID)
{
  var Things = Java.type("org.openhab.core.model.script.actions.Things");
  var statusInfo = Things.getThingStatusInfo(sThingUID);

  if (statusInfo != null)
  {
    var status = statusInfo.getStatus();

    if (status != null && status == "ONLINE" || statusInfo == "ONLINE") 
    {
      return true;
    }
    else 
    {
      return false;
    }
  }
}

And these are rules in the format required by Crazy Ivan’s helper libraries:

On item update:

function Rule_OnAlexaVentilationOff(event) 
{
  alexaControl.OnVentilationOff();
}
when("Item AlxTrgOH_VentilationOff received update")(Rule_OnAlexaVentilationOff);
rule
(
    "Rule_OnAlexaVentilationOff",
    "Turn ventilation off via Alexa"
)(Rule_OnAlexaVentilationOff);

An on item change rule with multiple triggers:

function Rule_LastUpdate(event) 
{
  // Do stuff
}
when("Item SecondBedroomAeotecZW100Multisensor6_SensorLuminance changed")(Rule_LastUpdate);
when("Item SecondBedroomAeotecZW100Multisensor6_SensorRelativeHumidity changed")(Rule_LastUpdate);
rule
(
    "Rule_LastUpdate",
    "Does stuff"
)(Rule_LastUpdate);

And a rule with a 10-minute timer trigger:

function OnTimer_EveryTenMinutes(event) 
{
	// Do stuff
}
// @ts-ignore
when("Time cron 0 0/10 * * * ?")(OnTimer_EveryTenMinutes);
// @ts-ignore
rule
(
    "On timer:  (every 10 minutes)",
    "Does stuff"
)(OnTimer_EveryTenMinutes);

That’s not one of mine. When I wait and block while waiting I just call

java.lang.Thread.sleep(<number of milliseconds to wait>);

Using a CompletableFuture and a Timer just to wait a certain number of seconds seems like a lot of bother just to block a rule for a given amount of time. Maybe there is some reason I don’t see why one would want to do it this way.

If I don’t want to block while waiting I create Timers, and I do have a lot of timer management libraries.

I have no idea which is better :slightly_smiling_face:.

Probably I recall you countering with your own example.

Knowing how the two approaches actually work might show when/if one is better than the other.

`java.lang.Thread.sleep()

When a rule is executing (any rules programming language) and the user wants the rule to stop for a defined amount of time at that point, a call to java.lang.Thread.sleep() will halt the execution of the rule at that point for the defined number of miliiseconds. After that point the rule continues executing.

Wait() function

When a rule call this function it imports a bunch of needed Java classes. The rule then creates a CompletableFuture which is a class used to coordinate the activities between multiple threads in Java. Next a Timer is created for the given number of seconds. The timer will call complete on the CompletableFuture Object when it goes off. Finally future.get() is called which caused the rule to wait at that point until the timer goes off.

From the rules’ perspective the two do exactly the same thing.

But Thread.sleep is just a single line of code and a simple call to a core Java programming language feature.

However the Wait() function needs to be loaded, involves four different classes, and the instantiation of two different Objects (the CompletableFuture and the Timer), and the coordination between two separate threads (the rule’s thread and the Timer’s thread). That’s a whole lot of work and a lot of moving parts to do exactly the same thing that can be done with one line of code that is a core part of the language.

Unless there is something else going on that is not apparent, I can’t recommend the Wait function approach.

Some more:

function DoHttpPutRequest(sURL, sDesc, sContentType, sContent, headers)
{
  logInfo("DoHttpPutRequest " + sDesc + ": URL: " + sURL);

  var bCurrentAPICallOK = true;
  var response;
  var sResponseText;

  try 
  {
    var HTTP = Java.type("org.openhab.core.model.script.actions.HTTP");    

    response = HTTP.sendHttpPutRequest(sURL, sContentType, sContent, headers, 1000);  
    sResponseText = JSON.parse(response);

    //logInfo("DoHttpPutRequest: " + sDesc + ": result: " + sResponseText + "; unparsed result: " + response);
  } 
  catch(exception) 
  {    

    HandleHTTPException("DoHttpPutRequest", sDesc, exception, response);

    bCurrentAPICallOK = false;
  }     

  if (bCurrentAPICallOK)
  {
    return sResponseText;
  }
  else
  {
    return null;
  }
}

I took me a while to work out that I had to use the admin (openhabian) user/password here, rather than the cloud access one I use to access the REST API from outside.

function EnableOrDisableThing(sThingUID, bEnable)
{
  var sEncodedUID;
  var headers = [];

  headers['Content-Type'] = '*/*';
  headers['accept'] = '*/*';
  headers['Authorization'] = 'Basic <user:password encoded in BASE64 goes here>';
  headers['WWW-Authenticate'] = 'Basic';
  
  sEncodedUID = sThingUID.replace(/:/g, "%3A");

  var sResponseText = DoHttpPutRequest("http://openhabianpi:8080/rest/things/" + sEncodedUID + "/enable", "Enable/disable thing", "*/*", (bEnable ? "true":"false"), headers);
  //logInfo("EnableOrDisableThing: response text: " + sResponseText);    
}

This topic was automatically closed 41 days after the last reply. New replies are no longer allowed.