So I have been trying this for hours and I cant wrap my head around it.
I am setting up an automated irrigation, which is working very well, especially through the help of @rlkoshak’s design patterns. It takes my hours to understand them (no computer savvy background whatsoever) but I got there. A Post in the solutions area will follow, once everything works to my satisfaction.
I have a Number Item (Setpoint in Sitemap) where I can set the IrrigationDuration in Minutes.
When Automated Irrigation is started, I want to show the RemainingMinutes of the Duration.
I found:
rule "Countdown"
when
Time cron "0 0 * * * ?"
then
var Number remain = MinutesRemainingOnTimer.state as DecimalType
if((myTimer == null || myTimer.hasTerminated) && remain != 0) {
MinutesRemainingOnTimer.postUpdate(0)
}
MinutesRemainingOnTimer.postUpdate(remain - 1)
end
*/
But I don’t really like it, because that rule would fire every Minute, no matter if the Irrigation is running or not. So I want something like this in plain text:
rule "Remaining Time"
When
AutoIrrigation changed to ON
Then:
IrrigationDuration=MinutesRemaining
Every Minute:
MinutesRemainin.postUpdate(-1)
How on earth do I implement this?
Another approach I thought of is to calculate the End time and then subtract currentTime from the EndTime
So something like:
rule "Remaining Time"
When AutoIrrigation changed to ON
then
Endtime=TimeNow+IrrigationDuration
For Every minute calculate
RemainingTime=Endtime-TimeNow
Stop When RemainingTime=0
I fixed the formatting.
I implemented as above, but for some reason, it throws an error, when trying the timer expired (so when
remain = remain -1
comes up.
I`ll look into it again tonight and then post the complete look. Also I’ll do some reading into Xtend to better understand the syntax. Is there any good tutorial available?
var Timer irrigationDripTimer = null
var Timer countdownDripTimer
rule "Reset Irrigation"
when
System started
then
createTimer(now.plusSeconds(80)) [|
gDrip.members.forEach[ i | i.sendCommand(OFF)]
Garden_Irrigation_DripSwitch.sendCommand(OFF) ]
end
Above code turns off Irrigation at restart of the system.
rule "Start Automatic Drip Irrigation"
when
Item Garden_Irrigation_DripSwitch received command ON
then
gDrip.members.forEach[ i | i.sendCommand(ON)]
val currValveDripMins = Garden_Irrigation_DripDuration.state as Number
MinutesRemainingOnDripTimer.postUpdate(currValveDripMins)
irrigationDripTimer = createTimer(now.plusMinutes(currValveDripMins.intValue), [|
gDrip.members.forEach[ i | i.sendCommand(OFF)]
Garden_Irrigation_DripSwitch.postUpdate(OFF)])
end
Above code for the actual timer, next is defining a cancel action:
rule "Cancel Drip Irrigation"
when
Item Garden_Irrigation_DripSwitch received command OFF
then
// Cancel the timer if there is one, the ? will cause the line to be skipped if timer is null
irrigationDripTimer?.cancel
irrigationDripTimer = null
countdownDripTimer?.cancel
countdownDripTimer = null
gDrip.members.forEach[ i | i.sendCommand(OFF)]
end
Now comes the rule for the Timer which shows the remaining Timer.
rule "Remaining"
when Item Garden_Irrigation_DripSwitch changed to ON
then
val currValveDripMinutes = Garden_Irrigation_DripDuration.state as Number
var remain = currValveDripMinutes
countdownDripTimer = createTimer(now.plusMinutes(1), [|
remain = remain - 1
if( remain < 0 ) remain = 0
MinutesRemainingOnDripTimer.postUpdate(remain)
if( remain > 0){ countdownDripTimer.reschedule(now.plusMinutes(1))
} ])
end
By trial and error I learned some things about vals and vars and the declaratioion thereof.
When using timers I have to declare
var timer myTimer = null in the beginning?
Doing that for the timer used for the remain messed up the timer (errors came when I used Timer.reschedule(now.PlusMinutes(1)
Also I have some general questions Are var and val defined per Rule or globally? So can I just reuse them in different rules (that would make my rules a littler shorter and easier). Does it matter in which order the rules are in the rules file?
var xx = 1 // a global, can be seen in all rules (in this rules file)
// but not by rules in other files
rule xxx
...
then
var zz = 1 // only accessible in the context of this rule
...
createTimer( ... [ |
// code executed here is in global context
// globals cannot 'see' each other
// code cannot see 'xx'
// nor can code see 'zz' which was in rule context
])
end
I think you are beginning to run into the difficulties described in Rik’s post below, in particular
“lambdas do not have access to the global vals and vars in their context so all of those must be passed as arguments.”