Arithmetic operations in rules causing errors

I’m having trouble with what should be simple. The hardest part is that the log file usually gives me unhelpful error messages like “Error during the execution of rule ‘FloorLampByNight’: Index: 1, Size: 1” which is less than I’d expect from a programming environment.

Anyway I’m trying to incorporate the sunset time (no problem), the cloud cover (problem) and a random wait (problem) into my script to turn on a floor lamp. This is early days for openhab for me and I don’t feel that I have found a suitable reference document from which I can learn how to do things like. The examples I’ve been reading are either too simple, very complex or do things I don’t understand.

var Timer duskTimer
var Number c
var Number randomDelay
var Number cloudDelay

rule "FloorLampOff"
when
    Time cron "0 0 20 * * ?"
then
    sendCommand(FloorLamp, OFF)
end

/*
FloorLampByNight
If overcast, turn on the light immediately
If clear, wait 25 minutes
Interpolate between those two points for partially cloudy
Add random delay of 0 to 14 minutes
*/

rule "FloorLampByNight"
when
    Item Sunset_event received update ON or
    Item test_event received command ON
then
    c = Clouds.state
    randomDelay = (new java.util.Random).nextInt(15)
    cloudDelay = ((100 - c) / 4).intValue
    duskTimer = createTimer(now.plusMinutes(randomDelay) [|
            sendCommand(FloorLamp, ON)
    ]

end

I confess I don’t know if I’m getting cloud cover from the weather binding as a percentage or a fraction. I’ve tried both without success, although was at least able to get the code to execute without error with it as a fraction, there was no delay at all even when it was only scattered clouds.

I also haven’t yet understood how to put the equivalent of print statements in the code for debugging. That would be helpful but everything I’ve found so far seems to want me to put XML statements into various files, which is fine if necessary, but I’ve not found an procedure I’m confident to follow at this point.

All help will be greatly appreciated.

Chris

More info:

OK By going through a few more random posts on this forum I found the logInfo function (I guess the XML was for something more sophisticated than writing in openhab.log). So my 3 values are calculated correctly AFAIK.

2015-12-18 16:32:06.232 [INFO ] [.model.script.FloorLampByNight] - Clouds = 100.00
2015-12-18 16:32:06.734 [INFO ] [.model.script.FloorLampByNight] - randomDelay = 13
2015-12-18 16:32:07.562 [INFO ] [.model.script.FloorLampByNight] - cloudDelay = 0

I changed the value in the call to the plusMinutes method to 1, so it’s something simple I’m missing. The weird thing is that I had something similar working before.

It seems you calculated cloudDelay but never make use of it. I think the code should be
createTimer(now.plusMinutes(randomDelay + cloudDelay)

Thanks for the reply Udo. You’re absolutely right, but that’s not the problem. I had exactly what you had there but simplified it to just randomDelay because I was unsure of the value of cloudDelay (whether 0 to 1 or 0 to 100 - I now know it is 0 to 100).

No matter what value I send to plusMinutes, or even if I just put an integer like 1 there, it fails and logs an error.

Chris

What kind of item is “Clouds”? I think you need to convert its state to proper type before computation or extract the number from the state, depending on what item type it is.

In the extract from the Log, Clouds is the variable c, a number, which is an value representing the percentage cloud cover.
Here’s the changes I made to test…

then
    c = Clouds.state
    logInfo("FloorLampByNight", "Clouds = " + c.toString)
    randomDelay = (new java.util.Random).nextInt(15)
    logInfo("FloorLampByNight", "randomDelay = " + randomDelay.toString)
    cloudDelay = ((100 - c) / 4).intValue
    logInfo("FloorLampByNight", "cloudDelay = " + cloudDelay.toString)
    duskTimer = createTimer(now.plusSeconds(30) [|
            sendCommand(FloorLamp, ON)
    ]
end

You can see that in createTimer I changed it to seconds and used an integer (i.e. I didn’t use any of the calculations) - but it still fails. So now I just tried commenting out all 6 lines before the one that starts with duskTimer and it still fails, putting the following message into openhab.log.

2015-12-19 09:05:17.500 [ERROR] [o.o.c.s.ScriptExecutionThread ] - Error during the execution of rule ‘FloorLampByNight’: Index: 1, Size: 1

I must confess that I don’t understand the meaning of the [| … ] syntax, but that’s what all the examples seem to have.

So what I know is that everything up to that line works fine. As a final experiment I commented out the 3 line statement beginning with duskTimer and now it prints out the values of the 3 variables and does not log any errors. Today clouds are 23% (although it is actually overcast and snowing, but that’s not openhab’s fault) and cloudDelay is 19 as I would expect.

Chris

OK One more clue. If I remove the createTimer line but remove sendCommand it works.

/*
duskTimer = createTimer(now.plusSeconds(30) [|
/
sendCommand(FloorLamp, ON)
/

]
*/

So that’s about as simple as it gets, I think.

did you import the necessary classes?

import org.openhab.model.script.actions.Timer
import org.joda.time.*
should be in top of rule-file

I wasn’t importing the org.joda.time.* but it makes no difference. I cut all the fluff I could from the file and I still get the same error. Here’s the rule as it currently stands.It is my only rule file.

import org.openhab.model.script.actions.Timer
import org.joda.time.*

var Timer duskTimer

rule "FloorLampOff"
when
    Time cron "0 0 20 * * ?"
then
    sendCommand(FloorLamp, OFF)
end

rule "FloorLampByNight"
when
    Item test_event received command ON
then
    duskTimer = createTimer(now.plusSeconds(30) [|
            sendCommand(FloorLamp, ON)
    ]
end

A paren is missing in your createTimer statement:

duskTimer = createTimer(now.plusSeconds(30)) [|
    sendCommand(FloorLamp, ON)
]

Sorry to have wasted all your time. I can’t believe I missed that. I must have been overthinking it!.

That completely explains why I thought I had a simpler version working at some point. While experimenting I must have erased it.

Thanks for your help.

On to the next problem!

Chris

There’s one more thing to note. The final code for the rule was…

rule "FloorLampByNight"
when
    Item Sunset_event received update ON
then
    cs = Clouds.state
    randomDelay = (new java.util.Random).nextInt(15)
    cloudDelay = ((100 - cs) / 4).intValue
    logInfo("FloorLampByNight", "Delaying Floor Lamp " + (randomDelay + cloudDelay).toString)
    duskTimer = createTimer(now.plusMinutes((randomDelay + cloudDelay).intValue)) [|
            sendCommand(FloorLamp, ON)
    ]
end

The .intValue in the argument of plusMinutes was necessary for successful execution.

So just set the Vars as Integer, then it should’nt be necessary (for plusMinutes)

Thanks. I’ll give it a try.

No joy. I get the following error if I omit intValue even if I declare randomDelay and cloudDelay as integers.

2015-12-22 16:41:00.112 [ERROR] [o.o.c.s.ScriptExecutionThread ] - Error during the execution of rule ‘FloorLampByNight’: Could not invoke method: org.joda.time.DateTime.plusMinutes(int) on instance: 2015-12-22T16:41:00.099-05:00

Anyway, the way I have it works fine.

Thanks,
Chris