Rule optimization: Window OPEN reminder

You should definitely define EG_wo_fe_li as Number, not as String. This will not affect the mapping or any other part of your configuration, but you will get the state as a number.
The first filter then would be (in theory):

if (gHContacts.members.filter[ w | if(w.state instanceof Number) (w.state as Number) > 0 else w.state == OPEN ].size == 0)

The timer code would be more difficult to deal with. Of course you will have to use another filter for the open filter:

var openWins = gHContacts.members.filter[ w | if(w.state instanceof Number) (w.state as Number) == 2 else w.state == OPEN ]

Please be aware that you have to use the if statement if(w.state instanceof Number) as openHAB will throw a nasty error if trying to compare a number with a not-number.

for ajar you will need another string:

var ajarWins = gHContacts.members.filter[ w | w.state instanceof Number ].filter[ v | v.state as Number == 1 ]

Itā€™s easier first to filter all those items which have a number state instead of using the if statement. :slight_smile:

You will then have to use the same procedures to build the correct sentence as for openWins.

There is a shortcut to use of mixed Items of Contact and Number type. I had a play before realising OP was using strings.

mysteryItem.getStateAs(DecimalType)
will return 0 for number 0, or for contact CLOSED
and obvs 1 or 2 etc. for number, and 1 for contact OPEN

So long as number 0 and contact CLOSED represent the same ā€œsafeā€ state, you can easily find non-zero Items for the ā€œunsafeā€ state

I think, I need to solve the existing problems firstā€¦after 12h running the rule, I receive some errors from time to time:

2019-03-01 09:09:41.218 [INFO ] [.eclipse.smarthome.model.script.Test] - Running Window openNEW Rule: EG_Vi_hkpump == ON
2019-03-01 09:09:41.225 [INFO ] [.eclipse.smarthome.model.script.Test] - stopMotionTimer is null, proceeding to create the timer
2019-03-01 09:09:41.233 [INFO ] [.eclipse.smarthome.model.script.Test] - Rule is done
2019-03-01 09:10:32.078 [INFO ] [.smarthome.model.script.system.rules] - Uptime updated to 2 Tage / 6 Std. / 9 Min.
2019-03-01 09:10:41.231 [INFO ] [.eclipse.smarthome.model.script.Test] - Inside the timer
2019-03-01 09:10:41.356 [INFO ] [.eclipse.smarthome.model.script.Test] - Open window Items: [DB_fe_te (Type=ContactItem, State=OPEN, Label=Technik Fenster, Category=null, Groups=[gHFenster, gDB, gDBFenster, gTE, gHContacts])]
2019-03-01 09:10:41.426 [INFO ] [.eclipse.smarthome.model.script.Test] - Open window names: [Technikraum im Dachboden]
2019-03-01 09:10:41.489 [INFO ] [.eclipse.smarthome.model.script.Test] - Open window message: Technikraum im Dachboden
2019-03-01 09:10:41.495 [INFO ] [.eclipse.smarthome.model.script.Test] - Sent message to the Echo
2019-03-01 09:10:41.499 [INFO ] [.eclipse.smarthome.model.script.Test] - Set the Timer to null
2019-03-01 09:11:21.158 [INFO ] [.eclipse.smarthome.model.script.Test] - Inside the timer
2019-03-01 09:11:21.166 [ERROR] [org.quartz.core.JobRunShell         ] - Job DEFAULT.2019-03-01T09:11:21.155+01:00: Proxy for org.eclipse.xtext.xbase.lib.Procedures$Procedure0: [ | {
  logInfo(<XStringLiteralImpl>,<XStringLiteralImpl>)
  var openWins
  logInfo(<XStringLiteralImpl>,<XBinaryOperationImplCustom>)
  var openWinsNames
  logInfo(<XStringLiteralImpl>,<XBinaryOperationImplCustom>)
  var openWinsMsg
  logInfo(<XStringLiteralImpl>,<XBinaryOperationImplCustom>)
  <null>.openWinsMsg = <XMemberFeatureCallImplCustom>
  logInfo(<XStringLiteralImpl>,<XBinaryOperationImplCustom>)
  <XFeatureCallImplCustom>.sendCommand(<XBinaryOperationImplCustom>)
  logInfo(<XStringLiteralImpl>,<XStringLiteralImpl>)
  <null>.stopMotionTimer = <XNullLiteralImplCustom>
  logInfo(<XStringLiteralImpl>,<XStringLiteralImpl>)
} ] threw an unhandled Exception: 
java.lang.NullPointerException: null
	at org.eclipse.smarthome.model.script.engine.ScriptError.<init>(ScriptError.java:66) ~[?:?]
	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:140) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:902) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:865) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:224) ~[?:?]
	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:768) ~[?:?]
	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:827) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:264) ~[?:?]
	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.$Proxy150.apply(Unknown Source) ~[?:?]
	at org.eclipse.smarthome.model.script.internal.actions.TimerExecutionJob.execute(TimerExecutionJob.java:49) ~[?:?]
	at org.quartz.core.JobRunShell.run(JobRunShell.java:202) [107:org.eclipse.smarthome.core.scheduler:0.10.0.oh240]
	at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [107:org.eclipse.smarthome.core.scheduler:0.10.0.oh240]
