From b1de4b52daec3c9b677c1c1e1e65ec234e2adb5c Mon Sep 17 00:00:00 2001
From: Marko Oldenburg <fhemdevelopment@cooltux.net>
Date: Fri, 11 Oct 2024 06:59:53 +0200
Subject: [PATCH] fix: Update forecast with cachemaxage after API calls are
 down. special thanks to stefanru (forum)

[Ticket: no]
---
 CHANGELOG.md                             |  12 +-
 controls_Weather.txt                     |   4 +-
 lib/FHEM/APIs/Weather/wundergroundAPI.pm | 161 +++++++++++++----------
 lib/FHEM/Core/Weather.pm                 |   1 +
 4 files changed, 107 insertions(+), 71 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5cacf2e..ada5bd1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,14 @@
-### feat: new reading owmAPICode for original code (HEAD -> patch-createDecimal)
+### test: add new CHANGELOG (HEAD -> patch-createDecimal)
+>Sat, 21 Oct 2023 08:59:11 +0200
+
+>Author: Marko Oldenburg (fhemdevelopment@cooltux.net)
+
+>Commiter: Marko Oldenburg (fhemdevelopment@cooltux.net)
+
+
+
+
+### feat: new reading owmAPICode for original code (origin/patch-createDecimal)
 >Tue, 11 Jul 2023 14:10:13 +0200
 
 >Author: Marko Oldenburg (fhemdevelopment@cooltux.net)
diff --git a/controls_Weather.txt b/controls_Weather.txt
index f54136f..d6499c9 100644
--- a/controls_Weather.txt
+++ b/controls_Weather.txt
@@ -1,5 +1,5 @@
 UPD 2023-01-29_16:14:48 25809 FHEM/59_Weather.pm
-UPD 2023-06-06_07:31:00 34254 lib/FHEM/Core/Weather.pm
+UPD 2024-10-11_06:52:17 34293 lib/FHEM/Core/Weather.pm
 UPD 2023-01-29_16:14:48 50106 lib/FHEM/APIs/Weather/DarkSkyAPI.pm
 UPD 2023-07-11_14:08:00 33779 lib/FHEM/APIs/Weather/OpenWeatherMapAPI.pm
-UPD 2023-06-02_05:03:58 36607 lib/FHEM/APIs/Weather/wundergroundAPI.pm
+UPD 2024-10-11_06:49:47 37627 lib/FHEM/APIs/Weather/wundergroundAPI.pm
diff --git a/lib/FHEM/APIs/Weather/wundergroundAPI.pm b/lib/FHEM/APIs/Weather/wundergroundAPI.pm
index 32a23cd..35e6163 100644
--- a/lib/FHEM/APIs/Weather/wundergroundAPI.pm
+++ b/lib/FHEM/APIs/Weather/wundergroundAPI.pm
@@ -15,9 +15,9 @@ return "$@" if ($@);
 return $ret if ($ret);
 $::packages{wundergroundAPI}{META} = $META;
 
-use version 0.77; our $VERSION = $META->{version};
+use version 0.80; our $VERSION = $META->{version};
 
-# use Data::Dumper;
+use Data::Dumper;
 
 # try to use JSON::MaybeXS wrapper
 #   for chance of better performance + open code
@@ -103,10 +103,11 @@ sub new {
             ? $argsRef->{apikey}
             : 'none'
         ),
-        lang      => $argsRef->{language},
-        lat       => ( split( ',', $argsRef->{location} ) )[0],
-        long      => ( split( ',', $argsRef->{location} ) )[1],
-        fetchTime => 0,
+        lang              => $argsRef->{language},
+        lat               => ( split( ',', $argsRef->{location} ) )[0],
+        long              => ( split( ',', $argsRef->{location} ) )[1],
+        fetchTime         => 0,
+        forecastFetchTime => 0,
     };
 
     $self->{cachemaxage} = (
@@ -210,29 +211,66 @@ sub _RetrieveDataFromWU {
     return 0 unless ( __PACKAGE__ eq caller(0) );
 
     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} )
-    {
-        return _CallWeatherCallbackFn($self);
-    }
+    my $paramRef;
+    my $options;
 
     $self->{cached}->{lat} = $self->{lat}
       unless ( $self->{cached}->{lat} == $self->{lat} );
     $self->{cached}->{long} = $self->{long}
       unless ( $self->{cached}->{long} == $self->{long} );
 
