I’m trying to manipulate a value with while function and timer…
looks like this:
Rule "increase volume"
when
Time cron "0 30 10 * * ? *" or
Item TestSwitch received command ON
then
val vol = 50
while ( (vol=vol+1) < 86 ) {
volTimer = createTimer(now.plusSeconds(15))[ |
SqueezeLivingRoomVolume.sendCommand(vol)
logInfo("Squeeze", "Living Room: increasing volume to "+vol)
volTimer = null
]
}
end
but this isn’t working.
log throws this error
==> /var/log/openhab2/openhab.log <==
2019-02-19 19:02:19.670 [ERROR] [ntime.internal.engine.RuleEngineImpl]
- Rule 'increase volume':
An error occurred during the script execution:
Couldn't invoke 'assignValueTo' for feature JvmVoid:
(eProxyURI: squeeze.rules#|::0.2.2.2.0.2::0::/1)
i have no idea what this error is telling me…
any suggestions??
This code can’t possibly be what you intend to do. Here is what it does, in English, assuming it worked as written without the error.
Initialize the vol variable to 50
enter a while loop that will loop from 50 to 85 (35 iterations).
Inside each iteration create a Timer that goes off in 15 seconds.
Inside the timer send the vol value to the Squeezebox.
As a result, you will end up with 35 Timers that in 15 seconds (plus a few milliseconds) all run at the same time and send the command to the Squeezebox at pretty much the same time.
It looks like what you are after is a Thread::sleep, not a Timer. Thread::sleep(x) vs timers in rules. A Timer schedules something to take place in the future. A Thread::sleep causes the Rule to wait the given amount of time before continuing.
But Thread::sleep is a dangerous thing to use. Long running Rules can cause all sorts of problems.
var Timer volTimer = null
rule "increase volume"
when
Time cron "0 30 10 * * ? *" or
Item TestSwitch received command ON
then
volTimer?.cancel
var vol = 51
volTimer = createTimer(now, [|
SqueezeLivingRoomVolulme.sendCommand(vol)
logInfo("Squeeze", "Living Room: increasing volume to " + vol)
vol = vol + 1
if(vol < 86) volTimer.reschedule(now.plusSeconds(15))
else volTimer = null
])
end
NOTE: The error message you are seeing is almost certainly caused by the fact that you are trying to assign a new value to a val. val means constant. You need to define vol as a var.
Also, I’m not sure if you can embed the iteration inside the while loop like that. But a while loop is not the right loop to implement this anyway. You would want to use a for loop.
you’re absolutely right… I tested around a bit - disturbed by a phone call - but got stuck with Thread::sleep what I was trying to avoid because of the known side-effects…
rule "increase volume"
when
Time cron "0 30 10 * * ? *" or
Item TestSwitch received command ON
then
while ( (vol=vol+1) < 86 ) {
SqueezeLivingRoomVolume.sendCommand(vol)
logInfo("Squeeze", "Living Room: increasing volume to "+vol)
Thread::sleep(15000)
}
end
but it’s working…
I will try your code tomorrow because its getting late I have to go to bed now
Ok its working! Nice! I didn’t know that there is this easy way to restart a timer
volTimer.reschedule()
btw could you please explain the questionmark in
volTimer?.cancel
and I don’t really understand why the timer has to be canceled before it is running… or is this because of using the reschedule feature?? Thanks for your help!! I’m still learning…
You cannot guarantee that this Rule will not be triggered again while it is already processing a previous event (i.e. volTimer is not null). This Rule takes almost 9 minutes to complete and you can trigger it manually.
There are two ways to avoid ending up with two copies of the Timer running in this case. Cancel the old one before starting the new one, which is what the above code does. Or ignore the new event and let the old Timer continue to process. That would replace the volTimer?.cancel with
the manual triggering was only for testing purposes… but you’re right the rule takes a long period of time to end.
Good to know that the volTimer?.cancel isn’t essentually neccessary but will provide safety.