Design Pattern: Gate Keeper

@rlkoshak: so you offer real-time problem solving services - cool :wink: ! In my job, I have access to some paid “premium support services” which are nowhere as good (or quick) as you are :smiley:

Thanks - I fully understand what you say. I even remember reading about the receivedCommand variable at some point. But I never used it and forgot about it.
I’ll go that way - I am very confident it’ll work!

You just happened to catch me when I was online. Though when I’m tagged I get an email and can often reply from my phone, which was the case here.

Edit: @5iver solved my problem and I have corrected the code so that one can copy&paste items and code if one have a similar use case. @rlkoshak thank you for this great design pattern!

Hi @rlkoshak , this is the case with my sonos speakers, when there are multiple notifications to be played.
That’s why I try to use the complex example of your design pattern to manage playing notifications.
But there are errors in my openhab.log that I cannot solve and I couldn’t find a solution in the forum.

My items in file GateKeeperExamples.items

Group GrpMessages
Switch CreateMessage    "CreateMessage [%s]"    (GrpMessages)
String TextQueued       "TextQueued [%s]"       (GrpMessages)
String TextOutput       "TextOutput [%s]"       (GrpMessages)

My code in file GateKeeperExamples.rules

// IMPORTS **************************************************************************  
    import java.util.concurrent.ConcurrentLinkedQueue

// GLOBAL VARIABLES ************************************************************
    val MyQueue = new ConcurrentLinkedQueue()    // Edited this line. The code causing the errror was: val Queue<String> MyQueue = new ConcurrentLinkedQueue()
    var Timer timer = null
    var lastCommand = now.minusSeconds(1).millis

    var MyMessageCounter = 0

// RULES ****************************************************************************

rule "rGateKeeperExample_CreateMessage"
 when
    Item CreateMessage received command
 then
    MyMessageCounter = MyMessageCounter + 1     // MyMessageCounter see global variables section
    val MyMessage = "Message no. " + MyMessageCounter.toString + " , date = " + now.toString
    TextQueued.sendCommand( MyMessage )
    logInfo("openhab", "New Message = " + MyMessage )
end // EndOfRule rGateKeeperExample_CreateMessage

rule "rGateKeeperExample_MessageOutput"
 when
    Item TextQueued received command
 then
    val String          MyLogFile = "MySeparateLogFile"   // if 'MySeparateLogFile' does not exist, logging goes into openhab.log (to create a separate logfile see https://www.openhab.org/docs/administration/logging.html#logging-into-separate-file)
    val DateTime        MyLogDate = now  
    val StringBuilder   MyLogMessage = new StringBuilder
    MyLogMessage.append( "\n" + "\n" + " ----------   rGateKeeperExample_MessageOutput v001   ----------" + "\n" + "\n" )
    MyLogMessage.append( "    MyLogDate = " + MyLogDate.toString + "\n" + "\n" ) // ("yyyy-MM-dd'T'HH:mm:ss.SSSZ")

    MyQueue.add(receivedCommand.toString)  // https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentLinkedQueue.html#add(E)
    MyLogMessage.append( "    TextQueued = " + receivedCommand.toString + "\n" ) 

    if(timer === null) {
        timer = createTimer(now, [ |
            if(MyQueue.peek !== null) {    // https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentLinkedQueue.html#peek()
                val TmpText = MyQueue.poll     // https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentLinkedQueue.html#poll()
                TextOutput.sendCommand( TmpText.toString )
                // say(TextOutput, "voicerss:deDE", "sonos:PLAY1:SonosLiving", new PercentType(25))
                MyLogMessage.append( "       TextOutput = " + TmpText.toString + "\n" ) 
                lastCommand = now.millis
            }
            timer.reschedule(now.plusMillis(60000))  // output of next message after 60s
        ] )
    } 
    logInfo( MyLogFile, MyLogMessage.toString )
end // EndOfRule rGateKeeperExample_MessageOutput

My openhab.log

2019-03-28 20:58:18.129 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model 'GateKeeperExample.rules'
2019-03-28 21:25:55.014 [INFO ] [el.core.internal.ModelRepositoryImpl] - Validation issues found in configuration model 'GateKeeperExample.rules', using it anyway:
The field Tmp_GateKeeperExampleRules.MyQueue refers to the missing type Object
The field Tmp_GateKeeperExampleRules.MyQueue refers to the missing type Object
The field Tmp_GateKeeperExampleRules.MyQueue refers to the missing type Object
2019-03-28 21:25:55.209 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model 'GateKeeperExample.rules'
2019-03-28 21:26:26.329 [INFO ] [lipse.smarthome.model.script.openhab] - New Message = Message no. 1 , date = 2019-03-28T21:26:26.320+01:00
2019-03-28 21:26:26.359 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'rGateKeeperExample_MessageOutput': 'add' is not a member of 'Object'; line 38, column 5, length 37
2019-03-28 21:26:28.888 [INFO ] [lipse.smarthome.model.script.openhab] - New Message = Message no. 2 , date = 2019-03-28T21:26:28.875+01:00
2019-03-28 21:26:28.915 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'rGateKeeperExample_MessageOutput': 'add' is not a member of 'Object'; line 38, column 5, length 37
2019-03-28 21:26:29.725 [INFO ] [lipse.smarthome.model.script.openhab] - New Message = Message no. 3 , date = 2019-03-28T21:26:29.719+01:00
2019-03-28 21:26:29.757 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'rGateKeeperExample_MessageOutput': 'add' is not a member of 'Object'; line 38, column 5, length 37

