Last week I’ve updated my enviornment from OH 2.1 to OH 2.3 stable.
Since that, my rules for sunprotection with shutters don’t work, and I dont find the error.
I use a set of astro and weather items to determine, if sunprotection is needed and on which direction.
My items:
Number VT_VAL_Sonnenschutz "Betriebsmodus Sonnenschutz" <sun> (gInfluxDB) //generell Mode for Sunprotection: 0 = deactivated 1 = automatic
Switch VT_SWI_Sonnenschutz "Sonnenschutz" <sun> (gSwitches) // Overall Mode
Switch VT_SWI_Sonnenschutz_Dach "Sonnenschutz Dach" <sun> (gSwitches) // Sunprotection for Roof-Windows
Switch VT_SWI_Sonnenschutz_Osten "Sonnenschutz Osten" <sun> (gSwitches) // sunprotection east
Switch VT_SWI_Sonnenschutz_Sueden "Sonnenschutz Süden" <sun> (gSwitches)// sunprotection south
Switch VT_SWI_Sonnenschutz_Westen "Sonnenschutz Westen" <sun> (gSwitches) // sunprotection west
Number VT_VAL_Current_Clouds "Bewölkung [%.0f %%]" <sun_clouds> (gInfluxDB) {weather="locationId=home, type=clouds, property=percent"}
Number VT_VAL_Sun_Azimuth "Azimuth [%.2f]" (gAstro, gInfluxDB) {channel="astro:sun:2cae180a:position#azimuth"}
Number VT_VAL_Sun_Elevation "Elevation [%.2f]" (gAstro, gInfluxDB) {channel="astro:sun:2cae180a:position#elevation"}
rule "Sonnenschutz Dach aktivieren"
when
Item VT_VAL_Sun_Elevation received update
then
if ((VT_SWI_Sonnenschutz.state == ON)
&& (VT_VAL_Sun_Elevation.state >= 30)
&& (VT_SWI_Sonnenschutz_Dach.state != ON)) {
VT_SWI_Sonnenschutz_Dach.sendCommand(ON)
logInfo("Rollershutter", "Sonnenschutz für die Dachefenster wurde aktiviert " +VT_VAL_Current_Clouds.state +" " +VT_VAL_Sun_Elevation)
}
end
rule "Sonnenschutz Osten aktivieren"
when
Item VT_VAL_Sun_Azimuth changed
then
if ((VT_SWI_NightState.state != ON)
&& (VT_SWI_Sonnenschutz.state == ON)
&& (VT_VAL_Sun_Azimuth.state <= 150)
&& (VT_SWI_Sonnenschutz_Osten.state != ON)) {
VT_SWI_Sonnenschutz_Osten.sendCommand(ON)
logInfo("Rollershutter", "Sonnenschutz für die Ostseite wurde aktiviert " +VT_VAL_Current_Clouds.state +" " +VT_VAL_Sun_Azimuth)
}
end
rule "Sonnenschutz Süden aktivieren"
when
Item VT_VAL_Sun_Azimuth changed
then
Thread::sleep(200) //give System time, because more rules are calculated at the same
if ((VT_SWI_Sonnenschutz.state == ON)
&& (VT_VAL_Sun_Azimuth.state > 150)
&& (VT_VAL_Sun_Azimuth.state < 280)
&& (VT_SWI_Sonnenschutz_Sueden.state != ON)) {
VT_SWI_Sonnenschutz_Sueden.sendCommand(ON)
logInfo("Rollershutter", "Sonnenschutz für die Südseite wurde aktiviert " +VT_VAL_Current_Clouds.state +" " +VT_VAL_Sun_Azimuth)
}
end
rule "Sonnenschutz Westen aktivieren"
when
Item VT_VAL_Sun_Azimuth changed
then
Thread::sleep(300) //give System time, because more rules are calculated at the same
if ((VT_SWI_Sonnenschutz.state == ON)
&& ((VT_VAL_Sun_Azimuth.state) > 225)
&& (VT_SWI_Sonnenschutz_Westen.state != ON)) {
VT_SWI_Sonnenschutz_Westen.sendCommand(ON)
logInfo("Rollershutter", "Sonnenschutz für die Westseite wurde aktiviert " +VT_VAL_Current_Clouds.state +" " +VT_VAL_Sun_Azimuth)
}
end
Sidemarks:
With OH 2.1 I have every trigger on “received update” for testing purposes I changed it to “changed”
Roofprotection (Sonnenschutz Dach) and West-protection (Sonnenschutz Westen) works well, while East and south dont get triggered.
The trigger for the overall protection works (get set on “ON”)
I know the rules are complicated, if you have a more smart solution, Im openminded
Well, there’s no obvious change in OH2.3 to cause this, so please resort to “classic” debugging:
check events.log if and when the triggering event takes place
If I was to guess, it’s that your astro binding might not be working properly thus failing to create the event your rules trigger upon
First, let’s combine into one Rule so we can get rid of those Thread::sleeps. They aren’t needed (unless there is something I don’t know) and only tie up the run time threads.
Then it can be a little easier to split up the if statements a bit. It can be hard to keep and reason long complicated if statements in your head at the same time. The complicated part here is that there is overlap when the various shutters should be activated so I’m going to use a List to keep all the shutters that should be activated.
import java.util.List
rule "Sonnenschutz aktivieren"
when
Item VT_VAL_Sun_Elevation received update or
Item VT_VAL_Sun_Azimuth changed
then
if(VT_SWI_Sonnenschutz.state != ON) return; // exit if this isn't ON
// get the list of shutters that need to be activated based on the sun position
val List<SwitchItem> activate = newArrayList
if(VT_VAL_Sun_Elevation.state >= 30) activate.add(VT_SWI_Sonnenschutz_Dach)
if(VT_VAL_Sun_Azimuth.state <= 150) activate.add(VT_SWI_Sonnenschutz_Osten)
if(VT_VAL_Sun_Azimuth.state > 150 && VT_VAL_Sun_Azimuth.state < 280) activate.add(VT_SWI_Sonnenschutz_Sueden)
if(VT_VAL_Sun_Azimuth.state > 225) activate.add(VT_SWI_Sonnenschutz_Westen)
// send the command if necessary
activate.filter[ s | s.state != ON].forEach[ s |
s.sendCommand(ON)
logInfo("Rollershutter", "Sonnenschutz für die " + s.name.split("_").get(3) + " wurde aktiviert " +VT_VAL_Current_Clouds.state +" " +VT_VAL_Sun_Azimuth)
]
end
If the sleeps were there to keep from overloading your devices with too many commands at once, add a Thread::sleep(100) to the for loop.
It’s fewer lines of code, and perhaps a little easier to work through the cases to figure out what rollershutters are to be activated under what circumstances. And there is no duplicated code. But it requires a List and loop so I don’t know if it is a fare trade.
Thank you for your quick responses…
Its fantastic to get your inputs and learn from your deep knowledge.
As I see in the log, that both involved astro items (azimuth and elevation) get updates and other astro based rules (like closing the blinds at sunset and open them at sunrise), I dont belive, that the astro item has problems.
I focussed by debugging on comparing the Azimuth States with the thresholds.
Today I didn’t do any manual overrides and will check all the logs today in the evening and redesign my rule(s) to Rich’s suggested template.
Im glad to see, that there is always a smarter guy with more fency solution
Nice to know
I thought, it would be helpfull, if so many rules get triggered on the same event, I spread them a little over time, so OH can handle all this rule-triggerings.
But with your consolidated rule, they sleeps get redundant.
I guess, I can extend your example-rule with a second array for deactivating Sunprotection and complete the if-clauses with the deactivations?
@rlkoshak
Your way of programming is very impressive to me and its a honor to learn from you.
OK, if that is the case then spreading them out actually causes more problems, not fewer. You can see (OH 1.x and OH 2.x Rules DSL only] Why have my Rules stopped running? Why Thread::sleep is a bad idea for the full explanations.The tl;dr is you only get five Rules that can run at the same time. The longer your Rules run, the more likely you will encounter a situation where all five threads are in use meaning no new Rules can run.
I was wondering about how you close them. Yes indeed you can add to the Rule for closing. Duplicate the middle section by creating another List and adding those Items that need to be closed under whatever your conditions are. Then duplicate the filter and forEach on this new list, sending OFF instead of ON and with the appropriate log statement.
It is a style of programming Rules that has developed over time. I’ve picked up a lot of tips and tricks along the way from many other users on this forum. Keep at it and I bet you’ll discover some new trick I’ve never thought of and I’ll learn from you.
Thanks for this input. I’ve changed my complete rules to eleminate the Thread::sleep (where possible and useful).
I set a virtual switch, which triggeres the “real” action. I use a 3-State-Item to choose if the sunprotection is in manual mode, automatic mode or disabled.
Also here I have redesigned my rule and it works great
Once more: Thank you for sharing your experience.