PV Überschuss Regel wird nach einer Zeit nicht mehr getriggert

Einrichtung der openHAB Umgebung und allgemeine Konfigurationsthemen.

Moderatoren: seppy, udo1toni

Antworten
Mic91
Beiträge: 15
Registriert: 15. Jan 2021 21:48
Answers: 0

PV Überschuss Regel wird nach einer Zeit nicht mehr getriggert

Beitrag von Mic91 »

Hallo,

ich habe folgende Rule erstellt. Diese funktioniert auch. Aber nach einer Zeit X >einige Stunden bis Tage wird diese Rule nicht mehr getriggert. Im Log über den Port 9001 wird nichts angezeigt. Normal kommt alle paar Sekunden die Meldung: "PV-Rule", "Rule Routine gestartet" aber das kommt irgendwann nicht mehr.

Installiert ist das auf einem Raspberry 4 mit 2 GB RAM. Installiert ist Openhab 4.1.2.

Wenn ich lokal per Visual Studio die Rule neu speichere läuft Sie erstmal wieder und wird auch ohne Fehler im Log "eingelesen"
Der Pi steht bei meinen Eltern. Ich kann mich in das Netz nicht per VPN einloggen. Aber ich habe myopenhab eingerichtet und würde auch online sehen ob die Ausgänge vom Shelly geschaltet werden. Kann ich mich mit Visual Studio Code auch ohne vpn über myopenhab.org auf den Pi wählen?

Danbke für eure Hilfe

Gruß Michael

Code: Alles auswählen

var Timer tPV = null
var rulestate = 0


rule "PV steuert Relais"
when
        Item solaxFeedInPower received update
then
        if (rulestate == 0 && Automatikmodus.state == ON){
            logInfo( "PV-Rule", "Rule Routine gestartet")
            if (solaxFeedInPower.state > 975) {
                logInfo( "PV-Rule", "Einspeisung >975W Timer 30 sek gestartet")
                rulestate = 1
                tPV = createTimer(now.plusSeconds(30), [|
                    if (solaxFeedInPower.state > 975 && shellymqttitema.state == "false"){
                        logInfo( "PV-Rule", "Relais 1 wird angeschaltet, Rule beendet")
                        ShellyPro3_Out1.sendCommand(ON)
                        rulestate = 0
                        tPV.cancel
                        return
                    }
                    if (solaxFeedInPower.state > 975 && shellymqttitema.state == "true" && shellymqttitemb.state == "false"){
                        logInfo( "PV-Rule", "Relais 2 wird angeschaltet, Rule beendet")
                        ShellyPro3_Out2.sendCommand(ON)
                        rulestate = 0
                        tPV.cancel
                        return
                    }
                    if (solaxFeedInPower.state > 975 && shellymqttitemb.state == "true"){
                        logInfo( "PV-Rule", "Relais 3 wird angeschaltet, Rule beendet")
                        ShellyPro3_Out3.sendCommand(ON)
                        rulestate = 0
                        tPV.cancel
                        return
                    }
                ])
            }
            if (solaxFeedInPower.state < 0) {
                logInfo( "PV-Rule", "Einspeisung <0W Timer 30 sek gestartet")
                rulestate = 1
                tPV = createTimer(now.plusSeconds(30), [|
                    if (solaxFeedInPower.state < 0 && shellymqttitemc.state == "true"){
                        logInfo( "PV-Rule", "Relais 3 wird ausgeschalten, Rule beendet")
                        ShellyPro3_Out3.sendCommand(OFF)
                        rulestate = 0
                        tPV.cancel
                        return
                    }
                    if (solaxFeedInPower.state < 0 && shellymqttitemb.state == "true"){
                        logInfo( "PV-Rule", "Relais 2 wird ausgeschalten, Rule beendet")
                        ShellyPro3_Out2.sendCommand(OFF)
                        rulestate = 0
                        tPV.cancel
                        return
                    }
                    if (solaxFeedInPower.state < 0 && shellymqttitema.state == "true"){
                        logInfo( "PV-Rule", "Relais 1 wird ausgeschalten, Rule beendet")
                        ShellyPro3_Out1.sendCommand(OFF)
                        rulestate = 0
                        tPV.cancel
                        return
                    }
                    else {
                        logInfo( "PV-Rule", "Einspeisung nicht mehr über 1000W")
                        rulestate = 0
                        tPV.cancel
                        return
                    }
                    
                ])
            }
        }
