SVG Plot: Tagesverbrauch von Zählern dem Tag "richtig" zuordnen

Begonnen von Betonklotz, 07 Januar 2024, 12:10:24

Vorheriges Thema - Nächstes Thema

Betonklotz

Hallo FHEM Team,

habe ein Log in dem ich mir Tageswerte von div. Verbrauchszählern (Strom, Wasser, Gas, Zwischenzähler...) immer kurz vor Mitternacht wegspeichere, z.B.
get FileLog_Zaehlerstaende CURRENT INT 2024-01-01_00:00:00 2024-01-07_23:59:59 4:MQTT2_Gaszaehler.logging_delta_counter_lastday\x3a::

2024-01-02_23:59:50 4.770
2024-01-03_23:59:50 4.394
2024-01-04_23:59:50 5.012
2024-01-05_23:59:50 5.302
2024-01-06_23:59:50 4.951
#4:MQTT2_Gaszaehler.logging_delta_counter_lastday\x3a::
Nun würde ich daraus gerne einen Plot erzeugen, wobei der Verbrauch dem Tag zugeordnet werden soll, d.h. hier für das Beispiel für den 2. Januar also 4,77, für den 3. Jan dann 4,394 usw.
Leider ist das alles um einen Tag verschoben, d.h. die Werte vom 2. Januar tauchen beim 3. Jan auf usw., egal ob ich steps oder histeps nutze.
defmod SVG_FileLog_Zaehlerstaende SVG FileLog_Zaehlerstaende:SVG_FileLog_Zaehlerstaende:CURRENT
attr SVG_FileLog_Zaehlerstaende plotWeekStartDay 1
attr SVG_FileLog_Zaehlerstaende plotsize 1024,400
attr SVG_FileLog_Zaehlerstaende room Infos

setstate SVG_FileLog_Zaehlerstaende initialized
# Created by FHEM/98_SVG.pm, 2024-01-07 12:02:42
set terminal png transparent size <SIZE> crop
set output '<OUT>.png'
set xdata time
set timefmt "%Y-%m-%d_%H:%M:%S"
set xlabel " "
set title 'Gasverbrauch'
set ytics
set y2tics
set grid ytics
set ylabel "m³"
set y2label ""

#FileLog_Zaehlerstaende 4:MQTT2_Gaszaehler.logging_delta_counter_lastday\x3a::

plot "<IN>" using 1:2 axes x1y1 title 'Verbrauch [Tag]' ls l0fill lw 1 with steps

Anbei mal ein Screenshot vom aktuellen IST Zustand zur besseren Erklärung und dann dem SOLL das ich erreichen möchte. Die Frage ist nur: wie bekomme ich die Werte zu den Tagen zugeordnet?
IST Zustand mit Offset beim Tag
SOLL Zustand mit Wert über dem Tag

Und wenn wir dabei sind: kann ich den Zoomlevel auf "Tage" begrenzen, also als max. Zoom einen Tag erlauben (anstatt dann stundnenweise reinzugehen)?


betateilchen

Ich würde dafür sorgen, dass es pro Tag zwei Werte gibt, einen um 00:00:10 und einen um 23:59:50 Uhr.

Zitat von: Betonklotz am 07 Januar 2024, 12:10:24Und wenn wir dabei sind: kann ich den Zoomlevel auf "Tage" begrenzen, also als max. Zoom einen Tag erlauben (anstatt dann stundnenweise reinzugehen)?

Den "höchsten" Zoomlevel kannst Du nicht festlegen. Das Attribut fixedrange könnte vielleicht weiterhelfen, damit kannst Du die Anzeige auf den Zeitraumes eines Tages begrenzen. Dann kannst Du aber die Wochendarstellung nicht mehr auswählen. Falls Du beides brauchst, würde ich einfach zwei SVG mit der gleichen Definition anlegen, und darin dann jeweils einen bestimmten fixedrange angeben (1 SVG mit Woche, 1 SVG mit Tag). So habe ich das bei mir mit der Anzeige von Kursdaten pro Tag und pro Woche gelöst.

Und wenn wir dabei sind: man könnte diesen Thread auch mittels des Buttons unten links in das richtige Unterforum für SVG verschieben...
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Betonklotz

