Seite 1 von 26

Elektrischen Rolladen abhängig von Sonnenstand und Wetter steuern lassen

Verfasst: 22. Mai 2019 20:33
von PeterA
Hallo zusammen,

hier möchte ich nun mein Projekt der automatischen Verschattung vorstellen.
Vorweg: Der Urheber der Rule ist Florian Schießl. Ihm möchte ich auch hiermit danken, das ich mein Projekt hier veröffentlichen darf.
https://www.forwardme.de/2018/03/12/ele ... -openhab2/
Ebenso danke ich auch Udo hier aus dem Forum für die ein oder andere "Fachfrage" :)

Was wird alles benötigt ?
Software:
OpenHab 2.4
MqTT
Weather Binding
Astro Binding
OpenHab Cloud Connector

Hardware:
Shelly 2.5 Rolladenaktor

Was kann das Ganze ?
Die Rule kann abhängig vom Sonnenstand, Temperatur und Wolken über einen elektrischen Rolladen ein Zimmer Verschatten.
Zusätzlich wird zu Beginn und Ende der Verschattung eine Pushnachricht versendet.

Wie es sich mit Sonnenrichtung und Sonnenhöhe so verhält, findet man hier:
https://www.sunearthtools.com

Das ganz ist natürlich individuell konfigurierbar.
Und funktioniert folgendermaßen:

*Es soll eine Schaltung abhängig von Sonnenwinkel und Sonnenhöhe erfolgen.
Natürlich soll das aber erst ab einer bestimmten Außentemperatur greifen, denn im Winter sind wir dann doch eher froh über das Licht und wenn Regen oder auch nur Wolken am Himmel stehen, ist eine Beschattung auch nicht notwendig. Ist der Rolladen bereits weiter geschlossen, als er geschlossen werden soll, soll nichts passieren.
Ebenso soll nichts passieren, der Rolladen beim Versuch ihn hochzufahren einen inzwischen veränderten Zustand hat.
[*Original Beschreibung von Florian]

Hier zunächst die entsprechende Items Datei: (Exemplarisch für die Westseite unseres Hauses)

Code: Alles auswählen

Group gruppeRolladen_West
// Konfiguration Rollo-Automatik West
Switch Rolloautomatik "Rollo-Automatik aus/an"
Switch Rolloautomatik_oeffnen "Rolladen öffnen aus/an"
Number Rolloautomatik_zielwert "Schließen auf [%d Prozent]"
Number Rolloautomatik_temp_min "Temperatur größer [%d °C]"
Number Rolloautomatik_wolken_max "Bewölkung weniger als [%d Prozent]"
Number Rolloautomatik_azimuth_start "Sonnenrichtung größer gleich [%d °]"
Number Rolloautomatik_elevation_ende "Sonnenhöhe kleiner gleich [%d °]"
DateTime Rolloautomatik_start_last "Letzte Ausführung (Rollo ab)"
DateTime Rolloautomatik_ende_last "Letzte Ausführung (Rollo hoch)"
Hier die Rule dazu:

Code: Alles auswählen

