Kleine Rechenaufgabe in Perl

Begonnen von Superposchi, 24 Juni 2022, 22:56:02

Vorheriges Thema - Nächstes Thema

Superposchi

Hallo, ich bräuchte mal Hilfe bei einem kleinen Projekt.

Keine Ahnung ob es ein passenderes Unterforum gibt, wüsste jetzt aktuell keins.

Ich überwache mehrere Tankstellen und logge die Preisänderungen mit.
Jetzt würde ich mir aus dem Logfile gerne den Durchschnittswert der letzten 24 oder 48 Stunden und den niedrigsten Wert der letzten 7 Tage errechnen. Dann soll bei jeder Änderung der aktuelle wert entsprechend mit den errechneten Preise vergleichen werden und bei bestimmten Kriterien eine Meldung ausgegeben werden.

Die Perl-Funktionen sind mir bekannt, allerdings weiß ich nicht wie ich die einzelnen Werte aus dem Logfile abrufen kann.
Kann man überhaupt einzelne Werte aus einem Logfile extrahieren?
Oder muss ich jeden Wert immer in ein UserReading schreiben und einzelnd speichern?

betateilchen

Es gibt doch fertige Module, die solche Berechnungen machen? (average, statistics)
Warum willst Du das Rad neu erfinden?

Und ja, man kann einzelne Werte aus dem Logfile auslesen. Dabei orientiert man sich an Zeiträumen.
Schau mal in die commandref zu Filelog, da ist das bei "get" beschrieben.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Superposchi

Das mit den fertigen Modulen war mir nicht bekannt - schaue ich mir an.

Danke erst mal

bartman121

Moin,

Wäre es möglich den Titel des Threads irgendwie sinnvoll zu schreiben?
"Mittelwert letzte x Stunden berechnen"....

Da es hier tatsächlich um letzte x Stunden geht:
Das würde man dann gleitende Mittelwerte nennen
https://wiki.fhem.de/wiki/Gleitende_Mittelwerte_berechnen_und_loggen

Viele Grüße

Andreas

Superposchi

Also erst mal kurze Klarstellung:
Hauptpunkt ist für mich der Niedrigste Preis, nicht der Durchschnittswert. Letzteres ist nur als hübsche Beiinformation gedacht.

Ich habe es jetzt mal mit dem statistic-Module versucht umzusetzen.
Hier ist das List des device:
Internals:
   CFGFN     
   DEF        Tankstelle_oberforstbach|Tankstelle_Uebach|Tankstelle_Jet
   DEV_REGEXP Tankstelle_oberforstbach|Tankstelle_Uebach|Tankstelle_Jet
   FUUID      62b6ca6f-f33f-6c14-854d-b5acbbc65c41146f
   NAME       Statistik
   NOTIFYDEV  global,Tankstelle_oberforstbach|Tankstelle_Uebach|Tankstelle_Jet
   NR         433872
   NTFY_ORDER 10-Statistik
   PREFIX     stat
   STATE      Updated stats for: Tankstelle_oberforstbach
   TYPE       statistics
   READINGS:
     2022-06-25 11:00:12   monitoredDevicesHTTPMOD Tankstelle_Uebach,Tankstelle_oberforstbach,Tankstelle_Jet
     2022-06-25 10:42:34   monitoredDevicesUnsupported Tankstelle_Uebach#HTTPMOD,Tankstelle_oberforstbach#HTTPMOD
     2022-06-25 13:59:55   nextPeriodChangeCalc 2022-06-25 14:59:55
     2022-06-25 14:40:11   state           Updated stats for: Tankstelle_oberforstbach
   fhem:
     modulVersion $Date: 2019-12-23 23:07:57 +0000 (Mon, 23 Dec 2019) $
     nextPeriodChangeTime 1656161995
Attributes:
   deltaReadings SuperPlus,SuperE10,SuperE5,Diesel
   durationPeriodHour 1
   durationReadings SuperPlus,SuperE10,SuperE5,Diesel
   ignoreDefaultAssignments 1
   minAvgMaxReadings SuperPlus,SuperE10,SuperE5,Diesel
   tendencyReadings SuperPlus,SuperE10,SuperE5,Diesel


Zum einen fehlen mir aber genau die Min/Max-Angaben noch und zum anderen bräuchte ich Hilfe beim Aufteilen des Readingsinhaltes.

Auf dem beigefügten Screenshot habe ich mal den betreffenden Teil der Readings einer der überwachten Tankstellen ausgeschnitten.

Superposchi

So, ich habe mal über eine Woche lang die Daten gesammelt und ausgewertet und verstehe langsam was wie wo ausgegeben wird.

Nun komme ich aber zum zweiten Problem des Projekts.
Und zwar überwache ich ja mehrere Tankstellen, das heißt ich vergleiche diese auch.
Ich möchte also den jeweils billigsten Preis aller Tankstellen - geht ja mit min-Funktion - mit den statistic-Werten vergleichen und dann eine Benachrichtigung ausgeben welche Tankstelle am billigsten ist wenn der aktuelle Preis zb unter den Durchschnitt fällt.
Ich müsste also herausfiltern aus welchem Device der niedrigste Wert der Min-Funktion stammt.