2019-03-01 09:11:21.340 [ERROR] [org.quartz.core.ErrorLogger         ] - Job (DEFAULT.2019-03-01T09:11:21.155+01:00: Proxy for org.eclipse.xtext.xbase.lib.Procedures$Procedure0: [ | {
  logInfo(<XStringLiteralImpl>,<XStringLiteralImpl>)
  var openWins
  logInfo(<XStringLiteralImpl>,<XBinaryOperationImplCustom>)
  var openWinsNames
  logInfo(<XStringLiteralImpl>,<XBinaryOperationImplCustom>)
  var openWinsMsg
  logInfo(<XStringLiteralImpl>,<XBinaryOperationImplCustom>)
  <null>.openWinsMsg = <XMemberFeatureCallImplCustom>
  logInfo(<XStringLiteralImpl>,<XBinaryOperationImplCustom>)
  <XFeatureCallImplCustom>.sendCommand(<XBinaryOperationImplCustom>)
  logInfo(<XStringLiteralImpl>,<XStringLiteralImpl>)
  <null>.stopMotionTimer = <XNullLiteralImplCustom>
  logInfo(<XStringLiteralImpl>,<XStringLiteralImpl>)
} ] threw an exception.
org.quartz.SchedulerException: Job threw an unhandled exception.
	at org.quartz.core.JobRunShell.run(JobRunShell.java:213) [107:org.eclipse.smarthome.core.scheduler:0.10.0.oh240]
	at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [107:org.eclipse.smarthome.core.scheduler:0.10.0.oh240]
Caused by: java.lang.NullPointerException
	at org.eclipse.smarthome.model.script.engine.ScriptError.<init>(ScriptError.java:66) ~[?:?]
	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:140) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:902) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:865) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:224) ~[?:?]
	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:768) ~[?:?]
	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:827) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:264) ~[?:?]
	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.$Proxy150.apply(Unknown Source) ~[?:?]
	at org.eclipse.smarthome.model.script.internal.actions.TimerExecutionJob.execute(TimerExecutionJob.java:49) ~[?:?]
	at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[?:?]
	... 1 more

The rule is actually like this:

rule "Window state announcement"
when
    Member of gHContacts changed
