Seite 1 von 1

Hilfe bei 2 Rules

Verfasst: 26. Sep 2024 18:19
von Snatsch
Hallo, Ich habe folgende Rule am laufen

Code: Alles auswählen

// Globale Variablen vor der ersten Rule definieren!
var Timer tSoll = null                                                           // Timer für Solltemperatur
var nSoll       = 18.0                                                           // Default Temperatur

rule "Solltemperatur setzen"
when
    Item Heizungsschalter_Alle_Heizungen changed or
    Member of gSPOnline changed
then
    var nStart  = 1
    if(Heizungsschalter_Alle_Heizungen.state == OFF) {                           // Hauptschalter aus
        nSoll = 6
    } else {                                                                     // Hauptschalter nicht aus
        val bOnline = (gSPOnline.members.filter[i|i.state != OFF].size > 0)      // true falls mindestens ein Gerät nicht OFF
        nSoll       = if(bOnline) 21 else  18                                    // Solltemperatur
        if(!bOnline) nStart = 600                                                // Zeitverzögerung abhängig von Soll
    }
    gTempSoll.members.filter[i|!(i.state instanceof Number)].forEach[j|          // uninitialisierte Items notfalls initialisieren
        j.postUpdate(19)
    ]
    tSoll?.cancel                                                                // laufende Timer abbrechen

    tSoll = createTimer(now.plusSeconds(nStart), [|                              // nach nStart Sekunden
        val lItems = gTempSoll.members.sortBy[name].filter[i|
                     (i.state as Number).floatValue != nSoll]                    // Liste aller Items die vom Soll abweichen
        if(lItems.size == 0)                                                     // falls noch Abweichungen vom Soll bestehen
            return;
        tSoll.reschedule(now.plusSeconds(5))                                     // führe Timer erneut aus
        logInfo("soll","Setze {} auf {}", lItems.head.name, nSoll)
        lItems.head.sendCommand(nSoll)                                           // Solltemperatur setzen
    ])

end

und diese hier wenn jemand das Fenster öffnet

Code: Alles auswählen

var HeizungBadezimmer_Solltemperatur = 6  // HeizungBadezimmer_Solltemperatur_Fensterkontakt   
var Timer BadezimmerfensterkleinHeizungMeldung = null

rule "Fenster klein Badezimmer Auf Heizung aus"
when
    Item Badezimmerfensterklein_TurFensterstatus changed
then
    // Timer abbrechen, falls er noch läuft
    BadezimmerfensterkleinHeizungMeldung?.cancel
    
    if (Badezimmerfensterklein_TurFensterstatus.state == OPEN) {
        // Solltemperatur basierend auf dem aktuellen Zustand setzen
        HeizungBadezimmer_Solltemperatur = if(HeizungBadezimmer_Solltemperatur_Fensterkontakt.state instanceof QuantityType) {
            (HeizungBadezimmer_Solltemperatur_Fensterkontakt.state as QuantityType<Number>).toBigDecimal.intValue
        } else {
            21
        }
        
        // Timer starten, um nach 1 Minute die Heizung zu reduzieren
        BadezimmerfensterkleinHeizungMeldung = createTimer(ZonedDateTime.now.plusMinutes(1), [|
            HeizungBadezimmer_Solltemperatur_Fensterkontakt.sendCommand(6)                       
        ])
    }
    
    if (Badezimmerfensterklein_TurFensterstatus.state == CLOSED) {
        // Heizung auf ursprüngliche Solltemperatur zurücksetzen
        HeizungBadezimmer_Solltemperatur_Fensterkontakt.sendCommand(HeizungBadezimmer_Solltemperatur)        
    }
end

leider funktioniert es nicht das wenn das Fenster geöffnet wurden ist die Temperatur auf 6 Grad geht.
Kann es eventuell sein das die erste Regel die zweite aufhebt ?

Re: Hilfe bei 2 Rules

