Rule issue with Hue blink (LSELECT) and custom color

Hi there,

I’ve the following scenario:
Up on an incoming phone call I want to switch on my Hue lights in the living room, make it blink in a pre-defined color (not the latest color that is currently set for the bulb) for a while then switch color back and depending whether the bulb was already on or off before the call has arrived, switch it off again (or leave it on).
The issue I’m facing is in the condition if the bulb was off before. Because then, I’m not able to change the color back. It just turns off and stays with the pre-defined color. So next time someone switch on the lights, the “wrong” color is set.
For example: The current color should be green. The pre-defined color should be red. So if a call arrives, the bulb should blink in red but then switch back to the previous state (green). To let it blink, I’m sending the command LSELECT to the bulb which works fine for my use-case.

Based on the rule below: It all works as expected, if the bulb is ON and a phone call arrives. Then, it switches from green to red and blink for 15 seconds or so (based on LSELECT) and after the timer exceeds the color switch back to green and the bulb is in previous state.
It does not work as expected if the bulb is OFF and a phone call arrives. If so, the bulb switches to ON (I can see that it’s for some millis in green) then it will switch to red and starts blinking (fine so far) but then the issue is, that after LSELECT is done and the timer has finished it does not switch back to green but it just goes OFF and therefore the color red remains as setting.

Because I’m a beginner it might be that I misunderstood something regarding the timer? Or at the end my approach to fulfill the requirement is wrong? I appreciate any help why the bulb does not set the previous color if it is OFF .

This is the rule:

//Globals required otherwise the error  is: Cannot refer to the non-final variable lichtWohnzimmerAn inside a lambda expression
var int lichtWohnzimmerAn 	= 0  // 0=false, 1=true
var HSBType backupColorWohnzimmer

rule "Eingehender Anruf"
when
	Item fboxRinging received update ON
then
	lichtWohnzimmerAn = if (Licht_Wohnzimmer.state == ON) 1 else 0
	//Falls Licht noch nicht an, dann einschalten
	if(lichtWohnzimmerAn == 0) {
		Licht_Wohnzimmer.sendCommand(ON)
	}
	//Aktuelle Farbe der Lampe ermitteln und speichern
	backupColorWohnzimmer = Licht_Wohnzimmer_Farbe.state as HSBType
	//Blinkfarbe definieren			
	var DecimalType hue = new DecimalType(0) // 0-360; 0=red, 120=green, 240=blue, 360=red(again)
	var PercentType sat = new PercentType(100) // 0-100
	var PercentType bright = new PercentType(100) // 0-100
	var HSBType blinkLichtFarbe = new HSBType(hue,sat,bright)
	
	Licht_Wohnzimmer_Farbe.sendCommand(blinkLichtFarbe)
    Licht_Wohnzimmer_Alarm.sendCommand("LSELECT") //läuft ca. 15 Sekunden
 	//Rund 20 Sekunden warten (mit Puffer) bis LSELECT definitiv durchlaufen ist 
    createTimer(now.plusSeconds(20), 
	[|
		//Wohnzimmer: Farbe zuruecksetzen und Licht ausschalten (falls vorher aus gewesen ist)
		Licht_Wohnzimmer_Farbe.sendCommand(backupColorWohnzimmer)
		//Wenn folgende Abfrage zutrifft, passiert der 'Fehler'. Licht geht nur aus, ohne die vorherige Zeile zu beruecksichtigen
		if(lichtWohnzimmerAn == 0) { 
			Licht_Wohnzimmer.sendCommand(OFF)
		}    		
	])	
end

BR

Hi Mario,

Try to add a Thread.sleep(600) between sending the Licht_Wohnzimmer_Farbe.sendCommand(backupColorWohnzimmer)
and the last Licht_Wohnzimmer.sendCommand(ON). The bulbs need a little delay to execute and finish each command.

Openhab fetch every 5 seconds … (default) when send command Licht_Wohnzimmer_Farbe.sendCommand(backupColorWohnzimmer) the state for Openhab is lichtWohnzimmerAn 0… after the next fetch is the state the backup state…

I have test it without the Alert… because I have no bulb how support this :wink:

Your rule is too complicated… this is enough and works :slight_smile:

var HSBType backupColorWohnzimmer

rule "Eingehender Anruf"
when
	Item fboxRinging changed from OFF to ON
then
	backupColorWohnzimmer = Licht_Wohnzimmer_Farbe.state as HSBType
	Licht_Wohnzimmer_Farbe.sendCommand(new HSBType(new DecimalType(360), new PercentType(100), new PercentType(100)))
    //Perhaps here a little Delay ... I can't test it ;-)
    Licht_Wohnzimmer_Alarm.sendCommand("LSELECT")
    createTimer(now.plusSeconds(20), 
	[|
		Licht_Wohnzimmer_Farbe.sendCommand(backupColorWohnzimmer) 		
	])	
end

Thank you both very much for the answers and even for testing it,

good to know that OH fetches values every 5 seconds. I’ve never used such a high value because its too spread for the use case. Your code works well but will even fail with the same issue because you don’t switch the bulb OFF at the end. If you would switch it OFF in the rule and then manually ON again, the bulb will shine in red and not the color that was set before blinking.

However, without knowing the 5 seconds fetch time, I did some further try&error testing and found a possible solution by myself after digging deeper and getting more familiar with the HSBType. The reason of the strange behavior is, that the Brightness is still 0 after switching the bulb to ON and trying to get the current color immediately with:

backupColorWohnzimmer = Licht_Wohnzimmer_Farbe.state as HSBType

Solution for me is to extract brightness from the HSBType, then check the value and if it’s 0 just set it to 100 and create a new instance with the changed value:

	var currentState = Licht_Wohnzimmer_Farbe.state as HSBType
	var PercentType currentBrightness = currentState.brightness
	if(currentBrightness.intValue == 0){
		currentBrightness = new PercentType(100)
	}	
	backupColorWohnzimmer = new HSBType(currentState.hue,
                                           currentState.saturation,
                                                currentBrightness)	

This works perfect, even for the use-case the light was OFF and should go OFF again. I guess if I would set the Thread.sleep(5000) right after the Licht_Wohnzimmer.sendCommand(ON) it would work, too. But as this is not an option for me, I set the Brightness manually to 100%.
Finally, this also explains why it’s always working if the bulb is ON before.

BR,

you don’t need set the brightness to 100 in an extra command …

if the Bulb is off and you send this command:

Licht_Wohnzimmer_Farbe.sendCommand(new HSBType(new DecimalType(360), new PercentType(100), new PercentType(100)))

the bulb goes On …

after the timer the backupColor is send … and if in backup color the brightness is 0 … the bulb goes Off

I think not … because I write the old Color from the backupColor …

Thanks again. Just now I’ve tested it again with the Thread.sleep(5000) and it also works for both use-cases BUT if you use this command, you have to switch on the bulb before. So the following code is necessary:

	if(lichtWohnzimmerAn == 0){
		Licht_Wohnzimmer.sendCommand(ON)
		Thread.sleep(5000)
	}

If I just start the rule with the Thread.sleep(5000) without switching ON the bulb before it does not work. So the backup color is not set and therefore the color remains in the alert color after switching OFF.
I have no clue what causes this issue exactly. At least to answer my initial question by myself: There are 2 workarounds, one is to use Thread.sleep() which does not fit my needs and the second one is to set the Brightness to 100% before sending the Alert command - you’re right, then I don’t need to switch ON the bulb before. I’m not sure why this action seems to be triggered immediately (or considered by OH immediately) and for the other one I’ve to wait at least 5 seconds. Maybe this is also related to the Hue bulb model? All my bulbs are 0210 models and with all of them I’m facing the same issue.

This is the complete rule script which is working with Thread.sleep():

var int lichtWohnzimmerAn = 0
var HSBType backupColorWohnzimmer

rule "Eingehender Anruf"
when
	Item fboxRinging received update ON
