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
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
Your rule is too complicated… this is enough and works
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.
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 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)
a rule, which stores the state before executing the rule and restores the prior state afterwards
a rule which allows the duration of blinking
a rule which allows adjusting the blink speed (to a slower speed than here)
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?