Blockly Group Filter with Timer

Hi All
I’m on OH 3.2 and migrate all my rules to blockly, so far so good. The rules where i need Group Filter i followed this Workaround and it works pretty well.
I have this rule sending a Telegram when a window is open, when more than one Window is open, as many messages are sent as windows are open, thats OK

Then i need another rule with a timer, after the timer expired the command should be sent to each item with the state ON.
This is the blockly

Blockly2

var list, names, status;

var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + ctx.ruleUID);

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 = [];
}


var list_list = Java.from(itemRegistry.getItem('Vorhaus_Licht').members);
for (var list_index in list_list) {
  list = list_list[list_index];
  names = list.getName();
  status = list.getState();
  if (status == 'ON') {
    logger.warn(names);
    if (typeof this.timers['MyTimer'] === 'undefined' || this.timers['MyTimer'].hasTerminated()) {
      this.timers['MyTimer'] = scriptExecution.createTimer(zdt.now().plusSeconds(10), function () {
        events.sendCommand(names, 'OFF');
        logger.info(names);
        })
    }
  }
}

and the log

2022-01-16 23:09:14.563 [WARN ] [org.openhab.rule.ABTest             ] - Vorhaus_Vorhaus1

2022-01-16 23:09:14.603 [WARN ] [org.openhab.rule.ABTest             ] - Vorhaus_Vorhaus2

2022-01-16 23:09:24.585 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'GerderobeShelly01_state' received command OFF

2022-01-16 23:09:24.587 [WARN  ] [org.openhab.rule.ABTest             ] - GerderobeShelly01_stat

The log with the items state is correct but after 10 seconds the command is sent to an item with state not ON but in the same group and the log after the command is also not correct.

If i use a thread.sleep for 10 seconds, each command is sent but not at once, 10 seconds between the commands. and both logs.

Blockly3

var list, names, status;

var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + ctx.ruleUID);

var thread = Java.type('java.lang.Thread')


var list_list = Java.from(itemRegistry.getItem('Vorhaus_Licht').members);
for (var list_index in list_list) {
  list = list_list[list_index];
  names = list.getName();
  status = list.getState();
  if (status == 'ON') {
    logger.warn(names);
    thread.sleep(10000);
    events.sendCommand(names, 'OFF');
    logger.warn(names);
  }
}

2022-01-16 23:25:57.936 [WARN ] [org.openhab.rule.ABTest             ] - Vorhaus_Vorhaus1

2022-01-16 23:26:07.943 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'Vorhaus_Vorhaus1' received command OFF

2022-01-16 23:26:07.946 [WARN ] [org.openhab.rule.ABTest             ] - Vorhaus_Vorhaus1

2022-01-16 23:26:07.948 [INFO ] [penhab.event.ItemStatePredictedEvent] - Item 'Vorhaus_Vorhaus1' predicted to become OFF

2022-01-16 23:26:07.956 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'Vorhaus_Vorhaus1' changed from ON to OFF

2022-01-16 23:26:07.964 [WARN ] [org.openhab.rule.ABTest             ] - Vorhaus_Vorhaus2

2022-01-16 23:26:17.967 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'Vorhaus_Vorhaus2' received command OFF

2022-01-16 23:26:17.967 [WARN ] [org.openhab.rule.ABTest             ] - Vorhaus_Vorhaus2

2022-01-16 23:26:17.972 [INFO ] [penhab.event.ItemStatePredictedEvent] - Item 'Vorhaus_Vorhaus2' predicted to become OFF

2022-01-16 23:26:17.985 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'Vorhaus_Vorhaus2' changed from ON to OFF

I not need the thread.sleep, it was just a test because with the timer it is not working.
hope somebody can help.
Thanks Rolli

Hi @Rolli.

i think the problem is, that you use one timer for all items. In my opinion a timer can only have one function. Until the timer is not finished you can’t use it again.

So what you can try is to create in every loop another timer for the specific item:

grafik

Can you report if it worked?

Something else that is not important:

Please correct the names of your variables (because with this names it’s hard to read):

list → listEntry
names → name

In addition to previous post I would add that you do not even need to iterate through the entire group of windows or lights.

