If's and While Loops (jumping between them in a single script)

Hi everyone,

I’m writing a script to DIM my Ikea lights on a long press (Velbus) input - but while it looks to be working something strange is happening…
What I wanted is - if the brightness is below 30%, the long press must increase brightness to max 100. If the brightness is above 30% the function must decrease brightness.

What happens now with the below code is that indeed the light goes from 100 to 30% brightness, but then increases again to 40, then back to 30 back to 40 etc… and I dont understand why it would not stay within it’s own loop / if statement…

ideas?

var ButtonLong=false
var ButtonDown=false

rule "Test short press"
when
    Channel 'velbus:vmbgpod-2:7f964e441a:02:input#CH1' triggered PRESSED
then
    ButtonLong=false
        var IKEA_state = IKEA_Color.state()
        logInfo("IKEA","IKEA detected on with luminosity " + IKEA_state.toString)
end

rule "Test long press"
when
    Channel 'velbus:vmbgpod-2:7f964e441a:02:input#CH1' triggered LONG_PRESSED
then
    logInfo("TEST", "Test fired! LONG_PRESSED")
        ButtonLong=true
        ButtonDown=true 

    if (IKEA_Color.state.toString != "0,0,0") {  //validating that the light is actually on
        var HSBType hsbValue = IKEA_Color.state as HSBType
        logInfo("IKEA", "IKEA_Color=" + hsbValue)
        var DecimalType hue = new DecimalType(hsbValue.hue.intValue % 360 + 10) // 0-360; 0=red, 120=green, 240=blue, 360=red(again)
        var PercentType sat = new PercentType(hsbValue.saturation.intValue) // 0-100
        var PercentType bright = new PercentType(hsbValue.brightness.intValue) // 0-100
        logInfo("IKEA", "IKEA_Color_HUE=" + hue)
        logInfo("IKEA", "IKEA_Color_SATURATION=" + sat)
        logInfo("IKEA", "IKEA_Color_BRIGHNTESS=" + bright)
        
        if (bright <30) {  //if the brightness is below 30 - we need to dim upwards 
            logInfo("IKEA", "IKEA_Color_BRIGHNTESS DIM UP")
            while(bright < 100 && ButtonDown == true) {
                bright = bright + 10 // doing 10% on 1000 sleep in a loop till 100% or button down is false - eg released)
                logInfo("IKEA", "IKEA_Color_BRIGHNTESS=" + bright)                
                var newStatus = hue+","+sat+","+bright 
                IKEA_Color.sendCommand(newStatus)
                Thread::sleep(1000) 
            }
        }
        if (bright >30 ) { //if brightness is above 30% we need to dim down by 10% steps
             logInfo("IKEA", "IKEA_Color_BRIGHNTESS DIM DOWN")
            while(bright < 100 && bright > 10 && ButtonDown == true) { //just keeping a minimum of 10% - while button is still pressed downward
                bright = bright - 10
                logInfo("IKEA", "IKEA_Color_BRIGHNTESS=" + bright)
                var newStatus = hue+","+sat+","+bright 
                IKEA_Color.sendCommand(newStatus)
                Thread::sleep(1000) // one minute
                logInfo("IKEA", "IKEA_Color_BRIGHNTESS DIM DOWN NEXT")
                
            }
        }
    }

end

rule "Test release"
when
    Channel 'velbus:vmbgpod-2:7f964e441a:02:input#CH1' triggered RELEASED
then
    ButtonDown = false
    if (ButtonLong==false){
        logInfo("IKEA", "Test fired! PRESSED")

        if (IKEA_Color.state.toString == "0,0,0") { 
            IKEA_Color.sendCommand("ON")
        }
        else{
            IKEA_Color.sendCommand("OFF")
        }
    }
    ButtonLong=false
end

and the log:

