Timer reset in js rule

Hello,

I use this script

rules.JSRule({
  name: "Switch TV automated off",
  description: "Switch TV automated off",
  triggers: [triggers.ItemStateChangeTrigger("switch_tvlivingroom_debouncedpresence"), triggers.ItemStateChangeTrigger("Z_way_number_WallPlug10_actualpower")],
  execute: (event) => {
                if (items.Z_way_number_WallPlug10_actualpower.numericState < 14){
                        console.log("Switch TV automated off, start timer");
                        actions.ScriptExecution.createTimer('timertvautomation', time.toZDT().plusSeconds(300), () => {
                                if (items.Z_way_number_WallPlug10_actualpower.numericState < 14){
                                        console.log("Switch TV automated off", "off");
                                        items.getItem("Z_way_switch_WallPlug10").sendCommand("OFF");
                                        console.log("Switch TV automated off", items.Z_way_switch_WallPlug10.state);
                                }
                        });
                }
        },
  tags: ["Automation", "TV"],
  id: "Switch TV automated off"
});

But the rule gets triggered everytime the power value is changed…How can I simply reset the timer and not creating a new timer everytime?

This is the way how I do it in another DSL rule

var Timer MovementTimer = null
rule “BI Motion FC”
when
    Item BI_FC_Motion changed from OFF to ON
then
....
    if (MovementLightsOn == true) {
        MovementTimer?.cancel
        MovementTimer = createTimer(now.plusSeconds(20), [| LS_FrontOutside.sendCommand(OFF)])
        ...
    }
end

But there is no cancel function in the js automation documentations…or at least I haven’t seen it

The return value is an openhab Timer object, so you can call cancel on it.

FYI jruby makes this easier using reentrant timer (timer with an ID automatically resets / reschedules when re-entered)

# This is a file-based JRuby rule. It can be implemented as a UI rule too
rule "Switch TV automated off" do
  description "Switch TV automated off"
  tags "Automation", "TV"

  # triggers:
  changed switch_tvlivingroom_debouncedpresence
  changed Z_way_number_WallPlug10_actualpower

  # condition:
  only_if { Z_way_number_WallPlug10_actualpower.state < 14 }

  # execution:
  run do
    logger.info "Switch TV automated off, (re)start timer"
    after 5.minutes, id: Z_way_number_WallPlug10_actualpower do
      next unless Z_way_number_WallPlug10_actualpower.state < 14

      logger.info "Switch TV automated off, switching off"
      Z_way_switch_WallPlug10.off
    end
  end
end

Note: JRuby’s after method returns an openhab Timer object too, but there’s no need to do anything special with it because the reset is already handled for you when id is specified. For more info see after

I tried cancel already but getting this error

var tvautomatedofftimer = null;

rules.JSRule({
  name: "Switch TV automated off",
  description: "Switch TV automated off",
  triggers: [triggers.ItemStateChangeTrigger("switch_tvlivingroom_debouncedpresence"), triggers.ItemStateChangeTrigger("Z_way_number_WallPlug10_actualpower")],
  execute: (event) => {
                if (items.switch_automation.state.toString()  == "ON") {
                        if (items.Z_way_number_WallPlug10_actualpower.numericState < 14) {
                                console.log("Switch TV automated off, start timer");
                                tvautomatedofftimer.cancel();
                                tvautomatedofftimer = actions.ScriptExecution.createTimer(time.toZDT().plusSeconds(300), () => {
                                        if (items.Z_way_number_WallPlug10_actualpower.numericState < 14){
                                                console.log("Switch TV automated off", "off");
                                                items.getItem("Z_way_switch_WallPlug10").sendCommand("OFF");
                                                console.log("Switch TV automated off", items.Z_way_switch_WallPlug10.state);
                                        }
                                });
                        }
                } else {
                        console.log("Switch TV automated off", "Master automation switch is off");
                }
        },
  tags: ["Automation", "TV"],
  id: "Switch TV automated off"
});

I also tried this version

