Thread not stopping

I am using an EnOcean rocker with 4 taps to control a set of 3 Hues (all 3 in parallel, i. e. same brightness and color temperature). A short click sets brightness and color temperature to 100 or 0 percent, a longer (holding) click dims up or down. The functionality is inspired from Kai’s Enocean video.

Variables brightIter1, warmIter1 are used to keep track of how many iterations have been counted. If the value of such an iteration variable is still low (i. e. not much time has passed when depressing), then an instant 100 or 0 percent are set. That does work.

Not working however is the longer click: I understand that createTimer() creates a new thread, however besides receiving a timely “OFF”, the dimming threads are never stopped. They run all the way through to 100 or to 0.

The code is quite lengthy. - Any suggestions on improving this - please comment.

var Timer brightTimer1 = null // may not contain underscores?!
var Timer warmTimer1 = null
var PercentType brightPercent1 = new PercentType(0)
var PercentType warmPercent1 = new PercentType(0)
var Integer brightIter1 = new Integer(0)
var Integer warmIter1 = new Integer(0)

var Timer brightTimer2 = null
var Timer warmTimer2 = null
var PercentType brightPercent2 = new PercentType(0)
var PercentType warmPercent2 = new PercentType(0)
var Integer brightIer2 = new Integer(0)
var Integer warmIter2 = new Integer(0)

rule "FT4_1 for Licht @EG brighter"
	when
		Item FT4_1_A_Up received update
	then
		if(FT4_1_A_Up.toString().contains("ON")) {
			brightIter1 = new Integer(0)
			brightTimer1 = createTimer(now.plusSeconds(1)) [|
				for(i: 1..10) {
					brightIter1 = new Integer(brightIter1.intValue + 1)
					brightPercent1 = new PercentType(brightPercent1.intValue + 10)
					sendCommand(Hue_Dimm_1, brightPercent1)
					sendCommand(Hue_Dimm_3, brightPercent1)
					sendCommand(Hue_Dimm_5, brightPercent1)
					if(brightPercent1.intValue > 100) brightPercent1 = new PercentType(100)
					Thread::sleep(1000)
				}
			]
		} else if(FT4_1_A_Up.toString().contains("OFF")) {
				brightTimer1.cancel
				brightTimer1 = null
				if(brightIter1.intValue < 2) {
					brightPercent1 = new PercentType(100)
					sendCommand(Hue_Dimm_1, brightPercent1)
					sendCommand(Hue_Dimm_3, brightPercent1)
					sendCommand(Hue_Dimm_5, brightPercent1)
				}
		}
end

rule "FT4_1 for Licht @EG darker"
	when
		Item FT4_1_A_Dn received update
	then
		if(FT4_1_A_Dn.toString().contains("ON")) {
			brightIter1 = new Integer(0)
			brightTimer1 = createTimer(now.plusSeconds(1)) [|
				for(i: 1..10) {
					brightPercent1 = new PercentType(brightPercent1.intValue - 10)
					if(brightPercent1.intValue < 0) brightPercent1 = new PercentType(0)
					sendCommand(Hue_Dimm_1, brightPercent1)
					sendCommand(Hue_Dimm_3, brightPercent1)
					sendCommand(Hue_Dimm_5, brightPercent1)
					brightIter1 = new Integer(brightIter1.intValue + 1)
					Thread::sleep(1000)
				}				
			]
		} else if(FT4_1_A_Dn.toString().contains("OFF")) {
				brightTimer1.cancel
				brightTimer1 = null
				if(brightIter1.intValue < 2) {
					brightPercent1 = new PercentType(0)
					sendCommand(Hue_Dimm_1, brightPercent1)
					sendCommand(Hue_Dimm_3, brightPercent1)
					sendCommand(Hue_Dimm_5, brightPercent1)
				}		
		}
end

