Hallo!
Ich hab mal auf Basis von https://wiki.fhem.de/wiki/Gleitende_Mittelwerte_berechnen_und_loggen (https://wiki.fhem.de/wiki/Gleitende_Mittelwerte_berechnen_und_loggen) eine Subroutine für die Windrichtung geschrieben, dabei hab ich auch die entsprechende Funktion von pywws mit heran gezogen.
Für die Windrichtung ist ja das normale average nicht vewendbar, wie man leicht erkennen kann, wenn man die Mittelwert von NNW (337.5°) und NNO (22.5°) berechnen will. Ein einfaches average ergäbe dann 180°, also Süd. Tatsächlich ist der Mittelwert aber Nord (0° bzw. 360°). Für die Berechnung muss man daher die Windrichtung in Vektoren zerlegen.
Die einzelenen Parameter werden in den Kommentarzeilen am Anfang beschrieben.
use Math::Trig;
###############################################################################
#
# Moving myWindDirAverage
#
# Aufruf: myWindDirAverage(devicename,readingname_windspeed,readingname_winddir,avtime,decay,minspee)
# z.B.: myWindDirAverage('WH1080','windSpeed','winDirectionDegree',900,0.75,0.5)
# avtime ist optional, default ist 600 s Zeitspanne, die berücksichtig werden soll
# decay ist optional, default ist 1 Parameter, um ältere Werte geringer zu gewichten
# minspeed ist optional, default ist 0 m/s
#
# Als Ergebnis wird die Windrichtung zurück geliefert, die aus dem aktuellen und
# vergangenen Werten über eine Art exponentiellen Mittelwert berechnet werden.
# Dabei wird zusätzlich die jeweilige Windgeschwindigkeit mit berücksichtigt (höhere Geschwindigkeit
# bedeutet höhere Gewichtung).
#
# decay: 1 -> alle Werte werden gleich gewichtet
# 0 -> nur der aktuelle Wert wird verwendet.
# in der Praxis wird man Werte so um 0.75 nehmen
#
# minspeed: da bei sehr geringer Windgeschwindigkeit die Windrichtung üblicherweise nicht
# eindeutig ist, kann mit minspeed ein Schwellwert angegeben werden
# Ist die (gewichtetete) mittlere Geschwindigkeit < minspeed wird undef zurück geliefert
#
###############################################################################
sub myWindDirAverage($$$;$$$) {
my ($name, $wsr, $wdr, $avtime, $decay, $minspeed) = @_;
# default Werte für die optionalen Parameter, falls nicht beim Aufruf mit angegeben
$avtime = 600 if (!(defined $avtime));
return $wdr if ($avtime == 0);
$decay = 1 if (!(defined $decay));
$decay = 1 if ($decay > 1); # darf nicht >1 sein
$decay = 0 if ($decay < 0); # darf nicht <0 sein
$minspeed = 0 if (!(defined $minspeed));
my $ws = ReadingsVal($name, $wsr, undef);
if (!defined $ws) {
Log 0,"myWindDirAverage: Reading $name->$wsr unknown!";
return undef;
}
my $wd = ReadingsVal($name, $wdr, undef);
if (!defined $wd) {
Log 0,"myWindDirAverage: Reading $name->$wdr unknown!";
return undef;
}
$wd = deg2rad($wd);
my $time = ReadingsTimestamp($name, $wdr, undef);
my $hash = $defs{$name};
my @new = ($ws,$wd,$time);
Log 3,"[$name myWDA1] call: Speed=".$ws." Dir=".round($wd,2)." Time=".$time." avtime=".$avtime." decay=".$decay."minspeed=".$minspeed;
my $ctime = time_str2num($time);
my $num;
my $arr;
#-- initialize if requested
if( ($avtime eq "-1") ){
$hash->{READINGS}{$wdr}{"history"}=undef;
}
#-- test for existence
if( !$hash->{READINGS}{$wdr}{"history"}){
Log 3,"[$name myWDA2] ARRAY CREATED";
push(@{$hash->{READINGS}{$wdr}{"history"}},\@new);
$num = 1;
$arr=\@{$hash->{READINGS}{$wdr}{"history"}};
} else {
$num = int(@{$hash->{READINGS}{$wdr}{"history"}});
$arr=\@{$hash->{READINGS}{$wdr}{"history"}};
my $stime = time_str2num($arr->[0][2]); # Zeitpunkt des ältesten Eintrags
my $ltime = time_str2num($arr->[$num-1][2]); # Zeitpunkt des letzten Eintrags
Log 3,"[$name myWDA3] Speed=".$ws." Dir=".round($wd,2)." Time=".$time." minspeed=".$minspeed." ctime=".$ctime."ltime=".$ltime." stime=".$stime." num=".$num;
if((($ctime - $ltime) > 10) || ($num == 0)) {
if(($num < 25) && (($ctime-$stime) < $avtime)){
#Log 1,"ARRAY has $num elements, adding another one";
Log 3,"[$name myWDA4] push: Speed=".$ws." Dir=".round($wd,2)." Time=".$time." minspeed=".$minspeed." num=".$num;
push(@{$hash->{READINGS}{$wdr}{"history"}},\@new);
}else{
shift(@{$hash->{READINGS}{$wdr}{"history"}});
push(@{$hash->{READINGS}{$wdr}{"history"}},\@new);
Log 3,"[$name myWDA5] push: Speed=".$ws." Dir=".round($wd,2)." Time=".$time." minspeed=".$minspeed." num=".$num;
}
} else {
return undef;
}
}
#-- output and average
my ($anz, $sanz) = 0;
$num = int(@{$hash->{READINGS}{$wdr}{"history"}});
my ($sumSin, $sumCos, $sumSpeed, $age, $maxage, $weight) = 0;
for(my $i=0; $i<$num; $i++){
($ws, $wd, $time) = @{ $arr->[$i] };
$age = $ctime - time_str2num($time);
if (($time eq "") || ($age > $avtime)) {
#-- zu alte Einträge entfernen
Log 3,"[$name myWDA6] i=".$i." Speed=".round($ws,2)." Dir=".round($wd,2)." Time=".substr($time,11)." ctime=".$ctime." akt.=".time_str2num($time);
shift(@{$hash->{READINGS}{$wdr}{"history"}});
$i--;
$num--;
} else {
#-- Werte aufsummieren, Windrichtung gewichtet über Geschwindigkeit und decay/"alter"
$weight = $decay ** ($age / $avtime);
#-- für die Mittelwertsbildung der Geschwindigkeit wird nur ein 10tel von avtime genommen
if ($age < ($avtime / 10)) {
$sumSpeed += $ws * $weight if ($age < ($avtime / 10));
$sanz++;
}
$sumSin += sin($wd) * $ws * $weight;
$sumCos += cos($wd) * $ws * $weight;
$anz++;
Log 3,"[$name myWDA7] i=".$i." Speed=".round($ws,2)." Dir=".round($wd,2)." Time=".substr($time,11)." vec=".round($sumSin,2)."/".round($sumCos,2)." age=".$age." ".round($weight,2);
}
}
my $average = int((rad2deg(atan2($sumSin, $sumCos)) + 360) % 360);
Log 3,"[$name myWDA8] Mittelwert über $anz Werte ist $average, avspeed=".round($sumSpeed/$num,1) if ($num > 0);
#-- undef zurückliefern, wenn die durchschnittliche Geschwindigkeit zu gering oder gar keine Werte verfügbar
return undef if (($anz == 0) || ($sanz == 0));
return undef if (($sumSpeed / $sanz) < $minspeed);
return $average;
}
Die "Log 3" Zeilen hab ich zum Debuggen eingebaut, die kann man natürlich weg lassen...
Bei meinem Device der Wetterstation WH1080 hab ich dann ein userReading angelegt:
userReadings WH1080 windDirAverage {myWindDirAverage('WH1080','windSpeed','windDirectionDegree',1200,0.75,0.5); }
Ich hab hier Plots von Windgeschwindigkeit und Windrichtung beigefügt, wobei ich bei der Windrichtung zusätzlich zum Vergleich die Werte darstelle, wie sie von der Wetterstation kommen.
Man sieht auch, dass ich die Werte nur anzeige, wenn die Windgeschwindigkeit mehr als 0.5 m/s beträgt.
Update 25.9.2017: Ergänzungen im Code um fehlerhafte Aufrufe abzufangen
Cool wäre es, wenn man die Winddaten wie folgt darstellen könnte:
https://de.wikipedia.org/wiki/Windrose_(Meteorologie)#/media/File:Wind_rose_plot.jpg (https://de.wikipedia.org/wiki/Windrose_(Meteorologie)#/media/File:Wind_rose_plot.jpg)
Ich hatte da mal SQL-Abfragen gebastelt, die die Werte aus dem DbLog-Device generieren. Allerdings hatte ich nichts gefunden, wie das in FHEM auch graphisch dargestellt werden kann.
https://www.highcharts.com/demo/polar-wind-rose & smartVisu
Danke für den Tipp!
Lässt sich das leicht in FHEM integrieren? Gibt es da Erfahrungswerte?
Wenn ich das Lizenzmodell richtig verstehe, ist die Bibliothek für private Nutzung frei.
Hi!
@SabineT: Das ist ein genialer Code. Vielen Danke fürs Teilen! :D
Das hab ich schon lange gesucht. Scheint als ob das zu Berrechen sehr kompliziert ist. Auf jeden Fall funktioniert es!
Haha: Jz muss ich noch schaffen alles ein Jahr zurückzurechnen, dann wären wieder ein paar 100.000 Datensätze weniger ;D
Lg Max
Hallo SabineT,
hab den Codeschnipsel heute mal auf mein FHEM "kopiert"
Läuft mit meiner Ventus266 -> MQTT prima!
Gruß
p99p
Zitat von: SabineT am 09 August 2017, 19:31:19
...
Ich hab mal auf Basis von https://wiki.fhem.de/wiki/Gleitende_Mittelwerte_berechnen_und_loggen (https://wiki.fhem.de/wiki/Gleitende_Mittelwerte_berechnen_und_loggen) eine Subroutine für die Windrichtung geschrieben, dabei hab ich auch die entsprechende Funktion von pywws mit heran gezogen.
Für die Windrichtung ist ja das normale average nicht vewendbar, wie man leicht erkennen kann, wenn man die Mittelwert von NNW (337.5°) und NNO (22.5°) berechnen will. Ein einfaches average ergäbe dann 180°, also Süd. Tatsächlich ist der Mittelwert aber Nord (0° bzw. 360°). Für die Berechnung muss man daher die Windrichtung in Vektoren zerlegen.
..........
Man sieht auch, dass ich die Werte nur anzeige, wenn die Windgeschwindigkeit mehr als 0.5 m/s beträgt.
Hallo SabineT,
ich habe mal den Code in 99_myUtil.pm kopiert und aufgerufen, leider bekomme ich Div/0. Tritt beim Loglevel=5 auf. Die Berechung beim Log stimmt nicht, bzw. div/0 muß abgefangen werden. Ich habe das mal angepaßt, so das es bei mir läuft. Bei windDirAverage habe ich aber immer 0.
Könntest du auch mal die Daten für den Plot mit angeben. Danke.
pejonp
Hallo pejonp!
Das mit Div/0 schau ich mir an, im Moment herrscht bei mir aber Flaute, muss also warten, bis wieder genug Wind bläst.
Zu den Plot Daten:
Die Definition schaut bei mir so aus:
define gnuPlot_DbLog_Wetterdaten_winddir SVG lp:gnuplot_DbLog_Wetterdaten_winddir:CURRENT
attr gnuPlot_DbLog_Wetterdaten_winddir comment Windrichtung
attr gnuPlot_DbLog_Wetterdaten_winddir plotmode gnuplot-scroll
attr gnuPlot_DbLog_Wetterdaten_winddir plotsize 600,205
attr gnuPlot_DbLog_Wetterdaten_winddir room GnuPlots
Und das Plotfile selber so:
set terminal pngcairo enhanced font "DejaVuSansCondensed,10" rounded transparent size <SIZE> crop
set size 0.94, 1
set output '<OUT>.png'
set xdata time
set timefmt "%Y-%m-%d_%H:%M:%S"
set lmargin 8
set rmargin 8
set xtics format "%H:%M"
set xtics 14400
set format y " %3.0f"
set xtics out
set ytics 45 out
set y2tics ('N' 0, 'O' 90, 'S' 180, 'W' 270, 'N' 360) out offset 2
set grid ytics
set ylabel "°"
set y2label ' '
set yrange [0:360]
set y2range [0:360]
set grid x y2 front
set style circle radius 150
set pointsize 0.2
set key outside above right maxrows 1 samplen 2
#lp DbLog:myDbLog:WH1080:windDirAverage
plot "<IN>" using 1:2 axes x1y1 title 'Windrichtung' with circles lc rgb 'blue'
Ich verwende plotmode gnuplot-scroll, weil ich da mehr Möglichkeiten der Formatierung habe (z.B. Legenden ausserhalb des Plots), für plotmode SVG müsste man das dann anpassen.
lg, Sabine
Eigentlich sind mir im Code nur 2 Stellen aufgefallen, wo ein Div/0 passieren könnte:
$weight = $decay ** ($age / $avtime);
passiert aber nur, wenn man beim userReading für avtime 0 angibt.
Das müsste sich mit folgender Änderung abfangen lassen:
~/FHEM$ diff -c 99_myUtils.pm.old 99_myUtils.pm
*** 99_myUtils.pm.old 2017-09-24 07:25:30.763850589 +0200
--- 99_myUtils.pm 2017-09-24 07:33:10.058351197 +0200
***************
*** 274,279 ****
--- 274,280 ----
# default Werte für die optionalen Parameter, falls nicht beim Aufruf mit angegeben
$avtime = 600 if (!(defined $avtime));
+ return $wdr if ($avtime == 0);
$decay = 1 if (!(defined $decay));
$decay = 1 if ($decay > 1); # darf nicht >1 sein
$decay = 0 if ($decay < 0); # darf nicht <0 sein
Die Zeile "return $wdr if ($avtime == 0);" an der entsprechenden Stelle einfügen.
Die zweite Stelle ist:
Log 3,"[$name myWDA8] Mittelwert über $anz Werte ist $average, avspeed=".round($sumSpeed/$num,1);
Da darf $num nicht 0 sein. Ist aber nur relevant, wenn man verbose >=3 eingestellt hat, das war bei meinen Test während der Entwicklungsphase aber nie der Fall.
ZitatDie zweite Stelle ist:
Log 3,"[$name myWDA8] Mittelwert über $anz Werte ist $average, avspeed=".round($sumSpeed/$num,1);
Dies lässt sich abfangen, wenn auf num > 0 geprüft wird:
Log 3,"[$name myWDA8] Mittelwert über $anz Werte ist $average, avspeed=".round($sumSpeed/$num,1) if ($num > 0);
Gruß Ralf
Zitat von: Ralf9 am 24 September 2017, 09:01:28
Dies lässt sich abfangen, wenn auf num > 0 geprüft wird:
Log 3,"[$name myWDA8] Mittelwert über $anz Werte ist $average, avspeed=".round($sumSpeed/$num,1) if ($num > 0);
Gruß Ralf
Bei mir ist der Fall nie aufgetreten, hab das aber jetzt mal gemeinsam mit der anderen Änderung im 1. Posting ergänzt.
@pejonp falls bei dir Div/0 immer noch auftritt poste mir bitte mal den Logauszug dazu.
Sabine
Zitat von: SabineT am 24 September 2017, 10:31:29
Bei mir ist der Fall nie aufgetreten, hab das aber jetzt mal gemeinsam mit der anderen Änderung im 1. Posting ergänzt.
@pejonp falls bei dir Div/0 immer noch auftritt poste mir bitte mal den Logauszug dazu.
Sabine
Hallo Sabine,
ich habe mal deine Vorschläge ins 14_SD_WS09.pm eingebaut und hänge das hier mal an. Kannst du dir das mal ansehen ?
Ich möchte es noch nicht Einchecken, falls noch Fehler drin sind.
pejonp
PS: Anlage noch einmal angepaßt.
Zitat von: pejonp am 24 September 2017, 21:29:39
Hallo Sabine,
ich habe mal deine Vorschläge ins 14_SD_WS09.pm eingebaut und hänge das hier mal an. Kannst du dir das mal ansehen ?
Ich möchte es noch nicht Einchecken, falls noch Fehler drin sind.
pejonp
PS: Anlage noch einmal angepaßt.
Ich hab die Version mal bei mir installiert. Jetzt in der Nacht ist nur leider der Wind wieder zu schwach, kann also erst morgen was genaueres dazu sagen.
Ich würde aber für das Reading statt WindDirAverage
windDirAverage verwenden, damit es bei den übrigen wind Readings dabei steht (die haben ja alles das w klein geschrieben ;)).
Und statt rainTotal wäre rain_total sinnvoller, dann wird es auch von
statistics berücksichtigt!
Hi SabineT,
habe die Readings 14_SD_WS09.pm angepaßt.
Im 99_myUtils.pm habe ich die Version angepaßt und wollte meine W266 damit füttern. Geht nicht so richtig. Ich hänge mal eine Ausschnitt aus dem Log an. Fehler habe ich noch nicht eingrenzen können.
Def:
attr ESPEasy_W266_Wind userReadings windDirAverage {myWindDirAverage('ESPEasy_W266_Wind','Guest','Average',1200,0.75,0.5);; }
2017.09.24 23:36:35.386 1: PERL WARNING: Use of uninitialized value $ws in concatenation (.) or string at ./FHEM/99_myUtils.pm line 287.
2017.09.24 23:36:35.386 1: PERL WARNING: Use of uninitialized value $time in concatenation (.) or string at ./FHEM/99_myUtils.pm line 287.
2017.09.24 23:36:35.387 1: PERL WARNING: Use of uninitialized value $time in string eq at ./FHEM/99_myUtils.pm line 331.
2017.09.24 23:36:35.387 1: PERL WARNING: Use of uninitialized value $v in sprintf at ./FHEM/99_myUtils.pm line 245.
2017.09.24 23:36:35.387 1: PERL WARNING: Use of uninitialized value $time in substr at ./FHEM/99_myUtils.pm line 333.
2017.09.24 23:36:35.388 1: PERL WARNING: substr outside of string at ./FHEM/99_myUtils.pm line 333.
2017.09.24 23:36:35.388 1: PERL WARNING: Use of uninitialized value in concatenation (.) or string at ./FHEM/99_myUtils.pm line 333.
2017.09.24 23:36:35.388 1: PERL WARNING: Use of uninitialized value $sumCos in atan2 at ./FHEM/99_myUtils.pm line 351.
2017.09.24 23:36:35.389 1: PERL WARNING: ESPEasy_W266_Wind userReadings windDirAverage evaluated to undef at fhem.pl line 4288.
2017.09.24 23:36:35.391 5: ESPEasy ESPEasy_W266_Wind: Start internalTimer +304 => 2017-09-24 23:41:40
2017.09.24 23:36:47.368 1: PERL WARNING: Use of uninitialized value $ws in concatenation (.) or string at ./FHEM/14_SD_WS09.pm line 519.
2017.09.24 23:36:47.369 1: PERL WARNING: Use of uninitialized value $time in concatenation (.) or string at ./FHEM/14_SD_WS09.pm line 519.
2017.09.24 23:36:47.369 1: PERL WARNING: Use of uninitialized value $time in string eq at ./FHEM/14_SD_WS09.pm line 564.
2017.09.24 23:36:47.370 1: PERL WARNING: Use of uninitialized value $time in substr at ./FHEM/14_SD_WS09.pm line 566.
2017.09.24 23:36:47.370 1: PERL WARNING: substr outside of string at ./FHEM/14_SD_WS09.pm line 566.
2017.09.24 23:36:47.370 1: PERL WARNING: Use of uninitialized value in concatenation (.) or string at ./FHEM/14_SD_WS09.pm line 566.
2017.09.24 23:36:47.371 1: PERL WARNING: Use of uninitialized value $sumCos in atan2 at ./FHEM/14_SD_WS09.pm line 584.
2017.09.24 23:36:47.371 1: PERL WARNING: Use of uninitialized value $windex in array element at ./FHEM/14_SD_WS09.pm line 408.
2017.09.24 23:36:50.859 5: ESPEasy ESPEasy_W266_Wind: Received: W266_Wind::192.168.2.103::1::1::1::i||unit||0||0|||i||sleep||0||0|||i||build||20000||0|||i||build_git||dev11||0|||i||build_notes|| - Mega||0|||i||version||2||0|||i||node_type_id||17||0|||r||Direction||0.0||6|||r||Average||225.0||6|||r||Guest||0.0||6
2017.09.24 23:36:50.861 1: PERL WARNING: Use of uninitialized value $ws in concatenation (.) or string at ./FHEM/99_myUtils.pm line 307.
2017.09.24 23:36:50.861 1: PERL WARNING: Use of uninitialized value $time in concatenation (.) or string at ./FHEM/99_myUtils.pm line 307.
2017.09.24 23:36:50.862 1: PERL WARNING: Use of uninitialized value $ws in concatenation (.) or string at ./FHEM/99_myUtils.pm line 312.
2017.09.24 23:36:50.862 1: PERL WARNING: Use of uninitialized value $time in concatenation (.) or string at ./FHEM/99_myUtils.pm line 312.
2017.09.24 23:36:50.864 4: ESPEasy ESPEasy_W266_Wind: Direction: 0.0
2017.09.24 23:36:50.865 1: PERL WARNING: Use of uninitialized value $ws in multiplication (*) at ./FHEM/99_myUtils.pm line 342.
2017.09.24 23:36:50.866 1: PERL WARNING: Use of uninitialized value $ws in multiplication (*) at ./FHEM/99_myUtils.pm line 345.
2017.09.24 23:36:50.866 1: PERL WARNING: Use of uninitialized value $ws in multiplication (*) at ./FHEM/99_myUtils.pm line 346.
2017.09.24 23:36:50.867 4: ESPEasy ESPEasy_W266_Wind: Average: 225.0
2017.09.24 23:36:50.868 4: ESPEasy ESPEasy_W266_Wind: Guest: 0.0
2017.09.24 23:36:50.868 5: ESPEasy ESPEasy_W266_Wind: Internals: unit:0 sleep:0 build:20000 build_git:dev11 build_notes: - Mega version:2 node_type_id:17: ESP Easy Mega
2017.09.24 23:36:50.870 4: ESPEasy ESPEasy_W266_Wind: presence: present
2017.09.24 23:37:00.036 1: PERL WARNING: Odd number of elements in hash assignment at ./FHEM/98_HTTPMOD.pm line 1717.
2017.09.24 23:37:22.421 5: ESPEasy ESPEasy_W266_Wind: Received:
pejonp
Zitat von: pejonp am 25 September 2017, 00:03:40
Hi SabineT,
habe die Readings 14_SD_WS09.pm angepaßt.
Im 99_myUtils.pm habe ich die Version angepaßt und wollte meine W266 damit füttern. Geht nicht so richtig. Ich hänge mal eine Ausschnitt aus dem Log an. Fehler habe ich noch nicht eingrenzen können.
Def:
attr ESPEasy_W266_Wind userReadings windDirAverage {myWindDirAverage('ESPEasy_W266_Wind','Guest','Average',1200,0.75,0.5);; }
2017.09.24 23:36:35.386 1: PERL WARNING: Use of uninitialized value $ws in concatenation (.) or string at ./FHEM/99_myUtils.pm line 287.
2017.09.24 23:36:35.386 1: PERL WARNING: Use of uninitialized value $time in concatenation (.) or string at ./FHEM/99_myUtils.pm line 287.
pejonp
Bei dir passt die Definition des userReadings nicht! Im Log sieht man, dass $ws und $time garnicht initialisiert wird, das passiert im Programm in der Zeile:
my @new = my ($ws,$wd,$time) = ($hash->{READINGS}{$wsr}{VAL},deg2rad($hash->{READINGS}{$wdr}{VAL}),$hash->{READINGS}{$wdr}{TIME});
Du verwendest als Definition:
attr ESPEasy_W266_Wind userReadings windDirAverage {myWindDirAverage('ESPEasy_W266_Wind','Guest','Average',1200,0.75,0.5);; }
Statt 'Guest' müsste der Readingname der Windgeschwindigkeit stehen (bei der WH1080 ist das 'windSpeed').
Statt 'Average' gehört dann der Readingname der Windrichtung (ist bei der WH1080 'windDirectionDegree').
Ich denke, bei der W266 werden die die gleichen Namen haben.
Probier einfach mal
attr ESPEasy_W266_Wind userReadings windDirAverage {myWindDirAverage('ESPEasy_W266_Wind','windSpeed','windDirectionDegree',1200,0.75,0.5);; }
lg, Sabine
Solche Fehler könnte man vermeiden wenn man die zum auslesen von Readings bestimmten FHEM Funktionen verwendet. Generell empfiehlt es sich nicht unnötig Hash's aus zu lesen oder für Bedingungen zu verwenden. Dafür dann lieber die FHEM Funktionen.
Ein weiterer Grund auf Hash Abfragen zu verzichten ist, das bei der Abfrage von verschachtelten Hash's auch Hash's unnötiger Weise angelegt werden.
if(hash->{READINGS}{$wdr}{VAL})
Sollte aus einem Grund {$wdr} nicht existieren wird es bei der Abfrage von {VAL} angelegt.
Sabine vielleicht schaust Du einmal das Du Deine wirklich gute Sub entsprechend um baust.
ReadingsVal währe hier angebracht. Eventuell kannst Du dann ganz auf den Wert von $hash verzichten. Habe mir aber nicht alles angeschaut. $name sollte dann reichen.
Grüße
@pejonp
nicht Average sondern Direction brauchst du im userreading.
userReadings windDirAverage {myWindDirAverage('WetterstnNdn','Gust','Direction',1200,0.75,1.8); }
Bei mir läuft das mit MQTT fehlerfrei.
EDIT:
der Vollständigkeit halber häng ich noch ein list vom Device an
Internals:
IODev MyBroker
NAME WetterstnNdn
NR 127
STATE incoming publish received
TYPE MQTT_DEVICE
Helper:
DBLOG:
Average:
logdb:
TIME 1506319798.01265
VALUE 0.0
Battery:
logdb:
TIME 1506319802.10818
VALUE 0
Direction:
logdb:
TIME 1506319797.94068
VALUE 135.0
Distance_in_km:
logdb:
TIME 1506319801.20898
VALUE 40
Gust:
logdb:
TIME 1506319798.08269
VALUE 0.0
Humidity:
logdb:
TIME 1506319796.98924
VALUE 27
Rainfall:
logdb:
TIME 1506319799.05028
VALUE 0.0
Strike_counter:
logdb:
TIME 1506319801.0653
VALUE 1126
Strikes_past_5_minutes:
logdb:
TIME 1506319801.13818
VALUE 0
Temperature:
logdb:
TIME 1506319796.90516
VALUE 11.0
Total:
logdb:
TIME 1506319798.97798
VALUE 770.0
UV:
logdb:
TIME 1506319800.04946
VALUE 0.0
transmission-state:
logdb:
TIME 1506319802.07354
VALUE incoming publish received
windDirAverage:
logdb:
TIME 1506020788.95284
VALUE 180
READINGS:
2017-09-25 08:09:58 Average 0.0
2017-09-25 08:10:02 Battery 0
2017-09-25 08:09:57 Direction 135.0
2017-09-25 08:10:01 Distance_in_km 40
2017-09-25 08:09:58 Gust 0.0
2017-09-25 08:09:56 Humidity 27
2017-09-25 08:09:59 Rainfall 0.0
2017-09-25 08:10:01 Strike_counter 1126
2017-09-25 08:10:01 Strikes_past_5_minutes 0
2017-09-25 08:09:56 Temperature 11.0
2017-09-25 08:09:58 Total 770.0
2017-09-25 08:10:00 UV 0.0
2017-09-25 08:10:02 transmission-state incoming publish received
2017-09-21 21:06:28 windDirAverage 180
message_ids:
sets:
subscribe:
/VentusNdn/Ventus/Average
/VentusNdn/Ventus/Battery
/VentusNdn/Ventus/Direction
/VentusNdn/Ventus/Distance
/VentusNdn/Ventus/Gust
/VentusNdn/Ventus/Humidity
/VentusNdn/Ventus/Rainpasthour
/VentusNdn/Ventus/Strikecounter
/VentusNdn/Ventus/Strikespast5
/VentusNdn/Ventus/Temperature
/VentusNdn/Ventus/Totalrain
/VentusNdn/Ventus/UV
subscribeExpr:
^\/VentusNdn\/Ventus\/Average$
^\/VentusNdn\/Ventus\/Battery$
^\/VentusNdn\/Ventus\/Direction$
^\/VentusNdn\/Ventus\/Distance$
^\/VentusNdn\/Ventus\/Gust$
^\/VentusNdn\/Ventus\/Humidity$
^\/VentusNdn\/Ventus\/Rainpasthour$
^\/VentusNdn\/Ventus\/Strikecounter$
^\/VentusNdn\/Ventus\/Strikespast5$
^\/VentusNdn\/Ventus\/Temperature$
^\/VentusNdn\/Ventus\/Totalrain$
^\/VentusNdn\/Ventus\/UV$
subscribeReadings:
/VentusNdn/Ventus/Average:
cmd
name Average
/VentusNdn/Ventus/Battery:
cmd
name Battery
/VentusNdn/Ventus/Direction:
cmd
name Direction
/VentusNdn/Ventus/Distance:
cmd
name Distance_in_km
/VentusNdn/Ventus/Gust:
cmd
name Gust
/VentusNdn/Ventus/Humidity:
cmd
name Humidity
/VentusNdn/Ventus/Rainpasthour:
cmd
name Rainfall
/VentusNdn/Ventus/Strikecounter:
cmd
name Strike_counter
/VentusNdn/Ventus/Strikespast5:
cmd
name Strikes_past_5_minutes
/VentusNdn/Ventus/Temperature:
cmd
name Temperature
/VentusNdn/Ventus/Totalrain:
cmd
name Total
/VentusNdn/Ventus/UV:
cmd
name UV
Attributes:
DbLogInclude .*
IODev MyBroker
room Wetter
stateFormat transmission-state
subscribeReading_Average /VentusNdn/Ventus/Average
subscribeReading_Battery /VentusNdn/Ventus/Battery
subscribeReading_Direction /VentusNdn/Ventus/Direction
subscribeReading_Distance_in_km /VentusNdn/Ventus/Distance
subscribeReading_Gust /VentusNdn/Ventus/Gust
subscribeReading_Humidity /VentusNdn/Ventus/Humidity
subscribeReading_Rainfall /VentusNdn/Ventus/Rainpasthour
subscribeReading_Strike_counter /VentusNdn/Ventus/Strikecounter
subscribeReading_Strikes_past_5_minutes /VentusNdn/Ventus/Strikespast5
subscribeReading_Temperature /VentusNdn/Ventus/Temperature
subscribeReading_Total /VentusNdn/Ventus/Totalrain
subscribeReading_UV /VentusNdn/Ventus/UV
userReadings windDirAverage {myWindDirAverage('WetterstnNdn','Gust','Direction',1200,0.75,1.8); }
Zitat von: CoolTux am 25 September 2017, 08:01:16
Solche Fehler könnte man vermeiden wenn man die zum auslesen von Readings bestimmten FHEM Funktionen verwendet. Generell empfiehlt es sich nicht unnötig Hash's aus zu lesen oder für Bedingungen zu verwenden. Dafür dann lieber die FHEM Funktionen.
Ein weiterer Grund auf Hash Abfragen zu verzichten ist, das bei der Abfrage von verschachtelten Hash's auch Hash's unnötiger Weise angelegt werden.
if(hash->{READINGS}{$wdr}{VAL})
Sollte aus einem Grund {$wdr} nicht existieren wird es bei der Abfrage von {VAL} angelegt.
Sabine vielleicht schaust Du einmal das Du Deine wirklich gute Sub entsprechend um baust.
ReadingsVal währe hier angebracht. Eventuell kannst Du dann ganz auf den Wert von $hash verzichten. Habe mir aber nicht alles angeschaut. $name sollte dann reichen.
Grüße
Ich hab für meine Sub ja das movingAverage (https://wiki.fhem.de/wiki/Gleitende_Mittelwerte_berechnen_und_loggen (https://wiki.fhem.de/wiki/Gleitende_Mittelwerte_berechnen_und_loggen)) vom Wiki als Basis genommen und nur für die speziellen Anforderungen für die Windrichtung ergänzt.
Ganz ohne $hash wird das aber vermutlich nicht gehen, da ja dort in {"history"} das Array mit den vorhergehenden Werten gespeichert wird. Ich bin jetzt nicht so firm mit dem Development für fhem, aber vielleicht gibt es ja eine bessere Möglichkeit, das Array beim jeweiligen Device zu speichern.
pejonp hat die Sub ja jetzt in 14_SD_WS09.pm integriert, da können dann ohnehin keine falschen Readingsnamen mehr angegeben werden.
lg, Sabine
Für hash->{history} kommst Du in der Tat nicht an $hash vorbei, das stimmt.
Vielleicht ergibt es sich aber das Du Dir
$hash->{READINGS}{$wsr}{VAL},deg2rad($hash->{READINGS}{$wdr}{VAL}),$hash->{READINGS}{$wdr}{TIME}
solche Sachen noch einmal an schaust und auf ReadingsVal um baust.
Ich schaue mir den Wiki Artikel einmal genauer an.
Grüße
Zitat von: CoolTux am 25 September 2017, 09:12:13
Für hash->{history} kommst Du in der Tat nicht an $hash vorbei, das stimmt.
Vielleicht ergibt es sich aber das Du Dir
$hash->{READINGS}{$wsr}{VAL},deg2rad($hash->{READINGS}{$wdr}{VAL}),$hash->{READINGS}{$wdr}{TIME}
solche Sachen noch einmal an schaust und auf ReadingsVal um baust.
Ich schaue mir den Wiki Artikel einmal genauer an.
Grüße
Ich hab jetzt
my $hash = $defs{$name};
my @new = my ($ws,$wd,$time) = ($hash->{READINGS}{$wsr}{VAL},deg2rad($hash->{READINGS}{$wdr}VAL}),$hash->{READINGS}{$wdr}{TIME});
durch
my $ws = ReadingsVal($name, $wsr, undef);
if (!defined $ws) {
Log 0,"myWindDirAverage: Reading $name->$wsr unknown!";
return undef;
}
my $wd = ReadingsVal($name, $wdr, undef);
if (!defined $wd) {
Log 0,"myWindDirAverage: Reading $name->$wdr unknown!";
return undef;
}
my $time = ReadingsTimestamp($name, $wdr, undef);
my $hash = $defs{$name};
ersetzt (ist im 1. Posting eingepflegt).
Falsche Angaben bei der Definition des userReadings werden damit abgefangen und im FHEM-Log angezeigt (hab ich getestet ;)).
@pejonp im 14_SD_WS09.pm ist diese Änderung nicht notwendig, dort hast du die Readings je fix vorgegeben.
lg
Hallo Sabine,
Ich habe den Wikieintrag (https://wiki.fhem.de/wiki/Gleitende_Mittelwerte_berechnen_und_loggen) entsprechend engepasst. Vielleicht magst ja mal drüber schauen.
Grüße
Leon
Zitat von: CoolTux am 25 September 2017, 11:56:37
Hallo Sabine,
Ich habe den Wikieintrag (https://wiki.fhem.de/wiki/Gleitende_Mittelwerte_berechnen_und_loggen) entsprechend engepasst. Vielleicht magst ja mal drüber schauen.
Grüße
Leon
Im Prinzip macht meine letzte Änderung eh das gleiche. Ich hab nur zusätzlich noch eine Logausgabe eingebaut, falls nicht vorhandene Readings angegeben werden und beende dann auch gleich die sub mit "return undef".
Zitat von: pejonp am 25 September 2017, 00:03:40
Hi SabineT,
habe die Readings 14_SD_WS09.pm angepaßt.
pejonp
Ein paar Sachen sind mir noch aufgefallen:
- bei dir wird immer der vorhergehende Wert verwendet, und nicht der aktuelle. Grund dafür ist, dass du "my $average = SD_WS09_WindDirAverage($hash);" aufrufst, $hash da aber noch nicht mit den aktuellen Werten befüllt wurde.
Sieht man, wenn man das Logging entsprechend aufdreht:
2017.09.25 12:18:35 4: SD_WS09_WindDirAverage_01 WH1080 :Speed=1.4 DirR=2.36 Time=2017-09-25 12:18:01
Meine sub im myUtils liefert da:
2017.09.25 12:18:35 3: [WH1080 myWDA1] call: Speed=1.4 Dir=1.57 Time=2017-09-25 12:18:35
In der Praxis wirkt sich das aber nicht sonderlich aus.
- in "Log3 $hash,4, "[$name myWDA2] ARRAY CREATED";" gehört myWDA2 durch SD_WS09_WindDirAverage_02 ersetzt (ist aber nur eine kosmetische Sache).
Durch deinen Code bin ich übrigens drauf gekommen, dass ich bei mir deg2rad vergessen hatte, ist jetzt im 1. Posting mit berücksichtigt.
lg, Sabine
Zitat von: pejonp am 25 September 2017, 00:03:40
Hi SabineT,
habe die Readings 14_SD_WS09.pm angepaßt.
pejonp
Hallo pejonp!
Ich hab jetzt mal die sub SD_WS09_WindDirAverage so umgeschrieben, dass gleich die aktuellen Werte genommen werden. Hab sie hier dran gehängt. Die 1. Zeile wäre der dazugehörige Aufruf.
Beim Plot sieht man, dass die Werte von meiner sub in myUtils (blau) und die aus der SD_WS09 (rot) nachmittags dann praktisch gleich sind (Vormittag ist noch deine Version zu sehen).
lg, Sabine
@pink99panther
Der Fehler bei mir war das noch keine Daten geloggt wurden. Als ich diese dann in die DBlog geschrieben habe, hat es auch funktioniert.
Zitat von: SabineT am 25 September 2017, 18:12:59
...
Ich hab jetzt mal die sub SD_WS09_WindDirAverage so umgeschrieben, dass gleich die aktuellen Werte genommen werden. ...
Hallo Sabine,
habe versuchte alle deine Änderungen einzuarbeiten. Vielen Dank für deine Hilfe. Bei der Werteübergabe in die sub hat es bei mir gehakt.
windDirAverage --> windDirectionAverage geändert. So wird er richtiger einsortiert. Neue Datei zum testen hänge ich an.
Was jetzt noch fehlt, wäre das automatische anlegen der Diagramme. gplot siehe Anhang.
in der Datei steht ja:
$hash->{AutoCreate} =
{ "SD_WS09.*" => { ATTR => "event-min-interval:.*:300 event-on-change-reading:.* windKorrektur:.*:0 " , FILTER => "%NAME",
GPLOT => "wind4windDir4:wind/Dir,", autocreateThreshold => "2:180"} };
Ich bin jetzt aber noch nicht dahinter gestiegen wie der Aufruf ist. Vielleicht gibt es ja einen Wissenden.
1.Versuch der nicht geht: GPLOT => "WH1080wind4:windSpeed/windGust
Jörg
Zitat von: pejonp am 25 September 2017, 22:13:58
Hallo Sabine,
habe versuchte alle deine Änderungen einzuarbeiten. Vielen Dank für deine Hilfe. Bei der Werteübergabe in die sub hat es bei mir gehakt.
windDirAverage --> windDirectionAverage geändert. So wird er richtiger einsortiert. Neue Datei zum testen hänge ich an.
Was jetzt noch fehlt, wäre das automatische anlegen der Diagramme. gplot siehe Anhang.
in der Datei steht ja:
$hash->{AutoCreate} =
{ "SD_WS09.*" => { ATTR => "event-min-interval:.*:300 event-on-change-reading:.* windKorrektur:.*:0 " , FILTER => "%NAME",
GPLOT => "wind4windDir4:wind/Dir,", autocreateThreshold => "2:180"} };
Ich bin jetzt aber noch nicht dahinter gestiegen wie der Aufruf ist. Vielleicht gibt es ja einen Wissenden.
1.Versuch der nicht geht: GPLOT => "WH1080wind4:windSpeed/windGust
Jörg
Hallo Jörg,
ich hab jetzt dein 14_SD_WS09.pm bei mir installiert (und auch im DBlog das Reading von windDirAverage auf windDirectionAverage geändert).
Zum automatischen Anlegen der Plots kann ich leider nichts sagen, ich hab meine .gplot Dateien selber erstellt (ich verwende auch gnuplot statt SVG...). Ich würde aber Windgeschwindigkeit und Windrichtung in getrennten Diagrammen darstellen, sonst wird das schnell unübersichtlich. Und windDirectionDegree würde ich ganz weg lassen, das streut speziell bei schwachem Wind viel zu stark (sieht man in meinem Beispiel beim 1. Posting).
lg, Sabine
Hi Sabine,
habe die 14_SD_WS09.pm angepaßt und auch eingecheckt.
Mach mal bitte ein Update: update all https://raw.githubusercontent.com/RFD-FHEM/RFFHEM/dev-r33/controls_signalduino.txt
Jörg
Hi Jörg!
Update durchgeführt. Die Datei hat sich aber gegenüber der bei mir seit 26.9. laufenden Version nicht mehr geändert, daher sollte alles passen.
Danke, dass du meine Vorschläge übernommen hast.
Liebe Grüße,
Sabine