cron Ausdruck und Visual Studio Code

Einrichtung der openHAB Umgebung und allgemeine Konfigurationsthemen.

Moderatoren: seppy, udo1toni

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

Re: cron Ausdruck und Visual Studio Code

Beitrag von udo1toni »

Also, er kommt bis Zeile ~105 (Ich fürchte, die Zählung wird nicht genau mit Deiner korrelieren):

Code: Alles auswählen

    logInfo("timer","Status1")
    time1_Aus_BZ = createTimer(now.withTimeAtStartOfDay.plusMinutes(soll1AusBZ.intValue), [|
        logInfo("timer","Status2")
Logischerweise (da die nächste log-Zeile nicht mehr erscheint) tritt der Fehler im createTimer auf. soll1AusBZ ist zu dem Zeitpunkt null.
Vermutlich gibt es irgendeinen Fall, in dem Du diese Variable nicht setzt. Ändere mal die logInfo-Zeile vor dem createTimer auf

Code: Alles auswählen

logInfo("timer","Status1 soll1AusBZ {}",soll1AusBZ)
dann kannst Du das im Zweifel im Log sehen.

Die ganze Rule ist halt auch etwas... länglich...
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

hardl
Beiträge: 347
Registriert: 10. Mai 2018 09:46
Answers: 1

Re: cron Ausdruck und Visual Studio Code

Beitrag von hardl »

soll1AusBZ ist leer, da

Code: Alles auswählen

 if (Sw_2_BZ == OFF && Sw_So_BZ == OFF) { 
 
nicht gültig ist. Warum??

Beide sind im

Code: Alles auswählen

logInfo("timer","Status {}",(Sw_2_BZ.state))
logInfo("timer","Status {}",(Sw_So_BZ.state))
"OFF"

hardl
Beiträge: 347
Registriert: 10. Mai 2018 09:46
Answers: 1

Re: cron Ausdruck und Visual Studio Code

Beitrag von hardl »

Scheinbar habe ich den Fehler gefunden:

Code: Alles auswählen

 if (Sw_2_BZ == OFF && Sw_So_BZ == OFF) { 
 
muss heissen:

Code: Alles auswählen

 if (Sw_2_BZ.state == OFF && Sw_So_BZ.state == OFF) { 
 

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

Re: cron Ausdruck und Visual Studio Code

Beitrag von udo1toni »

Ja, korrekt. Wenn Du den Status eines Items verwenden willst, musst Du explizit den Status verwenden.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

hardl
Beiträge: 347
Registriert: 10. Mai 2018 09:46
Answers: 1

Re: cron Ausdruck und Visual Studio Code

Beitrag von hardl »

Der Ablauf um Mitternacht läuft perfekt und die ersten Schaltzeiten ebenso.

Wenn ich aber manuell ändere, läuft was falsch.
Beispiel:
Ein 7.00 Uhr sendCommand 1 - ok
Aus 9.00 Uhr sendCommand 11 - ok

10.00 Uhr manuelle Aenderung in der sitemap auf 10.15 Uhr
Neuinitialisierung der Timer - ok
1.Timer sendet 1 - ok
2. Timer sendet nicht, da angeblich nicht Thermostat.state != 11
??

Code: Alles auswählen

018-10-29 10:31:24.427 [INFO ] [eclipse.smarthome.model.script.timer] - Rule BZ getriggert!
2018-10-29 10:31:24.435 [INFO ] [eclipse.smarthome.model.script.timer] - Wochentag BZ ist 1
2018-10-29 10:31:24.452 [INFO ] [eclipse.smarthome.model.script.timer] - BZ Einschaltzeit 1 2018-10-29T07:00:00.000+01:00
2018-10-29 10:31:24.471 [INFO ] [eclipse.smarthome.model.script.timer] - BZ Ausschaltzeit 1 2018-10-29T09:15:00.000+01:00
2018-10-29 10:31:24.501 [INFO ] [eclipse.smarthome.model.script.timer] - BZ Ausschaltzeit 1 Thermostat gleich!
==> /var/log/openhab2/events.log <==
2018-10-29 10:31:24.502 [ome.event.ItemCommandEvent] - Item 'Thermostat_BZ' received command 1
2018-10-29 10:31:24.512 [nt.ItemStatePredictedEvent] - Thermostat_BZ predicted to become 1
==> /var/log/openhab2/openhab.log <==
2018-10-29 10:31:24.515 [INFO ] [eclipse.smarthome.model.script.timer] - BZ Einschaltzeit 1 erreicht und Automatik aktiv!
==> /var/log/openhab2/events.log <==
2018-10-29 10:31:24.530 [vent.ItemStateChangedEvent] - Thermostat_BZ changed from 11 to 1

hardl
Beiträge: 347
Registriert: 10. Mai 2018 09:46
Answers: 1

Re: cron Ausdruck und Visual Studio Code

Beitrag von hardl »

Nach dem Log ist time1_Ein_WZ noch nicht abgearbeitet, wenn time1_Aus_WZ bereits fertig ist.

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

Re: cron Ausdruck und Visual Studio Code

Beitrag von udo1toni »

Also, bei genauem Überlegen komme ich auf einen Fall, den wir nicht berücksichtigt haben, nämlich, dass Schaltzeiten bereits vorbei sind, wenn Du etwas änderst. Es könnte also sein, dass die Rule Timer anlegt, die in der Vergangenheit liegen. Die werden zwar am nächsten Tag um 0 Uhr (alternativ bei Änderungen) gelöscht, aber bis dahin existieren sie ohne dass sie getriggert werden. Es spielt aber keine Rolle, ob Timer schon abgelaufen sind oder nicht, wenn ein Timer abläuft, wird der enthaltene Code ausgeführt. Der Code prüft, welchen Zustand der Thermostat hat und ändert ihn gegebenenfalls. Wenn der Modus schon dem Soll entspricht, wird auch nchts geändert.

Allerdings, wenn ich die Rule so betrachte, scheint mir das sehr viel Code zu sein. Überdenke vielleicht mal, was Du erreichen möchtest, und ob es dafür nicht elegantere Lösungen geben könnte.
Stand jetzt hast Du 6 * 2 Items für Uhrzeiten (Warum getrennte Ausschaltzeiten für das Wochenende, aber keine getrennten Einschaltzeiten?), Schalter für 2. Schaltzeit aktiv, Samstag aus aktiv und Sonntag aus aktiv, sowie ein generelles Automatik aus.
Eine Heimautomation soll automatisch arbeiten. Es mag vielleicht manchmal nicht einfach sein, eine komplexe Steuerung ohne Eingriff einzurichten, aber das Konstrukt sieht für mich reichlich unsexy und sehr manuell aus.

Am Rande: Ich arbeite Schichtdienst mit Dienstbeginn zwischen 4 Uhr und 20 Uhr, Schichtende entsprechend, unregelmäßig und ohne erkennbare Muster. Meine Heizung ist nicht auf den letzten Punkt optimiert, weil ich auch noch eine Familie habe, aber grundsätzlich könnte ich die Steuerung auch abhängig von meinen Dienstzeiten machen, sicher aber nicht mit 20 manuell zu bedienenden Items.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

hardl
Beiträge: 347
Registriert: 10. Mai 2018 09:46
Answers: 1

Re: cron Ausdruck und Visual Studio Code

Beitrag von hardl »

Du hast ja recht, bei der Umsetzung bin ich auch erschrocken, wie viele items dafür nötig sind.

Ich habe vorher verschiedene fertige z-wave Lösungen benutzt, aber immer wieder Probleme mit der Reichweite gehabt.
Eigentlich wollte ich gar nicht selbst "Programmieren", aber auf eine Empfehlung hin, bin ich auf openhab gekommen.
Ich habe bei der Thermostatsteuerung versucht, die Fertiglösung von zwave.me oder Popp-HUB nachzustellen.
Auch dort gibt es die Möglichkeit ein oder zwei Schaltzeiten pro Tag und unterschiedliche Abschaltzeiten am Wochenende einzurichten. Man könnte sogar täglich unterschiedlich schalten.

Nur ungern würde ich nochmals von vorne anfangen, denn der Bereich mit den vielen Items und den unterschiedlichen Zeiten am Wochenende läuft inzwischen gut und es hängt nur "noch" an den vier timern.

Ich habe heute versucht die timer time2_Ein_xx und time2_Aus_xx mit time2_xxx_xx = null oder time2_xxx_xx.cancel zu deaktivieren, wenn Sw_2_xx "OFF" ist, aber das funktioniert nicht.

Ich suche einen Weg, um die 4 createTimer Anweisungen nur dann auszuführen, wenn die aktuelle Uhrzeit größer ist.
Alternativ könnte ich auch unter "when" nur Time cron ausführen, aber das wäre die 2.Wahl, da Korrekturen erst Mitternacht gültig würden.

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

Re: cron Ausdruck und Visual Studio Code

Beitrag von udo1toni »

Die erste Möglichkeit wäre, beim Anlegen des Timers zu prüfen, ob now.getMinuteOfDay größer als der berechnete Minutenwert ist, wenn ja, wäre die Schaltzeit bereits überschritten.

Was meinst Du mit
hardl hat geschrieben: 29. Okt 2018 19:29Ich habe heute versucht die timer time2_Ein_xx und time2_Aus_xx mit time2_xxx_xx = null oder time2_xxx_xx.cancel zu deaktivieren, wenn Sw_2_xx "OFF" ist, aber das funktioniert nicht.
?

Oder anders gesagt: Was funktioniert da nicht? Du musst natürlich an der richtigen Stelle den Timer löschen, also vor allem erst dann, wenn er bereits angelegt wurde ;)
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

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

Re: cron Ausdruck und Visual Studio Code

Beitrag von udo1toni »

Ich hab jetzt noch mal intensiv über die Aufgabe gehirnt :)
Dabei habe ich eine, wie ich glaube, recht schicke Variante:
Items (nur angedeutet...)

Code: Alles auswählen

Group SchaltUhr                    // Alle Stell-Items
Number Uhr1_Ein_H (SchaltUhr)
Number Uhr1_Ein_M (SchaltUhr)
Number Uhr1_Aus_H (SchaltUhr)
Number Uhr1_Aus_M (SchaltUhr)
Number Uhr2_Ein_H (SchaltUhr)
Number Uhr2_Ein_M (SchaltUhr)
Number Uhr2_Aus_H (SchaltUhr)
Number Uhr2_Aus_M (SchaltUhr)
Number Uhr6_Aus_H (SchaltUhr)
Number Uhr6_Aus_M (SchaltUhr)
Number Uhr7_Aus_H (SchaltUhr)
Number Uhr7_Aus_M (SchaltUhr)
Group SchaltMinute                 // Alle Schaltzeiten
Number Uhr1_Ein (SchaltMinute)
Number Uhr2_Ein (SchaltMinute)
Number Uhr1_Aus (SchaltMinute)
Number Uhr2_Aus (SchaltMinute)
Number Uhr6_Aus (SchaltMinute)
Number Uhr7_Aus (SchaltMinute)
Switch planTimer                   // ein Trigger
Die Rules:

Code: Alles auswählen

var String nextName                                                                     // Name des aktuellen Timers
var Timer nextTimer = null                                                              // der Timer

rule "Zeiten berechnen"
when
    Time cron " 0 0 0 * * ?" or                                                         // Mitternacht
    System started or                                                                   // Neustart oder Rules neu geladen
    Member of SchaltUhr changed                                                         // oder Schaltzeit geändert
then
    logDebug("timer","Zeiten berechnen")
    var Number hour   = null
    var Number minute = null
    SchaltMinute.members.forEach[n|
        hour   = if(SchaltUhr.filter[u|u.name.contains(n.name + "_H")].head.state instanceof Number) SchaltUhr.filter[u|u.name.contains(n.name + "_H")].head.state else null    // falls gültige Stunde, übernehmen
        minute = if(SchaltUhr.filter[u|u.name.contains(n.name + "_M")].head.state instanceof Number) SchaltUhr.filter[u|u.name.contains(n.name + "_M")].head.state else null    // falls gültige Minute, übernehmen
        n.postUpdate(if((hour instanceof Number) && (minute instanceof Number)) hour * 60 + minute else NULL)        // Falls gültige Zeit, eintragen
        logInfo("timer","Schaltzeit {} auf {}:{} Uhr ({}) gesetzt.",n.name,hour,minute,n.state)
    ]
    logDebug("timer","Zeiten berechnen fertig")
end

rule "Timer anlegen"
when
    Member of SchaltMinute received update or                                           // Schaltzeit getriggert
    planTimer received command                                                          // Nachtriggern (nächsten Timer setzen)
then
    logDebug("timer","Timer setzen")
    if(nextTimer !== null) nextTimer.                                     cancel        // alten Timer löschen, falls noch aktiv
    nextName = SchaltMinute.filter[n|                                                   // nur gültige Schaltzeiten
        n.state instanceof Number
    ].filter[m|                                                                         // nur solche, die in der Zukunft liegen
        (m.state as Number) > now.getMinuteOfDay
    ].sortBy[state].head.name                                                           // nur der nächste -> Namen merken
    logDebug("timer","Timer setzen für {}",nextName)
    nextTimer = createTimer(now.withTimeAtStartOfDay.plusMinutes(SchaltMinute.filter[n| // setze Timer
        n.state instanceof Number                                                       // nur gültige Schaltzeit
    ].filter[m|
        (m.state as Number) > now.getMinuteOfDay                                        // nur in der Zukunft
    ].sortBy[state].head.state),[                                                       // nur der nächste
        logInfo("timer","Timer ausgelöst: {}",nextName)
        if(Schalter_manu_BZ.state != OFF) {                                             // falls manueller Betrieb
            logInfo("timer","Aber manueller Betrieb, Abbruch!")
            planTimer.sendCommand(OFF)                                                  // nächsten Timer planen
            return;                                                                     // und Schluss
        }
        val Number soll = if(nextName.contains("Ein") 11 else 1                         // Sollzustand nach Timer
        logInfo("timer","geforderter Schaltvorgang: {}",Soll)    
        if((nextName.contains("1") ||                                                   // Soll der Timer berücksichtigt werden?
           (nextName.contains("2") && SW_2_BZ.state == ON) ||
           (nextName.contains("6") && SW_Sa_BZ.state == ON && now.getDayOfWeek == 6) ||
           (nextName.contains("7") && SW_So_BZ.state == ON) && now.getDayOfWeek == 7) {
            logInfo("timer","Schaltvorgang aktiv")
           if((Thermostat_BZ.state as Number) != soll) Thermostat_BZ.sendCommand(soll) else logInfo("timer","aber Zustand bereits erreicht")
        } else {
            logInfo("timer","Schaltvorgang inaktiv")
        }
        planTimer.sendCommand(OFF)
    ])
    logDebug("timer","Timer setzen fertig")
end
WARNUNG: Der Code ist ungetestet! Falls Du magst, kannst Du den Code parallel einrichten, dann solltest Du die echten Schaltvorgänge auskommentieren und mal beobachten, ob die Rules so wie geplant funktionieren.

Die Idee hinter dem Code:
Die erste Rule kümmert sich nur darum, die gewählten Zeiten in "Tagesminuten" umzurechnen. Dabei werden die Zeiten in korrespondierenden Items gespeichert. Durch Verwendung der Gruppen ist der entstehende Code extrem kompakt.

Die zweite Rule erzeugt jeweils den nächsten anstehenden Timer. Dabei wird bewusst darauf verzichtet, auf Schaltstellungen zu achten. Dadurch muss der Timer nur dann neu erzeugt werden, wenn eine Schaltzeit geändert wird, nicht aber, wenn der Modus gewechselt wird. Ein angelegter Timer kostet nur wenig Speicher und praktisch keine Rechenzeit, da sich der Scheduler um die Ausführung kümmert.

Wenn der Timer abläuft, wird geprüft, ob der manuelle Modus aktiv ist. sollte das der Fall sein, wird der nächste Timer generiert und danach die Ausführung abgebrochen.
Als nächstes wird der Sollzustand ermittelt.
Dann wird geprüft, ob die Schaltzeit berücksichtigt werden soll (2. Schaltzeit aktiv, Samstag aktiv, Sonntag aktiv), dies natürlich in Bezug auf die gerade aktive Schaltzeit und unter Berücksichtigung des Wochentags.
Abschließend wird, falls alles passt, der Schaltbefehl ausgeführt, natürlich nur, falls das nötig ist.

Die Zeiten werden streng aufsteigend abgearbeitet, falls man z.B. folgende Zeiten einstellt (alle aktiv):
1. Ein 4:00
1. Aus 20:00
2. Ein 15:00
2. Aus 12:00
6. Aus 14:00
7: Aus 19:00

wird Samstags um 4 Uhr eingeschaltet (1. Timer),
um 12 Uhr ausgeschaltet (2. Timer),
um 14 Uhr nochmals ausgeschaltet, falls zwischenzeitlich anderweitig wieder eingeschaltet wurde (Samstag),
um 15 Uhr eingeschaltet (2. Timer) und
um 20 Uhr ausgeschaltet (1. Timer).

Die Codezeilen mit filter[] können natürlich auch in einer Zeile geschrieben werden, ich wollte hier lediglich die Lesbarkeit erhöhen :)
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Antworten