Hallo zusammen,
ich versuche Werte einer Wettersoftware die auf dem gleichen Raspi läuft wie der Fhem-Server in Fhem zu bekommen. Nach einiger Recherche scheint der Weg per Dummy und userreadings mit dem Befehl FileRead die richtige Wahl zu sein.
Die Datei selbst besteht aus 14.02.17 13:02:44 6,8 68 1,3 1,0 1,4 157 0,0 0,3 1028,9 SSE 1 m/s C mb mm 19,9 -0,2 37,5 166,5 3,0 23,4 44 6,8 +1,9 8,4 12:38 -2,7 02:06 2,4 11:14 2,7 11:10 1029,5 09:40 1024,9 00:02 3.0.0 3043 1,4 6,8 5,0 0,0 0,00 0 191 0,0 8 1 0 S 2249 ft 4,3 0,0 280 0.0
Die Zahlenwerte stehen in einer Zeile und sind durch Leerzeichen getrennt. Nun wüsste ich gerne, wie ich die Werte sinnvoll einlese. Der Weg wie in https://forum.fhem.de/index.php/topic,64627.msg680050.html#msg680050 (https://forum.fhem.de/index.php/topic,64627.msg680050.html#msg680050) führt mit attr WetterVAL userReadings WetterwerteEchtzeit { my @content = FileRead({FileName => "/home/pi/CumulusMX/data/realtime/realtimeval.txt", ForceType => "file"});; $content[-1] =~ s/\;;/,/g;; return $content[-1]}
nicht zum Ziel. Ich nehme an da ist noch der Fehlerteufel drin.
Die einzelnen Werte sind wie folgt definiert:
<#date format=dd/mm/yy> <#timehhmmss> <#temp> <#hum> <#dew> <#wspeed> <#wlatest> <#bearing> <#rrate> <#rfall> <#press> <#currentwdir> <#beaufortnumber> <#windunit> <#tempunitnodeg> <#pressunit> <#rainunit> <#windrun> <#presstrendval> <#rmonth> <#ryear> <#rfallY> <#intemp> <#inhum> <#wchill> <#temptrend> <#tempTH> <#TtempTH> <#tempTL> <#TtempTL> <#windTM> <#TwindTM> <#wgustTM> <#TwgustTM> <#pressTH> <#TpressTH> <#pressTL> <#TpressTL> <#version> <#build> <#wgust> <#heatindex> <#humidex> <#UV> <#ET> <#SolarRad> <#avgbearing> <#rhour> <#forecastnumber> <#isdaylight> <#SensorContactLost> <#wdir> <#cloudbasevalue> <#cloudbaseunit> <#apptemp> <#SunshineHours> <#CurrentSolarMax> <#IsSunny>
Wie kann ich das Reading am sinnvollsten definieren?
Vielen Dank
Grüße Martin
ZitatWie kann ich das Reading am sinnvollsten definieren?
Wäre es nicht sinnvoll, ein wenig Perl zu lernen und die fast fertige Lösung selbst entsprechend anzupassen? FHEM ist nun mal ein Framework...
Wäre es nicht sinnvoll, ein wenig Perl zu lernen und die fast fertige Lösung selbst entsprechend anzupassen? FHEM ist nun mal ein Framework...
Ja, ... Könntest du mir was dazu empfehlen? Website, Tutorial...? So von wegen Syntax usw.
Und zum Thema "fast fertig": Was fehlt denn? Ich völliger Neuling in Perl. Daher ja auch die Frage in den Anfängerfragen...
ZitatKönntest du mir was dazu empfehlen? Website, Tutorial...?
Das sind die Geschmäcker sehr unterschiedlich. Ein wenig Recherche im Netz wird Dir tausende brauchbare Ergebisse liefern.
Mir hat das bisher gereicht:
https://web.archive.org/web/20161226115243/wiki.selfhtml.org/wiki/Perl/
http://perldoc.perl.org/
Wäre es nicht sinnvoller ein zyklisches at statt userReadings zu verwenden?
Es gibt doch kein Event welches WetterVAL dazu anregen könnte userReadings zu erstellen.
Dann würde ich den String zerlegen und die jeweiligen Werte in dazu passende Readings schreiben.
Gruß
Dan
Hi,
ich würde an Deiner Stelle erst einmal versuchen, den ganzen Dateiinhalt an ein Reading zu hängen. Dann weißt Du, dass das Einlesen im Prinzip klappt. Danach sehen wir weiter.
Also in etwa:
attr WetterVAL userReadings WetterwerteEchtzeit { my ($error, @content) = FileRead({FileName => "/home/pi/CumulusMX/data/realtime/realtimeval.txt", ForceType => "file"});; return join(" / ", @content)}
Den Rückgabewert der FileRead Funktion habe ich angepasst, damit es hierzu passt: https://wiki.fhem.de/wiki/DevelopmentModuleAPI#FileRead.
...und DeeSPe hat natürlich Recht. Du must das ganze auch noch getriggert bekommen. Testweise kannst Du das aber auch mit "set WetterVal on" machen.
Gruß,
Thorsten
Super das Einlesen klappt, auch schon einmal pro Minute. Jetzt fehlt nur noch das Aufsplitten.
Grüße Martin
Zitat von: maddinthebrain am 14 November 2017, 19:15:15
Super das Einlesen klappt, auch schon einmal pro Minute. Jetzt fehlt nur noch das Aufsplitten.
Na bitte, das Aufsplitten ist ja nur Fleißarbeit... ;)
Gruß
Dan
Zitat von: maddinthebrain am 14 November 2017, 19:15:15
Super das Einlesen klappt, auch schon einmal pro Minute. Jetzt fehlt nur noch das Aufsplitten.
Zeigst Du mal ein "list" von dem Teil?
Gruß,
Thorsten
Here we go:
Internals:
CFGFN
NAME WetterWH1080
NR 3124
STATE on
TYPE dummy
Helper:
DBLOG:
WetterEchtzeit:
logmysql:
TIME 1510687155.0985
VALUE 14.19.17 20:19:14 2,6 82 -0,2 1,0 1,4 135 0,0 0,3 1030,9 SE 1 m/s C mb mm 42,1 0,5 37,5 166,5 3,0 23,5 45 2,6 -0,1 8,4 12:38 -2,7 02:06 2,4 11:14 3,4 16:56 1030,9 20:17 1024,9 00:02 3.0.0 3043 2,0 2,6 0,4 0,0 0,00 0 126 0,0 1 0 0 SE 1131 ft -0,1 0,0 0 0
state:
logmysql:
TIME 1510687155.0985
VALUE on
READINGS:
2017-11-14 20:19:15 WetterEchtzeit 14.19.17 20:19:14 2,6 82 -0,2 1,0 1,4 135 0,0 0,3 1030,9 SE 1 m/s C mb mm 42,1 0,5 37,5 166,5 3,0 23,5 45 2,6 -0,1 8,4 12:38 -2,7 02:06 2,4 11:14 3,4 16:56 1030,9 20:17 1024,9 00:02 3.0.0 3043 2,0 2,6 0,4 0,0 0,00 0 126 0,0 1 0 0 SE 1131 ft -0,1 0,0 0 0
2017-11-14 20:19:15 state on
Attributes:
room Wetter
userReadings WetterEchtzeit { my ($error, @content) = FileRead({FileName => "/home/pi/CumulusMX/data/realtime/realtimeval.txt", ForceType => "file"});; return join(" / ", @content) }
verbose 3
Bei der Zeit ist noch ein Bug. Aber das kommt vom CumulusMX, soll hier aber nicht stören.
Hi,
userReadings WetterDate { my ($error, @content) = FileRead({FileName => "/home/pi/CumulusMX/data/realtime/realtimeval.txt", ForceType => "file"});; my @readings = split(' ', $content[0]);; return $readings[0] }
Das müsste sich jetzt das Datum herauspicken.
Mit Datum und Zeit wäre das in etwa so:
userReadings WetterDate { my ($error, @content) = FileRead({FileName => "/home/pi/CumulusMX/data/realtime/realtimeval.txt", ForceType => "file"});; my @readings = split(' ', $content[0]);; return $readings[0] }, WetterZeit { my ($error, @content) = FileRead({FileName => "/home/pi/CumulusMX/data/realtime/realtimeval.txt", ForceType => "file"});; my @readings = split(' ', $content[0]);; return $readings[1] }
Das ganze wird also schnell etwas unhandlich. Wahrscheinlich wäre das eine kleine Routine in der 99_myUtils.pm sinnvoller, die z.B. per at einmal pro Minute aufgerufen wird.
Gruß,
Thorsten
Ich würde immer noch ein at nehmen. ;)
Etwa so:
defmod at_WetterWH1080_set at +*00:01 {\
my ($error,@content) = FileRead("/home/pi/CumulusMX/data/realtime/realtimeval.txt");;\
return $error if ($error);;\
my $dev = "WetterWH1080";;\
my @read = split " ",$content[0];;\
fhem "setreading $dev date $read[0]";;\
fhem "setreading $dev time $read[1]";;\
fhem "setreading $dev temperature $read[2]";;\
fhem "setreading $dev humidity $read[3]";;\
fhem "setreading $dev dewpoint $read[4]";;\
fhem "setreading $dev windspeed $read[5]";;\
fhem "setreading $dev wlatest $read[6]";;\
fhem "setreading $dev bearing $read[7]";;\
fhem "setreading $dev rrate $read[8]";;\
fhem "setreading $dev rfall $read[9]";;\
fhem "setreading $dev pressure $read[10]";;\
fhem "setreading $dev winddir $read[11]";;\
fhem "setreading $dev beaufortnumber $read[12]";;\
}
Die setreading müssen natürlich noch weiter geführt werden für die restlichen Werte (Fleißarbeit).
Gruß
Dan
Ok super. So was in der Art hatte ich schon im Auge. Ist halt etwas Fleißarbeit. Interessant ist aber auch die Variante über myutils. Mal sehen, ich werde berichten.
Vielen Dank bis dahin! :)
Eine Frage hätte ich noch, ich werde nicht alle Einträge brauchen, z.B. die Einheiten. Da lasse ich einfach das Feld aus, oder? Die Felder werden doch in der eckigen Klammer adressiert, richtig?
Viele Grüße
Martin
Zitat von: maddinthebrain am 15 November 2017, 06:43:40
Ok super. So was in der Art hatte ich schon im Auge. Ist halt etwas Fleißarbeit. Interessant ist aber auch die Variante über myutils. Mal sehen, ich werde berichten.
Vielen Dank bis dahin! :)
Du kannst den Code genauso auch in eine Funktion in der 99_myUtils schreiben und dann die Funktion im at aufrufen.
Wie Du möchtest.
Zitat von: maddinthebrain am 15 November 2017, 08:43:42
Eine Frage hätte ich noch, ich werde nicht alle Einträge brauchen, z.B. die Einheiten. Da lasse ich einfach das Feld aus, oder? Die Felder werden doch in der eckigen Klammer adressiert, richtig?
So ist es.
Gruß
Dan
Es gibt noch ein kleines Problem: Das Reading enthält als Dezimaltrenner das Komma (,). Fhem braucht aber doch den Punkt (.). Ich hätte das mit einem RegExp gemacht. z.B. so
$val =~ s/,/\./; $val;
das kann man doch sicher elegant in das Splitting mit aufnehmen.
Grüße Martin
Hallo zusammen,
Mein erster Versuch schaut so aus:
WetterEchtzeit {
my ($error,@content) = FileRead({FileName=> "/home/pi/CumulusMX/data/realtime/realtimeval.txt", ForceType => "file" });;
return $error if ($error);;
my $dev = "WetterWH1080";;
my @read = split " ",$content[0];;
#
$read[5] =~ s/,/\./; $read[5];
fhem "setreading $dev wind $read[5]";;
#return $read[5];;
}
Leider kackt Fhem darüber ab, die Logdatei wächst in rasender Geschwindigkeit. Endlosschleife ? Das setreading habe ich im Verdacht. Wenn ich über das return was zurück gebe, funktioniert das. Das Wetterechtzeit wird über eine at Funkton getriggert. Das Listing dazu
Internals:
COMMAND set WetterWH1080 on
DEF +*00:01:00 set WetterWH1080 on
NAME WetterRead
NR 76
NTM 22:51:09
PERIODIC yes
RELATIVE yes
REP -1
STATE inactive
TIMESPEC 00:01:00
TRIGGERTIME 1510955469.37713
TRIGGERTIME_FMT 2017-11-17 22:51:09
TYPE at
READINGS:
2017-11-17 22:50:09 state inactive
Attributes:
Was passt da nicht? Ist es die Art, wie ich mit set on aufrufe?
Grüße Martin
Du hast für das userReading keinen Trigger angegeben und somit triggert es auf alles (auch auf sich selbst).
Damit hast Du eine schöne Rekursion gebaut.
Gruß
Dan
Hi,
lass das userReading ganz weg und rufe das Coding aus dem at heraus auf.
Gruß,
Thorsten
Ok. So dachte ich schon. Nun möchte ich das wie schon vorgeschlagen in die 99myUtils stecken. Ich hätte dazu
WetterEchtzeit {
my ($error,@content) = FileRead({FileName=> "/home/pi/CumulusMX/data/realtime/realtimeval.txt", ForceType => "file" });;
return $error if ($error);;
my $dev = "WetterWH1080";;
my @read = split " ",$content[0];;
$read[5] =~ s/,/\./; $read[5];
fhem "setreading $dev wind $read[5]";;
#return $read[5];;
}
Dorthin verschoben. Im WetterWH1080 das userreading gelöscht.
Aufruf in der At wäre dann wie richtig? So
WetterEchtzeit()
?
Ich versuche parallel auch perl zu verstehen. Ein bisschen was geht schon, nur sind mir manche Besonderheiten im Zusammenhang mit Fhem noch nicht ganz klar.
Grüße Martin
Hi,
ja, genau. Das Coding in die 99_myUtils.pm packen und die doppelten Semikola (Semikolons?) wegmachen. Hier sollten es einzelne sein.
Zitat von: maddinthebrain am 18 November 2017, 08:05:53
$read[5] =~ s/,/\./; $read[5];
In der obigen Zeile macht das "$read[5];" am Ende gar nichts. Das würde ich wegmachen.
Zitat
Aufruf in der At wäre dann wie richtig?
Nein, Du musst nach Perl wechseln mit {}, also etwa
{WetterEchtzeit()}
Gruß,
Thorsten
Super, es klappt! ;D Dankeschön! War ich ja gar so weit vom Ziel weg. :P
Schönes Wochenende
Ich werde das bei Gelegenheit noch mal hier schön dokumentieren. Und auch ins Wiki tun.
Grüße Martin
Hallo zusammen,
Ein Problem gibts doch noch. Die Readings werden nach dem Speichern der 99myUtil.pm genau einmal gesetzt. Danach bleiben die Werte stehen. Beim Speichern von der myutils kommt eine Fehlermeldung
Can't call method "WetterEchtzeit" on an undefined value at ./FHEM/99_myUtils.pm line 21.
Die Datei selber sieht so aus
##############################################
# $Id: myUtilsTemplate.pm 7570 2015-01-14 18:31:44Z rudolfkoenig $
#
# Save this file as 99_myUtils.pm, and create your own functions in the new
# file. They are then available in every Perl expression.
package main;
use strict;
use warnings;
use POSIX;
sub
myUtils_Initialize($$)
{
my ($hash) = @_;
}
# Enter you functions below _this_ line.
WetterEchtzeit {
my ($error,@content) = FileRead({FileName=> "/home/pi/CumulusMX/data/realtime/realtimeval.txt", ForceType => "file" });
return $error if ($error);
my $dev = "WetterWH1080";
my @read = split " ",$content[0];
$read[2] =~ s/,/\./;
fhem "setreading $dev temperature $read[2]";
$read[3] =~ s/,/\./;
fhem "setreading $dev humidity $read[3]";
$read[5] =~ s/,/\./;
fhem "setreading $dev wind $read[5]";
$read[6] =~ s/,/\./;
fhem "setreading $dev windgust $read[6]";
}
Das List vom Dummy so
Internals:
CFGFN
NAME WetterWH1080
NR 963
STATE ???
TYPE dummy
Helper:
DBLOG:
humidity:
logmysql:
TIME 1511026359.33647
VALUE 64
temperature:
logmysql:
TIME 1511026359.28601
VALUE 4.8
wind:
logmysql:
TIME 1511026359.38474
VALUE 1.4
windgust:
logmysql:
TIME 1511026359.43855
VALUE 2.4
READINGS:
2017-11-18 18:32:39 humidity 64
2017-11-18 18:32:39 temperature 4.8
2017-11-18 18:32:39 wind 1.4
2017-11-18 18:32:39 windgust 2.4
Attributes:
Das At so Internals:
COMMAND {WetterEchtzeit()}
DEF +*00:01:00 {WetterEchtzeit()}
NAME WetterRead
NR 76
NTM 18:43:18
PERIODIC yes
RELATIVE yes
REP -1
STATE Next: 18:43:18
TIMESPEC 00:01:00
TRIGGERTIME 1511026998.85024
TRIGGERTIME_FMT 2017-11-18 18:43:18
TYPE at
Helper:
DBLOG:
state:
logmysql:
TIME 1511026938.86464
VALUE Next
READINGS:
2017-11-18 18:42:18 state Next: 18:43:18
Attributes:
icon weather_station_quadra
room Wetter
Wenn ich {WetterEchtzeit()} in die Fhem-Befehlszeile eintippe und ausführe kommt
Undefined subroutine &main::WetterEchtzeit called at (eval 6917) line 1.
Ich finde den Fehler nicht...
Grüße Martin
Funktionen fangen immer mit sub an.
Also statt:
WetterEchtzeit {
so:
sub WetterEchtzeit {
Gruß
Dan
Hmm genau das mit der richtigem Funktionsdefinition hatte nicht gefunden.
Es geht. Super.
Schönen Abend und Dankeschön
Martin
Hallo,
habe ein ähnliches Problem. Es funktioniert zwar aus dem LogFile auszulesen und als Reading zu setzen, nur wird immer die 1. Zeile des LogFiles ausgelesen.
Ich benötige aber die letzte Zeile. Hatte schon es mit "tail -n 1" versucht, scheitert wohl an der syntax.
define LogWertEinlesen at +*00:15 {my ($error,@content) = FileRead("/opt/fhem/log/MyLog.log") ; return $error if ($error) ; my $dev = "MyDev" ; my @read = split " ",$content[0] ; fhem "setreading $dev state $read[3]"}
wäre für jeden Tipp dankbar
dann nimm nicht $content[0] , d.h. das erste Element aus @content sondern einfach das letzte :)
$ich_bin_das_letzte = pop(@content);
oder gruselig:
$content[$content-1]
Zitat von: ixsus300 am 23 Oktober 2020, 17:19:07
nur wird immer die 1. Zeile des LogFiles ausgelesen.
Die Behauptung ist Quatsch. Gelesen wird sehr wohl das ganze File, aber Du verwendest nur die erste Zeile.
Fehlende perl Grundlagen, insbesondere beim Thema "array". Hat nix mit FHEM zu tun.
Danke an Wzut, nun funktioniert es.
@betateilchen: ich habe nichts behauptet sondern eben einen Fehler in meinem code vermutet.
Klar ist es für einen Profi leicht ersichtlich und ja ist perl, aber denke das Forum ist auch für Hilfestellungen da. Du supportest gut, nur finde ich man darf es nicht immer nur aus seiner eigenen Sicht sehen.
Danke nochmal 😁