I want my rule to just run the first time in a 24h window?

I have the following rule;

when 
       Item Z_LUX_GF_Hallway changed
then 
	logInfo("Z_LuxSetpoint_GF_Hallway", "GF Lux changed. Lux: "+Z_LUX_GF_Hallway.state+" - SetPoint: "+Z_LuxSetpoint_GF_Hallway.state+" - Strip Light: "+Hue_LivingRoom_StripLight.state)
       	if ((Z_LUX_GF_Hallway.state as DecimalType) < (Z_LuxSetpoint_GF_Hallway.state as DecimalType) && Twilight_Lux.state == ON) 
        { 
        sendCommand(Hue_LivingRoom_StripLight, ON)
	logInfo("Z_LuxSetpoint_GF_Hallway", "GF Lux changed. Lux: "+Z_LUX_GF_Hallway.state+" - SetPoint: "+Z_LuxSetpoint_GF_Hallway.state+" - Strip Light: "+Hue_LivingRoom_StripLight.state)
	sendMail("poe@email.address", "GF Lux < SetPoint", "GF Lux is below the SetPoint, StripLight is now ON")							  
        } 
end

Which works absolutely fine. However, I check my Lux status every 5 minutes, and this is causing the rule to trigger many times.

Is there a way to just run the rule one time?

For example, my Twilight_Lux item is a dynamic window that is enabled 3 hours before SunSet and then goes off at Midnight. It would be brilliant if this rule would only fire one time during this window…

If you know the time that this rule is active for, why not set a simple latch? e.g. (note the two additions to your previous rule)

var boolean ruleTriggered = false
rule "Do the thing"
when 
       Item Z_LUX_GF_Hallway changed
then 
	logInfo("Z_LuxSetpoint_GF_Hallway", "GF Lux changed. Lux: "+Z_LUX_GF_Hallway.state+" - SetPoint: "+Z_LuxSetpoint_GF_Hallway.state+" - Strip Light: "+Hue_LivingRoom_StripLight.state)
       	if ((Z_LUX_GF_Hallway.state as DecimalType) < (Z_LuxSetpoint_GF_Hallway.state as DecimalType) && Twilight_Lux.state == ON && !ruleTriggered) 
        { 
        sendCommand(Hue_LivingRoom_StripLight, ON)
	logInfo("Z_LuxSetpoint_GF_Hallway", "GF Lux changed. Lux: "+Z_LUX_GF_Hallway.state+" - SetPoint: "+Z_LuxSetpoint_GF_Hallway.state+" - Strip Light: "+Hue_LivingRoom_StripLight.state)
	sendMail("poe@email.address", "GF Lux < SetPoint", "GF Lux is below the SetPoint, StripLight is now ON")
	ruleTriggered = true						  
        } 
end

rule "Reset Trigger"
when
	Time cron "0 0 1 1/1 * ? *"
then
	ruleTriggered = false
end
2 Likes

I didn’t know anything about ‘a latch’ - but it looks ideal! Thank you @Benjy !!

Question is, what exactly does it do?? Is it essentially a ‘switch’ for rule on, and rule off… ie. when triggered the rule is ON and stays on until the Cron time turns it off (midnight)…?

and what difference does ‘knowing the time it’s active for’ make, I ask, given the start time will be forever moving.

I presume in your example, ‘ruleTriggered’ can be renamed???

This is an excellent design pattern. I’m going to include it when I write up there design patterns section of the guide.

When ruleTriggered is false, the logic of the rule runs. One line in that logic sets ruleTriggered to true. As long as ruleTriggered is true, the if condition will be false so the logic will not run.

ruleTriggered remains false until the rule at midnight runs to set it back to false. The first time the main rule with the logic runs after midnight it can now run the logic because ruleTriggered is false.

There are several ways to implement this in addition to the above. One way is to use a Timer instead of the rule that runs at midnight to reset the ruleTriggered flag. Another is to use a reentrantLock instead of the boolean flag, though that would tie up a thread in the tread pool so I wouldn’t recomend it except for relatively short periods of time.

You can name ruleTriggered anything you want. The band didn’t matter.

The Cron in the example sets ruleTriggered to false at 1am each day, but this is fine because you know that your lux item goes off at midnight, but say you didn’t know a fixed time and just wanted to stop a rule from working more than once every 3 hours you can use a timer as @rlkoshak says e.g. :

var boolean ruleLock = false
var Timer exampleTimer = null
rule "Example Rule Timeout"
when
	Item someThing changed
then
	// If ruleLock is false
	if(!ruleLock){

	// Do things here
		
	//Stop this rule being triggered again
		ruleLock = true 
	//Then Create a timer that unlocks it in three hours
		exampleTimer = createTimer(now.plusHours(3)) [|
			ruleLock = false
		]
	}
end
2 Likes

I added your original effort with the Cron, to my rules, unfortunately this prevented all other rules from running, for some reason. I could see my items changing status, but no rules were firing…

I’ll try the timer route.

Sounds like you introduced a syntax error. Are you using designer? Are there errors in the log?

I’m not, I really should start to use designer I suppose :blush:

I’ll install it and have a peek.

It was whinging about missing an EOF for the var (which I had tagged to the bottom of my file, as part of the rule above)

I have since moved the vars to the top of the rules file… Will see what happens 2 hours before sunset I guess :slight_smile:

Ah yes, should probably mention that vars and vals (constants) should only be declared at the top, after imports if you have any.