then
    if(previousState == NULL) return;
    if(gHContacts.members.filter[ w | w.state == OPEN ].size == 0) {
        stopMotionTimer?.cancel
        stopMotionTimer = null
        logInfo("Test","All windows closed. Ending...")
        Echo_TTS.sendCommand("Ich registriere, dass alle Fenster nun geschlossen sind. Danke!")
        return;
    }
    var Number TimerLength = 1
    logInfo("Test", "Running Window openNEW Rule: EG_Vi_hkpump == " + EG_Vi_hkpump.state.toString)
    if(EG_Vi_hkpump.state == OFF) return;
    if(triggeringItem.state == CLOSED) 
        TimerLength = 1 
    if(stopMotionTimer !== null) 
        stopMotionTimer.reschedule(now.plusMinutes(TimerLength.intValue))
    else {
        logInfo("Test", "stopMotionTimer is null, proceeding to create the timer")

        // Set the timer
        stopMotionTimer = createTimer(now.plusMinutes(TimerLength.intValue), [|
            logInfo("Test", "Inside the timer")
            // Generate a list of all the open windows
            var openWins = gHContacts.members.filter[ w | w.state == OPEN ]
            logInfo("Test", "Open window Items: " + openWins)
            var openWinsNames = openWins.map[ transform("MAP", "windows.map", name) ]
            logInfo("Test", "Open window names: " + openWinsNames)
            var openWinsMsg = openWinsNames.reduce[ msg, winName | msg + " und " + winName ]
            logInfo("Test", "Open window message: " + openWinsMsg)

            //openWinsMsg = openWinsMsg.replaceFirst(" und ", "") // delete the first comma
            //logInfo("Test", "Deleted the first und: " + openWinsMsg)
            // openWinsMsg = openWinsMsg.replaceLast(", ", "und ") // replace the last comma with "und"
            // logInfo("Test", "Replaced last comma with und: " + openWinsMsg)

            Echo_TTS.sendCommand("Die Heizung ist an. Bitte Fenster schlieƟen im " + openWinsMsg + ".")
            logInfo("Test", "Sent message to the Echo")
            stopMotionTimer = null
            logInfo("Test", "Set the Timer to null")
        ])
    }
    logInfo("Test", "Rule is done")
end

Any idea what the problem is?

When timer jobs mysteriously fail, it is very often because you are trying to process a null in there somewhere.

For example,

var openWins = gHContacts.members.filter[ w | w.state == OPEN ]

What happens if there are no Items OPEN when the timer code runs?
You must code defensively, and check if a result is what you expect before trying to use it.

Okay, but here we also have the rule for windows CLOSED. And there is nothing more than OPEN or CLOSEDā€¦I hope :wink:
What I donā€™t fully understand is the following.

rule "Window state announcement"
when
    Member of gHContacts changed
then
    if(previousState == NULL) return;
    if(gHContacts.members.filter[ w | w.state == OPEN ].size == 0) {
        stopMotionTimer?.cancel
        stopMotionTimer = null
        logInfo("Test","All windows closed. Ending...")
        //stopMotionTimer = createTimer(now.plusMinutes(1), [|
        Echo_TTS.sendCommand("Ich registriere, dass alle Fenster nun geschlossen sind. Danke!")
        return;
        //])
    }
    var Number TimerLength = 15
    logInfo("Test", "Running Window openNEW Rule: EG_Vi_hkpump == " + EG_Vi_hkpump.state.toString)
    if(EG_Vi_hkpump.state == OFF) return;
    if(triggeringItem.state == CLOSED) 
        TimerLength = 1 
    if(stopMotionTimer !== null) 
        stopMotionTimer.reschedule(now.plusMinutes(TimerLength.intValue))
    else {
        logInfo("Test", "stopMotionTimer is null, proceeding to create the timer")

        // Set the timer
        stopMotionTimer = createTimer(now.plusMinutes(TimerLength.intValue), [|
            logInfo("Test", "Inside the timer")
            // Generate a list of all the open windows
            var openWins = gHContacts.members.filter[ w | w.state == OPEN ]
            logInfo("Test", "Open window Items: " + openWins)
            var openWinsNames = openWins.map[ transform("MAP", "windows.map", name) ]
            logInfo("Test", "Open window names: " + openWinsNames)
            var openWinsMsg = openWinsNames.reduce[ msg, winName | msg + " und " + winName ]
            logInfo("Test", "Open window message: " + openWinsMsg)

            //openWinsMsg = openWinsMsg.replaceFirst(" und ", "") // delete the first comma
            //logInfo("Test", "Deleted the first und: " + openWinsMsg)
            // openWinsMsg = openWinsMsg.replaceLast(", ", "und ") // replace the last comma with "und"
            // logInfo("Test", "Replaced last comma with und: " + openWinsMsg)

            Echo_TTS.sendCommand("Die Heizung ist an. Bitte Fenster schlieƟen im " + openWinsMsg + ".")
            logInfo("Test", "Sent message to the Echo")
            stopMotionTimer = null
            logInfo("Test", "Set the Timer to null")
        ])
    }
    logInfo("Test", "Rule is done")
end