rule "FT4_1 for Licht @EG warmer"
	when
		Item FT4_1_B_Up received update
	then
		if(FT4_1_B_Up.toString().contains("ON")) {
			warmIter1 = new Integer(0)
			warmTimer1 = createTimer(now.plusSeconds(1)) [|
				for(i: 1..10) {
					warmPercent1 = new PercentType(warmPercent1.intValue + 10)
					if(warmPercent1.intValue > 100) warmPercent1 = new PercentType(100)
					sendCommand(Hue_CT_Dimm_1, warmPercent1)
					sendCommand(Hue_CT_Dimm_3, warmPercent1)
					sendCommand(Hue_CT_Dimm_5, warmPercent1)
					warmIter1 = new Integer(warmIter1.intValue + 1)
					Thread::sleep(1000)
				}
			]
		} else if(FT4_1_B_Up.toString().contains("OFF")) {
				warmTimer1.cancel
				warmTimer1 = null
				if(warmIter1.intValue < 2) {
					warmPercent1 = new PercentType(100)
					sendCommand(Hue_CT_Dimm_1, warmPercent1)
					sendCommand(Hue_CT_Dimm_3, warmPercent1)
					sendCommand(Hue_CT_Dimm_5, warmPercent1)
				}		
		}
end

rule "FT4_1 for Licht @EG colder"
	when
		Item FT4_1_B_Dn received update
	then
		if(FT4_1_B_Dn.toString().contains("ON")) {
			warmIter1 = new Integer(0)
			warmTimer1 = createTimer(now.plusSeconds(1)) [|
				for(i: 1..10) {
					warmPercent1 = new PercentType(warmPercent1.intValue - 10)
					if(warmPercent1.intValue < 0) warmPercent1 = new PercentType(0)
					sendCommand(Hue_CT_Dimm_1, warmPercent1)
					sendCommand(Hue_CT_Dimm_3, warmPercent1)
					sendCommand(Hue_CT_Dimm_5, warmPercent1)
					warmIter1 = new Integer(warmIter1.intValue + 1)
					Thread::sleep(1000)
				}
			]
		} else if(FT4_1_B_Dn.toString().contains("OFF")) {
				warmTimer1.cancel
				warmTimer1 = null
				if(warmIter1.intValue < 2) {
					warmPercent1 = new PercentType(0)
					sendCommand(Hue_CT_Dimm_1, warmPercent1)
					sendCommand(Hue_CT_Dimm_3, warmPercent1)
					sendCommand(Hue_CT_Dimm_5, warmPercent1)
				}		
		}
end

Keeps dimming down besides releasing the button:

2017-06-16 06:02:47 - FT4_1_A_Dn state updated to ON
...
2017-06-16 06:02:48 - Hue_Dimm_1 received command 100
2017-06-16 06:02:48 - Hue_Dimm_3 received command 100
2017-06-16 06:02:48 - Hue_Dimm_5 received command 100
2017-06-16 06:02:50 - Hue_Dimm_1 received command 90
2017-06-16 06:02:50 - Hue_Dimm_3 received command 90
2017-06-16 06:02:50 - Hue_Dimm_5 received command 90
2017-06-16 06:02:50 - FT4_1_A_Dn state updated to OFF
2017-06-16 06:02:51 - Hue_Dimm_1 received command 80
2017-06-16 06:02:51 - Hue_Dimm_3 received command 80
2017-06-16 06:02:51 - Hue_Dimm_5 received command 80
2017-06-16 06:02:51 - Hue_Toggle_5 state updated to ON
2017-06-16 06:02:51 - Hue_CT_Dimm_5 state updated to ON
2017-06-16 06:02:51 - Hue_Dimm_1 state updated to 80
2017-06-16 06:02:51 - Hue_Color_1 state updated to 189.642857142857138796898652799427509307861328125,93,80
2017-06-16 06:02:51 - Hue_Color_5 state updated to ON
2017-06-16 06:02:51 - Hue_Color_5 state updated to 189.642857142857138796898652799427509307861328125,93,80
2017-06-16 06:02:51 - Hue_Color_3 state updated to 189.642857142857138796898652799427509307861328125,93,80
2017-06-16 06:02:51 - Hue_Dimm_3 state updated to 80
2017-06-16 06:02:51 - Hue_Dimm_5 state updated to ON
2017-06-16 06:02:51 - Hue_Dimm_5 state updated to 80
2017-06-16 06:02:52 - Hue_Dimm_1 received command 70
2017-06-16 06:02:52 - Hue_Dimm_3 received command 70
2017-06-16 06:02:52 - Hue_Dimm_5 received command 70
...

Ah - to stop an already running thread, I probably need a shared variable to communicate the wish to stop.

Hi,
when you keep the button pressed, the rule fires constantly, thus creating timer after timer. As a first measure, i think you should build in a check if there is allready a timer running. something like:

//only create timer when none active...
if brightTimer1 == null {
        //create a new timer...
        brightTimer1 = createTimer(now.plusSeconds(1))
       }

that should reduce repeated actions even after you have released the button.
HTH,
-OLI

This might help:

1 Like

Thanks @rlkoshak - the cancel pattern / variable works well. I have named it “doBright1” (for running the brightness dimmer) and “doWarm1” (for running the warmness dimmer).

@Oli For that type of energy-harvesting rocker, every ON when pressing is followed by an OFF when depressing (and no repeated ONs in between), therefore I do not care much about timers being null. When looking at the logs, the rules for the update do not fire constantly.

Also, I added the concept of detecting double clicks and setting random colors - working code below.

This is in progress; I need to factor out constant values and replace individual objects with iterators on groups somehow.

best regards

Klaus

var boolean doBright1 = true // the cancel pattern
var boolean doWarm1 = true // dito
var org.joda.time.DateTime lastClick1 = now // for measuring double click timespan
var boolean isBrightDouble1 = false
var boolean isWarmDouble1 = false
var Timer brightTimer1 = null // may not contain underscores?!
var Timer warmTimer1 = null
var PercentType brightPercent1 = new PercentType(0)
var PercentType warmPercent1 = new PercentType(0)
var Integer brightIter1 = new Integer(0)
var Integer warmIter1 = new Integer(0)

rule "FT4_1 for light @EG brighter"
	when
		Item FT4_1_A_Up received update
	then
		if(FT4_1_A_Up.toString().contains("ON")) {
			isBrightDouble1 = (now.getMillis() - lastClick1.getMillis()) < 750
			lastClick1 = now
			brightIter1 = new Integer(0)
			doBright1 = true
			brightTimer1 = createTimer(now.plusSeconds(1)) [|
				// for(i: 1..10) {
				var i = 0;
				while(doBright1 && (i = i + 1) < 10) {
					brightIter1 = new Integer(brightIter1.intValue + 1)
					brightPercent1 = new PercentType(brightPercent1.intValue + 10)
					sendCommand(Hue_Dimm_1, brightPercent1)
					sendCommand(Hue_Dimm_3, brightPercent1)
					sendCommand(Hue_Dimm_5, brightPercent1)
					if(brightPercent1.intValue > 100) brightPercent1 = new PercentType(100)
					try { Thread::sleep(1000) } catch(Throwable t) {}
				}
			]
		} else if(FT4_1_A_Up.toString().contains("OFF")) {
			brightTimer1.cancel
			brightTimer1 = null
			doBright1 = false
			if(brightIter1.intValue == 0) {
				if(isBrightDouble1) brightPercent1 = new PercentType(100)
				else brightPercent1 = new PercentType(50)
				sendCommand(Hue_Dimm_1, brightPercent1)
				sendCommand(Hue_Dimm_3, brightPercent1)
				sendCommand(Hue_Dimm_5, brightPercent1)
			}
		}
end

rule "FT4_1 for light @EG darker"
	when
		Item FT4_1_A_Dn received update
	then
		if(FT4_1_A_Dn.toString().contains("ON")) {
			isBrightDouble1 = (now.getMillis() - lastClick1.getMillis()) < 750
			lastClick1 = now
			brightIter1 = new Integer(0)
			doBright1 = true
			brightTimer1 = createTimer(now.plusSeconds(1)) [|
				var i = 0;
				while(doBright1 && (i = i + 1) < 10) {
					brightPercent1 = new PercentType(brightPercent1.intValue - 10)
					if(brightPercent1.intValue < 0) brightPercent1 = new PercentType(0)
					sendCommand(Hue_Dimm_1, brightPercent1)
					sendCommand(Hue_Dimm_3, brightPercent1)
					sendCommand(Hue_Dimm_5, brightPercent1)
					brightIter1 = new Integer(brightIter1.intValue + 1)
					try { Thread::sleep(1000) } catch(Throwable t) {}
				}				
			]
		} else if(FT4_1_A_Dn.toString().contains("OFF")) {
			brightTimer1.cancel
			brightTimer1 = null
			doBright1 = false
			if(brightIter1.intValue == 0) {
				if(isBrightDouble1) brightPercent1 = new PercentType(50)
				else brightPercent1 = new PercentType(0)
				sendCommand(Hue_Dimm_1, brightPercent1)
				sendCommand(Hue_Dimm_3, brightPercent1)
				sendCommand(Hue_Dimm_5, brightPercent1)
			}		
		}