Verfasst: 26. Sep 2024 22:06
von udo1toni
Liegen beide Rules in separaten Dateien? Du kannst beliebig viele Rules in einer *.rules Datei speichern. Du musst lediglich darauf achten, dass alle globalen Variablen und Konstanten vor der ersten Rule definiert sind.
Was soll die 2. Rule bewirken? Stand jetzt startet die Rule sobald sich der Status des Items Badezimmerfensterklein_TurFensterstatus ändert.
Ist der Status OPEN, wird die aktuelle Solltemperatur über das Item HeizungBadezimmer_Solltemperatur_Fensterkontakt eingelesen, falls dessen Status vom Typ QuantityType ist. Dabei übernimmst Du den Wert dann (recht umständlich) in die globale Variable HeizungBadezimmer_Solltemperatur. Hat das Item keinen Inhalt vom Typ QuantityType, setzt die Rule 21 als Wert.
Anschließend wird ein Timer gestartet, der nach einer Minute abläuft.
Ist der Status hingegen CLOSED, wird der Inhalt der globalen Variablen an das Item HeizungBadezimmer_Solltemperatur_Fensterkontakt gesendet.

Läuft der Timer ab, so wird der Wert 6 an das Item HeizungBadezimmer_Solltemperatur_Fensterkontakt gesendet.

Gesetzt den Fall, dass die erste Rule (bzw. deren Timer) nicht gerade aktiv ist, weil z.B. einer der Member der Gruppe gSPOnline seinen Status geändert hat, sollten sich die Rules nicht in die Quere kommen.

Ist das Item HeizungBadezimmer_Solltemperatur_Fensterkontakt vom Typ Number:Temperature?

Wenn Du eine Rule mit changed triggerst, steht eine implizite lokale Konstante zur Verfügung, die den Status des triggernden Items enthält. Der Name lautet newState. Statt

Code: Alles auswählen

if(Badezimmerfensterklein_TurFensterstatus.state == OPEN)
kannst Du also besser

Code: Alles auswählen

if(newState == OPEN)
verwenden.

Achtung! newState enthält den Status, der die Rule getriggert hat. Das Item kann aber ab dem Zeitpunkt des Triggers seinen Status bereits geändert haben (auch während die Rule ausgeführt wird; auch mehrfach!) Es ist also ein Unterschied, ob man auf das Item oder die implizite Konstante zugreift (letztere sollte bevorzugt werden).
Bei ja/nein Entscheidungen ist es besser, explizit nur zwei Möglichkeiten vorzusehen.
Natürlich gäbe es streng genommen noch den Fall, dass das Item seinen Zustand auf NULL oder UNDEF ändert, das ist aber eher unwahrscheinlich. Elegant könnte man das so abfangen:

Code: Alles auswählen

if(!(previousState instanceof OpenClosedType)) return; // vorheriger Wert ungültig -> Systemstart
if(!(newState instanceof OpenClosedType))      return; // Item wechselt auf ungültigen Wert -> Fehler
previousState steht ebenfalls als implizite lokale Konstante zur Verfügung, wenn der Trigger changed war. :)
Danach gibt es dann nur noch zwei Möglichkeiten, OPEN oder CLOSED, was Du dann mit if()...else... abfrühstücken kannst.
Das Konstrukt (HeizungBadezimmer_Solltemperatur_Fensterkontakt.state as QuantityType<Number>).toBigDecimal.intValue ist zum einen seltsam, zum anderen ungültig. Wenn Du den Wert als QuantityType nutzen willst, solltest Du explizit angeben, welche Größe Du erwartest, hier also Temperature, nicht Number. .toBigDezimal steht nur für DecimalType zur Verfügung. Das spielt aber auch keine Rolle, in Wirklichkeit willst Du ja .intValue, das steht für Number zur Verfügung, QuantityType<Temperature> ist Teil von Number, korrekt wäre also

Code: Alles auswählen

(HeizungBadezimmer_Solltemperatur_Fensterkontakt.state as QuantityType<Temperature>).intValue
Wobei man immer aufpassen muss, denn .intValue schneidet einfach die Einheit ab.
Wenn das Item den Wert "konventionell" speichert, also in °C (Parameter unit in den Metadaten des Items), kannst Du auch vereinfacht

Code: Alles auswählen

(HeizungBadezimmer_Solltemperatur_Fensterkontakt.state as Number).intValue
nutzen, siehe oben, QuantityType ist ja Teil von Number.

Re: Hilfe bei 2 Rules

Verfasst: 26. Sep 2024 22:22
von Snatsch
vorher hatte ich die Rule so

Code: Alles auswählen

var HeizungBadezimmer_Solltemperatur = 6  //HeizungBadezimmer_Solltemperatur_Fensterkontakt   
var Timer BadezimmerfensterkleinHeizungMeldung = null