-    my $paramRef = {
-        timeout  => 15,
-        self     => $self,
-        callback => (
-            $self->{stationId}
-            ? \&_RetrieveDataFromPWS
-            : \&_RetrieveDataFinished
-        ),
-    };
+    # retrieve forecast data from cache
+    if (    ( time() - $self->{forecastFetchTime} ) < $self->{cachemaxage}
+        and $self->{cached}->{lat} == $self->{lat}
+        and $self->{cached}->{long} == $self->{long} )
+    {
+        # old: return _CallWeatherCallbackFn($self);
+        # Do not just return but get PWS data without forecast
+        $paramRef = {
+            timeout  => 15,
+            self     => $self,
+            callback => \&_RetrieveDataFinished,
+        };
+
+        #Build station URL
+        $options = 'stationId=' . $self->{stationId};
+        $options .= '&format=json';
+        $options .= '&units=' . $self->{units};
+        $options .= '&numericPrecision=decimal';
+        $options .= '&apiKey=' . $self->{key};
+
+        $paramRef->{url} = $URL . 'v2/pws/observations/current?' . $options;
+    }
+    else {
+        # Get the complete data station and forecast
+        $paramRef = {
+            timeout  => 15,
+            self     => $self,
+            callback => (
+                $self->{stationId}
+                ? \&_RetrieveDataFromPWS
+                : \&_RetrieveDataFinished
+            ),
+        };
+
+        # Build forecast URL
+        $options = 'geocode=' . $self->{lat} . ',' . $self->{long};
+        $options .= '&format=json';
+        $options .= '&units=' . $self->{units};
+        $options .= '&language='
+          . (
+            $self->{lang} eq 'en'
+            ? 'en-US'
+            : $self->{lang} . '-' . uc( $self->{lang} )
+          );
+        $options .= '&apiKey=' . $self->{key};
+
+        $paramRef->{url} =
+            $URL
+          . 'v3/wx/forecast/daily/'
+          . $self->{days} . 'day' . '?'
+          . $options;
+    }
 
     if (   $self->{lat} eq 'error'
         or $self->{long} eq 'error'
@@ -250,23 +288,6 @@ sub _RetrieveDataFromWU {
           if ( $self->{key} eq 'none' );
     }
     else {
-        my $options = 'geocode=' . $self->{lat} . ',' . $self->{long};
-        $options .= '&format=json';
-        $options .= '&units=' . $self->{units};
-        $options .= '&language='
-          . (
-            $self->{lang} eq 'en'
-            ? 'en-US'
-            : $self->{lang} . '-' . uc( $self->{lang} )
-          );
-        $options .= '&apiKey=' . $self->{key};
-
-        $paramRef->{url} =
-            $URL
-          . 'v3/wx/forecast/daily/'
-          . $self->{days} . 'day' . '?'
-          . $options;
-
         if ( lc( $self->{key} ) eq 'demo' ) {
             _RetrieveDataFinished( $paramRef, undef, 'DEMODATA' . $DEMODATA );
         }
@@ -352,10 +373,20 @@ sub _RetrieveDataFinished {
         $self->{cached}{status}   = 'ok';
         $self->{cached}{validity} = 'up-to-date';
         $self->{fetchTime}        = time();
+
+        #print Dumper $response; ## for debugging
+        #print Dumper $data;     ## for debugging
+        #if (exists( $response->{daily} )) {
+        if ( $response =~ /{"daily":/ ) {
+            $self->{forecastFetchTime} = time();
+        }
         _ProcessingRetrieveData( $self, $response );
     }
     else {
         $self->{fetchTime} = time() if ( not defined( $self->{fetchTime} ) );
+        $self->{forecastFetchTime} = time()
+          if ( not defined( $self->{forecastFetchTime} ) );
+
         _ErrorHandling( $self, $err );
         _ProcessingRetrieveData( $self, $response );
     }
@@ -389,12 +420,15 @@ sub _ProcessingRetrieveData {
             #         'Code: ' . $data->{code} . ' Error: ' . $data->{error} );
             # }
             else {
-                # print Dumper $response;    ## für Debugging
-                # print Dumper $data;    ## für Debugging
+                # print Dumper $response; ## for debugging
+                # print Dumper $data;     ## for debugging
 
                 $self->{cached}{current_date_time} =
                   _strftimeWrapper( "%a, %e %b %Y %H:%M",
                     localtime( $self->{fetchTime} ) );
+                $self->{cached}{current_forecast_date_time} =
+                  _strftimeWrapper( "%a, %e %b %Y %H:%M",
+                    localtime( $self->{forecastFetchTime} ) );
 
                 # $self->{cached}{timezone} = $data->{timezone};
                 $self->{cached}{license}{text} =
@@ -423,34 +457,22 @@ sub _ProcessingRetrieveData {
                     );
 
                     $self->{cached}{current} = {
-                        'dewPoint' =>
-                          int( sprintf( "%.1f", $data->{$unit}{dewpt} ) + 0.5 ),
-                        'heatIndex'   => $data->{$unit}{heatIndex},
+                        'dewPoint'  => sprintf( "%.1f", $data->{$unit}{dewpt} ),
+                        'heatIndex' => $data->{$unit}{heatIndex},
                         'precipRate'  => $data->{$unit}{precipRate},
                         'precipTotal' => $data->{$unit}{precipTotal},
-                        'pressure'    => int(
-                            sprintf( "%.1f", $data->{$unit}{pressure} ) + 0.5
-                        ),
+                        'pressure'    =>
+                          sprintf( "%.1f", $data->{$unit}{pressure} ),
                         'temperature' =>
-                          int( sprintf( "%.1f", $data->{$unit}{temp} ) + 0.5 ),
-                        'temp_c' =>
-                          int( sprintf( "%.1f", $data->{$unit}{temp} ) + 0.5 ),
-                        'wind_chill' => int(
-                            sprintf( "%.1f", ( $data->{$unit}{windChill} ) ) +
-                              0.5
-                        ),
-                        'windGust' => int(
-                            sprintf( "%.1f", ( $data->{$unit}{windGust} ) ) +
-                              0.5
-                        ),
-                        'wind' => int(
-                            sprintf( "%.1f", ( $data->{$unit}{windSpeed} ) ) +
-                              0.5
-                        ),
-                        'wind_speed' => int(
-                            sprintf( "%.1f", ( $data->{$unit}{windSpeed} ) ) +
-                              0.5
-                        ),
+                          sprintf( "%.1f", $data->{$unit}{temp} ),
+                        'temp_c'     => sprintf( "%.1f", $data->{$unit}{temp} ),
+                        'wind_chill' =>
+                          sprintf( "%.1f", $data->{$unit}{windChill} ),
+                        'windGust' =>
+                          sprintf( "%.1f", $data->{$unit}{windGust} ),
+                        'wind' => sprintf( "%.1f", $data->{$unit}{windSpeed} ),
+                        'wind_speed' =>
+                          sprintf( "%.1f", $data->{$unit}{windSpeed} ),
                         'wind_direction' => $data->{winddir},
                         'solarRadiation' => $data->{solarRadiation},
                         'uvIndex'        => $data->{uv},
@@ -742,7 +764,7 @@ sub _CallWeatherCallbackFn {
 
     my $self = shift;
 
-    #     ## Aufruf der callbackFn
+    ## Aufruf der callbackFn
     return FHEM::Core::Weather::RetrieveCallbackFn( $self->{devName} );
 }
 
@@ -754,6 +776,9 @@ sub _ErrorHandling {
 
     $self->{cached}{current_date_time} =
       _strftimeWrapper( "%a, %e %b %Y %H:%M", localtime( $self->{fetchTime} ) );
+    $self->{cached}{current_forecast_date_time} =
+      _strftimeWrapper( "%a, %e %b %Y %H:%M",
+        localtime( $self->{forecastFetchTime} ) );
     $self->{cached}{status}   = $err;
     $self->{cached}{validity} = 'stale';
 
diff --git a/lib/FHEM/Core/Weather.pm b/lib/FHEM/Core/Weather.pm
index 2408121..b6841f6 100644
--- a/lib/FHEM/Core/Weather.pm
+++ b/lib/FHEM/Core/Weather.pm
@@ -8,6 +8,7 @@
 #       Contributors:
 #         - Marko Oldenburg (CoolTux)
 #         - Lippie
+#         - stefanru (wundergroundAPI)
 #
 #
 #     This file is part of fhem.