2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-10 09:16:53 +00:00

59_Weather: add limit forecast, selection between daily and hourly forecast

git-svn-id: https://svn.fhem.de/fhem/trunk@18386 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
LeonGaultier 2019-01-23 06:43:45 +00:00
parent 853466dc7a
commit 9a398ab052
2 changed files with 570 additions and 286 deletions

View File

@ -1,5 +1,7 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
# Do not insert empty lines here, update check depends on it. # Do not insert empty lines here, update check depends on it.
- feature: 59_Weather: add limit forecast, selection between daily and hourly
forecast
- feature: 49_SSCam: V8.6.1, new attribute snapReadingRotate, time format in - feature: 49_SSCam: V8.6.1, new attribute snapReadingRotate, time format in
readings and galleries depends from global language readings and galleries depends from global language
attribute, minor bug fixes attribute, minor bug fixes

View File

@ -22,7 +22,6 @@
# #
############################################################################## ##############################################################################
package main; package main;
use strict; use strict;
@ -34,33 +33,138 @@ use vars qw($FW_ss);
# use Data::Dumper; # for Debug only # use Data::Dumper; # for Debug only
my %pressure_trend_txt_en = ( 0 => "steady", 1 => "rising", 2 => "falling" ); my %pressure_trend_txt_en = ( 0 => "steady", 1 => "rising", 2 => "falling" );
my %pressure_trend_txt_de = ( 0 => "gleichbleibend", 1 => "steigend", 2 => "fallend" ); my %pressure_trend_txt_de =
( 0 => "gleichbleibend", 1 => "steigend", 2 => "fallend" );
my %pressure_trend_txt_nl = ( 0 => "stabiel", 1 => "stijgend", 2 => "dalend" ); my %pressure_trend_txt_nl = ( 0 => "stabiel", 1 => "stijgend", 2 => "dalend" );
my %pressure_trend_txt_fr = ( 0 => "stable", 1 => "croissant", 2 => "décroissant" ); my %pressure_trend_txt_fr =
( 0 => "stable", 1 => "croissant", 2 => "décroissant" );
my %pressure_trend_txt_pl = ( 0 => "stabilne", 1 => "rośnie", 2 => "spada" ); my %pressure_trend_txt_pl = ( 0 => "stabilne", 1 => "rośnie", 2 => "spada" );
my %pressure_trend_txt_it = ( 0 => "stabile", 1 => "in aumento", 2 => "in diminuzione" ); my %pressure_trend_txt_it =
( 0 => "stabile", 1 => "in aumento", 2 => "in diminuzione" );
my %pressure_trend_sym = ( 0 => "=", 1 => "+", 2 => "-" ); my %pressure_trend_sym = ( 0 => "=", 1 => "+", 2 => "-" );
my @directions_txt_en = ('N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW'); my @directions_txt_en = (
my @directions_txt_de = ('N', 'NNO', 'NO', 'ONO', 'O', 'OSO', 'SO', 'SSO', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW'); 'N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE',
my @directions_txt_nl = ('N', 'NNO', 'NO', 'ONO', 'O', 'OZO', 'ZO', 'ZZO', 'Z', 'ZZW', 'ZW', 'WZW', 'W', 'WNW', 'NW', 'NNW'); 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW'
my @directions_txt_fr = ('N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSO', 'SO', 'OSO', 'O', 'ONO', 'NO', 'NNO'); );
my @directions_txt_pl = ('N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW'); my @directions_txt_de = (
my @directions_txt_it = ('N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSO', 'SO', 'OSO', 'O', 'ONO', 'NO', 'NNO'); 'N', 'NNO', 'NO', 'ONO', 'O', 'OSO', 'SO', 'SSO',
'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW'
);
my @directions_txt_nl = (
'N', 'NNO', 'NO', 'ONO', 'O', 'OZO', 'ZO', 'ZZO',
'Z', 'ZZW', 'ZW', 'WZW', 'W', 'WNW', 'NW', 'NNW'
);
my @directions_txt_fr = (
'N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE',
'S', 'SSO', 'SO', 'OSO', 'O', 'ONO', 'NO', 'NNO'
);
my @directions_txt_pl = (
'N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE',
'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW'
);
my @directions_txt_it = (
'N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE',
'S', 'SSO', 'SO', 'OSO', 'O', 'ONO', 'NO', 'NNO'
);
my %wdays_txt_en = ('Mon' => 'Mon', 'Tue' => 'Tue', 'Wed'=> 'Wed', 'Thu' => 'Thu', 'Fri' => 'Fri', 'Sat' => 'Sat', 'Sun' => 'Sun'); my %wdays_txt_en = (
my %wdays_txt_de = ('Mon' => 'Mo', 'Tue' => 'Di', 'Wed'=> 'Mi', 'Thu' => 'Do', 'Fri' => 'Fr', 'Sat' => 'Sa', 'Sun' => 'So'); 'Mon' => 'Mon',
my %wdays_txt_nl = ('Mon' => 'Maa', 'Tue' => 'Din', 'Wed'=> 'Woe', 'Thu' => 'Don', 'Fri' => 'Vri', 'Sat' => 'Zat', 'Sun' => 'Zon'); 'Tue' => 'Tue',
my %wdays_txt_fr= ('Mon' => 'Lun', 'Tue' => 'Mar', 'Wed'=> 'Mer', 'Thu' => 'Jeu', 'Fri' => 'Ven', 'Sat' => 'Sam', 'Sun' => 'Dim'); 'Wed' => 'Wed',
my %wdays_txt_pl = ('Mon' => 'Pon', 'Tue' => 'Wt', 'Wed'=> 'Śr', 'Thu' => 'Czw', 'Fri' => 'Pt', 'Sat' => 'Sob', 'Sun' => 'Nie'); 'Thu' => 'Thu',
my %wdays_txt_it = ('Mon' => 'Lun', 'Tue' => 'Mar', 'Wed'=> 'Mer', 'Thu' => 'Gio', 'Fri' => 'Ven', 'Sat' => 'Sab', 'Sun' => 'Dom'); 'Fri' => 'Fri',
'Sat' => 'Sat',
'Sun' => 'Sun'
);
my %wdays_txt_de = (
'Mon' => 'Mo',
'Tue' => 'Di',
'Wed' => 'Mi',
'Thu' => 'Do',
'Fri' => 'Fr',
'Sat' => 'Sa',
'Sun' => 'So'
);
my %wdays_txt_nl = (
'Mon' => 'Maa',
'Tue' => 'Din',
'Wed' => 'Woe',
'Thu' => 'Don',
'Fri' => 'Vri',
'Sat' => 'Zat',
'Sun' => 'Zon'
);
my %wdays_txt_fr = (
'Mon' => 'Lun',
'Tue' => 'Mar',
'Wed' => 'Mer',
'Thu' => 'Jeu',
'Fri' => 'Ven',
'Sat' => 'Sam',
'Sun' => 'Dim'
);
my %wdays_txt_pl = (
'Mon' => 'Pon',
'Tue' => 'Wt',
'Wed' => 'Śr',
'Thu' => 'Czw',
'Fri' => 'Pt',
'Sat' => 'Sob',
'Sun' => 'Nie'
);
my %wdays_txt_it = (
'Mon' => 'Lun',
'Tue' => 'Mar',
'Wed' => 'Mer',
'Thu' => 'Gio',
'Fri' => 'Ven',
'Sat' => 'Sab',
'Sun' => 'Dom'
);
my %status_items_txt_en = ( 0 => "Wind", 1 => "Humidity", 2 => "Temperature", 3 => "Right Now", 4 => "Weather forecast for " ); my %status_items_txt_en = (
my %status_items_txt_de = ( 0 => "Wind", 1 => "Feuchtigkeit", 2 => "Temperatur", 3 => "Jetzt Sofort", 4 => "Wettervorhersage für " ); 0 => "Wind",
my %status_items_txt_nl = ( 0 => "Wind", 1 => "Vochtigheid", 2 => "Temperatuur", 3 => "Direct", 4 => "Weersvoorspelling voor " ); 1 => "Humidity",
my %status_items_txt_fr = ( 0 => "Vent", 1 => "Humidité", 2 => "Température", 3 => "Maintenant", 4 => "Prévisions météo pour " ); 2 => "Temperature",
my %status_items_txt_pl = ( 0 => "Wiatr", 1 => "Wilgotność", 2 => "Temperatura", 3 => "Teraz", 4 => "Prognoza pogody w " ); 3 => "Right Now",
my %status_items_txt_it = ( 0 => "Vento", 1 => "Umidità", 2 => "Temperatura", 3 => "Adesso", 4 => "Previsioni del tempo per " ); 4 => "Weather forecast for "
);
my %status_items_txt_de = (
0 => "Wind",
1 => "Feuchtigkeit",
2 => "Temperatur",
3 => "Jetzt Sofort",
4 => "Wettervorhersage für "
);
my %status_items_txt_nl = (
0 => "Wind",
1 => "Vochtigheid",
2 => "Temperatuur",
3 => "Direct",
4 => "Weersvoorspelling voor "
);
my %status_items_txt_fr = (
0 => "Vent",
1 => "Humidité",
2 => "Température",
3 => "Maintenant",
4 => "Prévisions météo pour "
);
my %status_items_txt_pl = (
0 => "Wiatr",
1 => "Wilgotność",
2 => "Temperatura",
3 => "Teraz",
4 => "Prognoza pogody w "
);
my %status_items_txt_it = (
0 => "Vento",
1 => "Umidità",
2 => "Temperatura",
3 => "Adesso",
4 => "Previsioni del tempo per "
);
my %wdays_txt_i18n; my %wdays_txt_i18n;
my @directions_txt_i18n; my @directions_txt_i18n;
@ -68,14 +172,31 @@ my %pressure_trend_txt_i18n;
my %status_items_txt_i18n; my %status_items_txt_i18n;
my @iconlist = ( my @iconlist = (
'storm', 'storm', 'storm', 'thunderstorm', 'thunderstorm', 'rainsnow', 'storm', 'storm',
'sleet', 'snow', 'drizzle', 'drizzle', 'icy' ,'chance_of_rain', 'storm', 'thunderstorm',
'chance_of_rain', 'snowflurries', 'chance_of_snow', 'heavysnow', 'snow', 'sleet', 'thunderstorm', 'rainsnow',
'sleet', 'dust', 'fog', 'haze', 'smoke', 'flurries', 'sleet', 'snow',
'windy', 'icy', 'cloudy', 'mostlycloudy_night', 'mostlycloudy', 'partly_cloudy_night', 'drizzle', 'drizzle',
'partly_cloudy', 'sunny', 'sunny', 'mostly_clear_night', 'mostly_sunny', 'heavyrain', 'icy', 'chance_of_rain',
'sunny', 'scatteredthunderstorms', 'scatteredthunderstorms', 'scatteredthunderstorms', 'scatteredshowers', 'heavysnow', 'chance_of_rain', 'snowflurries',
'chance_of_snow', 'heavysnow', 'partly_cloudy', 'heavyrain', 'chance_of_snow', 'scatteredshowers'); 'chance_of_snow', 'heavysnow',
'snow', 'sleet',
'sleet', 'dust',
'fog', 'haze',
'smoke', 'flurries',
'windy', 'icy',
'cloudy', 'mostlycloudy_night',
'mostlycloudy', 'partly_cloudy_night',
'partly_cloudy', 'sunny',
'sunny', 'mostly_clear_night',
'mostly_sunny', 'heavyrain',
'sunny', 'scatteredthunderstorms',
'scatteredthunderstorms', 'scatteredthunderstorms',
'scatteredshowers', 'heavysnow',
'chance_of_snow', 'heavysnow',
'partly_cloudy', 'heavyrain',
'chance_of_snow', 'scatteredshowers'
);
################################### ###################################
sub Weather_LanguageInitialize($) { sub Weather_LanguageInitialize($) {
@ -86,27 +207,32 @@ sub Weather_LanguageInitialize($) {
@directions_txt_i18n = @directions_txt_de; @directions_txt_i18n = @directions_txt_de;
%pressure_trend_txt_i18n = %pressure_trend_txt_de; %pressure_trend_txt_i18n = %pressure_trend_txt_de;
%status_items_txt_i18n = %status_items_txt_de; %status_items_txt_i18n = %status_items_txt_de;
} elsif($lang eq "nl") { }
elsif ( $lang eq "nl" ) {
%wdays_txt_i18n = %wdays_txt_nl; %wdays_txt_i18n = %wdays_txt_nl;
@directions_txt_i18n = @directions_txt_nl; @directions_txt_i18n = @directions_txt_nl;
%pressure_trend_txt_i18n = %pressure_trend_txt_nl; %pressure_trend_txt_i18n = %pressure_trend_txt_nl;
%status_items_txt_i18n = %status_items_txt_nl; %status_items_txt_i18n = %status_items_txt_nl;
} elsif($lang eq "fr") { }
elsif ( $lang eq "fr" ) {
%wdays_txt_i18n = %wdays_txt_fr; %wdays_txt_i18n = %wdays_txt_fr;
@directions_txt_i18n = @directions_txt_fr; @directions_txt_i18n = @directions_txt_fr;
%pressure_trend_txt_i18n = %pressure_trend_txt_fr; %pressure_trend_txt_i18n = %pressure_trend_txt_fr;
%status_items_txt_i18n = %status_items_txt_fr; %status_items_txt_i18n = %status_items_txt_fr;
} elsif($lang eq "pl") { }
elsif ( $lang eq "pl" ) {
%wdays_txt_i18n = %wdays_txt_pl; %wdays_txt_i18n = %wdays_txt_pl;
@directions_txt_i18n = @directions_txt_pl; @directions_txt_i18n = @directions_txt_pl;
%pressure_trend_txt_i18n = %pressure_trend_txt_pl; %pressure_trend_txt_i18n = %pressure_trend_txt_pl;
%status_items_txt_i18n = %status_items_txt_pl; %status_items_txt_i18n = %status_items_txt_pl;
} elsif($lang eq "it") { }
elsif ( $lang eq "it" ) {
%wdays_txt_i18n = %wdays_txt_it; %wdays_txt_i18n = %wdays_txt_it;
@directions_txt_i18n = @directions_txt_it; @directions_txt_i18n = @directions_txt_it;
%pressure_trend_txt_i18n = %pressure_trend_txt_it; %pressure_trend_txt_i18n = %pressure_trend_txt_it;
%status_items_txt_i18n = %status_items_txt_it; %status_items_txt_i18n = %status_items_txt_it;
} else { }
else {
%wdays_txt_i18n = %wdays_txt_en; %wdays_txt_i18n = %wdays_txt_en;
@directions_txt_i18n = @directions_txt_en; @directions_txt_i18n = @directions_txt_en;
%pressure_trend_txt_i18n = %pressure_trend_txt_en; %pressure_trend_txt_i18n = %pressure_trend_txt_en;
@ -121,12 +247,12 @@ sub Weather_DebugCodes($) {
Debug "Weather Code List, see http://developer.yahoo.com/weather/#codes"; Debug "Weather Code List, see http://developer.yahoo.com/weather/#codes";
for ( my $c = 0 ; $c <= 47 ; $c++ ) { for ( my $c = 0 ; $c <= 47 ; $c++ ) {
Debug sprintf("%2d %30s %30s", $c, $iconlist[$c], $YahooCodes_i18n[$c]); Debug
sprintf( "%2d %30s %30s", $c, $iconlist[$c], $YahooCodes_i18n[$c] );
} }
} }
##################################### #####################################
sub Weather_Initialize($) { sub Weather_Initialize($) {
my ($hash) = @_; my ($hash) = @_;
@ -137,6 +263,8 @@ sub Weather_Initialize($) {
$hash->{SetFn} = 'Weather_Set'; $hash->{SetFn} = 'Weather_Set';
$hash->{AttrList} = $hash->{AttrList} =
'disable:0,1 ' 'disable:0,1 '
. 'forecast:hourly,daily,every,off '
. 'forecastLimit '
. $readingFnAttributes; . $readingFnAttributes;
$hash->{NotifyFn} = 'Weather_Notify'; $hash->{NotifyFn} = 'Weather_Notify';
@ -151,7 +279,6 @@ sub degrees_to_direction($@) {
return $directions_txt_i18n[$mod]; return $directions_txt_i18n[$mod];
} }
sub Weather_ReturnWithError($$) { sub Weather_ReturnWithError($$) {
my ( $hash, $responseRef ) = @_; my ( $hash, $responseRef ) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
@ -160,9 +287,14 @@ sub Weather_ReturnWithError($$) {
readingsBulkUpdate( $hash, 'lastError', $responseRef->{status} ); readingsBulkUpdate( $hash, 'lastError', $responseRef->{status} );
foreach my $r ( keys %{$responseRef} ) { foreach my $r ( keys %{$responseRef} ) {
readingsBulkUpdate($hash, $r, $responseRef->{$r}) if ( ref($responseRef->{$r}) ne 'HASH' ); readingsBulkUpdate( $hash, $r, $responseRef->{$r} )
if ( ref( $responseRef->{$r} ) ne 'HASH' );
} }
readingsBulkUpdate($hash, 'state', 'API Maintainer: ' . $responseRef->{apiMaintainer} . ' ErrorMsg: ' . $responseRef->{status}); readingsBulkUpdate( $hash, 'state',
'API Maintainer: '
. $responseRef->{apiMaintainer}
. ' ErrorMsg: '
. $responseRef->{status} );
readingsEndUpdate( $hash, 1 ); readingsEndUpdate( $hash, 1 );
my $next = 60; # $next= $hash->{INTERVAL}; my $next = 60; # $next= $hash->{INTERVAL};
@ -190,101 +322,177 @@ sub Weather_WriteReadings($$) {
readingsBeginUpdate($hash); readingsBeginUpdate($hash);
# delete some unused readings # delete some unused readings
delete($hash->{READINGS}->{temp_f}) if(defined($hash->{READINGS}->{temp_f})); delete( $hash->{READINGS}->{temp_f} )
delete($hash->{READINGS}->{unit_distance}) if(defined($hash->{READINGS}->{unit_distance})); if ( defined( $hash->{READINGS}->{temp_f} ) );
delete($hash->{READINGS}->{unit_speed}) if(defined($hash->{READINGS}->{unit_speed})); delete( $hash->{READINGS}->{unit_distance} )
delete($hash->{READINGS}->{unit_pressuree}) if(defined($hash->{READINGS}->{unit_pressuree})); if ( defined( $hash->{READINGS}->{unit_distance} ) );
delete($hash->{READINGS}->{unit_temperature}) if(defined($hash->{READINGS}->{unit_temperature})); delete( $hash->{READINGS}->{unit_speed} )
if ( defined( $hash->{READINGS}->{unit_speed} ) );
delete( $hash->{READINGS}->{unit_pressuree} )
if ( defined( $hash->{READINGS}->{unit_pressuree} ) );
delete( $hash->{READINGS}->{unit_temperature} )
if ( defined( $hash->{READINGS}->{unit_temperature} ) );
# housekeeping information # housekeeping information
readingsBulkUpdate( $hash, 'lastError', '' ); readingsBulkUpdate( $hash, 'lastError', '' );
foreach my $r ( keys %{$dataRef} ) { foreach my $r ( keys %{$dataRef} ) {
readingsBulkUpdate( $hash, $r, $dataRef->{$r} ) readingsBulkUpdate( $hash, $r, $dataRef->{$r} )
if ( ref($dataRef->{$r}) ne 'HASH' and ref($dataRef->{$r}) ne 'ARRAY' ); if ( ref( $dataRef->{$r} ) ne 'HASH'
and ref( $dataRef->{$r} ) ne 'ARRAY' );
readingsBulkUpdate( $hash, '.license', $dataRef->{license}->{text} ); readingsBulkUpdate( $hash, '.license', $dataRef->{license}->{text} );
} }
### current ### current
if ( defined($dataRef->{current}) and ref( $dataRef->{current} ) eq 'HASH' ) { if ( defined( $dataRef->{current} )
and ref( $dataRef->{current} ) eq 'HASH' )
{
while ( my ( $r, $v ) = each %{ $dataRef->{current} } ) { while ( my ( $r, $v ) = each %{ $dataRef->{current} } ) {
readingsBulkUpdate( $hash, $r, $v ) readingsBulkUpdate( $hash, $r, $v )
if ( ref($dataRef->{$r}) ne 'HASH' and ref($dataRef->{$r}) ne 'ARRAY' ); if ( ref( $dataRef->{$r} ) ne 'HASH'
and ref( $dataRef->{$r} ) ne 'ARRAY' );
} }
readingsBulkUpdate($hash, 'icon', $iconlist[$dataRef->{current}->{code}]); readingsBulkUpdate( $hash, 'icon',
$iconlist[ $dataRef->{current}->{code} ] );
if ( defined( $dataRef->{current}->{wind_direction} ) if ( defined( $dataRef->{current}->{wind_direction} )
and $dataRef->{current}->{wind_direction} and $dataRef->{current}->{wind_direction}
and defined( $dataRef->{current}->{wind_speed} ) and defined( $dataRef->{current}->{wind_speed} )
and $dataRef->{current}->{wind_speed} and $dataRef->{current}->{wind_speed} )
)
{ {
my $wdir= degrees_to_direction($dataRef->{current}->{wind_direction}, @directions_txt_i18n); my $wdir =
readingsBulkUpdate($hash, 'wind_condition', 'Wind: ' . $wdir . ' ' . $dataRef->{current}->{wind_speed} . ' km/h'); degrees_to_direction( $dataRef->{current}->{wind_direction},
@directions_txt_i18n );
readingsBulkUpdate( $hash, 'wind_condition',
'Wind: '
. $wdir . ' '
. $dataRef->{current}->{wind_speed}
. ' km/h' );
} }
} }
### forecast ### forecast
if ( ref( $dataRef->{forecast} ) eq 'HASH' ) { if ( ref( $dataRef->{forecast} ) eq 'HASH'
and AttrVal( $name, 'forecast', 'every' ) ne 'off' )
{
## hourly ## hourly
if ( defined($dataRef->{forecast}->{hourly}) if (
defined( $dataRef->{forecast}->{hourly} )
and ref( $dataRef->{forecast}->{hourly} ) eq 'ARRAY' and ref( $dataRef->{forecast}->{hourly} ) eq 'ARRAY'
and scalar( @{ $dataRef->{forecast}->{hourly} } ) > 0 ) and scalar( @{ $dataRef->{forecast}->{hourly} } ) > 0
and ( AttrVal( $name, 'forecast', 'every' ) eq 'every'
or AttrVal( $name, 'forecast', 'hourly' ) eq 'hourly' )
)
{ {
my $i = 0; my $i = 0;
my $limit = AttrVal( $name, 'forecastLimit', -1 );
foreach my $fc ( @{ $dataRef->{forecast}->{hourly} } ) { foreach my $fc ( @{ $dataRef->{forecast}->{hourly} } ) {
$i++; $i++;
my $f = "hfc" . $i . "_"; my $f = "hfc" . $i . "_";
while ( my ( $r, $v ) = each %{$fc} ) { while ( my ( $r, $v ) = each %{$fc} ) {
readingsBulkUpdate( $hash, $f . $r, $v ) readingsBulkUpdate( $hash, $f . $r, $v )
if ( ref($dataRef->{$r}) ne 'HASH' and ref($dataRef->{$r}) ne 'ARRAY' ); if ( ref( $dataRef->{$r} ) ne 'HASH'
and ref( $dataRef->{$r} ) ne 'ARRAY' );
} }
readingsBulkUpdate($hash, $f . 'icon', $iconlist[$dataRef->{forecast}->{hourly}[$i-1]{code}]); readingsBulkUpdate(
$hash,
$f . 'icon',
$iconlist[ $dataRef->{forecast}->{hourly}[ $i - 1 ]{code} ]
);
if ( defined($dataRef->{forecast}->{hourly}[$i-1]{wind_direction}) if (
defined(
$dataRef->{forecast}->{hourly}[ $i - 1 ]{wind_direction}
)
and $dataRef->{forecast}->{hourly}[ $i - 1 ]{wind_direction} and $dataRef->{forecast}->{hourly}[ $i - 1 ]{wind_direction}
and defined($dataRef->{forecast}->{hourly}[$i-1]{wind_speed}) and defined(
$dataRef->{forecast}->{hourly}[ $i - 1 ]{wind_speed}
)
and $dataRef->{forecast}->{hourly}[ $i - 1 ]{wind_speed} and $dataRef->{forecast}->{hourly}[ $i - 1 ]{wind_speed}
) )
{ {
my $wdir= degrees_to_direction($dataRef->{forecast}->{hourly}[$i-1]{wind_direction}, @directions_txt_i18n); my $wdir = degrees_to_direction(
readingsBulkUpdate($hash, $f . 'wind_condition', 'Wind: ' . $wdir . ' ' . $dataRef->{forecast}->{hourly}[$i-1]{wind_speed} . ' km/h'); $dataRef->{forecast}
->{hourly}[ $i - 1 ]{wind_direction},
@directions_txt_i18n
);
readingsBulkUpdate(
$hash,
$f . 'wind_condition',
'Wind: '
. $wdir . ' '
. $dataRef->{forecast}->{hourly}[ $i - 1 ]{wind_speed}
. ' km/h'
);
} }
last if ( $i == $limit and $limit > 0 );
} }
} }
## daily ## daily
if ( defined($dataRef->{forecast}->{daily}) and ref( $dataRef->{forecast}->{daily} ) eq 'ARRAY' if (
and scalar( @{ $dataRef->{forecast}->{daily} } ) > 0 ) defined( $dataRef->{forecast}->{daily} )
and ref( $dataRef->{forecast}->{daily} ) eq 'ARRAY'
and scalar( @{ $dataRef->{forecast}->{daily} } ) > 0
and ( AttrVal( $name, 'forecast', 'every' ) eq 'every'
or AttrVal( $name, 'forecast', 'daily' ) eq 'daily' )
)
{ {
my $i = 0; my $i = 0;
my $limit = AttrVal( $name, 'forecastLimit', -1 );
foreach my $fc ( @{ $dataRef->{forecast}->{daily} } ) { foreach my $fc ( @{ $dataRef->{forecast}->{daily} } ) {
$i++; $i++;
my $f = "fc" . $i . "_"; my $f = "fc" . $i . "_";
while ( my ( $r, $v ) = each %{$fc} ) { while ( my ( $r, $v ) = each %{$fc} ) {
readingsBulkUpdate( $hash, $f . $r, $v ) readingsBulkUpdate( $hash, $f . $r, $v )
if ( ref($dataRef->{$r}) ne 'HASH' and ref($dataRef->{$r}) ne 'ARRAY' ); if ( ref( $dataRef->{$r} ) ne 'HASH'
and ref( $dataRef->{$r} ) ne 'ARRAY' );
} }
readingsBulkUpdate($hash, $f . 'icon', $iconlist[$dataRef->{forecast}->{daily}[$i-1]{code}]); readingsBulkUpdate(
$hash,
$f . 'icon',
$iconlist[ $dataRef->{forecast}->{daily}[ $i - 1 ]{code} ]
);
if ( defined($dataRef->{forecast}->{daily}[$i-1]{wind_direction}) if (
defined(
$dataRef->{forecast}->{daily}[ $i - 1 ]{wind_direction}
)
and $dataRef->{forecast}->{daily}[ $i - 1 ]{wind_direction} and $dataRef->{forecast}->{daily}[ $i - 1 ]{wind_direction}
and defined($dataRef->{forecast}->{daily}[$i-1]{wind_speed}) and defined(
$dataRef->{forecast}->{daily}[ $i - 1 ]{wind_speed}
)
and $dataRef->{forecast}->{daily}[ $i - 1 ]{wind_speed} and $dataRef->{forecast}->{daily}[ $i - 1 ]{wind_speed}
) )
{ {
my $wdir= degrees_to_direction($dataRef->{forecast}->{daily}[$i-1]{wind_direction}, @directions_txt_i18n); my $wdir = degrees_to_direction(
readingsBulkUpdate($hash, $f . 'wind_condition', 'Wind: ' . $wdir . ' ' . $dataRef->{forecast}->{daily}[$i-1]{wind_speed} . ' km/h'); $dataRef->{forecast}->{daily}[ $i - 1 ]{wind_direction},
@directions_txt_i18n
);
readingsBulkUpdate(
$hash,
$f . 'wind_condition',
'Wind: '
. $wdir . ' '
. $dataRef->{forecast}->{daily}[ $i - 1 ]{wind_speed}
. ' km/h'
);
} }
last if ( $i == $limit and $limit > 0 );
} }
} }
} }
my $val= 'T: ' . $dataRef->{current}->{temperature} . ' °C' my $val = 'T: '
.' ' . substr($status_items_txt_i18n{1}, 0, 1) . ': ' . $dataRef->{current}->{humidity} . ' %' . $dataRef->{current}->{temperature} . ' °C' . ' '
.' ' . substr($status_items_txt_i18n{0}, 0, 1) . ': ' . $dataRef->{current}->{wind} . ' km/h' . substr( $status_items_txt_i18n{1}, 0, 1 ) . ': '
.' P: ' . $dataRef->{current}->{pressure} . ' hPa'; . $dataRef->{current}->{humidity} . ' %' . ' '
. substr( $status_items_txt_i18n{0}, 0, 1 ) . ': '
. $dataRef->{current}->{wind} . ' km/h' . ' P: '
. $dataRef->{current}->{pressure} . ' hPa';
Log3 $hash, 4, "$name: $val"; Log3 $hash, 4, "$name: $val";
readingsBulkUpdate( $hash, 'state', $val ); readingsBulkUpdate( $hash, 'state', $val );
@ -302,13 +510,15 @@ sub Weather_GetUpdate($) {
my $name = $hash->{NAME}; my $name = $hash->{NAME};
if ( $attr{$name} && $attr{$name}->{disable} ) { if ( $attr{$name} && $attr{$name}->{disable} ) {
Log3 $hash, 5, "Weather $name: retrieval of weather data is disabled by attribute."; Log3 $hash, 5,
"Weather $name: retrieval of weather data is disabled by attribute.";
readingsBeginUpdate($hash); readingsBeginUpdate($hash);
readingsBulkUpdate( $hash, "pubDateComment", "disabled by attribute" ); readingsBulkUpdate( $hash, "pubDateComment", "disabled by attribute" );
readingsBulkUpdate( $hash, "validity", "stale" ); readingsBulkUpdate( $hash, "validity", "stale" );
readingsEndUpdate( $hash, 1 ); readingsEndUpdate( $hash, 1 );
Weather_RearmTimer( $hash, gettimeofday() + $hash->{INTERVAL} ); Weather_RearmTimer( $hash, gettimeofday() + $hash->{INTERVAL} );
} else { }
else {
# Weather_RetrieveData($name, 0); # Weather_RetrieveData($name, 0);
$hash->{fhem}->{api}->setRetrieveData; $hash->{fhem}->{api}->setRetrieveData;
} }
@ -327,7 +537,8 @@ sub Weather_Get($@) {
if ( defined( $hash->{READINGS}->{$reading} ) ) { if ( defined( $hash->{READINGS}->{$reading} ) ) {
$value = $hash->{READINGS}->{$reading}->{VAL}; $value = $hash->{READINGS}->{$reading}->{VAL};
} else { }
else {
my $rt = ''; my $rt = '';
if ( defined( $hash->{READINGS} ) ) { if ( defined( $hash->{READINGS} ) ) {
$rt = join( ":noArg ", sort keys %{ $hash->{READINGS} } ); $rt = join( ":noArg ", sort keys %{ $hash->{READINGS} } );
@ -350,7 +561,8 @@ sub Weather_Set($@) {
Weather_DisarmTimer($hash); Weather_DisarmTimer($hash);
Weather_GetUpdate($hash); Weather_GetUpdate($hash);
return undef; return undef;
} else { }
else {
return "Unknown argument $cmd, choose one of update:noArg"; return "Unknown argument $cmd, choose one of update:noArg";
} }
} }
@ -386,7 +598,8 @@ sub Weather_Notify($$) {
#$delay= 3; # delay removed until further notice #$delay= 3; # delay removed until further notice
Log3 $hash, 5, "Weather $name: FHEM initialization or rereadcfg triggered update, delay $delay seconds."; Log3 $hash, 5,
"Weather $name: FHEM initialization or rereadcfg triggered update, delay $delay seconds.";
Weather_RearmTimer( $hash, gettimeofday() + $delay ); Weather_RearmTimer( $hash, gettimeofday() + $delay );
return undef; return undef;
@ -396,7 +609,8 @@ sub Weather_Notify($$) {
sub Weather_Define($$) { sub Weather_Define($$) {
my ( $hash, $def ) = @_; my ( $hash, $def ) = @_;
my $usage= "syntax: define <name> Weather [API=<API>] [apikey=<apikey>] [location=<location>] [interval=<interval>] [lang=<lang>]"; my $usage =
"syntax: define <name> Weather [API=<API>] [apikey=<apikey>] [location=<location>] [interval=<interval>] [lang=<lang>]";
# defaults # defaults
my $API = "DarkSkyAPI,cachemaxage:600"; my $API = "DarkSkyAPI,cachemaxage:600";
@ -411,7 +625,6 @@ sub Weather_Define($$) {
return $usage unless ( scalar @a == 2 ); return $usage unless ( scalar @a == 2 );
my $name = $a[0]; my $name = $a[0];
my $location = $h{location} if exists $h{location}; my $location = $h{location} if exists $h{location};
my $apikey = $h{apikey} if exists $h{apikey}; my $apikey = $h{apikey} if exists $h{apikey};
my $lang = $h{lang} if exists $h{lang}; my $lang = $h{lang} if exists $h{lang};
@ -421,16 +634,21 @@ sub Weather_Define($$) {
# evaluate API options # evaluate API options
my ( $api, $apioptions ) = split( ',', $API, 2 ); my ( $api, $apioptions ) = split( ',', $API, 2 );
$apioptions = "" unless ( defined($apioptions) ); $apioptions = "" unless ( defined($apioptions) );
eval { eval { require "$api.pm"; };
require "$api.pm";
};
return "$name: cannot load API $api: $@" if ($@); return "$name: cannot load API $api: $@" if ($@);
$hash->{NOTIFYDEV} = "global"; $hash->{NOTIFYDEV} = "global";
$hash->{fhem}->{interfaces} = "temperature;humidity;wind"; $hash->{fhem}->{interfaces} = "temperature;humidity;wind";
$hash->{LOCATION} = ( (defined($location) and $location) ? $location : AttrVal( 'global', 'latitude', 'error' ).','.AttrVal( 'global', 'longitude', 'error' ) ); $hash->{LOCATION} =
( ( defined($location) and $location )
? $location
: AttrVal( 'global', 'latitude', 'error' ) . ','
. AttrVal( 'global', 'longitude', 'error' ) );
$hash->{INTERVAL} = $interval; $hash->{INTERVAL} = $interval;
$hash->{LANG} = ( (defined($lang) and $lang) ? $lang : lc(AttrVal('global','language','de')) ); $hash->{LANG} =
( ( defined($lang) and $lang )
? $lang
: lc( AttrVal( 'global', 'language', 'de' ) ) );
$hash->{API} = $api; $hash->{API} = $api;
$hash->{MODEL} = $api; $hash->{MODEL} = $api;
$hash->{APIKEY} = $apikey; $hash->{APIKEY} = $apikey;
@ -443,7 +661,15 @@ sub Weather_Define($$) {
Weather_LanguageInitialize( $hash->{LANG} ); Weather_LanguageInitialize( $hash->{LANG} );
my $apistring = $api . '::Weather'; my $apistring = $api . '::Weather';
$hash->{fhem}->{api} = $apistring->new( { devName => $hash->{NAME}, apikey => $hash->{APIKEY}, location => $hash->{LOCATION}, apioptions => $hash->{APIOPTIONS}, language => $hash->{LANG} } ); $hash->{fhem}->{api} = $apistring->new(
{
devName => $hash->{NAME},
apikey => $hash->{APIKEY},
location => $hash->{LOCATION},
apioptions => $hash->{APIOPTIONS},
language => $hash->{LANG}
}
);
Weather_GetUpdate($hash) if ($init_done); Weather_GetUpdate($hash) if ($init_done);
@ -478,11 +704,11 @@ sub WeatherIconIMGTag($) {
##################################### #####################################
sub WeatherAsHtmlV($;$) { sub WeatherAsHtmlV($;$$) {
my ($d,$items) = @_; my ( $d, $items, $f ) = @_;
$d = "<none>" if ( !$d ); $d = "<none>" if ( !$d );
$items = 9 if( !$items ); $items = 6 if ( !$items );
return "$d is not a Weather instance<br>" return "$d is not a Weather instance<br>"
if ( !$defs{$d} || $defs{$d}->{TYPE} ne "Weather" ); if ( !$defs{$d} || $defs{$d}->{TYPE} ne "Weather" );
@ -490,21 +716,44 @@ sub WeatherAsHtmlV($;$) {
my $width = int( ICONSCALE * ICONWIDTH ); my $width = int( ICONSCALE * ICONWIDTH );
my $ret = '<table class="weather">'; my $ret = '<table class="weather">';
$ret .= sprintf('<tr><td class="weatherIcon" width=%d>%s</td><td class="weatherValue">%s<br>%s°C %s%%<br>%s</td></tr>', my $fc;
if (
defined($f)
and ( $f eq 'h'
or $f eq 'd' )
)
{
$fc = ( $f eq 'd' ? 'fc' : 'hfc' );
}
else {
$fc = (
(
defined( $h->{READINGS}->{fc1_day_of_week} )
and $h->{READINGS}->{fc1_day_of_week}
) ? 'fc' : 'hfc'
);
}
$ret .= sprintf(
'<tr><td class="weatherIcon" width=%d>%s</td><td class="weatherValue">%s<br>%s°C %s%%<br>%s</td></tr>',
$width, $width,
WeatherIconIMGTag( ReadingsVal( $d, "icon", "" ) ), WeatherIconIMGTag( ReadingsVal( $d, "icon", "" ) ),
ReadingsVal( $d, "condition", "" ), ReadingsVal( $d, "condition", "" ),
ReadingsVal($d, "temp_c", ""), ReadingsVal($d, "humidity", ""), ReadingsVal( $d, "temp_c", "" ),
ReadingsVal($d, "wind_condition", "")); ReadingsVal( $d, "humidity", "" ),
ReadingsVal( $d, "wind_condition", "" )
);
my $fc = ( (defined($h->{READINGS}->{fc1_day_of_week}) and $h->{READINGS}->{fc1_day_of_week}) ? 'fc' : 'hfc' );
for ( my $i = 1 ; $i < $items ; $i++ ) { for ( my $i = 1 ; $i < $items ; $i++ ) {
$ret .= sprintf('<tr><td class="weatherIcon" width=%d>%s</td><td class="weatherValue"><span class="weatherDay">%s: %s</span><br><span class="weatherMin">min %s°C</span> <span class="weatherMax">max %s°C</span></td></tr>', $ret .= sprintf(
'<tr><td class="weatherIcon" width=%d>%s</td><td class="weatherValue"><span class="weatherDay">%s: %s</span><br><span class="weatherMin">min %s°C</span> <span class="weatherMax">max %s°C</span></td></tr>',
$width, $width,
WeatherIconIMGTag( ReadingsVal( $d, "${fc}${i}_icon", "" ) ), WeatherIconIMGTag( ReadingsVal( $d, "${fc}${i}_icon", "" ) ),
ReadingsVal( $d, "${fc}${i}_day_of_week", "" ), ReadingsVal( $d, "${fc}${i}_day_of_week", "" ),
ReadingsVal( $d, "${fc}${i}_condition", "" ), ReadingsVal( $d, "${fc}${i}_condition", "" ),
ReadingsVal($d, "${fc}${i}_low_c", ""), ReadingsVal($d, "${fc}${i}_high_c", "")); ReadingsVal( $d, "${fc}${i}_low_c", " - " ),
ReadingsVal( $d, "${fc}${i}_high_c", " - " )
);
} }
$ret .= "</table>"; $ret .= "</table>";
@ -517,50 +766,79 @@ sub WeatherAsHtml($;$) {
WeatherAsHtmlV( $d, $i ); WeatherAsHtmlV( $d, $i );
} }
sub WeatherAsHtmlH($;$) { sub WeatherAsHtmlH($;$$) {
my ($d,$items) = @_; my ( $d, $items, $f ) = @_;
$d = "<none>" if ( !$d ); $d = "<none>" if ( !$d );
$items = 9 if( !$items ); $items = 6 if ( !$items );
return "$d is not a Weather instance<br>" return "$d is not a Weather instance<br>"
if ( !$defs{$d} || $defs{$d}->{TYPE} ne "Weather" ); if ( !$defs{$d} || $defs{$d}->{TYPE} ne "Weather" );
my $h = $defs{$d}; my $h = $defs{$d};
my $width = int( ICONSCALE * ICONWIDTH ); my $width = int( ICONSCALE * ICONWIDTH );
my $format =
'<td><table border=1><tr><td class="weatherIcon" width=%d>%s</td></tr><tr><td class="weatherValue">%s</td></tr><tr><td class="weatherValue">%s°C %s%%</td></tr><tr><td class="weatherValue">%s</td></tr></table></td>';
my $format= '<td><table border=1><tr><td class="weatherIcon" width=%d>%s</td></tr><tr><td class="weatherValue">%s</td></tr><tr><td class="weatherValue">%s°C %s%%</td></tr><tr><td class="weatherValue">%s</td></tr></table></td>';
my $ret = '<table class="weather">'; my $ret = '<table class="weather">';
my $fc = ( (defined($h->{READINGS}->{fc1_day_of_week}) and $h->{READINGS}->{fc1_day_of_week}) ? 'fc' : 'hfc' ); my $fc;
if (
defined($f)
and ( $f eq 'h'
or $f eq 'd' )
)
{
$fc = ( $f eq 'd' ? 'fc' : 'hfc' );
}
else {
$fc = (
(
defined( $h->{READINGS}->{fc1_day_of_week} )
and $h->{READINGS}->{fc1_day_of_week}
) ? 'fc' : 'hfc'
);
}
# icons # icons
$ret .= sprintf('<tr><td class="weatherIcon" width=%d>%s</td>', $width, WeatherIconIMGTag(ReadingsVal($d, "icon", ""))); $ret .= sprintf( '<tr><td class="weatherIcon" width=%d>%s</td>',
$width, WeatherIconIMGTag( ReadingsVal( $d, "icon", "" ) ) );
for ( my $i = 1 ; $i < $items ; $i++ ) { for ( my $i = 1 ; $i < $items ; $i++ ) {
$ret .= sprintf('<td class="weatherIcon" width=%d>%s</td>', $width, WeatherIconIMGTag(ReadingsVal($d, "${fc}${i}_icon", ""))); $ret .= sprintf( '<td class="weatherIcon" width=%d>%s</td>',
$width,
WeatherIconIMGTag( ReadingsVal( $d, "${fc}${i}_icon", "" ) ) );
} }
$ret .= '</tr>'; $ret .= '</tr>';
# condition # condition
$ret .= sprintf('<tr><td class="weatherDay">%s</td>', ReadingsVal($d, "condition", "")); $ret .= sprintf( '<tr><td class="weatherDay">%s</td>',
ReadingsVal( $d, "condition", "" ) );
for ( my $i = 1 ; $i < $items ; $i++ ) { for ( my $i = 1 ; $i < $items ; $i++ ) {
$ret .= sprintf('<td class="weatherDay">%s: %s</td>', ReadingsVal($d, "${fc}${i}_day_of_week", ""), $ret .= sprintf(
ReadingsVal($d, "${fc}${i}_condition", "")); '<td class="weatherDay">%s: %s</td>',
ReadingsVal( $d, "${fc}${i}_day_of_week", "" ),
ReadingsVal( $d, "${fc}${i}_condition", "" )
);
} }
$ret .= '</tr>'; $ret .= '</tr>';
# temp/hum | min # temp/hum | min
$ret .= sprintf('<tr><td class="weatherMin">%s°C %s%%</td>', ReadingsVal($d, "temp_c", ""), ReadingsVal($d, "humidity", "")); $ret .= sprintf(
'<tr><td class="weatherMin">%s°C %s%%</td>',
ReadingsVal( $d, "temp_c", "" ),
ReadingsVal( $d, "humidity", "" )
);
for ( my $i = 1 ; $i < $items ; $i++ ) { for ( my $i = 1 ; $i < $items ; $i++ ) {
$ret .= sprintf('<td class="weatherMin">min %s°C</td>', ReadingsVal($d, "${fc}${i}_low_c", "")); $ret .= sprintf( '<td class="weatherMin">min %s°C</td>',
ReadingsVal( $d, "${fc}${i}_low_c", " - " ) );
} }
$ret .= '</tr>'; $ret .= '</tr>';
# wind | max # wind | max
$ret .= sprintf('<tr><td class="weatherMax">%s</td>', ReadingsVal($d, "wind_condition", "")); $ret .= sprintf( '<tr><td class="weatherMax">%s</td>',
ReadingsVal( $d, "wind_condition", "" ) );
for ( my $i = 1 ; $i < $items ; $i++ ) { for ( my $i = 1 ; $i < $items ; $i++ ) {
$ret .= sprintf('<td class="weatherMax">max %s°C</td>', ReadingsVal($d, "${fc}${i}_high_c", "")); $ret .= sprintf( '<td class="weatherMax">max %s°C</td>',
ReadingsVal( $d, "${fc}${i}_high_c", " - " ) );
} }
$ret .= "</tr></table>"; $ret .= "</tr></table>";
@ -572,14 +850,14 @@ sub WeatherAsHtmlD($;$) {
if ($FW_ss) { if ($FW_ss) {
WeatherAsHtmlV( $d, $i ); WeatherAsHtmlV( $d, $i );
} else { }
else {
WeatherAsHtmlH( $d, $i ); WeatherAsHtmlH( $d, $i );
} }
} }
##################################### #####################################
1; 1;
=pod =pod
@ -632,7 +910,7 @@ sub WeatherAsHtmlD($;$) {
Examples: Examples:
<pre> <pre>
define Forecast Weather apikey=987498ghjgf864 define Forecast Weather apikey=987498ghjgf864
define MyWeather Weather api=OpenWeatherMapAPI,cachemaxage:600 apikey=09878945fdskv876 location=52.4545,13.4545 interval=3600 lang=de define MyWeather Weather API=OpenWeatherMapAPI,cachemaxage:600 apikey=09878945fdskv876 location=52.4545,13.4545 interval=3600 lang=de
</pre> </pre>
@ -841,9 +1119,11 @@ sub WeatherAsHtmlD($;$) {
Darstellung des Wetterberichtes. Die letztgenannte Funktion w&auml;hlt Darstellung des Wetterberichtes. Die letztgenannte Funktion w&auml;hlt
automatisch eine Ausrichtung, die abh&auml;ngig davon ist, ob ein automatisch eine Ausrichtung, die abh&auml;ngig davon ist, ob ein
Smallcreen Style ausgew&auml;hlt ist (vertikale Darstellung) oder Smallcreen Style ausgew&auml;hlt ist (vertikale Darstellung) oder
nicht (horizontale Darstellung). Alle vier Funnktionen akzeptieren nicht (horizontale Darstellung). Alle vier Funktionen akzeptieren
einen zus&auml;tzlichen optionalen Paramter um die Anzahl der einen zus&auml;tzlichen optionalen Paramter um die Anzahl der
darzustellenden Icons anzugeben.<br><br> darzustellenden Icons anzugeben.<br>
Zus&auml;tzlich erlauben die Funktionen 2 und 3 noch einen dritten Parameter (d oder h) welcher die Forecast-Art (h-Hourly oder d-Daily) mit an gibt.<br>
Wird der dritte Parameter verwendet muss auch der zweite Parameter f&uuml;r die Anzahl der darzustellenden Icons gesetzt werden.<br><br>
Beispiel: Beispiel:
<pre> <pre>
define MyWeatherWeblink weblink htmlCode { WeatherAsHtmlH("MyWeather") } define MyWeatherWeblink weblink htmlCode { WeatherAsHtmlH("MyWeather") }
@ -910,6 +1190,8 @@ sub WeatherAsHtmlD($;$) {
gem&auml;&szlig Plan doch es werden keine Daten vom gem&auml;&szlig Plan doch es werden keine Daten vom
API angefordert.</li> API angefordert.</li>
<li><a href="#readingFnAttributes">readingFnAttributes</a></li> <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
<li>forecast - every/hourly/daily/off, Anzeige von forecast Daten. Alle, nur Stundenforecast, nur Tageforecast, keine.</li>
<li>forecastLimit - Anzahl der Forecast-Datens&auml;tze welche als Reading geschrieben werden sollen.</li>
</ul> </ul>
<br> <br>
</ul> </ul>