Problem
I think the info in openhab.log
The field Tmp_GateKeeperExampleRules.MyQueue refers to the missing type Object
indicates, that there is something wrong with the declaration of MyQueue in this line of my code
val Queue<String> MyQueue = new ConcurrentLinkedQueue()

Every time the rule is triggered I get this error
Rule 'rGateKeeperExample_MessageOutput': 'add' is not a member of 'Object'; line 38, column 5, length 37
which points to line 38 with this code MyQueue.add(receivedCommand.toString)

I couldn’t find a solution yet, so every help is appreciated.

My system is openhabian installed on raspberry pi:

  • Release = Raspbian GNU/Linux 9 (stretch)*
  • Kernel = Linux 4.14.79-v7+*
  • Platform = Raspberry Pi 3 Model B Rev 1.2*
  • openHAB 2.4.0-1 (Release Build)*
1 Like

In DSL rules, only be as specific as you need to be.You shouldn’t get the error if you use this…

val MyQueue = new ConcurrentLinkedQueue()
1 Like

Many thanks, that is the solution.
Small cause, big effect!

If I have a rule using a GateKeeper (the complex example using queues), then one timer runs forever:
If a timer runs forever, does it mean, one thread is used forever?

If I have five rules, each using one GateKeeper:
Does the Rules DLS run out of threads?

When a timer is timing, no thread is used.
When a timer has expired and is executing it’s little code block, it uses a thread until it has exited that code.

rossko57 is correct. That is why I use Timers in that example. Timers use no resources beyond a tiny bit of ram while they are awaiting their time to execute.

Before the code block within timer = createTimer(now, [ | ... ]) can be exit, the timer is rescheduled. That’s why I’m wondering if the thread is running forever. Or almost forever.

That’s fine. Awaiting a scheduled time uses no thread.
When the timer’s little code block has completed the reschedule task, it exits. So releasing the execution thread.

Okay thank you very much. That’s reassuring.

The Gatekeeper (python) version is not (yet) in the community openhab helper libraries. Would be nice to have it there.

Regards S

That’s the plan. I’ve still some unit tests to write and documentation to flesh out before I submit the PR. I’ll update the OP when it’s merged. Most of the DPs I hope to similarly submit most of the DPs and tutorials.

2 Likes

I used this pattern to help out with turning on/off wifi for my kids… I’m using the Unifi binding and I put all my kids devices into a separate group (gDevicesToBlock). The problem was that when I did a set on the group, all commands where sent to the binding without any delays and it didn’t catch all devices. Same problem that’s described in the design pattern above for 433 Mhz devices.

Anyway, I updated the pattern and I just want to share it, as it took some time to get right.


Items:
======
Switch UnifiBlockController "Block wireless" <switch>
Group gDevicesToBlock "Devices to block"

Switch NilsPhoneBlock "Nils phone block" <switch> (gDevicesToBlock)
  {channel="unifi:wirelessClient:home:nilsPhone:blocked"}
Switch IvarsPhoneBlock "Ivar phone block" <switch> (gDevicesToBlock)
  {channel="unifi:wirelessClient:home:ivarsPhone:blocked"}


Rule:
=====

import java.util.concurrent.ConcurrentLinkedQueue

val deviceQueue = new ConcurrentLinkedQueue()
var Timer timer = null
val delay = 1000  // Delay in milliseconds between commands


rule "Block unblock Unifi"
when
  Item UnifiBlockController received update
then

  gDevicesToBlock.members.forEach[ device |
    deviceQueue.add(device)
  ]

  if (timer === null) {
    timer = createTimer(now.plusMillis(delay), [ |
      if (deviceQueue.peek !== null) {
        val device = deviceQueue.poll as SwitchItem
        device.sendCommand(UnifiBlockController.state)
        timer.reschedule(now.plusMillis(delay))
      } else {
        timer = null
      }
    ])
  }
end
3 Likes

