Seite 2 von 3

Re: Time cron in Rule durch Setpoint Variable beeinflussen

Verfasst: 10. Jun 2024 08:33
von Quautiputzli
Ja, das hätte ich letzen Winter schon angreifen können, aber das System wie es jetzt ist läuft einfach so gut, so dass ich es dann doch gelassen habe.

Re: Time cron in Rule durch Setpoint Variable beeinflussen

Verfasst: 7. Nov 2024 10:45
von Quautiputzli
Hallo,
da ich nun auf OH4 bin, habe ich das auch ausprobiert, mit folgender rule:

Code: Alles auswählen

rule "Ramona_Start"

when
    Time is Ramona_Start timeOnly
then
    sendNotification("????????????????@t-online.de", "erste  Ausloesungung", "time", "Info")
end
Leider scheint es nur zu funktionieren wenn auch das heutige Datum eingegeben wird. Der Ausdruck "timeOnly" scheint also ignoriert zu werden. Stimmt hier die Schreibweise?

Re: Time cron in Rule durch Setpoint Variable beeinflussen

Verfasst: 7. Nov 2024 12:09
von udo1toni
Ja, die Schreibweise sollte korrekt sein. Ansonsten müsste es auch eine Fehlermeldung in openhab.log geben, wenn Du die Rules-Datei speicherst.

Re: Time cron in Rule durch Setpoint Variable beeinflussen

Verfasst: 7. Nov 2024 12:44
von Quautiputzli
Jetzt funktioniert es doch. Ich habe das timeOnly mal rausgelöscht, gespeichert, laufen lassen, und dann wieder reingeschrieben und gespeichert, und nun geht es.

Re: Time cron in Rule durch Setpoint Variable beeinflussen

Verfasst: 7. Nov 2024 12:50
von Quautiputzli
Jetzt will ich als nächstes, wenn die erste Aktion zu der eingestellten Zeit gestartet wurde mit z.B. 5 Minuten Verzögerung eine weitere starten.
Mach ich das dann am besten mit einem Timer in der rule, oder eine extra rule bei der man im Trigger diesen Offset von 5 Minuten addiert oder so ähnlich?

Re: Time cron in Rule durch Setpoint Variable beeinflussen

Verfasst: 7. Nov 2024 13:35
von Quautiputzli
Außerdem möchte ich das auf einzelne Wochentage begrenzen.
Wie bekomme ich denn den Wochentag als Zahl?
Ich habe mit:

Code: Alles auswählen

ZonedDateTime.now.getDayOfWeek()

den Wochentag als Wort ausgelesen, aber ich denke für Vergleiche wäre es als Zahl einfacher. Ich habe "Value" angehängt, aber das geht wohl nicht, Weder mit noch ohne "." dazwischen, also so:

Code: Alles auswählen

ZonedDateTime.now.getDayOfWeekValue()

Re: Time cron in Rule durch Setpoint Variable beeinflussen

Verfasst: 7. Nov 2024 14:08
von udo1toni
Wenn die zweite Aktion abhängig von der ersten Aktion ist, wäre meine bevorzugte Variante eine State Machine mit Timer. Das kannst Du Dir wie ein mechanisches Programmschaltwerk aus einer Waschmaschine vorstellen, nur in Programmcode. Unterm Strich ist es ein Timer, der mehrfach ausgeführt wird.

Code: Alles auswählen

var Timer tAblauf = null
var Integer iAblauf = 0

rule "Ablauf starten"
when
    Time is Startzeit timeOnly
then
    tAblauf?.cancel
    iAblauf = 0
    tAblauf = createTimer(now.plusSeconds(1), [|
        iAblauf ++ // Zähler um 1 erhöhen
        var Integer iSeconds = 0 // Variable für Pausenlänge definieren
        switch(iAblauf) { // welcher Schritt?
            case 1  : {
                // mach was in Schritt 1
                iSeconds = 5 * 60 // nächster Schritt in 5 Minuten
            }
            case 2  : {
                // mach was in Schritt 2
                iSeconds = 35 // nächster Schritt in 35 Sekunden
            }
            case 3  : {
                // mach was in Schritt 3
                return; // letzter Schritt, also kein weiterer Durchlauf
            }
            default : { // ungültiger Wert -> da ist was schief gelaufen
                return; // Abbruch
            }
        }
        tAblauf.reschedule(now.plusSeconds(iSeconds)) // Timer erneut ausführen
    ])
end
Man kann beliebig viele Schritte definieren, mit variablem Abstand zwischen den einzelnen Schritten. Falls es definiert nur zwei Schritte sein sollen, kann man natürlich auch auf einen Gutteil des Codes verzichten:

Code: Alles auswählen

rule "Ablauf starten"
when
    Time is Startzeit timeOnly
then
    // MAch was in Schritt 1
    createTimer(now.plusMinutes(5), [| // nach 5 Minuten
        // mach was in Schritt 2
    ])