21:45:23.906 [INFO ] [org.openhab.core.model.script.TEST   ] - Test fired! LONG_PRESSED
21:45:23.917 [INFO ] [org.openhab.core.model.script.IKEA   ] - IKEA_Color=124,69,59
21:45:23.928 [INFO ] [org.openhab.core.model.script.IKEA   ] - IKEA_Color_HUE=134
21:45:23.935 [INFO ] [org.openhab.core.model.script.IKEA   ] - IKEA_Color_SATURATION=69
21:45:23.942 [INFO ] [org.openhab.core.model.script.IKEA   ] - IKEA_Color_BRIGHNTESS=59
21:45:23.951 [INFO ] [org.openhab.core.model.script.IKEA   ] - IKEA_Color_BRIGHNTESS DIM DOWN
21:45:23.962 [INFO ] [org.openhab.core.model.script.IKEA   ] - IKEA_Color_BRIGHNTESS=49
21:45:23.972 [INFO ] [openhab.event.ItemCommandEvent       ] - Item 'IKEA_Color' received command 134,69,49
21:45:23.980 [INFO ] [openhab.event.ItemStatePredictedEvent] - Item 'IKEA_Color' predicted to become 134,69,49
21:45:23.989 [INFO ] [openhab.event.ItemStateChangedEvent  ] - Item 'IKEA_Color' changed from 124,69,59 to 134,69,49
21:45:24.027 [INFO ] [openhab.event.ItemStateChangedEvent  ] - Item 'IKEA_Color' changed from 134,69,49 to 133,69,59
21:45:24.630 [INFO ] [openhab.event.ItemStateChangedEvent  ] - Item 'IKEA_Color' changed from 133,69,59 to 133,69,49
21:45:24.973 [INFO ] [org.openhab.core.model.script.IKEA   ] - IKEA_Color_BRIGHNTESS DIM DOWN NEXT
21:45:24.985 [ERROR] [.internal.handler.ScriptActionHandler] - Script execution of rule with UID 'myrules-2' failed: An error occurred during the script execution: Could not invoke method: org.openhab.core.model.script.lib.NumberExtensions.operator_greaterThan(org.openhab.core.types.Type,java.lang.Number) on instance: null in myrules
21:45:27.838 [INFO ] [openhab.event.ChannelTriggeredEvent  ] - velbus:vmbgpod-2:7f964e441a:02:input#CH1 triggered RELEASED

Which version of openHAB are we dealing with? Behaviour of long-running rules with potential multiple triggers is different for OH2 and OH3.

While-loops are invariably a bad idea in openHABs event driven rule system.
This old thread develops into a timer based method instead.

Interestingly, it also exhibits the same sluggish response problem that you have with hue responses -

After the command, autoupdate predicts the effect and then updates the Item state within a few milliseconds.
A short while later, hue responds to the command with the old state, updating the Item again.
Then after another half-second, hue sends a further update, this time with the post-command state.

A rule that uses Item state to work out next step is going to need to be careful if it is working within a second or two of previous command, you don’t know what you’ll get for “current” state.
You should be okay though, you’re working off a local variable bright instead.

Nope, that’s one second.

Okay, so what is going wrong?

All starts off well - initial bright 59, enter the DIM DOWN code, calculate new bright 49 and issue command.
Then pause, get to end of loop … and fail at the while() evaluation.

I don’t know why that is; so I tried the code myself.

VSCode complains about “ambiguous operations” with bright and >, <, subtraction etc., that’s usually a sign of typing troubles.
var PercentType bright = new PercentType( ...
and I reckon the comparisons are choking on that type.

Letting DSL sort out typing for itself seems to sort everything out, eliminating complaints and leaving a working while-loop

var bright = (IKEA_Color.state as HSBType).brightness.intValue // 0-100

You can get rid of the hue/sat stuff and just do
IKEA_Color.sendCommand(bright)
You can command Color type with just a single number, it will be treated as a dimmer/brightness value.

That seemed to be better…

and its working now - there is indeed a delay in execution (when releasing it still adjusts the light - but so far so good…

var bright = (IKEA_Color.state as HSBType).brightness.intValue // 0-100

I just wanted to point out that since the While loop would run until ‘bright => 100’ that second ‘If’ statement would be triggered and should be fixed with an ‘else’:

        if (bright <30) {  //if the brightness is below 30 - we need to dim upwards 
            logInfo("IKEA", "IKEA_Color_BRIGHNTESS DIM UP")
...
        }
        else if (bright >30 )

Agreed. Thnx!