var boolean log = true
rule "Rollos West abfahren"
when Item Azimuth changed
then
    val String logPrefix = 'Rolloautomatik (Rollo West ab) - '
    if (log) logInfo('rules', logPrefix + 'Regel wurde gestartet')
    
    var String timeLast = 'xxxx-xx-xx'
    if (Rolloautomatik_start_last.state == NULL) {
        if (log) logInfo('rules', logPrefix + 'Erstmalige Ausführung am System, Belegung mit Initialwert')
    } else {
        timeLast = Rolloautomatik_start_last.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_start.state.toString())) {
                if (AussenTemp.state > Integer::parseInt(Rolloautomatik_temp_min.state.toString())) {
                    if (LocalWeatherAndForecast_Current_Cloudiness.state  <= Integer::parseInt(Rolloautomatik_wolken_max.state.toString())) { if (Elevation.state > Integer::parseInt(Rolloautomatik_elevation_ende.state.toString())) {
                            // Rollos runterfahren
                            if (log) logInfo('rules', logPrefix + 'Rollos werden abgefahren')
                            gruppeRolladen_West.members.forEach[i|
                                if (i.state <= Integer::parseInt(Rolloautomatik_zielwert.state.toString())) {
                                    if (log) logInfo('rules', logPrefix + 'Fahre Rolladen auf ' + Rolloautomatik_zielwert.state.toString() + '%: ' + i.name)
                                    i.sendCommand(Integer::parseInt(Rolloautomatik_zielwert.state.toString()))
                                } else {
                                    if (log) logInfo('rules', logPrefix + 'Rolladen ist bereits weiter geschlossen (' + i.state.toString() + '%) als er geschlossen werden sollte und wird daher ignoriert')
                                }
                            ]
                            // Letzte Ausführung mit entsprechendem Zeitstempel belegen
                            sendBroadcastNotification("Verschattung Westseite aktiv") //Pushnachricht
                            Rolloautomatik_start_last.postUpdate(now.toString())
                        } else {
                            if (log) logInfo('rules', logPrefix + 'Elevation für wieder abfahren (' + Rolloautomatik_elevation_ende.state.toString() + ') ist groesser als aktuelle (' + Elevation.state.toString() + ')')
                        }
                    } else {
                        if (log) logInfo('rules', logPrefix + 'Mindestbewoelkung (' + Rolloautomatik_wolken_max.state.toString() + ') wurde unterschritten (' + LocalWeatherAndForecast_Current_Cloudiness.state.toString() + ')')
                    }
                } else {
                    if (log) logInfo('rules', logPrefix + 'Mindest-Temperatur (' + Rolloautomatik_temp_min.state.toString() + ') wurde nicht erreicht durch aktuelle Temperatur (' + AussenTemp.state.toString() + ')')
                }
            } else {
                if (log) logInfo('rules', logPrefix + 'Azimuth (' + Azimuth.state.toString() + ') hat noch nicht Schwellwert (rolloautomatik_azimuth_start.state.toString()) erreicht')
            }
        } else {
            if (log) logInfo('rules', logPrefix + 'Automatik heute bereits einmal gelaufen, wird daher ignoriert')
        }
    } else {
         if (log) logInfo('rules', logPrefix + 'Beende, da Automatik generell nicht aktiv')
    }
end

rule "Rollo West wieder öffnen"
when Item Elevation changed
then
    val String logPrefix = 'Rolloautomatik (Rollo West hoch) - '
    if (log) logInfo('rules', logPrefix + 'Regel wurde gestartet')

    var String timeLastEnde = 'xxxx-xx-xx'
    if (Rolloautomatik_ende_last.state == NULL) {
        if (log) logInfo('rules', logPrefix + 'Erstmalige Ausführung am System, Belegung mit Initialwert')
    } else {
        timeLastEnde = Rolloautomatik_ende_last.state.toString().substring(0,10)
    }

    var String timeLastStart = 'yyyy-yy-yy'
    if (Rolloautomatik_start_last.state == NULL) {
        if (log) logInfo('rules', logPrefix + 'Erstmalige Ausführung am System, Belegung mit Initialwert')
    } else {
        timeLastStart = Rolloautomatik_start_last.state.toString().substring(0,10)
    }

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


    if (Rolloautomatik_oeffnen.state == ON) {
        if (Elevation.state <= Integer::parseInt(Rolloautomatik_elevation_ende.state.toString())) {
            if (timeLastStart == timeNow) {
                if (timeLastEnde != timeNow) {
                    // Rollos wieder hoch
                    if (log) logInfo('rules', logPrefix + 'Rollos werden hinaufgefahren')
                    gruppeRolladen_West.members.forEach[i|
                        if((Rolloautomatik_zielwert.state as Number).intValue <= (i.state as Number).intValue +5 && (Rolloautomatik_zielwert.state as Number).intValue >= (i.state as Number).intValue -5) {
                            if (log) logInfo('rules', logPrefix + 'Fahre Rolladen auf 0%: ' + i.name)
                            i.sendCommand(0)
                        } else {
                            if (log) logInfo('rules', logPrefix + 'Fahre Rolladen nicht auf 0%, da dieser zwischenzeitlich manuell verändert wurde: ' + i.name)
                        }
                    ]
                    // Letzte Ausführung mit entsprechendem Zeitstempel belegen
                    sendBroadcastNotification("Verschattung Westseite beendet") //Pushnachricht
                    Rolloautomatik_ende_last.postUpdate(now.toString())
                } else {
                    if (log) logInfo('rules', logPrefix + 'Beende, da heute bereits ein automatisches Wiederhochfahren stattfand')
                }
            } else {
                if (log) logInfo('rules', logPrefix + 'Beende, da heute noch keine Ausführung stattfand. Demzufolge kann auch kein automatisches Öffnen gewollt sein')
            }
        } else {
            if (log) logInfo('rules', logPrefix + 'Beende, da Elevation (' + Elevation.state.toString() + ') nicht  kleiner der eingestellten Elevation (' + Rolloautomatik_elevation_ende.state.toString()+ ') war')
        }
    } else {
        if (log) logInfo('rules', logPrefix + 'Beende, da Automatik generell nicht aktiv')
    }
