2019-01-12 14:02:53 +00:00
# $Id: $
2019-01-09 09:37:55 +00:00
###############################################################################
#
2022-02-12 11:56:04 +00:00
# Developed with VSCodium and richterger perl plugin.
2019-01-09 09:37:55 +00:00
#
2022-02-12 11:56:04 +00:00
# (c) 2019-2022 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net)
2019-01-09 09:37:55 +00:00
# All rights reserved
#
# Special thanks goes to:
#
#
# 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.
#
#
###############################################################################
### Beispielaufruf
# https://api.openweathermap.org/data/2.5/weather?lat=[lat]&lon=[long]&APPID=[API] Current
2019-01-09 23:11:19 +00:00
# https://api.openweathermap.org/data/2.5/forecast?lat=[lat]&lon=[long]&APPID=[API] Forecast
2022-02-12 11:56:04 +00:00
# https://api.openweathermap.org/data/2.5/onecall?lat=[lat]&lon=[long]&APPID=[API] Forecast
2019-01-09 09:37:55 +00:00
# https://openweathermap.org/weather-conditions Icons und Conditions ID's
2019-09-11 06:42:42 +00:00
package OpenWeatherMapAPI ;
use strict ;
use warnings ;
use FHEM::Meta ;
FHEM::Meta:: Load ( __PACKAGE__ ) ;
2022-02-12 11:56:04 +00:00
use version 0.50 ; our $ VERSION = $ ::packages { OpenWeatherMapAPI } { META } { version } ;
2019-09-11 06:42:42 +00:00
2019-03-15 20:41:32 +00:00
package OpenWeatherMapAPI::Weather ;
2019-01-09 09:37:55 +00:00
use strict ;
use warnings ;
use POSIX ;
use HttpUtils ;
2022-02-12 11:56:04 +00:00
use experimental qw /switch/ ;
2019-01-09 09:37:55 +00:00
2020-04-25 06:49:56 +00:00
# use Data::Dumper;
2019-06-15 07:42:07 +00:00
# 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 ;
2022-02-12 11:56:04 +00:00
} or do {
2019-06-15 07:42:07 +00:00
# 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 ;
2022-02-12 11:56:04 +00:00
} or do {
2019-06-15 07:42:07 +00:00
# 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 ;
2022-02-12 11:56:04 +00:00
} or do {
2019-06-15 07:42:07 +00:00
# In rare cases, JSON::XS may
# be installed but JSON not ...
eval {
require JSON::XS ;
import JSON:: XS qw( decode_json encode_json ) ;
1 ;
2022-02-12 11:56:04 +00:00
} or do {
2019-06-15 07:42:07 +00:00
# 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 ;
2022-02-12 11:56:04 +00:00
} or do {
2019-06-15 07:42:07 +00:00
# Fallback to JSON::backportPP in really rare cases
require JSON::backportPP ;
import JSON:: backportPP qw( decode_json encode_json ) ;
1 ;
2022-02-12 11:56:04 +00:00
} ;
} ;
} ;
} ;
} ;
2019-06-15 07:42:07 +00:00
2019-01-09 09:37:55 +00:00
my $ missingModul = '' ;
2022-02-12 11:56:04 +00:00
## no critic (Conditional "use" statement. Use "require" to conditionally include a module (Modules::ProhibitConditionalUseStatements))
eval { use Encode qw /encode_utf8/; 1 } or $ missingModul . = 'Encode ' ;
2019-01-09 09:37:55 +00:00
2019-01-12 15:20:31 +00:00
# use Data::Dumper; # for Debug only
2019-01-09 09:37:55 +00:00
## API URL
2022-02-12 11:56:04 +00:00
eval { use Readonly ; 1 }
or $ missingModul . = 'Readonly ' ; # apt install libreadonly-perl
## use critic
2022-11-24 18:22:40 +00:00
# Readonly my $URL => 'https://api.openweathermap.org/data/2.5/';
Readonly my $ URL = > 'https://api.openweathermap.org/data/' ;
2019-01-09 09:37:55 +00:00
## URL . 'weather?' for current data
2022-11-20 20:10:22 +00:00
## URL . 'onecall?' for forecast data
2019-01-09 09:37:55 +00:00
my % codes = (
2019-01-09 11:17:10 +00:00
200 = > 45 ,
201 = > 45 ,
202 = > 45 ,
210 = > 4 ,
211 = > 4 ,
212 = > 3 ,
221 = > 4 ,
230 = > 45 ,
231 = > 45 ,
232 = > 45 ,
300 = > 9 ,
301 = > 9 ,
302 = > 9 ,
310 = > 9 ,
311 = > 9 ,
312 = > 9 ,
313 = > 9 ,
314 = > 9 ,
321 = > 9 ,
500 = > 35 ,
501 = > 35 ,
502 = > 35 ,
503 = > 35 ,
504 = > 35 ,
511 = > 35 ,
520 = > 35 ,
521 = > 35 ,
522 = > 35 ,
531 = > 35 ,
2019-01-09 12:14:06 +00:00
600 = > 14 ,
601 = > 16 ,
602 = > 13 ,
611 = > 46 ,
612 = > 46 ,
2019-01-09 12:42:27 +00:00
615 = > 5 ,
616 = > 5 ,
620 = > 14 ,
621 = > 46 ,
622 = > 42 ,
701 = > 19 ,
711 = > 22 ,
721 = > 19 ,
731 = > 23 ,
741 = > 20 ,
751 = > 23 ,
761 = > 19 ,
762 = > 3200 ,
771 = > 1 ,
781 = > 0 ,
800 = > 32 ,
801 = > 30 ,
802 = > 26 ,
803 = > 26 ,
804 = > 28 ,
2019-01-09 09:37:55 +00:00
) ;
sub new {
### geliefert wird ein Hash
my ( $ class , $ argsRef ) = @ _ ;
2022-11-24 18:22:40 +00:00
my $ apioptions = _parseApiOptions ( $ argsRef - > { apioptions } ) ;
2019-01-09 09:37:55 +00:00
my $ self = {
2019-01-10 21:35:57 +00:00
devName = > $ argsRef - > { devName } ,
key = > (
2022-02-12 11:56:04 +00:00
( defined ( $ argsRef - > { apikey } ) && $ argsRef - > { apikey } )
2019-01-10 21:35:57 +00:00
? $ argsRef - > { apikey }
: 'none'
) ,
lang = > $ argsRef - > { language } ,
lat = > ( split ( ',' , $ argsRef - > { location } ) ) [ 0 ] ,
long = > ( split ( ',' , $ argsRef - > { location } ) ) [ 1 ] ,
fetchTime = > 0 ,
endpoint = > 'none' ,
2022-11-24 18:22:40 +00:00
forecast = > $ argsRef - > { forecast } ,
alerts = > $ argsRef - > { alerts } ,
2019-01-09 09:37:55 +00:00
} ;
2019-01-09 11:17:10 +00:00
2019-06-15 07:36:11 +00:00
$ self - > { cachemaxage } = (
defined ( $ apioptions - > { cachemaxage } )
? $ apioptions - > { cachemaxage }
2020-04-25 06:51:34 +00:00
: 900
) ;
2019-01-09 09:37:55 +00:00
2022-11-24 18:22:40 +00:00
$ self - > { apiversion } = ( $ apioptions - > { version } ? $ apioptions - > { version } : '2.5' ) ;
$ self - > { cached } = _CreateForecastRef ( $ self ) ;
2022-11-20 20:10:22 +00:00
2019-01-09 09:37:55 +00:00
bless $ self , $ class ;
return $ self ;
}
2022-11-24 18:22:40 +00:00
sub _parseApiOptions {
2019-03-19 20:35:59 +00:00
my $ apioptions = shift ;
my @ params ;
my % h ;
2019-06-15 07:36:11 +00:00
@ params = split ( ',' , $ apioptions ) ;
2019-03-19 20:35:59 +00:00
while ( @ params ) {
my $ param = shift ( @ params ) ;
2019-06-15 07:36:11 +00:00
next if ( $ param eq '' ) ;
my ( $ key , $ value ) = split ( ':' , $ param , 2 ) ;
2019-03-19 20:35:59 +00:00
$ h { $ key } = $ value ;
}
2019-06-15 07:36:11 +00:00
2019-03-19 20:35:59 +00:00
return \ % h ;
}
2022-11-24 18:22:40 +00:00
sub setAlerts {
my $ self = shift ;
my $ alerts = shift // 0 ;
$ self - > { alerts } = $ alerts ;
return ;
}
sub setForecast {
my $ self = shift ;
my $ forecast = shift // '' ;
$ self - > { forecast } = $ forecast ;
return ;
}
2019-01-09 09:37:55 +00:00
sub setFetchTime {
my $ self = shift ;
$ self - > { fetchTime } = time ( ) ;
2022-11-24 18:22:40 +00:00
return ;
2019-01-09 09:37:55 +00:00
}
sub setRetrieveData {
my $ self = shift ;
_RetrieveDataFromOpenWeatherMap ( $ self ) ;
2022-11-24 18:22:40 +00:00
return ;
2019-01-09 09:37:55 +00:00
}
2019-09-09 15:35:35 +00:00
sub setLocation {
2022-11-24 18:22:40 +00:00
my $ self = shift ;
my $ lat = shift ;
my $ long = shift ;
2019-09-09 15:35:35 +00:00
2020-04-25 06:51:34 +00:00
$ self - > { lat } = $ lat ;
$ self - > { long } = $ long ;
2019-09-09 15:35:35 +00:00
2022-11-24 18:22:40 +00:00
return ;
2019-09-09 15:35:35 +00:00
}
2019-01-09 09:37:55 +00:00
sub getFetchTime {
my $ self = shift ;
return $ self - > { fetchTime } ;
}
sub getWeather {
my $ self = shift ;
return $ self - > { cached } ;
}
2020-04-22 07:18:12 +00:00
sub _RetrieveDataFromOpenWeatherMap {
2019-01-09 09:37:55 +00:00
my $ self = shift ;
# retrieve data from cache
2022-02-12 11:56:04 +00:00
if ( ( time ( ) - $ self - > { fetchTime } ) < $ self - > { cachemaxage }
&& $ self - > { cached } - > { lat } == $ self - > { lat }
&& $ self - > { cached } - > { long } == $ self - > { long }
&& $ self - > { endpoint } eq 'none' )
2019-09-09 15:35:35 +00:00
{
return _CallWeatherCallbackFn ( $ self ) ;
2019-01-09 09:37:55 +00:00
}
2020-04-25 06:51:34 +00:00
$ self - > { cached } - > { lat } = $ self - > { lat }
2019-09-09 15:35:35 +00:00
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 ,
2022-02-12 11:56:04 +00:00
endpoint = > $ self - > { endpoint } eq 'none' ? 'weather'
2022-11-17 18:58:56 +00:00
: $ self - > { endpoint } eq 'weather' ? 'onecall'
: 'weather' ,
2019-01-09 09:37:55 +00:00
callback = > \ & _RetrieveDataFinished ,
} ;
$ self - > { endpoint } = $ paramRef - > { endpoint } ;
if ( $ self - > { lat } eq 'error'
2022-02-12 11:56:04 +00:00
|| $ self - > { long } eq 'error'
|| $ self - > { key } eq 'none'
|| $ missingModul )
2019-01-09 09:37:55 +00:00
{
2019-01-09 11:17:10 +00:00
_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
2022-02-12 11:56:04 +00:00
) if ( $ self - > { lat } eq 'error' || $ self - > { long } eq 'error' ) ;
2019-01-09 11:17:10 +00:00
2019-01-09 09:37:55 +00:00
_RetrieveDataFinished ( $ paramRef ,
2019-01-09 11:17:10 +00:00
'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 {
$ paramRef - > { url } =
2022-02-12 11:56:04 +00:00
$ URL
2022-11-24 18:22:40 +00:00
. $ self - > { apiversion } . '/'
2019-01-09 11:17:10 +00:00
. $ paramRef - > { endpoint } . '?' . 'lat='
. $ self - > { lat } . '&' . 'lon='
2019-01-09 09:37:55 +00:00
. $ self - > { long } . '&'
. 'APPID='
2022-11-24 18:22:40 +00:00
. $ self - > { key } . '&' . 'units='
. 'metric' . '&' . 'lang='
2022-11-20 20:10:22 +00:00
. $ self - > { lang } . '&' . 'exclude='
2022-11-24 18:22:40 +00:00
. _createExcludeString ( $ self - > { forecast } , $ self - > { alerts } ) ;
2019-01-09 09:37:55 +00:00
2022-02-12 11:56:04 +00:00
:: HttpUtils_NonblockingGet ( $ paramRef ) ;
2019-01-09 09:37:55 +00:00
}
2022-02-12 11:56:04 +00:00
return ;
2019-01-09 09:37:55 +00:00
}
2022-11-24 18:22:40 +00:00
sub _createExcludeString {
my $ forecast = shift ;
my $ alerts = shift ;
my @ exclude = qw/alerts minutely hourly daily/ ;
my @ forecast = split ( ',' , $ forecast ) ;
my @ alerts = ( $ alerts ? ',alerts' : '' ) ;
my % in_forecast = map { $ _ = > 1 } @ forecast , @ alerts ;
my @ diff = grep { not $ in_forecast { $ _ } } @ exclude ;
return join ( ',' , @ alerts ) ;
}
2020-04-22 07:18:12 +00:00
sub _RetrieveDataFinished {
2020-04-25 06:51:34 +00:00
my $ paramRef = shift ;
my $ err = shift ;
my $ response = shift ;
my $ self = $ paramRef - > { self } ;
2019-01-09 09:37:55 +00:00
if ( ! $ err ) {
2022-02-12 11:56:04 +00:00
$ 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 ) ;
}
2022-02-12 11:56:04 +00:00
return ;
2019-01-09 09:37:55 +00:00
}
2020-04-22 07:18:12 +00:00
sub _ProcessingRetrieveData {
2020-04-25 06:51:34 +00:00
my $ self = shift ;
my $ response = shift ;
2019-01-09 09:37:55 +00:00
2022-02-12 11:56:04 +00:00
if ( $ self - > { cached } - > { status } eq 'ok'
&& defined ( $ response )
&& $ response )
2019-01-10 21:35:57 +00:00
{
2022-02-12 11:56:04 +00:00
if ( $ response =~ m/^{.*}$/x ) {
2019-01-13 08:22:28 +00:00
my $ data = eval { decode_json ( $ response ) } ;
2019-01-09 11:17:10 +00:00
2019-01-13 08:22:28 +00:00
if ( $@ ) {
_ErrorHandling ( $ self ,
'OpenWeatherMap Weather decode JSON err ' . $@ ) ;
2019-01-09 23:11:19 +00:00
}
2022-02-12 11:56:04 +00:00
elsif ( defined ( $ data - > { cod } )
&& $ data - > { cod }
&& $ data - > { cod } != 200
&& defined ( $ data - > { message } )
&& $ data - > { message } )
2019-01-13 08:22:28 +00:00
{
_ErrorHandling ( $ self , $ data - > { cod } . ': ' . $ data - > { message } ) ;
}
else {
2019-01-15 13:51:50 +00:00
### Debug
2022-11-20 20:10:22 +00:00
# print '!!! DEBUG !!! - Endpoint: ' . $self->{endpoint} . "\n";
# print '!!! DEBUG !!! - Response: ' . Dumper $data;
2019-01-13 08:22:28 +00:00
###### Ab hier wird die ResponseHash Referenze für die Rückgabe zusammen gestellt
$ self - > { cached } - > { current_date_time } =
2019-06-15 07:36:11 +00:00
strftimeWrapper ( "%a, %e %b %Y %H:%M" ,
2019-03-14 17:40:42 +00:00
localtime ( $ self - > { fetchTime } ) ) ;
2019-01-13 08:22:28 +00:00
2022-02-12 11:56:04 +00:00
given ( $ self - > { endpoint } ) {
when ( 'weather' ) {
$ self - > { cached } - > { country } = $ data - > { sys } - > { country } ;
$ self - > { cached } - > { city } = encode_utf8 ( $ data - > { name } ) ;
$ self - > { cached } - > { license } { text } = 'none' ;
2022-11-17 18:58:56 +00:00
$ self - > { cached } - > { current } = {
2022-02-12 11:56:04 +00:00
'temperature' = > int (
sprintf ( "%.1f" ,
2022-11-24 18:22:40 +00:00
$ data - > { main } - > { temp } ) + 0.5
2022-02-12 11:56:04 +00:00
) ,
'temp_c' = > int (
sprintf ( "%.1f" ,
2022-11-24 18:22:40 +00:00
$ data - > { main } - > { temp } ) + 0.5
2022-02-12 11:56:04 +00:00
) ,
'low_c' = > int (
sprintf ( "%.1f" ,
2022-11-24 18:22:40 +00:00
$ data - > { main } - > { temp_min } ) + 0.5
2022-02-12 11:56:04 +00:00
) ,
'high_c' = > int (
sprintf ( "%.1f" ,
2022-11-24 18:22:40 +00:00
$ data - > { main } - > { temp_max } ) + 0.5
2022-02-12 11:56:04 +00:00
) ,
'tempLow' = > int (
sprintf ( "%.1f" ,
2022-11-24 18:22:40 +00:00
$ data - > { main } - > { temp_min } ) + 0.5
2022-02-12 11:56:04 +00:00
) ,
'tempHigh' = > int (
sprintf ( "%.1f" ,
2022-11-24 18:22:40 +00:00
$ data - > { main } - > { temp_max } ) + 0.5
2022-02-12 11:56:04 +00:00
) ,
'tempFeelsLike_c' = > int (
sprintf ( "%.1f" ,
2022-11-24 18:22:40 +00:00
$ data - > { main } - > { feels_like } ) + 0.5
2022-02-12 11:56:04 +00:00
) ,
'humidity' = > $ data - > { main } - > { humidity } ,
'condition' = > encode_utf8 (
$ data - > { weather } - > [ 0 ] - > { description }
) ,
'pressure' = > int (
sprintf ( "%.1f" , $ data - > { main } - > { pressure } ) +
0.5
) ,
'wind' = > int (
sprintf ( "%.1f" ,
( $ data - > { wind } - > { speed } * 3.6 ) ) + 0.5
) ,
'wind_speed' = > int (
sprintf ( "%.1f" ,
( $ data - > { wind } - > { speed } * 3.6 ) ) + 0.5
) ,
'wind_gust' = > int (
sprintf ( "%.1f" ,
( $ data - > { wind } - > { gust } * 3.6 ) ) + 0.5
) ,
'wind_direction' = > $ data - > { wind } - > { deg } ,
2022-11-17 18:58:56 +00:00
'rain_1h' = > $ data - > { rain } - > { '1h' } ,
2022-02-12 11:56:04 +00:00
'cloudCover' = > $ data - > { clouds } - > { all } ,
'code' = > $ codes { $ data - > { weather } - > [ 0 ] - > { id } } ,
'iconAPI' = > $ data - > { weather } - > [ 0 ] - > { icon } ,
'sunsetTime' = > strftimeWrapper (
"%a, %e %b %Y %H:%M" ,
localtime ( $ data - > { sys } - > { sunset } )
) ,
'sunriseTime' = > strftimeWrapper (
"%a, %e %b %Y %H:%M" ,
localtime ( $ data - > { sys } - > { sunrise } )
) ,
'pubDate' = > strftimeWrapper (
"%a, %e %b %Y %H:%M" ,
localtime ( $ data - > { dt } )
) ,
} ;
$ self - > { cached } - > { current } - > { 'visibility' } =
int ( sprintf ( "%.1f" , $ data - > { visibility } ) + 0.5 )
if ( exists $ data - > { visibility } ) ;
}
2019-01-09 23:11:19 +00:00
2022-11-17 18:58:56 +00:00
when ( 'onecall' ) {
if ( ref ( $ data - > { hourly } ) eq "ARRAY"
&& scalar ( @ { $ data - > { hourly } } ) > 0 )
2022-02-12 11:56:04 +00:00
{
## löschen des alten Datensatzes
delete $ self - > { cached } - > { forecast } ;
my $ i = 0 ;
2022-11-17 18:58:56 +00:00
for ( @ { $ data - > { hourly } } ) {
2022-02-12 11:56:04 +00:00
push (
@ { $ self - > { cached } - > { forecast } - > { hourly } } ,
{
'pubDate' = > strftimeWrapper (
"%a, %e %b %Y %H:%M" ,
localtime (
2022-11-17 18:58:56 +00:00
( $ data - > { hourly } - > [ $ i ] - > { dt } )
- 3600
2019-01-13 08:22:28 +00:00
)
2022-02-12 11:56:04 +00:00
) ,
'day_of_week' = > strftime (
"%a, %H:%M" ,
localtime (
2022-11-17 18:58:56 +00:00
( $ data - > { hourly } - > [ $ i ] - > { dt } )
- 3600
2019-01-13 08:22:28 +00:00
)
2022-02-12 11:56:04 +00:00
) ,
'temperature' = > int (
sprintf (
"%.1f" ,
(
2022-11-17 18:58:56 +00:00
$ data - > { hourly } - > [ $ i ]
2022-11-24 18:22:40 +00:00
- > { temp }
2022-02-12 11:56:04 +00:00
)
) + 0.5
) ,
'temp_c' = > int (
sprintf (
"%.1f" ,
(
2022-11-17 18:58:56 +00:00
$ data - > { hourly } - > [ $ i ]
2022-11-24 18:22:40 +00:00
- > { temp }
2022-02-12 11:56:04 +00:00
)
) + 0.5
) ,
'humidity' = >
2022-11-20 20:10:22 +00:00
$ data - > { hourly } - > [ $ i ]
2022-02-12 11:56:04 +00:00
- > { humidity } ,
'condition' = > encode_utf8 (
2022-11-17 18:58:56 +00:00
$ data - > { hourly } - > [ $ i ] - > { weather }
- > [ 0 ] - > { description }
2022-02-12 11:56:04 +00:00
) ,
'pressure' = > int (
sprintf ( "%.1f" ,
2022-11-20 20:10:22 +00:00
$ data - > { hourly } - > [ $ i ]
2022-02-12 11:56:04 +00:00
- > { pressure } ) + 0.5
) ,
'wind' = > int (
sprintf (
"%.1f" ,
(
2022-11-17 18:58:56 +00:00
$ data - > { hourly } - > [ $ i ]
2022-11-20 20:10:22 +00:00
- > { wind_speed } * 3.6
2022-02-12 11:56:04 +00:00
)
) + 0.5
) ,
'wind_speed' = > int (
sprintf (
"%.1f" ,
(
2022-11-17 18:58:56 +00:00
$ data - > { hourly } - > [ $ i ]
2022-11-20 20:10:22 +00:00
- > { wind_speed } * 3.6
2022-02-12 11:56:04 +00:00
)
) + 0.5
) ,
'wind_gust' = > int (
sprintf (
"%.1f" ,
(
2022-11-17 18:58:56 +00:00
$ data - > { hourly } - > [ $ i ]
2022-11-20 20:10:22 +00:00
- > { wind_gust } * 3.6
2022-02-12 11:56:04 +00:00
)
) + 0.5
) ,
'cloudCover' = >
2022-11-20 20:10:22 +00:00
$ data - > { hourly } - > [ $ i ]
- > { clouds } ,
2022-02-12 11:56:04 +00:00
'code' = > $ codes {
2022-11-17 18:58:56 +00:00
$ data - > { hourly } - > [ $ i ] - > { weather }
- > [ 0 ] - > { id }
2022-02-12 11:56:04 +00:00
} ,
'iconAPI' = >
2022-11-17 18:58:56 +00:00
$ data - > { hourly } - > [ $ i ] - > { weather } - > [ 0 ]
2022-02-12 11:56:04 +00:00
- > { icon } ,
'rain1h' = >
2022-11-20 20:10:22 +00:00
$ data - > { hourly } - > [ $ i ] - > { rain } - > { '1h' } ,
2022-02-12 11:56:04 +00:00
'snow1h' = >
2022-11-20 20:10:22 +00:00
$ data - > { hourly } - > [ $ i ] - > { snow } - > { '1h' } ,
2022-02-12 11:56:04 +00:00
} ,
) ;
$ i + + ;
}
}
if ( ref ( $ data - > { daily } ) eq "ARRAY"
&& scalar ( @ { $ data - > { daily } } ) > 0 )
{
my $ i = 0 ;
for ( @ { $ data - > { daily } } ) {
push (
@ { $ self - > { cached } - > { forecast } - > { daily } } ,
{
'pubDate' = > strftimeWrapper (
"%a, %e %b %Y %H:%M" ,
localtime (
( $ data - > { daily } - > [ $ i ] - > { dt } )
- 3600
2019-01-13 08:22:28 +00:00
)
2022-02-12 11:56:04 +00:00
) ,
'day_of_week' = > strftime (
"%a, %H:%M" ,
localtime (
( $ data - > { daily } - > [ $ i ] - > { dt } )
- 3600
2019-01-13 08:22:28 +00:00
)
2022-02-12 11:56:04 +00:00
) ,
'sunrise' = > strftime (
"%H:%M" ,
localtime (
(
$ data - > { daily } - > [ $ i ]
- > { sunrise }
) - 3600
2019-01-13 08:22:28 +00:00
)
2022-02-12 11:56:04 +00:00
) ,
'sunset' = > strftime (
"%a, %H:%M" ,
localtime (
(
$ data - > { daily } - > [ $ i ]
- > { sunset }
) - 3600
2019-01-13 08:22:28 +00:00
)
2022-02-12 11:56:04 +00:00
) ,
'moonrise' = > strftime (
"%a, %H:%M" ,
localtime (
(
$ data - > { daily } - > [ $ i ]
- > { moonrise }
) - 3600
2019-06-15 07:36:11 +00:00
)
2022-02-12 11:56:04 +00:00
) ,
'moonset' = > strftime (
"%a, %H:%M" ,
localtime (
(
$ data - > { daily } - > [ $ i ]
- > { moonset }
) - 3600
2019-06-15 07:36:11 +00:00
)
2022-02-12 11:56:04 +00:00
) ,
'temperature' = > int (
sprintf (
"%.1f" ,
2022-11-24 18:22:40 +00:00
$ data - > { daily } - > [ $ i ] - > { temp } - > { day }
2022-02-12 11:56:04 +00:00
) + 0.5
) ,
2022-11-20 20:10:22 +00:00
'temperature_morn' = > int (
sprintf (
"%.1f" ,
2022-11-24 18:22:40 +00:00
$ data - > { daily } - > [ $ i ] - > { temp } - > { morn }
2022-11-20 20:10:22 +00:00
) + 0.5
) ,
'temperature_eve' = > int (
sprintf (
"%.1f" ,
2022-11-24 18:22:40 +00:00
$ data - > { daily } - > [ $ i ] - > { temp } - > { eve }
2022-11-20 20:10:22 +00:00
) + 0.5
) ,
'temperature_night' = > int (
sprintf (
"%.1f" ,
2022-11-24 18:22:40 +00:00
$ data - > { daily } - > [ $ i ] - > { temp } - > { night }
2022-11-20 20:10:22 +00:00
) + 0.5
) ,
'tempFeelsLike_morn' = > int (
sprintf (
"%.1f" ,
2022-11-24 18:22:40 +00:00
$ data - > { daily } - > [ $ i ] - > { feels_like } - > { morn }
2022-11-20 20:10:22 +00:00
) + 0.5
) ,
'tempFeelsLike_eve' = > int (
sprintf (
"%.1f" ,
2022-11-24 18:22:40 +00:00
$ data - > { daily } - > [ $ i ] - > { feels_like } - > { eve }
2022-11-20 20:10:22 +00:00
) + 0.5
) ,
'tempFeelsLike_night' = > int (
sprintf (
"%.1f" ,
2022-11-24 18:22:40 +00:00
$ data - > { daily } - > [ $ i ] - > { feels_like } - > { night }
2022-11-20 20:10:22 +00:00
) + 0.5
) ,
'tempFeelsLike_day' = > int (
sprintf (
"%.1f" ,
2022-11-24 18:22:40 +00:00
$ data - > { daily } - > [ $ i ] - > { feels_like } - > { day }
2022-11-20 20:10:22 +00:00
) + 0.5
) ,
2022-02-12 11:56:04 +00:00
'temp_c' = > int (
sprintf (
"%.1f" ,
2022-11-24 18:22:40 +00:00
$ data - > { daily } - > [ $ i ] - > { temp } - > { day }
2022-02-12 11:56:04 +00:00
) + 0.5
) ,
'low_c' = > int (
sprintf (
"%.1f" ,
2022-11-24 18:22:40 +00:00
$ data - > { daily } - > [ $ i ] - > { temp } - > { min }
2022-02-12 11:56:04 +00:00
) + 0.5
) ,
'high_c' = > int (
sprintf (
"%.1f" ,
2022-11-24 18:22:40 +00:00
$ data - > { daily } - > [ $ i ] - > { temp } - > { max }
2022-02-12 11:56:04 +00:00
) + 0.5
) ,
'tempLow' = > int (
sprintf (
"%.1f" ,
2022-11-24 18:22:40 +00:00
$ data - > { daily } - > [ $ i ] - > { temp } - > { min }
2022-02-12 11:56:04 +00:00
) + 0.5
) ,
'tempHigh' = > int (
sprintf (
"%.1f" ,
2022-11-24 18:22:40 +00:00
$ data - > { daily } - > [ $ i ] - > { temp } - > { max }
2022-02-12 11:56:04 +00:00
) + 0.5
) ,
2022-11-20 20:10:22 +00:00
'dew_point' = > int (
sprintf (
"%.1f" ,
2022-11-24 18:22:40 +00:00
$ data - > { daily } - > [ $ i ] - > { dew_point }
2022-11-20 20:10:22 +00:00
) + 0.5
) ,
2022-02-12 11:56:04 +00:00
'humidity' = >
$ data - > { daily } - > [ $ i ] - > { humidity } ,
'condition' = > encode_utf8 (
$ data - > { daily } - > [ $ i ] - > { weather }
- > [ 0 ] - > { description }
) ,
'pressure' = > int (
sprintf ( "%.1f" ,
$ data - > { daily } - > [ $ i ] - > { pressure }
) + 0.5
) ,
'wind' = > int (
sprintf (
"%.1f" ,
(
$ data - > { daily } - > [ $ i ]
- > { wind_speed } * 3.6
)
) + 0.5
) ,
'wind_speed' = > int (
sprintf (
"%.1f" ,
(
$ data - > { daily } - > [ $ i ]
- > { wind_speed } * 3.6
)
) + 0.5
) ,
'wind_gust' = > int (
sprintf (
"%.1f" ,
(
$ data - > { daily } - > [ $ i ]
- > { wind_gust } * 3.6
)
) + 0.5
) ,
'wind_direction' = > int (
sprintf (
"%.1f" ,
(
$ data - > { daily } - > [ $ i ]
- > { wind_deg }
)
2021-06-09 18:30:35 +00:00
)
2022-02-12 11:56:04 +00:00
) ,
'cloudCover' = >
$ data - > { daily } - > [ $ i ] - > { clouds } ,
'code' = > $ codes {
$ data - > { daily } - > [ $ i ] - > { weather }
- > [ 0 ] - > { id }
} ,
'iconAPI' = >
$ data - > { daily } - > [ $ i ] - > { weather } - > [ 0 ]
- > { icon } ,
'rain' = > $ data - > { daily } - > [ $ i ] - > { rain } ,
'snow' = > $ data - > { daily } - > [ $ i ] - > { snow } ,
'uvi' = > $ data - > { daily } - > [ $ i ] - > { uvi } ,
2019-06-15 07:36:11 +00:00
} ,
2022-02-12 11:56:04 +00:00
) ;
$ i + + ;
}
2019-01-13 08:22:28 +00:00
}
2022-11-20 20:10:22 +00:00
if ( ref ( $ data - > { alerts } ) eq "ARRAY"
&& scalar ( @ { $ data - > { alerts } } ) > 0 )
{
## löschen des alten Datensatzes
delete $ self - > { cached } - > { alerts } ;
my $ i = 0 ;
for ( @ { $ data - > { alerts } } ) {
push (
@ { $ self - > { cached } - > { alerts } } ,
{
'warn_' . $ i . '_End' = > strftimeWrapper (
"%a, %e %b %Y %H:%M" ,
localtime (
( $ data - > { alerts } - > [ $ i ] - > { end } )
- 3600
)
) ,
'warn_' . $ i . '_Start' = > strftimeWrapper (
"%a, %e %b %Y %H:%M" ,
localtime (
( $ data - > { alerts } - > [ $ i ] - > { start } )
- 3600
)
) ,
'warn_' . $ i . '_Description' = > encode_utf8 (
$ data - > { alerts } - > [ $ i ] - > { description }
) ,
'warn_' . $ i . '_SenderName' = > encode_utf8 (
$ data - > { alerts } - > [ $ i ] - > { sender_name }
) ,
'warn_' . $ i . '_Event' = > encode_utf8 (
$ data - > { alerts } - > [ $ i ] - > { event }
) ,
} ,
) ;
$ i + + ;
}
}
2019-01-09 23:11:19 +00:00
}
}
}
2019-01-09 11:17:10 +00:00
}
2019-01-13 08:22:28 +00:00
else { _ErrorHandling ( $ self , 'OpenWeatherMap ' . $ response ) ; }
2019-01-09 11:17:10 +00:00
}
2019-01-10 21:35:57 +00:00
2022-02-12 11:56:04 +00:00
$ self - > { endpoint } = 'none' if ( $ self - > { endpoint } eq 'onecall' ) ;
2019-01-09 09:37:55 +00:00
2019-01-09 11:17:10 +00:00
_RetrieveDataFromOpenWeatherMap ( $ self )
2022-11-17 18:58:56 +00:00
if ( $ self - > { endpoint } eq 'weather' ) ;
2019-01-09 11:17:10 +00:00
2019-01-09 23:11:19 +00:00
_CallWeatherCallbackFn ( $ self ) if ( $ self - > { endpoint } eq 'none' ) ;
2022-02-12 11:56:04 +00:00
return ;
2019-01-09 09:37:55 +00:00
}
2020-04-22 07:18:12 +00:00
sub _CallWeatherCallbackFn {
2019-01-09 09:37:55 +00:00
my $ self = shift ;
2019-01-10 21:35:57 +00:00
# print 'Dumperausgabe: ' . Dumper $self;
2019-01-09 23:11:19 +00:00
### Aufruf der callbackFn
2022-02-12 11:56:04 +00:00
:: Weather_RetrieveCallbackFn ( $ self - > { devName } ) ;
return ;
2019-01-09 09:37:55 +00:00
}
2020-04-22 07:18:12 +00:00
sub _ErrorHandling {
2020-04-25 06:51:34 +00:00
my $ self = shift ;
my $ err = shift ;
2019-01-09 09:37:55 +00:00
2019-01-09 11:17:10 +00:00
$ self - > { cached } - > { current_date_time } =
2022-02-12 11:56:04 +00:00
strftimeWrapper ( "%a, %e %b %Y %H:%M" , localtime ( $ self - > { fetchTime } ) ) ;
$ self - > { cached } - > { status } = $ err ;
2019-01-09 09:37:55 +00:00
$ self - > { cached } - > { validity } = 'stale' ;
2022-02-12 11:56:04 +00:00
return ;
2019-01-09 09:37:55 +00:00
}
2020-04-22 07:18:12 +00:00
sub _CreateForecastRef {
2019-01-09 09:37:55 +00:00
my $ self = shift ;
2019-01-09 23:11:19 +00:00
my $ forecastRef = (
2019-01-09 11:17:10 +00:00
{
2022-11-17 18:58:56 +00:00
lat = > $ self - > { lat } ,
long = > $ self - > { long } ,
2019-01-09 11:17:10 +00:00
apiMaintainer = >
2021-01-30 17:41:41 +00:00
'Marko Oldenburg (<a href=https://forum.fhem.de/index.php?action=profile;u=13684>CoolTux</a>)' ,
2020-04-25 06:51:34 +00:00
apiVersion = >
version - > parse ( OpenWeatherMapAPI - > VERSION ( ) ) - > normal ,
2019-01-09 11:17:10 +00:00
}
) ;
2019-01-09 09:37:55 +00:00
2019-01-09 23:11:19 +00:00
return $ forecastRef ;
2019-01-09 09:37:55 +00:00
}
2020-04-22 07:18:12 +00:00
sub strftimeWrapper {
2022-02-12 11:56:04 +00:00
my @ data = @ _ ;
my $ string = POSIX:: strftime ( @ data ) ;
$ string =~ s/\xe4/ä/xg ;
$ string =~ s/\xc4/Ä/xg ;
$ string =~ s/\xf6/ö/xg ;
$ string =~ s/\xd6/Ö/xg ;
$ string =~ s/\xfc/ü/xg ;
$ string =~ s/\xdc/Ü/xg ;
$ string =~ s/\xdf/ß/xg ;
$ string =~ s/\xdf/ß/xg ;
$ string =~ s/\xe1/á/xg ;
$ string =~ s/\xe9/é/xg ;
$ string =~ s/\xc1/Á/xg ;
$ string =~ s/\xc9/É/xg ;
2019-03-14 17:40:42 +00:00
return $ string ;
}
2019-01-09 09:37:55 +00:00
##############################################################################
1 ;
2019-09-11 06:42:42 +00:00
= pod
= encoding utf8
= for : application / json ; q = META . json OpenWeatherMapAPI . pm
{
"abstract" : "Weather API for Weather OpenWeatherMap" ,
"x_lang" : {
"de" : {
"abstract" : "Wetter API für OpenWeatherMap"
}
} ,
2022-02-12 11:56:04 +00:00
"version" : "v1.2.0" ,
2019-09-11 06:42:42 +00:00
"author" : [
2022-02-12 11:56:04 +00:00
"Marko Oldenburg <fhemdevelopment@cooltux.net>"
2019-09-11 06:42:42 +00:00
] ,
"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
2022-02-12 11:56:04 +00:00
__END__