The problem that you will still pass (((
This pattern is not usable for group switches, that are most used.
If you try to turn on or off the group from example on the top. This one

Group WirelessDevices

It will fail because of basic fault of setting timers at one time.
It means that the group switch just forces all the switches in group to to turn on or off AT ONE TIME (millis are difference)!
Because of it the rull will try to create multiply timers (it will just have not time to process all of them at once and to check if timer exists) and will fail (((

It can works somethimes with 2 switches in group, but if you have more it will cause the fault.

Can this behavior be in someway changed?

Show your code.

You can’t send a command to a Group with this DP. You must send the command to each member of the Group individually. From what you describe I can’t tell if that is what you are trying to do.

In the DP above, there is only one timer. If you are calling Gatekeeper for each member individually, you may need you add a short Thread::sleep, 10 msec should be enough, between each call to Gatekeeper.

I’m assuming the Rules DSL version of the code. The Python version blocks on the call to addCommand so there is no chance of processing a new consensus before the looking timer is created.

1 Like

Here is my code.


import java.util.concurrent.ConcurrentLinkedQueue
val ConcurrentLinkedQueue<String> commands = new ConcurrentLinkedQueue()

var String commandToQuery 
var Timer timer = null
var lastCommand = now.minusSeconds(1).millis

rule "Arduino 433Mhz Send Command. Query."
when
  Member of gSocket3All received command
then 
    commandToQuery = triggeringItem.name + "-" + receivedCommand.toString
    commands.add(commandToQuery)
        logInfo("arduino", "Add to queue: " + commandToQuery + "// Timer State: " + timer)
        if (timer === null) {
            logInfo("arduino", "No timer. Creating.")
            timer = createTimer(now, [|
                if(commands.peek !== null) {
                    val cmd = commands.poll
                    logInfo("arduino", "Sending command to Arduino 433Mhz: " + cmd + " and transformed: " + transform("MAP", "arduino2.map", cmd))
                    Arduino.sendCommand(transform("MAP", "arduino2.map", cmd))
                    lastCommand = now.millis
                } 
                val deltaTime = now.millis - lastCommand
                timer.reschedule(now.plusMillis(if(deltaTime<100) 100-deltaTime else 0)) // 0 will reschedule the timer to run immediately
            ]) 
        } 
end 

And after the first use it crashes with

2019-12-15 19:38:14.858 [INFO ] [lipse.smarthome.model.script.arduino] - Add to queue: Socket3N2-ON// Timer State: null

2019-12-15 19:38:14.861 [INFO ] [lipse.smarthome.model.script.arduino] - No timer. Creating.

2019-12-15 19:38:14.871 [INFO ] [lipse.smarthome.model.script.arduino] - Sending command to Arduino 433Mhz: Socket3N2-ON and transformed: 10;NewKaku;02a0ec00;3;ON;

==> /var/log/openhab2/events.log <==

2019-12-15 19:38:14.877 [ome.event.ItemCommandEvent] - Item 'Arduino' received command 10;NewKaku;02a0ec00;3;ON;

2019-12-15 19:38:14.882 [vent.ItemStateChangedEvent] - Arduino changed from 20;82;GlobalTronics;ID=0010;TEMP=0000;HUM=91;BAT=OK;

 to 10;NewKaku;02a0ec00;3;ON;

==> /var/log/openhab2/openhab.log <==

2019-12-15 19:38:14.891 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Arduino 433Mhz Receiver': 6

2019-12-15 19:38:14.895 [ERROR] [org.quartz.core.JobRunShell         ] - Job DEFAULT.Timer 1197 2019-12-15T19:38:14.864+01:00: Proxy for org.eclipse.xtext.xbase.lib.Procedures$Procedure0: [ | {

  org.eclipse.xtext.xbase.impl.XIfExpressionImpl@f84189

  val deltaTime

  <XFeatureCallImplCustom>.reschedule(<XMemberFeatureCallImplCustom>)

} ] threw an unhandled Exception: 

java.lang.IllegalStateException: Could not invoke method: org.joda.time.DateTime.plusMillis(int) on instance: 2019-12-15T19:38:14.877+01:00

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1103) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1061) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._invokeFeature(XbaseInterpreter.java:1047) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeFeature(XbaseInterpreter.java:992) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:151) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:772) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:220) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluateArgumentExpressions(XbaseInterpreter.java:1116) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._invokeFeature(XbaseInterpreter.java:1046) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeFeature(XbaseInterpreter.java:992) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:151) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:772) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:220) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:447) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:228) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluate(XbaseInterpreter.java:190) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.ClosureInvocationHandler.doInvoke(ClosureInvocationHandler.java:46) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.AbstractClosureInvocationHandler.invoke(AbstractClosureInvocationHandler.java:29) ~[?:?]

	at com.sun.proxy.$Proxy519.apply(Unknown Source) ~[?:?]

	at org.eclipse.smarthome.model.script.internal.actions.TimerExecutionJob.execute(TimerExecutionJob.java:48) ~[?:?]

	at org.quartz.core.JobRunShell.run(JobRunShell.java:202) [182:org.openhab.core.scheduler:2.5.0.M4]

	at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [182:org.openhab.core.scheduler:2.5.0.M4]

