Elektrischen Rolladen abhängig von Sonnenstand und Wetter steuern lassen

Für welche Projekte verwendet Ihr OpenHAB? Was habt Ihr automatisiert? Stellt eure Projekte hier vor.

Moderatoren: Cyrelian, seppy

Antworten
Benutzeravatar
udo1toni
Beiträge: 13982
Registriert: 11. Apr 2018 18:05
Answers: 222
Wohnort: Darmstadt

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

Beitrag von udo1toni »

Ich hab mir erst jetzt mal kurz die Rules zu Gemüte geführt - oberflächlich.

Eigentlich sollte es durch die Verwendung von .intValue keine Rolle spielen, ob der Wert nun als Integer oder als Float rein kommt.

Allerdings schreie ich innerlich auf bei so einer Formulierung:

Code: Alles auswählen

if(log) logInfo(...)
Der in openHAB integrierte Logger beherrscht weit mehr, als vorn im Logfile das Wort auszutauschen. Man kann während der Laufzeit (!) das Loglevel anpassen, und zwar beliebig kleinteilig. Dazu muss man aber den logbefehl korrekt verwenden.

Code: Alles auswählen

logInfo("meinLogger","Meine Meldung")
Erzeugt die Logzeile mit [INFO] nach dem Zeitstempel, aber nur unter der Bedingung, dass das LogLevel für org.smarthome.model.script.meinLogger mindestens auf INFO steht. Setzt man das Level auf WARN, werden keine Meldungen des Levels INFO mehr ausgegeben.
Das macht man während der LAufzeit von der Karaf Konsole aus per

Code: Alles auswählen

log:set WARN org.smarthome.model.script.meinLogger
Und das gilt dann nur für diese eine Rule (bzw. überall da, wo man halt meinLogger als Logger angegeben hat).
Man kann auch das Logging gemeinsam für alle Rules steuern, dann lässt man halt den hinteren Teil ab script weg (funktionert natürlich nur, solange man del Level noch nicht auf der unteren Ebene gesetzt hat).

Man spart sich also die Variable zu Beginn der Rules Datei, das if(log), wenn man Warnmeldungen ausgeben möchte, macht man das mit logWarn(), Fehler mit logError, Meldungen, die nur zum Debugging interessant sind, gibt man mit logDebug() aus. Dann muss man das Logging nur über die Karaf Konsole entsprechend setzen und bekommt die Logmeldungen entsprechend.

Weiterhin ist das Konstrukt mit toString an manchen Stellen nicht so gut, vor allem aber bei log-Meldungen. Diese beiden Zeilen:

Code: Alles auswählen

logInfo(filename, logPrefix + "Beende, aktuelle Temperatur (" + localCurrentTemperature.state.toString() + ") ueberschreitet den eingestellten Grenzwert zum hochfahren von (" + AutoShading_Temp_raise.state.toString()+ ") ")
logInfo("beschattung","Beende, aktuelle Temperatur ({}) überschreitet den eingestellten Grenzwert zum hochfahren ({}) ",localCurrentTemperature.state, AutoShading_Temp_raise.state)
sind weitgehend bedeutungsgleich, aber im zweiten Fall wird aus der Zahl automatisch ein passender String erzeugt. Die beiden werte werden nun als Werte übergeben, nicht als Teilstring.

Diese Zeile hier

Code: Alles auswählen

