HI,
I would like the last 3 lines of the rule to be executed only after he went through 4 x if conditions. I guess Thread::sleep or Timer will work, but is there a smarter way?
rule "Set AC Limit"
when
Item TimeOfDay changed to 1 or
System started
then
val currMonth = now.getMonthValue
if(currMonth == 4 || currMonth == 11)
{ACLimit.sendCommand(24.9)}
if(currMonth == 5 || currMonth == 10)
{ACLimit.sendCommand(25.4)}
if(currMonth == 6 || currMonth == 9)
{ACLimit.sendCommand(25.7)}
if(currMonth == 7 || currMonth == 8)
{ACLimit.sendCommand(25.9)}
Thread::sleep(500)
var Number aclimit = ACLimit.state as DecimalType
var Number aclimitrooms = aclimit + 0.3
postUpdate(ACLimitRooms, aclimitrooms)
end
You will have to emaplin your use case a with a whole lot more detail. What are you trying to accomplish?
Note, you already know what ACLimit’s state is supposed to be, so just use that and then you don’t need to sleep or use a timer at all.
rule "Set AC Limit"
when
Item TimeOfDay changed to 1 or
System started
then
val currMonth = now.getMonthValue
var currACLimit = ACLimit.state as Number
if(currMonth == 4 || currMonth == 11)
{currACLimit = 24.9}
else if(currMonth == 5 || currMonth == 10)
{currACLimit = 25.4}
else if(currMonth == 6 || currMonth == 9)
{currACLimit = 25.7}
if(currMonth == 7 || currMonth == 8)
{currACLimit = 25.9}
ACLimit.sendCommand(currACLimit)
val aclimitrooms = currACLimit + 0.3
ACLimitRooms.postUpdate(aclimitrooms)
end
If you use a switch statement this becomes much cleaner
rule "Set AC Limit"
when
Item TimeOfDay changed to 1 or
System started
then
val currMonth = now.getMonthValue
var currACLimit = ACLimit.state as Number
switch(currMonth) {
case currMonth == 4 || currMonth == 11: currACLimit = 24.9
case currMonth == 5 || currMonth == 10: currACLimit = 25.4
case currMonth == 6 || currMonth == 9: currACLimit = 25.7
case currMonth == 7 || currMonth == 8: currACLimit = 25.9
}
ACLimit.sendCommand(currACLimit)
val aclimitrooms = currACLimit + 0.3
ACLimitRooms.postUpdate(aclimitrooms)
end
Some other differences demonstrating Rules DSL best practices:
cast the state of Number Items to Number instead of DecimalType
do not force the type of a variable except where absolutely necessary
use the postUpdate method on the Item, not the postUpdate action
I dont know what is the AC limit until all 4 IF statements are complete, this is what I was trying to accomplish. Wait until ACLimit is defined and only THEN calculate ACLimitRooms.
As I understand the part of the rule that is outside of IF loops executes simultaneously to IF, it doesnt wait for IF to complete as he doesnt care about the results? It knows it has to be executed in either case when the rule was fired.
But your example with cases is perfect and it will work exactly as I intended, thanks!
That is not correct and not how it works. Each line of code executes in sequence from top to bottom. So the line var Number aclimit = ACLimit.state as DecimalTypedoes wait until the four if statements complete before running.
The problem is that sending a command to an Item gets processed in the background. It takes some time for the Item to change after sending a command to it and the rule doesn’t wait around until the Item changes before running the next line of code. All of that happens in the background so if you try to check the state of an Item immediately after sending a command to it, the Item is unlikely to have finished processing that command and won’t be in it’s new state.
To complicate things further, there is no guarantee that an Item will change in response to a command at all. But that’s not something to worry about here, but soemthing to keep in mind.
The Thread::sleep(500) was basically giving enough time for the command to be processed in the background and for the Item to be updated in response to the command.
In my version of the rule, we don’t need to wait because we already know what state the Item will be in eventually. So we just use that.
switch(currMonth) {
case 4, case 11: currACLimit = 24.9
case 5, case 10: currACLimit = 25.4
// or split into separate lines
case 6,
case 9: currACLimit = 25.7
case 7, case 8: currACLimit = 25.9
}
Or even better:
val currACLimit = switch(currMonth) {
case 4, case 11: 24.9
case 5, case 10: 25.4
case 6, case 9: 25.7
case 7, case 8: 25.9
}
There’s probably other ways of doing it, e.g. using a Hashmap
rule "Set AC Limit"
when
Item TimeOfDay changed to 1 or
System started
then
val currACLimit = switch(now.getMonthValue) {
case 4, case 11: 24.9
case 5, case 10: 25.4
case 6, case 9: 25.7
case 7, case 8: 25.9
}
ACLimit.sendCommand(currACLimit)
ACLimitRooms.postUpdate(currACLimit + 0.3)
end
That must be relatively new (meaning within the last five years or so). One of the annoying things with Rules DSL/Xtend switch statements was there didn’t used to be a fall through. I’m glad to see they eventually added it.