end
        

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

Re: PV Überschuss Regel wird nach einer Zeit nicht mehr getriggert

Beitrag von udo1toni »

Die Rule hat etliche Fehler, manche kleiner, manche größer :) wobei die meisten Wiederholungsfehler sind.
Die erste Frage ist aber: Was soll die Rule tatsächlich tun?
Meine Vermutung: Du möchtest die drei Relais einschalten, sofern mehr als 975 Watt eingespeist werden, allerdings sollten diese 975 Watt mindestens 30 Sekunden anstehen.
In der Gegenrichtung das gleiche, sobald die Einspeisung unter 0 sinkt, sollen nacheinander die drei Relais ausgeschaltet werden, aber eben erst nach 30 Sekunden.
Und hier kommt der erste Fehler: So, wie die Rule aufgebaut ist, misst Du exakt zweimal den Wert - bevor der Timer startet und nachdem der Timer abgelaufen ist. Besser wäre es, den Timer abzubrechen, sobald der auslösende Wert nicht mehr erreicht wird.

Weiterhin triggert die Rule mit received update, was eigentlich unnötig ist. Besser wäre changed, denn es geht um Werteänderungen.

Das Konstrukt mit der rulestate Variablen ist in dieser Form unnütz, Du verhinderst mit dieser Variablen ja lediglich, dass bei laufendem Timer ein weiterer Timer angelegt wird. Das geht wesentlich eleganter mithilfe der Timer Variablen.

Ein weiterer Fehler: return erfordert zwingend ein Semikolon am Ende. Der Grund hierfür: return liefert an die übergebende Routine einen Rückgabewert. Dieser wird nach return angegeben. Ohne Rückgabewert wertet der Parser also den nächsten Befehl als Rückgabewert. Gibt man einen Rückgabewert an, so weiß openHAB nicht, an welchen Prozess es den Rückgabewert senden soll, man muss also einen null-Wert setzen, das geschieht mit dem ;
Eventuell kommt es dennoch nicht zu einem Fehler, weil der Befehl als letztes in einem Block steht, es ist aber definitiv falsch.

Die bessere Rule:

Code: Alles auswählen

var Timer tPV = null

rule "PV steuert Relais"
when
    Item solaxFeedInPower changed
