mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-03-03 04:36:36 +00:00
59_Weather: included caching in YahooWeatherAPI
git-svn-id: https://svn.fhem.de/fhem/trunk@11249 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
422f12057c
commit
e02d2fc17f
@ -1,5 +1,6 @@
|
||||
# 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.
|
||||
- change: 59_Weather: included caching in YahooWeatherAPI
|
||||
- change: 49_SSCam: behavior of "set ... on" changed, Attr "recextend" added
|
||||
please have a look at commandref and Wiki
|
||||
- bugfix: 49_SSCam: setstate-warning if FHEM is restarted and SVS not
|
||||
|
@ -100,21 +100,6 @@ sub degrees_to_direction($@) {
|
||||
return $directions_txt_i18n[$mod];
|
||||
}
|
||||
|
||||
sub F_to_C($) {
|
||||
my ($F)= @_;
|
||||
return(int(($F-32)*5/9+0.5));
|
||||
}
|
||||
|
||||
sub inHg_to_hPa($) {
|
||||
my ($inHg)= @_;
|
||||
return int($inHg/33.86390+0.5);
|
||||
}
|
||||
|
||||
sub miles_to_km($) {
|
||||
my ($miles)= @_;
|
||||
return int(1.609347219*$miles+0.5);
|
||||
}
|
||||
|
||||
###################################
|
||||
sub Weather_RetrieveData($$) {
|
||||
my ($name, $blocking) = @_;
|
||||
@ -132,9 +117,32 @@ sub Weather_RetrieveData($$) {
|
||||
hash => $hash,
|
||||
);
|
||||
|
||||
YahooWeatherAPI_RetrieveData(\%args);
|
||||
my $maxage= $hash->{fhem}{allowCache} ? 600 : 0; # use cached data if allowed
|
||||
$hash->{fhem}{allowCache}= 1;
|
||||
YahooWeatherAPI_RetrieveDataWithCache($maxage, \%args);
|
||||
}
|
||||
|
||||
|
||||
sub Weather_ReturnWithError($$$$$) {
|
||||
my ($hash, $doTrigger, $err, $pubDate, $pubDateComment)= @_;
|
||||
my $name= $hash->{NAME};
|
||||
|
||||
$hash->{fhem}{allowCache}= 0; # do not use cache on next try
|
||||
|
||||
Log3 $hash, 3, "$name: $err";
|
||||
readingsBeginUpdate($hash);
|
||||
readingsBulkUpdate($hash, "lastError", $err);
|
||||
readingsBulkUpdate($hash, "pubDateComment", $pubDateComment) if(defined($pubDateComment));
|
||||
readingsBulkUpdate($hash, "pubDateRemote", $pubDate) if(defined($pubDate));
|
||||
readingsBulkUpdate($hash, "validity", "stale");
|
||||
readingsEndUpdate($hash, $doTrigger);
|
||||
|
||||
my $next= 60; # $next= $hash->{INTERVAL};
|
||||
Weather_RearmTimer($hash, gettimeofday()+$next);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub Weather_RetrieveDataFinished($$$) {
|
||||
|
||||
my ($argsRef, $err, $response)= @_;
|
||||
@ -143,76 +151,23 @@ sub Weather_RetrieveDataFinished($$$) {
|
||||
my $name= $hash->{NAME};
|
||||
my $doTrigger= $argsRef->{blocking} ? 0 : 1;
|
||||
|
||||
|
||||
# the next 4 stanzas need to be rewritten, they are too repetitive for my taste
|
||||
|
||||
# check for error from retrieving data
|
||||
if($err) {
|
||||
Log3 $hash, 3, "$name: $err";
|
||||
readingsBeginUpdate($hash);
|
||||
readingsBulkUpdate($hash, "lastError", $err);
|
||||
readingsBulkUpdate($hash, "validity", "stale");
|
||||
readingsEndUpdate($hash, $doTrigger);
|
||||
Weather_RearmTimer($hash, gettimeofday()+$hash->{INTERVAL});
|
||||
return;
|
||||
}
|
||||
return Weather_ReturnWithError($hash, $doTrigger, $err, undef, undef) if($err);
|
||||
|
||||
# decode JSON data from Weather Channel
|
||||
my $data;
|
||||
($err, $data)= YahooWeatherAPI_JSONReturnChannelData($response);
|
||||
if($err) {
|
||||
Log3 $hash, 3, "$name: $err";
|
||||
readingsBeginUpdate($hash);
|
||||
readingsBulkUpdate($hash, "lastError", $err);
|
||||
readingsBulkUpdate($hash, "validity", "stale");
|
||||
readingsEndUpdate($hash, $doTrigger);
|
||||
Weather_RearmTimer($hash, gettimeofday()+$hash->{INTERVAL});
|
||||
return;
|
||||
}
|
||||
return Weather_ReturnWithError($hash, $doTrigger, $err, undef, undef) if($err);
|
||||
|
||||
# check if up-to-date
|
||||
my ($pubDateComment, $pubDate, $pubDateTs)= YahooWeatherAPI_pubDate($data);
|
||||
if(!defined($pubDateTs)) {
|
||||
Log3 $hash, 3, "$name: $pubDateComment";
|
||||
readingsBeginUpdate($hash);
|
||||
readingsBulkUpdate($hash, "lastError", $pubDateComment);
|
||||
readingsBulkUpdate($hash, "pubDateComment", $pubDateComment);
|
||||
readingsBulkUpdate($hash, "pubDateRemote", $pubDate);
|
||||
readingsBulkUpdate($hash, "validity", "stale");
|
||||
readingsEndUpdate($hash, $doTrigger);
|
||||
Weather_RearmTimer($hash, gettimeofday()+$hash->{INTERVAL});
|
||||
return;
|
||||
} else {
|
||||
my $ts= defined($hash->{READINGS}{pubDateTs}) ? $hash->{READINGS}{pubDateTs}{VAL} : 0;
|
||||
if($ts> $pubDateTs) {
|
||||
$err= "stale data received";
|
||||
Log3 $hash, 3, "$name: $err";
|
||||
readingsBeginUpdate($hash);
|
||||
readingsBulkUpdate($hash, "lastError", $err);
|
||||
readingsBulkUpdate($hash, "pubDateComment", $pubDateComment);
|
||||
readingsBulkUpdate($hash, "pubDateRemote", $pubDate);
|
||||
readingsBulkUpdate($hash, "validity", "stale");
|
||||
readingsEndUpdate($hash, $doTrigger);
|
||||
Weather_RearmTimer($hash, gettimeofday()+$hash->{INTERVAL});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
# units
|
||||
my $units= YahooWeatherAPI_units($data); # units hash reference
|
||||
if($units->{temperature} ne "C") {
|
||||
$err= "wrong units received";
|
||||
Log3 $hash, 3, "$name: $err";
|
||||
readingsBeginUpdate($hash);
|
||||
readingsBulkUpdate($hash, "lastError", $err);
|
||||
readingsBulkUpdate($hash, "pubDateComment", $pubDateComment);
|
||||
readingsBulkUpdate($hash, "pubDateRemote", $pubDate);
|
||||
readingsBulkUpdate($hash, "validity", "stale");
|
||||
readingsEndUpdate($hash, $doTrigger);
|
||||
Weather_RearmTimer($hash, gettimeofday()+$hash->{INTERVAL});
|
||||
return;
|
||||
}
|
||||
|
||||
return Weather_ReturnWithError($hash, $doTrigger, $pubDateComment, $pubDate, $pubDateComment)
|
||||
unless(defined($pubDateTs));
|
||||
my $ts= defined($hash->{READINGS}{pubDateTs}) ? $hash->{READINGS}{pubDateTs}{VAL} : 0;
|
||||
return Weather_ReturnWithError($hash, $doTrigger, "stale data received", $pubDate, $pubDateComment)
|
||||
if($ts> $pubDateTs);
|
||||
|
||||
|
||||
#
|
||||
# from here on we assume that $data is complete and correct
|
||||
#
|
||||
@ -249,21 +204,27 @@ sub Weather_RetrieveDataFinished($$$) {
|
||||
|
||||
readingsBeginUpdate($hash);
|
||||
|
||||
# delete some unused readings
|
||||
delete($hash->{READINGS}{temp_f}) if(defined($hash->{READINGS}{temp_f}));
|
||||
delete($hash->{READINGS}{unit_distance}) if(defined($hash->{READINGS}{unit_distance}));
|
||||
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}));
|
||||
|
||||
|
||||
|
||||
# convert to metric units as far as required
|
||||
my $isConverted= YahooWeatherAPI_ConvertChannelData($data);
|
||||
|
||||
# housekeeping information
|
||||
readingsBulkUpdate($hash, "lastError", "");
|
||||
readingsBulkUpdate($hash, "pubDateComment", $pubDateComment);
|
||||
readingsBulkUpdate($hash, "pubDate", $pubDate);
|
||||
readingsBulkUpdate($hash, "pubDateRemote", $pubDate);
|
||||
readingsBulkUpdate($hash, "pubDateTs", $pubDateTs);
|
||||
readingsBulkUpdate($hash, "isConverted", $isConverted);
|
||||
readingsBulkUpdate($hash, "validity", "up-to-date");
|
||||
|
||||
# units
|
||||
readingsBulkUpdate($hash, "unit_distance", $units->{distance});
|
||||
readingsBulkUpdate($hash, "unit_speed", $units->{speed});
|
||||
readingsBulkUpdate($hash, "unit_pressuree", $units->{pressure});
|
||||
readingsBulkUpdate($hash, "unit_temperature", $units->{temperature});
|
||||
|
||||
|
||||
# description
|
||||
readingsBulkUpdate($hash, "description", $data->{description});
|
||||
|
||||
@ -278,22 +239,16 @@ sub Weather_RetrieveDataFinished($$$) {
|
||||
my $windspeed= int($data->{wind}{speed}+0.5);
|
||||
readingsBulkUpdate($hash, "wind", $windspeed);
|
||||
readingsBulkUpdate($hash, "wind_speed", $windspeed);
|
||||
# wind_chill comes in °F
|
||||
readingsBulkUpdate($hash, "wind_chill", F_to_C($data->{wind}{chill}));
|
||||
readingsBulkUpdate($hash, "wind_chill", $data->{wind}{chill});
|
||||
my $winddir= $data->{wind}{direction};
|
||||
readingsBulkUpdate($hash, "wind_direction", $winddir);
|
||||
my $wdir= degrees_to_direction($winddir, @directions_txt_i18n);
|
||||
readingsBulkUpdate($hash, "wind_condition", "Wind: $wdir $windspeed km/h");
|
||||
|
||||
|
||||
# delete the temp_f reading
|
||||
delete($hash->{READINGS}{temp_f}) if(defined($hash->{READINGS}{temp_f}));
|
||||
|
||||
# atmosphere
|
||||
my $humidity= $data->{atmosphere}{humidity};
|
||||
readingsBulkUpdate($hash, "humidity", $humidity);
|
||||
# pressure is in inHg
|
||||
my $pressure= inHg_to_hPa($data->{atmosphere}{pressure});
|
||||
my $pressure= $data->{atmosphere}{pressure};
|
||||
readingsBulkUpdate($hash, "pressure", $pressure);
|
||||
readingsBulkUpdate($hash, "visibility", int($data->{atmosphere}{visibility}+0.5));
|
||||
my $pressure_trend= $data->{atmosphere}{rising};
|
||||
@ -421,8 +376,7 @@ sub Weather_Notify($$) {
|
||||
Weather_DisarmTimer($hash);
|
||||
my $delay= 10+int(rand(20));
|
||||
|
||||
# delay removed until further notice
|
||||
$delay= 3;
|
||||
#$delay= 3; # delay removed until further notice
|
||||
|
||||
Log3 $hash, 5, "Weather $name: FHEM initialization or rereadcfg triggered update, delay $delay seconds.";
|
||||
Weather_RearmTimer($hash, gettimeofday()+$delay) ;
|
||||
@ -461,6 +415,8 @@ sub Weather_Define($$) {
|
||||
$hash->{READINGS}{current_date_time}{TIME}= TimeNow();
|
||||
$hash->{READINGS}{current_date_time}{VAL}= "none";
|
||||
|
||||
$hash->{fhem}{allowCache}= 1;
|
||||
|
||||
Weather_GetUpdate($hash) if($init_done);
|
||||
|
||||
return undef;
|
||||
|
@ -131,7 +131,30 @@ my @YahooCodes_pl = (
|
||||
'gorąco', 'gdzieniegdzie burze', 'burze', 'burze', 'przelotne opady śniegu', 'duże opady śniegu',
|
||||
'ciężkie opady śniegu', 'dużo śniegu', 'częściowe zachmurzenie', 'burze z deszczem', 'opady śniegu', 'przejściowo burze');
|
||||
|
||||
###################################
|
||||
|
||||
# Cache
|
||||
my %YahooWeatherAPI_CachedData= ();
|
||||
my %YahooWeatherAPI_CachedDataTs= ();
|
||||
|
||||
###################################
|
||||
|
||||
sub F_to_C($) {
|
||||
my ($F)= @_;
|
||||
return(int(($F-32)*5/9+0.5));
|
||||
}
|
||||
|
||||
sub inHg_to_hPa($) {
|
||||
my ($inHg)= @_;
|
||||
return int($inHg/33.86390+0.5);
|
||||
}
|
||||
|
||||
sub miles_to_km($) {
|
||||
my ($miles)= @_;
|
||||
return int(1.609347219*$miles+0.5);
|
||||
}
|
||||
|
||||
###################################
|
||||
|
||||
# call: YahooWeatherAPI_RetrieveData(%%args)
|
||||
#
|
||||
@ -144,9 +167,33 @@ my @YahooCodes_pl = (
|
||||
#
|
||||
|
||||
sub YahooWeatherAPI_RetrieveData($) {
|
||||
|
||||
my ($argsRef)= @_;
|
||||
YahooWeatherAPI_RetrieveDataWithCache(0, $argsRef);
|
||||
}
|
||||
|
||||
sub YahooWeatherAPI_RetrieveDataWithCache($$) {
|
||||
|
||||
my ($maxage, $argsRef)= @_;
|
||||
my $woeid= $argsRef->{woeid};
|
||||
|
||||
Log3 undef, 5, "YahooWeatherAPI: retrieve weather for $woeid.";
|
||||
|
||||
# retrieve data from cache
|
||||
my $ts= $YahooWeatherAPI_CachedDataTs{$woeid};
|
||||
if(defined($ts)) {
|
||||
my $now= time();
|
||||
my $age= $now- $ts;
|
||||
if($age< $maxage) {
|
||||
Log3 undef, 5, "YahooWeatherAPI: data is cached, age $age seconds < $maxage seconds.";
|
||||
$argsRef->{callbackFnRef}($argsRef, "", $YahooWeatherAPI_CachedData{$woeid});
|
||||
return;
|
||||
} else {
|
||||
Log3 undef, 5, "YahooWeatherAPI: cache is expired, age $age seconds > $maxage seconds.";
|
||||
}
|
||||
} else {
|
||||
Log3 undef, 5, "YahooWeatherAPI: no data in cache.";
|
||||
}
|
||||
|
||||
my $format= $argsRef->{format};
|
||||
my $blocking= $argsRef->{blocking};
|
||||
my $callbackFnRef= $argsRef->{callbackFnRef};
|
||||
@ -157,14 +204,14 @@ sub YahooWeatherAPI_RetrieveData($) {
|
||||
|
||||
if ($blocking) {
|
||||
# do not use noshutdown => 0 in parameters
|
||||
my $response = HttpUtils_BlockingGet({ url => $url, timeout => 5 });
|
||||
my $response = HttpUtils_BlockingGet({ url => $url, timeout => 15 });
|
||||
my %param= (argsRef => $argsRef);
|
||||
YahooWeatherAPI_RetrieveDataFinished(\%param, undef, $response);
|
||||
} else {
|
||||
# do not use noshutdown => 0 in parameters
|
||||
HttpUtils_NonblockingGet({
|
||||
url => $url,
|
||||
timeout => 5,
|
||||
timeout => 15,
|
||||
argsRef => $argsRef,
|
||||
callback => \&YahooWeatherAPI_RetrieveDataFinished,
|
||||
});
|
||||
@ -172,10 +219,16 @@ sub YahooWeatherAPI_RetrieveData($) {
|
||||
}
|
||||
|
||||
sub YahooWeatherAPI_RetrieveDataFinished($$$) {
|
||||
my ($paramRef, $err, $xml) = @_;
|
||||
my ($paramRef, $err, $response) = @_;
|
||||
my $argsRef= $paramRef->{argsRef};
|
||||
#Debug "Finished retrieving Yahoo Weather data for " . $argsRef->{hash}->{NAME};
|
||||
$argsRef->{callbackFnRef}($argsRef, $err, $xml);
|
||||
if(!$err) {
|
||||
my $woeid= $argsRef->{woeid};
|
||||
$YahooWeatherAPI_CachedDataTs{$woeid}= time();
|
||||
$YahooWeatherAPI_CachedData{$woeid}= $response;
|
||||
Log3 undef, 5, "YahooWeatherAPI: caching data.";
|
||||
}
|
||||
$argsRef->{callbackFnRef}($argsRef, $err, $response);
|
||||
}
|
||||
|
||||
|
||||
@ -184,6 +237,7 @@ sub YahooWeatherAPI_JSONReturnChannelData($) {
|
||||
my ($response)= @_;
|
||||
return("empty response", undef) unless($response);
|
||||
#Debug "Decoding response: $response";
|
||||
#Debug "response: " . Dumper($response);
|
||||
my $data;
|
||||
eval { $data= decode_json($response) };
|
||||
return($@, undef) if($@);
|
||||
@ -193,10 +247,34 @@ sub YahooWeatherAPI_JSONReturnChannelData($) {
|
||||
#Debug "$count result(s).";
|
||||
return("$count result(s) retrieved", undef) unless($count == 1);
|
||||
my $channel= $query->{results}{channel};
|
||||
#Debug "Result: " . Dumper($channel);
|
||||
return(undef, $channel);
|
||||
}
|
||||
|
||||
sub YahooWeatherAPI_ConvertChannelData($) {
|
||||
my ($data)= @_; # hash reference
|
||||
|
||||
$data->{wind}{chill}= F_to_C($data->{wind}{chill}); # wrongly always °F
|
||||
$data->{atmosphere}{pressure}= inHg_to_hPa($data->{atmosphere}{pressure}); # wrongly always in inHg
|
||||
|
||||
|
||||
my $units= YahooWeatherAPI_units($data); # units hash reference
|
||||
return 0 if($units->{temperature} eq "C");
|
||||
|
||||
$data->{wind}{speed}= miles_to_km($data->{wind}{speed});
|
||||
$data->{atmosphere}{visibility}= miles_to_km($data->{atmosphere}{visibility});
|
||||
|
||||
my $item= $data->{item};
|
||||
$item->{condition}{temp}= F_to_C($item->{condition}{temp});
|
||||
|
||||
my $forecast= $item->{forecast};
|
||||
foreach my $fc (@{$forecast}) {
|
||||
$fc->{low}= F_to_C($fc->{low});
|
||||
$fc->{high}= F_to_C($fc->{high});
|
||||
}
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
sub YahooWeatherAPI_ParseDateTime($) {
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user