Rollladenautomatik (Sonnenstand und Temperatur)

Einrichtung der openHAB Umgebung und allgemeine Konfigurationsthemen.

Moderatoren: seppy, udo1toni

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

Rollladenautomatik (Sonnenstand und Temperatur)

Beitrag von udo1toni »

Bist Du sicher, dass die 800 ein String ist?

Beziehungsweise: ist OneCallAPIweatherandforecast_Current_Conditionid vom Typ String?

Code: Alles auswählen

 OneCallAPIweatherandforecast_Current_Conditionid.state.toString
würde das sicherstellen. :)

Gesendet von iPad mit Tapatalk
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

int5749
Beiträge: 1161
Registriert: 4. Nov 2019 22:08
Answers: 9

Re: Rollladenautomatik (Sonnenstand und Temperatur)

Beitrag von int5749 »

Mist, wieder vergessen die Items direkt mit zu posten :cry:

Ja, es ist als String angelegt

Code: Alles auswählen

String                  OneCallAPIweatherandforecast_Current_Conditionid                 "Weather Condition Id"
Beim ersten Test sind die Rollladen gar nicht mehr gefahren, das ich die Anführungszeichen vergessen hatte.
openHAB 4.1.0 Release mit openHABian in einem Debian Bookworm (LXC) unter Proxmox 8.1.3

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

Re: Rollladenautomatik (Sonnenstand und Temperatur)

Beitrag von udo1toni »

Ich würde dennoch das .toString ergänzen, um da gar eine Möglichkeit der Fehlinterpretation zuzulassen.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

int5749
Beiträge: 1161
Registriert: 4. Nov 2019 22:08
Answers: 9

Re: Rollladenautomatik (Sonnenstand und Temperatur)

Beitrag von int5749 »

udo1toni hat geschrieben: 21. Jul 2021 17:50 Ich würde dennoch das .toString ergänzen, um da gar eine Möglichkeit der Fehlinterpretation zuzulassen.
Habe ich gemacht, aber leider wieder nix :-/
2021-07-22 08:30:00.186 [INFO ] [rg.openhab.core.model.script.Shutter] - OneCallAPIweatherandforecast_Current_Conditionid: 800
2021-07-22 08:30:00.186 [INFO ] [rg.openhab.core.model.script.Shutter] - tempmax: 24
2021-07-22 08:30:00.201 [INFO ] [rg.openhab.core.model.script.Shutter] - Night: OFF
2021-07-22 08:30:00.201 [INFO ] [rg.openhab.core.model.script.Shutter] - Comfort_Shutter: ON
2021-07-22 08:30:00.201 [INFO ] [rg.openhab.core.model.script.Shutter] - Holiday: OFF
2021-07-22 08:30:00.217 [INFO ] [rg.openhab.core.model.script.Shutter] - Rollladen fahren auf.
openHAB 4.1.0 Release mit openHABian in einem Debian Bookworm (LXC) unter Proxmox 8.1.3

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

Re: Rollladenautomatik (Sonnenstand und Temperatur)

Beitrag von udo1toni »

Ja, Deine Rule hat (nach intensiver Analyse...) ein paar Fehler.

Dabei ist die Komplexität Deiner Bedingungen auch Ausgangspunkt Deiner Probleme. Beispielsweise fragst Du mehrfach auf die gleiche Bedingung ab. Es gibt aber nur eine Stelle, wo das tatsächlich notwendig ist (nämlich innerhalb des Timers, weil dieser Code losgelöst von der Rule betrachtet werden muss).

Auch die Reihenfolge der Befehle in Deiner Rule ist unglücklich gewählt. Dadurch kommt es beispielsweise zu mehreren Meldungen, falls mehrere Randbedingungen nicht erfüllt sind.
Außerdem muss der gesamte Rulecode abgearbeitet werden. Und wie gesagt, diverse Bedingungen müssen mehrfach abgefragt werden.

Dadurch hat sich auch ein grundlegender Logikfehler eingeschlichen, nämlich hier:

Code: Alles auswählen

