It will work the same in OH 3 with one difference. The System started
trigger now does exactly what it says, it triggers when openHAB has started. If after OH has started the .rules file is reloaded, that rule will not trigger again because OH hasn’t restarted.
However, reloading a .rules file means everything in that file is unloaded/destroyed, including the “global” variables (they are not truly global, just global to this one file).
There is an issue open to add a “file loaded” trigger or somesuch but I don’t think it’s been implemented and merged. So in the mean time you can run the System started rule manually from MainUI or the Karaf Console. Or you can restart OH itself when you change this one file.
Yes if and only if they are in the same .rules file. The same general answer goes for the other languages too.
There is also a registry that has been implemented but not yet merged that can be used as a way to share data between rules not defined in the same file (UI rules don’t even have a file so without this there is no sharing at all). JS Scripting, in the mean time, has a cache
which is simpler but serves the same purpose as the registry.
There used to a subtle issue in Rules DSL which required you to use unique names for all your “global” variables, even if they are defined in separate files. But I think that was fixed but maybe not.
See above.
If you really care about scalability, Rules DSL is a poor choice for language. Almost every language feature that addresses that sort of thing simply does not exist in Rules DSL or, when it exists, is significantly limited.
Another alternative would be to put your System started method into a lambda (see Reusable Functions: A simple lambda example with copious notes) and put the test for null in the rules that depend on these variables being initialized and call that lambda from the rule.
However, looking at what these variables do and what you use them for, I’m going to guess you don’t know about Groups and their various uses.
For example, you could replace the global variable hueLampsMWColor
with a Group
Item that has all those Items as its members. Then you can replace
for(var int i = 0; i < hueLampsMWColor.size(); i++){
hueLampsMWColor.get(i).sendCommand(HSBType.RED)
}
with
hueLampsMWColor.sendCommand(HSBType.RED)
So not only do your rules become simpler, you don’t even need the System started rule nor the global variables in the first place.
Using Groups the code above could be reduced to:
rule "WindowsOpen"
when
Member of Windows changed to OPEN
then
Windows.members.forEach[ i, window | logInfo("rules", "{} state {}", window.label, window.state)]
logInfo("rules", "Windows open")
// Let's just count the number of open windows
if(Windows.members.filter[ window | window.state == "TILTED"].size > 0) {
// You can turn on, turn up the brightness and set the color to RED in one command
// A command to the Group goes to all its members
hueLampsMWColor.sendCommand("0,100,100")
}
else {
logInfo("rules", "One or more windows are opened")
hueLampsMWColor.sendCommand("0,100,100") // Why does it do the same thing?
}
logInfo("rules", "Windows open")
end
OK, now that I’ve done that I notice something, this rule will command the lights to RED no matter what. So why have the if statement in the first place. You want the light to be on and red if and window is open or tilted. So let’s just do that.
The same for closed but this actually doesn’t make sense. If any one window is OPEN or TILTED you set the light to red. But if, for example, you have 3 windows open and close one of them, all the light will turn off even though two windows are still open. Wouldn’t you want to wait for all the windows to be CLOSED?
To do that, set the aggregation function on Windows to AND(CLOSED,OPEN). That will set the state of Windows
to CLOSED only when all its members are CLOSED.
rule "Windows Open or Tilted"
when
Member of Windows changed to TILTED or
Member of Windows changed to OPEN
then
Windows.members.forEach[ i, window | logInfo("rules", "{} state {}", window.label, window.state)]
logInfo("rules", "Windows OPEN or TILTED")
// the fact that this rule triggered we know at least one window is now open or tilted
hueLampsMWColor.sendCommand("0,100,100")
logInfo("rules", "Windows open or tilted")
end
rule "Windows Closed"
when
Item Windows changed to CLOSED
then
Windows.members.forEach[ i, window | logInfo("rules", "{} state {}", window.label, window.state)]
logInfo("rules", "All windows are closed")
hueLampsMWColor.sendCommand("0,0,0")
logInfo("rules", "Windows Closed")
end
I looked up the colors online to get the HSB values. But hopefully you can see by using Groups we can do the same thing without globals, a System started rule, and in fewer lines of code as just one of the three rules.
We could go even further.
rule "Windows Lights"
when
Member of Windows changed
then
Windows.members.forEach[ i, window | logInfo("rules", "{} state {}", window.label, window.state)]
var newState = "0,0,0"
if(Windows.members.filter[ window | window.state == "OPEN" || window.state == "TILTED" ].size > 0) {
logInfo("rules", "At least one window is OPEN or TILTED")
newState = "0,100,100"
}
else {
logInfo("rules", "All windows are CLOSED")
}
// Adjust the lights
hueLampsMWToggle.sendCommand(newState)
end