(solved) Laufzeiten Kompressor und Heizkartusche einer Wärmepumpe erfassen

Einrichtung der openHAB Umgebung und allgemeine Konfigurationsthemen.

Moderatoren: seppy, udo1toni

mike69
Beiträge: 64
Registriert: 17. Nov 2020 22:38
Answers: 0

(solved) Laufzeiten Kompressor und Heizkartusche einer Wärmepumpe erfassen

Beitrag von mike69 »

Hallo an Alle.

Muss leider weiter ausholen. :)
Um den Energieverbrauch zu erfassen, haben wir für die WP Heizung einen Zähler eingebaut. Da kam die Idee auf, die Laufzeiten für den Kompressor und der elektrischen Heizung mit zu erfassen. Da die WP ziemlich einfach gestrickt ist, geht das nur über den Bezug.

0,1kW Grundlast
+0,8kW Kompressor
+3kW Heizkartusche Stufe 1
+6kW Heizkartusche Stufe 2

Daraus ergeben sich mehrere States:
0,9kW = Kompressorbetrieb
3,9kW = Kompressor und Heizpatrone Stufe 1
3,1kW = nur Heizpatrone Stufe 1 usw...

Hier die Rule, abgeleitet von diesem Thread: viewtopic.php?p=62227

Code: Alles auswählen

var long  HeaterStart1 = 0
var long  HeaterStart2 = 0

rule "WP aktiv"
when
    Item NibePower changed
then
var power     = NibePower.state                                        //Energieverbrauch WP
var counter1  = NibeCounter1.state                                     //Laufzeit Kompressor
var counter2  = NibeCounter2.state                                     //Laufzeit Heizpatrone
var counter3  = NibeCounter3.state                                     //Laufzeit Kompressor & Heizpatrone

    if(power >= 240 && power <= 1500) {counter1 = ON}     //Kompressor
        else {counter1 = OFF}

    if(power >= 2800 && power <= 3300) {counter2 = ON}    // Heizkartusche Stufe 1
        else {counter2 = OFF}

    if(power >= 5800 && power <= 6300) {counter2 = ON}    // Heizkartusche Stufe 2
        else {counter2 = OFF}

//    if(power >= 3200 && power <= 4500) {counter3 = ON}    // Kompressor & HP Stufe 1
//        else {counter3 = OFF}

//    if(power >= 6200 && power <= 7500) {counter3 = ON}    // Kompressor & HP Stufe 2
//        else {counter3 = OFF}

    if(NibeCounter1.state != counter1) {
      NibeState1.sendCommand(counter1.toString)
    }
    if(NibeCounter2.state != counter2) {
      NibeState2.sendCommand(counter2.toString)
    }
//    if(NibeCounter3.state != counter3) {
//      NibeState1.sendCommand(counter1.toString) 
//      NibeState2.sendCommand(counter2.toString)
//    }
end

rule "Laufzeit Kompressor"
when
    Item NibeState1 changed
then
    if(newState == OFF) {
      var iCounter1 = 0
      if(NibeCounter1.state instanceof Number)
        iCounter1 = (NibeCounter1.state as Number).intValue
      iCounter1 += (now.toEpochSecond - HeaterStart1).intValue
      logInfo("Nibe WP", "Kompressor Laufzeit heute {} Sekunden", iCounter1)
      NibeCounter1.postUpdate(iCounter1)
    } 
    else {
      HeaterStart1 = now.toEpochSecond
    }
end

rule "Laufzeit Heizkartusche"
when
    Item NibeState2 changed
then
    if(newState == OFF) {
      var iCounter2 = 0
      if(NibeCounter2.state instanceof Number)
        iCounter2 = (NibeCounter2.state as Number).intValue
      iCounter2 += (now.toEpochSecond - HeaterStart2).intValue
      logInfo("Nibe WP", "Heizkartusche Laufzeit {} Sekunden", iCounter2)
      NibeCounter2.postUpdate(iCounter2)
    } 
    else {
      HeaterStart2 = now.toEpochSecond
    }
end

rule "Reset Laufzeit"
when
    Item NibeStateReset changed
then
    if(newState == ON) {
     NibeCounter1.postUpdate(0)
    NibeCounter2.postUpdate(0)
    }
end
hier der zugehörende Item:

Code: Alles auswählen

Number:Time  NibeCounter1   "Laufzeit [%.0f min]"   <time>
Number:Time  NibeCounter2   "Laufzeit [%.0f min]"   <time>
Number:Time  NibeCounter3   "Laufzeit [%.0f min]"   <time>
Number:Time  iCounter1      "Laufzeit [%.0f min]"       <time>
Number:Time  iCounter2      "Laufzeit [%.0f min]"       <time>

Switch       NibeState1                                                 <switch>     (gNibe)
Switch       NibeState2                                                 <switch>     (gNibe)
Switch       NibeStateReset                                         <switch>     (gNibe)
Jede Wärmequelle für sich zählt die Laufzeit hoch. Wenn beides läuft, was öfters vorkommt, kommen sie sich in die Quere.

