Einzelnen Beitrag anzeigen
  #18  
Alt 20.01.2013, 00:23
Jockel Jockel ist offline
Erfahrener Benutzer
 
Registriert seit: 28.10.2009
Ort: NRW
Beiträge: 537
Jockel ist zur Zeit noch ein unbeschriebenes Blatt
Standard

Ne Regel die beim Einschalten den Zeitstempel nimmt und beim Ausschalten wieder. Die Differenz ist die Zeit die die Lampe eingeschaltet war. Die Differenz wird beim Ausschalten in einen Summenzähler addiert.
Das hab ich jetzt mal in einer ersten Version umgesetzt, ist aber ganz sicher noch deutlich verbesserungswürdig. Hier mal exemplarisch für eine Steckdose:

Items:
Code:
Number Steckdosen_Wohnen_Heizung_links_Zaehler "Steckdose Heizung li. [%d]"    (gOperatingHours)  
String Steckdosen_Wohnen_Heizung_links_Betriebsstunden "Steckdose Heizung li. [%s]"    (gOperatingHoursFormated)
Die beiden Gruppen nutze ich vor allem um mir die Einträge in der db4o.persist zu vereinfachen.

Dazu eine Regel, die beim Ausschalten die Zeitdifferenz zum Zähler addiert:

Code:
import org.openhab.core.library.types.*
import java.util.Calendar
import java.util.Date
import java.util.TimeZone

var Calendar Steckdosen_Wohnen_Heizung_links_OnTime

rule "Aktualisiere Betriebsstunden Steckdosen_Wohnen_Heizung_links_Schalten"
when
    Item Steckdosen_Wohnen_Heizung_links_Schalten changed
then
    if (Steckdosen_Wohnen_Heizung_links_Schalten.state == ON) {
        Steckdosen_Wohnen_Heizung_links_OnTime = java::util::Calendar::getInstance(TimeZone::getTimeZone("Europe/Berlin"))  
    } else if (Steckdosen_Wohnen_Heizung_links_Schalten.state == OFF) {
        var Calendar now   = java::util::Calendar::getInstance(TimeZone::getTimeZone("Europe/Berlin")) 
        var Number Diff    =  (now.getTimeInMillis() - Steckdosen_Wohnen_Heizung_links_OnTime.getTimeInMillis()) / 1000
        var Number Zaehler = (Steckdosen_Wohnen_Heizung_links_Zaehler.state as DecimalType) + Diff
        Steckdosen_Wohnen_Heizung_links_Zaehler.postUpdate(Zaehler)
        
        var Number h = (Zaehler/3600).intValue
        var Number m = ((Zaehler-h*3600)/60).intValue
        var Number s = ((Zaehler-h*3600 - m*60)).intValue
        var String TimeString = h + ":" 
        if (m < 10) {TimeString = TimeString + "0" + m.toString + ":"} else {TimeString = TimeString + m.toString + ":"}
        if (s < 10) {TimeString = TimeString + "0" + s.toString      } else {TimeString = TimeString + s.toString      } 
       	
        Steckdosen_Wohnen_Heizung_links_Betriebsstunden.postUpdate(TimeString)
		
        logInfo("operating hours rules", "Updated operating counter for Steckdosen_Wohnen_Heizung_links_Schalten: " + Zaehler)
    }
end

Initialisierung beim Start:
Code:
rule "Initialisiere Betriebsstundenzaehler"
when
    System started
then
    Steckdosen_Wohnen_Heizung_links_OnTime = java::util::Calendar::getInstance(TimeZone::getTimeZone("Europe/Berlin"))   
    
    if (Steckdosen_Wohnen_Heizung_links_Zaehler.state == Uninitialized) {
        Steckdosen_Wohnen_Heizung_links_Zaehler.postUpdate(0)
    }
end
Zusätzlich kann man bei lang laufenden Verbrauchern den Zähler auch periodisch, dann aber mit langem Intervall aktualisieren:

Code:
rule Betriebsstundenzaehler
when
  Time cron "* 0/30 * * * ?" // Abfrage alle 30min 
then
    var Number Diff
    var Number Zaehler
    var Calendar now   = java::util::Calendar::getInstance(TimeZone::getTimeZone("Europe/Berlin")) 

    if (Steckdosen_Wohnen_Heizung_links_Schalten.state == ON) {
        Diff    =  (now.getTimeInMillis() - Steckdosen_Wohnen_Heizung_links_OnTime.getTimeInMillis()) / 1000
        Zaehler = (Steckdosen_Wohnen_Heizung_links_Zaehler.state as DecimalType) + Diff
        Steckdosen_Wohnen_Heizung_links_Zaehler.postUpdate(Zaehler)
        Steckdosen_Wohnen_Heizung_links_OnTime = java::util::Calendar::getInstance(TimeZone::getTimeZone("Europe/Berlin"))  
        
        var Number h = (Zaehler/3600).intValue
        var Number m = ((Zaehler-h*3600)/60).intValue
        var Number s = ((Zaehler-h*3600 - m*60)).intValue
        var String TimeString = h + ":" 
        if (m < 10) {TimeString = TimeString + "0" + m.toString + ":"} else {TimeString = TimeString + m.toString + ":"}
        if (s < 10) {TimeString = TimeString + "0" + s.toString      } else {TimeString = TimeString + s.toString      } 
       	
       Steckdosen_Wohnen_Heizung_links_Betriebsstunden.postUpdate(TimeString)
    }
end
Ich bin noch beim Testen, Fehler sind also durchaus noch wahrscheinlich.

Natürlich ist das eine Sache bei der man sich, gerade bei vielen Verbrauchern, Funktionen in den Regeln wünscht...

Was mir überhaupt nicht gefällt ist die umständliche Formatierung des Strings zur Anzeige, eigentlich sogar schon nicht die Tatsache zwei Items zu benötigen. Wenn ich es richtig sehe, kennt das String Item aber keinen Format Operator mit dem man zumindest das Zusammensetzen des Strings etwas schöner umsetzen könnte. Vielleicht habe ich da aber auch andere Möglichkeiten übersehen.

Ein weiterer Schwachpunkt ist, dass der String erst beim Ausschalten des Verbrauchers (oder ggf. periodisch) aktualisiert wird. Deshalb hab ich in mit in die Persistence-Datenbank aufgenommen, damit er nach dem Start korrekt angezeigt wird. Alternativ könnte man ihn auch grundsätzlich peridisch aktualisieren oder Regeln erstellen, die auf das Ändern des Zählers triggern. Das sind mir dann aber doch deutlich zu viele Regeln. Bei meiner aktuellen Version mit 41 Verbrauchern reagiert der Designer beim Bearbeiten der Regel-Datei schon deutlich behäbig.

Als Kompromiss wäre auch eine Regel denkbar, die auf das Ändern aller Zähler triggert und dann jedes mal alle Strings aktualisiert. So etwas ist natürlich beim Start blöd.

Vielleicht habt ihr da ja noch Vorschläge?

P.S.: Warum der Browser das End im letzten Codeblock schluckt ist mir nicht klar, in meinem Posting ist es enthalten...

Geändert von Jockel (20.01.2013 um 00:25 Uhr)
Bei Google nach dem markiertem Wort suchen Bei Wikipedia nach dem markiertem Wort suchen Im Forum nach dem markiertem Wort suchen
Mit Zitat antworten