winni hat geschrieben: ↑10. Apr 2021 23:14
Kannst DU evtl. mal deine ganze Rule zur Verfügung stellen?
Trotz der Änderungen habe ich das Problem, dass die Rule nach 5 min wieder startet, ich eine Pushnachricht bekomme und wieder ein Kommand an meine Rolladen geschickt wird obwohl die Rule schon einmal gelaufen ist. Ich vermute, dass es immer noch an meinem Datetime item liegt. In OH 2 hat lief die Rule ohne Probleme.
Den letzten Satz kann ich so nicht glauben.
Dein Problem ist, dass Du in der letzten Zeile den Datumsstempel auf den Vortag setzt (minusDays(1)) womit dann die Abbruchbedingung nicht mehr wirken kann.
Insgesamt schreit diese Rule nach Codeumstellungen. Statt
Code: Alles auswählen
if(bla) {
// do something
} else {
// do nothing but a log
}
kannst Du schreiben
Code: Alles auswählen
if(!bla) {
// do nothing but a log
return;
}
// do something
also mit konkretem Code, statt:
Code: Alles auswählen
if (RolloautomatikSued.state == ON) {
[...]
} else {
if (log) logInfo('rules', logPrefix + 'Beende, da Automatik generell nicht aktiv')
}
schreibst Du
Code: Alles auswählen
if (RolloautomatikSued.state != ON) {
if (log) logInfo('rules', logPrefix + 'Beende, da Automatik generell nicht aktiv')
return;
}
[...]
Damit werden die Indentations Deiner Rule extrem verringert.
return; bricht die laufende Rule unmittelbar ab. Das ; am Ende ist in diesem Fall wichtig, da return gewöhnlich einen Rückgabewert liefert, der aber von der DSL nicht ausgegeben werden kann.
Weiterhin weise ich immer wieder gerne darauf hin, dass das Konstrukt
if(log) logInfo() kompletter Bullshit ist.
Der in openHAB integrierte Logger ist extrem mächtig. Man kann mit Leichtigkeit die Ausgabe der Logmeldungen im laufenden Betrieb(!) ein- und ausschalten - im Gegensatz zum Konstrukt mit der globalen boolean Variable, die nur mit Umwegen im laufenden Betrieb verändert werden kann
(indem man sie per Rule umschaltet)
Im Gegensatz zur globalen Variable ist es auch kein Problem, gezielt nur bestimmte Logmeldungen zu (de-)aktivieren.
Es gibt zum einen verschiedene Log Level (Debug, Info, Warn, Error, gelistet in ansteigender Reihenfolge der Wichtigkeit), zum anderen gibt es beliebig viele Logger. Dabei hat jeder Logger einen Namen, der in den Logbefehlen (z.B. logInfo()) als erster String angegeben werden muss. Statt dort also ein nichtssagendes
rules hin zu schreiben, wäre es sinnvoller, einen kurzen Namen zu setzen und diesen innerhalb der Rule (oder der Gruppe von Rules) beizubehalten, im vorliegenden Fall z.B.
autoShutter. Alle Logbefehle in der Rules DSL sind hierarchisch unterhalb des Loggers
org.openhab.core.automation.module.script. angesiedelt, der vollständige Loggername wäre in diesem Fall also
org.openhab.core.automation.module.script.autoShutter. Mit diesem Namen lässt sich das Logging dann gezielt ein- und ausschalten.
Die Logbefehle beherrschen Substitution, das heißt, sie können einen entsprechend vorbereiteten String mit Variablen ergänzen. Statt
Code: Alles auswählen
logInfo('rules', logPrefix + 'Azimuth (' + LokaleSonnendaten_Azimut.state.toString() + ') hat noch nicht Schwellwert (' + rolloautomatik_azimuth_start.state.toString() + ') erreicht')
kann man einfach
Code: Alles auswählen
logInfo('rules', logPrefix + 'Azimuth ({}) hat noch nicht Schwellwert ({}) erreicht', LokaleSonnendaten_Azimut.state,rolloautomatik_azimuth_start.state)
schreiben. Um die Typwandlung kümmert sich die Substitution automatisch (bei Float Werten könnte es allerdings sein, dass man die Anzahl der Kommastellen begrenzen möchte).
Du hast an verschiedenen Stellen absurde Konstrukte in Deiner Rule, Integer::parseInt(RolloAutomatikZielwert.state.toString()) Ernsthaft? Du wandelst einen Status eines Number Items in einen String, um ihn anschließend nach Integer parsen zu lassen?
Weiterhin werden immer beide Rules zeitgleich ausgeführt, obwohl sie unterschiedliche Trigger verwenden. Da gäbe es sicher noch Verbesserungspotential. Die Idee, einen Datumsstempel zu verwenden, um zu entscheiden, ob die Rule bereits gelaufen ist, ist ok, ich vermute mal, Du stellst diese Information in der UI dar? Ansonsten wäre ein einfacherer Ansatz, eine globale Boolean Variable dafür zu nutzen. Diese wird dann um Mitternacht auf false gesetzt und bei Verschattung bzw. bei Aufhebung der Verschattung auf true . Damit sparst Du Dir eine Menge Codebalast. Einen Datumsstempel kannst Du dennoch verwenden, dann halt nur für die Anzeige.
Hier mal Deine Rules mit eingearbeiteten Änderungen (nicht getestet)
Code: Alles auswählen
var Boolean bShadeStart = false
var Boolean bShadeEnd = false
rule "reset some vars"
when
Time is midnight
then
bShadeStart = false
bShadeEnd = false
end
rule "Rollos Süd abfahren"
when
Item LokaleSonnendaten_Azimut changed
then
logDebug('autoShutter', 'Regel (Rollo Süd runter) wurde gestartet')
if(RolloautomatikSued.state != ON) {
logDebug('autoShutter', 'Beende, da Automatik generell nicht aktiv')
return;
}
if(bShadeStart) {
logDebug('autoShutter', 'Automatik heute bereits einmal gelaufen, wird daher ignoriert')
return;
}
if((LokaleSonnendaten_Azimut.state as Number).floatValue < (RolloAutomatikSuedAzimuthStart.state as Number)) {
logDebug('autoShutter', 'Azimuth ({}) hat noch nicht Schwellwert ({}) erreicht',LokaleSonnendaten_Azimut.state,RolloAutomatikSuedAzimuthStart.state)
return;
}
if((XiaomiHumidityPressureGarten_Temperature.state as Number).floatValue < (RolloAutomatikSuedTempMin.state as Number)) {
logDebug('autoShutter', 'Mindest-Temperatur ({}) wurde nicht erreicht durch aktuelle Temperatur ({})',RolloAutomatikSuedTempMin.state,XiaomiHumidityPressureGarten_Temperature.state)
return;
}
if((Localweatherandforecast_Bewolkung.state as Number).floatValue > (RolloAutomatikSuedWolkenMax.state as Number)) {
logDebug('autoShutter', 'Maximalbewölkung ({}) wurde überschritten ({})',RolloAutomatikSuedWolkenMax.state,Localweatherandforecast_Bewolkung.state)
return;
}
if((LokaleSonnendaten_Position_Elevation.state as Number).floatValue < (RolloAutomatikSuedElevationEnde.state as Number)) {
logDebug('autoShutter', 'Elevation für wieder abfahren ({}) ist groesser als aktuelle ({})',RolloAutomatikSuedElevationEnde.state,LokaleSonnendaten_Position_Elevation.state)
return;
}
// Rollos runterfahren
logDebug('autoShutter', 'Rollos werden abgefahren')
val nZiel = RolloAutomatikZielwert.state as Number
RollosSued.members.forEach[i|
if(i.state <= nZiel) {
logDebug('autoShutter', 'Fahre Rolladen {} auf {}%'i.name,nZiel)
i.sendCommand(nZiel)
} else {
logDebug('autoShutter', 'Rolladen ist bereits weiter geschlossen ({}%) als er geschlossen werden sollte und wird daher ignoriert',i.state)
}
]
// Letzte Ausführung mit entsprechendem Zeitstempel belegen
sendBroadcastNotification("Verschattung Südseite aktiv") //Pushnachricht
bShadeStart = true
RolloAutomatikSuedStartLast.postUpdate(new DateTimeType(now))
end
rule "Rollo Süd wieder öffnen"
when
Item LokaleSonnendaten_Position_Elevation changed
then
val String logPrefix = 'Rolloautomatik - '
logDebug('autoShutter', 'Regel (Rollo Süd hoch) wurde gestartet')
if(RolloAutomatikSuedOeffnen.state != ON) {
logDebug('autoShutter', 'Beende, da Automatik generell nicht aktiv')
return;
}
if((LokaleSonnendaten_Position_Elevation.state as Number).floatValue > (RolloAutomatikSuedElevationEnde.state as Number)) {
logDebug('autoShutter', 'Beende, da Elevation ({}) nicht kleiner der eingestellten Elevation ({}) war',LokaleSonnendaten_Position_Elevation.state,RolloAutomatikSuedElevationEnde.state)
return;
}
if(!bShadeStart) {
logDebug('autoShutter', 'Beende, da heute noch keine Ausführung stattfand. Demzufolge kann auch kein automatisches Öffnen gewollt sein')
return;
}
if(bShadeEnd) {
logDebug('autoShutter', 'Beende, da heute bereits ein automatisches Wiederhochfahren stattfand')
return;
}
// Rollos wieder hoch
logDebug('autoShutter', 'Rollos werden hinaufgefahren')
val nZiel = RolloAutomatikZielwert.state as Number
RollosSued.members.forEach[i|
if(nZiel <= (i.state as Number) +5 && nZiel >= (i.state as Number) -5) {
logDebug('autoShutter', 'Fahre Rolladen {} auf 0%',i.name)
i.sendCommand(0)
} else {
logDebug('autoShutter', 'Fahre Rolladen {} nicht auf 0%, da dieser zwischenzeitlich manuell verändert wurde.',i.name)
}
]
// Letzte Ausführung mit entsprechendem Zeitstempel belegen
sendBroadcastNotification("Verschattung Südseite beendet") //Pushnachricht
RolloAutomatikSuedEndeLast.postUpdate(new DateTimeType())
bShadeEnd = true
end
Das Logging ist per default abgeschaltet, Einschalten geht über die Karaf Konsole, welche Du mit
aufrufen kannst.
Anschließend kannst Du mit
Code: Alles auswählen
log:set DEBUG org.openhab.core.automation.mudule.script.autoShutter
die Ausgabe des Logs aktivieren und mit
Code: Alles auswählen
log:set INFO org.openhab.core.automation.mudule.script.autoShutter
wieder deaktivieren.
EDIT: Fehlende Klammern im Code ergänzt.