rule "Fenster klein Badezimmer Auf  Heizung aus"
 
when
    Item Badezimmerfensterklein_TurFensterstatus changed
then
     //cancel timer if running
    BadezimmerfensterkleinHeizungMeldung?.cancel
    
    
    if (Badezimmerfensterklein_TurFensterstatus.state == OPEN){

     HeizungBadezimmer_Solltemperatur = if(HeizungBadezimmer_Solltemperatur_Fensterkontakt.state instanceof Number) ((HeizungBadezimmer_Solltemperatur_Fensterkontakt.state as DecimalType).intValue) else 21
     BadezimmerfensterkleinHeizungMeldung = createTimer(ZonedDateTime.now.plusMinutes(1), [|
            HeizungBadezimmer_Solltemperatur_Fensterkontakt.sendCommand(6)                       
    ])
    }
    if (Badezimmerfensterklein_TurFensterstatus.state == CLOSED){                                      
        HeizungBadezimmer_Solltemperatur_Fensterkontakt.sendCommand(HeizungBadezimmer_Solltemperatur)        
    }

end
und wenn das Fenster geöffnet wurden ist kam im Log diese Fehlermeldung

Code: Alles auswählen

16:42:30.737 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'Heizung_Badezimmer_Fenster-1' failed: Could not cast 21 °C to org.openhab.core.library.types.DecimalType; line 15, column 119, length 68 in Heizung_Badezimmer_Fenster" 

Re: Hilfe bei 2 Rules

Verfasst: 26. Sep 2024 22:25
von udo1toni
Ja, QuantityType ist Teil von Number, aber nicht von DecimalType. DecimalType ist nicht das gleiche wie Number.

Re: Hilfe bei 2 Rules

Verfasst: 27. Sep 2024 15:40
von Snatsch
Hallo Udo :)
Vielen Dank für deine Ausführliche Erläuterung :D
in openhab 3 lief die Rule dachte ich immer gut :?: Wenn ich dich richtig verstanden habe müsste die Rule jetzt so aussehen

Code: Alles auswählen

rule "Fenster klein Badezimmer Auf Heizung aus"
when
    Item Badezimmerfensterklein_TurFensterstatus changed
then
    // Timer abbrechen, falls er noch läuft
    BadezimmerfensterkleinHeizungMeldung?.cancel
    
    if (newState == OPEN) {
        // Solltemperatur basierend auf dem aktuellen Zustand setzen
        HeizungBadezimmer_Solltemperatur = if(HeizungBadezimmer_Solltemperatur_Fensterkontakt.state instanceof QuantityType) {
            (HeizungBadezimmer_Solltemperatur_Fensterkontakt.state as Number).intValue
        } else {
            21
        }
        
        // Timer starten, um nach 1 Minute die Heizung zu reduzieren
        BadezimmerfensterkleinHeizungMeldung = createTimer(ZonedDateTime.now.plusMinutes(1), [|
            HeizungBadezimmer_Solltemperatur_Fensterkontakt.sendCommand(6)                       
        ])
    }
    
    if (Badezimmerfensterklein_TurFensterstatus.state == CLOSED) {
        // Heizung auf ursprüngliche Solltemperatur zurücksetzen
        HeizungBadezimmer_Solltemperatur_Fensterkontakt.sendCommand(HeizungBadezimmer_Solltemperatur)        
    }
end
Richtig ?

Re: Hilfe bei 2 Rules

