Hi all.
Me and my wife has come to the agreement that what our home automation needs a master switch that puts it into “manual mode”, ie when this switch is on most of my rules shouldn’t be run. So that when we have people over for dinner the house don’t suddenly get all dark at eleven just because that’s what we normally want. I’m looking for some input on what would be the easiest way to implement this.
The obvious way would be to put extra if clauses all over my rules, checking this master switch before anything is done. Problem is that this would clutter up all rules with this extra logic. So I’m wondering if there is some more elegant solution I’m not seeing. Like some way of simply saying that rule this and that should simply be temporarily inactivated. Ideas?
This would be sooo easy with the Experimental Rules Engine and I think you will want to consider moving over to it in the near future as it matures. Unlike with the old rules which only have a “when” clause full of triggers, it also has a section that checks the state of Items before the rule triggers.
But in the old rules engine, this is a lot tougher. I’ve come up with a couple of alternative approaches but they all fail on some level or other to make this more elegant or you lose some capability in your rules.
For example, you could centralize your if statement into a lambda and pass the body of your rule to this as a lambda. It would look something like this:
import org.eclipse.xtext.xbase.lib.Functions
val Functions$Function1<Functions$Function0,Boolean> masterSwitchTest = [ Functions$Function0 lambda |
if(MasterSwitch.state == ON) {
lambda.apply()
}
true
]
rule "Some rule"
when
// some trigger
then
masterSwitchTest.apply([|
// body of your rule
])
end
But is that really any better than just using an If statement there in the first place? It could be useful if you had more interesting things you want to do to decide to run a rule, but for just testing one Switch I’d say it is not worth the effort.
There was another thread saying that the return statement does not behave as expected (i.e. doesn’t always exit the rule) so I don’t think you can get away with a simple:
if(MasterSwitch.state == OFF) return
or
if(MasterSwitch.state == OFF) return false
This second one will give you errors in the logs but it should work functionally.
You could try
if(MasterSwitch.state == OFF) break
though I’ve not tried break myself in a long time and I don’t remember how well it works.
One idea could be to use executeCommandLine to move the .rules file somewhere else when MasterSwitch turns ON and move them back when MasterSwitch turns OFF. You will have to be sure to preserve the one file where these moves take place though. This might be the more elegant of the ideas I’ve thought up so far.
Thanks a lot for all the suggestions! Seems at least there are a few decent ways to do this even though none of them are really perfect.
About the new rules engine, I last tried it out somewhere around the release of 2.0 and I gave it up pretty soon, it couldn’t do half of the things I wanted. Guess it may be time taking a look at it again…
I have to slightly disagree. Rules are there to define how your system is supposed to react in the case of an event. NOT to do something depending on certain conditions is just as much an important part of the rule as any other. I also found, that only a few rules need to be disabled for the manual switch (I also have one).
@rlkoshak your lambda solution is odly complicated. Why not a simple if?
Here’s how I’m going at it:
rule "Some rule"
when
// some trigger
then
if (masterSwitch.state == ON) return false
// body of your rule
end
Because op was specifically looking for a way to do it without having to put an if statement in every rule. I mainly listed it to illustrate that there really isn’t a simpler way than using the if statements, though the idea of moving or renaming the rules files doesn’t feel too bad to me.
I think the hesitation about using the if statements is because it really feels like a violation of Don’t Repeat Yourself.
And you will see I suggested the same return false approach in my reply after providing examples to prove there really isn’t a simpler way.
I didn’t want to provoke you. I also saw your alternatives. Just wanted to post my working and tested solution (btw. break is not supported, at least not in 2.1 stable).
Not provoked, just a bit grumpy these days. I don’t want to come off as such but sometimes it is hard to avoid.
I need to run some experiments about break sometime. Most of the time I’ve tried to use break and return has been from inside a lambda and I found that if I use either inside a lambda it would exit the whole rule, not just the lambda. But that was many versions ago.
Ok, I get the “Void functions cannot return a value.” Am I understanding the linked thread correctly that this error is safe to ignore and everything will work? I’m running 2.1.
I had another look and it turns out, that the issue was tackled and will be solved in newest snapshot and later stable release versions. If I understand the change correctly this is the solution you should go with:
if (masterSwitch.state == ON) return
This one will still yield the “Void functions cannot return a value” with 2.1 stable but will already do what it is supposed to.