then
    logDebug( "pv", "Rule gestartet")

    if(Automatikmodus.state != ON) {                                                         // Automatikmodus aus?
        logDebug("pv","Automatik aus, Abbruch")
        return;                                                                              // dann Rule abbrechen
    }
    if(tPV !== null) {                                                                       // Timer läuft?
        logDebug("pv","Timer läuft bereits")
        if((previousState < 0 && newState > 0) || (previousState > 975 && newState < 975)) { // Schwellwert über-/unterschritten?
            logDebug("pv","Grenzwert nicht mehr erreicht. Breche Timer ab")
            tPV.cancel                                                                       // dann Timer abbrechen
            tPV = null                                                                       // und Zeiger löschen
        } else {                                                                             // Timer läuft weiter,
            logDebug("pv","Grenzwert weiterhin erreicht. Breche Rule ab (Timer läuft weiter)")
            return;                                                                          // also Abbruch
        }
    }
    if(newState < 975 && newState > 0) {                                                     // Grenzwert nicht erreicht?
        logDebug("pv","Grenzwert nicht erreicht. Abbruch")
        return;                                                                              // dann Abbruch
    }
    logInfo( "pv", "Einspeisung {} W -> starte 30 sek. Timer",(newState as Number).intValue)
    tPV = createTimer(now.plusSeconds(30), [|                                                // Timer anlegen
        if(solaxFeedInPower.state > 975) {                                                   // oberer Grenzwert überschritten?
            if(shellymqttitema.state == "false") {                                           // falls Relais 1 aus
                logInfo( "pv", "Relais 1 wird angeschaltet") 
                ShellyPro3_Out1.sendCommand(ON)                                              // einschalten
            } else if(shellymqttitemb.state == "false") {                                    // ansonsten, falls Relais 2 aus
                logInfo( "pv", "Relais 2 wird angeschaltet")
                ShellyPro3_Out2.sendCommand(ON)                                              // einschalten
            } else if(shellymqttitemc.state == "false") {                                    // ansonsten, falls Relais 3 aus
                logInfo( "pv", "Relais 3 wird angeschaltet")
                ShellyPro3_Out3.sendCommand(ON)                                              // anschalten
            } else                                                                           // es sind bereits alle Relais an
                logDebug( "pv", "Alle Relais sind bereits aktiv!")
        } else {                                                                             // ansonsten (unterer Grenzwert unterschritten)
            if(shellymqttitemc.state == "true") {                                            // Falls Relais 3 an
                logInfo( "pv", "Relais 3 wird ausgeschaltet")
                ShellyPro3_Out3.sendCommand(OFF)                                             // ausschalten
            } else if(shellymqttitemb.state == "true") {                                     // ansonsten, falls Relais 2 an
                logInfo( "pv", "Relais 2 wird ausgeschaltet")
                ShellyPro3_Out2.sendCommand(OFF)                                             // ausschalten
            } else if(&& shellymqttitema.state == "true") {                                  // ansonsten, falls Relais 1 an
                logInfo( "pv", "Relais 1 wird ausgeschaltet")
                ShellyPro3_Out1.sendCommand(OFF)                                             // ausschalten
            } else                                                                           // es sind bereits alle Relais aus
                logDebug( "pv", "Alle Relais sind bereits ausgeschaltet!")
        }
        logDebug("pv","Timer beendet")
        tPV = null
    ])
end
Die Debug Meldungen bekommst Du nur zu Gesicht, wenn Du das Logging für die Rule mindestens auf DEBUG setzt. Das geht über die Karaf Konsole:

Code: Alles auswählen

log:set DEBUG org.openhab.core.model.script.pv
Und genauso kannst Du die Meldungen auch loswerden, indem Du bei dem Befehl das DEBUG gegen INFO oder WARN ersetzt (WARN unterdrückt dann auch die logInfo() Befehle)

Die Logik hinter der Rule:
Die Rule triggert bei jeder Wertänderung
Ist die Automatik abgeschaltet, so wird die Rule sofort abgebrochen.
Läuft der Timer bereits, wird über previousState und newState geprüft, ob der Wert seit der letzten Änderung den auslösenden Grenzwert durchschritten hat (also von über 975 auf unter 975, bzw. von unter 0 auf über 0). Ist das der Fall, so muss der Timer abgebrochen werden.
Anschließend kann die Rule aber evtl. sofort einen neuen Timer anlegen, immerhin kann die Einspeisung auch direkt von > 975 auf < 0 wechseln und umgekehrt.
Wurde der Grenzwert nicht durchschritten, muss die Rule nichts weiter tun, denn der Timer läuft ja noch.
Falls der Timer nicht (mehr) läuft, muss nun geprüft werden, ob einer der Grenzwerte überschritten wurde. Ist das der Fall, so wird der Timer erzeugt und die Rule ist fertig.

