Tägliche Regendauer in Sekunden

Für welche Projekte verwendet Ihr OpenHAB? Was habt Ihr automatisiert? Stellt eure Projekte hier vor.

Moderatoren: Cyrelian, seppy

Antworten
Benutzeravatar
Florian.Reinartz
Beiträge: 112
Registriert: 11. Apr 2022 08:47
Answers: 0
Wohnort: bei Schwerin

Tägliche Regendauer in Sekunden

Beitrag von Florian.Reinartz »

Moin Zusammen,

ich habe meine Wetterstation ausgetauscht und versuche nun alle verwendeten/benötigten Items umzustellen.
Leider habe ich keinen fertigen Channel für die täglichen Regenstunden.
Kein Problem... dachte ich :oops:

Ich versuche seit Stunden eine Rule zu schreiben die die Zeit in Sekunden erfasst die das Item "HomeMatic_Regensensor_Regen_ja_nein" täglich "ON" war.
Um Mitternacht soll der Zähler dann (auch wenn es grade regnet) zurück gesetzt werden.
Basierend auf diesem post viewtopic.php?t=7411
und diesem post viewtopic.php?t=3170
habe ich schon viel ausprobiert ...aber :cry:

Nun bin ich zu diesem Ergebnis gekommen aber es läuft etwas holprig.

Code: Alles auswählen

rule "Zeitpunkt Regenbeginn"
    when
        //Time cron "*/30 * * * * ?" or
        Item HomeMatic_Regensensor_Regen_ja_nein changed to ON
    then
        Regen_Beginn.postUpdate(now.toEpochSecond)
        if(RegenSekunden.state == NULL)
        {
            Regendauer_vor_Schauer.postUpdate(0)
            RegenSekunden.postUpdate(0)
        }
        else
        {
            Regendauer_vor_Schauer.postUpdate(RegenSekunden.state)
        }
end

rule "tägliche Regensekunden"
    when
        Time cron "*/10 * * * * ?"
    then
        if(HomeMatic_Regensensor_Regen_ja_nein.state == ON)
        {
            val Start   = (Regen_Beginn.state as DecimalType)
            val Now     = now.toEpochSecond
            val Diff    = Now - Start
            Regenschauer_Dauer.postUpdate(Diff)
            RegenSekunden.postUpdate(Regendauer_vor_Schauer.state as DecimalType + Regenschauer_Dauer.state as DecimalType)
        }
end

rule "Regensekunden zurück setzen"
    when
        Time cron "5 0 0 * * ?" 
    then
        RegenSekunden.postUpdate(0)
end
Vermutlich da ich die "Regenschauer_Dauer" und die "Regendauer_vor_Schauer" in items schreibe...

Kann ich hier noch was optimieren oder gibt es in zwischen einen fertigen Baustein für so etwas?

Danke und Gruß
Florian
openHAB 4.3.0 (64 bit) auf einem Raspberry Pi 5 Model B Rev 1.0 mit 8GB

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

Re: Tägliche Regendauer in Sekunden

Beitrag von udo1toni »

Grundsätzlich sollten die Rules funktionieren, was genau läuft denn holprig?
Eventuell solltest Du den Zählerreset auf Punkt 0 definieren und die täglichen Regensekunden auf 1/10 statt */10, 1/10 läuft alle zehn Sekunden, bedinnend mit der ersten Sekunde nach voll also 1, 11, 21, 31, 41, 51, während */100 alle zehn Sekunden ausgeführt wird, beginnend mit der Sekunde, in der die Rule vom System aktiv nutzbar ist (das kann dann auch 5 sein, womit die beiden Rules sich evtl. in die Quere kommen könnten)
Weiter könntest Du globale Variablen statt der Items nutzen, der Zugriff auf Variablen ist schneller als der auf den Status verschiedener Items.

Z.B. so:

Code: Alles auswählen

// globale Variablen vor der ersten Rule innerhalb der Datei definieren!
var Timer   tRegen      = null                           // Zeiger für den Timer
var Long    lStartRegen = null                           // Startzeitpunkt für Messfenster
var int iRegenDauer = 0                                  // Summe

rule "Regen Beginn oder Ende"
when
    Item HomeMatic_Regensensor_Regen_ja_nein changed     // triggert zu Beginn und beim Ende des Regens
then
    if(newState == ON) {                                 // Falls Regen beginnt
        tRegen?.cancel                                   // sicherheitshalber Timer löschen, falls existent
        lStartRegen = now.toEpochSecond                  // sichere Start des Zeitfensters
        tRegen = createTimer(now.plusSeconds(10), [|     // Timer starten - NAch Ablauf von 10 Sekunden
            iRegenDauer += 10                            // Addiere 10 Sekunden (Dauer des Timers...)
            lStartRegen = now.toEpochSecond              // sichere Start des neuen Zeitfensters
            RegenSekunden.postUpdate(iRegenDauer)        // Item updaten
            tRegen.reschedule(now.plusSeconds(10))       // Timer erneut ausführen in 10 Sekunden
        ])
    } else {                                             // Regen beendet
        tRegen.cancel                                    // Timer stoppen
        val Long lDiff = now.toEpochSecond - lStartRegen
        iRegenDauer += lDiff.intValue                    // restliche Zeit addieren
        RegenSekunden.postUpdate(iRegenDauer)            // Item updaten
    }