Mit dieser Rule klappt es, sieht irgendwie nicht so elegannt aus:

Code: Alles auswählen

rule "WP aktiv"
when
    Item NibePower changed
then
var power     = NibePower.state                           //Energieverbrauch WP
var counter1  = NibeCounter1.state                        //Laufzeit Kompressor
var counter2  = NibeCounter2.state                        //Laufzeit Heizpatrone

// beides aus
    if(power <= 200) counter1 = OFF
    if(power <= 200) counter2 = OFF

// nur Kompressor
    if(power >= 240  && power <= 1500) counter1 = ON
    if(power >= 240  && power <= 1500) counter2 = OFF

// nur Heizpatrone
    if(power >= 2800  && power <= 3200) counter1 = OFF
    if(power >= 2800  && power <= 3200) counter1 = ON

    if(power >= 5800  && power <= 6200) counter1 = OFF
    if(power >= 5800  && power <= 6200) counter1 = ON

// Kompressor und Heizpatrone
    if(power >= 3200 && power <= 4500) counter1 = ON    
    if(power >= 3200 && power <= 4500) counter2 = ON    

    if(power >= 6200 && power <= 7500) counter1 = ON
    if(power >= 6200 && power <= 7500) counter2 = ON


    if(NibeCounter1.state != counter1) {
      NibeState1.sendCommand(counter1.toString)
    }
    if(NibeCounter2.state != counter2) {
      NibeState2.sendCommand(counter2.toString)
   }
end

Wie wuppe ich das am besten?

edit1:
Bin ein bischen weiter, aktuell sieht es so aus:

Code: Alles auswählen

rule "WP aktiv"
when
    Item NibePower changed
then
var power     = NibePower.state                           //Energieverbrauch WP
var counter1  = NibeCounter1.state                        //Laufzeit Kompressor
var counter2  = NibeCounter2.state                        //Laufzeit Heizpatrone

// Kompressor
    if(power >= 240 && power <= 1500 || power >= 3600 && power <= 4400 || power >= 6600 && power <= 7400) {
      counter1 = ON
    }
    else {
      counter1 = OFF
    }

// Heizkartusche
    if(power >= 2900 && power <= 4400 || power >= 5900 && power <= 7400) {
      counter2 = ON
    }
    else {
      counter2 = OFF
    }

    if(NibeCounter1.state != counter1) {
      NibeState1.sendCommand(counter1.toString)
    }
    if(NibeCounter2.state != counter2) {
      NibeState2.sendCommand(counter2.toString)
    }
end


Gruß
von udo1toni » 20. Okt 2024 03:32
Das eigentliche Problem mit der Messung besteht darin, dass es verschiedene Situationen gibt, wo das ganze schief gehen kann, eben wenn openHAB neu gestartet wird (oder auch nur die Rules-Datei neu eingelesen wird, in der die globalen Variablen definiert sind).
Eine Möglichkeit, damit umzugehen, wäre, tatsächlich die Schaltzeitpunkte über die Persistence zu speichern.
Du müsstest also die Items NibeState1 bis NibeState3 persistieren. Innerhalb der Rule müsste es dann möglich sein, den Zeitpunkt des vorletzten Statuswechsel zu ermitteln.
Erfolgreich getestet habe ich folgende Rules (Achtung: ich habe die Itemnamen geändert, aus Gründen...)
Itemnamen:

Code: Alles auswählen

Group gNibeCount
Group gNibeState
Number:Time NibeCounter_1 "Kompressor"  (gNibeCount)
Number:Time NibeCounter_2 "Heizstufe 1" (gNibeCount)
Number:Time NibeCounter_3 "Heizstufe 2" (gNibeCount)
Switch      NibeState_1   "Kompressor"  (gNibeState)
Switch      NibeState_2   "Heizstufe 1" (gNibeState)
Switch      NibeState_3   "Heizstufe 2" (gNibeState)
Number:Power NibePower    "Leistung"
In influxdb.persist musst Du gNibeCount* und gNibeState* eintragen, beide bestenfalls mit everyChange, restoreOnStartup. Der * am Itemnamen bedeutet, dass nicht das Item selbst persistiert wird, sondern seine Kinder.

Rules:

Code: Alles auswählen

rule "WP aktiv"
when
    Item NibePower changed
