LogProxy: Unterschied zwischen den Versionen

Aus FHEMWiki
 
(57 dazwischenliegende Versionen von 4 Benutzern werden nicht angezeigt)
Zeile 5: Zeile 5:
|ModCmdRef=logProxy
|ModCmdRef=logProxy
|ModForumArea=Frontends
|ModForumArea=Frontends
|ModTechName=98_logProxy.pm
|ModTechName=[http://fhem.de/commandref.html#logProxy 98_logProxy.pm]
|ModOwner=Andre ([http://forum.fhem.de/index.php?action=profile;u=430 Forum] / [[Benutzer Diskussion:justme|Wiki]])}}
|ModOwner=Andre ([http://forum.fhem.de/index.php?action=profile;u=430 Forum] / [[Benutzer Diskussion:justme|Wiki]])}}


Das Fhem-[[:Kategorie:Hilfsmodul|Hilfsmodul]] [[logProxy]] bietet die Möglichkeit die Daten die in einem SVG-Plot dargestellt werden auf die folgenden Arten zu ergänzen und zu manipulieren:
Das Hilfsmodul [[logProxy]] bietet die Möglichkeit, die Daten, die in einem SVG-Plot dargestellt werden, auf die folgenden Arten zu ergänzen und zu manipulieren:
*horizontale und vertikale Linien an festen Positionen hinzufügen
* horizontale und vertikale Linien an festen Positionen hinzufügen
*Linien an dynamischen und von anderen Plots anhängigen Positionen hinzufügen (über die SVG specials min, max, mindate, maxdate, avg, currdate und currval)
* Linien an dynamischen und von anderen Plots abhängigen Positionen hinzufügen (über die SVG specials min, max, mindate, maxdate, avg, currdate und currval)
*plotten von dynamisch berechneten Kurven wie die Wochenprofile von Heating_Control und WeekdayTimer devices sowie HomeMatic und Max Thermostaten
* plotten von dynamisch berechneten Kurven wie die Wochenprofile von [[Heating Control]] und WeekdayTimer Devices sowie HomeMatic und Max Thermostaten
*mischen von Plots aus unterschiedlichen Quellen (DbLog und/oder mehrere FileLog devices)
* mischen von Plots aus unterschiedlichen Quellen ([[DbLog]] und/oder mehrere FileLog Devices)
*horizontales Verschieben von plots zueinander um die Daten aus den average oder statistic Modulen auf den richtigen Tag, Woche oder Monat zu schieben
* horizontales Verschieben von Plots zueinander, um die Daten aus den Average oder Statistic Modulen auf den richtigen Tag, Woche oder Monat zu schieben
* Auffüllen am Anfang und Ende des Plots, um den Plotabriss zu vermeiden ohne zusätzliche Daten zu loggen.
* Polar-/'Spinnennetz'-Darstellung


in progress:
Alle Funktionen, die logProxy bereitstellt, werden im .gplot file über #logProxy Zeilen konfiguriert. Zusätzlich muss natürlich genau wie für die #FileLog bzw. #DbLog Zeilen jeweils eine eigene Plot-Zeile vorhanden sein.
*Auffüllen am Anfang und Ende des Plots um den Plotabriss zu vermeiden ohne zusätzliche Daten zu loggen.
 
Alle Funktionen die logProxy bereit stellt werden im .gplot file über #logProxy Zeilen konfguriert. Zusätzlich muss natürlich genau wie für die #FileLog bzw. #DbLog Zeilen jeweils eine eigene Plot-Zeile vorhanden sein.
   
   
Der Plot-Editor wird (hoffentlich) so gut es geht unterstützt. Leider sind die Drop-Down Listen nicht dynamisch abhängig von einem anderen Feld konfgurierbar.
Der Plot-Editor wird (hoffentlich) so gut es geht unterstützt. Leider sind die Dropdown Listen nicht dynamisch abhängig von einem anderen Feld konfigurierbar.


Das Modul ist noch nicht eingecheckt und zur Zeit im [http://http://forum.fhem.de/index.php/topic,26529.0.html Forum] zu finden.
Das Modul ist seit dem 16.11.2014 eingecheckt und wir im regulären Update verteilt.


==Vorbereitung:==
== Vorbereitung ==
*Anlegen eines logProxy devices:
* Anlegen eines logProxy devices:
define lp logProxy
:<code>define lp logProxy</code>
*Wenn Daten zu einem bestehenden Plot hinzugefügt werden sollen muss
* Wenn Daten zu einem bestehenden Plot hinzugefügt werden sollen muss
**das SVG device vom jeweiligen DbLog oder FileLog device auf das logProxy device umgestellt werden
** das SVG device vom jeweiligen DbLog oder FileLog device auf das logProxy device umgestellt werden
**im .gplot file die <code>#FileLog</code> bzw. <code>#DbLog</code> zeilen in <code>#logProxy</code> geändert
** im .gplot file die <code>#FileLog</code> bzw. <code>#DbLog</code> Zeilen in <code>#logProxy</code> geändert
**und an den anfang der column_spec zusätzlich <code>FileLog:<logDevice>: bzw DbLog:<logDevice>:</code> eingefügt werden:
** und an den Anfang der column_spec zusätzlich <code>FileLog:<logDevice>: bzw. DbLog:<logDevice>:</code> eingefügt werden:


aus:
aus:
:<code>define SVG_PCA301 SVG '''FileLog_PCA301_076035''':myGplotFile:CURRENT</code>
wird dann:
:<code>define SVG_PCA301 SVG '''lp''':myGplotFile:CURRENT</code>
und aus:
  #DbLog myDevice:myReading
  #DbLog myDevice:myReading
  #FileLog 4:PCA301_076035:power::
  #FileLog 4:PCA301_076035.power::
  #FileLog 4:<SPEC1>:consumption::
  #FileLog 4:<SPEC1>.consumption::


wird dann:
wird:
  #logProxy DbLog:myDb:myDevice:myReading
  '''#logProxy''' DbLog:'''myDb:'''myDevice:myReading
  #logProxy FileLog:FileLog_PCA301_076035:4:PCA301_076035.power::
  '''#logProxy''' FileLog:'''FileLog_PCA301_076035:'''4:PCA301_076035.power::
  #logProxy FileLog:FileLog_<SPEC1>:4:<SPEC1>.consumption::
  '''#logProxy''' FileLog:'''FileLog_<SPEC1>:'''4:<SPEC1>.consumption::
 
Inzwischen ist es möglich statt der #FileLog, #DbLog und #logProxy Schlüsselworte den fhem Devicenamen des logDevice zu verwenden. Hiermit lassen sich auch unterschiedliche Log-Devices mischen und es ist nicht mehr nötig alle column_spec Zeilen umzustellen.
 
== column_spec ==
{{Randnotiz|RNTyp=r|RNText=In diesen Zeilen darf es nur direkt nach <code>#logProxy</code> ein Leerzeichen geben. Im Rest der Zeile nicht mehr.}}
In einer solchen #logProxy Zeile kann dann Folgendes stehen:
* <code>FileLog:<log device>[,<options>]:<(alte) FileLog column_spec></code><br>Plot mit Daten aus dem FileLog <log device>
* <code>DbLog:<log device>,[<options>]:<(alte) DbLog column_spec></code><br>Plot mit Daten aus dem DbLog <log device>
* <code>ConstX:<zeit>,<y>[,<y2>]</code><br>Vertikale Linie zwischen <y> und <y2> am Zeitpunkt <zeit>
* <code>ConstY:<y>[,<von>[,<bis>]]</code><br>Horizontale Line bei <y>, optional nur zwischen <von> und <bis>
* <code>Func:myFunc(...)</code><br>über myFunc() dynamisch erzeugter Plot
* <code>Polar:[polarOptions]:<values></code><br>Plottet das <code>values</code>-Array in einem 'Spinnennetz'-Diagramm. numerische Arrays werden als zu plottende Werte betrachtet und String Arrays als Achsenbeschriftung.
 
Für ConstX, ConstY und Func wird alles nach dem ersten <code>:</code> als Perl-Ausdruck mit eval ausgewertet. Es dürfen keine weiteren : in diesen Zeilen vorhanden sein. Für Polar wird alles nach dem zweiten <code>:</code> als Perl-Ausdruck mit eval ausgewertet.
 
=== Mögliche <options> ===
Eine oder mehrere der folgenden Optionen sind durch Komma getrennt möglich:
* <code>predict[=<wert>]</code><br>Verlängert den letzten Wert eines Plots bis zum Ende des Plots oder um <wert> Sekunden aber maximal bis zum aktuellen Zeitpunkt.
* <code>offset=<wert></code><br>Verschiebt den Plot um <wert> Sekunden (oder um <wert> Monate wenn <wert> mit einem m endet)
* <code>extend=<wert></code><br>Erweitert den aus dem log device abgefragten Bereich am Anfang und am Ende um <wert> Sekunden (oder um <wert> Monate wenn <wert> mit einem m endet)<br>Damit kann ein Abriss des Plots am Anfang und Ende verhindert werden. Aktiviert automatisch auch <code>clip</code>.
* <code>interpolate</code><br>Aktiviert die Interpolation zwischen dem ersten/letzen Wert innerhalb des Plots und dem zugehörigen Wert im <code>extend</code> Bereich um die Werte für den Rand des Plots zu bestimmen. Sinnvoll für Plot-Type <code>lines</code>.
* <code>clip</code><br>Beschneidet die Plotdaten auf den zum Plotten ausgewählten Bereich. Nur in Verbindung mit <code>offset=<wert></code> und/oder <code>extend=<wert></code> sinnvoll.
* <code>postFn='<myPostFn>'</code><br>optionale postprocessing Funktion.
* <code>scale2reading=<\%hash></code>Ermöglicht es das Reading abhängig vom aktuellen zoom Faktor zu ändern.


==column-spec==
====Die optionale Postprocessing Funktion====
in einer solchen #logProxy zeile kann dann folgendes stehen:
Nachdem für eine Kurve alle Verarbeitungsschritte erfolgt sind wird <code>myPostFn($devspec,$data)</code> aufgerufen. Hierbei ist <code>$devspec</code> die zugehörige Zeile aus dem gplot-File und $data ein Array, das alle Datenpunkte dieser Kurve enthält. Jeder Datenpunkt ist ein Triplet aus Zeitpunkt in Sekunden, Wert an diesem Punkt und Zeitpunkt als String. Die postFn muss ein Array in gleichem Format zurückliefern, wobei die dritte Komponente jedes Punktes optional ist und nicht weiter ausgewertet wird. Das zurückgegebene Array muss nicht die gleiche Anzahl an Punkten enthalten wie das ursprüngliche.
*<code>FileLog:<log device>[,<options>]:<(alte) FileLog column_spec></code><br>Plot mit Daten aus dem FileLog <log device>
*<code>DbLog:<log device>,[<options>]:<(alte) DbLog column_spec></code><br>Plot mit Daten aus dem DbLog <log device>
*<code>ConstX:<zeit>,<y>[,<y2>]</code><br>Vertikale Linie zwischen <y> und <y2> am Zeitpunkt <zeit>
*<code>ConstY:<y>[,<von>[,<bis>]]</code><br>Horizintale Line bei <y>, optional nur zwischen <von> und <bis>
*<code>Func:myFunc(...)</code><br>über myFunc() dynamisch erzeugter Plot


Alles nach dem : hinter ConstX, ConstY und Func wird als Perl-Ausdruck mit eval ausgewertet. Es dürfen keine weiteren : in diesen Zeilen vorhanden sein.
====scale2reading====
Mit der scale2reading Option ist es möglich den für einen Plot verwendete Readingnamen abhängig von aktuellen Zoomfaktor zu überschreiben. Hierzu wird die aktuelle Auflösung als Key für ein Lookup im angegeben Hash verwendet. Das Ergebnis wird dann als neuer Readingname verwendet. Die möglichen keys sind: year, month, week, day, qday, hour.
   
   
===Mögliche <options>===
Im folgenden Beispiel wird in der jahres und monats Zoomstufe das reading <code>temperature_avg_day</code> (aus dem average modul) verwendet statt des <code>temperature</code> readings das in allen anderen Zoomstufe verwendet wird.
Ein oder mehrere der folgenden Optionen sind durch Komma getrennt möglich:
#logProxy DbLog:dbLog,scale2reading={year=>'temperature_avg_day',month=>'temperature_avg_day'}:s300ht_1:temperature::
*<code>offset=<wert></code><br>Verschiebt den Plot um <wert> Sekunden (oder um <wert> Monate wenn <wert> mit einem m endet)
*<code>extend=<wert></code><br>Erweitert den aus dem log device abgefragten Bereich am Anfang und am Ende um <wert> Sekunden (oder um <wert> Monate wenn <wert> mit einem m endet)<br>Damit kann ein Abriss des Plots am Anfang und Ende verhindert werden. TODO: Plot am Fenster clipen und nicht drüber hinaus zeichen.


=== Mögliche <polarOptions> ===
Eine oder mehrere der folgenden Optionen sind durch Komma getrennt möglich:
* <code>axis</code><br>Axen zeichnen
* <code>noaxis</code><br>Axen unterdrücken
* <code>range=<wert></code><br>TODO
* <code>segments=<wert></code><br>Die Anzahl der Segmente die der plot haben soll


===Eigene Funktionen===
Achsen werden automatisch aktiviert, wenn das <code>values</code>-Array Text enthält oder die Anzahl der <code>segment</code>e angegeben ist und keine <code>values</code>.
Im Aufruf eigener Funktionen die Daten zum Plotten liefern kann auf <code>$from</code> und <cpde>$to</code> (jeweils ein String mit dem Start- bzw. End zeitpunkt) zugegriffen werden. Die Funktion selber muss vier Werte zurück liefern:
 
*Die eigentlichen Punkte des Plots als String mit durch \n getrennten Elemente der Form
=== Eigene Funktionen ===
Im Aufruf eigener Funktionen, die Daten zum Plotten liefern, kann auf <code>$from</code> und <code>$to</code> (jeweils ein String mit dem Start- bzw. End-Zeitpunkt) zugegriffen werden. Die Funktion selber muss vier Werte zurückliefern:
* Die eigentlichen Punkte des Plots als String mit durch \n getrennten Elemente der Form
  yyyy-mm-dd_hh:mm:ss <wert>
  yyyy-mm-dd_hh:mm:ss <wert>
*die <code>min</code>, <code>max</code> und <code>currval</code> werte (optional)
* die <code>min</code>, <code>max</code> und <code>currval</code> werte (optional)
   
   
Ein Beispiel für eine solche Funktion ist logProxy_WeekProfile2Plot mit dem das Temperaturprofil von Heating_Control und WeekdayTimer devices sowie von HomeMatic und MAX Thermostaten geplottet werden kann.
Ein Beispiel für eine solche Funktion ist logProxy_WeekProfile2Plot, mit dem das Temperaturprofil von Heating_Control und WeekdayTimer devices sowie von [[HomeMatic]] und MAX Thermostaten geplottet werden kann.
 
Wenn der erste Paramter der Name eines passenden Devices ist, wird mit logProxy_Heating_Controll2WeekProfile, logProxy_HM2WeekProfile bzw. logProxy_MAX2WeekProfile aus den internen Daten bzw. Readings ein Wochenprofil erzeugt und dieses dann geplottet. Alternativ kann statt eines Devicenamen auch direkt das aufbereitete Wochenprofil als Hash der Form <code>{$wday}{$time}{$value}</code> (bei dem ein <code>$wday</code> von 0 Sonntag entspricht) übergeben werden.


Wenn der erste Paramter der Name eines passenden devices ist wird mit logProxy_Heating_Controll2WeekProfile, logProxy_HM2WeekProfile bzw. logProxy_MAX2WeekProfile aus den intern Daten bzw. readings ein Wochenprofil erzeugt und dieses dann geplottet. Alternativ kann statt eines device namens auch direkt das aufbereitetes Wochenprofil als hash der form <code>{$wday}{$time}{$value}</code> (bei dem ein <code>$wday</code> von 0 Sonntag entspricht) übergeben werden.
logProxy_WeekProfile2Plot hat noch einen vierten, optionalen, Paramter. Hier kann ein regulärer Ausdruck (Regex) angegeben werden, um aus dem Heating_Control oder WeekdayTimer Schaltwert den zu plottenden Wert zu extrahieren, z.B. so:
:<code>logProxy_WeekProfile2Plot("myHeatingControl",$from,$to,"(\\d*)\$")</code>


logProxy_WeekProfile2Plot hat noch einen vierten, optionalen, Paramter. Hier kann eine Regex angegeben werden um aus dem Heating_Controll oder WeekdayTimer Schaltwert den zu plottenden Wert zu extrahieren z.B. so:
=== Hilfen zum Manipulieren von Zeitpunkten ===
logProxy_WeekProfile2Plot("myHeatingControl",$from,$to,"(\\d*)\$")
* <code>SVG_time_to_sec($time)</code><br>Wandelt den String <code>$time</code> im format yyyy-mm-dd_hh:mm:ss in Sekunden um.
* <code>logProxy_shiftTime($time,$offset)</code><br>Verschiebt den Zeitpunkt <code>$time</code> (als String) um <code>$offset</code> Sekunden (oder um <code>$offset</code> Monate wenn <code>$offset</code> mit einem m endet).
* <code>logProxy_Range2Zoom($seconds)</code>


===Hilfen zum Manipulieren von Zeitpunkten===
=== Direkt verwendbare Beispielfunktionen ===
*SVG_time_to_sec($time)<br>Wandelt den String <code>$time</code> im format yyyy-mm-dd_hh:mm:ss in Sekunden um.
* <code>logProxy_WeekProfile2Plot($device, $from, $to [,$regex])</code>
*logProxy_shiftTime($time,$offset)<br>Verschiebt den Zeitpunkt <code>$time</code> (als String) um <code>$offset</code> Sekunden (oder um <code>$offset</code> Monate wenn <code>$offset</code> mit einem m endet).
* <code>logProxy_Func2Plot($from, $to, $func [,$step])</code>
* <code>logProxy_xy2Plot(\@xyPoints)</code>
* <code>logProxy_xyFile2Plot($file,$column,$regex)</code>
* <code>logProxy_values2Plot(\@xyPoints)</code>


==Beispiele==
== Beispiele ==
===x-achse bei y=0 einblenden===
=== X-Achse bei y=0 einblenden ===
Für Plots mit negativen Temperaturen oder Energie erzeugungs/verbrauchs Plots:
Für Plots mit negativen Temperaturen oder Energieerzeugung/-verbrauchs Plots:
   #logProxy DbLog:dbLog:s300ht:temperature::
   #logProxy DbLog:dbLog:s300ht:temperature::
   #logProxy ConstY:0
   #logProxy ConstY:0
Zeile 86: Zeile 125:
[[Datei:h-line.png]]
[[Datei:h-line.png]]


===Horizontale Linie an einer dynamisch berechneten Position einbenden===
=== Horizontale Linie an einer dynamisch berechneten Position einblenden ===
   #logProxy ConstY:myFunc(123)
   #logProxy ConstY:myFunc(123)


===Horizontale Line auf y-position des Durchnisttswertes eines anderen Plots einblenden===
=== Horizontale Line auf y-position des Durchschnittswertes eines anderen Plots einblenden ===
   #logProxy DbLog:dbLog:s300ht:temperature::
   #logProxy DbLog:dbLog:s300ht:temperature::
   #logProxy ConstY:$data{avg1}
   #logProxy ConstY:$data{avg1}
Zeile 98: Zeile 137:
[[Datei:h-line2.png]]
[[Datei:h-line2.png]]


===Min- und Max- Position eines Plots hervorheben===
=== Min- und Max- Position eines Plots hervorheben ===
  #logProxy DbLog:dbLog:s300ht_1:temperature::
  #logProxy DbLog:dbLog:s300ht_1:temperature::
  #logProxy ConstY:$data{avg1}
  #logProxy ConstY:$data{avg1}
Zeile 115: Zeile 154:
[[Datei:min-max.png]]
[[Datei:min-max.png]]


===Punkt ans Ende des geplottenen Bereiches eines anderen Plots setzen===
=== Punkt ans Ende des geplottenden Bereiches eines anderen Plots setzen ===
   #logProxy DbLog:dbLog:s300ht:temperature::
   #logProxy DbLog:dbLog:s300ht:temperature::
   #logProxy ConstX:logProxy_shiftTime($data{currdate1},0),$data{currval1}+0.00001
   #logProxy ConstX:logProxy_shiftTime($data{currdate1},0),$data{currval1}+0.00001
Zeile 125: Zeile 164:




===Vertikale Line zwischen Min- und Max Wert eines anderen Plots 60 minuten nach Plotanfang zeichnen===
=== Vertikale Line zwischen Min- und Max Wert eines anderen Plots 60 Minuten nach Plotanfang zeichnen ===
   #logProxy DbLog:dbLog:s300ht:temperature::
   #logProxy DbLog:dbLog:s300ht:temperature::
   #logProxy ConstX:logProxy_shiftTime($from,60*60),$data{min1},$data{max1}
   #logProxy ConstX:logProxy_shiftTime($from,60*60),$data{min1},$data{max1}
Zeile 136: Zeile 175:
[[Datei:min-max2.png]]
[[Datei:min-max2.png]]


===Ploten von dynamisch erzeugten Werten aus einer eigenen Funktion===
===Plotten von dynamisch erzeugten Werten aus einer eigenen Funktion===
   #logProxy Func:myFunc($from,$to)
   #logProxy Func:myFunc($from,$to)
   
   
   plot "<IN>" using 1:2 axes x1y1 title 'avg' ls l1 lw 1 with lines,\
   plot "<IN>" using 1:2 axes x1y1 title 'avg' ls l1 lw 1 with lines,\


===Plotten eines Weekday_Timer Wochenprofils===
=== Plotten eines Weekday_Timer Wochenprofils ===
   #logProxy Func:logProxy_WeekProfile2Plot("myHeatingTimer",$from,$to)
   #logProxy Func:logProxy_WeekProfile2Plot("myHeatingTimer",$from,$to)
   
   
Zeile 148: Zeile 187:
[[Datei:weekprofile.png]]
[[Datei:weekprofile.png]]


===Verschieben der avg_day Werte aus dem average modul um -24 Stunden um sie auf den richtigen Tag zu bekommen===
=== Verschieben der avg_day Werte aus dem average Modul um -24 Stunden, um sie auf den richtigen Tag zu bekommen ===
   
   
   #logProxy DbLog:dbLog:s300ht_1:temperature::
   #logProxy DbLog:dbLog:s300ht_1:temperature::
Zeile 162: Zeile 201:
[[Datei:logProxy-offset.png]]
[[Datei:logProxy-offset.png]]


Der Effekt ist auf dem Screenshot am besten 21. März zu sehen. Ohne die verschiebung wäre der Wert für den 21. erst am 22. zu sehen (dunkel rot), mit Verschiebung ist er korrekt am 21. zu sehen (hell rot).
Der Effekt ist auf dem Screenshot am besten 21. März zu sehen. Ohne die Verschiebung wäre der Wert für den 21. erst am 22. zu sehen (dunkel rot), mit Verschiebung ist er korrekt am 21. zu sehen (hell rot).


===Mischen von Daten aus meheren Quellen===
=== Mischen von Daten aus mehreren Quellen ===
Hier zwei FileLogs mit je zwei readings über plotfunction konfiguriert, ein reading aus einem DbLog und ein dynamisch erzeugtes wochenprofil direkt aus einem HM Thermostaten:
Hier zwei FileLogs mit je zwei readings über plotfunction konfiguriert, ein reading aus einem DbLog und ein dynamisch erzeugtes Wochenprofil direkt aus einem HM Thermostaten:


   #logProxy FileLog:FileLog_<SPEC1>:4:<SPEC1>.consumption::
   #logProxy FileLog:FileLog_<SPEC1>:4:<SPEC1>.consumption::
Zeile 174: Zeile 213:
   #logProxy Func:logProxy_WeekProfile2Plot("myTcClimate",$from,$to)
   #logProxy Func:logProxy_WeekProfile2Plot("myTcClimate",$from,$to)


===Erweitern des zu plottenden Bereichs um ausserhalb liegende Anfangs- und End- Werte===
=== Darstellung des aktuell aufgelaufenen Wertes, zusätzlich zu historischen Monats- oder Wochendaten aus einem Log ===
Die zugrunde liegende Idee hierbei ist, zusätzlich zu den geloggten historischen Werten den bis jetzt für den aktuellen Zeitraum aufgelaufenen Wert, der noch nicht geloggt ist, direkt aus dem entsprechenden Reading zu holen und ebenfalls zu plotten.
 
Hierzu wird in einer sub ähnlich der folgenden geprüft, ob der Timestamp des entsprechen Readings innerhalb des gerade dargestellten Bereiches liegt und dieses dann zum Plotten zurückgegeben:
sub
current2Plot($$$$)
{
  my($from,$to,$device,$reading) = @_;
  my $fromsec = SVG_time_to_sec($from);
  my $tosec  = SVG_time_to_sec($to);
  my $ret = "";
  my $rt = ReadingsTimestamp( $device, $reading, undef );
  return $ret if( !$rt );
  my $sec = time_str2num($rt);
  return $ret if ( $sec < $fromsec || $sec > $tosec );
  my $val = ReadingsVal( $device, $reading, undef );
  my @t = localtime($sec);
  my $timestamp = sprintf("%04d-%02d-%02d_%02d:%02d:%02d", $t[5]+1900, $t[4]+1, $t[3], $t[2], $t[1], $t[0]);
  $ret .= "$timestamp $val\n";
  $ret .= "#plotCurrent: $device:$reading\n";
  return $ret;
}
Je nach Zoomfaktor und Intervall der Darstellung muss das Ganze eventuell angepasst werden, indem nur mit Tages-Genauigkeit verglichen und angezeigt wird.
 
Zusätzlich zur #logProxy Zeile, die die historischen Daten plottet, wird jetzt noch eine Zeile für den aktuellen Wert und die zugehörige Plot-Anweisung ins gplot File eingebaut:
#logProxy Func:current2Plot($from,$to,"meinDevice","meinReading")
plot "<IN>" using 1:2 axes x1y2 title 'Aktuell' ls l0fill lw 0.5 with bars
 
=== Erweitern des zu plottenden Bereichs um ausserhalb liegende Anfangs- und Endwerte ===
  #logProxy DbLog:dbLog:s300ht_1:temperature::               
  #logProxy DbLog:dbLog:s300ht_1:temperature::               
  #logProxy DbLog:dbLog:s300ht_1:temperature_avg_day::   
  #logProxy DbLog:dbLog:s300ht_1:temperature_avg_day::   
Zeile 190: Zeile 264:
nachher:<br>
nachher:<br>
[[Datei:logProxy-extend2.png]]
[[Datei:logProxy-extend2.png]]
Auf dem unteren Bild ist vor allem links noch zu sehen, dass die mit "extend" erweiterte Kurve aus dem Plotbereich hinausläuft. Das ist in der aktuellen Version behoben.
=== Sonnenauf- und -untergangszeiten plotten ===
logProxy_Func2Plot() ist eine Funktion, die eine beliebige übergebene Funktion jeweils für unterschiedliche Zeitpunkte auswertet, um die zu plottenden Daten zu bestimmen. Das 'Zeitraster', in dem die Werte bestimmt werden, ist konfigurierbar und dynamisch von der aktuellen Zoomstufe abhängig. Der Default für Jahres- und Monatsplots sind tägliche, für Wochen- und Tagesplots stündliche, usw. Aufrufe.
Anbei ein Beispiel, das auf dieser Basis die Idee zum Plotten von Sonnenauf- und -untergangzeiten, die {{Link2Forum|Topic=23912|Message=171292|LinkText=im Forum}} vorgestellt wurde, durch 'live' berechnete (statt täglich geloggte) Daten umsetzt. Voraussetzung ist dabei, dass der Standort des Systems entsprechend für das Modul [[SUNRISE_EL]] vorgegeben wurde.
set yrange [4:10]
set y2range [16:23]
 
#logProxy Func:logProxy_Func2Plot($from,$to,'{logProxy_hms2dec(sunrise_abs_dat($sec))}')
#logProxy Func:logProxy_Func2Plot($from,$to,'{logProxy_hms2dec(sunset_abs_dat($sec))}')
#logProxy ConstX:TimeNow(),4,10 
                                                             
plot "<IN>" using 1:2 axes x1y1 title 'Sonnenaufgang' ls l2 lw 1 with steps,\
plot "<IN>" using 1:2 axes x1y2 title 'Somnnenuntergang' ls l0 lw 1 with steps,
plot "<IN>" using 1:2 axes x1y1 title notitle ls l5 lw 1 with steps,\
Das komplette Beispiel ist Teil der fhem.cfg.demo.
[[Datei:logProxy-sun.png]]
Um zusätzlich die anzahl der Tagesstunden zu plotten:
set y3label "Tagesstunden"
set y3range [8:19]
 
#logProxy Fund:logProxy_Func2Plot($from,$to,'{logProxy_hms2dec(sunset_abs_dat($sec))-logProxy_hms2dec(sunrise_abs_dat($sec))}')
 
plot "<IN>" using 1:2 axes x1y3 title notitle ls l5 lw 1 with steps,\
Darüber hinaus muss über das Attribut nrAxis die Axenanzahl vorgegeben werden z.B. {{Link2Forum|Topic=13617|Message=119160|LinkText=1,2}}.
[[Datei:logProxy-sun2.png]]
=== Tagesstunden in einem Plot farblich hinterlegen ===
Mit den folgenden Zeilen lassen sich in jedem Plot die jeweiligen Tagesstunden farblich hinterlegen.
  set y3range [0:1] 
 
  #logProxy Func:logProxy_Func2Plot($from,$to,'{logProxy_isDay($sec)}',{week=>60*30,day=>60*10,qday=>60})
 
  "<IN>" using 1:2 axes x1y3 title notitle ls l4fill lw 1 with fsteps,\
[[Datei:logProxy-sun3.png]]
=== Einfügen von Zonen ===
Mit der Hilfsfunktion logProxy_values2Plot lässt sich direkt ein Array aus datum,y-Korrdinatenpaaren als Quelle für die Punkte eines Plots verwenden. Hiermit können auch gefüllte Flächen dargestellt werden.
<pre>
#logProxy Func:logProxy_Func2Plot($from,$to,'{logProxy_hms2dec(sunrise_abs_dat($sec))}')
#logProxy Func:logProxy_Func2Plot($from,$to,'{logProxy_hms2dec(sunset_abs_dat($sec))}')
#logProxy Func:logProxy_values2Plot([[$from,19],[$to,19],[$to,21],[$from,21]])
                                                     
plot "<IN>" using 1:2 axes x1y1 title 'Sonnenaufgang' ls l2 lw 1 with steps,\
plot "<IN>" using 1:2 axes x1y2 title 'Sonnenuntergang' ls l0 lw 1 with steps,\
plot "<IN>" using 1:2 axes x1y2 title 'Box' ls l1fill lw 1 with lines,\
</pre>
[[Datei:logProxy-values.png]]
=== Daten aus x,y-Koordinatenpaaren plotten ===
{{Randnotiz|RNTyp=r|RNText=Das Umschalten vom Zeitpunkt/Wert Modus auf den X/Y Modus ist an das Vorhandensein der xrange-Anweisung im gplot File geknüpft.}}
Mit der Hilfsfunktion logProxy_xy2Plot lässt sich direkt ein Array aus x,y-Korrdinatenpaaren als Quelle für die Punkte eines Plots verwenden. In folgendem Beispiel sind alle Daten fest im Plotfile angegeben. Normalerweise würde zumindest der eigentliche Datenpunkt aus den Temperatur- und Feuchte-Readings eines FHEM-Device kommen.
<pre>
set xrange [12:28]
set yrange [0:100]
#lp Func:logProxy_xy2Plot([[18,40],[24,33],[22,65],[17,75],[18,40]])
#lp Func:logProxy_xy2Plot([[19,20],[25,18],[27,32],[24,60],[21,80],[17,85],[16,75],[17,35],[19,20]])
#lp Func:logProxy_xy2Plot([[22,40]])
                               
plot "<IN>" using 1:2 axes x1y1 title 'Behaglich' ls l1fill lw 1 with lines,\
    "<IN>" using 1:2 axes x1y1 title 'Noch Behaglich' ls l5 lw 1 with lines
    "<IN>" using 1:2 axes x1y1 title 'Wert' ls l0 lw 1 with points
</pre>
[[Datei:logProxy-xy.png]]
Die Koordinaten der beiden Polygone sind aus einer Grafik auf der Seite [http://www.raumluft.org/gesunde-raumluft/raumklima-behaglichkeit raumluft.org] nur grob abgelesen und nur beispielhaft zu verstehen.
=== x,y Daten aus einem File plotten ===
Daten aus einem File der Form
timestamp device reading: X,Y
d.h.
2017-01-20_18:14:12 ade V_INST: 0.01847,47338.99
lassen sich mit der <code>logProxy_xyFile2Plot</code> Funktion zum plotten aufbereiten. (Idee:  {{Link2Forum|Topic=65303|Message=566323|LinkText=Forum}})
<pre>
#adeinst.logproxy Func:logProxy_xyFile2Plot("/path-to/adeinst.log",4,"V_INST:")
#adeinst.logproxy Func:logProxy_xyFile2Plot("/path-to/adeinst.log",4,"IA_INST:")
#adeinst.logproxy Func:logProxy_xyFile2Plot("/path-to/adeinst.log",4,"IB_INST:")
plot "<IN>" using 1:2 axes x1y2 title 'V' ls l0 lw 1 with lines, \
    "<IN>" using 1:2 axes x1y2 title 'IA' ls l1 lw 1 with lines, \
    "<IN>" using 1:2 axes x1y2 title 'IB' ls l2 lw 1 with lines
</pre>
[[Datei:logProxy-xy2.png]]
=== Plotten in Polar-Koordinaten, Spinnennetz Darstellung ===
Das Plot-Fenster quadratisch machen:
attr <mySVG> plotsize 340,400
Die automatische Achsenbschriftung ausschalten, das Kooardinatensystem auf X/Y-Achsen schalten und die zu plottenden Daten jeweils in einem Perl Array bereitstellen. In diesem Beispiel die "temperature" und "desiredTemperature" Werte aller MAX-Devices.
set xtics ()
set ytics ()
set y2tics ()
set xrange [-40:40]
set yrange [-40:40]
#logProxy Polar::[map{ReadingsVal($_,"temperature",0)}devspec2array("MAX.*")]
#logProxy Polar::[map{ReadingsVal($_,"desiredTemperature",0)}devspec2array("MAX.*")]
#logProxy Polar::[map{ReadingsVal($_,"temperature",0)}devspec2array("MAX.*")]
#logProxy Polar::[devspec2array("MAX.*")]
plot "<IN>" using 1:2 axes x1y1 title 'Ist' ls l0 lw 1 with lines,\
plot "<IN>" using 1:2 axes x1y1 title 'Soll' ls l1fill lw 1 with lines,\
plot "<IN>" using 1:2 axes x1y1 notitle ls l0 lw 1 with points,\
plot "<IN>" using 1:2 axes x1y1 notitle  ls l2 lw 1 with lines,\
Um statt den Device-Namen den Device-Alias zu verwenden, kann die vierte logProxy Zeile durch die folgende ersetzt werden
#logProxy Polar::[map{AttrVal($_,"alias",$_)}devspec2array("MAX.*")]
Ein komplette Beispiel ist Teil der fhem.cfg.demo.
Um den Plot für HomeMatic Thermostate zu verwenden, sind die Reading-Namen <code>temperature</code> und <code>desiredTemperature</code> jeweils durch <code>measured-temp</code> und <code>desired-temp</code> zu ersetzen und der reguläre Ausdruck zum Finden der Devices entsprechend anzupassen. Je nach Installation zum Beispiel auf <code>.*Climate</code>.
Für ein paar Devices und für ein paar mehr:
[[Datei:logProxy-polar1.png]] [[Datei:logProxy-polar2.png]]
=== Plot Daten mit postFn verändern ===
Das folgende (nicht sehr sinnvolle) Beispiel verschiebt alle Werte einer Kurve um 10 nach oben.
Eine sinnvollere Anwendung wäre es z.B., Ausreißer zu filtern, Mittelwerte über einzelne Intervalle zu berechnen
sub   
myPostFn($$)
{     
  my($devspec,$array) = @_;
     
  foreach my $point ( @{$array} ) {
    $point->[1] += 10;
  }   
  return $array;
}
#logProxy DbLog:dbLog,postFn='myPostFn':s300ht_1:temperature::

Aktuelle Version vom 1. November 2017, 12:50 Uhr


logProxy
Zweck / Funktion
manipulieren und ergänzen von Plotdaten
Allgemein
Typ Hilfsmodul
Details
Dokumentation EN / DE
Support (Forum) Frontends
Modulname 98_logProxy.pm
Ersteller Andre (Forum / Wiki)
Wichtig: sofern vorhanden, gilt im Zweifel immer die (englische) Beschreibung in der commandref!


Das Hilfsmodul logProxy bietet die Möglichkeit, die Daten, die in einem SVG-Plot dargestellt werden, auf die folgenden Arten zu ergänzen und zu manipulieren:

  • horizontale und vertikale Linien an festen Positionen hinzufügen
  • Linien an dynamischen und von anderen Plots abhängigen Positionen hinzufügen (über die SVG specials min, max, mindate, maxdate, avg, currdate und currval)
  • plotten von dynamisch berechneten Kurven wie die Wochenprofile von Heating Control und WeekdayTimer Devices sowie HomeMatic und Max Thermostaten
  • mischen von Plots aus unterschiedlichen Quellen (DbLog und/oder mehrere FileLog Devices)
  • horizontales Verschieben von Plots zueinander, um die Daten aus den Average oder Statistic Modulen auf den richtigen Tag, Woche oder Monat zu schieben
  • Auffüllen am Anfang und Ende des Plots, um den Plotabriss zu vermeiden ohne zusätzliche Daten zu loggen.
  • Polar-/'Spinnennetz'-Darstellung

Alle Funktionen, die logProxy bereitstellt, werden im .gplot file über #logProxy Zeilen konfiguriert. Zusätzlich muss natürlich genau wie für die #FileLog bzw. #DbLog Zeilen jeweils eine eigene Plot-Zeile vorhanden sein.

Der Plot-Editor wird (hoffentlich) so gut es geht unterstützt. Leider sind die Dropdown Listen nicht dynamisch abhängig von einem anderen Feld konfigurierbar.

Das Modul ist seit dem 16.11.2014 eingecheckt und wir im regulären Update verteilt.

Vorbereitung

  • Anlegen eines logProxy devices:
define lp logProxy
  • Wenn Daten zu einem bestehenden Plot hinzugefügt werden sollen muss
    • das SVG device vom jeweiligen DbLog oder FileLog device auf das logProxy device umgestellt werden
    • im .gplot file die #FileLog bzw. #DbLog Zeilen in #logProxy geändert
    • und an den Anfang der column_spec zusätzlich FileLog:<logDevice>: bzw. DbLog:<logDevice>: eingefügt werden:

aus:

define SVG_PCA301 SVG FileLog_PCA301_076035:myGplotFile:CURRENT

wird dann:

define SVG_PCA301 SVG lp:myGplotFile:CURRENT

und aus:

#DbLog myDevice:myReading
#FileLog 4:PCA301_076035.power::
#FileLog 4:<SPEC1>.consumption::

wird:

#logProxy DbLog:myDb:myDevice:myReading
#logProxy FileLog:FileLog_PCA301_076035:4:PCA301_076035.power::
#logProxy FileLog:FileLog_<SPEC1>:4:<SPEC1>.consumption::

Inzwischen ist es möglich statt der #FileLog, #DbLog und #logProxy Schlüsselworte den fhem Devicenamen des logDevice zu verwenden. Hiermit lassen sich auch unterschiedliche Log-Devices mischen und es ist nicht mehr nötig alle column_spec Zeilen umzustellen.

column_spec

X mark.svgIn diesen Zeilen darf es nur direkt nach #logProxy ein Leerzeichen geben. Im Rest der Zeile nicht mehr.

In einer solchen #logProxy Zeile kann dann Folgendes stehen:

  • FileLog:<log device>[,<options>]:<(alte) FileLog column_spec>
    Plot mit Daten aus dem FileLog <log device>
  • DbLog:<log device>,[<options>]:<(alte) DbLog column_spec>
    Plot mit Daten aus dem DbLog <log device>
  • ConstX:<zeit>,<y>[,<y2>]
    Vertikale Linie zwischen <y> und <y2> am Zeitpunkt <zeit>
  • ConstY:<y>[,<von>[,<bis>]]
    Horizontale Line bei <y>, optional nur zwischen <von> und <bis>
  • Func:myFunc(...)
    über myFunc() dynamisch erzeugter Plot
  • Polar:[polarOptions]:<values>
    Plottet das values-Array in einem 'Spinnennetz'-Diagramm. numerische Arrays werden als zu plottende Werte betrachtet und String Arrays als Achsenbeschriftung.

Für ConstX, ConstY und Func wird alles nach dem ersten : als Perl-Ausdruck mit eval ausgewertet. Es dürfen keine weiteren : in diesen Zeilen vorhanden sein. Für Polar wird alles nach dem zweiten : als Perl-Ausdruck mit eval ausgewertet.


Mögliche <options>

Eine oder mehrere der folgenden Optionen sind durch Komma getrennt möglich:

  • predict[=<wert>]
    Verlängert den letzten Wert eines Plots bis zum Ende des Plots oder um <wert> Sekunden aber maximal bis zum aktuellen Zeitpunkt.
  • offset=<wert>
    Verschiebt den Plot um <wert> Sekunden (oder um <wert> Monate wenn <wert> mit einem m endet)
  • extend=<wert>
    Erweitert den aus dem log device abgefragten Bereich am Anfang und am Ende um <wert> Sekunden (oder um <wert> Monate wenn <wert> mit einem m endet)
    Damit kann ein Abriss des Plots am Anfang und Ende verhindert werden. Aktiviert automatisch auch clip.
  • interpolate
    Aktiviert die Interpolation zwischen dem ersten/letzen Wert innerhalb des Plots und dem zugehörigen Wert im extend Bereich um die Werte für den Rand des Plots zu bestimmen. Sinnvoll für Plot-Type lines.
  • clip
    Beschneidet die Plotdaten auf den zum Plotten ausgewählten Bereich. Nur in Verbindung mit offset=<wert> und/oder extend=<wert> sinnvoll.
  • postFn='<myPostFn>'
    optionale postprocessing Funktion.
  • scale2reading=<\%hash>Ermöglicht es das Reading abhängig vom aktuellen zoom Faktor zu ändern.

Die optionale Postprocessing Funktion

Nachdem für eine Kurve alle Verarbeitungsschritte erfolgt sind wird myPostFn($devspec,$data) aufgerufen. Hierbei ist $devspec die zugehörige Zeile aus dem gplot-File und $data ein Array, das alle Datenpunkte dieser Kurve enthält. Jeder Datenpunkt ist ein Triplet aus Zeitpunkt in Sekunden, Wert an diesem Punkt und Zeitpunkt als String. Die postFn muss ein Array in gleichem Format zurückliefern, wobei die dritte Komponente jedes Punktes optional ist und nicht weiter ausgewertet wird. Das zurückgegebene Array muss nicht die gleiche Anzahl an Punkten enthalten wie das ursprüngliche.

scale2reading

Mit der scale2reading Option ist es möglich den für einen Plot verwendete Readingnamen abhängig von aktuellen Zoomfaktor zu überschreiben. Hierzu wird die aktuelle Auflösung als Key für ein Lookup im angegeben Hash verwendet. Das Ergebnis wird dann als neuer Readingname verwendet. Die möglichen keys sind: year, month, week, day, qday, hour.

Im folgenden Beispiel wird in der jahres und monats Zoomstufe das reading temperature_avg_day (aus dem average modul) verwendet statt des temperature readings das in allen anderen Zoomstufe verwendet wird.

#logProxy DbLog:dbLog,scale2reading={year=>'temperature_avg_day',month=>'temperature_avg_day'}:s300ht_1:temperature::

Mögliche <polarOptions>

Eine oder mehrere der folgenden Optionen sind durch Komma getrennt möglich:

  • axis
    Axen zeichnen
  • noaxis
    Axen unterdrücken
  • range=<wert>
    TODO
  • segments=<wert>
    Die Anzahl der Segmente die der plot haben soll

Achsen werden automatisch aktiviert, wenn das values-Array Text enthält oder die Anzahl der segmente angegeben ist und keine values.

Eigene Funktionen

Im Aufruf eigener Funktionen, die Daten zum Plotten liefern, kann auf $from und $to (jeweils ein String mit dem Start- bzw. End-Zeitpunkt) zugegriffen werden. Die Funktion selber muss vier Werte zurückliefern:

  • Die eigentlichen Punkte des Plots als String mit durch \n getrennten Elemente der Form
yyyy-mm-dd_hh:mm:ss <wert>
  • die min, max und currval werte (optional)

Ein Beispiel für eine solche Funktion ist logProxy_WeekProfile2Plot, mit dem das Temperaturprofil von Heating_Control und WeekdayTimer devices sowie von HomeMatic und MAX Thermostaten geplottet werden kann.

Wenn der erste Paramter der Name eines passenden Devices ist, wird mit logProxy_Heating_Controll2WeekProfile, logProxy_HM2WeekProfile bzw. logProxy_MAX2WeekProfile aus den internen Daten bzw. Readings ein Wochenprofil erzeugt und dieses dann geplottet. Alternativ kann statt eines Devicenamen auch direkt das aufbereitete Wochenprofil als Hash der Form {$wday}{$time}{$value} (bei dem ein $wday von 0 Sonntag entspricht) übergeben werden.

logProxy_WeekProfile2Plot hat noch einen vierten, optionalen, Paramter. Hier kann ein regulärer Ausdruck (Regex) angegeben werden, um aus dem Heating_Control oder WeekdayTimer Schaltwert den zu plottenden Wert zu extrahieren, z.B. so:

logProxy_WeekProfile2Plot("myHeatingControl",$from,$to,"(\\d*)\$")

Hilfen zum Manipulieren von Zeitpunkten

  • SVG_time_to_sec($time)
    Wandelt den String $time im format yyyy-mm-dd_hh:mm:ss in Sekunden um.
  • logProxy_shiftTime($time,$offset)
    Verschiebt den Zeitpunkt $time (als String) um $offset Sekunden (oder um $offset Monate wenn $offset mit einem m endet).
  • logProxy_Range2Zoom($seconds)

Direkt verwendbare Beispielfunktionen

  • logProxy_WeekProfile2Plot($device, $from, $to [,$regex])
  • logProxy_Func2Plot($from, $to, $func [,$step])
  • logProxy_xy2Plot(\@xyPoints)
  • logProxy_xyFile2Plot($file,$column,$regex)
  • logProxy_values2Plot(\@xyPoints)

Beispiele

X-Achse bei y=0 einblenden

Für Plots mit negativen Temperaturen oder Energieerzeugung/-verbrauchs Plots:

 #logProxy DbLog:dbLog:s300ht:temperature::
 #logProxy ConstY:0

 plot "<IN>" using 1:2 axes x1y1 title 'temp' ls l1 lw 1 with steps,\
      "<IN>" using 1:2 axes x1y1 ls l5 lw 1 with lines,\

H-line.png

Horizontale Linie an einer dynamisch berechneten Position einblenden

 #logProxy ConstY:myFunc(123)

Horizontale Line auf y-position des Durchschnittswertes eines anderen Plots einblenden

 #logProxy DbLog:dbLog:s300ht:temperature::
 #logProxy ConstY:$data{avg1}

 plot "<IN>" using 1:2 axes x1y1 title 'temp' ls l1 lw 1 with steps,\
      "<IN>" using 1:2 axes x1y1 title 'avg' ls l3 lw 1 with lines,\

H-line2.png

Min- und Max- Position eines Plots hervorheben

#logProxy DbLog:dbLog:s300ht_1:temperature::
#logProxy ConstY:$data{avg1}
#logProxy ConstX:$data{mindate1},$data{min1}
#logProxy ConstX:$data{maxdate1},$data{max1}
#logProxy ConstX:$data{mindate1},$data{min1},$data{avg1} 
#logProxy ConstX:$data{maxdate1},$data{max1},$data{avg1} 
 
plot "<IN>" using 1:2 axes x1y1 title 'temp' ls l2 lw 1 with steps,\
     "<IN>" using 1:2 axes x1y1 title 'avg' ls l5 lw 1 with lines,\
     "<IN>" using 1:2 axes x1y1 ls l0 lw 1 with points,\
     "<IN>" using 1:2 axes x1y1 ls l0 lw 1 with points,\
     "<IN>" using 1:2 axes x1y1 ls l0 lw 1 with lines,\
     "<IN>" using 1:2 axes x1y1 ls l0 lw 1 with lines,\

Min-max.png

Punkt ans Ende des geplottenden Bereiches eines anderen Plots setzen

 #logProxy DbLog:dbLog:s300ht:temperature::
 #logProxy ConstX:logProxy_shiftTime($data{currdate1},0),$data{currval1}+0.00001

 plot "<IN>" using 1:2 axes x1y1 title 'temp' ls l1 lw 1 with steps,\
      "<IN>" using 1:2 axes x1y1 ls l0 lw 1 with points,\

End-dot.png


Vertikale Line zwischen Min- und Max Wert eines anderen Plots 60 Minuten nach Plotanfang zeichnen

 #logProxy DbLog:dbLog:s300ht:temperature::
 #logProxy ConstX:logProxy_shiftTime($from,60*60),$data{min1},$data{max1}
 #logProxy ConstX:logProxy_shiftTime($from,60*60),$data{min1},$data{max1}

 plot "<IN>" using 1:2 axes x1y1 title 'temp' ls l1 lw 1 with steps,\
      "<IN>" using 1:2 axes x1y1 title 'minmax' ls l0 lw 1 with lines,\
      "<IN>" using 1:2 axes x1y1 ls l0 lw 1 with points,\

Min-max2.png

Plotten von dynamisch erzeugten Werten aus einer eigenen Funktion

 #logProxy Func:myFunc($from,$to)

 plot "<IN>" using 1:2 axes x1y1 title 'avg' ls l1 lw 1 with lines,\

Plotten eines Weekday_Timer Wochenprofils

 #logProxy Func:logProxy_WeekProfile2Plot("myHeatingTimer",$from,$to)

 plot "<IN>" using 1:2 axes x1y1 title 'profile' ls l2 lw 1 with steps,\

Weekprofile.png

Verschieben der avg_day Werte aus dem average Modul um -24 Stunden, um sie auf den richtigen Tag zu bekommen

 #logProxy DbLog:dbLog:s300ht_1:temperature::
 #logProxy DbLog:dbLog:s300ht_1:temperature_avg_day::
 #logProxy DbLog:dbLog,offset=-60*60*24:s300ht_1:temperature_avg_day::
 #logProxy ConstY:$data{avg1}

 plot "<IN>" using 1:2 axes x1y1 title 'temp' ls l2 lw 1 with steps,\
      "<IN>" using 1:2 axes x1y1 title 'avg_day' ls l4 lw 1 with steps,\
      "<IN>" using 1:2 axes x1y1 title 'avg_day_shifted' ls l0 lw 1 with steps,\
      "<IN>" using 1:2 axes x1y1 title 'avg' ls l5 lw 1 with lines,\

LogProxy-offset.png

Der Effekt ist auf dem Screenshot am besten 21. März zu sehen. Ohne die Verschiebung wäre der Wert für den 21. erst am 22. zu sehen (dunkel rot), mit Verschiebung ist er korrekt am 21. zu sehen (hell rot).

Mischen von Daten aus mehreren Quellen

Hier zwei FileLogs mit je zwei readings über plotfunction konfiguriert, ein reading aus einem DbLog und ein dynamisch erzeugtes Wochenprofil direkt aus einem HM Thermostaten:

 #logProxy FileLog:FileLog_<SPEC1>:4:<SPEC1>.consumption::
 #logProxy FileLog:FileLog_<SPEC1>:4:<SPEC1>.power::
 #logProxy FileLog:FileLog_<SPEC2>:4:<SPEC2>.consumption::
 #logProxy FileLog:FileLog_<SPEC2>:4:<SPEC2>.power::
 #logProxy DbLog:dbLog:s300ht:temperature::
 #logProxy Func:logProxy_WeekProfile2Plot("myTcClimate",$from,$to)

Darstellung des aktuell aufgelaufenen Wertes, zusätzlich zu historischen Monats- oder Wochendaten aus einem Log

Die zugrunde liegende Idee hierbei ist, zusätzlich zu den geloggten historischen Werten den bis jetzt für den aktuellen Zeitraum aufgelaufenen Wert, der noch nicht geloggt ist, direkt aus dem entsprechenden Reading zu holen und ebenfalls zu plotten.

Hierzu wird in einer sub ähnlich der folgenden geprüft, ob der Timestamp des entsprechen Readings innerhalb des gerade dargestellten Bereiches liegt und dieses dann zum Plotten zurückgegeben:

sub
current2Plot($$$$)
{
  my($from,$to,$device,$reading) = @_;
  my $fromsec = SVG_time_to_sec($from);
  my $tosec   = SVG_time_to_sec($to);

  my $ret = "";

  my $rt = ReadingsTimestamp( $device, $reading, undef );
  return $ret if( !$rt );

  my $sec = time_str2num($rt);
  return $ret if ( $sec < $fromsec || $sec > $tosec );

  my $val = ReadingsVal( $device, $reading, undef );

  my @t = localtime($sec);
  my $timestamp = sprintf("%04d-%02d-%02d_%02d:%02d:%02d", $t[5]+1900, $t[4]+1, $t[3], $t[2], $t[1], $t[0]);

  $ret .= "$timestamp $val\n";
  $ret .= "#plotCurrent: $device:$reading\n";

  return $ret;
}

Je nach Zoomfaktor und Intervall der Darstellung muss das Ganze eventuell angepasst werden, indem nur mit Tages-Genauigkeit verglichen und angezeigt wird.

Zusätzlich zur #logProxy Zeile, die die historischen Daten plottet, wird jetzt noch eine Zeile für den aktuellen Wert und die zugehörige Plot-Anweisung ins gplot File eingebaut:

#logProxy Func:current2Plot($from,$to,"meinDevice","meinReading")
plot "<IN>" using 1:2 axes x1y2 title 'Aktuell' ls l0fill lw 0.5 with bars

Erweitern des zu plottenden Bereichs um ausserhalb liegende Anfangs- und Endwerte

#logProxy DbLog:dbLog:s300ht_1:temperature::              
#logProxy DbLog:dbLog:s300ht_1:temperature_avg_day::   
#logProxy DbLog:dbLog,offset=-60*60*24,extend=60*60*24:s300ht_1:temperature_avg_day::
#logProxy ConstY:$data{avg1}                              
                                                          
plot "<IN>" using 1:2 axes x1y1 title 'temp' ls l2 lw 1 with steps,\
     "<IN>" using 1:2 axes x1y1 title 'avg_day' ls l4 lw 1 with steps,\
     "<IN>" using 1:2 axes x1y1 title 'avg_day_shifted' ls l0 lw 1 with steps,\
     "<IN>" using 1:2 axes x1y1 title 'avg' ls l5 lw 1 with lines,\

vorher:
LogProxy-extend.png

nachher:
LogProxy-extend2.png

Auf dem unteren Bild ist vor allem links noch zu sehen, dass die mit "extend" erweiterte Kurve aus dem Plotbereich hinausläuft. Das ist in der aktuellen Version behoben.

Sonnenauf- und -untergangszeiten plotten

logProxy_Func2Plot() ist eine Funktion, die eine beliebige übergebene Funktion jeweils für unterschiedliche Zeitpunkte auswertet, um die zu plottenden Daten zu bestimmen. Das 'Zeitraster', in dem die Werte bestimmt werden, ist konfigurierbar und dynamisch von der aktuellen Zoomstufe abhängig. Der Default für Jahres- und Monatsplots sind tägliche, für Wochen- und Tagesplots stündliche, usw. Aufrufe.

Anbei ein Beispiel, das auf dieser Basis die Idee zum Plotten von Sonnenauf- und -untergangzeiten, die im Forum vorgestellt wurde, durch 'live' berechnete (statt täglich geloggte) Daten umsetzt. Voraussetzung ist dabei, dass der Standort des Systems entsprechend für das Modul SUNRISE_EL vorgegeben wurde.

set yrange [4:10]
set y2range [16:23]
 
#logProxy Func:logProxy_Func2Plot($from,$to,'{logProxy_hms2dec(sunrise_abs_dat($sec))}')
#logProxy Func:logProxy_Func2Plot($from,$to,'{logProxy_hms2dec(sunset_abs_dat($sec))}')
#logProxy ConstX:TimeNow(),4,10  
                                                             
plot "<IN>" using 1:2 axes x1y1 title 'Sonnenaufgang' ls l2 lw 1 with steps,\
plot "<IN>" using 1:2 axes x1y2 title 'Somnnenuntergang' ls l0 lw 1 with steps,
plot "<IN>" using 1:2 axes x1y1 title notitle ls l5 lw 1 with steps,\

Das komplette Beispiel ist Teil der fhem.cfg.demo.

LogProxy-sun.png

Um zusätzlich die anzahl der Tagesstunden zu plotten:

set y3label "Tagesstunden"
set y3range [8:19]
 
#logProxy Fund:logProxy_Func2Plot($from,$to,'{logProxy_hms2dec(sunset_abs_dat($sec))-logProxy_hms2dec(sunrise_abs_dat($sec))}')
 
plot "<IN>" using 1:2 axes x1y3 title notitle ls l5 lw 1 with steps,\

Darüber hinaus muss über das Attribut nrAxis die Axenanzahl vorgegeben werden z.B. 1,2.

LogProxy-sun2.png

Tagesstunden in einem Plot farblich hinterlegen

Mit den folgenden Zeilen lassen sich in jedem Plot die jeweiligen Tagesstunden farblich hinterlegen.

 set y3range [0:1]  
 
 #logProxy Func:logProxy_Func2Plot($from,$to,'{logProxy_isDay($sec)}',{week=>60*30,day=>60*10,qday=>60})
 
 "<IN>" using 1:2 axes x1y3 title notitle ls l4fill lw 1 with fsteps,\ 

LogProxy-sun3.png

Einfügen von Zonen

Mit der Hilfsfunktion logProxy_values2Plot lässt sich direkt ein Array aus datum,y-Korrdinatenpaaren als Quelle für die Punkte eines Plots verwenden. Hiermit können auch gefüllte Flächen dargestellt werden.

#logProxy Func:logProxy_Func2Plot($from,$to,'{logProxy_hms2dec(sunrise_abs_dat($sec))}')
#logProxy Func:logProxy_Func2Plot($from,$to,'{logProxy_hms2dec(sunset_abs_dat($sec))}')
#logProxy Func:logProxy_values2Plot([[$from,19],[$to,19],[$to,21],[$from,21]])
                                                       
plot "<IN>" using 1:2 axes x1y1 title 'Sonnenaufgang' ls l2 lw 1 with steps,\
plot "<IN>" using 1:2 axes x1y2 title 'Sonnenuntergang' ls l0 lw 1 with steps,\
plot "<IN>" using 1:2 axes x1y2 title 'Box' ls l1fill lw 1 with lines,\

LogProxy-values.png

Daten aus x,y-Koordinatenpaaren plotten

X mark.svgDas Umschalten vom Zeitpunkt/Wert Modus auf den X/Y Modus ist an das Vorhandensein der xrange-Anweisung im gplot File geknüpft.

Mit der Hilfsfunktion logProxy_xy2Plot lässt sich direkt ein Array aus x,y-Korrdinatenpaaren als Quelle für die Punkte eines Plots verwenden. In folgendem Beispiel sind alle Daten fest im Plotfile angegeben. Normalerweise würde zumindest der eigentliche Datenpunkt aus den Temperatur- und Feuchte-Readings eines FHEM-Device kommen.

set xrange [12:28]
set yrange [0:100]

#lp Func:logProxy_xy2Plot([[18,40],[24,33],[22,65],[17,75],[18,40]])
#lp Func:logProxy_xy2Plot([[19,20],[25,18],[27,32],[24,60],[21,80],[17,85],[16,75],[17,35],[19,20]])
#lp Func:logProxy_xy2Plot([[22,40]])
                                 
plot "<IN>" using 1:2 axes x1y1 title 'Behaglich' ls l1fill lw 1 with lines,\
     "<IN>" using 1:2 axes x1y1 title 'Noch Behaglich' ls l5 lw 1 with lines
     "<IN>" using 1:2 axes x1y1 title 'Wert' ls l0 lw 1 with points

LogProxy-xy.png

Die Koordinaten der beiden Polygone sind aus einer Grafik auf der Seite raumluft.org nur grob abgelesen und nur beispielhaft zu verstehen.


x,y Daten aus einem File plotten

Daten aus einem File der Form

timestamp device reading: X,Y

d.h.

2017-01-20_18:14:12 ade V_INST: 0.01847,47338.99

lassen sich mit der logProxy_xyFile2Plot Funktion zum plotten aufbereiten. (Idee: Forum)

#adeinst.logproxy Func:logProxy_xyFile2Plot("/path-to/adeinst.log",4,"V_INST:")
#adeinst.logproxy Func:logProxy_xyFile2Plot("/path-to/adeinst.log",4,"IA_INST:")
#adeinst.logproxy Func:logProxy_xyFile2Plot("/path-to/adeinst.log",4,"IB_INST:")

plot "<IN>" using 1:2 axes x1y2 title 'V' ls l0 lw 1 with lines, \
     "<IN>" using 1:2 axes x1y2 title 'IA' ls l1 lw 1 with lines, \
     "<IN>" using 1:2 axes x1y2 title 'IB' ls l2 lw 1 with lines

LogProxy-xy2.png

Plotten in Polar-Koordinaten, Spinnennetz Darstellung

Das Plot-Fenster quadratisch machen:

attr <mySVG> plotsize 340,400

Die automatische Achsenbschriftung ausschalten, das Kooardinatensystem auf X/Y-Achsen schalten und die zu plottenden Daten jeweils in einem Perl Array bereitstellen. In diesem Beispiel die "temperature" und "desiredTemperature" Werte aller MAX-Devices.

set xtics ()
set ytics ()
set y2tics ()

set xrange [-40:40]
set yrange [-40:40]
#logProxy Polar::[map{ReadingsVal($_,"temperature",0)}devspec2array("MAX.*")]
#logProxy Polar::[map{ReadingsVal($_,"desiredTemperature",0)}devspec2array("MAX.*")]
#logProxy Polar::[map{ReadingsVal($_,"temperature",0)}devspec2array("MAX.*")]
#logProxy Polar::[devspec2array("MAX.*")]

plot "<IN>" using 1:2 axes x1y1 title 'Ist' ls l0 lw 1 with lines,\
plot "<IN>" using 1:2 axes x1y1 title 'Soll' ls l1fill lw 1 with lines,\
plot "<IN>" using 1:2 axes x1y1 notitle ls l0 lw 1 with points,\
plot "<IN>" using 1:2 axes x1y1 notitle  ls l2 lw 1 with lines,\

Um statt den Device-Namen den Device-Alias zu verwenden, kann die vierte logProxy Zeile durch die folgende ersetzt werden

#logProxy Polar::[map{AttrVal($_,"alias",$_)}devspec2array("MAX.*")]

Ein komplette Beispiel ist Teil der fhem.cfg.demo.

Um den Plot für HomeMatic Thermostate zu verwenden, sind die Reading-Namen temperature und desiredTemperature jeweils durch measured-temp und desired-temp zu ersetzen und der reguläre Ausdruck zum Finden der Devices entsprechend anzupassen. Je nach Installation zum Beispiel auf .*Climate.

Für ein paar Devices und für ein paar mehr:

LogProxy-polar1.png LogProxy-polar2.png

Plot Daten mit postFn verändern

Das folgende (nicht sehr sinnvolle) Beispiel verschiebt alle Werte einer Kurve um 10 nach oben.

Eine sinnvollere Anwendung wäre es z.B., Ausreißer zu filtern, Mittelwerte über einzelne Intervalle zu berechnen

sub    
myPostFn($$)
{      
  my($devspec,$array) = @_; 
      
  foreach my $point ( @{$array} ) { 
    $point->[1] += 10;
  }    

  return $array;
}
#logProxy DbLog:dbLog,postFn='myPostFn':s300ht_1:temperature::