Thread::sleep(10000) not working

  • Platform information:
    • Hardware: CPUArchitecture/RAM/storage
    • OS: what OS is used and which version
    • Java Runtime Environment: which java platform is used and what version
    • openHAB version:
  • Issue of the topic: please be detailed explaining your issue
  • Please post configurations (if applicable):
    • Items configuration related to the issue
    • Sitemap configuration related to the issue
    • Rules code related to the issue
    • Services configuration related to the issue
  • If logs where generated please post these here using code fences:

Hello everyone i have a problem with the Thread::sleep(xmillis) opetion.
It seems to be ignored in my rule.


    then
            if (onewiregpio_sensor_1d9a1ad9_temperature.state > Tempa ) {
                    Relais8.sendCommand(ON)
                    createTimer(now.plusMillis(2000), [|
                    Relais8.sendCommand(OFF)
                    ])
                    Tempa = 150
                    Tempb = 26
                    Tempe = 23
            Thread::sleep(10000)

            }

I need the rule to stop here and let the above 2000 timer finish its action before the next one starts.
This is part of a control which opens a hatch when temperatures 24,26,28,30 °C are reached.
But if it is for example above 30° all the part of teh rule are triggered. Normally it should open 8 seconds in all but does only 2 seconds.

Thats why i need the pause.

Whole code below. If needed there are still empty timers which also don´t work. But as a test with the Thread::sleep also seems to be ignored i haven´t chnaged it yet.

var Number Tempa = 24
var Number Tempb = 26
var Number Tempc = 28
var Number Tempd = 30

var Number Tempe = 23
var Number Tempf = 25
var Number Tempg = 27
var Number Temph = 29

rule Temperaturschalter1

when

        Item Relais5 changed from OFF to ON

then

        Tempa = 150
        Tempb = 150
        Tempc = 150
        Tempd = 150
        Tempe = -150
        Tempf = -150
        Tempg = -150
        Temph = -150

        Relais7.sendCommand(ON)
        Relais8.sendCommand(ON)
        createTimer(now.plusMillis(20000), [|
        Relais8.sendCommand(OFF)
        Relais7.sendCommand(OFF)
        ])

end

rule Temperaturschalter2

when

        Item Relais5 changed from ON to OFF

then
        Tempa = 24


end

rule Temperaturschalter3

when

        Item onewiregpio_sensor_1d9a1ad9_temperature changed