Verfasst: 27. Sep 2024 15:52
von Snatsch
auch nicht Richtig :roll: Die Heizung geht nach 1 Minute zwar auf 6 Grad runter aber springt dann wieder auf 21 Grad obwohl das Fenster noch offen ist :(

Re: Hilfe bei 2 Rules

Verfasst: 27. Sep 2024 17:23
von udo1toni
Erst mal kann die Rule so bleiben, wie sie ursprünglich war. Besser wäre es allerdings so:

Code: Alles auswählen

rule "Fenster klein Badezimmer Auf Heizung aus"
when
    Item Badezimmerfensterklein_TurFensterstatus changed
then
    // Timer abbrechen, falls er noch läuft
    BadezimmerfensterkleinHeizungMeldung?.cancel
    
    if(newState == OPEN) {
        // Solltemperatur basierend auf dem aktuellen Zustand setzen
        HeizungBadezimmer_Solltemperatur = if(HeizungBadezimmer_Solltemperatur_Fensterkontakt.state instanceof QuantityType) {
            (HeizungBadezimmer_Solltemperatur_Fensterkontakt.state as QuantityType<Temperature>).intValue
        } else {
            21
        }
        
        // Timer starten, um nach 1 Minute die Heizung zu reduzieren
        BadezimmerfensterkleinHeizungMeldung = createTimer(ZonedDateTime.now.plusMinutes(1), [|
            HeizungBadezimmer_Solltemperatur_Fensterkontakt.sendCommand(6)                       
        ])
    } else { // oder alternativ     if(newState == CLOSED) {
        // Heizung auf ursprüngliche Solltemperatur zurücksetzen
        HeizungBadezimmer_Solltemperatur_Fensterkontakt.sendCommand(HeizungBadezimmer_Solltemperatur)        
    }
end
Wenn die Temperatur aber zurück springt, wäre die erste Maßnahme ein intensiver Blick ins Log. Werden Befehle an HeizungBadezimmer_Solltemperatur_Fensterkontakt gesendet? Wenn ja, musst Du herausfinden, wer (welche Rule...) da sendet, z.B. indem Du bei jeder Rule, die an dieses Item sendet eine Loganweisung ergänzt.
Falls nein, musst Du prüfen, warum das Thermostat von sich aus die Temperatur zurückstellt.

Re: Hilfe bei 2 Rules

Verfasst: 27. Sep 2024 17:29
von Snatsch
ich denke es liegt an der Rule

Code: Alles auswählen

// Globale Variablen vor der ersten Rule definieren!
var Timer tSoll = null                                                           // Timer für Solltemperatur
var nSoll       = 18.0                                                           // Default Temperatur

rule "Solltemperatur setzen"
when
    Item Heizungsschalter_Alle_Heizungen changed or
    Member of gSPOnline changed
then
    var nStart  = 1
    if(Heizungsschalter_Alle_Heizungen.state == OFF) {                           // Hauptschalter aus
        nSoll = 6
    } else {                                                                     // Hauptschalter nicht aus
        val bOnline = (gSPOnline.members.filter[i|i.state != OFF].size > 0)      // true falls mindestens ein Gerät nicht OFF
        nSoll       = if(bOnline) 21 else  18                                    // Solltemperatur
        if(!bOnline) nStart = 600                                                // Zeitverzögerung abhängig von Soll
    }
    gTempSoll.members.filter[i|!(i.state instanceof Number)].forEach[j|          // uninitialisierte Items notfalls initialisieren
        j.postUpdate(19)
    ]
    tSoll?.cancel                                                                // laufende Timer abbrechen

    tSoll = createTimer(now.plusSeconds(nStart), [|                              // nach nStart Sekunden
        val lItems = gTempSoll.members.sortBy[name].filter[i|
                     (i.state as Number).floatValue != nSoll]                    // Liste aller Items die vom Soll abweichen
        if(lItems.size == 0)                                                     // falls noch Abweichungen vom Soll bestehen
            return;
        tSoll.reschedule(now.plusSeconds(5))                                     // führe Timer erneut aus
        logInfo("soll","Setze {} auf {}", lItems.head.name, nSoll)
        lItems.head.sendCommand(nSoll)                                           // Solltemperatur setzen
    ])

end
im Log steht nur " Setze Solltemperatur Fensterkontakt auf 21 Grad"

Re: Hilfe bei 2 Rules

Verfasst: 27. Sep 2024 22:04
von udo1toni
Ich gehe mal davon aus, dass unmittelbar in der Nähe auch ein HeizungBadezimmer_Solltemperatur_Fensterkontakt received Command 21 steht?
Die Frage wäre nun, was die Rule getriggert hat, entweder Heizungsschalter_Alle_Heizungen hat den Zustand auf ON gewechselt oder einer der Member von gSPOnline hat seinen Zustand geändert. Auf jeden Fall scheint die Rule etwas zu tun... Also müsste man sicherstellen, dass die Rule nur dann die Solltemperaturen setzt, wenn sich der Zustand vom Hauptschalter Heizungsschalter_Alle_Heizungen oder von bOnline geändert hat.
Am einfachsten machst Du aus dem Group Item eines mit Aggregation (hier als *.items Definition):

Code: Alles auswählen

Group:Switch:OR(ON,OFF) "Online Status [%s]"
Das Item sollte nun OFF anzeigen, wenn alle zugehörigen Items OFF sind oder ON, wenn mindestens eines der Items ON meldet.

Nun kannst Du die Rule anpassen:

Code: Alles auswählen

rule "Solltemperatur setzen"
when
    Item Heizungsschalter_Alle_Heizungen changed or
    Item gSPOnline changed
then
    var nStart  = 1
    if(Heizungsschalter_Alle_Heizungen.state == OFF) {                           // Hauptschalter aus
        nSoll = 6
    } else {                                                                     // Hauptschalter nicht aus
        nSoll = if(gSPOnline.state != OFF) 21 else  18                           // Solltemperatur
        if(!bOnline) nStart = 600                                                // Zeitverzögerung abhängig von Soll
    }
    gTempSoll.members.filter[i|!(i.state instanceof Number)].forEach[j|          // uninitialisierte Items notfalls initialisieren
        j.postUpdate(19)
    ]
    tSoll?.cancel                                                                // laufende Timer abbrechen

    tSoll = createTimer(now.plusSeconds(nStart), [|                              // nach nStart Sekunden
        val lItems = gTempSoll.members.sortBy[name].filter[i|
                     (i.state as Number).floatValue != nSoll]                    // Liste aller Items die vom Soll abweichen
        if(lItems.size == 0)                                                     // falls noch Abweichungen vom Soll bestehen
            return;
        tSoll.reschedule(now.plusSeconds(5))                                     // führe Timer erneut aus
        logInfo("soll","Setze {} auf {}", lItems.head.name, nSoll)
        lItems.head.sendCommand(nSoll)                                           // Solltemperatur setzen
    ])
end
So sollte die Rule nur noch triggern, wenn entweder der Hauptschalter umgeschaltet wurde oder der Zustand der Gruppe zwischen ON und OFF gewechselt hat. Das passiert aber nur, wenn die Anzahl der ON-Items von 0 auf > 0 oder von >0 auf 0 wechselt, nicht mehr jedes Mal, wenn ein einzelnes Gerät seinen Zustand wechselt.

Andere Thermostaten müssten übrigens von dem gleichen Problem betroffen sein, wenn Du die Temperatur eines Thermostaten verstellst und eines der Items seinen Zustand wechselt, müsste die Rule triggern und alle Solltemperaturen setzen (je nachdem, alle auf 6, 18 oder 21) Eventuell verstellst Du die Solltemperaturen bei den anderen Thermostaten aber nie, weshalb das nicht weiter auffällt.

Eine "große" Lösung des Problems könnte so aussehen:

Code: Alles auswählen

// Imports
import java.util.HashMap

// Globale Variablen vor der ersten Rule definieren!
var Timer tSoll = null                                                           // Timer für Solltemperatur

val HashMap<String, Number> hmSoll = newHashMap(                                 // Definition und Default bei Start
    "Heizkreis_1"                                     -> 6,
    "Heizkreis_2"                                     -> 6,
    "Heizkreis_3"                                     -> 6,
    "HeizungBadezimmer_Solltemperatur_Fensterkontakt" -> 6
}

rule "Soll setzen"
when
    Item Heizungsschalter_Alle_Heizungen changed or
    Item gSPOnline changed or
    Item Badezimmerfensterklein_TurFensterstatus changed
then
    var nStart  = 1
    if(Heizungsschalter_Alle_Heizungen.state == OFF) {                // Heizung aus -> Frostschutz 
        gSPOnline.members.forEach[i| hmSoll.put(i.name,6)]
    } else {                                                          // Heizung an
        nStart = 600
        if(gSPOnline.state != OFF)                                    // Anwesenheit -> Komfort
            gSPOnline.members.forEach[i| hmSoll.put(i.name,21)]
        else                                                          // Abwesenheit -> Absenkung
           gSPOnline.members.forEach[i| hmSoll.put(i.name,18)]
                                                                      // Korrektur einzelner Heizkreise
        if(Badezimmerfensterklein_TurFensterstatus.state == OPEN)     // Badfenster
           hmSoll("HeizungBadezimmer_Solltemperatur_Fensterkontakt",6)
    }
    if(triggeringItemName == "Badezimmerfensterklein_TurFensterstatus") {
        if(newState == OPEN)
            nStart = 60
        else
            nStart = 1
    }
    tSoll = createTimer(now.plusSeconds(nStart), [|
        val lItems = gTempSoll.members.sortBy[name].filter[i|
                     (i.state as Number).floatValue != hmSoll.get(i.name)]       // Liste aller Items die vom Soll abweichen
        if(lItems.size == 0)                                                     // falls noch Abweichungen vom Soll bestehen
            return;
        tSoll.reschedule(now.plusSeconds(5))                                     // führe Timer erneut aus
        logInfo("soll","Setze {} auf {}", lItems.head.name, hmSoll.get(i.name))
        lItems.head.sendCommand(hmSoll.get(i.name))                              // Solltemperatur setzen
    ])
end
Nun ist es nur noch eine Rule, die sich um die Temperaturen kümmert. Die Sollwerte werden in einer HashMap gespeichert. Wenn der Timer abläuft, werden die Sollwerte wie gehabt gesetzt, nun aber anhand der HashMap. Im Beispiel habe ich ein paar Beispiel Items eingefügt, im Grunde ist das aber gar nicht nötig, denn die Rule initialisiert die HashMap anhand der Gruppe gSPOnline, man könnte also die Zuordnungen hier auch einfach weg lassen.
Außerdem ließe sich die Rule leicht dahingehend erweitern, dass die Komfortwerte pro Thermostat individuell sind (ginge natürlich auch für die Absenkung und/oder den Frostschutz), dazu muss man nur weitere HashMaps mit den Sollwerten definieren und die Werte aus diesen Voreinstellungen abrufen. Man könnte gar soweit gehen, dass die eingestellten Temperaturen jeweils beim Verlassen des Modus entsprechend gespeichert werden, also Beim Verlassen des Hauses sichert die Rule alle Einstellungen als Komfortwert, anschließend werden die Absenktemperaturen gesetzt. Kommt man wieder, werden die aktuellen Absenktemperaturen gespeichert und die Komfortwerte werden wieder geladen, und das gleiche sinngemäß bei Wechsel nach/von Frostschutz. Nur das Badezimmer muss extra berücksichtigt werden, falls das Fenster gerade auf ist, darf weder Absenk- noch Komforttemperatur überschrieben werden und umgekehrt muss als oberste Priorität der Fensterstatus beim Setzen der Solltemperatur berücksichtigt werden.

Die Verzögerung wird individuell gesetzt, natürlich gehe ich hier davon aus, dass beim Ändern des Fensterstatus alle anderen Thermostate bereits ihre Solltemperatur haben, ansonsten kann sich der Setzvorgang für das Bad natürlich auch mehr als gewollt verzögern...

Re: Hilfe bei 2 Rules

Verfasst: 28. Sep 2024 19:56
von Snatsch
He Udo :)
mit der ersten Rule scheint es jetzt zu laufen :D