end

rule "Regensekunden zurück setzen"
when
    Time cron "0 0 0 * * ?" 
then
    iRegenDauer = 0
end
Die Funktionsweise ist ähnlich Deinem Code, allerdings läuft der Timer zum Update der Regendauer nur, wenn es regnet.

Eventuell muss der Variablentyp für den Zeitstempel auch vom Typ Integer sein, dann müssten die Definition und die Typumwandlungen entsprechend geändert werden,

Man könnte den Code auch noch "etwas" vereinfachen:

Code: Alles auswählen

var Timer   tRegen      = null                       // Zeiger für den Timer
var Integer iRegenDauer = 0                          // Summe

rule "Regen"
when
    Item HomeMatic_Regensensor_Regen_ja_nein changed
then
    tRegen?.cancel
    if(newState != ON) return;

    tRegen = createTimer(now.plusSeconds(1), [|
        iRegenDauer ++
        RegenSekunden.postUpdate(iRegenDauer)
        tRegen.reschedule(now.plusSeconds(1))
    ])
end

rule "Regensekunden zurück setzen"
when
    Time cron "0 0 0 * * ?" 
then
    iRegenDauer = 0
end
Um den Preis, dass das Item nun sekündlich upgedatet wird. Die Ausführungfszeit des Timers ist minimal, kommt halt etwas auf den Rest des Systems an, ob das arg aufträgt. Ich habe bei mir einige Items, die sekündlich durch das entsprechende Binding upgedatet werden, da sind mir bisher noch keine Probleme aufgefallen.

Die Shortcuts ++ und += stehen leider jeweils nur in dem exakten Datentyp zur Verfügung, ++ (und --) für Integer, += (und -=) für int. Natürlich kann man stattdessen auch iRegenDauer = iRegenDauer + 1 schreiben...
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

nw378
Beiträge: 280
Registriert: 22. Sep 2018 10:38
Answers: 5

Re: Tägliche Regendauer in Sekunden

Beitrag von nw378 »

Ich speichere schon seit längerem die Sonnenstunden ab um dies dann in einem Diagramm darzustellen.
Dies mit einer recht einfachen Regel:

Code: Alles auswählen

rule "Sonnenstunden"
when 
    Item Sonne changed  
then
    if (newState == ON) 
      lStart = now.toEpochSecond                     
    else 
      if (newState == OFF) {  
        if(previousState == NULL) 
          return;
        var double dSum = (Sonnen_std.state as QuantityType<?>).doubleValue          
        dSum = dSum + ((now.toEpochSecond - lStart).doubleValue / 3600.0)
        Sonnen_std.postUpdate(dSum)         
      }
end
Daran hatte mich immer gestört, dass für den aktuellen Tag - solange die Sonne scheint - der Wert 0 angezeigt wurde, da das Update ja erst erfolgt, wenn die Helligkeit unter einen Schwellwert fällt. (Langer Sommertag: abends plus 12h...)

Ich habe dies nun um den Timer erweitert. Somit liegt der Wert nun nicht nur als Variable vor, sondern wird auch persistiert.

Udos Clou ist ja, den Startzeitpunkt immer wieder innerhalb des Timers neu zu setzen. Da wär ich nicht drauf gekommen.

Code: Alles auswählen

rule "Sonnenstunden"
when 
    Item Sonne changed  
then
    if (newState == ON) { 
      tSonne?.cancel
      tSonne = createTimer(now.plusSeconds(60), [|     
        lStartSonne = now.toEpochSecond      
        var double dSum = (Sonnen_std.state as QuantityType<?>).doubleValue          
        dSum += (60 / 3600.0)
        Sonnen_std.postUpdate(dSum) 
        tSonne.reschedule(now.plusSeconds(60))       
      ])
    }                  
    else 
      if (newState == OFF) {  
        if(previousState == NULL) 
          return;
        tSonne.cancel 
        var double dSum = (Sonnen_std.state as QuantityType<?>).doubleValue          
        dSum +=((now.toEpochSecond - lStartSonne).doubleValue / 3600.0)
        Sonnen_std.postUpdate(dSum) 
      }
end
Und der Regen wird ab jetzt - STRG-H - natürlich auch getrackt ;-)
openHAB 4.3.3 @ RPi 4 / SSD - InfluxDB2 und Grafana @ Synology Docker - KNX

Antworten