Seite 1 von 1

Rule zur Überwachung

Verfasst: 3. Jul 2023 15:41
von goerdi
Hi !

Ich wollte mir eine rule schreiben um den Gefrierschrank zu überwachen.
1. Ob Power an ist
2. Anhand von der Leistung/dauer ob das teil offen ist oder nicht.

25% der rule funktionieren (den ersten Teil habe ich aus ner Überwachung eines Schalters geklaut.. (ddas funktioniert)

Hier die Rule

Code: Alles auswählen

var hilfsVariable = null
var hilfsVariable2 = null

rule "Gefrierschrank Status"
when                                          
  Item Shelly_WZ_Power_Out changed                      
then          
var Timer WindowTimer = null
Thread::sleep(3000)

  if(Shelly_WZ_Power_Out.state != ON) {
        WindowTimer = createTimer(now.plusMinutes(1), [|              
        sendBroadcastNotification("Gefrierschrank abgeschaltet!")
        WindowTimer = null
        hilfsVariable = 1
      ])                                                             
  } else {
      if (Shelly_WZ_Power_Out.state == OFF) {
        if(WindowTimer !== null) {                                     
          WindowTimer.cancel                                      
          WindowTimer = null
        }
         if (hilfsVariable == 1) {
          sendBroadcastNotification("Gefrierschrank eingeschaltet!")
          hilfsVariable = null
        }
      }  
    }
end


rule "Gefrierschrank Status"
when                                          
  Item Shelly_WZ_Power changed                      
then          
var Timer WindowTimer = null
Thread::sleep(1000)
var Number nPac = 0                        // hier Number ergänzen

        nPac = Shelly_WZ_Power.state as Number

  if (nPac > 40.0 && hilfsVariable2 == 0) {

        WindowTimer = createTimer(now.plusMinutes(1), [|              
        sendBroadcastNotification("Laufzeitüberwachung Gefrierschrank!")
        WindowTimer = null
        hilfsVariable2 = 1
      ])                                                             
  } else {
      if (nPac < 5.0) {
        if(WindowTimer !== null) {                                     
          WindowTimer.cancel 
          WindowTimer = null
        }
         if (hilfsVariable2 == 1) {
          sendBroadcastNotification("Gefrierschrank hat abgeschaltet!")
          hilfsVariable2 = null
        }
      }  
    }
end
So dervordere Teil funktioniert , sprich ich kriege eine Meldung wenn Power off, alelrdings hakt es schon beim zweiten Teil der ersten rues, das ich keine Meldung kriege wenn Power wieder ON ist...

die zweite Rule zuckt sich gar nicht....

Gruss gerd

Re: Rule zur Überwachung

Verfasst: 4. Jul 2023 16:21
von udo1toni
Also, es geht mal damit los, dass Du Variablen falsch definierst. :)

Eine Timer Variable wird benötigt, um auf einen Timer zugreifen zu können. Man sollte grundsätzlich immer mit Timer Variablen arbeiten. ABER: Timer Variablen müssen global definiert sein, denn der Timer existiert auch noch, wenn die Rule schon längst beendet wurde. Eine lokal definierte Variable wird mit Beenden der Rule aus dem Speicher entfernt.

Beide Rules haben den gleichen Namen, das ist nicht erlaubt. Namen müssen systemweit eindeutig sein!

Was soll das Thread::sleep()? Bitte mach das nicht. Nie.
Es gibt nur eine Ausnahme dieser Regel, nämlich, wenn Du per .postUpdate() oder per .persist() einen Wert in ein Item schreibst oder das Item gezielt persistieren lässt um anschließend über historicState oder irgendwelche Persistence Aggregationen (sumSince usw) auf die Persistence zuzugreifen. Dann muss man tatsächlich eine kleine (!) Denkpause einlegen und zu Thread::sleep(100) greifen - Benötigt eine Rule wesentlich längere Pausen, hast Du etwas falsch gemacht.

Die erste Rule...
Du prüfst zunächst, auf Shelly_WZ_Power_Out.state != ON (der Status ist nicht ON). Ist dies nicht der Fall (d.h. der Status ist ON), prüfst Du auf
Shelly_WZ_Power_Out.state == OFF (der Staus ist OFF). Da dies aufgrund der vorigen Bedingung ausgeschlossen ist, wird der Code niemals ausgeführt.

Besser:

Code: Alles auswählen

// Globale Variablen immer vor der ersten Rule definieren!
var Timer tFridgeOn  = null                                 // Timer für Warnmelung per Broadcast Notification

rule "Power Gefrierschrank"
when
    Item Shelly_WZ_Power_Out changed
then
    tFridgeOn?.cancel
    switch(newState) {
        case OFF : {
            logWarn("fridge","Stromversorgung Gefierschrank wurde ausgeschaltet!")
            tFridgeOn = createTimer(now.plusMinutes(1), [|
                sendBroadcastNotification("Gefrierschrank wurde ausgeschaltet!")
            ])
        }
        case ON  : {
            logInfo("fridge","Stromversorgung Gefierschrank wurde eingeschaltet.")
        }
        default  : {
            logError("fridge","Ungültiger Zustand des überwachten Items! ({})",newState)
        }
    }