Caused by: java.lang.IllegalArgumentException

	at sun.reflect.GeneratedMethodAccessor197.invoke(Unknown Source) ~[?:?]

	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]

	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1086) ~[?:?]

	... 27 more

2019-12-15 19:38:15.018 [ERROR] [org.quartz.core.ErrorLogger         ] - Job (DEFAULT.Timer 1197 2019-12-15T19:38:14.864+01:00: Proxy for org.eclipse.xtext.xbase.lib.Procedures$Procedure0: [ | {

  org.eclipse.xtext.xbase.impl.XIfExpressionImpl@f84189

  val deltaTime

  <XFeatureCallImplCustom>.reschedule(<XMemberFeatureCallImplCustom>)

} ] threw an exception.

org.quartz.SchedulerException: Job threw an unhandled exception.

	at org.quartz.core.JobRunShell.run(JobRunShell.java:213) [182:org.openhab.core.scheduler:2.5.0.M4]

	at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [182:org.openhab.core.scheduler:2.5.0.M4]

Caused by: java.lang.IllegalStateException: Could not invoke method: org.joda.time.DateTime.plusMillis(int) on instance: 2019-12-15T19:38:14.877+01:00

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1103) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1061) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._invokeFeature(XbaseInterpreter.java:1047) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeFeature(XbaseInterpreter.java:992) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:151) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:772) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:220) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluateArgumentExpressions(XbaseInterpreter.java:1116) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._invokeFeature(XbaseInterpreter.java:1046) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeFeature(XbaseInterpreter.java:992) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:151) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:772) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:220) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:447) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:228) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluate(XbaseInterpreter.java:190) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.ClosureInvocationHandler.doInvoke(ClosureInvocationHandler.java:46) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.AbstractClosureInvocationHandler.invoke(AbstractClosureInvocationHandler.java:29) ~[?:?]

	at com.sun.proxy.$Proxy519.apply(Unknown Source) ~[?:?]

	at org.eclipse.smarthome.model.script.internal.actions.TimerExecutionJob.execute(TimerExecutionJob.java:48) ~[?:?]

	at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[?:?]

	... 1 more

Caused by: java.lang.IllegalArgumentException

	at sun.reflect.GeneratedMethodAccessor197.invoke(Unknown Source) ~[?:?]

	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]

	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1086) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1061) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._invokeFeature(XbaseInterpreter.java:1047) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeFeature(XbaseInterpreter.java:992) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:151) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:772) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:220) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluateArgumentExpressions(XbaseInterpreter.java:1116) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._invokeFeature(XbaseInterpreter.java:1046) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeFeature(XbaseInterpreter.java:992) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:151) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:772) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:220) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:447) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:228) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluate(XbaseInterpreter.java:190) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.ClosureInvocationHandler.doInvoke(ClosureInvocationHandler.java:46) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.AbstractClosureInvocationHandler.invoke(AbstractClosureInvocationHandler.java:29) ~[?:?]

	at com.sun.proxy.$Proxy519.apply(Unknown Source) ~[?:?]

	at org.eclipse.smarthome.model.script.internal.actions.TimerExecutionJob.execute(TimerExecutionJob.java:48) ~[?:?]

	at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[?:?]

	... 1 more

And timer do not run in loop after this.

Where do i add this delay Rich?
If i set it direct after

then

then the commands added witout any delay.

You have to add it to the forEach that is sending the command to the members of gSocket3All.

As I indicated in my previous reply, you cannot use a Group to trigger the Gatekeeper Rule. Not even if you use Member of, unless you are sending the command to each member individually (i.e. you cannot sendCommand to the Group Item).

To make this work properly, you need to create a proxy for the Arduino Item. This proxy Item is what triggers the Gatekeeper Rule. Then you need a proxy for gSocket3All which triggers a different rule. In that other rule, forEach over gSocket3All’s members sending the proper command to the Arduino proxy Item then add the small thread sleep too give the Gatekeeper Rule time to create the Timer before the rule triggered again.

Note, I don’t believe this is a problem at all when using the Python version.

1 Like

Undersood! I will try, thanks, Rich!
But the problem above https://community.openhab.org/t/design-pattern-gate-keeper/36483/31?u=thisisio in not in all this . The rule crashes at once even if i triger only one switch.
It is somthing with deltaTime. Please, look in log.