Lambda and endless loop

Hi all,
first of all: thanks for the amazing work, that the community does. I am using openHAB since about 6 months controlling my lights and rollershutters (by LCN / Issendorff). Recently, I introduced Alexa and got a rule to manage the up/down/stop commands. The item looks as follows:

Rollershutter EGArbeitszimmerGross "Arbeitszimmer Gross"  <rollershutter> (Huette, Strasse, EGAZimmer)["Switchable"] {lcn="[UP:lcnzinow:RELAYS.0.14.----11--], [DOWN:lcnzinow:RELAYS.0.14.----10--], [STOP:lcnzinow:RELAYS.0.14.----00--]"}

The corresponsing rule looks like this:

rule "EGAZG"
when
	 Item EGArbeitszimmerGross received command
then
	logInfo("EGAZG","Rule triggered with {}",receivedCommand)
	switch(receivedCommand) {
		case 100 : {
			EGArbeitszimmerGross.sendCommand(UP)
			logInfo("EGAZ","Rollo hoch")
			}
		case 49 : {
			EGArbeitszimmerGross.sendCommand(STOP)
			logInfo("EGAZ","Rollo STOP")
			}	
		case 0 : {
			EGArbeitszimmerGross.sendCommand(DOWN)
			logInfo("EGAZ","Rollo runter")
			}
	}
end

and it works fine. As I have quite a few rollershutters I looked for a way to write a routine, that I could pass both the item name as well as the command to avoid duplicating code. I found @rlkoshak contributions on the concept of lambdas and converted my rule into the following:

import org.eclipse.xtext.xbase.lib.Functions

val Functions$Function2<GenericItem, String, Boolean> rollladenHandler = [
	GenericItem rollladen, String Wert | 
        logInfo("Lambda","Lambda: " + rollladen.name.toString + " " + Wert)
        switch(Integer.parseInt(Wert)) {
		case 100 : {
			rollladen.sendCommand(DOWN)
			logInfo("Lambda",rollladen.name.toString + " down")
			}
		case 49 : {
			rollladen.sendCommand(STOP)
			logInfo("Lambda",rollladen.name.toString + " stop")
			}	
		case 0 : {
			rollladen.sendCommand(UP)
			logInfo("Lambda",rollladen.name.toString + " up")
			}
		}
    true
]

rule "EGAZG"
when 
	Item EGArbeitszimmerGross received command
then
	logInfo("EGAZG","Rule EGAZG triggerd with ",receivedCommand)
		rollladenHandler.apply(EGArbeitszimmerGross,EGArbeitszimmerGross.state.toString)
end

The result is, that it looks as if the rule performs the task and then triggers itself.

10:16:39.402 [INFO ] [eclipse.smarthome.model.script.EGAZG] - Rule EGAZG triggerd with UP
10:16:39.406 [INFO ] [clipse.smarthome.model.script.Lambda] - Lambda: EGArbeitszimmerGross 0
10:16:39.409 [INFO ] [smarthome.event.ItemCommandEvent    ] - Item 'EGArbeitszimmerGross' received command UP
10:16:39.410 [INFO ] [clipse.smarthome.model.script.Lambda] - EGArbeitszimmerGross up
10:16:39.414 [INFO ] [eclipse.smarthome.model.script.EGAZG] - Rule EGAZG triggerd with UP
10:16:39.418 [INFO ] [clipse.smarthome.model.script.Lambda] - Lambda: EGArbeitszimmerGross 0
10:16:39.421 [INFO ] [smarthome.event.ItemCommandEvent    ] - Item 'EGArbeitszimmerGross' received command UP
10:16:39.422 [INFO ] [clipse.smarthome.model.script.Lambda] - EGArbeitszimmerGross up
10:16:39.426 [INFO ] [eclipse.smarthome.model.script.EGAZG] - Rule EGAZG triggerd with UP
10:16:39.429 [INFO ] [clipse.smarthome.model.script.Lambda] - Lambda: EGArbeitszimmerGross 0
10:16:39.432 [INFO ] [smarthome.event.ItemCommandEvent    ] - Item 'EGArbeitszimmerGross' received command UP
10:16:39.433 [INFO ] [clipse.smarthome.model.script.Lambda] - EGArbeitszimmerGross up
10:16:39.436 [INFO ] [eclipse.smarthome.model.script.EGAZG] - Rule EGAZG triggerd with UP
10:16:39.440 [INFO ] [clipse.smarthome.model.script.Lambda] - Lambda: EGArbeitszimmerGross 0
10:16:39.442 [INFO ] [smarthome.event.ItemCommandEvent    ] - Item 'EGArbeitszimmerGross' received command UP
10:16:39.443 [INFO ] [clipse.smarthome.model.script.Lambda] - EGArbeitszimmerGross up
10:16:39.447 [INFO ] [eclipse.smarthome.model.script.EGAZG] - Rule EGAZG triggerd with UP
10:16:39.451 [INFO ] [clipse.smarthome.model.script.Lambda] - Lambda: EGArbeitszimmerGross 0
10:16:39.453 [INFO ] [smarthome.event.ItemCommandEvent    ] - Item 'EGArbeitszimmerGross' received command UP

I read about locks and hatches, but have no clue, what I got wrong when introducing the lambda. Any clue?
Best regards
Rainer

Maybe I am getting it wrong, but I am more surprised that you first rule did not show the same behaviour.
You trigger a rule when ITEM received any command ; you then use the very same ITEM in the rule and you send a command to it (which as designed will trigger your rule…in an endless loop).
A few solutions that come to mind:

  • you could try concurrency locks (http://docs.openhab.org/configuration/rules-dsl.html#concurrency-guard); NOTE: if you use that you will be design get messages that show that no lock could be obtained when the sendCommand function is used in your rule
  • you could think about using timestamps (persist these states, add a few thread::sleep statements to make sure that persistence catches up, and then check in your rule whether the last action was just very recently
  • you could add some logic that checks for the current state and does not issue another up command when the shutters are already up
  • you could add a virtual item and send commands to your real things when the virtual item gets triggered
  • not sure about this one: but consider using postUpdate instead of sendCommand; a postUpdate will not trigger your rule (but I am not sure if it would trigger your shutter to do anything either)
1 Like

Markus, thanks a lot. I will work my way through your proposals and come back.