Zitat von: betateilchen am 07 Januar 2024, 13:23:47Ich würde dafür sorgen, dass es pro Tag zwei Werte gibt, einen um 00:00:10 und einen um 23:59:50 Uhr.
Wie das denn? Also in die Zukunft schauen kann ich ja nicht, also den Wert für 00:00:10 kenne ich ja erst um 23:59:50 (am Ende des Tages).
Aktuell rufe ich via at eine kleine Perl Datei um kurz vor Mitternacht auf, die mir dann jeweils einen Haufen readings aktualisiert/neu schreibt (die dann im Log landen). Rein theoretisch könnte ich darüber auch direkt in die (Log)Datei schreiben (nutze FileLog, kein DBLog), aber das dürfte ja nicht im Sinne des Erfinders sein: also um 23:59:50 einen dummyEintrag für 00:00:10 des Folgetages erzeugen und gleichzeitig den "alten" dummy um 00:00:10 des laufenden Tages suchen und mit dem Wert von 23:59:50 überschreiben damit die Tageswerte für 00:00:10 und 23:59:50 identisch sind.

Zitat von: betateilchen am 07 Januar 2024, 13:23:47Den "höchsten" Zoomlevel kannst Du nicht festlegen. Das Attribut fixedrange könnte vielleicht weiterhelfen, damit kannst Du die Anzeige auf den Zeitraumes eines Tages begrenzen. Dann kannst Du aber die Wochendarstellung nicht mehr auswählen. Falls Du beides brauchst, würde ich einfach zwei SVG mit der gleichen Definition anlegen, und darin dann jeweils einen bestimmten fixedrange angeben (1 SVG mit Woche, 1 SVG mit Tag). So habe ich das bei mir mit der Anzeige von Kursdaten pro Tag und pro Woche gelöst.
Hmm, ein wenig dynamisch hätte ich es schon gerne, hier: Woche, Monat, Jahr
Zitat von: betateilchen am 07 Januar 2024, 13:23:47Und wenn wir dabei sind: man könnte diesen Thread auch mittels des Buttons unten links in das richtige Unterforum für SVG verschieben...
mache ich doch glatt, dachte (ok, da ist der Fehler im Satz...) das es bei den Anfängern besser aufgehoben ist, da es weniger mit svg zu tun hat (zeigt ja auch dein Lösungsvorschlag mit zusätzlichem Wert um 00:00:10)

betateilchen

#3
Wäre es nicht die einfachste Lösung, das statistics Modul zu verwenden, das Dir Tageswerte automatisch ermittelt und logged?

Ansonsten:

Um 23:59:50 kennst Du ja den Wert, den Du brauchst. Du musst nur dafür sorgen, dass dieser Wert zweimal im Log landet, einmal für 00:00:10 und einmal für 23:59:50 des gleichen Tages.

Sowas kann man z.B. mit setreading erreichen, wenn man den entsprechenden (optionalen) Timestamp mitgibt.

https://commandref.fhem.de/#setreading

setreading global 2024-01-07 00:00:10 test 12345
erzeugt im EventMonitor:

2024-01-07 14:18:00 Global global panelZeit: 14:18
2024-01-07 14:18:00 at at_minute Next: 14:19:00
2024-01-07 00:00:10 Global global test: 12345
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Betonklotz

Zitat von: betateilchen am 07 Januar 2024, 14:18:19Wäre es nicht die einfachste Lösung, das statistics Modul zu verwenden, das Dir Tageswerte automatisch ermittelt und logged?
Wenn es denn das machen würde, was ich benötige... :-) Leider macht es das nicht, bzw. ich komme damit nicht klar. Weder funktionieren die SingularReadings wie gewünscht, tw. keine Delta und min/max parallel in einem Device, für Zähler sind nur max Werte relevant (da brauche ich kein min und kein avg parallel) und andere Unstimmigkeiten. Habe dazu mal im Anfängerbereich gefragt, aber dann aufgegeben. Von daher habe ich da Teile als Vorlage genommen und mir was eigenes gebastelt. Das funktioniert mittlerweile und macht exakt das was ich möchte. Und einen Tageswert kann auch ein statistics Modul nicht vorher kennen, d.h. das würde mir m.E. bei der grafischen Ausgabe auch nicht helfen.

Zitat von: betateilchen am 07 Januar 2024, 14:18:19Ansonsten:

Um 23:59:50 kennst Du ja den Wert, den Du brauchst. Du musst nur dafür sorgen, dass dieser Wert zweimal im Log landet, einmal für 00:00:10 und einmal für 23:59:50 des gleichen Tages.
Ja, verstanden. Habe das mal per Hand eingetragen und schaut gut aus. ABER: siehe weiter unten

Zitat von: betateilchen am 07 Januar 2024, 14:18:19Sowas kann man z.B. mit setreading erreichen, wenn man den entsprechenden (optionalen) Timestamp mitgibt.