Im Timer selbst können wir uns nun darauf beschränken, zu unterscheiden, ob der obere Grenzwert überschritten, oder der untere Grenzwert unterschritten ist. In jedem anderen Fall wurde der Timer ja bereits gecancelt :)
Ist der obere Grenzwert überschritten, werden nacheinander die Relais 1-3 geprüft. Das erste, welches nicht eingeschaltet ist, wird eingeschaltet.
Ist der untere Grenzwert unterschritten, werden nacheinander die Relais 3-1 geprüft. Das erste, welches nicht ausgeschaltet ist, wird ausgeschaltet.
Abschließend wird der Zeiger auf den Timer gelöscht, damit der Timer erneut angelegt werden kann.

Mögliche Fehlerquellen: previousState und/oder newState sind nicht vom Typ Number. Für previousState wird das regelhaft nach einem Neustart von openHAB geschehen, weil solaxFeedInPower nach dem Neustart den Status NULL hat. Zugleich wird previousState aber nur verwendet, wenn der Timer bereits läuft. Das heißt, es muss bereits mehr als eine Änderung seit Systemstart stattgefunden haben.
Die einzige Situation, in der wegen eines ungültigen Wertes in den beiden impliziten Variablen eine nullPointerException auftreten könnte, wäre deshalb, wenn solaxFeedInPower einen fehlerhaften Messwert NULL liefert. Das war jedoch bei Deiner Rule nicht anders :)

Ein weiterer Punkt: Du hast pro Relais zwei Items. Es gibt dafür keinen vernünftigen Grund. Allenfalls könnte ich mir vorstellen, dass Du es nicht hinbekommen hast, das korrekt zu konfigurieren :) was keine Sünde ist :)
Ich habe selbst die ShellyPro3 im Einsatz, allerdings habe ich meine direkt nach dem Auspacken mit Tasmota geflasht :) weshalb ich mir den Rotz mit den verqueren Topics komplett sparen konnte. Der Punkt ist aber: man kann es so drehen, dass man nur einen Thing Channel pro Geräte Channel benötigt, der dann in beide Richtungen normal mit einem Switch Item funktioniert. Das sähe in der Rule dann z.B. so aus:

Code: Alles auswählen

    if(ShellyPro3_Out1.state != ON)
        ShellyPro3_Out1.sendCommand(ON)
was wesentlich besser zu verstehen wäre.
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

Mic91
Beiträge: 15
Registriert: 15. Jan 2021 21:48
Answers: 0

Re: PV Überschuss Regel wird nach einer Zeit nicht mehr getriggert

Beitrag von Mic91 »

Hallo udo1toni,

Dafür das du mich nicht kennst, konntest du viel über mich sagen ;-)

Spaß beiseite.

Ähm also was soll ich sagen... Das ich so falsch liege ist schon bitter...

Ich habe das gleich ausprobiert. Es wird vom System angenommen, bis auf

Code: Alles auswählen

Configuration model 'PV.rules' has errors, therefore ignoring it: [49,23]: no viable alternative at input '&&'
Ich habe die beiden && Zeichen entfernt. Was bedeuten diese?

Ich wollte das Shelly ursprünglich auch mit Tasmota flashen aber ich habe mir gedacht wenn das Gerät mal kaputt kann eigentlich jeder das Shelly tauschen ohne das Tasmota drauf ist. Aber das werde ich evtl. nach ändern.

Die beiden Items für das Shelly haben den Hintergrund, dass ich warum auch immer den Status nie auslesen konnte deshalb habe ich mit den aktuellen Status mit zusätzlich über MQTT geholt vom Shelly ist zwar total verrückt aber ich habe mir einfach ein workaround geschaffen. Weil ich mir nicht anders helfen konnte.

Wegen dem Thema mit dennullPointerExecption. Wenn einmal ein Null kommt und danach wieder normale Werte. Wird die Regel trotzdem ausgeführt?

Gruß Michael

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

Re: PV Überschuss Regel wird nach einer Zeit nicht mehr getriggert

Beitrag von udo1toni »

