Design Pattern : Expire Binding based Countdown timer

Complex example

A more practical use of the countdown technique where Groups are used in an ‘associated Items’ way, exploiting the Group features of rules in OH2.3 onwards.
One rule operates many counters, and derives the name of the ‘target’ light from the counter name being processed.
Control is as before, by sending a number to the counter in a Command eg. from a rule responding to a motion sensor.

// example counters
Group gCounters
Group gLights
Number LampAA_counter "Minutes counter A[%s]" <clock> (gCounters) {expire="1m,command=-1", autoupdate="false"}
Switch LampAA "example light A [%s]" <light> (gLights)
Number LampBB_counter "Minutes counter B[%s]" <clock> (gCounters) {expire="1m,command=-1", autoupdate="false"}
Switch LampBB "example light B [%s]" <light> (gLights)

.

// Rule to manage countdowns
rule "Countdown tick"
when
	Member of gCounters received command
then
	var cmmd = (receivedCommand as Number).intValue // integers only
	var count = 0
	if (triggeringItem.state != NULL) {  // avoid 1st time run error
		count = (triggeringItem.state as Number).intValue
	}
	val lightname = triggeringItem.name.split("_").get(0)  // derive light
	val myLight = gLights.members.filter[ i | i.name == lightname ].head // get light item
    
	if (cmmd == -1 && count > 0) {  // decrement counter, do not go below zero
		if (count == 1) {
			// do actions for counter expiry, as we about to zero it now
			myLight.sendCommand(OFF)
		}
		triggeringItem.postUpdate(count - 1)
	} else if (cmmd == 0) {  // cancel countdown
		triggeringItem.postUpdate(0)
		// do optional cancel actions
		myLight.sendCommand(OFF)
	} else if (cmmd >= count || cmmd < -1) {  // new or refreshed target
		if (cmmd < -1) {  // force override
			cmmd = 0 - cmmd  // make it positive
		}
		triggeringItem.postUpdate(cmmd)  // nb we still update even if equal value - resets expire binding
		// do startup/continue actions
		if (myLight.state != ON) {
			myLight.sendCommand(ON)
		}
	}
end

See Rik’s ‘Associated Items’ design pattern for group/item naming

EDIT - changed order of main ‘if’ evaluation, so that accidentally commanding 0/cancel when already zero will not trigger light.

8 Likes