Seite 1 von 2

Energieverbrauch Monat

Verfasst: 26. Jun 2023 18:41
von PeterA
Hi,

unseren neuen Stromzähler lese ich mit einem hitchi/Tasmota Lesekopf aus.
Den aktuellen Zählerstand (1.8.0) lese ich aus und persistiere ihn auch damit ich zb. mit den Tagesverbrauch anzeigen lassen kann usw.

Jetzt möchte mich mir auch den Monatsverbrauch Anzeigen lassen:

Code: Alles auswählen

hitchi_in_monat.postUpdate(hitchi_in.deltaSince(now.withDayOfMonth(1).withTimeAtStartOfDay) as Number )
Warum passiert da nichts ?

Dieser Code für den Tageswert Funktioniert:

Code: Alles auswählen

hitchi_in_heute.postUpdate(hitchi_in.deltaSince(now.withTimeAtStartOfDay) as Number )

Re: Energieverbrauch Monat

Verfasst: 26. Jun 2023 19:19
von udo1toni
Ich empfehle es gebetsmühlenartig ;)
Nutze Variablen. Das tut nicht weh!
Wenn Du einen Wert in einer Variablen zwischenspeicherst, kannst Du den Wert prima loggen und schauen, ob das erwartete Ergebnis vorliegt (oder auch nicht)

Seit wann schreibst Du Daten in die Persistence? Kannst Du sicher sein, dass hitchi_in für den 1.6. 0:00 Uhr einen gültigen Zählerstand hat?
Welche Persistence kommt zum Einsatz?
Wie ist die Persistence konfiguriert?

Re: Energieverbrauch Monat

Verfasst: 26. Jun 2023 19:36
von oh73
ich hab da auch etwas länger versucht,

wichtig ist das die Datenbank richtig befüllt ist!

mein Code zum abfragen der jdbc Datenbank,

Code: Alles auswählen

	val dtMidnight = ZonedDateTime.now().with(LocalTime.now.withHour(1).withMinute(0).withSecond(0))
	Pv_Ertrag_Monat.postUpdate(inverter1TotalErtrag.deltaSince(dtMidnight.withDayOfMonth(1), "jdbc")  as Number )
andere Beispiele,

Code: Alles auswählen

	val dtMidnight = ZonedDateTime.now().with(LocalTime.now.withHour(1).withMinute(0).withSecond(0))
	var Number Verbrauch_tag 		= Total_Verbrauch.deltaSince(now.withHour(1).withMinute(0).withSecond(0), "jdbc") as Number 
//	var Number Verbrauch_ab_gestern = Total_Verbrauch.deltaSince(dtMidnight.minusDays(1), "jdbc") as Number
	var Number Verbrauch_Monat 	 	= Total_Verbrauch.deltaSince(dtMidnight.withDayOfMonth(1), "jdbc")  as Number
	var Number Verbrauch_Jahr 	 	= Total_Verbrauch.deltaSince(dtMidnight.withDayOfYear(1), "jdbc")  as Number
//	var Number Verbrauch_gestern 	= Verbrauch_ab_gestern - Verbrauch_tag
wichtig ist auch die Variable dtMidnight , hab ich auch irgend wo geklaut!
Jahresverbrauch geht bei mir auch noch nicht, weil vom Anfang des Jahres Werte fehlen!

Re: Energieverbrauch Monat

Verfasst: 26. Jun 2023 19:38
von PeterA
Ok..
Das Item wird seit ca. Mitte Mai Persistiert. Sehe ich im Chart Widget.

So stehts in der .persist drinne für rrd4j

Code: Alles auswählen

hitchi_in   : strategy = everyMinute, everyChange, restoreOnStartup
Aber ob das genau am 1.6 00:00 einen gültigen Wert hatte kann ich natürlich nicht sagen.

Achso... OpenHab 2.4 (duck)

Re: Energieverbrauch Monat

Verfasst: 26. Jun 2023 19:43
von oh73
Aber ob das genau am 1.6 00:00 einen gültigen Wert hatte kann ich natürlich nicht sagen.
auch deshalb nehme ich die jdbc Datenbank, da kann ich den Speicherort festlegen und mit dem sqlite Browers mir auch die Datenbank anzeigen lassen!