end

rule "FT4_1 for light @EG warmer"
	when
		Item FT4_1_B_Up received update
	then
		if(FT4_1_B_Up.toString().contains("ON")) {
			isWarmDouble1 = (now.getMillis() - lastClick1.getMillis()) < 750
			lastClick1 = now
			warmIter1 = new Integer(0)
			doWarm1 = true
			warmTimer1 = createTimer(now.plusSeconds(1)) [|
				var i = 0;
				while(doWarm1 && (i = i + 1) < 10) {
					warmPercent1 = new PercentType(warmPercent1.intValue + 10)
					if(warmPercent1.intValue > 100) warmPercent1 = new PercentType(100)
					sendCommand(Hue_CT_Dimm_1, warmPercent1)
					sendCommand(Hue_CT_Dimm_3, warmPercent1)
					sendCommand(Hue_CT_Dimm_5, warmPercent1)
					warmIter1 = new Integer(warmIter1.intValue + 1)
					try { Thread::sleep(1000) } catch(Throwable t) {}
				}
			]
		} else if(FT4_1_B_Up.toString().contains("OFF")) {
			warmTimer1.cancel
			warmTimer1 = null
			doWarm1 = false
			if(warmIter1.intValue == 0) {
				if(isWarmDouble1) {
						var int randomHue = (new java.util.Random).nextInt(360)
						// var int randomSat = (new java.util.Random).nextInt(20)	
						var DecimalType hue = new DecimalType(randomHue) // 0-360; 0=red, 120=green, 240=blue, 360=red(again)
						var PercentType sat = new PercentType(100) // 0-100
						var PercentType bright = new PercentType(50) // 0-100
						var HSBType light = new HSBType(hue,sat,bright)
						sendCommand(Hue_Color_1, light)
						sendCommand(Hue_Color_3, light)
						sendCommand(Hue_Color_5, light)
				} else {
					warmPercent1 = new PercentType(100)
					sendCommand(Hue_CT_Dimm_1, warmPercent1)
					sendCommand(Hue_CT_Dimm_3, warmPercent1)
					sendCommand(Hue_CT_Dimm_5, warmPercent1)
				}
			}		
		}
end

rule "FT4_1 for light @EG colder"
	when
		Item FT4_1_B_Dn received update
	then
		if(FT4_1_B_Dn.toString().contains("ON")) {
			isWarmDouble1 = (now.getMillis() - lastClick1.getMillis()) < 750
			lastClick1 = now
			warmIter1 = new Integer(0)
			doWarm1 = true
			warmTimer1 = createTimer(now.plusSeconds(1)) [|
				var i = 0;
				while(doWarm1 && (i = i + 1) < 10) {
					warmPercent1 = new PercentType(warmPercent1.intValue - 10)
					if(warmPercent1.intValue < 0) warmPercent1 = new PercentType(0)
					sendCommand(Hue_CT_Dimm_1, warmPercent1)
					sendCommand(Hue_CT_Dimm_3, warmPercent1)
					sendCommand(Hue_CT_Dimm_5, warmPercent1)
					warmIter1 = new Integer(warmIter1.intValue + 1)
					try { Thread::sleep(1000) } catch(Throwable t) {}
				}
			]
		} else if(FT4_1_B_Dn.toString().contains("OFF")) {
			warmTimer1.cancel
			warmTimer1 = null
			doWarm1 = false
			if(warmIter1.intValue == 0) {
				if(isWarmDouble1) {
					var DecimalType hue = new DecimalType(0) // 0-360; 0=red, 120=green, 240=blue, 360=red(again)
					var PercentType sat = new PercentType(0) // 0-100
					var PercentType bright = new PercentType(50) // 0-100
					var HSBType light = new HSBType(hue,sat,bright)
					sendCommand(Hue_Color_1, light)
					sendCommand(Hue_Color_3, light)
					sendCommand(Hue_Color_5, light)
				} else {
					warmPercent1 = new PercentType(0)
					sendCommand(Hue_CT_Dimm_1, warmPercent1)
					sendCommand(Hue_CT_Dimm_3, warmPercent1)
					sendCommand(Hue_CT_Dimm_5, warmPercent1)
				}
			}		
		}
end