var tvautomatedofftimer = null;

rules.JSRule({
  name: "Switch TV automated off",
  description: "Switch TV automated off",
  triggers: [triggers.ItemStateChangeTrigger("switch_tvlivingroom_debouncedpresence"), triggers.ItemStateChangeTrigger("Z_way_number_WallPlug10_actualpower")],
  execute: (event) => {
                if (items.switch_automation.state.toString()  == "ON") {
                        if (items.Z_way_number_WallPlug10_actualpower.numericState < 14) {
                                console.log("Switch TV automated off, start timer");
                                tvautomatedofftimer.cancel();
                                actions.ScriptExecution.createTimer('tvautomatedofftimer', time.toZDT().plusSeconds(300), () => {
                                        if (items.Z_way_number_WallPlug10_actualpower.numericState < 14){
                                                console.log("Switch TV automated off", "off");
                                                items.getItem("Z_way_switch_WallPlug10").sendCommand("OFF");
                                                console.log("Switch TV automated off", items.Z_way_switch_WallPlug10.state);
                                        }
                                });
                        }
                } else {
                        console.log("Switch TV automated off", "Master automation switch is off");
                }
        },
  tags: ["Automation", "TV"],
  id: "Switch TV automated off"
});
Failed to execute action: 1(Error: Failed to execute rule Switch TV automated off: TypeError: null has no such function "cancel": TypeError: null has no such function "cancel"
if (tvautomatedofftimer !== null) tvautomatedofftimer.cancel();

I think jsscripting has the ?. syntax too but I’m not familiar with it.

Don’t you need to save the return value as your timer in order to be able to cancel it? You’ve got a name for logging, but that’s not the actual timer.
https://openhab.github.io/openhab-js/actions.ScriptExecution.html#.createTimer

tvautomatedofftimer = actions.ScriptExecution.createTimer('tvautom...

This is the solution:

var tvautomatedofftimer = null;

rules.JSRule({
  name: "Switch TV automated off",
  description: "Switch TV automated off",
  triggers: [triggers.ItemStateChangeTrigger("switch_tvlivingroom_debouncedpresence"), triggers.ItemStateChangeTrigger("Z_way_number_WallPlug10_actualpower")],
  execute: (event) => {
                if (items.switch_automation.state.toString()  == "ON") {
                        if (items.Z_way_number_WallPlug10_actualpower.numericState < 14) {
                                console.log("Switch TV automated off, start timer");
                                if (tvautomatedofftimer !== null) tvautomatedofftimer.cancel();
                                tvautomatedofftimer = actions.ScriptExecution.createTimer('tvautomatedofftimer', time.toZDT().plusSeconds(300), () => {
                                        if (items.Z_way_number_WallPlug10_actualpower.numericState < 14){
                                                console.log("Switch TV automated off", "off");
                                                items.getItem("Z_way_switch_WallPlug10").sendCommand("OFF");
                                                console.log("Switch TV automated off", items.Z_way_switch_WallPlug10.state);
                                        }
                                });
                        }
                } else {
                        console.log("Switch TV automated off", "Master automation switch is off");
                }
        },
  tags: ["Automation", "TV"],
  id: "Switch TV automated off"
});

But why is it not documented the cancel funtion?

Are you asking where the cancel method is documented, or why you need to check for null prior to using the cancel method? Below has the timer documentation which does show a check for null as an example (in DSL, but the same concept applies to JS). Other useful methods are also documented there.

ScriptExecution.createTimer is an openhab core’s method that returns an openhab core Timer object. It doesn’t matter whether it’s called from jsscripting, jruby, rulesdsl, it will return the same core timer object.

The documentation for the timer object is here
https://www.openhab.org/javadoc/latest/org/openhab/core/automation/module/script/action/timer

Every other documentation (dsl, jsscripting, jruby) is simply documenting the core interface above, but adapted to their respective language syntax.

Just to complete the circle, all the methods supported by timers is documented in the JS Scripting add-on docs as well.