If I understand correct eg. if 1 of x windows will be open, you only want to send a message for this specific window.

For this usecase you can use “when a member of the group changes” as rule trigger and within the rule you can use the contextual info (what will give you the name of the window that was opened).

If multiple windows will be opened at the same time, the contextual info will get overwritten, and therefore you need to pass the event to the Timer (otherweise the timer will always only know the window that was opened / closed latest).

Simply use the timer in this library (instead of the ootb timer in blockly) what will solve the issue with the context (as I’m doing exactly the same).

Removing your loop would make your rule faster and more easy to read, as there is no need to always check all windows and OH will tell you which window was opened / closed.

For the light you can do the same or, if you always want to turn off the light after a specific time, e.g. 10 minutes, simple use the expiration timer metadata and you do not need to have a rule at all.

@Christian_Kittel
Hi Christian, thanks for your answer and for the hint with the variables, i tryed your solution unfortunately
it´s not working. The timers are created, in my test case 2 timesr, but still send the command, 2 times, to a groupmember which is not ON.

@Matze0211
Hi Matthias
The window notification through telegram works as it should, i assumed that it will work also with the timer.
I tryed the timer from your library but i get following error.

2022-01-17 10:08:53.720 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'ABTest' failed: ReferenceError: "scriptExecution" is not defined in <eval> at line number 14

I compared the code from your blocks with the oh blocks. With the oh blocks following code is automatically injeckted, not with your blocks.

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

The light setup was just a test, if the rule works it should watch my garagedoors which are operatet with a sonoff 4ch where the hardware is set to pushbutton which automaticaly cange to OFF after a view seconds.
Therefore the expiration timer metadata will not work.

The error you mentioned is already fixed. Please make sure to use the latest version.

(While testing I had ootb timer and the custom timer in one rule to compare both, therefore I only recognized this issue after testing)

You can delete the library from Developer Tools → block library and just add it again via the marketplace or manually copy to be library code to your system.

Could you paste JavaScript and an image of yout Blockly again?