https://commandref.fhem.de/#setreading
Geht das auch per API, z.B. https://wiki.fhem.de/wiki/DevelopmentModuleAPI? Die nutze ich tw., aber für z.B. readingsBulkUpdate habe ich keinen Zeitparameter gefunden...
Spielt die Reihenfolge in der Logdatei eine Rolle? Denn das wird ja in der Logdatei selbst ein heilloses Durcheinander (ich nutze Tages-, Wochen-, Monats-, Quartalswerte) wenn ich immer zur aktuellen Zeit mit altem Zeitstempel was einfüge was ggf. Wochen (oder gar 3 Moante/Quartal) zurückliegt... Wie auch immer: da ich die ganzen Aktualisierungen dazu nicht benötige, würde ich es sonst auch direkt in die Datei schreiben. Habe ich bisher nie gemacht, aber geht sicher auch.

Danke für die Hilfe

betateilchen

Zitat von: Betonklotz am 07 Januar 2024, 15:38:55Geht das auch per API, z.B. https://wiki.fhem.de/wiki/DevelopmentModuleAPI? Die nutze ich tw., aber für z.B. readingsBulkUpdate habe ich keinen Zeitparameter gefunden...

Die readings..Update() Funktionen sind für Modulentwickler gedacht, nicht für Anwender. Das ist fast die unterste Ebene, auf der man ein reading setzen kann. Solche Spezialitäten wie die Sache mit dem Timestamp passieren viel weiter "oben" in der Befehlskette.

Und Deine Frage nach der Reihenfolge im Logfile kann ich Dir im Moment nicht beantworten, da ich es nicht testen konnte. Vermutlich spielt es aber keine Rolle. FileLog ist bei mir seit Jahren nicht mehr im Einsatz und in DbLog gibt es auf den Timestamp einen Index, insofern ist es völlig wurscht, wann ein Eintrag mit einem bestimmten Timestamp ins Log kommt.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Betonklotz

#6
Zitat von: betateilchen am 07 Januar 2024, 15:51:18Die readings..Update() Funktionen sind für Modulentwickler gedacht, nicht für Anwender.
Dafür sind die gut dokumentiert und funktioniert wunderbar und ohne jegliche Verzögerung oder merkliche Last (ca. 350 readings pro Durchgang). Also:
$rv = readingsBulkUpdate ($zaehler_hash, "logging_counter_lastday", $zaehler_hash->{READINGS}{"Zaehlerstand"}{VAL}, 1);
Sollte ich als Anwender nicht in einer *.pm nutzen? Dann müsste ich dort auf die FHEM Ebene wechseln und da jeweils das reading einlesen und setzen. Mal schauen ob ich das übernächste Woche mal ausprobiere und schaue was das für Auswirkungen hat.

Zitat von: betateilchen am 07 Januar 2024, 15:51:18[...] in DbLog gibt es auf den Timestamp einen Index, insofern ist es völlig wurscht, wann ein Eintrag mit einem bestimmten Timestamp ins Log kommt.
Das glaube ich dir sofort, da hat eine DB u.a. Vorteile. Beim FileLog sieht das aber anders aus, zumindest muss da m.E. die Reihenfolge stimmen.
get FileLog_Zaehlerstaende CURRENT INT 2024-01-01_00:00:00 2024-01-07_23:59:59 4:MQTT2_Gaszaehler.logging_delta_counter_lastday\x3a::

2024-01-02_23:59:50 4.770
2024-01-03_23:59:50 4.394
2024-01-04_23:59:50 5.012
2024-01-05_23:59:50 5.302
2024-01-01_23:59:50 4.951
#4:MQTT2_Gaszaehler.logging_delta_counter_lastday\x3a::
liefert zumindest einen unbrauchbaren Plot (habe nun auch den Dateiupload gefunden...) (hier: Wert vom 06.Jan auf den 01. Jan umgebogen)
Das erinnert mich daran, irgendwann mal auf eine DB umzustellen. Bisher habe ich da nur nie die Notwendigkeit gesehen. Und never touch a running system, bin froh wenn das alles so läuft wie ich möchte :-)

betateilchen

#7
Zitat von: Betonklotz am 07 Januar 2024, 18:18:12Sollte ich als Anwender nicht in einer *.pm nutzen?

Es ist nicht verboten.
Aber man sollte als Anwender eigentlich nicht auf interne hashes zugreifen, von %data mal abgesehen.
Das kann merkwürdige Auswirkungen haben, deren Ursache dann sehr schwer zu finden sind.

Deshalb wurden Funktionen wie ReadingsVal()/ReadingsNum() und Befehle wie setreading geschaffen, um es dem Anwender so einfach wie möglich zu machen.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Betonklotz