then
    var power     = (newState as Number).floatValue  // Energieverbrauch WP
    var OnOffType counter1  = OFF                    // Default Counter aus
    var OnOffType counter2  = OFF                    // Default Counter aus
    var OnOffType counter3  = OFF                    // Default Counter aus

    if(power > 3000) {                               // über 3 kW -> Heizpatrone 1 muss an sein
        counter2 = ON
        power = power - 3000                         // Leistung von Heizpatrone abziehen
    }
    if(power > 3000) {                               // über 3 kW -> Heizpatrone 2 muss an sein
        counter3 = ON
        power = power - 3000                         // Leistung von Heizpatrone abziehen
    }
    if(power > 600) {                                // über 600 W -> Kompressor muss an sein
        counter1 = ON
    }

    if(NibeState_1.state != counter1)
        NibeState_1.postUpdate(counter1.toString)

    if(NibeState_2.state != counter2)
        NibeState_2.postUpdate(counter2.toString)

    if(NibeState_3.state != counter3)
        NibeState_3.postUpdate(counter3.toString)
end

rule "Laufzeit bestimmen"
when
    Member of gNibeState changed to OFF
then
    val strItem = triggeringItem.name.split("_").get(1)
    val nCount = gNibeCount.members.filter[i|i.name.endsWith(strItem)].head
    val nStart = triggeringItem.previousState(true,"influxdb").timestamp.toEpochSecond
    var strDev = ""
    switch(strItem) {
        case "1" : strDev = "Kompressor"
        case "2" : strDev = "Heizstufe 1"
        case "3" : strDev = "Heizstufe 2"
    }
    var iCounter = 0
    if(nCount.state instanceof Number)
        iCounter = (nCount.state as Number).intValue
    iCounter += (now.toEpochSecond - nStart).intValue
        logInfo("nibeWp", "Laufzeit {} total {} Sekunden", strDev, iCounter)
      nCount.postUpdate(iCounter)
end
Upsi...

Die erste Rule kümmert sich darum, abhängig von der abgerufenen Leistung die drei Verbraucher zu detektieren (bzw. die zwei Stufen des einen Verbrauchers plus den anderen...)
Die zweite Rule löst aus, wenn einer der Verbraucher ausgeschaltet wird. Zunächst ermittelt die Rule anhand des letzten Teilstrings nach dem _ welches Item genau die Rule getriggert hat. als nächstes wird der zugehörige Counter aus der Gruppe geladen und im Objekt nCount verfügbar gemacht.
Dann wird der Startzeitpunkt des Verbrauchers ermittelt, der gerade abgeschaltet wurde. Dies geschieht, indem aus der Datenbank der zugehörige Zeitpunkt (.timestamp) des persistierten vorherigen Zustands (.previousState) ausgelesen wird. Das true bewirkt, dass sich der Status vom aktuellen Status unterscheiden muss.
Der nächste Block wird nur benötigt, damit die Logmeldung den Namen des Geräts im Klartext ausgeben kann :) ansonsten könnte man auf die Variable strDev und den switch-Block auch verzichten.
Nun wird wie gehabt die Laufzeit ermittelt, indem die Differenz von Jetzt und Start gebildet, und zum aktuellen Zählerstand addiert wird.
Abschließend wird der Wert im passenden Counter gespeichert.
Auch die erste Rule kann durch die Gruppe noch etwas optimiert werden:

Code: Alles auswählen

import java.util.HashMap

rule "WP aktiv"
when
    Item NibePower changed
then
    var power     = (newState as Number).floatValue  // Energieverbrauch WP
    val HashMap<String,OnOffType> hmStat = newHashMap("NibeState_1" -> OFF,"NibeState_2" -> OFF,"NibeState_3" -> OFF)

    if(power > 3000) {                               // über 3 kW -> Heizpatrone 1 muss an sein
        hmStat.put("NibeState_2",ON)
        power = power - 3000                         // Leistung von Heizpatrone abziehen
    }
    if(power > 3000) {                               // über 3 kW -> Heizpatrone 2 muss an sein
        hmStat.put("NibeState_3",ON)
        power = power - 3000                         // Leistung von Heizpatrone abziehen
    }
    if(power > 600) {                                // über 600 W -> Kompressor muss an sein
        hmStat.put("NibeState_1",ON)
    }
    gNibeState.members.forEach[i|
        if(i.state != hmStat.get(i.name))
            i.postUpdate(hmStat.get(i.name).toString)
    ]
end
Allerdings benötigen wir eine HashMap, also auch einen Import zu Beginn der Datei.
Die gewünschten Status werden nun in der HashMap gespeichert, weshalb man in der forEach-Schleife einfach über die HashMap auf den passenden Wert zugreifen kann. Die Funktion als solche bleibt gleich.
Natürlich ist die Einsparung hier eher marginal, das soll eher als eine Art Proof of Concept dienen (oder nenne mich einfach Spielkind...)
Auch die optimierte Fassung der Rule funktioniert bei mir korrekt. 8-)
Gehe zur vollständigen Antwort
Zuletzt geändert von mike69 am 20. Okt 2024 21:56, insgesamt 2-mal geändert.
openHAB 4.2.0 auf Debian 12 als VM unter Proxmox

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

Re: Laufzeiten Kompressor und Heizkartusche einer Wärmepumpe erfassen

Beitrag von udo1toni »

Andere Herangehensweise:

Code: Alles auswählen