Re: Energieverbrauch Monat

Verfasst: 26. Jun 2023 20:18
von udo1toni
Ja, dann steht schon ein Wert zur Verfügung, wenn rrd4j seit mehr als einem Monat persistiert, dann wird es auch einen Wert für den abgefragten Moment bereitstellen - ob es der richtige Wert ist, steht aber auf einem anderen Blatt.

Lege bitte mal eine kleine Rule an, um zu sehen, was da kommt:

Code: Alles auswählen

rule "lese Wert aus"
when
    Item MySwitch received command                                         // irgend ein passender Trigger, z.B. ein Item empfängt einen Befehl
then
    val startOfMonth = now.withDayOfMonth(1).withTimeAtStartOfDay
    logInfo("getval","startOfMonth = {}",startOfMonth)

    if(!(hitchi_in.historicState(startOfMonth).state instanceof Number)) {
        logWarn("getval","hitchi_in.hitoricState.state ungültig: {}",hitchi_in.historicState(startOfMonth).state)
        return;
    }
    if(!(hitchi_in.state instanceof Number)) {
        logWarn("getval","hitchi_in.state ungültig: {}",hitchi_in.state)
        return;
    }
    val Number nStart = (hitchi_in.historicState(startOfMonth).state as Number).floatValue
    val Number nEnd   = (hitchi_in.state as Number).floatValue
    logInfo("getval","nStart = {} nEnd = {} Differenz = {}",nStart,nEnd,nEnd - nStart)
    val Number nDiff  = (hitchi_in.deltaSince(startOfMonth) as Number).floatValue
    logInfo("getval","nDiff ermittelt mit deltaSince = {}",nDiff)
end
Der Code sollte auf jeden Fall eine aufschlussreiche Ausgabe liefern, so oder so...

Re: Energieverbrauch Monat

Verfasst: 26. Jun 2023 20:30
von PeterA
Das kommt dann:

Code: Alles auswählen

2023-06-26 20:29:15.254 [INFO ] [clipse.smarthome.model.script.getval] - startOfMonth = 2023-06-01T00:00:00.000+02:00

2023-06-26 20:29:15.262 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'lese Wert aus': cannot invoke method public abstract org.eclipse.smarthome.core.types.State org.eclipse.smarthome.core.persistence.HistoricItem.getState() on null

Re: Energieverbrauch Monat

Verfasst: 26. Jun 2023 21:11
von udo1toni
Oh. Das bedeutet, er kann von vornherein nicht auf die Historie zugreifen.
Ich hatte Dein Ausgangsposting so verstanden, dass Du schon auf historische Werte des Items zugreifst.

Was sein könnte: Deine default Persistence verweist nicht auf rrd4j (welche Du ja für die Persistence nutzt). Also kleine Änderung:

Code: Alles auswählen

rule "lese Wert aus"
when
    Item MySwitch received command                                         // irgend ein passender Trigger, z.B. ein Item empfängt einen Befehl
then
    val startOfMonth = now.withDayOfMonth(1).withTimeAtStartOfDay
    logInfo("getval","startOfMonth = {}",startOfMonth)

    if(!(hitchi_in.historicState(startOfMonth,"rrd4j").state instanceof Number)) {
        logWarn("getval","hitchi_in.hitoricState.state ungültig: {}",hitchi_in.historicState(startOfMonth,"rrd4j").state)
        return;
    }
    if(!(hitchi_in.state instanceof Number)) {
        logWarn("getval","hitchi_in.state ungültig: {}",hitchi_in.state)
        return;
    }
    val Number nStart = (hitchi_in.historicState(startOfMonth,"rrd4j").state as Number).floatValue
    val Number nEnd   = (hitchi_in.state as Number).floatValue
    logInfo("getval","nStart = {} nEnd = {} Differenz = {}",nStart,nEnd,nEnd - nStart)
    val Number nDiff  = (hitchi_in.deltaSince(startOfMonth,"rrd4j") as Number).floatValue
    logInfo("getval","nDiff ermittelt mit deltaSince = {}",nDiff)
