When having difficulty with if statements (or any problem really):
- add lots of logging
- break up long lines that do a whole lot into single lines that do less; you can move them back to one line once you figure out what is wrong.
Another technique I like is to test whether the conditions are right to even run the rule and if not exit. That can greatly simplify the following lines of code.
So the if you only want to run the rule when the lock is OFF, test for that up front.
if(Solar_Lock.state == ON) return;
Now you don’t have to worry about it for the rest of the rule. If the lock is ON, it exits immediately.
Next you only care if it’s between 08:00 and 15:00. If the time falls outside that range you don’t want the rule to run.
if(Solar_Lock.state == ON) return;
if(now.getHourOfDay() < 8 || now.getHourOfDay() > 15) return;
Now you don’t have to mess with the hour either. If you get past those two lines you now know you need to do something. While trying to figure out the problems, add some logging so you know why nothing happens in those cases where nothing happens.
logInfo("solar", "Running solar automation rule")
if(Solar_Lock.state == ON) {
logInfo("solar", "Skipping, lock is ON.")
return;
}
if(now.getHourOfDay() < 8 || now.getHourOfDay() > 15) {
logInfo("solar", "Skipping, it's not between 08:00 and 15:00")
return;
}
logInfo("About to calculate the new Solar_Switch state")
Note that in OH 3 when using UI rules, the above could/should be put into the “But only if…” part of the rule. No actual code would be required actually.
With the logging we now know why the rule just exits and when it doesn’t just exit.
Next you use the same value twice so store it into a variable and log out it’s value.
logInfo("solar", "Running solar automation rule")
if(Solar_Lock.state == ON) {
logInfo("solar", "Skipping, lock is ON.")
return;
}
if(now.getHourOfDay() < 8 || now.getHourOfDay() > 15) {
logInfo("solar", "Skipping, it's not between 08:00 and 15:00")
return;
}
logInfo("solar", "About to calculate the new Solar_Switch state")
val avg = PVng5sum.averageSince(now.minusMinutes(15)
logInfo("solar", "Fifteen minute average is " + avg)
Now you know the raw numbers that you are working with. Let’s further simplify and wait to test the current state of Solar_Switch’s state until later and just save the new state into a variable and log that out.
logInfo("solar", "Running solar automation rule")
if(Solar_Lock.state == ON) {
logInfo("solar", "Skipping, lock is ON.")
return;
}
if(now.getHourOfDay() < 8 || now.getHourOfDay() > 15) {
logInfo("solar", "Skipping, it's not between 08:00 and 15:00")
return;
}
logInfo("solar", "About to calculate the new Solar_Switch state")
val avg = PVng5sum.averageSince(now.minusMinutes(15)
logInfo("solar", "Fifteen minute average is " + avg)
var newState = "STAY"
if(avg > 150) {
newState = "ON"
}
else if(avg < 80) {
newState = "OFF"
}
logInfo("solar", "The calculated new state is " + newState)
Finally, if newState isn’t “STAY” and it’s different from the switch’s current state, send it as a command.
logInfo("solar", "Running solar automation rule")
if(Solar_Lock.state == ON) {
logInfo("solar", "Skipping, lock is ON.")
return;
}
if(now.getHourOfDay() < 8 || now.getHourOfDay() > 15) {
logInfo("solar", "Skipping, it's not between 08:00 and 15:00")
return;
}
logInfo("solar", "About to calculate the new Solar_Switch state")
val avg = PVng5sum.averageSince(now.minusMinutes(15)
logInfo("solar", "Fifteen minute average is " + avg)
var newState = "STAY"
if(avg > 150) {
newState = "ON"
}
else if(avg < 80) {
newState = "OFF"
}
else {
logInfo("solar", "Average is inside the hysteresis range, doing nothing");
}
logInfo("solar", "The calculated new state is " + newState)
if(newState != "STAY" && newState != Solar_Switch.state.toString){
logInfo("solar", "Commanding the Solar_Switch to " + newState)
Solar_Switch.sendCommand(newState)
}
This should give you all the information you need to understand what the rule is doing and why. Once you understand that you should have an idea what the logical error is and what needs to be done to fix it. Once you figure it out you can change the logInfos to logDebug to suppress them, or just remove them. If you remove them the rule will reduce to:
if(Solar_Lock.state == ON) return;
if(now.getHourOfDay() < 8 || now.getHourOfDay() > 15) return;
val avg = PVng5sum.averageSince(now.minusMinutes(15)
var newState = "STAY"
if(avg > 150) newState = "ON"
else if(avg < 80) newState = "OFF"
if(newState != "STAY" && newState != Solar_Switch.state.toString){
Solar_Switch.sendCommand(newState)
}
Pay close attention to how I used the curly brackets above. If you have difficulty switching between the two styles, always use curly brackets.
The reduced rule is longer but it should be much easier to understand because you don’t have to do as much mental gymnastics to understand a single line of code. And it opens a lot more opportunities for adding logging to understand the rule.