rule "WP aktiv"
when
    Item NibePower changed
then
    var power     = NibePower.state                  // Energieverbrauch WP
    var counter1  = OFF                              // Default Counter aus
    var counter2  = OFF                              // Default Counter aus
    var counter3  = OFF                              // Default Counter aus

    if(power > 3000) {                               // über 3 kW -> Heizpatrone 1 muss an sein
        counter2 = ON
        power = power - 3000                         // Leistung von Heizpatrone abziehen
    }
    if(power > 3000) {                               // über 3 kW -> Heizpatrone 2 muss an sein
        counter3 = ON
        power = power - 3000                         // Leistung von Heizpatrone abziehen
    }
    if(power > 800) {                                // über 800 W -> Kompressor muss an sein
        counter1 = ON
    }

    if(NibeCounter1.state != counter1)
        NibeState1.postUpdate(counter1.toString)

    if(NibeCounter2.state != counter2)
        NibeState2.postUpdate(counter2.toString)

    if(NibeCounter3.state != counter3)
        NibeState3.postUpdate(counter3.toString)
end
Die Rule setzt einen Default Wert OFF für die drei Status und prüft anschließend auf den Grenzwert 3 kW. Ist der überschritten, so muss die erste Heizpatrone aktiv sein, entsprechend wird das Flag gesetzt und die Leistungsaufnahme der Heizpatrone abgezogen.
Jetzt wird wieder auf ein Überschreiten der 3 kW geprüft. Ist das der Fall, so muss auch die zweite Heizpatrone aktiv sein -> Flag wird aktiviert und es wird wieder die entsprechende Leistung abgezogen.
Nun muss nur noch geprüft werden, ob die übrig gebliebene Leistung über 800 W ist, ist das der Fall, so muss auch der Kompressor eingeschaltet sein.
Abschließend werden die Status in die Items geschrieben, und zwar per postUpdate, nicht per sendCommand. Der Unterschied: ein sendCommand sendet einen Befehl über das Item an damit verlinkte Channel. Anschließend ermittelt openHAB als Default Verhalten den wahrscheinlichen neuen Status des Items und erzeugt ein postUpdate, welches den Status des Items setzt. postUpdate setzt den Status direkt. Da Du das Item nicht benötigst, um irgendwas extern zu steuern, reicht das postUpdate völlig aus.

Ein anderes Detail: Im Code oben verwendest Du durchaus die geschweiften Klammern {}, unten aber nicht. {} markiert einen Anweisungsblock. Statt also

Code: Alles auswählen

if(power >= 240  && power <= 1500) counter1 = ON
if(power >= 240  && power <= 1500) counter2 = OFF
zu schreiben könntest Du genauso gut auch

Code: Alles auswählen

    if(power >= 240  && power <= 1500) {
    counter1 = ON
    counter2 = OFF
}
schreiben.
Falls Du keinen gesonderten Zähler für die zweite Heizpatrone haben willst, kannst Du die Variable counter3 und das Item NibeState3 auch weg lassen (aber NICHT die zweite if-Anweisung!!!, Falls die zweite Stufe eingeschaltet ist, müssen die 3 kW ja trotzdem abgezogen werden, damit die Restleistung nur noch Grundlast und evtl. Kompressor enthält)
Achte auch auf die Itemnamen... NibeCounterX enthält die Zeit, NibeStateX enthält den Zustand ON/OFF, entsprechend ist die Prüfung auf Ungleichheit in Deiner Rule immer erfüllt, die Rule soll die Itemstatus aber nur bei Bedarf ändern.

Wenn Du ein Group Item gNibeCount anlegst, dort drei Items Number:Time als Member hinzufügst und die Itemnamen der Status Items leicht abänderst, kannst Du den Code weiter optimieren:

Code: Alles auswählen

var long  nNibeStart1 = 0
var long  nNibeStart2 = 0
var long  nNibeStart3 = 0

rule "Laufzeit Nibe"
when
    Item NibeState_1 changed or
    Item NibeState_2 changed or
    Item NibeState_3 changed
then
    val nState = triggeringItemName.split("_").get(1)
    var nStart = 0
    var strName = ""
    switch(nState) {
        case 1: {
            nStart = nNibeStart1 
            strName = "Kompressor"
        }
        case 2: {
            nStart = nNibeStart2 
            strName = "Heizpatrone 1"
        }
        case 3: {
            nStart = nNibeStart3 
            strName = "Heizpatrone 2"
        }
    }
    val Count = gNibeCount.members.filter[i|i.name.endsWith(nState)].head
    if(newState == OFF) {
      var iCounter = 0
      if(Count.state instanceof Number)
          iCounter = (Count.state as Number).intValue
      iCounter += (now.toEpochSecond - nStart).intValue
      Count.postUpdate(iCounter)
      logInfo("nibeWP", "Laufzeit {} seit Reset {} Sekunden", strName, iCounter)
    } 
    else 
        switch(nState) {
            case 1: nNibeStart1 = now.toEpochSecond
            case 2: nNibeStart2 = now.toEpochSecond
            case 3: nNibeStart3 = now.toEpochSecond
        }