Zitat von: betateilchen am 07 Januar 2024, 18:32:13Deshalb wurden Funktionen wie ReadingsVal()/ReadingsNum() und Befehle wie setreading geschaffen, um es dem Anwender so einfach wie möglich zu machen.
Danke dir, kommt mit auf die To-Do Liste das umzubauen. Über die Hashes zu arbeiten war eigentlich ganz praktisch und lief über die Jahre zuverlässig, wobei FHEM mehr Sammler und Regler war und kein "hübsch und Auswertung". Aber kann/soll sich ändern :-)
Eine Anmerkung: im Gegensatz zu ReadingsVal habe ich setreading nicht in Perl gefunden, sondern nur als FHEM Befehl. Hast du da einen Wink mit dem Zaunpfahl für mich? Oder in Perl dann via "fhem" auf FHEM wechseln und ausführen?

betateilchen

Zitat von: Betonklotz am 07 Januar 2024, 21:31:33im Gegensatz zu ReadingsVal habe ich setreading nicht in Perl gefunden, sondern nur als FHEM Befehl.

Du findest auch ReadingsVal() nicht "in perl".

fhem() ist ein Funktionsaufruf (um FHEM Befehle auszuführen), der genau wie ReadingsVal() (um readings abzufragen) in fhem.pl definiert ist und von dort ausgeführt wird. Du "wechselst" damit nirgendwo hin.

-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Betonklotz

Hallo FHEM Team,

muss den Thread noch einmal auskramen:
positiv: in perl die FHEM Befehle setreading und ReadingsNum zu nutzen erzeugt keine spürbare "Mehrlast", das flutscht auch sauber durch

Frage: gibt es einen einfachen Kniff um den Zeitstempel nach vorne zu drehen? Meine Funktion selbst wird über ein notify um xx:59:50 aufgerufen. Beim Tageswechsel (also Aufruf um 23:59:50) gehe ich also 23:59:40 zurück, um bei 00:00:10 zu landen. Das dann wieder in eine lesbare Zeit für FHEM zu bekommen ist aber "grausam", da die Ausgabe von localtime nicht mit FHEM kompatibel ist (völlig falsches Format) und strftime an meinen deutschen Einstellungen scheitert, bzw. ich später bei einem Systemwechsel böse auf die Nase falle wenn eine local Einstellung anders sein sollte... Also bleibt mir im Grunde nur, Element für Element aus dem Array zu picken und zu einem (Zeit-)String für FHEM zusammenzubauen. Oder mache ich es mir zu kompliziert?
my ($Sekunden, $Minuten, $Stunden, $Monatstag, $Monat, $Jahr, $Wochentag, $Jahrestag, $Sommerzeit) = localtime(time-(23*60*60+59*60+40));
my $fhem_zeitstempel = ($Jahr + 1900)."-".($Monat + 1)."-".$Monatstag." 00:00:10";
fhem("setreading $zaehler $fhem_zeitstempel Deltawert $delta");
Das kommt mir ein wenig zu kompliziert vor...

RalfRog

Zitat von: Betonklotz am 07 Januar 2024, 12:10:24...egal ob ich steps oder histeps nutze...

Hast du mal fsteps probiert? Bei mir passt das für die Tageswerte der Zähler.
Wenn es passt erübrigen sich die nachträglichen Einträge im Logging.

Siehe Link von Betateilchen mit nem Vergleich der "Steps"  ;)       https://forum.fhem.de/index.php?msg=100077

Gruß Ralf
FHEM auf Raspi 2B mit nanoCUL, HM-MOD-RPI-PCB und über LAN MAX!Cube mit a-culFW (Stack 868 + 433)
HM- Fensterkontakte, UP-Schalter, Bewegungsmelder und ein Rauchmelder

Betonklotz

Zitat von: RalfRog am 22 Januar 2024, 18:27:06Hast du mal fsteps probiert? Bei mir passt das für die Tageswerte der Zähler.

Gruß Ralf


Moin,

ja, habe ich alles durch. Auch Bars habe ich probiert.
Zu wann ist denn dein Zeitstempel für den Tag? Auch kurz vor Mitternacht, oder Mittags?

RalfRog

#13
Ja (nicht ganz) kurz vor Mitternacht => 23:58

Die Werte vom 21.1 23:58 Uhr stehen dann im ganzen Tagesabschnitt des 21.; dargestellt sind die letzten 30 Tage.
Das "Darstellungsproblem" verlagert sich hier auf den ersten Tag des Zeitraums, da der Wert des 23.12 nur der aufsteigende Strich ist.
Die Frage ist: was genau will ich an der Kurve sehen