if (Night.state == OFF && Comfort_Shutter.state == ON && Holiday.state == OFF && (tempmax < 20 || (tempmax >= 20 && (OneCallAPIweatherandforecast_Current_Conditionid.state != "800" || OneCallAPIweatherandforecast_Current_Conditionid.state  != "801")))) {
Wenn wir mal die ersten drei Bedingungen weg lassen, bleibt

Code: Alles auswählen

if (tempmax < 20 || (tempmax >= 20 && (OneCallAPIweatherandforecast_Current_Conditionid.state != "800" || OneCallAPIweatherandforecast_Current_Conditionid.state  != "801"))) {
Stattdessen kannst Du aber auch

Code: Alles auswählen

if(true)
schreiben.
Entweder, die Bedingung ist wahr, weil tempmax < 20 ist. Oder tempmax >= 20 und eine der beiden nachfolgenden Bedinguen ist nicht(!!!) erfüllt. Da aber immer maximal eine der beiden Bedingungen erfüllt sein kann, ist dieser Teil immer true, womit der Rest des Bool'schen Terms ebenfalls immer true ist.

Besser ist es also, solche komplexen Abfragen in kleinere Einheiten zu zerlegen.
statt

Code: Alles auswählen

if(tempmax >= 20 && (OneCallAPIweatherandforecast_Current_Conditionid.state != "800" || OneCallAPIweatherandforecast_Current_Conditionid.state  != "801")))
besser

Code: Alles auswählen

var Boolean bCondition = false                             // default: falsch
if(strCondition == "800") bCondition = true                // falls Condition 800 
if(strCondition == "801") bCondition = true                // oder 801 -> true
if(tempmax < 20) bCondition = false                        // falls Temperatur < 20 false

if(!bCondition)) {                                         // falls false
wobei strCondition den Status des entsprechenden Items als String enthält.

Dies wäre die umgemodelte Rule:

Code: Alles auswählen

var Integer tempmax = 0

rule Rollladen_Task
when
    Time cron "0 30 08 ? * MON-SAT" or
    Time cron "0 00 09 ? * SUN"
then
    val mailActions = getActions("mail","mail:smtp:h478579470")
    tempmax = (Weather_Temp_Max_0.state as DecimalType).intValue
    val String strCondition = OneCallAPIweatherandforecast_Current_Conditionid.state.toString    // schon wegen der Länge des Itemnamens...

    logInfo("Shutter", "Comfort_Shutter: {}", Comfort_Shutter.state) 
    logInfo("Shutter", "Holiday: {}", Holiday.state)
    logInfo("Shutter", "Night: {}", Night.state)
    logInfo("Shutter", "tempmax: {}", tempmax)
    logInfo("Shutter", "OneCallAPIweatherandforecast_Current_Conditionid: {}", strCondition)

    if(Comfort_Shutter.state != ON) {                              // Automatik ist ausgeschaltet
        mailActions.sendMail("abcdefghijklmnop@api.prowlapp.com", "Komfortfunktion aus: " + OffsetDateTime.now().toString, "Rollladen bleiben unten.")
        return;
    }
    if (Holiday.state == ON) {                                     // Ferien
        mailActions.sendMail("abcdefghijklmnop@api.prowlapp.com", "" + SpecialDay + ": " + OffsetDateTime.now().toString, "Rollladen bleiben unten.")
        return;
    }

    if (Night.state != ON) {                                       // Es ist Tag
                                                                   // anders gestaltete Logik:
        var Boolean bCondition = false                             // default: falsch
        if(strCondition == "800") bCondition = true                // falls Condition 800 
        if(strCondition == "801") bCondition = true                // oder 801 -> true
        if(tempmax < 20) bCondition = false                        // falls Temperatur < 20 false

        if(!bCondition) {                                          // falls false
            logInfo("Shutter", "Rollladen fahren auf.")
            mailActions.sendMail("abcdefghijklmnop@api.prowlapp.com", ""+ tempmax + " Grad: " + OffsetDateTime.now().toString, "Rollladen fahren auf.")
            Rollladen.allMembers.filter(f|(f.state as Number).intValue != 0).forEach[ s|
                s.sendCommand(UP)
                logInfo("Shutter", s.name + " received UP")
            ]
            Lampe_Treppe.sendCommand(OFF)
        } else {                                                   // Temperatur >= 20 und (800 oder 801)
            SunProtection.postUpdate(ON)
        }
    } else {                                                       // es ist Nacht
        mailActions.sendMail("abcdefghijklmnop@api.prowlapp.com", "Information: " + OffsetDateTime.now().toString, "Es ist noch Nacht, Rollladen bleiben unten.")
        if (t_night !== null) {                                    // Timer läuft bereits
            return;
        }
        t_night = createTimer(now.plusMinutes(10), [ |
            if (Night.state == ON) {                               // es ist weiterhin Nacht
                mailActions.sendMail("abcdefghijklmnop@api.prowlapp.com", "Information: " + OffsetDateTime.now().toString, "Es ist immer noch Nacht, Rollladen bleiben unten.")
                t_night.reschedule(now.plusMinutes(10))
            } else {                                               // es ist nun Tag
                mailActions.sendMail("abcdefghijklmnop@api.prowlapp.com", "Information: " + OffsetDateTime.now().toString, "Rollladen fahren auf")
                Rollladen.allMembers.filter(f|(f.state as Number).intValue != 0).forEach[ s|
                    s.sendCommand(UP)
                    logInfo("Shutter", s.name + " received UP")
                ]
                Lampe_Treppe.sendCommand(OFF)
                t_night = null
            }
        ])
    }
end
Die Abbruchbedingungen sind nach oben gewandert. Dadurch wird nur diejenige Bedingung ausgegeben, die als erste nicht zutrifft. Wenn also Ferien sind und die Automatik ausgeschaltet ist, kommt nur die Meldung wegen der abgeschalteten Automatik, das ist aber in meinen Augen auch sinnvoller.

Noch ein Wort zu !== ... (oder doch ein paar Worte...)

a == b -> a entspricht b, bzw. a ist gleich b
a != b -> a ist ungleich b
a === b -> a ist identisch b
a !== b -> a ist nicht identisch b

Umgangssprachlich (aber korrekt im Sinne der alten Definition): a === b -> a ist dasselbe wie b (Man kann nicht dasselbe Ei zweimal essen)

Der Vergleich auf Identität ist nur an einer stelle sinnvoll, nämlich, wenn es um den Vergleich mit null geht (bitte nicht mit NULL verwechseln!) null ist ein Zeiger auf eine ganz bestimmte Speicherzelle. Wenn eine Variable null enthält, dann wird der Zeiger der Rule auf eben diese Speicherstelle verbogen, womit die Variable identisch mit null ist (sie zeigt auf dieselbe(!) Speicherzelle.
Dieser Vergleich des Zeigers ist aber ausschließlich bei null sinnvoll (jedenfalls wenn es um openHAB geht...) Schon wenn es um Zahlen geht:

Code: Alles auswählen

var Number a = 5
if(a === 5)
    logInfo("test","a ist identisch mit 5!")
else if (a == 5)
    logInfo("test","a ist gleich 5!")
Dieser Code wird als Ausgabe nur die zweite Logzeile ausgeben, weil a eben nicht identisch mit 5 ist.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

int5749
Beiträge: 1161
Registriert: 4. Nov 2019 22:08
Answers: 9

Re: Rollladenautomatik (Sonnenstand und Temperatur)

Beitrag von int5749 »

udo1toni hat geschrieben: 22. Jul 2021 22:47 Ja, Deine Rule hat (nach intensiver Analyse...) ein paar Fehler.
Ich hatte es ja befürchtet, bin aber nicht auf den Fehler gekommen
udo1toni hat geschrieben: 22. Jul 2021 22:47 Dies wäre die umgemodelte Rule:
DANKE, habe ich so eingebaut. Evtl. magst Du oben den Post noch einmal editieren, falls sich den jemand kopieren möchte.
udo1toni hat geschrieben: 22. Jul 2021 22:47 if(!bCondition)) { // falls false
Hier hat sich eine zweite ")" eingeschlichen ;-)

An dieser Stelle noch und gerne zum wiederholten Male einen Riesendank für Deinen Einsatz und die Unterstützung. Nicht nur, dass Du Dir die Zeit nimmst darüber zu schauen, sondern auch direkt eine Lösung erstellst/codest und als Doppel i-Tüpfelchen auch noch erklärst und Hintergrund Info's lieferst! Chapeau !!!!

Morgen Früh werde ich dann sehen und berichten, was passiert ist :)
openHAB 4.1.0 Release mit openHABian in einem Debian Bookworm (LXC) unter Proxmox 8.1.3

