Best Practise: 10Min timer?

My use case is as follows:

  1. I turn on the coffee machine (porta filter)
    It needs about 10-15mins pre-heating
  2. I forget about it (damn you, ADHD… :wink: )
  3. I’ll remember hours later
  4. coffee machine is on standby

So what I need is a rule, which trigger some of my Alexas or even notifications on my openHAB App to remind me like 10mins later.

What’s the best practise for that with JS Scripting at best? Can a timer run 10mins? or is it better to use an proxy item with expire-metadata?

btw: I tried the following, but the code wouldn’t wait 10mins?

// Announce
var echoAnnounce = function(echo) {
  items.getItem(echo).sendCommand("You can make your coffee now!");
  console.log("INFO COFFEE: Kaffemaschine ist heiß.");

}

// Durchsage in Küche
var timeoutKueche = setTimeout(echoAnnounce("AMZ_EchoBath_Ankundigung"), 600000);

// Durchsage in Office
var timeoutOffice = setTimeout(echoAnnounce("AMZ_EchoOffice_Ankundigung"), 600500);

// Durchsage in Keller
var timeoutOffice = setTimeout(echoAnnounce("AMZ_EchoBasemnt_Ankundigung"), 601000);

I’m not really sure what is the recommended best practice but for me more and more I’ve been trying to get away from direct scripting for rules toward gui based if possible. I had created a bunch of simple javascript based expiry rules some time ago that all broke with the new version 4 and java 17 so I switched to expire metadata based for each and is seems to work well now.

In the past expire metadata was reset by any state change in the item but it appears at some point a new switch was added to the expire metadata for ‘ignore state updates’ that makes it work much more like what you would expect from an expiry timer

Cheers

that’s how I don’t forget the open toilet window. There is no problem with long timer setting.

var {OH_function} = require ('./kroenert/index.js');

// falls Fenster geöffnet wurde
if (event.itemState.toString() == 'OPEN' ){
  var iCounter       = items.getItem('FS01_WindowCounter');
  var iTime          = items.getItem('FS01_Timestamp');
  var temperature    = parseFloat(items.getItem('LS01_Sensortemperature').state);
  var volume         = 20;
  var sound          = 4;  
  var message_1      = ['0Toilettenfenster zu lange offen',volume,sound];
  var message_2      = ['0Toilettenfenster nicht vergessen']; 
  var Minute         = 60000;
  if (isNaN(parseFloat(iCounter.state)) ) iCounter.postUpdate(1);
  else iCounter.postUpdate(parseFloat(iCounter.state)+1);
  
  iTime.postUpdate(Date.now());  // Datum in Timestamp speichern
  if (typeof timer !== 'number'){
    if (temperature <= 0 ) {         
      var timer = setTimeout(function() {OH_function.sendMessage(message_1)},5 * Minute ); 
    }
    else if ((temperature > 0 ) && (temperature <= 13 )) {         
      var timer = setTimeout(function() {OH_function.sendMessage(message_1)},10 * Minute ); 
    }
    else {                           
      var timer = setTimeout(function() {OH_function.sendMessage(message_2)},15 * Minute );   
    }
  }
}

//falls Fenster geschlossen wurde -> Timer löschen
else{
  if (typeof timer === 'number') {
    clearTimeout (timer);
    timer = undefined ;
  }  
}
2 Likes

I don’t know much about javascript, but it seems to me that you are calling your anonymous function (echoAnnounce) at the time you’re calling setTimeout, so it is executed immediately.

You need to pass that anonymous function as a variable, and let setTimeout call it.

Once again I don’t know much about javascript but it might look like this

var timeoutKueche = setTimeout(echoAnnounce, 600000, "AMZ_EchoBath_Ankundigung");

This has a lot of really good info… you can also use an arrow function (maybe)

setTimeout(() => echoAnnounce("AMZ_EchoBath_Ankundigung"), 600000);
1 Like

Are you interested in blockly, too? Then I guess I got a nice solution for you: It’s got a rolling timer so that you can display the remaining time in the UI. And it survives a reboot and continues the remaining time. I’m currently on my phone but would copy the code at the PC if anybody is interested.
I made it for my coffee machine too:)

1 Like

Here my solution for a coffee-machine-timer:

First the code. You can create a new rule, then switch to the code tab and paste this code. Then adapt to your need.

Click to see code
configuration: {}
triggers:
  - id: "2"
    configuration:
      itemName: PlugKaffee
    type: core.ItemStateChangeTrigger
  - id: "3"
    configuration:
      startlevel: 100
    type: core.SystemStartlevelTrigger
