VisualCrossing Api via httpmod | Wetter weltweit

Begonnen von holle75, 07 Februar 2026, 19:49:31

Vorheriges Thema - Nächstes Thema

holle75

Für alle, die vielleicht Wetter ausserhalb Deutschlands in höchster Auflösung brauchen, schreibe ich mal meinen VisualCrossing Api Weg zusammen (https://www.visualcrossing.com/weather-api/ ... "sign up for free" --- 1000 Abfragen pro Tag).

Das meiste an Code ist aus allen möglichen Informationen aus dem Forum zusammengebastelt. Ich bin kein Programmierer. Und schön ist sicherlich anders.

Entstanden ist das Ganze, weil alle Wettermodule früher oder später nicht mehr für Italien funktioniert haben und ich spezielle Infos weiterführend brauche (explizite Windwarnungen, Solar, Regenwahrscheinlichkeit, etc).

Es ist recht komplex (für mein Dafürhalten), aber liefert einen grafischen Überblick des zukünftigen Wetters an jedem Ort der Welt. Dies erstaunlich akurat.

Alle Userreadings habe ich mal dringelassen, vielleicht braucht es jemand.

httpmod device RAW (x=euer longitude, y=euer latitude, w=key von visualcrossing gilt es anzupassen. Auch in 99_myUtil.pm. Am besten mit einem Editor mit Replace-Funktion):

define WetterVisualCrossing HTTPMOD https://weather.visualcrossing.com/VisualCrossingWebServices/rest/services/weatherdata/forecast?locations=xx.xxxxxx%2C%20yy.yyyyyyy&aggregateHours=1&forecastDays=7&unitGroup=metric&shortColumnNames=false&contentType=json&key=WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW 1200
attr WetterVisualCrossing enforceGoodReadingNames 1
attr WetterVisualCrossing event-on-change-reading .*
attr WetterVisualCrossing extractAllJSON 1
attr WetterVisualCrossing group Wetter
attr WetterVisualCrossing room Wettervorhersage
attr WetterVisualCrossing stateFormat T: locations_xx.xxxxxx__yy.yyyyyyy_currentConditions_temp&deg - H: locations_xx.xxxxxx__yy.yyyyyyy_currentConditions_humidity - Wetter: locations_xx.xxxxxx__yy.yyyyyyy_currentConditions_icon - Wind: locations_xx.xxxxxx__yy.yyyyyyy_currentConditions_wspd km/h mit locations_xx.xxxxxx__yy.yyyyyyy_values_01_wgust km/h Boen
attr WetterVisualCrossing userReadings Regenmenge24h:locations_xx.xxxxxx__yy.yyyyyyy_currentConditions_datetime:.*\
{\
    my $hdmsum = 0;;;;\
    my $hdmvalue = 0;;;;\
    for my $i ("01" .. "24")\
        {\
            $hdmvalue = ReadingsVal("WetterVisualCrossing", "locations_xx.xxxxxx__yy.yyyyyyy_values_".$i."_precip",0);;;;\
            $hdmsum = $hdmsum + $hdmvalue;;;;\
        };;;;\
        return sprintf("%.1f",$hdmsum);;;;\
}, \
Regenwahrscheinlichkeit24h:locations_xx.xxxxxx__yy.yyyyyyy_currentConditions_datetime:.*\
{\
    my $hdmvalue = 0;;;;\
    my $hdmzwischen = 0;;;;\
    my $hdmklammerkomplett = 1;;;;\
    my $hdmtotal = 0;;;;\
    for my $i ("01" .. "24")\
        {\
            $hdmvalue = ReadingsVal("WetterVisualCrossing", "locations_xx.xxxxxx__yy.yyyyyyy_values_".$i."_pop",0);;;;\
            $hdmzwischen = 1 - ($hdmvalue / 100.0);;;;\
            $hdmklammerkomplett = $hdmklammerkomplett * $hdmzwischen;;;;\
        };;;;\
        $hdmtotal = (1 - $hdmklammerkomplett) * 100.0;;;;\
        return sprintf("%d",$hdmtotal);;;;\
}, \
WindWertMail:locations_xx.xxxxxx__yy.yyyyyyy_currentConditions_datetime:.*\
{\
    my $hdmwindrichtung = 0;;;;\
    my $hdmcompassPoint = 0;;;;\
\
    for my $n ("01" .. "48")\
    {\
        if (ReadingsVal("WetterVisualCrossing", "locations_xx.xxxxxx__yy.yyyyyyy_values_".$n."_wgust",0)>69) {\
            $hdmwindrichtung = ReadingsVal("WetterVisualCrossing", "locations_xx.xxxxxx__yy.yyyyyyy_values_".$n."_wdir",0);;;;\
            \
\
            if ($hdmwindrichtung      < 22.5) {\
                $hdmcompassPoint = "Norden";;\
            } elsif ($hdmwindrichtung < 45)   {\
                $hdmcompassPoint = "Nord-Nordost";;\
            } elsif ($hdmwindrichtung < 67.5) {\
                $hdmcompassPoint = "Nordost";;\
            } elsif ($hdmwindrichtung < 90)   {\
                $hdmcompassPoint = "Ost-Nordost";;\
            } elsif ($hdmwindrichtung < 112.5){\
                $hdmcompassPoint = "Osten";;\
            } elsif ($hdmwindrichtung < 135)  {\
                $hdmcompassPoint = "Ost-Suedost";;\
            } elsif ($hdmwindrichtung < 157.5){\
                $hdmcompassPoint = "Suedost";;\
            } elsif ($hdmwindrichtung < 180)  {\
                $hdmcompassPoint = "Sued-Suedost";;\
            } elsif ($hdmwindrichtung < 202.5){\
                $hdmcompassPoint = "Sueden";;\
            } elsif ($hdmwindrichtung < 225)  {\
                $hdmcompassPoint = "Sued-Suedwest";;\
            } elsif ($hdmwindrichtung < 247.5){\
                $hdmcompassPoint = "Suedwest";;\
            } elsif ($hdmwindrichtung < 270)  {\
                $hdmcompassPoint = "West-Suedwest";;\
            } elsif ($hdmwindrichtung < 292.5){\
                $hdmcompassPoint = "Westen";;\
            } elsif ($hdmwindrichtung < 315)  {\
                $hdmcompassPoint = "West-Nordwest";;\
            } elsif ($hdmwindrichtung < 337.5){\
                $hdmcompassPoint = "Nordwest";;\
            } elsif ($hdmwindrichtung <= 361)  {\
                $hdmcompassPoint = "Nord-Nordwest";;\
            }\
            return ReadingsVal("WetterVisualCrossing", "locations_xx.xxxxxx__yy.yyyyyyy_values_".$n."_wgust",0)." km/h Boen in ".$n." Stunden aus ".$hdmcompassPoint;;;;\
        }\
        \
    };;;; \
    return "normal";;;;\
}

######### das Filelog braucht es mMn für das Logproxy Device. Deshalb/trotzdem spaeter disabled, weil ich die Readings nicht mehr speichern wollte. Ohne Device hatte ich es nicht probiert

define FileLog_WetterVisualCrossing FileLog ./log/WetterVisualCrossing-%Y-%m-%d.log WetterVisualCrossing
attr FileLog_WetterVisualCrossing disable 1
attr FileLog_WetterVisualCrossing group Wetter
attr FileLog_WetterVisualCrossing logtype text
attr FileLog_WetterVisualCrossing nrarchive 3

######## den Namen hatte es noch von vormals Proplanta, ist aber egal

define LogproxyWetterProplanta logProxy
attr LogproxyWetterProplanta group Wetter

######### die Plots. Die zugehoerigen Dateien angehaengt

define SVG_FileLog_WetterVisualCrossing SVG FileLog_WetterVisualCrossing:SVG_FileLog_WetterVisualCrossing:CURRENT
attr SVG_FileLog_WetterVisualCrossing fixedoffset 6
attr SVG_FileLog_WetterVisualCrossing fixedrange 7days
attr SVG_FileLog_WetterVisualCrossing group Wetter
attr SVG_FileLog_WetterVisualCrossing room Wettervorhersage

define SVG_FileLog_WetterVisualCrossing_temperatur SVG FileLog_WetterVisualCrossing:SVG_FileLog_WetterVisualCrossing_temperatur:CURRENT
attr SVG_FileLog_WetterVisualCrossing_temperatur fixedoffset 6
attr SVG_FileLog_WetterVisualCrossing_temperatur fixedrange 7days
attr SVG_FileLog_WetterVisualCrossing_temperatur group Wetter
attr SVG_FileLog_WetterVisualCrossing_temperatur label "Temperatur min $data{min1} C - max $data{max1} C"
attr SVG_FileLog_WetterVisualCrossing_temperatur room Wettervorhersage

99_myUtil.pm (hier auch x und y beachten)
############## hdm WetterVisualCrossing Wetter Plot funktion  ##################################
sub logProxy_WetterVisualCrossing2Plot($$$$;$$) {
    my ($device, $fcValue, $from, $to, $fcHour, $expMode) = @_;
    my $regex;
    my @rl;
    my $hdmreading;
    my $hdmtime;
   
    return undef if(!$device);
    if ($fcValue =~ s/_$//)
        {
            $regex = "^locations_xx.xxxxxx__yy.yyyyyyy_values_[\\d]+_".$fcValue."\$";           
        }   
    $fcHour = 12 if(!defined $fcHour);
    $expMode = "point" if(!defined $expMode);
#Log3 undef,2, "regex: ".$regex;
    if( defined($defs{$device}) ) {
        if( $defs{$device}{TYPE} eq "HTTPMOD" ) {
            @rl = sort{
                my ($an) = ($a =~ m/locations_xx.xxxxxx__yy.yyyyyyy_values_(\d+)_.*/);
#Log3 undef,2, "an: ".$an;
#Log3 undef,2, "a: ".$a;
                my ($bn) = ($b =~ m/locations_xx.xxxxxx__yy.yyyyyyy_values_(\d+)_.*/);
                $an <=> $bn or $a cmp $b;
                }( grep /${regex}/,keys %{$defs{$device}{READINGS}} );
            return undef if( !@rl );
        } else {
            Log3 undef, 2, "logProxy_WetterVisualCrossing2Plot: $device is not a HTTPMOD device";
            return undef;
        }
    }
#Log3 undef,2, Dumper(@rl);
    my $fromsec = SVG_time_to_sec($from);
    my $tosec   = SVG_time_to_sec($to);
    my $sec = $fromsec;
    my ($h,$hdmsec,$hdmmin,$hdmhour,$hdmmday,$hdmmon,$hdmyear,$hdmwday,$hdmyday,$hdmisdst);
    my $timestamp;
   
    my $reading;
    my $value;
    my $prev_value;
    my $min = 999999;
    my $max = -999999;
    my $ret = "";

    # while not end of plot range reached
    while(($sec < $tosec) && @rl) {
        #remember previous value for start of plot range
        $prev_value = $value;

        $reading = shift @rl;
        ($h) = $reading =~ m/^locations_xx.xxxxxx__yy.yyyyyyy_values_(\d+).*/;   
        $value = ReadingsVal($device,$reading,undef);


        use Date::Parse;
        $hdmreading = ReadingsVal($device, "locations_xx.xxxxxx__yy.yyyyyyy_values_".$h."_datetimeStr",undef);
#Log3 undef,2, "hdmvorCONV: ".$hdmreading;
        $hdmtime = str2time($hdmreading);
       
       
#Log3 undef,2, "hdmreading: ".$hdmreading;
#Log3 undef,2, "hdmtime: ".$hdmtime;
       
       
        #($hdmsec, $hdmmin, $hdmhour, $hdmmday, $hdmmon, $hdmyear, $hdmwday, $hdmyday, $hdmisdst) = localtime(ReadingsVal($device, "hfc".$h."_time",undef));
        ($hdmsec, $hdmmin, $hdmhour, $hdmmday, $hdmmon, $hdmyear, $hdmwday, $hdmyday, $hdmisdst) = localtime($hdmtime);       
       
 
        # necessary conversion of $mon and $year
        $hdmmon += 1;
        $hdmyear += 1900;
   
        $timestamp = sprintf("%04d-%02d-%02d_%02d:%02d:%02d", $hdmyear, $hdmmon, $hdmmday, $hdmhour, $hdmmin, $hdmsec);
#Log3 undef,2, "timestamp: ".$timestamp;
        $sec = SVG_time_to_sec($timestamp);
       
        # skip all values before start of plot range
        next if( SVG_time_to_sec($timestamp) < $fromsec );

        # add first value at start of plot range
        if( !$ret && $prev_value ) {
        $min = $prev_value if( $prev_value < $min );
        $max = $prev_value if( $prev_value > $max );
        $ret .= "$from $prev_value\n";
        }

        # done if after end of plot range
        last if($sec > $tosec);

        $min = $value if( $value < $min );
        $max = $value if( $value > $max );

        # add actual controll point
        $ret .= "$timestamp $value\n";

#Log 3, "$timestamp $value -0- $reading";
    }
    if(($sec < $tosec) && !@rl && ($expMode eq "day")) {
        $timestamp = sprintf("%04d-%02d-%02d_%02d:%02d:%02d", $hdmyear, $hdmmon, $hdmmday, 23, 59, 59);
        if(SVG_time_to_sec($timestamp) < $tosec) {
            $ret .= "$timestamp $value\n";
        }
        else {
            $ret .= "$to $value\n";
        }
    }
    elsif(($sec > $tosec) && ($expMode eq "day")) {
           $value = $prev_value + ($value - $prev_value)*(86400 + ($tosec - $sec))/86400;
           $ret .= "$to $value\n";
    }
    return ($ret,$min,$max,$prev_value);
}

############## end hdm WetterVisualCrossing Wetter Plot funktion ##################################

Wenn Interesse besteht, gibt es auch noch eine separate Abfrage des täglichen Wetters mit Wetterwarnungen zum zB implementieren in ftui.