Code: Alles auswählen

var Number nSoll = null
var Timer tSoll = null

rule "Solltemperatur setzen"
when
    Item Heizungsschalter_Alle_Heizungen changed or
    Item gSPOnline changed
then
    var nStart  = 1
    if(Heizungsschalter_Alle_Heizungen.state == OFF) {                           // Hauptschalter aus
        nSoll = 6
    } else {                                                                     // Hauptschalter nicht aus
        nSoll = if(gSPOnline.state != OFF) 21 else  18                           // Solltemperatur
        if(gSPOnline.state == OFF) nStart = 600                                  // Zeitverzögerung abhängig von Soll
    }
    gTempSoll.members.filter[i|!(i.state instanceof Number)].forEach[j|          // uninitialisierte Items notfalls initialisieren
        j.postUpdate(19)
    ]
    tSoll?.cancel                                                                // laufende Timer abbrechen

    tSoll = createTimer(now.plusSeconds(nStart), [|                              // nach nStart Sekunden
        val lItems = gTempSoll.members.sortBy[name].filter[i|
                     (i.state as Number).floatValue != nSoll]                    // Liste aller Items die vom Soll abweichen
        if(lItems.size == 0)                                                     // falls noch Abweichungen vom Soll bestehen
            return;
        tSoll.reschedule(now.plusSeconds(5))                                     // führe Timer erneut aus
        logInfo("soll", "Setze {} auf {}", lItems.head.name.toString, nSoll)
        lItems.head.sendCommand(nSoll)                                           // Solltemperatur setzen
    ])
end
Vielen Dank