end
Die Regel fragt ab, ob die Automatik generell an, eventuell bereits gelaufen ist, ob Temperatur, Bewölkung und aktueller Status der Rolläden passen und wenn dies so ist werden sie hinuntergefahren.

Wichtig ist: Alle Rolläden müssen der Gruppe gruppeRolladen_West zugeordnet werden.

Ist zum errechneten Zeitpunkt des wieder-hinauf-fahrens ein Rolladen in einem anderen Status, als er hätte sein müssen, als er heruntergefahren wurde, wird er nicht automatisch wieder hochgefahren.

Und hier der relevante Teil aus der Sitemap:

Code: Alles auswählen

Text label="Konfiguration Verschattung West" icon="rollershutter" {
        Frame label="Aktivieren der Automatik" {
        Switch item=Rolloautomatik
        Setpoint item=Rolloautomatik_zielwert minValue=0 maxValue=100 step=1
        }
        Frame label="Rollo ab, wenn..." {
        Setpoint item=Rolloautomatik_temp_min minValue=0 maxValue=35 step=1
        Text item=AussenTemp label="Temperatur Aussen [%.1f °C]" icon="temperature" valuecolor=[>27="red",>20="orange",>10="purple",>5="green",<=5="blue"]
        Setpoint item=Rolloautomatik_wolken_max minValue=0 maxValue=100 step=1
        Text item=LocalWeatherAndForecast_Current_Cloudiness icon="sun_clouds" label="Bewölkung [%.0f %%]"
        Setpoint item=Rolloautomatik_azimuth_start minValue=0 maxValue=360 step=1
        Default item=Azimuth icon="niveau" label="Azimuth"
        }
        Frame label="Rollo hoch, wenn..." {
        Switch item=Rolloautomatik_oeffnen
        Setpoint item=Rolloautomatik_elevation_ende minValue=-20 maxValue=60 step=1
        Default item=Elevation label="Elevation"
Viel Spass beim ausprobieren :)

So kann das in der Sitemap aussehen:
Bildschirmfoto 2019-05-26 um 14.33.45.png

Re: Elektrischen Rolladen abhängig von Sonnenstand und Wetter steuern lassen

Verfasst: 23. Mai 2019 18:58
von sihui
Peter Aschinger hat geschrieben: 22. Mai 2019 20:33 Was kann das Ganze ?
+1

Re: Elektrischen Rolladen abhängig von Sonnenstand und Wetter steuern lassen

Verfasst: 27. Mai 2019 08:58
von Cyrelian
Hi Peter,

super Projekt. Werde ich direkt mal verwenden. Dank Dir.

CU
Cyrelian

Re: Elektrischen Rolladen abhängig von Sonnenstand und Wetter steuern lassen

Verfasst: 27. Mai 2019 20:43
von Cyrelian
Hi Peter,

habs gerade mal ausprobiert....geile Nr :D . Läuft! ;) Allerdings hab ich mal ne Persistence auf die "Sonnenrichtung" gelegt. Sonst klickt man sich beim nächsten mal wieder nen Wolf. Ich habs dann via Rest Api eingestellt ;) .