ā€“stopMotionTimer?.cancel
ā€“stopMotionTimer = null
If windows are all CLOSED, than the Alexa message and then return without timer.
So why the ā€œstopMotionTimer?.cancelā€ and ā€œstopMotionTimer = nullā€ at this point? There will be no timer when all windows are closed, or?
The timer comes afterwards, when windows are OPEN?

I also get this error:

2019-03-01 12:32:29.528 [INFO ] [.eclipse.smarthome.model.script.Test] - Running Window openNEW Rule: EG_Vi_hkpump == OFF
2019-03-01 12:32:37.368 [INFO ] [.eclipse.smarthome.model.script.Test] - Running Window openNEW Rule: EG_Vi_hkpump == OFF
2019-03-01 12:32:37.407 [INFO ] [.eclipse.smarthome.model.script.Test] - Running Window openNEW Rule: EG_Vi_hkpump == OFF
2019-03-01 12:32:47.509 [INFO ] [.eclipse.smarthome.model.script.Test] - Running Window openNEW Rule: EG_Vi_hkpump == OFF
2019-03-01 12:34:44.918 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Window state announcement': null
2019-03-01 12:34:44.962 [INFO ] [.eclipse.smarthome.model.script.Test] - Running Window openNEW Rule: EG_Vi_hkpump == ON
2019-03-01 12:34:44.984 [INFO ] [.eclipse.smarthome.model.script.Test] - Rule is done
2019-03-01 12:35:32.064 [INFO ] [.smarthome.model.script.system.rules] - Uptime updated to 1 Std. / 29 Min.
2019-03-01 12:36:38.648 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Window state announcement': null
2019-03-01 12:36:38.725 [INFO ] [.eclipse.smarthome.model.script.Test] - Running Window openNEW Rule: EG_Vi_hkpump == ON
2019-03-01 12:36:38.746 [INFO ] [.eclipse.smarthome.model.script.Test] - Rule is done
2019-03-01 12:37:45.546 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Window state announcement': null
2019-03-01 12:37:45.590 [INFO ] [.eclipse.smarthome.model.script.Test] - Running Window openNEW Rule: EG_Vi_hkpump == ON
2019-03-01 12:37:45.603 [INFO ] [.eclipse.smarthome.model.script.Test] - Rule is done

Yes there is. You might have NULL after a reboot or edit, before the binding updates your Item. Or maybe UNDEF if thereā€™s a communications error with one window.

Letā€™s say you want to sound a horn if any windows are open.
A way to do that is to search for state != CLOSED
Itā€™s not quite the same thing, because it will also find any NULL etc. where you are not sure if they are closed or not.
You get to choose which way to do these things.

What happens if you open and close a window quickly?

If the timer is running, cancel stops the scheduled future execution.
Setting the placeholder to null as well is a convenient way to erase it, so that you can easily detect later if this timer is running or not.

That should return an empty List, not null.

It is the same as

if(stopMotionTimer === null){
    stopMotionTimer.cancel
}

Because we use the existence of a timer to determine whether we ignore subsequent OPEN events, whenever we cancel the timer or the timer is done we need to set stopMotionTimer to null.

When all the windows are closed we want to cancel the Alexa announcement. That is what those two lines do.

If a window later opens, the Timer will be recreated.

Hi,
can somebody help me with the transformation? Getting this error:

2019-03-04 21:55:01.855 [INFO ] [.eclipse.smarthome.model.script.Test] - Inside the timer

2019-03-04 21:55:01.921 [INFO ] [.eclipse.smarthome.model.script.Test] - Open window Items: [OG_Schlafzimmer_Fenster_State (Type=ContactItem, State=OPEN, Label=Schlafzimmerfenster, Category=contact, Groups=[gHContacts, Whg])]

2019-03-04 21:55:02.040 [WARN ] [rm.AbstractFileTransformationService] - Could not transform ā€˜OG_Schlafzimmer_Fenster_Stateā€™ with the file ā€˜windows.mapā€™ : Target value not found in map for ā€˜OG_Schlafzimmer_Fenster_Stateā€™

2019-03-04 21:55:02.044 [INFO ] [.eclipse.smarthome.model.script.Test] - Open window names:

2019-03-04 21:55:02.103 [WARN ] [rm.AbstractFileTransformationService] - Could not transform ā€˜OG_Schlafzimmer_Fenster_Stateā€™ with the file ā€˜windows.mapā€™ : Target value not found in map for ā€˜OG_Schlafzimmer_Fenster_Stateā€™

2019-03-04 21:55:02.107 [INFO ] [.eclipse.smarthome.model.script.Test] - Open window message:

2019-03-04 21:55:02.114 [INFO ] [.eclipse.smarthome.model.script.Test] - Deleted the first comma:

My windows.map just has this entries:

CLOSED=geschlossen
OPEN=offen

Your Item is probably NULL or UNDEF and since you donā€™t have NULL or UNDEF defined in the map file the transformation returns nothing.

Thanks for the fast reply, seems that NULL or UNDEF is not the problem, it seems the building of the list for the open windows is not working

2019-03-05 22:31:07.285 [INFO ] [.eclipse.smarthome.model.script.Test] - Running Window openNEW Rule: EG_Vi_hkpump == ON
2019-03-05 22:31:07.376 [INFO ] [.eclipse.smarthome.model.script.Test] - stopMotionTimer is null, proceeding to create the timer
2019-03-05 22:31:07.393 [INFO ] [.eclipse.smarthome.model.script.Test] - Rule is done
2019-03-05 22:32:07.382 [INFO ] [.eclipse.smarthome.model.script.Test] - Inside the timer
2019-03-05 22:32:07.477 [INFO ] [.eclipse.smarthome.model.script.Test] - Open window Items: [OG_Duschbad_Fenster_State (Type=ContactItem, State=OPEN, Label=Duschbadfenster, Category=contact, Groups=[gHContacts, Whg])]
2019-03-05 22:32:07.525 [WARN ] [rm.AbstractFileTransformationService] - Could not transform ā€˜OG_Duschbad_Fenster_Stateā€™ with the file ā€˜windows.mapā€™ : Target value not found in map for ā€˜OG_Duschbad_Fenster_Stateā€™
2019-03-05 22:32:07.555 [INFO ] [.eclipse.smarthome.model.script.Test] - Open window names:
2019-03-05 22:32:07.602 [WARN ] [rm.AbstractFileTransformationService] - Could not transform ā€˜OG_Duschbad_Fenster_Stateā€™ with the file ā€˜windows.mapā€™ : Target value not found in map for ā€˜OG_Duschbad_Fenster_Stateā€™
2019-03-05 22:32:07.633 [INFO ] [.eclipse.smarthome.model.script.Test] - Open window message:
2019-03-05 22:32:07.638 [INFO ] [.eclipse.smarthome.model.script.Test] - Deleted the first comma:
2019-03-05 22:32:07.641 [ERROR] [org.quartz.core.JobRunShell ] - Job DEFAULT.2019-03-05T22:32:07.378+01:00: Proxy for org.eclipse.xtext.xbase.lib.Procedures$Procedure0: [ | {
logInfo(,)
var openWins
logInfo(,)
var openWinsNames
logInfo(,)
var openWinsMsg
logInfo(,)
.openWinsMsg =
logInfo(,)
.sendCommand()
logInfo(,)
.stopMotionTimer =
logInfo(,)
} ] threw an unhandled Exception:
java.lang.reflect.UndeclaredThrowableException: null
at com.sun.proxy.$Proxy163.apply(Unknown Source) ~[?:?]
at org.eclipse.smarthome.model.script.internal.actions.TimerExecutionJob.execute(TimerExecutionJob.java:49) ~[?:?]
at org.quartz.core.JobRunShell.run(JobRunShell.java:202) [107:org.eclipse.smarthome.core.scheduler:0.10.0.oh240]
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [107:org.eclipse.smarthome.core.scheduler:0.10.0.oh240]
Caused by: org.eclipse.smarthome.model.script.engine.ScriptExecutionException: The name ā€˜Echo_TTSā€™ cannot be resolved to an item or type; line 42, column 13, length 8
at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:141) ~[?:?]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:902) ~[?:?]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:865) ~[?:?]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:224) ~[?:?]
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:768) ~[?:?]
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) ~[?:?]
ā€¦ 4 more
2019-03-05 22:32:07.698 [ERROR] [org.quartz.core.ErrorLogger ] - Job (DEFAULT.2019-03-05T22:32:07.378+01:00: Proxy for org.eclipse.xtext.xbase.lib.Procedures$Procedure0: [ | {
logInfo(,)
var openWins
logInfo(,)
var openWinsNames
logInfo(,)
var openWinsMsg
logInfo(,)
.openWinsMsg =
logInfo(,)
.sendCommand()
logInfo(,)
.stopMotionTimer =
logInfo(,)
} ] threw an exception.
org.quartz.SchedulerException: Job threw an unhandled exception.
at org.quartz.core.JobRunShell.run(JobRunShell.java:213) [107:org.eclipse.smarthome.core.scheduler:0.10.0.oh240]
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [107:org.eclipse.smarthome.core.scheduler:0.10.0.oh240]
Caused by: java.lang.reflect.UndeclaredThrowableException
at com.sun.proxy.$Proxy163.apply(Unknown Source) ~[?:?]
at org.eclipse.smarthome.model.script.internal.actions.TimerExecutionJob.execute(TimerExecutionJob.java:49) ~[?:?]
at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[?:?]
ā€¦ 1 more
Caused by: org.eclipse.smarthome.model.script.engine.ScriptExecutionException: The name ā€˜Echo_TTSā€™ cannot be resolved to an item or type; line 42, column 13, length 8
at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:141) ~[?:?]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:902) ~[?:?]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:865) ~[?:?]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:224) ~[?:?]
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:768) ~[?:?]
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.$Proxy163.apply(Unknown Source) ~[?:?]
at org.eclipse.smarthome.model.script.internal.actions.TimerExecutionJob.execute(TimerExecutionJob.java:49) ~[?:?]
at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[?:?]
ā€¦ 1 more