Gibt es dafür auch was fertiges oder kennt jemand eine Funktion dafür?


Superposchi

Hab ich mir gerade angesehen.
Zur Visualisierung wirklich nicht schlecht, wobei ich mich mit dem ui-table Klamotten bislang noch nicht auseinander gesetzt habe.

Aber es geht ja leider an der Frage vorbei.
Es geht ja darum aus z.b. 6 Tankstellen herauszufiltern welche den niedrigsten Preis hat und dann diese Tankstelle namentlich auszulesen.

Der niedrigste Preis geht ja wie gesagt mit der Perl-Funktion Min, aber ich weiß nicht wie (und ob es überhaupt möglich ist) dann ein anderes Reading aus dem Device auszulesen, welches den niedrigsten Wert geliefert hat.

Damian

mit minNum kannst du das Minimum aus mehreren Zahlen/Readings bestimmen:

Bsp.: minNum(1,2,3,4)

Wenn du deine Readings mit den Preisen dort einsetzt, erhältst du den niedrigsten Preis, danach musst du noch die dazugehörige Tankstelle ermitteln, die den Preis anbietet. Das kannst du über eine Schleife programmieren.

Es gibt auch Funktionen, die das schon können:

https://fhem.de/commandref_DE.html#DOIF_aggregation

Stichwort hierbei: #min für die kleinste Zahl, bzw. @min für das dazugehörige Device. Voraussetzung dabei ist, dass die Devices bzw. Readings sich über eine Regex bestimmen lassen.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Superposchi

Danke, das ist die Richtung die ich gesucht habe.

Alle meine Tankstellen-Devices heißen "Tankstelle_***" - wobei ***die jeweilige Tankstelle kennzeichnet
Alle Tankstellen Devices haben die gleichen Readings, unter anderem "SuperE5", "SuperE10", "SuperPlus", "Diesel", sowie die entsprechenden Readings aus den zugehörigen statistics-Devices.

Wenn ich also den Text der commandRef richtig verstehe sollte ein DOIF mit folgendem Ausführungsteil den Tankstellennamen der billigsten Tanke zurückliefern:
[@min:^Tankstelle_.*:SuperE10]

Um das dann in ein anderes Reading einzufügen müsste ich einen Ausführungsteil generieren der in etwa so aussieht:
(setreading <Device> <Reading> [@min:^Tankstelle_.*:SuperE10])

Hab ich das richtig verstanden?


Damian

Zitat von: Superposchi am 06 Juli 2022, 14:39:44
Danke, das ist die Richtung die ich gesucht habe.

Alle meine Tankstellen-Devices heißen "Tankstelle_***" - wobei ***die jeweilige Tankstelle kennzeichnet
Alle Tankstellen Devices haben die gleichen Readings, unter anderem "SuperE5", "SuperE10", "SuperPlus", "Diesel", sowie die entsprechenden Readings aus den zugehörigen statistics-Devices.

Wenn ich also den Text der commandRef richtig verstehe sollte ein DOIF mit folgendem Ausführungsteil den Tankstellennamen der billigsten Tanke zurückliefern:
[@min:^Tankstelle_.*:SuperE10]

Um das dann in ein anderes Reading einzufügen müsste ich einen Ausführungsteil generieren der in etwa so aussieht:
(setreading <Device> <Reading> [@min:^Tankstelle_.*:SuperE10])

Hab ich das richtig verstanden?

Regex müssen in Anführungszeichen und wenn du Event_Readings in einem DOIF-Device benutzt, brauchst du auch keine Bedingung zum Triggern - das Reading aktualisiert sich von alleine.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Superposchi

Zitatwenn du Event_Readings in einem DOIF-Device benutzt, brauchst du auch keine Bedingung zum Triggern - das Reading aktualisiert sich von alleine.
Das verstehe ich gerade nicht. Mir sagt der Begriff Event_Readings gerade nichts. Event ist klar und Reading ist klar, aber in Kombination kenne ich den Begriff noch nicht.

ZitatRegex müssen in Anführungszeichen
also muss es so lauten:
(setreading <Device> <Reading> [@min:"^Tankstelle_.*":SuperE10])

Damian

Zitat von: Superposchi am 06 Juli 2022, 16:05:33
Das verstehe ich gerade nicht. Mir sagt der Begriff Event_Readings gerade nichts. Event ist klar und Reading ist klar, aber in Kombination kenne ich den Begriff noch nicht.
also muss es so lauten:
(setreading <Device> <Reading> [@min:"^Tankstelle_.*":SuperE10])

siehe: https://fhem.de/commandref_DE.html#DOIF_event_Readings
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Superposchi

Sorry, aber das kapiere ich nicht.

Wo sind die Readings dann zu finden?
Welchen Namen haben die Readings?
Werden die Readings nur erzeugt wenn das DOIF ausgelöst wird? Attribut ist ja unabhängig vom Auslöser.

Das sind nur die spontanen Unklarheiten wenn ich das deinen Link lese.