then
        if (onewiregpio_sensor_1d9a1ad9_temperature.state > Tempa ) {
                Relais8.sendCommand(ON)
                createTimer(now.plusMillis(2000), [|
                Relais8.sendCommand(OFF)
                ])
                Tempa = 150

if (onewiregpio_sensor_1d9a1ad9_temperature.state > Tempb ) {
                Relais8.sendCommand(ON)
                createTimer(now.plusMillis(2000), [|
                Relais8.sendCommand(OFF)
                ])
                Tempb = 150
                Tempc = 28
                Tempf = 25
        createTimer(now.plusMillis(10000), [| ])

        }

if (onewiregpio_sensor_1d9a1ad9_temperature.state > Tempc ) {
                Relais8.sendCommand(ON)
                createTimer(now.plusMillis(2000), [|
                Relais8.sendCommand(OFF)
                ])
                Tempc = 150
                Tempd = 30
                Tempg = 27
        createTimer(now.plusMillis(10000), [| ])

        }

if (onewiregpio_sensor_1d9a1ad9_temperature.state > Tempd ) {
                Relais8.sendCommand(ON)
                createTimer(now.plusMillis(2000), [|
                Relais8.sendCommand(OFF)
                ])
                Tempd = 150
                Temph = 29
        createTimer(now.plusMillis(10000), [| ])

        }



if (onewiregpio_sensor_1d9a1ad9_temperature.state < Tempe ) {
                Relais7.sendCommand(ON)
                Relais8.sendCommand(ON)
                createTimer(now.plusMillis(2000), [|
                Relais8.sendCommand(OFF)
                Relais7.sendCommand(OFF)
                ])
                Tempe = -150
                Tempa = 24
        createTimer(now.plusMillis(10000), [| ])

        }
if (onewiregpio_sensor_1d9a1ad9_temperature.state < Tempf ) {
                Relais7.sendCommand(ON)
                Relais8.sendCommand(ON)
                createTimer(now.plusMillis(2000), [|
                Relais7.sendCommand(OFF)
                Relais8.sendCommand(OFF)
         ])
                Tempf = -150
                Tempb = 26
        createTimer(now.plusMillis(10000), [| ])

        }

if (onewiregpio_sensor_1d9a1ad9_temperature.state < Tempg ) {
                Relais7.sendCommand(ON)
                Relais8.sendCommand(ON)
                createTimer(now.plusMillis(2000), [|
                Relais8.sendCommand(OFF)
                Relais7.sendCommand(OFF)
                ])
                Tempg = -150
                Tempc = 28
        createTimer(now.plusMillis(10000), [| ])

        }

if (onewiregpio_sensor_1d9a1ad9_temperature.state < Temph ) {
                Relais7.sendCommand(ON)
                Relais8.sendCommand(ON)
                createTimer(now.plusMillis(2000), [|
                Relais8.sendCommand(OFF)
                Relais7.sendCommand(OFF)
                ])
                Temph = -150
                Tempd = 30
        createTimer(now.plusMillis(10000), [| ])


        }

end

Well, that isn’t how Timers nor Thread::sleep work.

First of all, Thread::sleep above around 500 is very dangerous and should be avoided. 10 seconds is an eternity.

Secondly, Timers run in a different Thread in parallel with the Rule. Adding a Thread::sleep does not impact the timer in any way.

Thirdly, a Thread::sleep in a Rule does not prevent another copy of the Rule from running if it gets triggered again. It just means that it will be 10 seconds+ for that one instance of the Rule to exit. If it gets triggered again in that 10 seconds then you have two copies of that Rule running.

You need to come up with a different approach to achieve what you are after.

OK, so rather than have all the parts of the Rule execute, why not instead structure the Rule to just calculate how long the hatch needs to remain open based on the temperature and create a timer for that amount of time?

Create a variable in the Rule to save how long the hatch should remain open. Then at the very end of the Rule is where you create the Timer using the appropriate amount of time.

Thats the Problem,

The state of how much the hatch should open should be entirely Temperature related.
Thats why there are 4 opening states and 4 closing states.

In general this works very good.

However the problem is the “Relais5” in that code which is a rainsensor. when that is triggered it should shut which it does.

Problem is it doesn´t remember the state how often/long it opened. Additionaly during and after rain the temperature normally drops so it should not open at the same state it was before the rain.

This is why i want to run the opening states from 24° upward again after the rainsensor shuts off.

I fail to see the problem.

if(temp < somevalue) opentime = 123
else (if temp >= somevalue && temp < someothervalue) opentime = 456

So you need a Rule triggered by the Relais5 that closes the hatch if it is open and cancels the Timer if one is active.

Right. So the rule would look something like (in psuedo code)

var Timer hatchTimer = null

rule "Rain detected"
when
    Item Relais5 changed to ON
then
    hatchTimer?.cancel
    Relais8.sendCommand(OFF)
end

rule "Temperature changed, opened the hatch when necessary"
then
    Item Temperature changed
then
    var openTime = 0

    if(temp > someLowTemp) openTime = 2000
    else if(temp > someOtherTemp) openTime = 4000
    else if(temp > someEvenLargerTemp) openTime = 8000

    // and so own

    if(openTime > 0) {
        Relais8.sendCommand(ON)
        hatchTimer = createTimer(now.plusMillis(openTime), [ |
            Relais8.sendCommand(OFF)
        ])
    }
    
end

Obviously I left out all the extra stuff you have in your Rules and only show the timer aspects.

Ultimately, Thread::sleep and createTimer do not work the way you think they do and the approach you seem to want to follow is exceptionally difficult to implement in Rules and even if you did, you run a very high risk of running out of runtime threads and locking up all your Rules.

OK thanks,

I will test that out as soon as im back home.

Ok,
heres the modified Rule. I get no Error when saving it but testing it throws an error when Rainsensor(Relais turns off)

Error message is:
ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule ‘Temperaturschalter2’: Unknown variable or command ‘>’; line 44, column 7, length 44





rule Temperaturschalter2

when

        Item Relais5 changed from ON to OFF

then
        if ((onewiregpio_sensor_1d9a1ad9_temperature > 24 ) || (onewiregpio_sensor_1d9a1ad9_temperature  < 26 )) {
                Relais8.sendCommand(ON)
                Tempa = 24
                Tempe = 23
        createTimer (now.plusMillis(2000), [|
                Relais8.sendCommand(OFF)
        ])}
        else if ((onewiregpio_sensor_1d9a1ad9_temperature > 26) || ( onewiregpio_sensor_1d9a1ad9_temperature < 28 )) {
                Relais8.sendCommand(ON)
                Tempb = 26
                Tempf = 25
        createTimer (now.plusMillis(4000), [|
                Relais8.sendCommand(OFF)
        ])}

        else if ((onewiregpio_sensor_1d9a1ad9_temperature > 28 ) || (onewiregpio_sensor_1d9a1ad9_temperature < 30 )) {
                Relais8.sendCommand(ON)
                Tempc = 28
                Tempg = 27
        createTimer (mow.plusMillis(6000), [|
                Relais8.sendCommand(OFF)
        ])}

        else if (onewiregpio_sensor_1d9a1ad9_temperature > 30 ) {
                Relais8.sendCommand(ON)
                Tempd = 30
                Temph = 29
        createTimer (now.plusMillis(8000), [|
                Relais8.sendCommand(OFF)
        ])}

end

Did you forget .state ?? Or did I miss something?

another thing: I guess you want to AND the boundary values, not OR them:

if ((onewiregpio_sensor_1d9a1ad9_temperature.state > 24 ) && (onewiregpio_sensor_1d9a1ad9_temperature.state  < 26 )) {

It’s possible that the temperature is exactly at one of the boundaries, so you would better use <= or >= at one boundary.
And for sure, it would be far better to structure the code:





rule Temperaturschalter2
when
    Item Relais5 changed from ON to OFF
then
    if(!(onewiregpio_sensor_1d9a1ad9_temperature.state instanceof Number)) return;
    val temp = onewiregpio_sensor_1d9a1ad9_temperature.state as Number
    var Number ttime
    if (temp > 30 ) {
        Tempd = 30
        Temph = 29
        ttime= 8000
    } else if(temp > 28) {
        Tempc = 28
        Tempg = 27
        ttime= 6000
    } else if(temp > 26) {
        Tempb = 26
        Tempf = 25
        ttime= 4000
    } else if(temp > 24) {
        Tempa = 24
        Tempe = 23
        ttime= 2000
    }
    if(temp > 24) {
        Relais8.sendCommand(ON)
        createTimer (now.plusMillis(temp.intValue), [|
            Relais8.sendCommand(OFF)
        ])
    }
end

By changing the order it’s not necessary to use two boundaries at all. And the chance to make a typo is less high (mow.plusMillis(6000))

1 Like