int5749
Beiträge: 1161
Registriert: 4. Nov 2019 22:08
Answers: 9

Re: Rollladenautomatik (Sonnenstand und Temperatur)

Beitrag von int5749 »

Halo Udo,

ich habe da noch einmal über Deine Erklärung sinniert und doch noch eine Frage/ein Verständnisproblem
udo1toni hat geschrieben: 22. Jul 2021 22:47 Wenn wir mal die ersten drei Bedingungen weg lassen, bleibt

Code: Alles auswählen

if (tempmax < 20 || (tempmax >= 20 && (OneCallAPIweatherandforecast_Current_Conditionid.state != "800" || OneCallAPIweatherandforecast_Current_Conditionid.state  != "801"))) {
Stattdessen kannst Du aber auch

Code: Alles auswählen

if(true)
schreiben.
Entweder, die Bedingung ist wahr, weil tempmax < 20 ist. Oder tempmax >= 20 und eine der beiden nachfolgenden Bedinguen ist nicht(!!!) erfüllt. Da aber immer maximal eine der beiden Bedingungen erfüllt sein kann, ist dieser Teil immer true, womit der Rest des Bool'schen Terms ebenfalls immer true ist.
Ich kürze für die Diskussion hier mal OneCallAPIweatherandforecast_Current_Conditionid auf Conditionid (wegen der Länge :) )