Thats what I would recommend instead of looping through the group (if you want to notify about open windows immediately you can remove the timer and just use the “contextual infos” blocks to replace your loop.

Rule
configuration: {}
triggers:
  - id: "1"
    configuration:
      groupName: Test_Group
    type: core.GroupStateChangeTrigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      blockSource: <xml xmlns="https://developers.google.com/blockly/xml"><block
        type="controls_if" id="-L~3fxxiis,t-L=eQ.4x" x="26" y="27"><mutation
        else="1"></mutation><value name="IF0"><block type="logic_compare"
        id="2MsR=?}JIb)aZMX@c03y"><field name="OP">EQ</field><value
        name="A"><block type="text" id="Z?kuTvc?[~KA{p0ZO(x4"><field
        name="TEXT">OPEN</field></block></value><value name="B"><block
        type="oh_context_info" id="][V*n[0cgY3+3RNX@]rt"><field
        name="contextInfo">itemState</field></block></value></block></value><statement
        name="DO0"><block type="commonBlocks_timerWithInitialEvent"
        id="5+1^R?vv]cR!mP./~898"><field
        name="duration_unit">plusMinutes</field><value name="duration"><shadow
        type="math_number" id="cJ@pIKC(AABHhV6MIM5c"><field
        name="NUM">10</field></shadow></value><value name="timer_name"><shadow
        type="text" id="/.8Pnq19^nGRmX98r1;!"><field
        name="TEXT">MyTimer</field></shadow><block type="text_join"
        id="fOoJei(}1%F1CZbI?/)^"><mutation items="2"></mutation><value
        name="ADD0"><block type="text" id="U+KH=;_bK*oRv1H~/QRI"><field
        name="TEXT">Trigger_</field></block></value><value name="ADD1"><block
        type="oh_context_info" id="J{+sXJv+=3!`)SJw9[8G"><field
        name="contextInfo">itemName</field></block></value></block></value><statement
        name="timer_statement"><block type="oh_log"
        id="WOz`PGnQ6L.:-Sdy|6LZ"><field name="severity">info</field><value
        name="message"><shadow type="text" id="jA9F}@pOI(?Z0t_qTFv8"><field
        name="TEXT"></field></shadow><block type="text_join"
        id="ALz@2G?(@@!yZaZ_x;c|"><mutation items="3"></mutation><value
        name="ADD0"><block type="text" id="OR;#cy%A1r?kAeKbI_;q"><field
        name="TEXT">The following item changed 10 minutes ago. Send telegram
        message, turn of light, etc.</field></block></value><value
        name="ADD1"><block type="oh_getitem_attribute"
        id="vAT}5%eNP)|BF[zlVUHC"><field
        name="attributeName">Label</field><value name="item"><shadow
        type="oh_getitem" id="U`NhtuwS0Rst#EFV@XdC"><value
        name="itemName"><shadow type="oh_item" id="(PRTn|19Z;;hj.BdD*`@"><field
        name="itemName">MyItem</field></shadow></value></shadow><block
        type="oh_getitem" id="}db3B?ZC$h%81JjoABai"><value
        name="itemName"><shadow type="oh_item" id="*Q_ClMz?~8^$A7IH}Yz7"><field
        name="itemName">MyItem</field></shadow><block type="oh_context_info"
        id="WKV!1XPP6~W74Ja2|bX4"><field
        name="contextInfo">itemName</field></block></value></block></value></block></value><value
        name="ADD2"><block type="oh_context_info"
        id="u_Dm4n6jh/g@btrczx~T"><field
        name="contextInfo">itemState</field></block></value></block></value></block></statement></block></statement><statement
        name="ELSE"><block type="oh_log" id="6HvO!V[.A0`j:YRHt}%R"><field
        name="severity">info</field><value name="message"><shadow type="text"
        id="}Z]Q:p8:oF{p9%4e9pRy"><field name="TEXT">This will cancel the timer
        if the window is closed / light turned off prior to the timer is
        running.</field></shadow></value><next><block type="oh_timer_cancel"
        id=",}Q^)N+=.0D-E{kHhVcK"><value name="timerName"><shadow type="text"
        id="Rz?m{Ty%6YWg~(9l/Zj?"><field
        name="TEXT">MyTimer</field></shadow><block type="text_join"
        id="GNP~kN1i_Iup(b#cTd_4"><mutation items="2"></mutation><value
        name="ADD0"><block type="text" id="NIJ|:$z~i#w5~-))]y`W"><field
        name="TEXT">Trigger_</field></block></value><value name="ADD1"><block
        type="oh_context_info" id="Qp{59wde:lZ[=`TE0mLN"><field
        name="contextInfo">itemName</field></block></value></block></value></block></next></block></statement></block></xml>
      type: application/javascript
      script: >
        var scriptExecution =
        Java.type('org.openhab.core.model.script.actions.ScriptExecution');


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


        var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + ctx.ruleUID);


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



        if ('OPEN' == event.itemState) {
          if (typeof this.timers === 'undefined') {
            this.timers = [];
          }
          if (typeof this.timers['Trigger_' + String(event.itemName)] === 'undefined' || this.timers['Trigger_' + String(event.itemName)].hasTerminated()) {
            this.timers['Trigger_' + String(event.itemName)] = scriptExecution.createTimerWithArgument(zdt.now().plusMinutes(10),event, function (event) {

            logger.info((['The following item changed 10 minutes ago. Send telegram message, turn of light, etc.',itemRegistry.getItem(event.itemName).getLabel(),event.itemState].join('')));

            })
          }
        } else {
          logger.info('This will cancel the timer if the window is closed / light turned off prior to the timer is running.');
          if (typeof this.timers[('Trigger_' + String(event.itemName))] !== 'undefined') {
            this.timers[('Trigger_' + String(event.itemName))].cancel();
            this.timers[('Trigger_' + String(event.itemName))] = undefined;
          }
        }
    type: script.ScriptAction

1 Like

Wow, i never thought of possibilitys like this. it works like a charm.

Rule

