var rulePoweroff = false
if (WindowcontactState.state == OPEN && Heating_MAINS_POWER_OUTLET_Switch.state == ON) {
Heating_MAINS_POWER_OUTLET_Switch.sendCommand(OFF)
rulePoweroff = true
}
if (WindowcontactState.state == CLOSED && rulePoweroff) {
Heating_MAINS_POWER_OUTLET_Switch.sendCommand(ON)
rulePoweroff = false
}
The idea is that the heating is turned off once the window is opened. And later, once the window is closed, it is turned back on again if it was previously turned off due the window being opened.
Now, it appears that powerOff is always set to false once the script action runs. Which is not really surpisingly.
Looking at
there seems to be a syntax for rules like
var Number counter = 0
rule "Increase counter"
when
Time cron "0 0 0 * * ?"
then
counter = counter + 1
end
which would do what I want: the state of counter is persisted across invocations.
However, if I click at the Code tab in OpenHAB 4.1.1’s WebUI, I get
Now I am really confused, as this syntax uses YAML to separate the condition from the action. And there appears to be no way to declare persistent variables.
In this example the variable counter is defined outside the rule. If you had more than one rule in that same .rules file, they can all see and modify counter.
In a managed rule (e.g. one defined through the UI), there is no outside the rule. However, among the implicit variables you’ll find privateCache and sharedCache. The privateCache is what you would use for variables only used by one Script Action or Script Condition that you want to preserve from one run to the next. The sharedCache is what you would use if you want to share variables across more than one Script Action or Script Condition.
In Rules DSL it’s usually best to avoid forcing the type of variables unless and until avbsolutely necessary. The following should be sufficient:
var rulePoweroff = privateCache.get(“rulePoweroff”, [false])
Rules DSL is happiest when it can determine the type of variables at runtime.
Since changes in the WindowcontactState are what triggers the rule, it can be shorter to use newState instead of WindowcontactState.state. If the rule were triggered by a command the Item may not have changed to the new state yet when the rule runs so in those cases you definitely want to use receivedCommand instead of the Item’s state. For update and changed triggers it’s not so bad as the rule doesn’t trigger until after the Item changes. However, the Item may have changed stated between the rule triggering and the call to get it’s state so using the implicit variables is better as it guarantees you are processing the actual state that triggered the rule.
When you use a return statement in Rules DSL, always follow it with a ;. Otherwise it will treat the next line of code as the return value which can lead to unexpected results.
The return statements here are not necessary. It would be far better to use an else if or even else if.
Why not put ON/OFF into the privateCache? Then you can use the same thing to command the Item and keep track of the state. I’ve applied the 1-2-3 rules design pattern below but that’s not necessary. I prefer to structure rules like this so the code that does the work is all in one place which makes it easier to maintain in the long run.
var lastState = privateCache.get("rulePoweroff", [ | Heating_MAINS_POWER_OUTLET_SWITCH,state.toString ]) // initialize the cache with the switch's current state
var desiredState = "STAY" // default to do nothing
// If the window opened and the heating is on, we want the heating to be turned off
if(newState == OPEN && Heating_MAINS_POWER_OUTLET_SWITCH,state == ON) {
desiredState = "OFF"
}
// If the window is closed and this rule previously turned off the heating, turn it back on
else if(newState == CLOSED && lastState == "ON") {
desiredState = "ON"
}
// If the current state of the heater needs to change
if(desiredState != "STAY") {
Heating_MAINS_POWER_OUTLET_Switch.sendCommand(desiredState) // you can send a string as a command
privateCache.put('rulePowerOff', desiredState)
}
If you find this rule is running a lot unnecessarily, you can change the rule trigger to a changed trigger. Then it will only trigger when the Window actually changes state, not when it gets updated to the same state.