Wenn aber doch tempmax >= 20 und Conditionid == 800 oder 801 müsste dieser Teil doch false sein wenn die Conditionid z.B: 799 oder 802 oder so ist? Und erst die folgende Abfrage auf 800/801 müsste true sein?

Ungenommen finde ich Deine Rule deutlich smarter und ich sollte mir das dringlichst angewöhnen Regeln beim eintreffen von Abfragen auch abzubrechen.
Dennoch verstehe ich derzeit noch nicht genau, wo der Fehler lag :-/

Viele Grüße
openHAB 4.1.0 Release mit openHABian in einem Debian Bookworm (LXC) unter Proxmox 8.1.3

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

Re: Rollladenautomatik (Sonnenstand und Temperatur)

Beitrag von udo1toni »

int5749 hat geschrieben: 23. Jul 2021 16:03 Wenn aber doch tempmax >= 20 und Conditionid == 800 oder 801 müsste dieser Teil doch false sein wenn die Conditionid z.B: 799 oder 802 oder so ist? Und erst die folgende Abfrage auf 800/801 müsste true sein?
Es geht um die Condition

Code: Alles auswählen

OneCallAPIweatherandforecast_Current_Conditionid.state != "800" || OneCallAPIweatherandforecast_Current_Conditionid.state  != "801"
Was bedeutet: eine der beiden Bedingungen muss erfüllt sein (|| -> logisches ODER)
Entweder a != "800" oder a != "801"
!= bedeutet: Ist NICHT gleich.
Also Entweder a ist ungleich "800" oder a ist ungleich "801".
Wenn a gleich 800 ist, dann ist es ungleich 801.
Wenn a gleich 801 ist, ist es ungleich 800.
Wenn es einen anderen Wert unter 800 oder über 801 hat, dann sind halt beide Bedingungen erfüllt (a ist ungleich 800 und a ist ungleich 801)
|| bedeutet aber, das mindestens eine der beiden Bedingungen erfüllt sein muss. Das ist immer der Fall.

Der Fehler ist halt das || im Zusammenhang mit !=, Du hättest stattdessen auch ein && setzen können:

Code: Alles auswählen

if(a != 800 && a!= 801)
Wahr, wenn a weder 800 noch 801 ist.

Die überzählige Klammer habe ich entfernt :) Danke für den Hinweis. Ich habe meist keinen VSCode direkt zur Hand...
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

int5749
Beiträge: 1161
Registriert: 4. Nov 2019 22:08
Answers: 9

Re: Rollladenautomatik (SonnenWstand und Temperatur)

Beitrag von int5749 »

Works like a charm 8-)

Code: Alles auswählen

2021-07-24 08:30:03.710 [INFO ] [rg.openhab.core.model.script.Shutter] - Comfort_Shutter: ON
2021-07-24 08:30:03.725 [INFO ] [rg.openhab.core.model.script.Shutter] - Holiday: OFF
2021-07-24 08:30:03.725 [INFO ] [rg.openhab.core.model.script.Shutter] - Night: OFF
2021-07-24 08:30:03.725 [INFO ] [rg.openhab.core.model.script.Shutter] - tempmax: 25
2021-07-24 08:30:03.725 [INFO ] [rg.openhab.core.model.script.Shutter] - OneCallAPIweatherandforecast_Current_Conditionid: 800
2021-07-24 08:34:05.410 [INFO ] [rg.openhab.core.model.script.Shutter] - Flur_Rollo received Höhe 55
2021-07-24 08:34:05.425 [INFO ] [rg.openhab.core.model.script.Shutter] - Kueche_rechts_Rollo received Höhe 55
openHAB 4.1.0 Release mit openHABian in einem Debian Bookworm (LXC) unter Proxmox 8.1.3

Antworten