(AUTOSOLVED) Keep breaking my head on random times

SOLVED
I am trying to make a rule that simply switches off a light after a given time+ a random value. Tried several, either the rule just didnt delay or didnt work.

I now came up with this (should switch off a light at 2pm +5-30 min (so 14.05-14.30)

rule "General - lightsoff"
when
 
Time cron "0 00 14 1/1 * ? *" // 
then
   var Integer RandomInterval = (Math::floor((Math::random * (30 - 5) + 5).doubleValue).intValue)
   LightsOffTimer = createTimer(now.plusMinutes(RandomInterval)) [|sendCommand(b2, OFF)]
  
end

but I get an error thrown: Couldnā€™t invoke ā€˜assignValueToā€™ for feature JvmVoid: (eProxyURI: burglar.rules#|::0.2.0.2.0.1::0::/1
What am i doing wrong?

Update.. wait a minute. I put the global variable at the topā€¦ fault disappeared, lets see if it works now
More Update
OK that seem sto work, but I have a question left. If I want to add more commands between the bracketsā€¦ do I seperate them with a "| " or just with a space.
So like [|command1 |command2 |command3]
or is it
[|command1 command2 command3]
or maybe seperate them with a comma?

ofcourse I am going to try all 3, but if someone knows the answer right away that would help

Even More update
apparently it is [ | command1 command2]

OK, Final Update
Though the Above rule didnt generate any Errorsā€¦ it just didnt do what it was supposed to do, it always fired at the same time. I only had the impression it worked as after every ā€˜saveā€™ the rule was reloaded and a new random variable was generated
I am not really familiar with Xtend, but I presume putting the Global variable on top was necessary for the declaration, but that that would just read the random value once and re-yse that till a restart or a resave of the rule.

So, I presumed I needed to call the variable at its original position but declare it on top.

hence it became:

var Integer RandomInterval = (Math::floor((Math::random * (30 - 5) + 5).doubleValue).intValue)
rule "General - lightsoff"
when
 
Time cron "0 00 14 1/1 * ? *" // 
then
   Integer RandomInterval = (Math::floor((Math::random * (30 - 5) + 5).doubleValue).intValue)
   LightsOffTimer = createTimer(now.plusMinutes(RandomInterval)) [|sendCommand(b2, OFF)]
  
end

In the declaration I could probably just use ā€œvar Integer RandomInterval = 0ā€ but I just left it as it is.

1 Like

Just to add a little detail to explain why you are seeing what you are seeing.

Anytime you see [ <nothing or some stuff> | <some code>] what you are seeing is a lambda. This is basically like a function that you can pass around and treat like it is an object. This is called a lambda.

The <nothing or some stuff> are the arguments passed to the lambda and <some code> is the code to execute when the lambda is executed.

Typically when there is more than one statement in <some code>, one writes it like any other code.

One thing that causes a little confusion is that the Rules language allows one to tack a lambda on to the end of a statement rather than making it part of the arguments. I prefer to show the lambda as an argument to the method as you will see below.

The lambdas that get passed to createTimer do not accept arguments so you will see nothing between the opening ā€œ[ā€ and the symbol that separates the arguments from the code: ā€˜|ā€™.

So a more typical way to write a lambda with multiple commands would be:

LightsOffTimer = createTimer(now.plusMinutes(RandomInterfval), [|
    command1
    command2
    command3
    // some comments
])
1 Like

Thanks Rich, that clarifies a lot.
I tried to find some ourse material on Xtend/RulesLanguage but it is scarce, Iā€™ll get there though.

With regard to my initial ā€œCouldnā€™t invoke ā€˜assignValueToā€ error, in fact you helped me too. From C++ I am used to put my global variables on top, but in rules have seen many put them as in my initial code, so i followed that. Nevertheless, I saw you make many remarks here and there ssaying to put the global variable on top, which makes perfect sense to me.