CU
Cyrelian

Re: Elektrischen Rolladen abhängig von Sonnenstand und Wetter steuern lassen

Verfasst: 27. Mai 2019 21:57
von PeterA
Hi Cyrelian,

ja das fetzt!
Die Sollwerte habe ich auch persistiert, allerdings werden die
Sollwerte mit einer Kommastelle restored.
Dann funktioniert die Rule erst mal nicht, da die Sollwerte ohne
Kommastelle erwartet werden.
Hier hilft dann einmal alles kurz ändern, dann sind wieder alle Werte ohne Kommastelle und alles passt 😁

Re: Elektrischen Rolladen abhängig von Sonnenstand und Wetter steuern lassen

Verfasst: 1. Jun 2019 17:11
von Cyrelian
HI Peter,

ich glaube hier muss ich nochmal ran ;)

Code: Alles auswählen

[INFO ] [smarthome.model.script.shutter.rules] - Abschattung aktivieren - Mindest-Temperatur (25) wurde nicht erreicht durch aktuelle Temperatur (26.33 °C)

Code: Alles auswählen

if (localCurrentTemperature.state > Integer::parseInt(Rollladenautomatik_Temp_min.state.toString())) 
Denke das Grad Zeichen ist das Problem, bzw. du wandelst das eine in einen String und das andere ist ein Number item oder?

CU
Cyrelian

Re: Elektrischen Rolladen abhängig von Sonnenstand und Wetter steuern lassen

Verfasst: 1. Jun 2019 18:00
von PeterA
Ja das Item muß Dimensionless sein. Das musste ich auch anpassen

Re: Elektrischen Rolladen abhängig von Sonnenstand und Wetter steuern lassen

Verfasst: 2. Jun 2019 13:30
von udo1toni
Da Rollladenautomatik_Temp_min vermutlich vom Typ Number ist, localCurrentTemperature aber vom Typ Number:Temperature,
sollte der Vergleich eher so aussehen:

Code: Alles auswählen

if ((localCurrentTemperature.state as Number).floatValue > (Rollladenautomatik_Temp_min.state as Number)) 
das .floatValue erzwingt in diesem Fall, dass der Wert dimensionslos ist.

Re: Elektrischen Rolladen abhängig von Sonnenstand und Wetter steuern lassen

Verfasst: 3. Jun 2019 09:01
von Cyrelian
udo1toni hat geschrieben: 2. Jun 2019 13:30 Da Rollladenautomatik_Temp_min vermutlich vom Typ Number ist, localCurrentTemperature aber vom Typ Number:Temperature,
sollte der Vergleich eher so aussehen:

Code: Alles auswählen

if ((localCurrentTemperature.state as Number).floatValue > (Rollladenautomatik_Temp_min.state as Number)) 
das .floatValue erzwingt in diesem Fall, dass der Wert dimensionslos ist.
Sauber, der floatValue war der Trick. Hatte es mit nur "Number", das hat aber nicht geklappt.

CYA
Cyrelian

Re: Elektrischen Rolladen abhängig von Sonnenstand und Wetter steuern lassen

Verfasst: 3. Jun 2019 10:46
von PeterA
Cyrelian hat geschrieben: 3. Jun 2019 09:01
udo1toni hat geschrieben: 2. Jun 2019 13:30 Da Rollladenautomatik_Temp_min vermutlich vom Typ Number ist, localCurrentTemperature aber vom Typ Number:Temperature,
sollte der Vergleich eher so aussehen:

Code: Alles auswählen

if ((localCurrentTemperature.state as Number).floatValue > (Rollladenautomatik_Temp_min.state as Number)) 
das .floatValue erzwingt in diesem Fall, dass der Wert dimensionslos ist.
Sauber, der floatValue war der Trick. Hatte es mit nur "Number", das hat aber nicht geklappt.

CYA
Cyrelian
auch von mir ein +1! :) Das ist OpenSource :)