end

rule "Reset Laufzeit"
when
    Item NibeStateReset changed to ON
then
    gNibeCount.forEach[i|i.postUpdate(0)]
    NibeStateReset.postUpdate(OFF)
end
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

mike69
Beiträge: 64
Registriert: 17. Nov 2020 22:38
Answers: 0

Re: Laufzeiten Kompressor und Heizkartusche einer Wärmepumpe erfassen

Beitrag von mike69 »

Danke dir, Udo.

Wir haben nur eine Heizpatrone, und die hat mehrere Stufen zum schalten, 3kW, 6kW und 9kW. wobei die letzte Stufe deaktiviert ist.

Noch was anderes, hier die Rule für die Laufzeit des Kompressors:

Code: Alles auswählen

rule "Laufzeit Kompressor"

when
    Item NibeState1 changed
then
    if(newState == OFF) {
      var iCounter1 = 0
      if(NibeCounter1.state instanceof Number)
        iCounter1 = (NibeCounter1.state as Number).intValue
        iCounter1 += (now.toEpochSecond - HeaterStart1).intValue
        logInfo("Nibe WP", "Kompressor Laufzeit heute {} Sekunden", iCounter1)
        NibeCounter1.postUpdate(iCounter1)
    } 
    else {
      HeaterStart1 = now.toEpochSecond
    }
end
Zählt hoch bis zum nächsten Neustart, soll permanent werden.
Als DB steht influxdb zur Verfügung, nur weiss ich beim besten Willen nicht, wo dieses

Code: Alles auswählen

, "influxdb"

hinkommt, um InfluxDB zu nutzen.
NibeState1, 2 und 3 sind in der influxdb.persist als Item eingetragen.

edit1:
Habe deinen zweiten Teil mit dem 3ten Counter voll übersehen, sorry.
Dann kann ich die Frage löschen.
Abgesehen davon, man sieht, wann die 2te Stufe sich zuschaltet. Lass ich drinne, zumindest als Laufzeiterfassung.
In der Basic UI reicht die Info Kompressor oder Heizpatrone ja/nein.
openHAB 4.2.0 auf Debian 12 als VM unter Proxmox

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

Re: Laufzeiten Kompressor und Heizkartusche einer Wärmepumpe erfassen

Beitrag von udo1toni »

mike69 hat geschrieben: 18. Okt 2024 17:07 Zählt hoch bis zum nächsten Neustart, soll permanent werden.
Also am ehesten eine Art Betriebsstunden (hier -sekunden) Zähler? Die einfachste Lösung ist, das Item zu persistieren. Du kannst für jeden Persistence Service pro Item separat festlegen, was die Persistence tun soll. Du hast die beiden Items NibeCounter1 und NibeCounter2 für den Zählerstand, diese werden nur beim Ein-/Ausschalten des jeweiligen Verbrauchers upgedatet. Entsprechend sollte es ausreichen, in der influxdb.persist für diese beiden Items einen Eintrag vorzunehmen:

Code: Alles auswählen

NibeCounter1, NibeCounter2 : strategy = everyChange, restoreOnStartup
Alternativ geht das auch direkt über die Main UI (seit V4.1.x?), solange man keine aktive influxdb.persist hat.

Der Eintrag bewirkt, dass jede Wertänderung direkt in der influxdb persistiert wird. Bei einem Neustart von openHAB wird der zuletzt gespeicherte Wert aus der influxdb gelesen und in das jeweilige Item übernommen. Innerhalb der Rule liest Du den aktuellen Status ein und addierst die Anzahl Sekunden zwischen ON und OFF, das sollte also direkt funktionieren, ganz ohne spezielle Zugriffe auf die Persistence.

Es gibt natürlich ein paar Fehlerquellen, die aber vor allem unglückliche Umstände betreffen, hauptsächlich ein Restart von openHAB während ein Zähler aktiv ist. Da dabei die Startzeit verloren geht, wird die Rule beim Berechnen der Laufzeit auf jeden Fall eine Exception melden.
Vermeidbar wäre dies, indem Du die Items NibeState1-NibeState3 persistierst und zur Berechnung der Betriebsstunden bei changed to OFF die Persistence befragst, wann zuletzt von OFF nach ON gewechselt wurde. Das kann allerdings auch etwas tricky sein :) Mit Datum und Zeit zu rechnen ist immer eine Herausforderung...
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

mike69
Beiträge: 64
Registriert: 17. Nov 2020 22:38
Answers: 0

Re: Laufzeiten Kompressor und Heizkartusche einer Wärmepumpe erfassen

Beitrag von mike69 »