conditions: []
actions:
  - inputs: {}
    id: "1"
    configuration:
      blockSource: <xml
        xmlns="https://developers.google.com/blockly/xml"><variables><variable
        id="}_`%y0{BF@~znZ]hhVm`">countdown</variable><variable
        id=")b_R[t#kX_SC?vi;Po0w">startLevel</variable><variable
        id="eLE$]xb7:LsH*wrcl7VE">timer</variable><variable
        id="cGn0#jI2g*d+OLKC41y:">newState</variable></variables><block
        type="variables_set" id="Mpm`u?#};Q3fsZGKZjiF" x="39" y="-60"><field
        name="VAR" id="}_`%y0{BF@~znZ]hhVm`">countdown</field><value
        name="VALUE"><block type="math_number" id=":=6{16!humms5vXy7G=l"><field
        name="NUM">600</field></block></value><next><block type="variables_set"
        id="YY5ju9Mt)%nb6DPZmB|7"><field name="VAR"
        id=")b_R[t#kX_SC?vi;Po0w">startLevel</field><value name="VALUE"><block
        type="text_join" id="Em+9.vFud|c)@fCZE4!r"><mutation
        items="1"></mutation><value name="ADD0"><block
        type="oh_context_attribute" id="q3xtBRYde+!B~F~-q3p."><value
        name="key"><shadow type="text" id="pZ)r;)2@K(jbb`:V?(#."><field
        name="TEXT">3.startlevel</field></shadow></value></block></value></block></value><next><block
        type="variables_set" id="k=|SKMP;{.#SP%FU6J,B"><field name="VAR"
        id="eLE$]xb7:LsH*wrcl7VE">timer</field><value name="VALUE"><block
        type="text_join" id=",N1Z-@D9Q!:+p6Ac3oAR"><mutation
        items="1"></mutation><value name="ADD0"><block
        type="oh_context_attribute" id="c}2X^?@A+u-R+q9D{-S)"><value
        name="key"><shadow type="text" id="6{l^BT*7}wrLbLaN^sOC"><field
        name="TEXT">ruleUID</field></shadow></value></block></value></block></value><next><block
        type="controls_if" id="i2S2{IdA_oO!Fi3##PT2"><mutation
        else="1"></mutation><value name="IF0"><block type="logic_compare"
        id="#4$-a9GVc5V/`~z)9)=j"><field name="OP">EQ</field><value
        name="A"><block type="variables_get" id="QA1/EB[SrTdr9-~m]M@w"><field
        name="VAR"
        id=")b_R[t#kX_SC?vi;Po0w">startLevel</field></block></value><value
        name="B"><block type="text" id="0S($rP?+I%!,.]u)%gk#"><field
        name="TEXT">100</field></block></value></block></value><statement
        name="DO0"><block type="variables_set" id="a!4XNiiC/v8m|ijaI2%a"><field
        name="VAR" id="cGn0#jI2g*d+OLKC41y:">newState</field><value
        name="VALUE"><block type="text" id="l,aBFG=R?/OfL@3{(|Zf"><field
        name="TEXT">ON</field></block></value></block></statement><statement
        name="ELSE"><block type="oh_event" id="p@i+7^B3L#A53b@r[:CR"><field
        name="eventType">postUpdate</field><value name="value"><shadow
        type="text" id="4BH~wD1l,=mM`(Ln]~zY"><field
        name="TEXT">value</field></shadow><block type="variables_get"
        id="V%1+Iy}.!v5P:GIwm{I3"><field name="VAR"
        id="}_`%y0{BF@~znZ]hhVm`">countdown</field></block></value><value
        name="itemName"><shadow type="oh_item" id="GsNTEtPZ[vdsR1LX.g-="><field
        name="itemName">PlugKaffeeCountdown</field></shadow></value><next><block
        type="variables_set" id="*NsF=4mVz9+O{IK[X2O{"><field name="VAR"
        id="cGn0#jI2g*d+OLKC41y:">newState</field><value name="VALUE"><block
        type="oh_context_info" id=":@yP.(KmU%!!#1sj_sA|"><field
        name="contextInfo">itemState</field></block></value></block></next></block></statement><next><block
        type="controls_if" id="P]pM*X,[?GmyYBvoN~2%"><mutation
        elseif="1"></mutation><value name="IF0"><block type="logic_compare"
        id="M6Rhp1IY@FXu01OJ?v(2"><field name="OP">EQ</field><value
        name="A"><block type="variables_get" id="CK`dtkyXxlCy=F01rwuj"><field
        name="VAR"
        id="cGn0#jI2g*d+OLKC41y:">newState</field></block></value><value
        name="B"><block type="text" id="r*OeiH_ty:!XX4e7XaFY"><field
        name="TEXT">ON</field></block></value></block></value><statement
        name="DO0"><block type="oh_timer" id="R?1`$!G.x*]l8T#|!o1_"><field
        name="delayUnits">plusSeconds</field><value name="delay"><shadow
        type="math_number" id="|q=Y=KvMhD,n.:4jQ+U="><field
        name="NUM">0</field></shadow></value><value name="timerName"><shadow
        type="text" id="1Y$C.40TDDbpX=[T|s|v"><field
        name="TEXT"></field></shadow><block type="variables_get"
        id="T4t.w!,,^t3i:tagMj(f"><field name="VAR"
        id="eLE$]xb7:LsH*wrcl7VE">timer</field></block></value><statement
        name="timerCode"><block type="controls_if"
        id="l^+St@b0:]dK$ik)pOw["><mutation else="1"></mutation><value
        name="IF0"><block type="logic_compare" id="Svw-t?t-/:!+UiLLO)C%"><field
        name="OP">GT</field><value name="A"><block type="oh_getitem_state"
        id="cROnn[RwSTAXnxG/6I=1"><value name="itemName"><shadow type="oh_item"
        id="TZXgy~8(s|o0Hu9M(O-Y"><field
        name="itemName">PlugKaffeeCountdown</field></shadow></value></block></value><value
        name="B"><block type="text" id="[}}M.6IUaNcx8ae-=X-9"><field
        name="TEXT">0</field></block></value></block></value><statement
        name="DO0"><block type="variables_set" id="9T9S|F`DPJg]o|4kGs]4"><field
        name="VAR" id="}_`%y0{BF@~znZ]hhVm`">countdown</field><value
        name="VALUE"><block type="oh_getitem_state"
        id="OxRr^BT84IXQNiDH_jVh"><value name="itemName"><shadow type="oh_item"
        id="CY*g/(/OIj5|mY(!Pyi|"><field
        name="itemName">PlugKaffeeCountdown</field></shadow></value></block></value><next><block
        type="oh_event" id="Y:}1$$Rk~U^tdoLq,Z!L"><field
        name="eventType">postUpdate</field><value name="value"><shadow
        type="text" id=";rK9)r{5bj_knbK%e/#/"><field
        name="TEXT">value</field></shadow><block type="math_arithmetic"
        id="e{uZYDPvA%``byI=gE-,"><field name="OP">MINUS</field><value
        name="A"><shadow type="math_number" id="F_7@6O6To@M!R%#os3;`"><field
        name="NUM">1</field></shadow><block type="variables_get"
        id="LLhAPiqp18R(1f0hA1vF"><field name="VAR"
        id="}_`%y0{BF@~znZ]hhVm`">countdown</field></block></value><value
        name="B"><shadow type="math_number" id="$ifW-X^yMcFuj)pDD(h1"><field
        name="NUM">1</field></shadow></value></block></value><value
        name="itemName"><shadow type="oh_item" id="O{qHP:#4;i5@?jY[DBXV"><field
        name="itemName">PlugKaffeeCountdown</field></shadow></value><next><block
        type="oh_timer_reschedule" id="]P)h.#J;DJOeurgrR)sC"><field
        name="delayUnits">plusSeconds</field><value name="delay"><shadow
        type="math_number" id="{vK.K_EVh*X4]kh?k20z"><field
        name="NUM">1</field></shadow></value><value name="timerName"><shadow
        type="text" id="I=-:m7;)w7AL)6/E+fZ3"><field
        name="TEXT"></field></shadow><block type="variables_get"
        id="EEGt*[PrRg{F|7cO%V:#"><field name="VAR"
        id="eLE$]xb7:LsH*wrcl7VE">timer</field></block></value></block></next></block></next></block></statement><statement
        name="ELSE"><block type="oh_event" id="C[n-M3S-@x/1Gf:|w)wU"><field
        name="eventType">sendCommand</field><value name="value"><shadow
        type="text" id="-F}k;WBV,J,gmP*4Pw}:"><field
        name="TEXT">value</field></shadow><block type="text"
        id="n+Cm^4hAFcrqI{2q-s]6"><field
        name="TEXT">OFF</field></block></value><value name="itemName"><shadow
        type="oh_item" id="7z00UYl6ST_q9;~$DA/X"><field
        name="itemName">PlugKaffee</field></shadow></value></block></statement></block></statement></block></statement><value
        name="IF1"><block type="logic_compare" id=".=@=jsT9l+4b{x[7Af1^"><field
        name="OP">EQ</field><value name="A"><block type="variables_get"
        id="/Rp%H7BBE,o@1t#i`|5."><field name="VAR"
        id="cGn0#jI2g*d+OLKC41y:">newState</field></block></value><value
        name="B"><block type="text" id="(q9!zo.5VTjE2U56F^;Q"><field
        name="TEXT">OFF</field></block></value></block></value><statement
        name="DO1"><block type="oh_event" id="-M6w`LiDoyBpUUP9lcOK"><field
        name="eventType">postUpdate</field><value name="value"><shadow
        type="text" id="N!=Fk@4%G}NgWHOYR4@K"><field
        name="TEXT">0</field></shadow></value><value name="itemName"><shadow
        type="oh_item" id="h4/0h,!u*k.}#J-pIfS2"><field
        name="itemName">PlugKaffeeCountdown</field></shadow></value><next><block
        type="oh_timer_cancel" id="o`D_*s@r[{vax/A%e5?M"><value
        name="timerName"><shadow type="text" id="lHgwDN$E~O`r^!pR`U~V"><field
        name="TEXT"></field></shadow><block type="variables_get"
        id="w.SnMxH,a,,sxsQGNZ{K"><field name="VAR"
        id="eLE$]xb7:LsH*wrcl7VE">timer</field></block></value></block></next></block></statement></block></next></block></next></block></next></block></next></block></xml>
      type: application/javascript
      script: >
        var countdown, startLevel, timer, newState;


        var scriptExecution = Java.type('org.openhab.core.model.script.actions.ScriptExecution');


        var zdt = Java.type('java.time.ZonedDateTime');


        if (typeof this.timers === 'undefined') {
          this.timers = [];
        }



        countdown = 600;

        startLevel = String(ctx['3.startlevel']);

        timer = String(ctx['ruleUID']);

        if (startLevel == '100') {
          newState = 'ON';
        } else {
          events.postUpdate('PlugKaffeeCountdown', countdown);
          newState = event.itemState;
        }

        if (newState == 'ON') {
          if (typeof this.timers[timer] === 'undefined' || this.timers[timer].hasTerminated()) {
            this.timers[timer] = scriptExecution.createTimer(zdt.now().plusSeconds(0), function () {
              if (itemRegistry.getItem('PlugKaffeeCountdown').getState() > '0') {
                countdown = itemRegistry.getItem('PlugKaffeeCountdown').getState();
                events.postUpdate('PlugKaffeeCountdown', (countdown - 1));
                if (typeof this.timers[timer] !== 'undefined') { this.timers[timer].reschedule(zdt.now().plusSeconds(1)); }
              } else {
                events.sendCommand('PlugKaffee', 'OFF');
              }
              })
          }
        } else if (newState == 'OFF') {
          events.postUpdate('PlugKaffeeCountdown', '0');
          if (typeof this.timers[timer] !== 'undefined') {
            this.timers[timer].cancel();
            this.timers[timer] = undefined;
          }
        }
    type: script.ScriptAction

And here the blockly:

The rule is triggered by state change of a switch item or at startup to resume a running timer.
The timer is realised with a rolling timer that restarts every second so you can display the remaining time in the UI. Therefor you need a number item (here PlugKaffeeCountdown).
Please try and give feedback.

2 Likes

// Define the function that will send the notification
var sendNotification = function() {
// Replace with your own items
items.getItem(“Alexa1”).sendCommand(“Your coffee is ready!”);
items.getItem(“Alexa2”).sendCommand(“Don’t forget your coffee!”);
};

// Set the timer to wait for 10 minutes and then execute the function
var timer = new java.util.Timer();
timer.schedule(new java.util.TimerTask({
run: function() {
sendNotification();
}
}), 10 * 60 * 1000);

This code sets a timer to wait for 10 minutes (converted to milliseconds) and then execute the sendNotification function. You can customize this function to send notifications to your Alexa devices or openHAB app as desired. I have Breville PrimaLatte II Source: 7 Kaffeepadmaschinen Test - Vergleich und Übersicht (Frühling 2023) it helped.