end
Ändert sich der Status des Items Shelly_WZ_Power_Out wird die Rule gestartet.
Zunächst wird ein eventuell laufender Timer beendet und entfernt. Das ? bedeutet: nur falls die Variable einen gültigen Zeiger enthält, entspricht also diesem Code:

Code: Alles auswählen

if(tFridgeOn !== null) tFridgeOn.cancel
Ja, bei einer Prüfung auf null (und nur exakt auf null!) schreibt man !== bzw. ===.
Nachdem der eventuell laufende Timer beseitigt ist, prüft die Rule auf drei verschiedene Möglichekiten:
Zustand OFF: eine Warnmeldung wird geloggt, außerdem startet ein Timer, der nach einer Minute eine Meldung versendet.
Zustand ON: Eine Information wird geloggt.
alle anderen Situationen: ein unerwareter Zustand. Dies wird als Fehler geloggt (mit aktuellem Zustand)
newState ist eine impliziete Variable, die den aktuellen Wert des Items enthält, welches die Rule mit changed getriggert hat. Ist einfach kürzer...
Für den letzten Fall möchtest Du eventuell ebenfalls eine Notification raus hauen, hier wäre es dann sinnvoll, gleich den Zustand mitzumelden, also z.B.

Code: Alles auswählen

sendBroadcastNotification("Gefrierschrank Stromversorgung gemeldeter Zustand ist "+newState.toString)
Nun zum zweiten Teil:
Wenn man mit Status arbeitet, die Messwerte enthalten, ist es immer gut, sich abzusichern, dass der gelieferte Status auch tatsächlich ein gültiger Wert ist (ein Number Item kann u.A. auch UNDEF oder NULL liefern)

Wie lange die normalen Kompressorzyklen sind, weißt Du natürlich am besten :) aber denke auch daran, dass man manchmal Ungefrorenes in dne Schrank packt, dann läuft der Kompressor im Zweifel etwas länger,

Etwa so:

Code: Alles auswählen

// Globale Variablen immer vor der ersten Rule definieren!
var Timer tFridgePow = null                                 // Timer für Einschaltdauer

rule "Gefrierschrank Tür offen Erkennung"
when
    Item Shelly_WZ_Power changed
then
    var nPac = 0.0

    if(newState instanceof Number)
        nPac = (newState as Number).floatValue
    else {
        logWarn("fridge","Messung der Leistung liefert ungültigen Wert! ({})",newState)
        return;
    }

    if(nPac < 5 && tFridgePow !== null) {
        logInfo("fridge","Kompressor Gefrierschrank hat abgeschaltet.")
        tFridgePow.cancel
        tFridgePow = null
    } else if(nPac > 40 && tFridgePow === null) {
        logInfo("fridge","Kompressor Gefrierschrank hat eingeschaltet.")
        tFridgePow = createTimer(now.plusMinutes(1), [|                                       // maximale EZ eine Minute?
            logWarn("fridge","Kompressor Gefrierschrank zu lange eingeschaltet. Tür prüfen!")
            sendBroadcastNotification("Laufzeitüberwachung Kompressor Gefrierschrank hat ausgelöst! Tür prüfen!")
            // tFridgePow.reschedule(now.plusMinutes(15))  // erneute Meldung in 15 Minuten
            // tFridgePow = null                            // neue Meldung sobald erneut Leistung über 40 erkannt
        ])
    }
end
Zunächst wird eine lokale Variable mit 0.0 vorbelegt (openHAB generiert daraus automatisch einen Typ Float)
Anschließend wird der aktuelle Status auf Gültigkeit geprüft und gegebenenfalls in die Variable übernommen. Andernfalls bricht die Rule mit einer LogMeldung ab.

Läuft der Code weiter, so gibt es zwei interessante Fälle:
Erstens, die aufgenommene Leistung ist unter 5 und ein Timer ist vorhanden, dann muss dieser Timer gecancelt und auf null gesetzt werden.
Zweitens, die aufgenommen Leistung ist über 40 und es ist kein Timer vorhanden, dann muss ein Timer angelegt werden.

Und nun scheiden sich die Geister... Es gibt drei Möglichkeiten, was der Timer macht, entsprechend zwei Zeilen Code, oben auskommentiert:
  1. einmalige Meldung. Danach ist Ruhe. Du lässt beide Zeilen auskommentiert.
  2. erneute Meldung frühestens nach (z.B.) 15 Minuten - unter der Voraussetzung, dass der Kompressor nicht zwischenzeitlich abgeschaltet hat. das wäre die erste im Code auskommentierte Zeile
  3. Erneute Meldung sobald wieder eine Leistung über 40 gemessen wird (abweichend von der vorher gemessenen Leistung, Meldung wieder nach einer Minute) Das wäre die zweite auskommentierte Zeile
Das ist ein Entweder - Oder (oder keine der beiden Zeilen, keinesfalls beide Zeilen gleichzeitig aktivieren!)

Re: Rule zur Überwachung

Verfasst: 6. Jul 2023 11:30
von goerdi
hI !

ok danke erst mal.... ich scheine da noch ein anderes problem zu haben.... ich hab einen shelly dran gehängt und der zeigt mit 40w im dauerlauf und wenn man die tür aufmacht steigt es kurzzeitig an...

gruss gerd