udo1toni hat geschrieben: 18. Okt 2024 20:50
mike69 hat geschrieben: 18. Okt 2024 17:07 Zählt hoch bis zum nächsten Neustart, soll permanent werden.
Also am ehesten eine Art Betriebsstunden (hier -sekunden) Zähler?
Die einfachste Lösung ist, das Item zu persistieren. Du kannst für jeden Persistence Service pro Item separat festlegen, was die Persistence tun soll. Du hast die beiden Items NibeCounter1 und NibeCounter2 für den Zählerstand, diese werden nur beim Ein-/Ausschalten des jeweiligen Verbrauchers upgedatet. Entsprechend sollte es ausreichen, in der influxdb.persist für diese beiden Items einen Eintrag vorzunehmen:

Code: Alles auswählen

NibeCounter1, NibeCounter2 : strategy = everyChange, restoreOnStartup
Ist geschehen, NibeCounterX eingetragen. Hätte NibeStatesX erwartet :lol:
Ja, genau, die Betriebsstunden, je für Kompressor, Heizpatrone Stufe 1 und 2.

Aber, muss die rule nicht umgeschrieben werden? Zugriff zur InfluxDB, damit bei Start/Stop die Laufzeiten angezeigt werden?

Mit einem

Code: Alles auswählen

iCounter1 += (now.toEpochSecond - HeaterStart1).intValue
klappt das auch?

sollte nicht so was rein?

Code: Alles auswählen

iCounter1 += (now.toEpochSecond - NibeCount1.lastChange("influxdb").toEpochSecond).intValue
Hattest du mal erwähnt hier. viewtopic.php?p=62246#p62246

Ich lass das erstmal laufen. Danke Dir. :D
openHAB 4.2.0 auf Debian 12 als VM unter Proxmox

mike69
Beiträge: 64
Registriert: 17. Nov 2020 22:38
Answers: 0

Re: Laufzeiten Kompressor und Heizkartusche einer Wärmepumpe erfassen

Beitrag von mike69 »

Moin.

Sobald die 1te Stufe der Heizpatrone sich zuschaltet, kommen diese Meldungen:

Code: Alles auswählen

2024-10-19 10:37:09.918 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'test3-1' failed: Unknown variable or command '-'; line 16, column 17, length 12 in test3
2024-10-19 10:37:10.975 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'test3-1' failed: Unknown variable or command '-'; line 16, column 17, length 12 in test3
2024-10-19 10:37:12.027 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'test3-1' failed: Unknown variable or command '-'; line 16, column 17, length 12 in test3
2024-10-19 10:37:13.078 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'test3-1' failed: Unknown variable or command '-'; line 16, column 17, length 12 in test3

Hier die Rule:

Code: Alles auswählen

rule "WP aktiv"
when
    Item NibePower changed
then
    var power     = NibePower.state                  // Energieverbrauch WP
    var counter1  = OFF                              // Default Counter aus
    var counter2  = OFF                              // Default Counter aus
    var counter3  = OFF                              // Default Counter aus

    if(power > 3000) {                               // über 3 kW -> Heizpatrone 1 muss an sein
        counter2 = ON
        power = power - 3000                         // Leistung von Heizpatrone abziehen
    }
    if(power > 3000) {                               // über 3 kW -> Heizpatrone 2 muss an sein
        counter3 = ON
        power = power - 3000                         // Leistung von Heizpatrone abziehen
    }
    if(power > 600) {                                // über 600 W -> Kompressor muss an sein
        counter1 = ON
    }

    if(NibeCounter1.state != counter1)
        NibeState1.postUpdate(counter1.toString)

    if(NibeCounter2.state != counter2)
        NibeState2.postUpdate(counter2.toString)

    if(NibeCounter3.state != counter3)
        NibeState3.postUpdate(counter3.toString)
end
Hier die Zeile 16:

Code: Alles auswählen

        power = power - 3000                         // Leistung von Heizpatrone abziehen 
Es werden die Start/Stop Zeiten des Kompressors in InfluxDB erfasst. In der persist sind eingetragen: NibeStateX, NibeCounterX und deren Gruppe, um zu sehen was durchschlägt.

Code: Alles auswählen

    gNIBE*					: strategy = everyChange, restoreOnStartup
    NibeState1, NibeState2, NibeState3		: strategy = everyChange, restoreOnStartup
    NibeCounter1, NibeCounter2, NibeCounter3	: strategy = everyChange, restoreOnStartup
    
NibeState1 liefert 1 und 0 für an/aus:

Code: Alles auswählen


_Time				value	Item
2024-10-19 00:46:00 GMT+2	1	NibeState1
2024-10-19 01:14:00 GMT+2	0	NibeState1
2024-10-19 04:44:00 GMT+2	1	NibeState1
2024-10-19 04:48:00 GMT+2	0	NibeState1
...

Und die Werte NibeCounter1 kann ich überhaupt nicht zuordnen.

Code: Alles auswählen