Gruß Ralf



P.S.
War nur ein Gedanke. Wenn schon alles durch ist....
Zitat von: Betonklotz am 22 Januar 2024, 18:58:29ja, habe ich alles durch. Auch Bars habe ich probiert.
FHEM auf Raspi 2B mit nanoCUL, HM-MOD-RPI-PCB und über LAN MAX!Cube mit a-culFW (Stack 868 + 433)
HM- Fensterkontakte, UP-Schalter, Bewegungsmelder und ein Rauchmelder

Fistandantilus

Hab genau das selbe Problem. Hatte gerade auch einen Thread aufgegemacht und dann diesen hier gefunden. Gibt es eine Lösung?
Zusätzliche Datenpunkte zu schreiben mag zwar das Problem lösen, ist aber nur ein Workaround und widerspricht mir eigentlich sehr wegen Datenredundanz.
Raspberry Pi 3 + FHEM + Smartvisu/Fronthem, CUL, HMLAN, Enocean USB300, Eltako (FAM14, FSB14, FSR,FTS14EM,Multisensor,...) - MySQL DB + 2.Raspberry für Heizungsregelung und 3. Raspberry als Alarmanlage

Klaus_R

Zitat von: Fistandantilus am 13 März 2024, 00:23:07Gibt es eine Lösung?
Zusätzliche Datenpunkte zu schreiben mag zwar das Problem lösen, ist aber nur ein Workaround und widerspricht mir eigentlich sehr wegen Datenredundanz.

Bin auch schon darüber gestolpert. Könnte es sein, dass das alles eine falsche Erwartung ist? Folgende Überlegung. Am Ende des Tages wird genau ein! Wert gelogt. Also kann ein Diagramm zunächst mal nur einen! Punkt dafür darstellen (im Beispiel Punkt I) Am nächsten Tag dasselbe mit Punkt II usw.

Würde man sich Punkte anzeigen lassen wäre alles ok oder?

Bei Linien wird nun Linie I->II als Ertrag des Tages II angesehen. Aber ist das so? Ich meine Nein!

Wenn schon eine Linie dann müsste diese vom Zeitpunkt (23:59) waagrecht nach links zeigen (da es sich auf die vergangenen 24 Std. bezieht!)
Dann gäbe es auch die Leerstelle am Anfang nicht. Gibt es so einen Darstellungsstil?? Sozusagen einen leftstep?
Gruss Klaus

Linux Mint, Raspi-OSMC, Raspi-fhem, WemosD1, Shelly, CUL

Fistandantilus

Korrekt!

Ich würde fast soweit gehen zu sagen, dass jede Darstellung. bei der die Range nicht Stundenweise ist, immer nur einen Wert berücksichtigen sollte. Also bei Tagen, Monaten, Jahren.
In meinen Augen aktuell ein Fehler in der Darstellung. Selbst in Excel wird das korrekt dargestellt - jeder Tag ist auch automatisch ein Datenpunkt. Hier können es mehrere sein.

Ich stimme für eine Anpassung der Darstellung  :P
Raspberry Pi 3 + FHEM + Smartvisu/Fronthem, CUL, HMLAN, Enocean USB300, Eltako (FAM14, FSB14, FSR,FTS14EM,Multisensor,...) - MySQL DB + 2.Raspberry für Heizungsregelung und 3. Raspberry als Alarmanlage

gichtl

#17
Man bekommt den Tagesverbrauch ohne zusätzliche Datenpunkte zum richtigen Tag geplottet wenn man anstatt lines oder bars einfach fsteps oder ibars verwendet. Damit "enden" die Linien ausgehend vom letzten Wert mit dem Logwert um 23:59:50.

Und um den Plot-Abriß zu vermeiden hilft der logProxy und das extend-Attribut um den letzten Wert vom Vortag zu bekommen.

2024-01-01_23:59:50 T.Test T: 0
2024-01-02_23:59:50 T.Test T: 4.770
2024-01-03_23:59:50 T.Test T: 4.394
2024-01-04_23:59:50 T.Test T: 5.012
2024-01-05_23:59:50 T.Test T: 5.302


#logProxy FileLog:FileLog_T.Test,extend=86400:4:T\x3a:0:
plot "<IN>" using 1:2 axes x1y2 title 'Line 1' ls l0 lw 1 with ibars

Du darfst diesen Dateianhang nicht ansehen.


Am Neujahrstag müßte man aber um 0:00 Uhr ein AddLog einfügen, da hier gewöhnlich das Logfile wechselt.