Simple-sleep-wait-example-with-ecma-script

Hey all…

Since 3.4.2 I have a issue after installing Java17 and not more Java 11.
Simple rules for wait, e.g. 5 sec will not more run.

E.g. java.lang.Thread.sleep(5000);

What is now exactly the Syntax in Java 17 to have a rule to wait for 5 sec?

BTW: I know the solution Nashorn binding, but this is not what I want, to have an additional binding.

Br
Jochen

Which openHAB are you running?

OH3 needs Java 11
OH4 needs Java 17

So if you’re still on OH3, move back to Java 11.

First, Tutorials and Examples should only be used for posting complete solutions, not for requesting solutions. I’ve moved this to a more appropriate category.

Second, in addition to the java version issue, having rule logic that utilizes sleep is usually (not always) a red-flag. There is almost certainly a better way to handle whatever the sleep command is providing for you, especially if you’re using JSScripting and the included helper library. Post the rule code and probably someone can point you in a more js appropriate direction.

1 Like

Thanks.

Yes, I’m still running on OH3.
But I assume, that with OH4, Java 17 is needed I then I ned a solution for the wait issue…

Thanks here as well,

Then I hope some in the area, has a script and some syntax for me for a “wait of 5 sec”,
so, that I can upgrade to OH4.0 and use JAVA 17.

BR
Jochen

openHAB 4.0 has not been released yet and is not ready for productive use.

Use blockly and it will create the requested code for wait or (better) timer

There is no technical reason why you shouldn’t use sleep. Sleep is even supported with OH 4. To know what the issue is it would make sense if you provided your code. (and, yes, blockly does use sleep in one of its blocks)

If you want ECMA Script you must install one of the two JS add-ons.

Which one you install dictates the syntax used for a “sleep”. But, as mentioned, a sleep in a rule is almost always a code smell and there is almost always a better/safer/more reliable approach.

While a rule is running, subsequent triggers of that rule are blocked and queued up. Couple that with the fact that most cases where I’ve seen a wait used in a rule the wait adds minutes or even worse, an indeterminate amount of time (the rule may never stop waiting).

I’ve seen rules where a sequence of events is scheduled out using sleeps connected to a button a person presses (light switch, door bell, etc.) and if there is even a little bit of a delay the human spams the button essentially locking up that one rule for hours.

Note, there is a max time a rule can be running before OH will kill it with an exception. So there are at least some protections, but the time is quite long (five minutes IIRC).

Another place where it becomes a problem is more of an advanced topic. If you have a rule that calls another rule, and the called rule has a sleep, subsequent calls to that rule will generate the multi-threaded exception. I think there was some explorations over using a lock in the call but that just turns the problem into the first problem.

I’m not sure what happens with the other languages that do not have the limitations on multi-threaded access to the context that GraalVM JS Scripting does. I suspect what happens is we end up with the old Rules DSL behavior where the multiple instances of the called rule run at the same time and interfere with each other (e.g. overwriting variables).

Stefan thanks for you offer to check the code…

So far I have had OH3.4.1 and Java 11 in use
I have sveral rules which check the power of the powerplug and switch off the powerplug, e.g. when the mobile is fully loaded.
So fare I have done this with a blockly script and a “wait rule script” to check, e.g. ever 2min if the power is less, e.g. 1,5 W. Please see here…

image

image

image

After now installing 3.4.2 I get an error and the scripts are not more running, bcause the installtation told me to install Java 17 in needed. I have instralled Java 17 and the wait script is not more running.

Going back to Java11 works, but when OH4.0 comes I need anyhow to switch to Java17.

So I’m easy looking for a replacement for my wait from 120 sec. wait script under Java 17 conditions

Any idea?

BR
Jochen

As mentioned, OH 3 is backed by Java 11 and only OH4 by Java 17. I see no reason why the above code wouldn’t work on OH4. Just use the the timer blocks to wait for 120 seconds.

see Rules Blockly - Timers & Delays | openHAB

If you are using Blockly you don’t have to do anything. When you upgrade to OH 4 you can open and save your rules and they will be recompiled to GraalVM JS Scripting automatically for you.

You will have to install the GraalVM JS Scripting add-on separately though, No JS comes with OH any longer as of OH 4. Only Rules DSL comes by default and even that is being looked at to remove and move to an add-on.

That was a temporary error. That message was incorrect and has since been corrected. You should remain on Java 11 for 3.4.2.

You don’t have to worry about it. @stefan.hoehn and @florian-h05 spent a lot of time making sure that your Blockly scripts will upgrade with minimal effort on your part. But again, you will have to install the JS Scripting add-on. There is no getting around that.

A much better approach for this is to use a cron trigger.

Let’s say that FlurSteckdose_Leistung updates every 10 seconds (which is pretty slow compared to what I’ve seen most of these power sensors report).

This rule triggers and immediately sleeps for 2 minutes. In that two minutes, the rule is retriggered 12 more times before the first one runs. Finally the rule runs and does it’s thing and then it runs again, waits two more minutes and an addition 12 triggers pile up in the mean time. Now we have 23 triggers of this rule queued up waiting to run. Two minutes later the rule runs again but in the mean time 12 more triggers piled up. Now we have 34 triggers of this rule waiting to run. At this point those remaining 10 triggers of the rule are probably starting to time out so you’re probably topped out at around 34 triggers of the rule always waiting to run at all times.

You can achieve the behavior you are after (i.e. every two minutes check if the power is less than 1.5 W) by using a cron trigger to run the rule every two minutes (get rid of the other triggers), add a condition to check if FlurSteckdose_Leistung is below 1.5 W and maybe another one to check if FlurSteckdose_Betrieb is ON, and your script action just needs to send command to FlurSteckdose_Betrieb. You don’t even need Blockly for this.

