Prevent ECMA script from running multiple times

Is there a possibilty to prevent a javascript ECMA script from running multiple times if it is triggered by a group item.

On the old rules there was a possibility to use ReentrantLock is there an alternative on the new rule engine? Or can i use a global variable to store a bool value (e.g. running=true) that i can set on rule start/end?

It sounds like you want to use the Member of trigger and the event.itemName to get the name of the Item that triggered the rule. Then the rule will only be triggered once for the change.

If not that, you probably want to use Item changed as the trigger which can often (but not always) reduce the number of triggers to just the one.

Otherwise the answer is no because the rules are already locked. Only one instance of a rule can run at a time and additional triggers get queued up in a FIFO. Note that this is the case for all rules no matter the language, including Rules DSL, in OH 3.

If the above doesnā€™t help, if you post your rule I might be able to come up with something that works.

@rlkoshak thanks for the fast answere.

Iā€˜m writing a volume control for my sonos rule. This will be triggered when one volume item receives a command. Then it will search for all active members and calculates the new volume based on the percentage difference of the previous volume and send this to the other speakers.

The problem is that this will be done by sending a command and this will trigger the rule again.

I can not compare the item states at the beginning. Due to the percentage calculation it will never be equal and the rule runs again as a never ending loop.

In the past i used a lock to prevent this

Is there a possibility to use timers and check on rule start if a timer is running?
Then i can define a timer for on second and use this as lock function.

Yes, there are several ways you can do this with a Timer. Probably the easiest would be something like the following. NOTE: Iā€™m assuming you are working with MainUI to write the rules in OH 3.

this.ScriptExecution = (this.ScriptExecution === undefined) ? Java.type("org.openhab.core.model.script.actions.ScriptExecution") : this.ScriptExecution;
this.ZonedDateTime = (this.ZonedDateTime === undefined) ? Java.type("java.time.ZonedDateTime") : this.ZonedDateTime;

this.locked = (lock === undefined) ? false : true;
if(!lock){
  this.locked = true;
  var runme = function() { this.locked = false; }
  var now = this.ZonedDateTime.now();
  var timer = ScriptExecution.createTimer(now.plusSeconds(1), runme);
    
  // Your code goes here
}

You can do this even more simply using an Item and the conditions clause.

In your script actions:

his.ScriptExecution = (this.ScriptExecution === undefined) ? Java.type("org.openhab.core.model.script.actions.ScriptExecution") : this.ScriptExecution;
this.ZonedDateTime = (this.ZonedDateTime === undefined) ? Java.type("java.time.ZonedDateTime") : this.ZonedDateTime;

event.sendCommand("SonosVolumeLock", "ON");

var runme = function() { event.sendCommand("SonosVolumeLock", "OFF"); }
var now = this.ZonedDateTime.now();
var timer = ScriptExecution.createTimer(now.plusSeconds(1), runme);

// your code goes here

Then in the condition (ā€œbut only ifā€ section) choose ā€œan item has a given stateā€ and select SonosVolumeLock as the Item and equals OFF as the state. This will prevent the rule from running as long as SonosVolumeLock is ON.

1 Like

@rlkoshak great thanks. I prefere the first solution to keep all in the rule. This makes it later easier for others to use the rule

I just want to make it clear, the conditional (but only if) is every bit as much a part of the rule as the script action is. So what you are really saying is you want to keep it all part of the same script action.

But even then, when you go to the code view of the rule, it shows you everything: the triggers, the actions, and the conditionals. So itā€™s no harder to share if you use the second approach. The only thing that is really external is the lock Item which, if that were really a problem for you, you can actually create in your rule if it doesnā€™t exist. Iā€™ve several Jython scripts in my library that do just that. Iā€™ve not done it in JavaScript yet but thatā€™s only because it hasnā€™t been a priority yet.

Thanks for the clarification.

Can you share a link to your library? Maybe i can adapt this to javascript.

It would be useful for my heating control. On habpanel i used an json array as data storage. Was easy to read with angularjs. On the new mainui this is not possible (or im not aware that i can use some script inside rhe framework7 components) and making a split() command to get content of a json array is mostly impossible. So i need to split the settings in different items that can be created and deleted dynamically

Iā€™m already working to port this to JavaScript. Iā€™m making it stand alone for now so what Iā€™m working on is not dependent on the Helper Libraries, unlike the Jython version which is.

Iā€™m also stepping away from dynamically creating rules for these and moving back to using Group membership. Though I may come back to dynamically creating the rules again at some point. I havenā€™t fully decided yet.

I have ported time_utils, TimerMgr, and debounce so far, though havenā€™t checked them into the repo yet. I do not plan on porting Expire at all, not will I port item_init (doing Item initialization through MainUI is better now that itā€™s an option, see https://community.openhab.org/search?q=oh3%20examples) and am ambivalent about porting MQTT EventBus. Iā€™m about half way through porting ephem_tod,

But the code that actually creates and deletes Item in the Jython scripts above depend on the Helper Library. https://github.com/openhab-scripters/openhab-helper-libraries/blob/65ef09f2bf9a99b08aec893f267eabe02d71d9e7/Core/automation/lib/python/core/items.py There really is no JavaScript equivalent in the Helper Libraries as far as I can tell. But it shouldnā€™t be too hard to rewrite since almost all of the code is getting access to and making calls on core openHAB Java Objects which will be the same.

1 Like

Perfect i will try to create a js version the next days when my sonos rule is done