Ich verstehe den Event-aggregator anscheinend nicht. Im Wiki (gleich kommt noch commandref) steht
Method const: Annahme, dass zwischen den zwei Messpunkten keine Veränderung stattgefunden hat
Wenn zwischen zwei Messpunkten keine Veränderung (Veränderung von was?) stattgefunden hat, ist dann der Messwert gleich? Das ergibt doch keinen Sinn? Also ist etwas anderes gemeint, nur was?
In der commandref steht
If method is none, then that's all there is.
OK, also das erklärt wenig. Muss man weiterlesen
If method is const or linear, the time-weighted series of values is taken into account instead.
Und vermutlich brauche ich das in meinem Fall, weil bei mir Gasverbräuche nicht in festem zeitlichen Abstand eintreffen, sondern dann, wenn Gas verbraucht wird und zudem erscheinen in dem Gerät nullen, wenn ein davon unabhängiges Reading (Messung, ob der Boden nass ist) aktualisiert wird. Damit ich das aggregieren kann, muss ich vermutlich zeitlich gewichten.
With the const method, the value is the value of the reading at the beginning of the timespan; with the linear method, the value is the arithmetic average of the values at the beginning and the end of the timespan.
Da steht jetzt zweimal Value drin. Ich vermute, es heißt ungefähr das hier:
Bei der const-Methode ist der Wert, der in die Aggregation eingeht, der Messwert zu Beginn der Zeitspanne; bei der linearen Methode ist der Wert, der in die Aggregation eingeht, das arithmetische Mittel der Werte am Anfang und am Ende der Zeitspanne.
Wo aber ist dann da die zeitliche Gewichtung? Die müsste sich doch an der Länge der Zeitspanne orientieren und davon ist gar nicht die Rede?
Da bei mir zudem jede einzelne Erhöhung des Gaszählers gemessen werden kann, dachte ich zuerst, dass ich statt "integral" besser "count" nehmen kann. Da kam aber nur Unsinn heraus.
Ich will einfach nur verstehen, ob das Gerät hier wirklich den Durchschnittsverbrauch über 5 minuten misst:
Internals:
CFGFN
NAME Heizungskeller
NR 248067
STATE Woche 42
TYPE dummy
eventCount 2037
Helper:
DBLOG:
Gasverbrauch:
DbLog:
TIME 1666361320.07258
VALUE 0.0999999999985448
Gasverbrauch_aggregiert:
DbLog:
TIME 1666361320.07258
VALUE 0.0999999999985448
wasser:
DbLog:
TIME 1666361149.34924
VALUE 1975
READINGS:
2022-10-21 16:08:40 Gasverbrauch 0.0999999999985448
2022-10-21 16:08:40 Gasverbrauch_aggregiert 0.0999999999985448
2022-10-21 16:08:40 Zaehlerstand 6504.96
2022-10-21 16:08:40 gas 650496
2022-10-21 16:05:49 wasser 1975
Attributes:
comment Wasser wird ca alle 5 Minuten geprueft
Gas wird sofort uebermittelt
event-aggregator Gasverbrauch_aggregiert::none:integral:300
group Messen
room Info
sortby 01
stateFormat {if (ReadingsNum($name, "wasser", 0) < 1000) {return "Wasser ausgelaufen!!"} else {return "Woche ".ReadingsVal("DOIFweek", "state", "")}}
userReadings Gasverbrauch difference {ReadingsVal($name,"gas",0)/10;;},
Zaehlerstand {ReadingsVal($name,"gas",0)/100;;},
Gasverbrauch_aggregiert {ReadingsVal($name, "Gasverbrauch",0);;}
Jetzt habe ich auch die Definition gefunden, in TimeSeries.pm:
# we must have an assumption about how the value varies between
# two data points in the time series (discretization method).
# The const method assumes, that the value was constant
# since the previous one.
# The linear method assumes, that the value changed linearly
# from the previous one to the current one.
Das ist vermutlich nicht meine Situation. Denn hier steht ein Modell dahinter, in dem es eine stetig veränderbare Größe gibt, die man nur in bestimmten Zeitabständen erfasst (Temperaturen, Luftfeuchtigkeiten zB). Ich habe aber diskrete Werte: Nämlich die Zeitpunkte, an der die Ziffer 6 an meinem Gaszähler vorbeirauscht. Dann passt das Modul gar nicht?!
Also bei so lautem Schweigen (bis jetzt 77 Aufrufe) kann die Schlussfolgerung nur sein: Ich habe mich nicht verständlich gemacht. Ein neuer Versuch.
Es gibt kontinuierliche Daten, die ständig anfallen und nur zu bestimmten Zeitpunkten gelesen werden: Temperatur, Luftfeuchtigkeit, Feinstaubbelastung, Lichtstärke... Anscheinend ist das Modul TimeSeries.pm dafür gemacht, denn wenn man diese Daten zu bestimmten Zeitpunkten liest muss man ja sicherstellen, dass man die dahinter liegenden wahren Daten korrekt erfasst. Denkbar wäre zB, dass die Daten sinusförmig schwanken und man blöderweise immer im Tal misst oÄ Probleme. Genau diese Fragen interessieren mich hier gar nicht.
Ich habe nämlich diskrete Daten, die nur an gewissen Zeitpunkten anfallen und dann auch vollständig gelesen werden:
10:10:11 => 1m^3 Gas
10:12:39 => 0m^3 Gas <== so was erscheint auch, obwohl logisch unsinnig
10:13:13 => 2m^3 Gas
10:15:19 => 1m^3 Gas
Diese Werte will ich auswerten. Ich will wissen, wie viel Gas in einem bestimmten Zeitraum verbraucht wurde. Mir ist nicht klar, ob das Modul TimeSeries.pm bzw der event-aggregator das machen. Zum einen sind die Zeitabstände zwischen den Verbrauchszeitpunkten unterschiedlich und dann kann es sein, dass die Verbrauchsmengen auch schwanken, so wie im Beispiel. (Bei mir scheint das aber eher nicht der Fall zu sein, da ich jede Umdrehung des Gaszählers erfasse.)
Ich weiß nun nicht, wie ich zB die Summe aller Verbräuche der letzten X Sekunden messen kann. Wären die Zeitabstände konstant, dann wäre das einfach: man zählt diejenigen Einträge, die ungleich null sind. Wegen der verschiedenen Zeitabstände geht das aber nicht. Die Länge der Zeitabstände spielt auch keine Rolle, so dass eine zeitliche Gewichtung nicht in Frage kommt - die erfassten Daten sind diskret und da passiert "dahinter" nichts, was auch noch beachtet werden müsste.
Ich verstehe leider den Programmcode von TimeSeries.pm nicht, sonst hätte ich versucht mir was eigenes zu bauen. Im Grunde muss es ja irgendwie so sein. Ich definiere eine Variable "Summe" und schleppe die gesamte Zeit eine Liste mit den alten Werten mit (Zeitpunkt und Verbrauch). Wenn ein Wert einen Zeitstempel hat, der außerhalb des zu erfassenden Bereiches liegt, fliegt er aus der Liste. Zeitgleich wird die Summe um den dazugehörigen Verbrauchswert gemindert. Wenn ein neuer Wert eintrifft, wird Zeitpunkt und Verbrauch der Liste dazugefügt; parallel wird Summe um Verbrauch erhöht. Das klingt alles plausibel - ist das irgendwo schon in TimeSeries umgesetzt? Macht das vielleicht auch event-aggrgeator? Sehe ich hier was elementares nicht?!
Langsam steige ich durch den Code durch. Also die statistischen Kenngrößen werden hier berechnet
sub _updatestat($$) {
my ($self, $V)= @_;
my $n= ++$self->{n};
if($n> 1) {
my $M= $self->{_M};
$self->{_M}= $M + ($V - $M) / $n;
$self->{_S}= $self->{_S} + ($V - $M) * ($V - $self->{_M});
$self->{integral}+= $V;
#main::Debug("V= $V M= $M _M= ".$self->{_M}." _S= " .$self->{_S}." int= ".$self->{integral});
} else {
$self->{_M}= $V;
$self->{_S}= 0;
$self->{integral}= $V;
}
Man sieht deutlich, dass das Integral eine Addition aller $V ist und bei den $V handelt es sich um die Messwerte (_M scheinen Mittelwert und _S Standardabweichung zu sein). ). Ohne Zeitgewichtung ist das gleich
if($self->{method} eq "none") {
# no time-weighting
$self->_updatestat($vn);
und mit Zeitgewichtung
if($self->{method} eq "const") {
# steps
$self->_updatestat($vo * $dt);
} else {
# linear interpolation
$self->_updatestat(0.5 * ($vo + $vn) * $dt);
Passt also zu meinem Problem! Ich denke, meine Version leistet doch das, was ich brauche. Also for the record, ich nehme
defmod Heizungskeller dummy
attr Heizungskeller event-aggregator Gasverbrauch_aggregiert:300:none:integral:300
attr Heizungskeller userReadings Gasverbrauch difference {ReadingsVal($name,"gas",0)/10}, \
Zaehlerstand {ReadingsVal($name,"gas",0)/100;;;;},\
Gasverbrauch_aggregiert {ReadingsVal($name, "Gasverbrauch",0);;;;}
Ich bastle mal ein wenig an dem Wikipedia Artikel, um den etwas aufzuhübschen.
Hallo andies,
erst einmal nur als Feedback: ich habe gerade diesen Thread gefunden da ich die aggregator Funktion verwenden wollte. Allerdings ist die Commandref dazu eine Katastrophe. Die versteht nur derjenige der sie geschrieben hat. Wenn überhaupt. Für mich ist jedenfalls weder die Beschreibung noch die darin aufgeführten Beispiele nachvollziehbar und somit werde ich die Funktion erst einmal nicht verwenden. Würde mich freuen, wenn du weiter am Ball bleibst. Helfen kann ich dir leider nicht aber ich hoffe, dass ich mit dem von dir überarbeiteten Wiki Artikel dann besser zurecht komme.
Gruß Reinhard
Schreib mal, was du möchtest und dann probieren wir gemeinsam. Ist für mich eine ,,challenge", wie meine pubertierenden Kinder sagen würden ;-)
PS Evtl ist auch das wichtig https://forum.fhem.de/index.php/topic,129920.0.html (https://forum.fhem.de/index.php/topic,129920.0.html)
Zitat von: andies am 05 November 2022, 15:43:02
Schreib mal, was du möchtest und dann probieren wir gemeinsam. Ist für mich eine ,,challenge", wie meine pubertierenden Kinder sagen würden ;-)
Na ja, für die "challenge" brauch ich nicht einmal pubertierende Kinder, das kommt auch täglich über das Business-Bullshit-Bingo ;)
Eigentlich ist mein Thema recht trivial und lässt sich sicherlich mit "userReadings" einfacher lösen. Ich habe eine DECT200 Steckdose die kontinuierlich Power und Total Energy anzeigt. Meine Tasmota Steckdosen verfügen darüber hinaus über "EnergyToday" und "EnergyYesterday". Ich hatte erst überlegt das Integral über Power zu bilden. Viel leichter dürfte es aber sein, über "userReadings" um Mitternacht den aktuellen Energy Wert abzuspeichern und den "Today" Wert aus der Differenz des aktuellen Energy Wertes und dem Mitternachtswert zu bilden. Der Yesterday Wert ergibt sich dann von selbst.
Gut möglich, dass ich in Zukunft die Funktion benötige, die Idee ist mir immer wieder mal gekommen. Bislang gab es für mich aber noch keinen konkreten Anlass bei dem ich es zwingend gebraucht hätte. Auf dein Angebot komme ich aber gerne wieder zurück wenn es soweit ist, vielen Dank :)
Ich habe so was ähnliches für die Verbräuche bei Gas, Strom und Wasser gemacht. In 99_myUtils.pm, etwas abgekürzt (bei mir steht da noch mehr drin)
sub VerbrauchswerteSpeichern(){
my $Daten = ReadingsVal("Gasrechner", "Heizungskeller_GesamtGas_EnergyCostDayLast","").;
fhem("setreading FileLog_GasTemperaturRegression logEntry ".$Daten);
fhem("setreading Gasrechner Normverbrauch ".sprintf "%.1f", $Daten);
}
und dieser Befehl wird dann mit einem notify (eigentlich mit YAAHM, https://wiki.fhem.de/wiki/Modul_YAAHM (https://wiki.fhem.de/wiki/Modul_YAAHM)) Mitternachts ausgelöst.