then
	lichtWohnzimmerAn = if (Licht_Wohnzimmer.state == ON) 1 else 0 
	if(lichtWohnzimmerAn == 0){
		Licht_Wohnzimmer.sendCommand(ON)
		Thread.sleep(5000)
	}
	backupColorWohnzimmer = Licht_Wohnzimmer_Farbe.state as HSBType
	
	var HSBType blinkLichtFarbe = HSBType::RED
	
	Licht_Wohnzimmer_Farbe.sendCommand(blinkLichtFarbe)
    Licht_Wohnzimmer_Alarm.sendCommand("LSELECT")

	createTimer(now.plusSeconds(20), [|
		Licht_Wohnzimmer_Farbe.sendCommand(backupColorWohnzimmer)
		if(lichtWohnzimmerAn == 0) { 
			Licht_Wohnzimmer.sendCommand(OFF)	
		} 
	])
end

And this is the complete rule script which works with setting the Brightness. It saves at least 4+ seconds of the sleep command:

var int lichtWohnzimmerAn = 0 
var HSBType backupColorWohnzimmer

rule "Eingehender Anruf"
when
	Item fboxRinging received update ON
then
	lichtWohnzimmerAn = if (Licht_Wohnzimmer.state == ON) 1 else 0 

	var currentState = Licht_Wohnzimmer_Farbe.state as HSBType
	var PercentType currentBrightness = currentState.brightness
	if(currentState.brightness.intValue == 0){
		currentBrightness = new PercentType(100)
	}
	backupColorWohnzimmer = new HSBType(currentState.hue,currentState.saturation,currentBrightness)

	var HSBType blinkLichtFarbe = HSBType::RED

	Licht_Wohnzimmer_Farbe.sendCommand(blinkLichtFarbe)
    Licht_Wohnzimmer_Alarm.sendCommand("LSELECT")

	createTimer(now.plusSeconds(20), [|
		Licht_Wohnzimmer_Farbe.sendCommand(backupColorWohnzimmer)
		if(lichtWohnzimmerAn == 0) { 
			Licht_Wohnzimmer.sendCommand(OFF)	
		} 
	])
end

For both rules the assumption is: If the bulb is ON once a call arrives then it should shine at least 5 seconds in the current color (prior the call), otherwise the backup still won’t work as expected. But in my use-case this is negligible.

Thanks for your code which works almost perfect for me. I wanted to have:

  • A rule, which realizes a blinking bulb (in red color) :white_check_mark:

  • a rule, which stores the state before executing the rule and restores the prior state afterwards :white_check_mark:

  • a rule which allows the duration of blinking :x:

  • a rule which allows adjusting the blink speed (to a slower speed than here) :x:

    var int lichtWohnzimmerAn = 0 
    var HSBType backupColorWohnzimmer
    
    rule "Zonenreinigung beendet"
    when
      Item Light2_Toggle received command ON
    then
      lichtWohnzimmerAn = if (Light1_Toggle.state == ON) 1 else 0 
    
      var currentState = Light1_Color.state as HSBType
      var PercentType currentBrightness = currentState.brightness
      if(currentState.brightness.intValue == 0){
      	currentBrightness = new PercentType(100)
      }
      backupColorWohnzimmer = new HSBType(currentState.hue,currentState.saturation,currentBrightness)
    
      var HSBType blinkLichtFarbe = HSBType::RED
    
      Light1_Color.sendCommand(blinkLichtFarbe)
      Light1_Alert.sendCommand("LSELECT")
    
      createTimer(now.plusSeconds(15), [|
      	Light1_Color.sendCommand(backupColorWohnzimmer)
      	if(lichtWohnzimmerAn == 0) { 
      		Light1_Toggle.sendCommand(OFF)	
      	} 
      ])
    end
    

This piece of code fulfills the two missing requirements from above:

// Create a timer to blink the light for 10 seconds
val timeStarted = now
timer = createTimer(now, [ | 
    Light1_Toggle.sendCommand(if(Light1_Toggle.state == ON) OFF else ON)
    if(now.isBefore(timeStarted.plusSeconds(10))) timer.reschedule(now.plusSeconds(1))
    else timer = null
])

Unfortunately I couldn’t merge the 2 pieces of code in a working rule, even if I know that I somehow have to substitute the line “Licht_Wohnzimmer_Alarm.sendCommand(“LSELECT”)”.

Could somebody please give me a hint how to put them together?

Kind regards
Linus