If you change your requirement to turn the switch off when it uses < 1.5 W for two minutes then it’s better to use a Timer. In that case, trigger the rule when FlurSteckdose_Leistung changes only. In the script action (in JS Scripting):

var currState = Quantity(event.itemState.toString());
var threshold = Quantity('1.5 W');

// If the current state < 1.5 W create the timer if it doesn't exist
if(currState.lessThan(threshold) && cache.private.get('timer') === null) {
  cache.private.put('timer', actions.ScriptExecution.createTimer(time.toZDT(120000, () => {
    console.log('switch power off');
    items.FlurSteckdose_Betrieb.sendCommand('OFF');
  }  
}  
// If the current state is above the threshold and the timer exists, cancel the timer
else if(cache.private.get('timer') !== null) {
  cache.private.get('timer').cancel();
}

The above code creates a timer as soon as the wattage drops below 1.5 to wait for two minutes. If there is a timer and the wattage is >= 1.5 the timer gets cancelled. As a result, the Item will only be commanded to OFF when the wattage has measured under 1.5 W for two minutes.

Thank you very much for the explanation rlkoshak.
But the timer (Sleep) has an other job to do…

When start the rule, an the rule has no sleep it switches directly off, because is has by start 0 W or less that 1,5 W. So it is only a hysteresis at the begin, to wait until everything has “booted”
So the sleep with 120sec is for a wait of that the e.g. mobile, or in one other case my charger for my e-bike, which needs to boot up ~ 1min. The same with my digital camera for charge.

So the logic start the rule by switch on the plug, wait for 120 sec, and if it less than 1,5 W send an off to the plug…

Maybe you can change the script for me…

The above rule does that too. It won’t turn off the switch until the Item has been under 1.5 W for two minutes. So when the rule starts you still get that two minute delay before any action is taken.

That’s exactly what the timer rule does, whether it’s at OH boot or any other time. Only when the Item is < 1.5 W for at least two minutes will the switch be turned OFF.

Hello rlkoshak,

I have now created the rule from your example. When I switch the plug on, the rule starts, but I get this error in the logfile:

2023-04-28 07:56:17.859 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'a52a367337' failed: <eval>:6:85 Expected an operand but found )
  cache.private.put('timer', actions.ScriptExecution.createTimer(time.toZDT(120000, () => {
                                                                                     ^ in <eval> at line number 6 at column number 85

What is wrong in line 6? As I’m not a developer and cannot generate source code, could you please help me?

I’m using for testing now a other plug, and the item ist called: WeihnachtsbeleuchtungInnen_Betrieb
Here is once more the script:

var currState = Quantity(event.itemState.toString());
var threshold = Quantity('1.5 W');

// If the current state < 1.5 W create the timer if it doesn't exist
if(currState.lessThan(threshold) && cache.private.get('timer') === null) {
  cache.private.put('timer', actions.ScriptExecution.createTimer(time.toZDT(120000, () => {
    console.log('switch power off');
    items.WeihnachtsbeleuchtungInnen_Betrieb.sendCommand('OFF');
  }  
}  
// If the current state is above the threshold and the timer exists, cancel the timer
else if(cache.private.get('timer') !== null) {
  cache.private.get('timer').cancel();
}

And as a picture:

Thanks in advanced.

Typo in the code:

...ion.createTimer(time.toZDT(120000), () => {

Hello Rich,

thanks for the correction, the script runs now without an error, but it doesent work.
It is still running when I pull out the mobile from the USB connector and the plug has less then 1.5 Watt than.

2023-04-28 18:45:56.195 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'WeihnachtsbeleuchtungInnen_Leistung' changed from 10.92 W to 0 W

here are the items from the thing…

In which line of the script, you are checking, if it the item “WeihnachtsbeleuchtungInnen_Leistung” has less than 1.50 W ?

there are two different items. One for power (watt) WeihnachtsbeleuchtungInnen_Leistung, and one for on / off, WeihnachtsbeleuchtungInnen_Betrieb

BR
Jochen

Right, it will wait for two minutes after if falls below 1.5 W before it turns off the switch.

Screenshots are next to useless on the forum. When available, always copy the contents of the “Code” tab and use code fences.

```
code goes here
```
if(currState.lessThan(threshold)

The rule should get only when triggered when WeihnachtsbeleuchtungInnen_Leistung changes. Therefore event.itemState will be the amount of power reported by the outlet.

var currState = Quantity(event.itemState.toString());

This line converts the incoming state, i.e. the state of WeihnachtsbeleuchtungInnen_Leistung, to a form easier to do math and comparisons with in the rule.

var threshold = Quantity('1.5 W');

This line creates a variable to hold the amount where if the state falls below that amount we create a two minute timer before turning off the switch.

And finally

if(currState.lessThan(threshold)

This part of the line will only be true if the Item that triggered the rule’s current state < 1.5 W.

Again, the WeihnachtsbeleuchtungInnen_Betrieb will only receive an OFF command when WeihnachtsbeleuchtungInnen_Leistung remains below 1.5 W (exclusive, if it’s exactly 1.5 W no OFF command will ever be sent) for two solid minutes. If WeihnachtsbeleuchtungInnen_Leistung ever jumps above 1.5 W, even for a moment, the timer will be reset and you’ll have to wait another two minutes.

Once more thanks Rich for all the information.

I have now tryed what ever come in my mind.
But it will not work.
The power goes down less that 1.5 W but after 120sec not automatic send “OFF” to the switch.
It stay on and on, and on…

Sorry…

BR
Jochen

Does it stay below 1.5 W the whole two minutes? Show events.log.

And it’s below 1.5 W. If it’s 1.5 W that doesn’t count.