Mic91 hat geschrieben: 5. Aug 2024 22:13 Ähm also was soll ich sagen... Das ich so falsch liege ist schon bitter...
Mach Dir keinen Kopf, die Steuerung ist schon etwas komplexer (und ich nutze openHAB nun schon seit mehr als einem Jahrzehnt, habe also evtl. "etwas" Vorsprung).
Mic91 hat geschrieben: 5. Aug 2024 22:13 Ich habe die beiden && Zeichen entfernt. Was bedeuten diese?
Die habe ich an dieser Stelle übersehen :lol: ich hatte ja den größten Teil Deines Codes jeweils kopiert, und Du hattest immer zwei Bedingungen pro if() verwendet. Das && ist das logische UND, das || ist das logische ODER. Keine meiner hier eingefügten Rules funktioniert auf Anhieb, es sei denn, ich habe sie bei mir testweise laufen lassen, weil ich immer irgendwo einen Tippfehler oder ein falsches Copy&Paste drin habe...
Mic91 hat geschrieben: 5. Aug 2024 22:13 Ich wollte das Shelly ursprünglich auch mit Tasmota flashen aber ich habe mir gedacht wenn das Gerät mal kaputt kann eigentlich jeder das Shelly tauschen ohne das Tasmota drauf ist. Aber das werde ich evtl. nach ändern.
Kein Ding, grundsätzlich funktioniert es ja, nur sollte die Rückmeldung auf jeden Fall funktionieren, auch (bzw. gerade) mit dem Shelly Binding alleine.
Möglicher Workaround: Du sorgst dafür, dass der mqtt Channel statt true und false korrekt ON und OFF ausgibt (auf switch Channel umstellen, on=true und off=false setzen, Rest sollte schon passen). Anschließend kannst Du einfach beide Channel mit dem selben(!) Switch Item verlinken, dann wird der Status des Items eben über mqtt gesetzt. Aber eigentlich sollte der Status auch vom Shelly Binding direkt kommen... :?

Rant:
Ich habe eine starke Abneigung gegen die aktuelle Shelly API (bzw. die Umsetzung auf mqtt), weil das in V1 API so schön war, und seit V2 ist es eine einzige Katastrophe, ohne dass man dadurch irgendeinen Benefit hätte. Und ich denke nicht, dass die Techniker bei Shelly die Tasmota Firmware nicht kennen, die läuft buchstäblich auf Millionen Geräten und auch auf einem Gutteil der Shelly Produkte. Das heißt, sie könnten die Schnittstelle notfalls abkupfern, um etwas Sinnvolles einzubauen, sie haben sich aber bewusst dagegen entschieden, halten damit zwar die Möglichkeit offen, mqtt zu nutzen, machen es dem Anwender aber möglichst schwer. Angeblich soll man die Geräte doch ohne Cloud nutzen können?!?
Rant Ende :)

Die Rule wird immer ausgeführt. Da aber keine Prüfung auf instanceof Number eingebaut ist, wird die Ausführung scheitern, wenn zwischendurch NULL-Werte auftreten.
Möglichkeit eins: Du sorgst dafür, dass immer gültige Werte anliegen :) (direkt im Quellitem einen entsprechenden Filter vorsehen).
Möglichkeit zwei: Du baust vorne in der Rule zusätzliche Zeilen ein, bevor newState bzw. previousState verwendet werden (also unmittelbar nach dem Block, der sich um den Automatikmodus kümmert):

Code: Alles auswählen

if(!(previousState instanceof Number)) {
    logWarn("pv","alter Wert ist keine gültige Zahl! Abbruch")
    return;
}
if(!(newState instanceof Number)) {
    logWarn("pv","neuer Wert ist keine gültige Zahl! Abbruch")
    return;
}
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

Mic91
Beiträge: 15
Registriert: 15. Jan 2021 21:48
Answers: 0

Re: PV Überschuss Regel wird nach einer Zeit nicht mehr getriggert

Beitrag von Mic91 »

Ich füge das alles zusammen und probiere das mal.

Danke!

Antworten