mod-Weather/DarkSkyAPI.pm

852 lines
56 KiB
Perl
Raw Normal View History

2019-01-12 14:02:53 +00:00
# $Id: $
2019-01-09 09:37:55 +00:00
###############################################################################
#
# Developed with Kate
#
# (c) 2019 Copyright: Marko Oldenburg (leongaultier at gmail dot com)
# All rights reserved
#
# Special thanks goes to:
# - Lippie hourly forecast code
2019-01-09 09:37:55 +00:00
#
#
# This script is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License,or
# any later version.
#
# The GNU General Public License can be found at
# http://www.gnu.org/copyleft/gpl.html.
# A copy is found in the textfile GPL.txt and important notices to the license
# from the author is found in LICENSE.txt distributed with these scripts.
#
# This script is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#
###############################################################################
2019-09-11 06:20:28 +00:00
package wundergroundAPI;
use strict;
use warnings;
use FHEM::Meta;
use Data::Dumper;
FHEM::Meta::Load(__PACKAGE__);
use version 0.50; our $VERSION = $main::packages{wundergroundAPI}{META}{version};
2019-03-15 20:41:32 +00:00
package DarkSkyAPI::Weather;
2019-01-09 09:37:55 +00:00
use strict;
use warnings;
use POSIX;
use HttpUtils;
# try to use JSON::MaybeXS wrapper
# for chance of better performance + open code
eval {
require JSON::MaybeXS;
import JSON::MaybeXS qw( decode_json encode_json );
1;
};
if ($@) {
$@ = undef;
# try to use JSON wrapper
# for chance of better performance
eval {
# JSON preference order
local $ENV{PERL_JSON_BACKEND} =
'Cpanel::JSON::XS,JSON::XS,JSON::PP,JSON::backportPP'
unless ( defined( $ENV{PERL_JSON_BACKEND} ) );
require JSON;
import JSON qw( decode_json encode_json );
1;
};
if ($@) {
$@ = undef;
# In rare cases, Cpanel::JSON::XS may
# be installed but JSON|JSON::MaybeXS not ...
eval {
require Cpanel::JSON::XS;
import Cpanel::JSON::XS qw(decode_json encode_json);
1;
};
if ($@) {
$@ = undef;
# In rare cases, JSON::XS may
# be installed but JSON not ...
eval {
require JSON::XS;
import JSON::XS qw(decode_json encode_json);
1;
};
if ($@) {
$@ = undef;
# Fallback to built-in JSON which SHOULD
# be available since 5.014 ...
eval {
require JSON::PP;
import JSON::PP qw(decode_json encode_json);
1;
};
if ($@) {
$@ = undef;
# Fallback to JSON::backportPP in really rare cases
require JSON::backportPP;
import JSON::backportPP qw(decode_json encode_json);
1;
}
}
}
}
}
2019-01-09 09:37:55 +00:00
my $missingModul = '';
eval "use Encode qw(encode_utf8);1" or $missingModul .= "Encode ";
# use Data::Dumper; # for Debug only
## API URL
use constant DEMODATA =>
'{"latitude":50.112,"longitude":8.686,"timezone":"Europe/Berlin","currently":{"time":1551214558,"summary":"Heiter","icon":"clear-night","precipIntensity":0,"precipProbability":0,"temperature":9.65,"apparentTemperature":9.65,"dewPoint":1.39,"humidity":0.56,"pressure":1032.69,"windSpeed":0.41,"windGust":1.35,"windBearing":84,"cloudCover":0,"uvIndex":0,"visibility":10.01,"ozone":276.41},"hourly":{"summary":"Leicht bewölkt am heute Nacht.","icon":"partly-cloudy-night","data":[{"time":1551211200,"summary":"Heiter","icon":"clear-night","precipIntensity":0,"precipProbability":0,"temperature":10.59,"apparentTemperature":10.59,"dewPoint":1.84,"humidity":0.55,"pressure":1032.7,"windSpeed":0.28,"windGust":1.15,"windBearing":89,"cloudCover":0,"uvIndex":0,"visibility":10.01,"ozone":277},{"time":1551214800,"summary":"Heiter","icon":"clear-night","precipIntensity":0,"precipProbability":0,"temperature":9.58,"apparentTemperature":9.58,"dewPoint":1.36,"humidity":0.56,"pressure":1032.69,"windSpeed":0.42,"windGust":1.37,"windBearing":83,"cloudCover":0,"uvIndex":0,"visibility":10.01,"ozone":276.37},{"time":1551218400,"summary":"Heiter","icon":"clear-night","precipIntensity":0,"precipProbability":0,"temperature":8.61,"apparentTemperature":8.61,"dewPoint":0.73,"humidity":0.58,"pressure":1032.63,"windSpeed":0.5,"windGust":1.47,"windBearing":72,"cloudCover":0,"uvIndex":0,"visibility":11.47,"ozone":275.56},{"time":1551222000,"summary":"Leicht bewölkt","icon":"partly-cloudy-night","precipIntensity":0,"precipProbability":0,"temperature":8.06,"apparentTemperature":8.06,"dewPoint":-0.45,"humidity":0.55,"pressure":1032.55,"windSpeed":0.86,"windGust":1.5,"windBearing":40,"cloudCover":0.26,"uvIndex":0,"visibility":16.09,"ozone":274.76},{"time":1551225600,"summary":"Leicht bewölkt","icon":"partly-cloudy-night","precipIntensity":0,"precipProbability":0,"temperature":7.48,"apparentTemperature":7.48,"dewPoint":-1.38,"humidity":0.53,"pressure":1032.4,"windSpeed":1.14,"windGust":1.49,"windBearing":33,"cloudCover":0.42,"uvIndex":0,"visibility":16.09,"ozone":274.13},{"time":1551229200,"summary":"Leicht bewölkt","icon":"partly-cloudy-night","precipIntensity":0,"precipProbability":0,"temperature":6.62,"apparentTemperature":6.62,"dewPoint":-1.89,"humidity":0.54,"pressure":1032.12,"windSpeed":1.11,"windGust":1.43,"windBearing":38,"cloudCover":0.36,"uvIndex":0,"visibility":16.09,"ozone":273.77},{"time":1551232800,"summary":"Leicht bewölkt","icon":"partly-cloudy-night","precipIntensity":0,"precipProbability":0,"temperature":5.73,"apparentTemperature":5.73,"dewPoint":-2.39,"humidity":0.56,"pressure":1031.83,"windSpeed":1.07,"windGust":1.34,"windBearing":46,"cloudCover":0.29,"uvIndex":0,"visibility":16.09,"ozone":273.55},{"time":1551236400,"summary":"Heiter","icon":"clear-night","precipIntensity":0,"precipProbability":0,"temperature":4.91,"apparentTemperature":4.91,"dewPoint":-2.81,"humidity":0.57,"pressure":1031.49,"windSpeed":1.03,"windGust":1.23,"windBearing":54,"cloudCover":0.23,"uvIndex":0,"visibility":16.09,"ozone":273.44},{"time":1551240000,"summary":"Heiter","icon":"clear-night","precipIntensity":0,"precipProbability":0,"temperature":4.02,"apparentTemperature":4.02,"dewPoint":-3.26,"humidity":0.59,"pressure":1031.18,"windSpeed":0.99,"windGust":1.15,"windBearing":63,"cloudCover":0.21,"uvIndex":0,"visibility":16.09,"ozone":273.43},{"time":1551243600,"summary":"Heiter","icon":"clear-night","precipIntensity":0,"precipProbability":0,"temperature":3.26,"apparentTemperature":3.26,"dewPoint":-3.61,"humidity":0.61,"pressure":1030.85,"windSpeed":0.96,"windGust":1.08,"windBearing":73,"cloudCover":0.22,"uvIndex":0,"visibility":16.09,"ozone":273.5},{"time":1551247200,"summary":"Heiter","icon":"clear-night","precipIntensity":0,"precipProbability":0,"temperature":3.19,"apparentTemperature":3.19,"dewPoint":-3.51,"humidity":0.61,"pressure":1030.54,"windSpeed":0.92,"windGust":1.01,"windBearing":83,"cloudCover":0.22,"uvIndex":0,"visibility":16.09,"ozone":273.65},{"time":1551250800,"summary":"Heiter","icon":"clear-day","precipIntensity":0,"precipProbability":0,"temperature":
2019-02-27 06:53:29 +00:00
use constant URL => 'https://api.darksky.net/forecast/';
2019-01-09 09:37:55 +00:00
my %codes = (
'clear-day' => 32,
'clear-night' => 31,
'rain' => 11,
'snow' => 16,
'sleet' => 18,
'wind' => 24,
'fog' => 20,
'cloudy' => 26,
'partly-cloudy-day' => 30,
'partly-cloudy-night' => 29,
'hail' => 17,
'thunderstorm' => 4,
'tornado' => 0,
);
sub new {
### geliefert wird ein Hash
my ( $class, $argsRef ) = @_;
my $apioptions = parseApiOptions( $argsRef->{apioptions} );
2019-01-09 09:37:55 +00:00
my $self = {
devName => $argsRef->{devName},
2019-01-10 21:35:57 +00:00
key => (
( defined( $argsRef->{apikey} ) and $argsRef->{apikey} )
? $argsRef->{apikey}
: 'none'
),
lang => $argsRef->{language},
lat => ( split( ',', $argsRef->{location} ) )[0],
long => ( split( ',', $argsRef->{location} ) )[1],
fetchTime => 0,
2019-01-09 09:37:55 +00:00
};
$self->{cachemaxage} = (
defined( $apioptions->{cachemaxage} )
? $apioptions->{cachemaxage}
: 900 );
$self->{extend} =
( defined( $apioptions->{extend} ) ? $apioptions->{extend} : 'none' );
$self->{cached} = _CreateForecastRef($self);
2019-01-09 09:37:55 +00:00
bless $self, $class;
2019-01-09 09:37:55 +00:00
return $self;
}
sub parseApiOptions($) {
my $apioptions = shift;
my @params;
my %h;
@params = split( ',', $apioptions );
while (@params) {
my $param = shift(@params);
next if ( $param eq '' );
my ( $key, $value ) = split( ':', $param, 2 );
$h{$key} = $value;
}
return \%h;
}
2019-01-09 09:37:55 +00:00
sub setFetchTime {
my $self = shift;
$self->{fetchTime} = time();
return 0;
}
sub setRetrieveData {
my $self = shift;
_RetrieveDataFromDarkSky($self);
return 0;
}
sub setLocation {
my ($self,$lat,$long) = @_;
$self->{lat} = $lat;
$self->{long} = $long;
return 0;
}
2019-01-09 09:37:55 +00:00
sub getFetchTime {
my $self = shift;
return $self->{fetchTime};
}
sub getWeather {
my $self = shift;
return $self->{cached};
}
sub _RetrieveDataFromDarkSky($) {
my $self = shift;
# retrieve data from cache
if ( ( time() - $self->{fetchTime} ) < $self->{cachemaxage}
and $self->{cached}->{lat} == $self->{lat}
and $self->{cached}->{long} == $self->{long}
)
{
2019-01-09 09:37:55 +00:00
return _CallWeatherCallbackFn($self);
}
$self->{cached}->{lat} = $self->{lat}
unless ( $self->{cached}->{lat} == $self->{lat} );
$self->{cached}->{long} = $self->{long}
unless ( $self->{cached}->{long} == $self->{long} );
2019-01-09 09:37:55 +00:00
my $paramRef = {
timeout => 15,
self => $self,
callback => \&_RetrieveDataFinished,
};
if ( $self->{lat} eq 'error'
or $self->{long} eq 'error'
or $self->{key} eq 'none'
or $missingModul )
{
_RetrieveDataFinished(
$paramRef,
'The given location is invalid. (wrong latitude or longitude?) put both as an attribute in the global device or set define option location=[LAT],[LONG]',
undef
) if ( $self->{lat} eq 'error' or $self->{long} eq 'error' );
2019-01-09 09:37:55 +00:00
_RetrieveDataFinished( $paramRef,
'No given api key. (define myWeather Weather apikey=[KEY])',
2019-01-09 09:37:55 +00:00
undef )
if ( $self->{key} eq 'none' );
_RetrieveDataFinished( $paramRef,
'Perl modul ' . $missingModul . ' is missing.', undef )
if ($missingModul);
}
else {
my $options = '&units=auto';
$options .= '&extend=' . $self->{extend}
if ( $self->{extend} ne 'none' );
2019-01-09 09:37:55 +00:00
$paramRef->{url} =
URL
. $self->{key} . '/'
. $self->{lat} . ','
. $self->{long}
. '?lang='
. $self->{lang}
. $options;
2019-01-09 09:37:55 +00:00
if ( lc( $self->{key} ) eq 'demo' ) {
_RetrieveDataFinished( $paramRef, undef, DEMODATA );
}
2019-02-27 06:53:29 +00:00
else { main::HttpUtils_NonblockingGet($paramRef); }
2019-01-09 09:37:55 +00:00
}
}
sub _RetrieveDataFinished($$$) {
my ( $paramRef, $err, $response ) = @_;
my $self = $paramRef->{self};
if ( !$err ) {
$self->{cached}->{status} = 'ok';
$self->{cached}->{validity} = 'up-to-date', $self->{fetchTime} = time();
2019-01-09 09:37:55 +00:00
_ProcessingRetrieveData( $self, $response );
}
else {
$self->{fetchTime} = time() if ( not defined( $self->{fetchTime} ) );
_ErrorHandling( $self, $err );
_ProcessingRetrieveData( $self, $response );
}
}
sub _ProcessingRetrieveData($$) {
my ( $self, $response ) = @_;
2019-01-10 21:35:57 +00:00
if ( $self->{cached}->{status} eq 'ok'
and defined($response)
and $response )
{
if ( $response =~ m/^{.*}$/ ) {
my $data = eval { decode_json($response) };
2019-01-09 09:37:55 +00:00
if ($@) {
_ErrorHandling( $self,
'DarkSky Weather decode JSON err ' . $@ );
}
elsif ( defined( $data->{code} )
and $data->{code}
and defined( $data->{error} )
and $data->{error} )
{
_ErrorHandling( $self,
'Code: ' . $data->{code} . ' Error: ' . $data->{error} );
}
else {
# print Dumper $data; ## für Debugging
$self->{cached}->{current_date_time} =
strftimeWrapper( "%a, %e %b %Y %H:%M",
2019-03-14 13:34:59 +00:00
localtime( $self->{fetchTime} ) );
$self->{cached}->{timezone} = $data->{timezone};
$self->{cached}->{license}{text} =
$data->{flags}->{'meteoalarm-license'};
$self->{cached}->{current} = {
'temperature' => int(
sprintf( "%.1f", $data->{currently}->{temperature} ) +
0.5
),
'temp_c' => int(
sprintf( "%.1f", $data->{currently}->{temperature} ) +
0.5
),
'dewPoint' => int(
sprintf( "%.1f", $data->{currently}->{dewPoint} ) + 0.5
),
'humidity' => $data->{currently}->{humidity} * 100,
'condition' => encode_utf8( $data->{currently}->{summary} ),
'pressure' => int(
sprintf( "%.1f", $data->{currently}->{pressure} ) + 0.5
),
'wind' => int(
sprintf( "%.1f",
( $data->{currently}->{windSpeed} * 3.6 ) ) + 0.5
),
'wind_speed' => int(
sprintf( "%.1f",
( $data->{currently}->{windSpeed} * 3.6 ) ) + 0.5
),
'wind_direction' => $data->{currently}->{windBearing},
'windGust' => int(
sprintf( "%.1f",
( $data->{currently}->{windGust} * 3.6 ) ) + 0.5
),
'cloudCover' => $data->{currently}->{cloudCover} * 100,
'uvIndex' => $data->{currently}->{uvIndex},
'visibility' => int(
sprintf( "%.1f", $data->{currently}->{visibility} ) +
0.5
),
'ozone' => $data->{currently}->{ozone},
'code' => $codes{ $data->{currently}->{icon} },
'iconAPI' => $data->{currently}->{icon},
2019-03-14 13:34:59 +00:00
'pubDate' => strftimeWrapper(
2019-01-14 17:16:39 +00:00
"%a, %e %b %Y %H:%M",
localtime( $data->{currently}->{'time'} )
2019-03-14 13:34:59 +00:00
),
'precipProbability' =>
$data->{currently}->{precipProbability} * 100,
'apparentTemperature' => int(
sprintf( "%.1f",
$data->{currently}->{apparentTemperature} ) + 0.5
),
'precipIntensity' => $data->{currently}->{precipIntensity},
};
if ( ref( $data->{daily}->{data} ) eq "ARRAY"
and scalar( @{ $data->{daily}->{data} } ) > 0 )
{
### löschen des alten Datensatzes
delete $self->{cached}->{forecast};
my $i = 0;
foreach ( @{ $data->{daily}->{data} } ) {
push(
@{ $self->{cached}->{forecast}->{daily} },
{
2019-03-14 13:34:59 +00:00
'pubDate' => strftimeWrapper(
2019-01-14 17:16:39 +00:00
"%a, %e %b %Y %H:%M",
localtime(
$data->{daily}->{data}->[$i]->{'time'}
)
2019-03-14 13:34:59 +00:00
),
'day_of_week' => strftime(
"%a",
localtime(
$data->{daily}->{data}->[$i]->{'time'}
)
),
'low_c' => int(
sprintf( "%.1f",
$data->{daily}->{data}->[$i]
->{temperatureLow} ) + 0.5
),
'high_c' => int(
sprintf( "%.1f",
$data->{daily}->{data}->[$i]
->{temperatureHigh} ) + 0.5
),
'tempLow' => int(
sprintf( "%.1f",
$data->{daily}->{data}->[$i]
->{temperatureLow} ) + 0.5
),
2019-03-14 13:34:59 +00:00
'tempLowTime' => strftimeWrapper(
2019-01-14 17:16:39 +00:00
"%a, %e %b %Y %H:%M",
localtime(
$data->{daily}->{data}->[$i]
->{temperatureLowTime}
)
2019-03-14 13:34:59 +00:00
),
'tempHigh' => int(
sprintf( "%.1f",
$data->{daily}->{data}->[$i]
->{temperatureHigh} ) + 0.5
),
2019-03-14 13:34:59 +00:00
'tempHighTime' => strftimeWrapper(
2019-01-14 17:16:39 +00:00
"%a, %e %b %Y %H:%M",
localtime(
$data->{daily}->{data}->[$i]
->{temperatureHighTime}
)
2019-03-14 13:34:59 +00:00
),
'apparentTempLow' => int(
sprintf( "%.1f",
$data->{daily}->{data}->[$i]
->{apparentTemperatureLow} ) + 0.5
),
2019-03-14 13:34:59 +00:00
'apparentTempLowTime' => strftimeWrapper(
2019-01-14 17:16:39 +00:00
"%a, %e %b %Y %H:%M",
localtime(
$data->{daily}->{data}->[$i]
->{apparentTemperatureLowTime}
)
2019-03-14 13:34:59 +00:00
),
'apparentTempHigh' => int(
sprintf( "%.1f",
$data->{daily}->{data}->[$i]
->{apparentTemperatureHigh} ) + 0.5
),
2019-03-14 13:34:59 +00:00
'apparentTempHighTime' => strftimeWrapper(
2019-01-14 17:16:39 +00:00
"%a, %e %b %Y %H:%M",
localtime(
$data->{daily}->{data}->[$i]
->{apparentTemperatureHighTime}
)
2019-03-14 13:34:59 +00:00
),
'code' =>
$codes{ $data->{daily}->{data}->[$i]->{icon}
},
'iconAPI' =>
$data->{daily}->{data}->[$i]->{icon},
'condition' => encode_utf8(
$data->{daily}->{data}->[$i]->{summary}
),
'ozone' =>
$data->{daily}->{data}->[$i]->{ozone},
'uvIndex' =>
$data->{daily}->{data}->[$i]->{uvIndex},
2019-03-14 13:34:59 +00:00
'uvIndexTime' => strftimeWrapper(
2019-01-14 17:16:39 +00:00
"%a, %e %b %Y %H:%M",
localtime(
$data->{daily}->{data}->[$i]
->{uvIndexTime}
)
2019-03-14 13:34:59 +00:00
),
'dewPoint' => int(
sprintf( "%.1f",
$data->{daily}->{data}->[$i]->{dewPoint}
) + 0.5
),
'humidity' =>
$data->{daily}->{data}->[$i]->{humidity} *
100,
'cloudCover' =>
$data->{daily}->{data}->[$i]->{cloudCover} *
100,
'wind_direction' =>
$data->{daily}->{data}->[$i]->{windBearing},
'wind' => int(
sprintf(
"%.1f",
(
$data->{daily}->{data}->[$i]
->{windSpeed} * 3.6
)
) + 0.5
),
'wind_speed' => int(
sprintf(
"%.1f",
(
$data->{daily}->{data}->[$i]
->{windSpeed} * 3.6
)
) + 0.5
),
'windGust' => int(
sprintf(
"%.1f",
(
$data->{daily}->{data}->[$i]
->{windGust} * 3.6
)
) + 0.5
),
2019-03-14 13:34:59 +00:00
'windGustTime' => strftimeWrapper(
2019-01-14 17:16:39 +00:00
"%a, %e %b %Y %H:%M",
localtime(
$data->{daily}->{data}->[$i]
->{windGustTime}
)
2019-03-14 13:34:59 +00:00
),
'moonPhase' =>
$data->{daily}->{data}->[$i]->{moonPhase},
2019-03-14 13:34:59 +00:00
'sunsetTime' => strftimeWrapper(
2019-01-14 17:16:39 +00:00
"%a, %e %b %Y %H:%M",
localtime(
$data->{daily}->{data}->[$i]
->{sunsetTime}
)
2019-03-14 13:34:59 +00:00
),
'sunriseTime' => strftimeWrapper(
2019-01-14 17:16:39 +00:00
"%a, %e %b %Y %H:%M",
localtime(
$data->{daily}->{data}->[$i]
->{sunriseTime}
)
2019-03-14 13:34:59 +00:00
),
'pressure' => int(
sprintf( "%.1f",
$data->{daily}->{data}->[$i]->{pressure}
) + 0.5
),
'visibility' => int(
sprintf( "%.1f",
$data->{daily}->{data}->[$i]
->{visibility} ) + 0.5
),
}
);
$self->{cached}->{forecast}
->{daily}[$i]{precipIntensityMax} = (
defined(
$data->{daily}->{data}->[$i]
->{precipIntensityMax}
)
? $data->{daily}->{data}->[$i]->{precipIntensityMax}
: '-'
);
$self->{cached}->{forecast}
->{daily}[$i]{precipIntensity} = (
defined(
$data->{daily}->{data}->[$i]->{precipIntensity}
)
? $data->{daily}->{data}->[$i]->{precipIntensity}
: '-'
);
$self->{cached}->{forecast}
->{daily}[$i]{precipProbability} = (
defined(
$data->{daily}->{data}->[$i]
->{precipProbability}
)
? $data->{daily}->{data}->[$i]->{precipProbability}
* 100
: '-'
);
$self->{cached}->{forecast}->{daily}[$i]{precipType} = (
defined(
$data->{daily}->{data}->[$i]->{precipType}
)
? $data->{daily}->{data}->[$i]->{precipType}
: '-'
);
$self->{cached}->{forecast}
->{daily}[$i]{precipIntensityMaxTime} = (
defined(
$data->{daily}->{data}->[$i]
->{precipIntensityMaxTime}
)
? strftimeWrapper(
"%a, %e %b %Y %H:%M",
localtime(
$data->{daily}->{data}->[$i]
->{precipIntensityMaxTime}
)
)
: '-'
);
$i++;
}
if ( ref( $data->{hourly}->{data} ) eq "ARRAY"
and scalar( @{ $data->{hourly}->{data} } ) > 0 )
{
### löschen des alten Datensatzes
delete $self->{cached}->{forecast}->{hourly};
my $i = 0;
foreach ( @{ $data->{hourly}->{data} } ) {
push(
@{ $self->{cached}->{forecast}->{hourly} },
{
2019-03-14 13:34:59 +00:00
'pubDate' => strftimeWrapper(
2019-01-14 17:16:39 +00:00
"%a, %e %b %Y %H:%M",
localtime(
$data->{hourly}->{data}->[$i]
->{'time'}
)
2019-03-14 13:34:59 +00:00
),
'day_of_week' => strftime(
2019-01-14 17:16:39 +00:00
"%a, %H:%M",
localtime(
$data->{hourly}->{data}->[$i]
->{'time'}
)
),
'temperature' => sprintf( "%.1f",
$data->{hourly}->{data}->[$i]
->{temperature} ),
'code' =>
$codes{ $data->{hourly}->{data}->[$i]
->{icon} },
'iconAPI' =>
$data->{hourly}->{data}->[$i]->{icon},
'condition' => encode_utf8(
$data->{hourly}->{data}->[$i]->{summary}
),
'ozone' =>
$data->{hourly}->{data}->[$i]->{ozone},
'uvIndex' =>
$data->{hourly}->{data}->[$i]->{uvIndex},
'dewPoint' => sprintf( "%.1f",
$data->{hourly}->{data}->[$i]
->{dewPoint} ),
'humidity' =>
$data->{hourly}->{data}->[$i]->{humidity}
* 100,
'cloudCover' =>
$data->{hourly}->{data}->[$i]
->{cloudCover} * 100,
'wind_direction' =>
$data->{hourly}->{data}->[$i]
->{windBearing},
2019-01-14 09:50:35 +00:00
'wind' => int(
sprintf(
"%.1f",
(
$data->{hourly}->{data}->[$i]
->{windSpeed} * 3.6
)
) + 0.5
2019-01-14 09:50:35 +00:00
),
'wind_speed' => int(
sprintf(
"%.1f",
(
$data->{hourly}->{data}->[$i]
->{windSpeed} * 3.6
)
) + 0.5
2019-01-14 09:50:35 +00:00
),
'windGust' => int(
sprintf(
"%.1f",
(
$data->{hourly}->{data}->[$i]
->{windGust} * 3.6
)
) + 0.5
2019-01-14 09:50:35 +00:00
),
'pressure' => sprintf( "%.1f",
$data->{hourly}->{data}->[$i]
->{pressure} ),
'visibility' => sprintf( "%.1f",
$data->{hourly}->{data}->[$i]
->{visibility} ),
}
);
$self->{cached}->{forecast}
->{hourly}[$i]{precipIntensity} = (
defined(
$data->{hourly}->{data}->[$i]
->{precipIntensity}
)
? $data->{hourly}->{data}->[$i]
->{precipIntensity}
: '-'
);
$self->{cached}->{forecast}
->{hourly}[$i]{precipProbability} = (
defined(
$data->{hourly}->{data}->[$i]
->{precipProbability}
)
? $data->{hourly}->{data}->[$i]
->{precipProbability} * 100
: '-'
);
$self->{cached}->{forecast}
->{hourly}[$i]{precipType} = (
defined(
$data->{hourly}->{data}->[$i]->{precipType}
)
? $data->{hourly}->{data}->[$i]->{precipType}
: '-'
);
2019-01-17 21:22:44 +00:00
$i++;
}
}
}
2019-01-09 09:37:55 +00:00
}
}
else { _ErrorHandling( $self, 'DarkSky Weather ' . $response ); }
}
2019-01-09 09:37:55 +00:00
## Aufruf der callbackFn
_CallWeatherCallbackFn($self);
}
sub _CallWeatherCallbackFn($) {
my $self = shift;
2019-01-09 09:37:55 +00:00
# ## Aufruf der callbackFn
main::Weather_RetrieveCallbackFn( $self->{devName} );
2019-01-09 09:37:55 +00:00
}
sub _ErrorHandling($$) {
my ( $self, $err ) = @_;
2019-01-09 09:37:55 +00:00
$self->{cached}->{current_date_time} =
2019-03-14 13:34:59 +00:00
strftimeWrapper( "%a, %e %b %Y %H:%M", localtime( $self->{fetchTime} ) ),
2019-01-10 21:35:57 +00:00
$self->{cached}->{status} = $err;
2019-01-09 09:37:55 +00:00
$self->{cached}->{validity} = 'stale';
}
sub _CreateForecastRef($) {
2019-01-09 09:37:55 +00:00
my $self = shift;
my $forecastRef = (
{
lat => $self->{lat},
long => $self->{long},
apiMaintainer =>
'Leon Gaultier (<a href=https://forum.fhem.de/index.php?action=profile;u=13684>CoolTux</a>)',
2019-09-11 06:20:28 +00:00
apiVersion => DarkSkyAPI->VERSION(),
}
);
2019-01-09 09:37:55 +00:00
return $forecastRef;
2019-01-09 09:37:55 +00:00
}
2019-03-14 13:34:59 +00:00
sub strftimeWrapper(@) {
my $string = POSIX::strftime(@_);
$string =~ s/\xe4/ä/g;
$string =~ s/\xc4/Ä/g;
$string =~ s/\xf6/ö/g;
$string =~ s/\xd6/Ö/g;
$string =~ s/\xfc/ü/g;
$string =~ s/\xdc/Ü/g;
$string =~ s/\xdf/ß/g;
$string =~ s/\xdf/ß/g;
$string =~ s/\xe1/á/g;
$string =~ s/\xe9/é/g;
$string =~ s/\xc1/Á/g;
$string =~ s/\xc9/É/g;
return $string;
}
2019-01-09 09:37:55 +00:00
##############################################################################
1;
2019-09-11 06:20:28 +00:00
=pod
=encoding utf8
=for :application/json;q=META.json DarkSkyAPI.pm
{
"abstract": "Weather API for Weather Dark Sky",
"x_lang": {
"de": {
"abstract": "Wetter API für Weather Dark Sky"
}
},
"version": "v1.0.0",
"author": [
"Marko Oldenburg <leongaultier@gmail.com>"
],
"x_fhem_maintainer": [
"CoolTux"
],
"x_fhem_maintainer_github": [
"LeonGaultier"
],
"prereqs": {
"runtime": {
"requires": {
"FHEM::Meta": 0,
"HttpUtils": 0,
"strict": 0,
"warnings": 0,
"constant": 0,
"POSIX": 0,
"JSON::PP": 0
},
"recommends": {
"JSON": 0
},
"suggests": {
"JSON::XS": 0,
"Cpanel::JSON::XS": 0
}
}
}
}
=end :application/json;q=META.json
=cut