end
Da die Startzeit ja nur einmal täglich ist, kann man relativ sicher auf das Gedöns zum deinitialisieren des Timers verzichten ;) und auch der ganze Zählmechanismus kann entfallen. Aber wo zwei Schritte gebraucht werden, werden auch drei Schritte gebraucht (oder so ähnlich), deshalb wollte ich lieber die allgemeinere Lösung zuerst beschreiben.
Durch das plusSeconds(1) zu Beginn läuft der erste Befehl natürlich eine Sekunde zu spät los, man könnte stattdessen auch plusNanos(10000000) für zehn Millisekunden Verzögerung verwenden (das ist sehr weit innerhalb der ohnehin vorhandenen Variabilität), das sieht nur so komisch aus... Mit Joda Time stand plusMillis() direkt zur Verfügung, mit JavaTime gibt es das nicht mehr direkt, sondern nur noch auf Umwegen:

Code: Alles auswählen

now.plus(10,java.time.temporal.ChronoUnit.MILLIS)
was zwar einfacher zu erfassen ist, aber weil ChronoUnit nicht zu den Standard Imports gehört, ist das auch nicht schön...

Re: Time cron in Rule durch Setpoint Variable beeinflussen

Verfasst: 7. Nov 2024 15:48
von Quautiputzli
Hallo Udo, und Vielen Dank.

Du musst hellseherische Fähigkeiten haben. Ich brauche nämlich tatsächlich 4 Schritte. Und eine 1 Sekunde hin oder her spielt hier keine Rolle. Ich brauche das eher im Minutenbereich.

Sehe ich das richtig, dass der Timer die ganze Zeit so weiterläuft, bis die Rule am nächsten Tag wieder getriggert wird?

Re: Time cron in Rule durch Setpoint Variable beeinflussen

Verfasst: 7. Nov 2024 19:51
von udo1toni
Quautiputzli hat geschrieben: 7. Nov 2024 15:48 Sehe ich das richtig, dass der Timer die ganze Zeit so weiterläuft, bis die Rule am nächsten Tag wieder getriggert wird?
Nein. Der Timer wird jeweils neu gestartet und läuft nur, bis der Code ausgeführt wird. Wenn der letzte Schritt ausgeführt wurde, wird die reschedule Methode nicht mehr aufgerufen und der Timer ist beendet.
Einzig der Zeiger auf den Timer ist potenziell noch vorhanden, was aber keine Rolle spielt. Die Rule muss ohnehin sicherstellen, dass der Timer-Code nicht mehrfach ausgeführt wird (tAblauf?.cancel), weil ein Anwender ja auf die Idee kommen könnte, den Timer Startpunkt zu ändern, nachdem die Sequenz bereits gestartet, aber noch nicht beendet wurde.
Falls im Gegenteil sichergestellt werden muss, dass unter allen Umständen die Sequenz vollständig abläuft, könnte man die Rule anders gestalten:

Code: Alles auswählen

var Timer tAblauf = null
var Integer iAblauf = 0

rule "Ablauf starten"
when
    Time is Startzeit timeOnly
then
    if(tAblauf !== null)
        return;
    iAblauf = 0
    tAblauf = createTimer(now.plusSeconds(1), [|
        iAblauf ++ // Zähler um 1 erhöhen
        var Integer iSeconds = 0 // Variable für Pausenlänge definieren
        switch(iAblauf) { // welcher Schritt?
            case 1  : {
                // mach was in Schritt 1
                iSeconds = 5 * 60 // nächster Schritt in 5 Minuten
            }
            case 2  : {
                // mach was in Schritt 2
                iSeconds = 35 // nächster Schritt in 35 Sekunden
            }
            case 3  : {
                // mach was in Schritt 3
                tAblauf = null
                return; // letzter Schritt, also kein weiterer Durchlauf
            }
            default : { // ungültiger Wert -> da ist was schief gelaufen
                tAblauf = null
                return; // Abbruch
            }
        }
        tAblauf.reschedule(now.plusSeconds(iSeconds)) // Timer erneut ausführen
    ])
end
Nun wird der Timer nur gestartet, wenn er nicht bereits ausgeführt wird (bzw. der Zeiger nicht null ist). Zum Abschluss der Sequenz muss deshalb unbedingt der Zeiger geleert werden, sonst wird die Sequenz nicht mehr gestartet. Diese Variante birgt auch die Gefahr, dass bei einem Fehler der Zeiger nicht geleert wird und in der Folge müsste mindestens die rules-Datei neu eingelesen werden um den Zeiger zu leeren, was aber (bei laufender Sequenz) ebenfalls Fehler nach sich ziehen wird. Da muss man also immer abwägen, was weniger gefährlich ist :)

Re: Time cron in Rule durch Setpoint Variable beeinflussen

Verfasst: 11. Nov 2024 12:32
von Quautiputzli
Jetzt habe ich nochmal eine Frage zu dem Item "Startzeit". Das ist ja vom Typ dateTime.

Nun habe ich festgestellt, dass das Item nach einem restart des pi "leer" ist. Wird das nicht persestiert, und sollte wieder die letzte Zeit enthalten? Oder geht das bei DateTime nicht. Das Item ist ja nicht mit einem Channel verlinkt. Ist das ein Problem?

Ich habe hier noch mehrere Items, jedoch vom Typ switch, die nachdem restart wieder den vorherigen Wert haben. Am Persistence Service habe ich keine speziellen Einstellungen gemacht. Hier die Datei "mapdb.persist":

Code: Alles auswählen

Strategies {

//        everyMinute : "0 * * * * ?"
//        everyHour : "0 0 * * * ?"
//        everyDay  : "0 0 0 * * ?"
        default = everyChange
}

Items {
	gMapdb* : strategy = everyChange, restoreOnStartup
}