Trouble with Shutter rules since OH 2.3

Hello Community

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"
	Item VT_VAL_Sun_Elevation received update
	if ((VT_SWI_Sonnenschutz.state == ON)
		&& (VT_VAL_Sun_Elevation.state >= 30)
		&& (VT_SWI_Sonnenschutz_Dach.state != ON)) {
			logInfo("Rollershutter", "Sonnenschutz für die Dachefenster wurde aktiviert " +VT_VAL_Current_Clouds.state +" " +VT_VAL_Sun_Elevation)

rule "Sonnenschutz Osten aktivieren"
	Item VT_VAL_Sun_Azimuth changed
	if ((VT_SWI_NightState.state != ON)
		&& (VT_SWI_Sonnenschutz.state == ON)
		&& (VT_VAL_Sun_Azimuth.state <= 150)
		&& (VT_SWI_Sonnenschutz_Osten.state != ON)) {
			logInfo("Rollershutter", "Sonnenschutz für die Ostseite wurde aktiviert " +VT_VAL_Current_Clouds.state +" " +VT_VAL_Sun_Azimuth)

rule "Sonnenschutz Süden aktivieren"
	Item VT_VAL_Sun_Azimuth changed
	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)) {
			logInfo("Rollershutter", "Sonnenschutz für die Südseite wurde aktiviert " +VT_VAL_Current_Clouds.state +" " +VT_VAL_Sun_Azimuth)

rule "Sonnenschutz Westen aktivieren"
	Item VT_VAL_Sun_Azimuth changed
	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)) {
			logInfo("Rollershutter", "Sonnenschutz für die Westseite wurde aktiviert " +VT_VAL_Current_Clouds.state +" " +VT_VAL_Sun_Azimuth)

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 :slight_smile:

Thank you for pointing me the right direction…


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
  • insert logInfo() at the beginning of each rule

Relax. How about a more complicated one :slight_smile:

Since you ask…

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"
    Item VT_VAL_Sun_Elevation received update or
    Item VT_VAL_Sun_Azimuth changed
    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 |
        logInfo("Rollershutter", "Sonnenschutz für die " +"_").get(3) + " wurde aktiviert " +VT_VAL_Current_Clouds.state +" " +VT_VAL_Sun_Azimuth)

You might want to do something like Design Pattern: Human Readable Names in Messages to convert the Item name to the proper String for your log if that is important.

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.

Hello Markus, Hello Rich

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 :slight_smile:
Nice to know :slight_smile:

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?

Your way of programming is very impressive to me and its a honor to learn from you.

Thank you guys!!!

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. :slight_smile:

Hey Rich

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 :slight_smile:
Once more: Thank you for sharing your experience.

I won¨t bet on it ^^

Thank you!