JS Scripting Rule: Trigger on Delta Change of 2 or More?

Hi everyone,

I’m trying to create a JS Scripting rule in openHAB (I’m on OH 3.x) that triggers only when an item’s numeric state changes by 2 or more. I’m using doubleValue to ensure precision.

Here’s what I have so far:

rules.JSRule({
  name: "Trigger on delta ≥ 2",
  description: "Runs when item changes by 2 or more",
  triggers: [triggers.ItemStateChangeTrigger('MyItem')],
  execute: (event) => {
    const oldValue = event.oldItemState.doubleValue;
    const newValue = event.itemState.doubleValue;
    const delta = Math.abs(newValue - oldValue);

    if (delta >= 2) {
      console.log(`Triggered: delta is ${delta}`);
      // Perform action
    } else {
      console.log(`No trigger: delta is ${delta}`);
    }
  }
});

It works in general, but I want to be sure:

  • Is this the best way to handle delta comparisons in JS Scripting?
  • Is there a more efficient or native way to trigger only when a delta of ≥ 2 occurs?
  • Could this miss any edge cases (like null state, non-numeric items, or persistence issues)?

Any improvements or suggestions would be appreciated!

Thanks!

Doesn’t matter the rules language (except maybe jRuby which does some stuff like this), you cannnot trigger a rule like that. You can trigger the rule when the Item changes and then have a rule condition only run the rule if it’s a change by 2 or more. But especially in OH 3 the only place where there are rule conditions is managed rules (i.e. UI rules). So you’ll need to add an if statement to your rule to ignore any chnages under 2, which is what you’ve done.

I don’t know if it’s more effecient, but one of the main reasons I move to all managed rules. There’s a whole section of the rule where you can evaluate stuff like this and prevent the actions from running.

And I think even way back in OH 3 the rule builder for JS included a condition clause that you could use for rule conditions. But I don’t think the event gets passed into the if so you’d have to use persistece and hope that persistence has updated in time (in OH 5 the Item will carry a previousState property that doesn’t depend upon persistence). It would look something like this for OH 3.

rules.when().item("MyItem").changed().if( ()=> { 
      let i = items.getItem('MyItem');
      return Math.abs(parseFloat(i.state), parseFloat(i.history.previousState)) >= 2;
    })
    .then( event => {
        console.info("The delta is > 2");
    }).build("Trigger on delta >= 2");

Your original rule indeed will throw an error if the state of the Item is null and of course it’s meaningless to do a subtraction and the absolute value of a Switch Item so indeed, you have to watch out for that. You can add a test for NULL and UNDEF with items.getItem('MyItem').isUninitialized.

Your current rule does not use persistence so that’s not a concern. My builder exaple with the condition does use persistence so that could be a problem.

Note, there are many changes in OH 4 and OH 5 which impact my example code above, for example “.history” has become “.persistence” and the Item will have a lastUpdate and lastChanged properties instead needing to use persistence. There have been things added to rule builder too which might be useful.

Other things you can do is use a profile to only change the Item with the new state from the Channel is above a thershold. There’s a bunch of options in the “Generic Profiles” add-on which is only available in OH 4 unfortunately. And I’ve published a JS transofrmation which could be used with the SCRIPT profile to do the same. However, I don’t think it will work with OH 3 either. I don’t think OH 3 supported passing arguments to transformations. Filter Profile But you can card code the thershold and get rid of the ID part.