2024-10-19 09:48:00 GMT+2	1.729.324.001	NibeCounter1
2024-10-19 09:52:00 GMT+2	-836.319.002	NibeCounter1	
2024-10-19 10:00:00 GMT+2	1.729.324.734	NibeCounter1
2024-10-19 10:04:00 GMT+2	1.729.324.960	NibeCounter1
...
ps:
Habe über ne halbe Stunde verballert, dass der Code irgendwie sauber dargestellt wird. gibt es da einen Trick?
openHAB 4.2.0 auf Debian 12 als VM unter Proxmox

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

Re: Laufzeiten Kompressor und Heizkartusche einer Wärmepumpe erfassen

Beitrag von udo1toni »

Ähm... ja, ich denke mal, Du musst den Wert explizit nach Number casten, am besten so:

Code: Alles auswählen

ule "WP aktiv"
when
    Item NibePower changed
then
    var power     = (newState as Number).floatValue  // Energieverbrauch WP
newState enthält den Status von NibePower, da dieses Item die Rule per changed getriggert hat.
Falls NibePower QuantityType zurückliefert, muss außerdem die Einheit gestrippt werden, dafür sorgt .floatValue.
Außerdem scheint es, dass openHAB die Variablen hier typisiert haben möchte, weil es OFF nicht zweifelsfrei zuordnen kann.
also so:

Code: Alles auswählen

    var OnOffType counter1  = OFF                    // Default Counter aus
    var OnOffType counter2  = OFF                    // Default Counter aus
    var OnOffType counter3  = OFF                    // Default Counter aus
Damit läuft die Rule bei mir fehlerfrei durch...

Was die Werte von NibeCounterX betrifft, so wird da die Startzeit leer gewesen sein.
Ich dachte eigentlich, gestern noch eine Antwort dazu geschickt zu haben... Mal schauen, ob ich auf der Arbeit dazu komme, etwaS ausführlicher zu schreiben...
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

mike69
Beiträge: 64
Registriert: 17. Nov 2020 22:38
Answers: 0

Re: Laufzeiten Kompressor und Heizkartusche einer Wärmepumpe erfassen

Beitrag von mike69 »

Nabend.

Keine Hektik, das is Hobby. :)
Mach, wenn Zeit ist.
openHAB 4.2.0 auf Debian 12 als VM unter Proxmox

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

Re: Laufzeiten Kompressor und Heizkartusche einer Wärmepumpe erfassen

Beitrag von udo1toni »

Das eigentliche Problem mit der Messung besteht darin, dass es verschiedene Situationen gibt, wo das ganze schief gehen kann, eben wenn openHAB neu gestartet wird (oder auch nur die Rules-Datei neu eingelesen wird, in der die globalen Variablen definiert sind).
Eine Möglichkeit, damit umzugehen, wäre, tatsächlich die Schaltzeitpunkte über die Persistence zu speichern.
Du müsstest also die Items NibeState1 bis NibeState3 persistieren. Innerhalb der Rule müsste es dann möglich sein, den Zeitpunkt des vorletzten Statuswechsel zu ermitteln.
Erfolgreich getestet habe ich folgende Rules (Achtung: ich habe die Itemnamen geändert, aus Gründen...)
Itemnamen:

Code: Alles auswählen

Group gNibeCount
Group gNibeState
Number:Time NibeCounter_1 "Kompressor"  (gNibeCount)
Number:Time NibeCounter_2 "Heizstufe 1" (gNibeCount)
Number:Time NibeCounter_3 "Heizstufe 2" (gNibeCount)
Switch      NibeState_1   "Kompressor"  (gNibeState)
Switch      NibeState_2   "Heizstufe 1" (gNibeState)
Switch      NibeState_3   "Heizstufe 2" (gNibeState)
Number:Power NibePower    "Leistung"
In influxdb.persist musst Du gNibeCount* und gNibeState* eintragen, beide bestenfalls mit everyChange, restoreOnStartup. Der * am Itemnamen bedeutet, dass nicht das Item selbst persistiert wird, sondern seine Kinder.

Rules:

Code: Alles auswählen

rule "WP aktiv"
when
    Item NibePower changed
then
    var power     = (newState as Number).floatValue  // Energieverbrauch WP
    var OnOffType counter1  = OFF                    // Default Counter aus
    var OnOffType counter2  = OFF                    // Default Counter aus
    var OnOffType counter3  = OFF                    // Default Counter aus

    if(power > 3000) {                               // über 3 kW -> Heizpatrone 1 muss an sein
        counter2 = ON
        power = power - 3000                         // Leistung von Heizpatrone abziehen
    }
    if(power > 3000) {                               // über 3 kW -> Heizpatrone 2 muss an sein
        counter3 = ON
        power = power - 3000                         // Leistung von Heizpatrone abziehen
    }
    if(power > 600) {                                // über 600 W -> Kompressor muss an sein
        counter1 = ON
    }

    if(NibeState_1.state != counter1)
        NibeState_1.postUpdate(counter1.toString)

    if(NibeState_2.state != counter2)
        NibeState_2.postUpdate(counter2.toString)

    if(NibeState_3.state != counter3)
        NibeState_3.postUpdate(counter3.toString)