configuration: {}
triggers:
  - id: "1"
    configuration:
      groupName: Vorhaus_Licht
    type: core.GroupStateChangeTrigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      blockSource: <xml xmlns="https://developers.google.com/blockly/xml"><block
        type="controls_if" id=")=gCZ.~7ugqBy,@m5k6t" x="-322" y="162"><mutation
        else="1"></mutation><value name="IF0"><block type="logic_compare"
        id="R[9Z9j*3dqvjn$1l!G_J"><field name="OP">EQ</field><value
        name="A"><block type="text" id="~xQB`VT;l,,`ivnk8{{P"><field
        name="TEXT">ON</field></block></value><value name="B"><block
        type="oh_context_info" id="0m#pH`8`G!eqL~f]Yp=p"><field
        name="contextInfo">itemState</field></block></value></block></value><statement
        name="DO0"><block type="commonBlocks_timerWithInitialEvent"
        id="UW]t::9XoUT}i?(KwpKb"><field
        name="duration_unit">plusSeconds</field><value name="duration"><shadow
        type="math_number" id="#wQS=ZqB0{Ncp#RTlqJb"><field
        name="NUM">10</field></shadow></value><value name="timer_name"><shadow
        type="text" id="]4e0My{k|hMNjd!ghvRo"><field
        name="TEXT">MyTimer</field></shadow><block type="text_join"
        id="Y2^KEP3I6A,JETbiPz0w"><mutation items="2"></mutation><value
        name="ADD0"><block type="text" id="DFrw79G@e`Nu6*oOD`?q"><field
        name="TEXT">myTimer</field></block></value><value name="ADD1"><block
        type="oh_context_info" id=":Z?=D+F(U3Tn4y_MM(yW"><field
        name="contextInfo">itemName</field></block></value></block></value><statement
        name="timer_statement"><block type="oh_event"
        id="zPx`#8Q$6Z04eq|w5cYg"><field
        name="eventType">sendCommand</field><value name="value"><shadow
        type="text" id="ykiOK+x$@]:bhDB*@{U9"><field
        name="TEXT">OFF</field></shadow></value><value name="itemName"><shadow
        type="oh_item" id="J~uQxmqHJJ{.A`J7l%$c"><field
        name="itemName">MyItem</field></shadow><block type="oh_context_info"
        id="OsHX}i?F/ra3/xwGZD:O"><field
        name="contextInfo">itemName</field></block></value></block></statement></block></statement><statement
        name="ELSE"><block type="oh_timer_cancel"
        id="%KWn{.ie#VC/7uIou.ZG"><value name="timerName"><shadow type="text"
        id="K^rdZ:Llgy3])h.q3oO2"><field
        name="TEXT">MyTimer</field></shadow><block type="text_join"
        id="xb4^u1a|6V7iZ6P;m@!("><mutation items="2"></mutation><value
        name="ADD0"><block type="text" id="A{SQ$MwhI}^Ttn?AFs(e"><field
        name="TEXT">myTimer</field></block></value><value name="ADD1"><block
        type="oh_context_info" id="czg7,8(ln1Ym9!p~AB[K"><field
        name="contextInfo">itemName</field></block></value></block></value></block></statement></block></xml>
      type: application/javascript
      script: >
        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 = [];
        }



        if ('ON' == event.itemState) {
          if (typeof this.timers === 'undefined') {
            this.timers = [];
          }
          if (typeof this.timers['myTimer' + String(event.itemName)] === 'undefined' || this.timers['myTimer' + String(event.itemName)].hasTerminated()) {
            this.timers['myTimer' + String(event.itemName)] = scriptExecution.createTimerWithArgument(zdt.now().plusSeconds(10),event, function (event) {

            events.sendCommand(event.itemName, 'OFF');

            })
          }
        } else {
          if (typeof this.timers[('myTimer' + String(event.itemName))] !== 'undefined') {
            this.timers[('myTimer' + String(event.itemName))].cancel();
            this.timers[('myTimer' + String(event.itemName))] = undefined;
          }
        }
    type: script.ScriptAction

Thanks a lott

2 Likes

This is my final rule including telegram notification, it is amazing what is possible once you figured out how to stack the blocks together.

Before i had this :man_facepalming: and there is not even the telegram notification included.

Again many thanks!!!