Problems with Rollershutter Shading

As an Openhab Beginner I would like to aks your for some help with my aim to install a automatic rollershutter shading.
I am using openhab 2.5.6 with Shelly Binding (no mqtt) on a Raspberry PI. The setup is based on the solution of rubenfuser and Peter_Aschinger.
Visual Studio doesn’t show any errors, I can navigate in the sitemap, the sitemap gets update with temperatures, azimuth etc. However, the rollershutter is notmoving at all.
Looks like I have a very basic error in this setup.
Any help / suggestion is highly appreciated.

My shading.item looks like this:

Group gRolloautomatik
/* Shelly 2.5 Roller */
Rollershutter RollerControl “Steuerung (0=offen, 100=geschlossen)” {channel=“shelly:shelly25-roller:c82b96109f49:roller#control”}

Switch Rolloautomatik “Steuerung (0=offen, 100=geschlossen)” //“Automatic blinds closing”

Switch Rolloautomatik_Open “Steuerung (0=offen, 100=geschlossen)” //“Inverts blinds Closing with opening”

Number Rolloautomatik_Closure //“Blinds closed at”

Number Rolloautomatik_Temperature //“Temperature higher than: [%1$.0f]”

Number Rolloautomatik_Cloudiness //“Cloudiness higher than: [%d]”

Number Rolloautomatik_Azimuth //“Sun Azimuth higher or equal to: [%d]”

Number Rolloautomatik_Elevation //“Sun Elevation higher or equal to: [%d]”

DateTime Rolloautomatik_Last_Start //“Last run (Close) [%1$tH:%1$tM %1$td/%1$tm/%1$tY]”

DateTime Rolloautomatik_Last_End //“Last run (Open) [%1$tH:%1$tM %1$td/%1$tm/%1$tY]”

Number External_Temperature { channel=“openweathermap:weather-and-forecast:api:local:current#temperature” } //“Temperature [%.0f]”

Number Local_Cloudiness { channel=“openweathermap:weather-and-forecast:api:local:current#cloudiness” } //“Clouds [%.0f]”

Number Azimuth {channel=“astro:sun:local:position#azimuth”} //“Azimuth [%.0f]”

Number Elevation {channel=“astro:sun:local:position#elevation”}

My shading.sitemap looks like this:

sitemap shading label=“Blinds Auto close”
{
Frame label=“Enable automation”

    {

        Switch item=Rolloautomatik label="Blinds Auto closure"

        Setpoint item=Rolloautomatik_Closure minValue=0 maxValue=100 step=1 label="Blinds closed at: [%s %%]"

    }

Frame label="Close if..." 

    {

        Setpoint item=Rolloautomatik_Temperature minValue=0 maxValue=35 step=1 icon="temperature" label="Temperature higher than: [%s °C]"

        Text item=External_Temperature icon="temperature" valuecolor=[>27="red",>20="orange",>10="purple",>5="green",<=5="blue"] label="External temperature: [%.0f °C]"

        Setpoint item=Rolloautomatik_Cloudiness minValue=0 maxValue=100 step=20 icon="sun_clouds" label="Cloudiness higher or equal than to: [%.0f %%]"

        Text item=Local_Cloudiness icon="sun_clouds" label="Cloudiness: [%.0f %%]"

        Setpoint item=Rolloautomatik_Azimuth minValue=0 maxValue=360 step=10 icon="niveau" label="Azimuth higher than: [%d °]"

        Text item=Azimuth icon="niveau" label="Azimuth: [%d °]"

    }

Frame label="Open if..." 

    {

        Switch item=Rolloautomatik_Open label="Enable auto opening"

        Setpoint item=Rolloautomatik_Elevation minValue=-20 maxValue=60 step=1 icon="sun" label="Elevation less than: [%d °]"

        Text item=Elevation icon="sun" label="Elevation: [%d °]"

    }

Frame label="Info"

    {

        Text item=Rolloautomatik_Last_Start label="Last run (Close) [%1$tH:%1$tM - %1$td/%1$tm/%1$tY]"

        Text item=Rolloautomatik_Last_End label="Last run (Open) [%1$tH:%1$tM - %1$td/%1$tm/%1$tY]"

    }

Frame label="Reset"

    {

    Switch item=resetautomatik mappings=[ON="Reset"] 

    Text item=Rolloautomatik_Last_Start label="Letzter Start [%1$tH:%1$tM - %1$td/%1$tm/%1$tY]"

    }

}

And the shading.rules looks like this

var boolean log = true
rule “Blinds closure”
when Item Azimuth changed
then
val String logPrefix = 'Autoblinds (Blinds closure) - ’

if (log) logInfo('rules', logPrefix + 'Rule loaded!')



var String timeLast = 'xxxx-xx-xx'

if (Rolloautomatik_Last_Start.state == NULL) 

    {

        if (log) logInfo('rules', logPrefix + 'First execution on this system.')

    } 

else 

    {

        timeLast = Rolloautomatik_Last_Start.state.toString().substring(0,10)

    }

var String timeNow = now.toString().substring(0,10)

if (Rolloautomatik.state == ON) 

    {

        if (timeNow != timeLast) 

            {

                if (Azimuth.state > Integer::parseInt(Rolloautomatik_Azimuth.state.toString())) 

                    {

                        if (External_Temperature.state > Integer::parseInt(Rolloautomatik_Temperature.state.toString())) 

                            {

                                if (Local_Cloudiness.state  >= Integer::parseInt(Rolloautomatik_Cloudiness.state.toString())) 

                                    {

                                        if (Elevation.state > Integer::parseInt(Rolloautomatik_Elevation.state.toString())) 

                                            {

                                                if (log) logInfo('rules', logPrefix + 'Blinds have been closed.') gRolloautomatik.members.forEach

                                                [i| if (i.state <= Integer::parseInt(Rolloautomatik_Closure.state.toString())) {if (log) logInfo('rules', logPrefix + 'Blind set to ' + Rolloautomatik_Closure.state.toString() + '%: ' + i.name) i.sendCommand(Integer::parseInt(Rolloautomatik_Closure.state.toString()))} else {if (log) logInfo('rules', logPrefix + 'Blind already closed (' + i.state.toString() + '%) so rule will be skipped')}]

                                                //sendBroadcastNotification("Auto closure enabled!")

                                                Rolloautomatik_Last_Start.postUpdate(now.toString())

                                            }

                                        else 

                                            {

                                                if (log) logInfo('rules', logPrefix + 'Sun elevation (' + Elevation.state.toString() + ') has not reached the value set (' + Rolloautomatik_Elevation.state.toString() + ')')

                                            }

                                    }

                                else

                                    {

                                        if (log) logInfo('rules', logPrefix + 'Cloudiness (' + Local_Cloudiness.state.toString() + ') has not reached the value set (' + Rolloautomatik_Cloudiness.state.toString() + ')')

                                    }

                            }

                        else

                            {

                                if (log) logInfo('rules', logPrefix + 'Temperature (' + External_Temperature.state.toString() + ') has not reached the value set (' + Rolloautomatik_Temperature.state.toString() + ')')

                            }

                    }

                else

                    {

                        if (log) logInfo('rules', logPrefix + 'Azimuth (' + Azimuth.state.toString() + ') has not reached the value set (' + Rolloautomatik_Azimuth.state.toString() + ')')

                    }

            }

        else

            {

                if (log) logInfo('rules', logPrefix + 'Task finished. The rule will not be executes again today.')

            }

    }

else 

    {

        if (log) logInfo('rules', logPrefix + 'Finished, automation disabled.')

    }

end

//-----------------------------------------------//

rule “Blinds opening”

when Item Elevation changed

then

val String logPrefix = 'Autoblinds (Blinds opening) - '

if (log) logInfo('rules', logPrefix + 'Rule loaded!')

var String timeLastEnde = 'xxxx-xx-xx'

if (Rolloautomatik_Last_End.state == NULL) 

    {

        if (log) logInfo('rules', logPrefix + 'First execution on this system.')

    } 

else 

    {

        timeLastEnde = Rolloautomatik_Last_End.state.toString().substring(0,10)

    }

var String timeLastStart = 'yyyy-yy-yy'

if (Rolloautomatik_Last_Start.state == NULL) 

    {

        if (log) logInfo('rules', logPrefix + 'First execution on this system.')

    } 

else 

    {

        timeLastStart = Rolloautomatik_Last_Start.state.toString().substring(0,10)

    }

var String timeNow = now.toString().substring(0,10)

if (Rolloautomatik_Open.state == ON) 

    {

        if (Elevation.state <= Integer::parseInt(Rolloautomatik_Elevation.state.toString())) 

            {

                if (timeLastStart == timeNow) 

                    {

                        if (timeLastEnde != timeNow) 

                            {

                                if (log) logInfo('rules', logPrefix + 'Blinds opened') gRolloautomatik.members.forEach

                                [i| if((Rolloautomatik_Closure.state as Number).intValue <= (i.state as Number).intValue +5 && (Rolloautomatik_Closure.state as Number).intValue >= (i.state as Number).intValue- 5) {if (log) logInfo('rules', logPrefix + 'Blind set to 0%: ' + i.name) i.sendCommand(0)} else {if (log) logInfo('rules', logPrefix + 'Blind not completely opened by script to 0%, because manually managed: ' + i.name)}]

                                //sendBroadcastNotification("Auto open finished")

                                Rolloautomatik_Last_End.postUpdate(now.toString())

                            } 

                        else 

                            {

                                if (log) logInfo('rules', logPrefix + 'Task finished. The rule will not be executes again today.')

                            }

                    } 

                else 

                    {

                        if (log) logInfo('rules', logPrefix + 'Finished. No task has been executed today. No auto opening can be executed.')

                    }

            } 

        else 

            {

                if (log) logInfo('rules', logPrefix + 'Elevation (' + Elevation.state.toString() + ') has not reached the value set (' + Rolloautomatik_Elevation.state.toString()+ ')')

            }

    } 

else 

    {

        if (log) logInfo('rules', logPrefix + 'Finished, automation disabled.')

    }

end

//-----------------------------------------------//

rule “Reset Rollo-Automatik”

when

    Item resetautomatik received command

then

    Rolloautomatik_Last_Start.state = NULL

    Rolloautomatik_Last_End.state = NULL    

end

I think you may need to add the channel info for the switches.

This rule looks awful! Guessing, you did a copy&paste :wink: where did you get this rule? 'cause it looks very familiar.

I strongly recommend to change the rule, just to get a more readable version.

  1. logInfo() is a powerful command. You don’t need to switch it on or off with an if (log) statement. You can switch it on or off by using the karaf console by typing log:set WARN org.openhab.model.script.<loggername> where <loggername> is the first string given to logInfo(). Please, don’t use "rules" as a loggername, it’s useless. Instead use the significant part of the logPrefix in an appropriate way (i.e. blinds.closure or blinds.opening here). Now you can switch the logging per rule through the karaf console:
    log:set WARN org.openhab.model.script.blinds.closure
    log:set WARN org.openhab.model.script.blinds.opening to switch OFF and
    log:set INFO org.openhab.model.script.blinds.closure
    log:set INFO org.openhab.model.script.blinds.opening to switch ON
  2. instead of nesting if-statements, use return; to end the rule early.
  3. whenever a complex expression is used more than once, use a val.

This is (almost) the same rule set:

rule "Blinds closure"
when
    Item Azimuth changed
then
    logInfo("blinds.closure", "Rule loaded!")
    var String timeLast = "xxxx-xx-xx"
    if (Rolloautomatik_Last_Start.state == NULL) {
        logInfo("blinds.closure", "First execution on this system.")
    } else {
        timeLast = Rolloautomatik_Last_Start.state.toString().substring(0,10)
    }
    var String timeNow = now.toString().substring(0,10)
    Rolloautomatik_Last_Start.postUpdate(now.toString())
    if (timeNow == timeLast) {
        logInfo("blinds.closure", "Task finished. The rule will not be executes again today.")
        return;
    }
    if (Rolloautomatik.state != ON) {
        logInfo("blinds.closure", "Finished, automation disabled.")
        return;
    }
    val nAzimuth = Azimuth.state as Number
    val nRAzimuth = Rolloautomatik_Azimuth.state as Number
    if (nAzimuth < nRAzimuth) {
        logInfo("blinds.closure", "Azimuth ({}) has not reached the value set ({})",nAzimuth,nRAzimuth)
        return;
    }
    val nExtTemp = External_Temperature.state as Number
    val nRTemp = Rolloautomatik_Temperature.state as Number
    if (nExtTemp > nRTemp) {
        logInfo("blinds.closure", "Temperature ({}) has not reached the value set ({})",nExtTemp,nRTemp)
        return;
    }
    val nCloudiness = Local_Cloudiness.state as Number
    val nRCloudiness = Rolloautomatik_Cloudiness.state as Number
    if (nCloudiness < nRCloudiness) {
        logInfo("blinds.closure", "Cloudiness ({}) has not reached the value set ({})",nCloudiness,nRCloudiness)
        return;
    }
    val nElevation = Elevation.state as Number
    val nRElevation = Rolloautomatik_Elevation.state as Number
    if (nElevation < nRElevation) {
        logInfo("blinds.closure", "Sun elevation ({}) has not reached the value set ({})",nElevation,nRElevation)
        return;
    }
    val nClosure = Rolloautomatik_Closure.state as Number
    logInfo("blinds.closure", "Blinds have been closed.") 
    gRolloautomatik.members.forEach[i| 
        if (i.state <= nClosure) {
            logInfo("blinds.closure", "Blind set to {}%: {}",nClosure, i.name) 
            i.sendCommand(nClosure)
        } else {
            logInfo("blinds.closure", "Blind already closed ({}%) so rule will be skipped",i.state)
        }
    ]
    //sendBroadcastNotification("Auto closure enabled!")
end

//-----------------------------------------------//
rule "Blinds opening"
when
    Item Elevation changed
then
    logInfo("blinds.opening", "Rule loaded!")
    var String timeLastEnde = "xxxx-xx-xx"
    if (Rolloautomatik_Last_End.state == NULL) {
        logInfo("blinds.opening", "First execution on this system.")
    } else {
        timeLastEnde = Rolloautomatik_Last_End.state.toString().substring(0,10)
    }
    Rolloautomatik_Last_End.postUpdate(now.toString())
    var String timeNow = now.toString().substring(0,10)
    if (timeLastEnde != timeNow) {
        logInfo("blinds.opening", "Task finished. The rule will not be executes again today.")
        return;
    }
    var String timeLastStart = "yyyy-yy-yy"
    if (Rolloautomatik_Last_Start.state == NULL) {
        logInfo("blinds.opening", "First execution on this system.")
    } else {
        timeLastStart = Rolloautomatik_Last_Start.state.toString().substring(0,10)
    }
    if (timeLastStart == timeNow) {
        logInfo("blinds.opening", "Finished. No task has been executed today. No auto opening can be executed.")
        return;
    }
    if (Rolloautomatik_Open.state == ON) {
        logInfo("blinds.opening", "Finished, automation disabled.")
        return;
    }
    val nElevation = Elevation.state as Number
    val nRElevation = Rolloautomatik_Elevation.state as Number
    if (nElevation <= nRElevation) {
        logInfo("blinds.opening", "Elevation ({}) has not reached the value set ({})",nElevation,nRElevation)
        return;
    }
    val nClosure = Rolloautomatik_Closure.state as Number
    logInfo("blinds.opening", "Blinds opened") 
    gRolloautomatik.members.forEach[i|
        if(Math.abs(nClosure.intValue - (i.state as Number).intValue) <= 5) {
            logInfo("blinds.opening", "Blind set to 0%: {}", i.name) 
            i.sendCommand(0)
        } else {
            logInfo("blinds.opening", "Blind not completely opened by script to 0%, because manually managed: {}", i.name)
        }
    ]
    //sendBroadcastNotification("Auto open finished")
end

//-----------------------------------------------//
rule "Reset Rollo-Automatik"
when
    Item resetautomatik received command
then
    Rolloautomatik_Last_Start.postUpdate(NULL)
    Rolloautomatik_Last_End.postUpdate(NULL)
end

Please be aware that you can’t change the state of an Item by using Item.state = whatever, this is not allowed. Instead use the appropriate method Item.postUpdate(whatever).

You have to add your rollershutter Items to the group ´gRolloautomatik`, I don’t see any Rollershutter Items in your Item definition, so I don’t know if that’s already correct.

Dear Udo,
thanks for your reply.
I did indeed a copy the .item, .sitemap and .rule File from a discussion in this forum

(Automatic Shading with Astro, OpenWeather and MqTT (for Shelly 2.5)).
Ruben and Peter have provided the solution
rubenfuser and Peter_Aschinger.

I copied everything in Visual Studio and adjusted it to my settings (weather and astro).
Is mentioned previously I am struggling with the binding of my rollershutter in this setup and you are right, this largely to the due the fact that I am not able to add my rollershutter to the group gRollomatik

Is there something wrong with this grouping below? Do I miss something?

Group gRolloautomatik
/* Shelly 2.5 Roller */
Rollershutter RollerControl “Steuerung (0=offen, 100=geschlossen)” (rRolloautomatik) {channel=“shelly:shelly25-roller:c82b96109f49:roller#control”}

I tried your rule set and get 8 errors
7 x “Type mismatch: cannot convert from State to Number”,
code": org.eclipse.xtext.xbase.validation.IssueCodes.incompatible_types",
This happens when you comparing the defined data with the real data e.g.
if (nAzimuth < nRAzimuth)

1x “The method or field intValue is undefined for the type State”,
“code”: “org.eclipse.xtext.diagnostics.Diagnostic.Linking”,
with
if(Math.abs(nClosure.intValue - (i.state as Number).intValue) <= 5) {

Do you have any suggestion on how to fix this?

Sure. Add an as Number whereever a val is set to a Number state. I’ll correct the rule above…

By the way: you have to use (gRolloautomatik) as Group, not (rRolloautomatik)