end

rule "Laufzeit bestimmen"
when
    Member of gNibeState changed to OFF
then
    val strItem = triggeringItem.name.split("_").get(1)
    val nCount = gNibeCount.members.filter[i|i.name.endsWith(strItem)].head
    val nStart = triggeringItem.previousState(true,"influxdb").timestamp.toEpochSecond
    var strDev = ""
    switch(strItem) {
        case "1" : strDev = "Kompressor"
        case "2" : strDev = "Heizstufe 1"
        case "3" : strDev = "Heizstufe 2"
    }
    var iCounter = 0
    if(nCount.state instanceof Number)
        iCounter = (nCount.state as Number).intValue
    iCounter += (now.toEpochSecond - nStart).intValue
        logInfo("nibeWp", "Laufzeit {} total {} Sekunden", strDev, iCounter)
      nCount.postUpdate(iCounter)
end
Upsi...

Die erste Rule kümmert sich darum, abhängig von der abgerufenen Leistung die drei Verbraucher zu detektieren (bzw. die zwei Stufen des einen Verbrauchers plus den anderen...)
Die zweite Rule löst aus, wenn einer der Verbraucher ausgeschaltet wird. Zunächst ermittelt die Rule anhand des letzten Teilstrings nach dem _ welches Item genau die Rule getriggert hat. als nächstes wird der zugehörige Counter aus der Gruppe geladen und im Objekt nCount verfügbar gemacht.
Dann wird der Startzeitpunkt des Verbrauchers ermittelt, der gerade abgeschaltet wurde. Dies geschieht, indem aus der Datenbank der zugehörige Zeitpunkt (.timestamp) des persistierten vorherigen Zustands (.previousState) ausgelesen wird. Das true bewirkt, dass sich der Status vom aktuellen Status unterscheiden muss.
Der nächste Block wird nur benötigt, damit die Logmeldung den Namen des Geräts im Klartext ausgeben kann :) ansonsten könnte man auf die Variable strDev und den switch-Block auch verzichten.
Nun wird wie gehabt die Laufzeit ermittelt, indem die Differenz von Jetzt und Start gebildet, und zum aktuellen Zählerstand addiert wird.
Abschließend wird der Wert im passenden Counter gespeichert.
Auch die erste Rule kann durch die Gruppe noch etwas optimiert werden:

Code: Alles auswählen

import java.util.HashMap

rule "WP aktiv"
when
    Item NibePower changed
then
    var power     = (newState as Number).floatValue  // Energieverbrauch WP
    val HashMap<String,OnOffType> hmStat = newHashMap("NibeState_1" -> OFF,"NibeState_2" -> OFF,"NibeState_3" -> OFF)

    if(power > 3000) {                               // über 3 kW -> Heizpatrone 1 muss an sein
        hmStat.put("NibeState_2",ON)
        power = power - 3000                         // Leistung von Heizpatrone abziehen
    }
    if(power > 3000) {                               // über 3 kW -> Heizpatrone 2 muss an sein
        hmStat.put("NibeState_3",ON)
        power = power - 3000                         // Leistung von Heizpatrone abziehen
    }
    if(power > 600) {                                // über 600 W -> Kompressor muss an sein
        hmStat.put("NibeState_1",ON)
    }
    gNibeState.members.forEach[i|
        if(i.state != hmStat.get(i.name))
            i.postUpdate(hmStat.get(i.name).toString)
    ]
end
Allerdings benötigen wir eine HashMap, also auch einen Import zu Beginn der Datei.
Die gewünschten Status werden nun in der HashMap gespeichert, weshalb man in der forEach-Schleife einfach über die HashMap auf den passenden Wert zugreifen kann. Die Funktion als solche bleibt gleich.
Natürlich ist die Einsparung hier eher marginal, das soll eher als eine Art Proof of Concept dienen (oder nenne mich einfach Spielkind...)
Auch die optimierte Fassung der Rule funktioniert bei mir korrekt. 8-)
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

mike69
Beiträge: 64
Registriert: 17. Nov 2020 22:38
Answers: 0

Re: Laufzeiten Kompressor und Heizkartusche einer Wärmepumpe erfassen

Beitrag von mike69 »

Läuft, mit viel weniger Code, großen Dank. :).

Nach einem Neustart von openHAB wird über eine nicht vorhandene persistence gemeckert, Nach einem refresh der UI passt aber alles. Eventuell braucht der persistence Service bissl länger zum starten.

Jetzt noch die Konvertierung der Laufzeit in Stunden/Minuten. Habe irgenwo ein JS gesehen hier im Forum, welches die Zeit in hh:mm:ss umwandelt.
Dann wäre es perfekt. :)
openHAB 4.2.0 auf Debian 12 als VM unter Proxmox

Antworten