The first step is working

 var openWins = gHContacts.members.filter[ w | w.state == OPEN ]

openWins is afterwards
[OG_Duschbad_Fenster_State (Type=ContactItem, State=OPEN, Label=Duschbadfenster, Category=contact, Groups=[gHContacts, Whg])]

Step two, is not working

var openWinsNames = openWins.map[ transform("MAP", "windows.map", name)

Unluckyly I donā€™t understand how the transformation work, perhaps somebody can enlight me. The further steps canā€™t work in my opinion because the var openWinsNames is empty and cant be further processed. So I think thats the point where I need help.

My Items are like that:

Contact OG_Duschbad_Fenster_State ā€œDuschbadfenster [MAP(windows.map):%s]ā€ (gHContacts, Whg) {channel=ā€œhomematic:HMIP-SWDO:ccu:0000D3Cxxxx7F5:1#STATE_CONTACTā€}

windows.maps (in folder transformation) looks like that

CLOSED=geschlossen
OPEN=offen
NULL=unbekannt
UNDEF=unbekannt
-=unbekannt

You donā€™t want to transform the name, you want to transform the state of the Item.

transform("MAP", "windows.map", state.toString)

Hello all,
I adapted the rule from @killercorny. It works pretty well so far. My problem is that from time to time I get multiple notifications at random intervals between 1 and 5 minutes.
according to my openhab.log the rule ā€œFenster checkā€ fires in almost the same interval.
Is anyone else using the Xiaomi window sensors and experiencing the same behaviour?

Regards
Florian

Thanks a lot for this topic. It helped me with creating my own version of this rule that I would like to share with you.

The main things I changed are:

  • Each window gets itā€™s own timer
  • The timer renews itself after its execution
  • If the heat pump, season item or whatever gets switched off, the timer will be canceled (necessary because the timer now renews itself)

import java.util.Map

var Map<String, Timer> timers = newHashMap

rule ā€œWindow state announcementā€
when
Member of gFenster changed
then
val Number TimerLength = 10

if(Season.state == OFF) {
logInfo("Test", "The timer gets canceled because current season is summer")
timers.get(triggeringItem.name)?.cancel
timers.remove(triggeringItem.name)
return;
}
if(triggeringItem.state == CLOSED) {
    if (timers.get(triggeringItem.name) !== null) {
    timers.get(triggeringItem.name).cancel();
    timers.remove(triggeringItem.name)
    logInfo("Test", transform("MAP", "windows.map", triggeringItem.name) + " is now closed!")
    return;
    }
} else {
    // Set the timer
    logInfo("Test", "New timer created for: " + transform("MAP", "windows.map", triggeringItem.name))
    timers.put(triggeringItem.name, createTimer(now.plusMinutes(TimerLength.intValue), [|
    logInfo("Test", transform("MAP", "windows.map", triggeringItem.name) + " is already open for " + TimerLength + " minutes and should be closed.")
    timers.get(triggeringItem.name).reschedule(now.plusMinutes(1))
    ]))
    
}

end

@Monsterflo: So your sensors randomly change their state?

1 Like

Hello All,
long time no see.
According to my log the state of my sensors only change when the windows are opened/closed.
the first alert comes after five minutes. then randomly. Sometimes 3 times in a row.
Did anyone find a solution for this in the meantime?

Regards
Florian

Hi Arne, Thanks for your inspiration for that rule. I realized my rule based on your proposal and it works fine. Now I have an additional idea and wanted to ask how I can best code it. In your above example when the timer was executed after 10 minutes a message will be given that the window was opened for 10 minutes. As long as the window will not be closed the timer renews every minute. But the given message will still be the same i.e. that the window was opened for 10 minutes although it was opened for 11 minutes after the first renewal of the timer, 12 minutes after the second renewal of the timer and so on. How can I add the additional minute(s) of each timer renewal to the already expired time in order to show the total time the window was opened in the message?

If windows is still open after 10 minutes. Tell openhab to close it :smiley: (sorry just kidding)ā€¦

Seriousā€¦ Is it important for you to know in time, how long the window has been open? If not, I would just send a message saying ā€œWindow is still openā€, or something simular.

That would indeed be an easy solution :grinning: But my idea is a bit more specific as follows. When the initial timer has expired an Alexa voice command is triggered saying ā€žThe window xyz is open for 10 minutes now and should be closedā€œ. That already works fine. If the window xyz will not be closed then the timer renews for letā€˜s say another 10 minutes and when that timer expires the Alexa voice command should be ā€žThe window xyz is open for 20 minutes now and should be closedā€œ and so on with the next 10 minutes and so onā€¦

Create a var on the line just before the call to createTimer and populate it with 0.

var elapsedTime = 0

In the timer, before sending the message to Alexa, add TimerLength to elapsedTime and use elapsedTime in your message

createTimer(now.plusMinutes(TimerLength.intValue), [ |
    elapsedTime = elapsedTime + TimerLength
    logInfo("test", "The window has been open for " + elapsedTime + " minutes.")
    timers.get(triggeringItem.name).reschedule(now.plusMinutes(TimerLength.intValue)
]

Hi Rick, youā€™re the man, thanks a lot for your reply :+1:
I have tried it according to your proposal but itā€™s a bit more tricky. The problem is that your proposal works fine as long as the value of TimerLength is used in an unchanged way also for the reschedule of the timer here: timers.get(triggeringItem.name).reschedule(now.plusMinutes(TimerLength.intValue)
]
If I want to reschedule the timer with a value different from that of TimerLength the wrong sum of elapsedTime is calculated. So letā€™s say, if TimerLength = 10 minutes then the first Alexa message is triggered after 10 minutes (OK). When the time to reschedule the timer is set to 5 minutes in order to get the next Alexa message after 10+5=15 minutes the elapsedTime is calculated by 20 minutes but not 15 minutes (as it was intended) and so the resulting Alexa message is stating a wrong time for the open window. How can I solve that in an efficient way?

Then just add 5 instead of 10. elapsedTime = elapsedTime + TimerLength. Thatā€™s the line that does the addition. Use what ever you use to reschedule instead of TimerLenght.

Honestly, this is simple enough that you should be able to figure out. It would do you well to take a quick online beginning programming course before continuing. ā€œCargo cult programmingā€ (i.e. copying code from the Internet without even a basic understanding of how that code works) is only going to lead you to frustration and disaster. You need to be sure you actually understand what the code does. Itā€™s OK if you canā€™t come up with the code yourself from scratch, but you have to understand how code you are copying works.