if ((blind.state as Number) < targetHights.get(blind.name.toString()).intValue) {
ist auch so eine Sache. blind.name ist immer(!) ein String. Wenn schon, müsste es so aussehen:

Code: Alles auswählen

if ((blind.state as Number) < targetHights.get(blind.name).intValue) {
Allerdings setzt das voraus, das blind.state schon eine gültige Zahl zurück liefert (das ist z.B. nach dem Systemstart nicht zwingend gegeben, auch
wenn das Item persistiert und mit restoreOnStartup wiederhergestellt wird!).
Besser ist es, in so einem Fall vorher mittels

Code: Alles auswählen

if (blind.state instanceof Number)
zu prüfen, ob der nachfolgende Vergleich funktionieren kann.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

jensilein
Beiträge: 34
Registriert: 24. Feb 2018 09:11
Answers: 0

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

Beitrag von jensilein »

Hallo Peter,

ich glaube, ich habe die Lösung gefunden. Die besagten items müssen über MapDB persistiert werden und nicht über InfluxDB, damit sollte es klappen. MapDB und InfluxDB lassen sich parallel betreiben. Ich werde es ausprobieren.

jensilein
Beiträge: 34
Registriert: 24. Feb 2018 09:11
Answers: 0

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

Beitrag von jensilein »

udo1toni hat geschrieben: 2. Aug 2019 13:55 Ich hab mir erst jetzt mal kurz die Rules zu Gemüte geführt - oberflächlich.

Eigentlich sollte es durch die Verwendung von .intValue keine Rolle spielen, ob der Wert nun als Integer oder als Float rein kommt.

Allerdings schreie ich innerlich auf bei so einer Formulierung:

Code: Alles auswählen

if(log) logInfo(...)
Der in openHAB integrierte Logger beherrscht weit mehr, als vorn im Logfile das Wort auszutauschen. Man kann während der Laufzeit (!) das Loglevel anpassen, und zwar beliebig kleinteilig. Dazu muss man aber den logbefehl korrekt verwenden.

Code: Alles auswählen

logInfo("meinLogger","Meine Meldung")
Erzeugt die Logzeile mit [INFO] nach dem Zeitstempel, aber nur unter der Bedingung, dass das LogLevel für org.smarthome.model.script.meinLogger mindestens auf INFO steht. Setzt man das Level auf WARN, werden keine Meldungen des Levels INFO mehr ausgegeben.
Das macht man während der LAufzeit von der Karaf Konsole aus per

Code: Alles auswählen

log:set WARN org.smarthome.model.script.meinLogger
Und das gilt dann nur für diese eine Rule (bzw. überall da, wo man halt meinLogger als Logger angegeben hat).
Man kann auch das Logging gemeinsam für alle Rules steuern, dann lässt man halt den hinteren Teil ab script weg (funktionert natürlich nur, solange man del Level noch nicht auf der unteren Ebene gesetzt hat).

Man spart sich also die Variable zu Beginn der Rules Datei, das if(log), wenn man Warnmeldungen ausgeben möchte, macht man das mit logWarn(), Fehler mit logError, Meldungen, die nur zum Debugging interessant sind, gibt man mit logDebug() aus. Dann muss man das Logging nur über die Karaf Konsole entsprechend setzen und bekommt die Logmeldungen entsprechend.

Weiterhin ist das Konstrukt mit toString an manchen Stellen nicht so gut, vor allem aber bei log-Meldungen. Diese beiden Zeilen:

Code: Alles auswählen

logInfo(filename, logPrefix + "Beende, aktuelle Temperatur (" + localCurrentTemperature.state.toString() + ") ueberschreitet den eingestellten Grenzwert zum hochfahren von (" + AutoShading_Temp_raise.state.toString()+ ") ")
logInfo("beschattung","Beende, aktuelle Temperatur ({}) überschreitet den eingestellten Grenzwert zum hochfahren ({}) ",localCurrentTemperature.state, AutoShading_Temp_raise.state)
sind weitgehend bedeutungsgleich, aber im zweiten Fall wird aus der Zahl automatisch ein passender String erzeugt. Die beiden werte werden nun als Werte übergeben, nicht als Teilstring.

Diese Zeile hier

Code: Alles auswählen

if ((blind.state as Number) < targetHights.get(blind.name.toString()).intValue) {
ist auch so eine Sache. blind.name ist immer(!) ein String. Wenn schon, müsste es so aussehen:

Code: Alles auswählen

if ((blind.state as Number) < targetHights.get(blind.name).intValue) {
Allerdings setzt das voraus, das blind.state schon eine gültige Zahl zurück liefert (das ist z.B. nach dem Systemstart nicht zwingend gegeben, auch
wenn das Item persistiert und mit restoreOnStartup wiederhergestellt wird!).
Besser ist es, in so einem Fall vorher mittels

Code: Alles auswählen

if (blind.state instanceof Number)
zu prüfen, ob der nachfolgende Vergleich funktionieren kann.
Hallo udo1toni,

kannst Du mir bitte mal einen Tipp zu folgendem Punkt geben. In der rule wird u.a. ja die aktuelle Bewölkung mit dem Sollwert für die Bewölkung verglichen, damit die Rollos nur dann abfahren, wenn die aktuelle Bewölkung kleiner als der Sollwert ist:
if (wetter_bewoelkung.state <= Integer::parseInt(rolloautomatik_wolken_max.state.toString())) {
Da die von Openweathermap gelieferten Bewölkungs-Daten im Minutenbereich immer wieder mal stärker Hin- und Herspringen, würde ich diese Sprünge gerne irgendwie ausgleichen, um ein fälschliches Abfahren der Rollos zu vermeiden. Ich hätte hier z.B. an eine Mittelwertbildung der persistierten Bewölkungs-Daten über die letzten 15 oder 30 Minuten gedacht (ich persistiere diese Daten in InfluxDB). Könnte ich das so machen, indem ich das oben stehende if-statement wie folgt anpasse:
if (wetter_bewoelkung.state.averageSince(now.minusMinutes(15)) <= Integer::parseInt(rolloautomatik_wolken_max.state.toString())) {
oder ist diese Syntax falsch?

Vielen Dank.

Benutzeravatar
udo1toni
Beiträge: 13982
Registriert: 11. Apr 2018 18:05
Answers: 222
Wohnort: Darmstadt

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

Beitrag von udo1toni »

Code: Alles auswählen

if(wetter_bewoelkung.averageSince(now.minusMinutes(15)) <= Integer::parseInt(rolloautomatik_wolken_max.state.toString())) { 
So sollte es sein. Das Wort .state ist Methode um den Status zu bekommen. .averageSince() liefert den Durchschnitt.

Aber wenn rolloautomatik_wolken_max ein Number Item ist, sollte es so genauso gehen:

Code: Alles auswählen

if(wetter_bewoelkung.averageSince(now.minusMinutes(15)) <= (rolloautomatik_wolken_max.state as Number).intValue) { 
Allerdings sollte man vorher in der Rule testen, ob tatsächlich Zahlen vorliegen:

Code: Alles auswählen

if(rolloautomatik_wolken_max.state instanceof Number)
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Benutzeravatar
Cyrelian
Beiträge: 601
Registriert: 24. Sep 2015 17:55
Answers: 4

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

Beitrag von Cyrelian »

Hallo zusammen,

wie versprochen hier ein weiters UPDATE:

Was ist neu?

- Präsenzerkennung (Verschattungs-Automatik wird ausgesetzt)
- Verbesserungsvorschläge von Udo zum Großteil eingearbeitet
- neue booleans für die Abfragen auf "Max Regenmenge in der letzten Stunde", "durchschnittliche Bewölkung der letzen Stunde" und "Temperaturabfall in der letzten Stunde" eingebaut (zum Öffnen der Rollladen)
- Anpassung der IF Abfragen auf boolean z.B.

Code: Alles auswählen

if (!isActiveWest && !isActiveEast && !isActiveSouth)
Mal schauen was mir fürs nächste Update noch so einfällt :D

Code: Alles auswählen

import java.util.Map

// Das Logging kann für diese Rules separat aktiviert werden (log=true)
var boolean log = true
var boolean message = true

val String filename = "shutter.rules"

val Number blindClosed = 100
val Number blindOpen = 0
val Number blindTranslucent = 35

var Number closingAzimuth_west = 181
var Number closingAzimuth_south = 111
var Number closingAzimuth_east = 65

var Number closingCloudiness = 20   
val Number cloudHysteresis = 45         //die Mindestbewölkung in der letzten Stunde
var Number openingTemperature = 22
val Number temperatureHysteresis = 5 //Temperaturabfall von min. 5 Grad in der letzten Stunde
val Number minPrecip = 5                //die Mindestmenge an Regen in der letzten Stunde

var boolean isActiveWest = false
var boolean isActiveEast = false
var boolean isActiveSouth = false

val Map<String, Number> targetHights = newHashMap ( 
    "KuecheRollladenTuer" -> 58,
    "SchlafzimmerRollladenTuer" -> 100,
    "BadezimmerRollladen" -> 55,
    "WohnzimmerRollladenEsstisch" -> 65,
    "WohnzimmerRollladenTuer" -> 68,
    "WohnzimmerRollladenBalkon" -> 100
)

/* -------------  Automatische Verschattung ein/aus --------------------
*/

//-------------  Verschattung FUNKTION --------------------

val shadingStart = [GroupItem shutter |

        val String logPrefix = "Verschattung aktivieren - "
        var boolean log = true

                val Map<String, Number> targetHights = newHashMap ( 
                "KuecheRollladenTuer" -> 58,
                "SchlafzimmerRollladenTuer" -> 100,
                "BadezimmerRollladen" -> 55,
                "WohnzimmerRollladenEsstisch" -> 65,
                "WohnzimmerRollladenTuer" -> 68,
                "WohnzimmerRollladenBalkon" -> 100
                )

                if ((Temperature.state as Number).floatValue <= (AutoShading_Temp_min.state as Number)) {
                        //if (log) logInfo ("Lambda", logPrefix + "Mindesttemperatur von (" + AutoShading_Temp_min.state.toString() + ") wurde nicht erreicht. Aktuelle Temperatur (" + Temperature.state.toString() + ")")
                        if (log) logInfo ("Lambda", logPrefix + "Mindesttemperatur von ({}) wurde nicht erreicht. Aktuelle Temperatur ({}) ", AutoShading_Temp_min.state, Temperature.state)
                        return false;
                }

                if ((Clouds.state as Number).floatValue > (AutoShading_Cloudiness_max.state as Number)) { 
                        //if (log) logInfo ("Lambda", logPrefix + "Aktuelle Bewoelkung (" + Clouds.state.toString() + ") ueberschreitet den eingestellten Grenzwert von (" + AutoShading_Cloudiness_max.state.toString() + ")")
                        if (log) logInfo ("Lambda", logPrefix + "Aktuelle Bewoelkung ({}) ueberschreitet den eingestellten Grenzwert von ({})", Clouds.state, AutoShading_Cloudiness_max.state)
                        return false;
                }

                if ((Elevation.state as Number) <= (AutoShading_Elevation_end.state as Number)) {
                        //if (log) logInfo ("Lambda", logPrefix + "Elevation für das Beenden der Verschattung (" + AutoShading_Elevation_end.state.toString() + ") ist groesser als aktuelle (" + Elevation.state.toString() + ")")
                        if (log) logInfo ("Lambda", logPrefix + "Elevation für das Beenden der Verschattung ({}) ist groesser als aktuelle ({}) ", AutoShading_Elevation_end.state, Elevation.state)
                        return false;
                }

                // Rollladen werden geschlossen
                if (log) logInfo("Lambda", logPrefix + "Grenzwert wurden erreicht, Rollladen werden geschlossen")

                shutter.members.forEach[ blind |
                    if ((blind.state as Number) < targetHights.get(blind.name).intValue) {
                        logInfo ("Lambda", logPrefix + "Fahre Rollladen (" + blind.name.toString() + ") auf (" + targetHights.get(blind.name).intValue) + ") %" )
                        blind.sendCommand(targetHights.get(blind.name).intValue))
                        //Pushnachricht versenden
                        sendPushoverMessage(pushoverBuilder("Verschattung für " + blind.name.toString + " aktiviert, schließen auf " + targetHights.get(blind.name.toString()).toString() + " %"))
                    } else {
                        logInfo ("Lambda", logPrefix + "Rollladen ist bereits weiter geschlossen (" + blind.state.toString() + "%) als er geschlossen werden sollte und wird daher ignoriert")
                    }
                ]
                AutoShading_Start_last.postUpdate(now.toString())
    return true;
]

//-------------  Verschattung starten --------------------

rule "Verschattung starten"
when
    Item Azimuth changed
then
    val String logPrefix = "Verschattung aktivieren - "
    
    //Prüfung ob Verschattungsautomatik an ist und ob es Tag ist
    if ((AutoShading.state == ON && IsDay.state == ON) && (DinesiPhone_Presence.state == OFF && OllisiPhone_Presence.state == OFF)) {
    
            
            if (AutoShading_Start_last.state === NULL) {
                if (log) logInfo(logPrefix, 'Letzte Ausführung unbekannt, Belegung mit Initialwert (-1 Tag)')
                    AutoShading_Start_last.postUpdate(now.minusDays(1).toString())
                }
            
            //var String timeNow = now.toString().substring(0,10)
            //var String timeLastStart = AutoShading_Start_last.state.toString().substring(0,10)
            
            // Items für Sitemap füllen
            if (AutoShading_Azimuth_east == "NULL" ||  AutoShading_Azimuth_south == "NULL" || AutoShading_Azimuth_west == "NULL" ){
                    AutoShading_Azimuth_east.postUpdate(closingAzimuth_west)
                    AutoShading_Azimuth_south.postUpdate(closingAzimuth_south)
                    AutoShading_Azimuth_west.postUpdate(closingAzimuth_west)
                    AutoShading_Temp_diff.postUpdate(temperatureHysteresis)
                    AutoShading_Cloudiness_Hyst.postUpdate(cloudHysteresis)
                    AutoShading_Rain_min.postUpdate(minPrecip)
            }
            
            //Azimuth ist größer als 181° (WEST)
            if (!isActiveWest) { 
                if ((Azimuth.state as Number).floatValue > (closingAzimuth_west)) {
                    if (log) logInfo (filename, logPrefix + "Abschatung für Rollläden WEST")
                    isActiveWest = shadingStart.apply(gRollladenWest)
                    return;
                }      
            } else {
                     if (log) logInfo (filename, logPrefix + "Abschatung für Rollläden WEST bereits aktiviert")
                } 
        
            //Azimuth ist größer als 111° (SÜD)
           if (!isActiveSouth) { 
                if ((Azimuth.state as Number).floatValue > (closingAzimuth_south) && (Azimuth.state as Number).floatValue < (closingAzimuth_west)) {
                    if (log) logInfo (filename, logPrefix + "Abschatung für Rollläden SÜD")
                    isActiveSouth = shadingStart.apply(gRollladenSouth)
                    return;
                }
           } else {
                     if (log) logInfo (filename, logPrefix + "Abschatung für Rollläden SÜD bereits aktiviert")
                }

            //Azimuth ist größer als 65° (OST)
            if (!isActiveEast) { 
                if ((Azimuth.state as Number).floatValue > (closingAzimuth_east) && (Azimuth.state as Number).floatValue < (closingAzimuth_south)) {
                    if (log) logInfo (filename, logPrefix + "Abschatung für Rollläden OST")
                    isActiveEast = shadingStart.apply(gRollladenEast)
                return;
                }
            } else {
                     if (log) logInfo (filename, logPrefix + "Abschatung für Rollläden OST bereits aktiviert")
                }
    
    } else {
            if (log) logInfo(filename, logPrefix + "Verschattung wird nicht ausgeführt, da einer der folgenden Parameter matched: Verschattung deakiviert, es ist Nacht oder Anwesenheit erkannt.")
           }

end

//-------------  Verschattung beenden --------------------

rule "Verschattung beenden"
when 
    Item Elevation changed
then   
    if (AutoShading_end.state == ON && IsDay.state == ON) {
                    
            val boolean isRainLastHour = (Rain.maximumSince(now.minusHours(1), "influxdb").state >= (minPrecip))
            val boolean isCloudLastHour = (Clouds.averageSince(now.minusHours(1), "influxdb").intValue >= (cloudHysteresis))
            val boolean isTempLastHour = (Temperature.state < ((Temperature.minimumSince(now.minusHours(1), "influxdb")as DecimalType).intValue -5))
            
            val String logPrefix = "Verschattung deaktivieren - "
            
            if (AutoShading_End_last.state === NULL) {
                if (log) logInfo(logPrefix, 'Letzte Ausführung unbekannt, Belegung mit Initialwert (-1 Tag)')
                    AutoShading_End_last.postUpdate(now.minusDays(1).toString())
                }

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

            if (timeLastEnde == timeNow) {
                if (log) logInfo(filename, logPrefix + "Beende, da heute bereits ein automatisches Hochfahren stattfand")
                return;
            }

            if ((Temperature.state as Number).floatValue > (AutoShading_Temp_raise.state as Number)) {
                //if (log) logInfo(filename, logPrefix + "Beende, aktuelle Temperatur (" + Temperature.state.toString() + ") ueberschreitet den eingestellten Grenzwert zum hochfahren von (" + AutoShading_Temp_raise.state.toString()+ ") ")
                if (log) logInfo(filename, logPrefix + "Beende, aktuelle Temperatur ({}) überschreitet den eingestellten Grenzwert zum hochfahren von ({}) ",Temperature.state, AutoShading_Temp_raise.state)
                return;
            }

            if ((Elevation.state as Number) > (AutoShading_Elevation_end.state as Number)) {
               //if (log) logInfo(filename, logPrefix + "Beende, aktuelle Elevation (" + Elevation.state.toString() + ") ueberschreitet den eingestellten Grenzwert von (" + AutoShading_Elevation_end.state.toString()+ ") ")
               if (log) logInfo(filename, logPrefix + "Beende, aktuelle Elevation ({}) ueberschreitet den eingestellten Grenzwert von ({}) ", Elevation.state, AutoShading_Elevation_end.state)
               return;
            }

            if (!isActiveWest && !isActiveEast && !isActiveSouth) {
                if (log) logInfo(filename, logPrefix + "Beende, da heute noch keine automatische Verschattung stattfand")
                return;
            }

            if (isActiveWest || isActiveEast || isActiveSouth || isRainLastHour || isCloudLastHour || isTempLastHour) {
                    // Rollladen öffnen
                        if (log) logInfo(filename, logPrefix + "Rollladen werden geoeffnet")
                        gRollladen.allMembers.forEach[blind|
                            if((blind.state as Number).intValue == targetHights.get(blind.name).intValue) {
                                if (log) logInfo(filename, logPrefix + "Oeffne Rollladen: " + blind.name.toString())
                                blind.sendCommand(UP)
                                //Pushnachricht versenden                        
                                sendPushoverMessage(pushoverBuilder("Verschattung für (" + blind.name.toString() + ") beendet, Rollladen wird geöffnet."))
                            } else {
                                if (log) logInfo(filename, logPrefix + "Rollladen: (" + blind.name.toString() + ") wird nicht geoeffnet, da dieser zwischenzeitlich manuell verändert wurde.")
                            }    
                        ]                         
                        // Letzte Ausführung mit entsprechendem Zeitstempel belegen
                        AutoShading_End_last.postUpdate(now.toString())
                        
                        //Variablen zurücksetzen
                        isActiveWest = false
                        isActiveEast = false
                        isActiveSouth = false
            }
        }            
end


/* -------------  Verschattung Variablen zurücksetzen wenn kein automtisches hochfahren erfolgt --------------------
*/

rule "Verschattung Variablen zurücksetzen"
when
        Time cron "15 59 23 * * ?"
then
        if (isActiveWest == true || isActiveEast == true || isActiveSouth == true) {
            isActiveWest = false
            isActiveEast = false
            isActiveSouth = false
        }
end
Mit dem logging hat Udo natürlich absolut recht. Via Karaf ist das die "sauberere" Variante....bin nur faul und in der Rule bin ich irgendwie schneller :D

CYA
Cyrelian

Benutzeravatar
PeterA
Beiträge: 1052
Registriert: 8. Feb 2019 12:12
Answers: 13

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

Beitrag von PeterA »

Hi Cyrelian,

mein Lieber Herr Gesangsverein!!!!
TOP TOP TOP!!!
- OpenHab 2.4
#PWRUP

Benutzeravatar
Cyrelian
Beiträge: 601
Registriert: 24. Sep 2015 17:55
Answers: 4

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

Beitrag von Cyrelian »

Peter Aschinger hat geschrieben: 6. Aug 2019 08:12 Hi Cyrelian,

mein Lieber Herr Gesangsverein!!!!
TOP TOP TOP!!!
Hi Peter,

dank dir für die "Blumen" :D. Ich dank Euch aber auch für eure Inspirationen und Verbesserungsvorschläge.
....bin schon wieder am optimieren...CODE folgt ;)

CU
Cyrelian

Benutzeravatar
Cyrelian
Beiträge: 601
Registriert: 24. Sep 2015 17:55
Answers: 4

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

Beitrag von Cyrelian »

Hallo zusammen,

wie angekündigt hier das nächste UPDATE:

Was ist neu?

- Abfrage auf Jahreszeiten...im Herbst und Winter keine Verschattung
- Verschattung beenden ist nun auch eine Lambda Funktion
- Reihenfolge der Rahmenparameterprüfung optimiert
- Historische Temperaturabfrage in boolean gepackt

Code: Alles auswählen

// Values und Variablen für die Verschattung

//val Number blindClosed = 100
//val Number blindOpen = 0
//val Number blindTranslucent = 35

var Number closingAzimuth_west = 181
var Number closingAzimuth_south = 111
var Number closingAzimuth_east = 65

var Number closingCloudiness = 20   
val Number cloudHysteresis = 45         //die Mindestbewölkung in der letzten Stunde
var Number openingTemperature = 22
val Number temperatureHysteresis = 4    //Temperaturabfall von min. 4 Grad in der letzten Stunde
val Number minPrecip = 5                //die Mindestmenge an Regen in der letzten Stunde

var boolean isActiveWest = false
var boolean isActiveEast = false
var boolean isActiveSouth = false


/* -------------  Verschattung FUNKTIONEN --------------------
*/
//-------------  Verschattung starten --------------------

val shadingStart = [GroupItem shutter |

        val String logPrefix = "Verschattung aktivieren - "
        var boolean log = true

                val Map<String, Number> targetHights = newHashMap ( 
                "KuecheRollladenTuer" -> 58,
                "SchlafzimmerRollladenTuer" -> 100,
                "BadezimmerRollladen" -> 55,
                "WohnzimmerRollladenEsstisch" -> 65,
                "WohnzimmerRollladenTuer" -> 68,
                "WohnzimmerRollladenBalkon" -> 100
                )

                if ((Temperature.state as Number).floatValue <= (AutoShading_Temp_min.state as Number)) {
                        //if (log) logInfo ("Lambda", logPrefix + "Mindesttemperatur von (" + AutoShading_Temp_min.state.toString() + ") wurde nicht erreicht. Aktuelle Temperatur (" + Temperature.state.toString() + ")")
                        if (log) logInfo ("Lambda", logPrefix + "Mindesttemperatur von ({}) wurde nicht erreicht. Aktuelle Temperatur ({}) ", AutoShading_Temp_min.state, Temperature.state)
                        return false;
                }

                if ((Clouds.state as Number).floatValue > (AutoShading_Cloudiness_max.state as Number)) { 
                        //if (log) logInfo ("Lambda", logPrefix + "Aktuelle Bewoelkung (" + Clouds.state.toString() + ") ueberschreitet den eingestellten Grenzwert von (" + AutoShading_Cloudiness_max.state.toString() + ")")
                        if (log) logInfo ("Lambda", logPrefix + "Aktuelle Bewoelkung ({}) ueberschreitet den eingestellten Grenzwert von ({})", Clouds.state, AutoShading_Cloudiness_max.state)
                        return false;
                }

                if ((Elevation.state as Number) <= (AutoShading_Elevation_end.state as Number)) {
                        //if (log) logInfo ("Lambda", logPrefix + "Elevation für das Beenden der Verschattung (" + AutoShading_Elevation_end.state.toString() + ") ist groesser als aktuelle (" + Elevation.state.toString() + ")")
                        if (log) logInfo ("Lambda", logPrefix + "Elevation für das Beenden der Verschattung ({}) ist groesser als aktuelle ({}) ", AutoShading_Elevation_end.state, Elevation.state)
                        return false;
                }

                // Rollladen werden geschlossen
                if (log) logInfo("Lambda", logPrefix + "Grenzwert wurden erreicht, Rollladen werden geschlossen")

                shutter.members.forEach[ blind |
                    if ((blind.state as Number) < targetHights.get(blind.name.toString()).intValue) {
                        logInfo ("Lambda", logPrefix + "Fahre Rollladen (" + blind.name.toString() + ") auf (" + targetHights.get(blind.name.toString()).intValue + ") %" )
                        blind.sendCommand(targetHights.get(blind.name.toString()).intValue)
                        //Pushnachricht versenden
                        sendPushoverMessage(pushoverBuilder("Verschattung für " + blind.name.toString + " aktiviert, schließen auf " + targetHights.get(blind.name.toString()).toString() + " %"))
                    } else {
                        logInfo ("Lambda", logPrefix + "Rollladen ist bereits weiter geschlossen (" + blind.state.toString() + "%) als er geschlossen werden sollte und wird daher ignoriert")
                    }
                ]
                AutoShading_Start_last.postUpdate(now.toString())
    return true;
]

//-------------  Verschattung beenden -------------------

val shadingEnd = [GroupItem shutter |

        val String logPrefix = "Verschattung deaktivieren - "
        var boolean log = true

                    val Map<String, Number> targetHights = newHashMap ( 
                    "KuecheRollladenTuer" -> 58,
                    "SchlafzimmerRollladenTuer" -> 100,
                    "BadezimmerRollladen" -> 55,
                    "WohnzimmerRollladenEsstisch" -> 65,
                    "WohnzimmerRollladenTuer" -> 68,
                    "WohnzimmerRollladenBalkon" -> 100
                     )
                    
                    // Rollladen öffnen
                    if (log) logInfo(filename, logPrefix + "Rollladen werden geoeffnet")
                    shutter.allMembers.forEach[blind|
                        if((blind.state as Number).intValue == targetHights.get(blind.name).intValue) {
                            logInfo ("Lambda", logPrefix + "Oeffne Rollladen: " + blind.name.toString())
                            blind.sendCommand(UP)
                            //Pushnachricht versenden                        
                            sendPushoverMessage(pushoverBuilder("Verschattung für (" + blind.name.toString() + ") beendet, Rollladen wird geöffnet."))
                        } else {
                            logInfo ("Lambda", logPrefix + "Rollladen: (" + blind.name.toString() + ") wird nicht geoeffnet, da dieser zwischenzeitlich manuell verändert wurde.")
                        }    
                    ]                         
                    // Letzte Ausführung mit entsprechendem Zeitstempel belegen
                    AutoShading_End_last.postUpdate(now.toString())
                    
                    //Variablen zurücksetzen
                    isActiveWest = false
                    isActiveEast = false
                    isActiveSouth = false
    return true;
]

/* -------------  Verschattung RULES --------------------
*/
//-------------  Verschattung starten --------------------

rule "Verschattung starten"
when
    Item Azimuth changed
then
    val String logPrefix = "Verschattung aktivieren - "
    
    //Prüfung auf: Verschattungsautomatik an / ob es Tag ist / Präsenz / Jahreszeit
    if ((AutoShading.state == ON && IsDay.state == ON) && (DinesiPhone_Presence.state == OFF && OllisiPhone_Presence.state == OFF) && (Jahreszeit.state=="SPRING" || Jahreszeit.state=="SUMMER")) {
               
            if (AutoShading_Start_last.state === NULL) {
                if (log) logInfo(logPrefix, 'Letzte Ausführung unbekannt, Belegung mit Initialwert (-1 Tag)')
                    AutoShading_Start_last.postUpdate(now.minusDays(1).toString())
                }
            
            //var String timeNow = now.toString().substring(0,10)
            //var String timeLastStart = AutoShading_Start_last.state.toString().substring(0,10)
            
            // Items für Sitemap füllen
            if (AutoShading_Azimuth_east == "NULL" ||  AutoShading_Azimuth_south == "NULL" || AutoShading_Azimuth_west == "NULL" ){
                    AutoShading_Azimuth_east.postUpdate(closingAzimuth_west)
                    AutoShading_Azimuth_south.postUpdate(closingAzimuth_south)
                    AutoShading_Azimuth_west.postUpdate(closingAzimuth_west)
                    AutoShading_Temp_diff.postUpdate(temperatureHysteresis)
                    AutoShading_Cloudiness_Hyst.postUpdate(cloudHysteresis)
                    AutoShading_Rain_min.postUpdate(minPrecip)
            }
            
            //Azimuth ist größer als 181° (WEST)
            if (!isActiveWest) { 
                if ((Azimuth.state as Number).floatValue > (closingAzimuth_west)) {
                    if (log) logInfo (filename, logPrefix + "Verschattung für Rollläden WEST")
                    isActiveWest = shadingStart.apply(gRollladenWest)
                    return;
                }      
            } else {
                     if (log) logInfo (filename, logPrefix + "Verschattung für Rollläden WEST bereits aktiviert")
                } 
        
            //Azimuth ist größer als 111° (SÜD)
           if (!isActiveSouth) { 
                if ((Azimuth.state as Number).floatValue > (closingAzimuth_south) && (Azimuth.state as Number).floatValue < (closingAzimuth_west)) {
                    if (log) logInfo (filename, logPrefix + "Verschattung für Rollläden SÜD")
                    isActiveSouth = shadingStart.apply(gRollladenSouth)
                    return;
                }
           } else {
                     if (log) logInfo (filename, logPrefix + "Verschattung für Rollläden SÜD bereits aktiviert")
                }

            //Azimuth ist größer als 65° (OST)
            if (!isActiveEast) { 
                if ((Azimuth.state as Number).floatValue > (closingAzimuth_east) && (Azimuth.state as Number).floatValue < (closingAzimuth_south)) {
                    if (log) logInfo (filename, logPrefix + "Verschattung für Rollläden OST")
                    isActiveEast = shadingStart.apply(gRollladenEast)
                return;
                }
            } else {
                     if (log) logInfo (filename, logPrefix + "Verschattung für Rollläden OST bereits aktiviert")
                }
    
    } else {
            if (log) logInfo(filename, logPrefix + "Verschattung wird nicht ausgeführt, da einer der folgenden Parameter matched: Verschattung deakiviert, es ist Nacht, Herbst oder Winter oder Anwesenheit erkannt.")
           }

end

//-------------  Verschattung beenden --------------------

rule "Verschattung beenden"
when 
    Item Elevation changed
then   
    if ((AutoShading_end.state == ON && IsDay.state == ON) && (Jahreszeit.state=="SPRING" || Jahreszeit.state=="SUMMER")) {
                    
            val boolean isRainLastHour = (Rain.maximumSince(now.minusHours(1), "influxdb").state >= (minPrecip))
            val boolean isCloudLastHour = (Clouds.averageSince(now.minusHours(1), "influxdb")as Number >= (cloudHysteresis))
            val boolean isTemperature = ((Temperature.state as Number).intValue < (Temperature.minimumSince(now.minusHours(1), "influxdb").state as DecimalType -(temperatureHysteresis)))
            
            val String logPrefix = "Verschattung deaktivieren - "
            
            if (AutoShading_End_last.state === NULL) {
                if (log) logInfo(logPrefix, "Letzte Ausführung unbekannt, Belegung mit Initialwert (-1 Tag)")
                    AutoShading_End_last.postUpdate(now.minusDays(1).toString())
                }

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

            if (timeLastEnde == timeNow) {
                if (log) logInfo(filename, logPrefix + "Beende, da heute bereits ein automatisches Hochfahren stattfand")
                return;
            }

            if (!isActiveWest && !isActiveEast && !isActiveSouth) {
                if (log) logInfo(filename, logPrefix + "Beende, da heute noch keine automatische Verschattung stattfand")
                return;
            }

            if (isTemperature) {
                if (log) logInfo (filename, logPrefix + "Verschattung beenden, Temperaturabfall von min. ({})° erkannt", temperatureHysteresis)
                shadingEnd.apply(gRollladen)
                return;
            }

            if ((Temperature.state as Number).floatValue > (AutoShading_Temp_raise.state as Number)) {
                if (log) logInfo(filename, logPrefix + "Beende, aktuelle Temperatur ({}) überschreitet den eingestellten Grenzwert zum hochfahren von ({}) ",Temperature.state, AutoShading_Temp_raise.state)
                return;
            }

            if (isRainLastHour || isCloudLastHour) {
                if (log) logInfo (filename, logPrefix + "Verschattung beenden, Mindestregenmenge von ({}) mm oder druchschnittliche Bewölkung von ({}) % erreicht",minPrecip, cloudHysteresis)
                shadingEnd.apply(gRollladen)
                return;
            }

            if ((Elevation.state as Number) > (AutoShading_Elevation_end.state as Number)) {
               if (log) logInfo(filename, logPrefix + "Beende, aktuelle Elevation ({}) ueberschreitet den eingestellten Grenzwert von ({}) ", Elevation.state, AutoShading_Elevation_end.state)
               return;
            }

            if (isActiveWest || isActiveEast || isActiveSouth ) {
                if (log) logInfo (filename, logPrefix + "Verschattung beenden")
                shadingEnd.apply(gRollladen)
                return;
            }
        }            
end


/* -------------  Verschattung Variablen zurücksetzen wenn kein automtisches hochfahren erfolgt --------------------
*/

rule "Verschattung Variablen zurücksetzen"
when
        Time cron "15 59 23 * * ?"
then
        if (isActiveWest == true || isActiveEast == true || isActiveSouth == true) {
            isActiveWest = false
            isActiveEast = false
            isActiveSouth = false
        }
end
CYA
Cyrelian

jensilein
Beiträge: 34
Registriert: 24. Feb 2018 09:11
Answers: 0

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

Beitrag von jensilein »

jensilein hat geschrieben: 2. Aug 2019 22:22 Hallo Peter,

ich glaube, ich habe die Lösung gefunden. Die besagten items müssen über MapDB persistiert werden und nicht über InfluxDB, damit sollte es klappen. MapDB und InfluxDB lassen sich parallel betreiben. Ich werde es ausprobieren.
Hallo Peter,

ich habe es ausprobiert. Mit MapDB funktioniert es jetzt einwandfrei. Ich habe MapDB zusätzlich zu InfluxDB installiert und InfluxDB als Standard persistence service belassen, hier also weiter nichts geändert. Die Sollwerte werden jetzt in MapDB persistiert und seitdem gibt es keine Probleme mehr mit den Nachkomma-Stellen 😀👍

VG

Benutzeravatar
PeterA
Beiträge: 1052
Registriert: 8. Feb 2019 12:12
Answers: 13

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

Beitrag von PeterA »

Hallo Jens,

danke fürs Testen! Weiter so!
- OpenHab 2.4
#PWRUP

Antworten