end
Nun fragen historicState() und deltaSince() explizit rrd4j nach den Werten.

Re: Energieverbrauch Monat

Verfasst: 26. Jun 2023 22:04
von PeterA
Ah ja...
Fehler gefunden!

Irrtümlicherweise hatte ich angenommen das dieses Item "hichi_in" schon länger als einen Monat persistiert wird.
Dem ist nicht so. Wird erst ab ca. Mitte diesen Monat persistiert... Habs mir im Chart noch mal angesehen.

Also werde ich wohl noch warten müssen. Denn auch die geänderte Rule wirft den selben Fehler.

Re: Energieverbrauch Monat

Verfasst: 26. Jun 2023 22:52
von udo1toni
Ach so...
udo1toni hat geschrieben: 26. Jun 2023 20:18 ob es der richtige Wert ist, steht aber auf einem anderen Blatt.
GANZ wichtig, wenn wir von rrd4j reden... rrd4j ist eine RoundRobin Datenbank, das heißt, es überschreibt die ältesten Werte mit den neuesten Werten, um die Datenbank immer auf der gleichen Größe zu halten
Ein weiterer Punkt bei rrd4j ist aber auch, dass man auf der einen Seite eine hohe Auflösung für die letzten Werte haben möchte, auf der anderen Seite aber möglichst weit in die Vergangenheit schauen möchte. Nehmen wir an, wir speichern einen Wert pro Minute, dann sind das 60 * 24 * 365 Werte pro Jahr, also 525.600 Werte, und für jeden Wert muss ein Zeitstempel und der Wert (mindestens als Float) gespeichert werden. Ohne leistungsfähige Kompression kommen wir damit auf etwa 4 MByte pro Item, und im Grund verbietet sich eine Kompression, weil dann die Dateien ständig aus- und eingepackt werden müssen, bei jedem Speichervorgang, bei jedem Lesevorgang.
Also verfolgt rrd4j einen anderen Ansatz, und das ist Datenreduktion. Es gibt mehrere Level (genaue Werte kann man konfigurieren, der Einfachheit halber denke ich mir hier mal Werte aus), z.B. ein Wert pro Minute für die letzten 24 Stunden (1440 Werte), ein Wert pro Stunde für die letzten 2 Monate (1440 Werte bei 2 * 30 Tagen) und ein Wert pro 6 Stunden für die letzten 365 Tage (1464 Werte), macht 4344 Werte insgesamt oder etwa 34 KByte pro Item (ohne weitere Kompression).
Jetzt gibt es nur ein Problem... Welchen Wert soll rrd4j für die ausgedünnten Werte nehmen? Da gibt es verschiedene Optionen und es gibt jeweils Argumente für die Optionen, die wären:
  • erster Wert der Zeitspanne
  • letzter Wert der Zeitspanne
  • mittlerer Wert der Zeitspanne
  • Durchschnittswert der Zeitspanne
Keine Ahnung ob man das anders konfigurieren könnte (ich habe mich nicht so intensiv mit rrd4j beschäftigt), aber openHAB nutzt gewöhnlich den Durchschnittswert. Im Beispiel errechnet rrd4j also stündlich einen Durchschnittswert der letzten 60 Minuten und speichert diesen in der Stundentabelle ab, alle sechs Stunden errechnet es den Durchschnittswert der letzten 360 Minuten und speichert diesen Wert in der 6-Stunden-Tabelle ab.
Wie bei der Minutentabelle auch wird jeweils der älteste Wert gelöscht.

So. Und nun kommst Du, und möchtest den Zählerstand vom Monatsersten, 0:00 Uhr als Referenz nutzen, um den Monatsverbrauch abzulesen. Es sollte klar sein, dass sich der Zählerwert vermutlich ändert, wenn rrd4j den Wert nicht mehr aus der Minutentabelle beziehen kann, sondern die Stundentablle nutzen muss.

Unterm Strich wäre also der korrekte Weg, eine Datenbank zu verwenden, welche den Daten (wesentlich) mehr Platz einräumt.