ein paar optimierungen und OldReadings routinen analog zu OldValue

Begonnen von justme1968, 07 März 2018, 20:35:36

Vorheriges Thema - Nächstes Thema

justme1968

manchmal ist es recht praktisch auf wert eines readings zuzugreifen den dieses vor der aktuellen änderung hatte. statt dies auf user ebene von hand umzusetzen oder auf modul ebene schlage ich vor das dies so wie bei OldValue zentral in fhem passiert.

dafür implementiert der angehängte patch das neue attribut oldreadings mit dem in jedem device konfiguriert werden kann für welche readings der zugriff auf den altwert möglich sein soll. der zugriff erfolgt über OldReadingsAge, OldReadingsNum, OldReadingsTimestamp und OldReadingsVal routinen analog zu OldValue und OldTimestamp

beim erstellen der änderung ist mir aufgefallen, das im code für die event-.* attribute das abfragen und splitten der attributwerte bei jedem aufruf von readingsBeginUpdate erneut passiert. das ist eigentlich unnötig. man kann die werte auch direkt beim setzen in CommandAttr einmal cachen.

der angehängte patch implementiert zum einen das oldreadings attribut und die oben erwähnten zugriffsroutinen, zum anderen auch noch das cachen der aufbereiteten event-.* attribute. zusätzlich habe ich noch CommandDeleteReading auf readingsDelete umgestellt.

wenn die oldreadings anklang findet schreibe ich noch die commandref ergänzung.

beim testen sind mir keine seiteneffekte aufgefallen. es gibt aber ein paar module die diese attribute über %attr direkt setzen. dort wird es probleme geben. wie sollen wir damit umgehen?


eine mögliche erweiterung könnte noch sein: im oldreadings attribut zusätzlich noch angeben wie viele generationen eines readings aufgehoben werden sollen. damit könnte man dann die implementierung eines gleitenden mittelwertes vereinfachen.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

rudolfkoenig

Bevor ich es einchecke, habe ich ein paar Fragen/Bemerkungen:
- ich wuerde die Zeile "$hash->{$cache} = \@a if( $cache );" ausserhalb der for-Schleife packen
- warum wird OLDREADINGSVAL nur dann gesetzt, falls der Wert sich unterscheidet?
- irgendwie "tut mir weh", dass die Old* Routinen nur in OLDREADINGS von den bisherigen Routinen unterscheiden. Eine Alternative waere mit den bisherigen Readings* Routinen OLDREADINGS anzusprechen, falls man einen weiteren Parameter auf 1 setzt. Bin aber unsicher, und lasse mich leicht ueberstimmen.
- das Cachen der vorverdauten event-* Parameter tauscht Geschwindigkeit gegen Speicherverbrauch. Habe zwar nichts dagegen, sollte aber einem bewusst sein.

justme1968

- ja. die zeile muss nach die schleife. das ist beim aufräumen passiert.
- weil es besonders dann nützlich ist wenn man auf änderungen triggern will. nicht wenn der gleiche wert immer wieder gesetzt wird. das passiert aber intern selbst dann wenn kein event erzeugt wird. wenn man es konfigurierbar macht wird es recht komplex da mann dan die event- und vor allem das timestamp-on-change attribut passend setzen und berücksichtigen muss.
- ja. das fand ich auch nicht wirklich schön. so ein altmodischer präprozessor oder ganz moderne templates gibt es aber in perl nicht :). unterm strich wird es aber auch damit (oder mit dem auslagern der gemeinsamen teile) nicht wirklich kürzer. den extra parameter finde ich ich nicht gut, zumal du durch die dann in allen drei routinen nötige fallunterscheidung an gesamt code länge auch wieder nichts sparst.
- ja. aber im zweifel stecke ich lieber ein mal mehr speicher in einen rechner und spare dann bei jedem einzelnen readingsBeginUpdate. wie gross beide effekte sind müßte man testen. von besserem cache verhalten durch weniger temporäre variablen, besserer garbage collection und weniger speicher verschnitt und weiteren effekten kann ja alles mögliche noch mit hinein spielen. 
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

rudolfkoenig

Habs mit der kleinen Aenderung aus dem ersten Punkt eingecheckt.

justme1968

hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

justme1968

es haben sich noch zwei falsche prototypen eingeschlichen :(:--- fhem.pl (revision 16352)
+++ fhem.pl (working copy)
@@ -85,13 +85,13 @@
sub Log3($$$);
sub OldTimestamp($);
sub OldValue($);
-sub OldReadingsAge($$$;$);
+sub OldReadingsAge($$$);
sub OldReadingsNum($$$;$);
sub OldReadingsTimestamp($$$);
sub OldReadingsVal($$$);
sub OpenLogfile($);
sub PrintHash($$);
-sub ReadingsAge($$$;$);
+sub ReadingsAge($$$);
sub ReadingsNum($$$;$);
sub ReadingsTimestamp($$$);
sub ReadingsVal($$$);
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

rudolfkoenig

Zitathier noch die ergänzung für die commandref.
Danke, habs im Browser geprueft und eingecheckt.Die Prototypen habe ich auch angepasst.

Dr. Boris Neubert

Zitat von: justme1968 am 07 März 2018, 20:35:36
eine mögliche erweiterung könnte noch sein: im oldreadings attribut zusätzlich noch angeben wie viele generationen eines readings aufgehoben werden sollen. damit könnte man dann die implementierung eines gleitenden mittelwertes vereinfachen.

Gleitende Mittelwerte sind per TimeSeries.pm mittels event-aggregator schon als userReading eingebaut.
Globaler Moderator, Developer, aktives Mitglied des FHEM e.V. (Marketing, Verwaltung)
Bitte keine unaufgeforderten privaten Nachrichten!

CoolTux

Vielen Dank für die sehr nützlichen Funktionen. Habe ich gleich mal meine eigen Entwickler mit ab gelöst  ;D


Grüße
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

justme1968

#9
@rudi: ich wurde eben noch auf ein problem hingewiesen.

ohne die folgende änderung:--- fhem.pl (revision 16393)
+++ fhem.pl (working copy)
@@ -2816,6 +2816,7 @@

         my @a = split($ra{$attrName}{s}, $lval) ;
         for my $v (@a) {
+          my $v = $v; #without this $v is only a reference into @a and @a will be changed by the following s///
           $v =~ s/$ra{$attrName}{r}// if($ra{$attrName}{r});
           my $err ="Argument $v for attr $sdev $attrName is not a valid regexp";
           return "$err: use .* instead of *" if($v =~ /^\*/); # no err in eval!?


ist das $v aus dem for scheinbar nur eine referenz in das array nur ein alias auf den wert im array und die nachfolgende suchen und ersetzen operation ändert nicht nur $v sondern auch das original im array. was dann zur folge hat das im cache die werte unvollständig sind da bei event-on-change-reading und timestamp-on-change-reading die optionalen :<wert> komponenten abgeschnitten werden.

mit der obigen änderung und der zusätzlichen kopie ist das problem behoben.

der grund warum das beim testen nicht aufgefallen ist: 362   "event-min-interval"         => { s=>",", c=>".attrminint", r=>";.*" }, hier ist schon immer eine falsche regex im code. ; statt :. dadurch erfolgt aktuell für event-min-interval die prüfung auf regex gültigkeit nicht.

mit beiden änderungen sollte wieder alles gehen wie gehabt.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

rudolfkoenig

Danke fuer den Hinweis, ich habe den Regexp auf ":.*" geaendert, und dein "Patch" eingespielt.