]> git.basschouten.com Git - openhab-addons.git/commitdiff
[netatmo] Add a buffer to lower Weather API requests (#15590)
authorGaël L'hopital <gael@lhopital.org>
Sat, 30 Sep 2023 09:04:47 +0000 (11:04 +0200)
committerGitHub <noreply@github.com>
Sat, 30 Sep 2023 09:04:47 +0000 (11:04 +0200)
* Add a buffer to lower Weather API requests
* Correcting typo identified in PR #15587 after merge

---------

Signed-off-by: clinique <gael@lhopital.org>
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/dto/HomeData.java
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/ApiBridgeHandler.java
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/capability/CacheWeatherCapability.java [new file with mode: 0644]
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/capability/MeasureCapability.java
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/capability/RefreshCapability.java
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/capability/WeatherCapability.java

index 94bba8e54ef5c3e642e6c176f805f794d36f8266..824497a901b4bc4e0ad5a460e8090142b1e5199e 100644 (file)
@@ -86,7 +86,7 @@ public class HomeData extends NAThing implements NAModule, LocationEx {
     private @Nullable String timezone;
 
     private NAObjectMap<HomeDataRoom> rooms = new NAObjectMap<>();
-    private NAObjectMap<HomeDataModule> modules = new NAObjectMap<>();
+    private @Nullable NAObjectMap<HomeDataModule> modules;
 
     @Override
     public ModuleType getType() {
@@ -118,7 +118,8 @@ public class HomeData extends NAThing implements NAModule, LocationEx {
     }
 
     public NAObjectMap<HomeDataModule> getModules() {
-        return modules;
+        NAObjectMap<HomeDataModule> local = modules;
+        return local != null ? local : new NAObjectMap<>();
     }
 
     public Set<FeatureArea> getFeatures() {
index 10580177587fe5b63110c58c05a43c1a4aa0a4bd..340059da07747c151df7f98ff99a1f974436f71c 100644 (file)
@@ -302,7 +302,7 @@ public class ApiBridgeHandler extends BaseBridgeHandler {
     public synchronized <T> T executeUri(URI uri, HttpMethod method, Class<T> clazz, @Nullable String payload,
             @Nullable String contentType, int retryCount) throws NetatmoException {
         try {
-            logger.trace("executeUri {}  {} ", method.toString(), uri);
+            logger.debug("executeUri {}  {} ", method.toString(), uri);
 
             Request request = httpClient.newRequest(uri).method(method).timeout(TIMEOUT_S, TimeUnit.SECONDS);
 
diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/capability/CacheWeatherCapability.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/capability/CacheWeatherCapability.java
new file mode 100644 (file)
index 0000000..24c7260
--- /dev/null
@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) 2010-2023 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.netatmo.internal.handler.capability;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.netatmo.internal.api.WeatherApi;
+import org.openhab.binding.netatmo.internal.api.dto.NAObject;
+import org.openhab.binding.netatmo.internal.handler.CommonInterface;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * {@link CacheWeatherCapability} give the ability to buffer weather related requests and reduce server requests
+ *
+ * @author Gaël L'hopital - Initial contribution
+ *
+ */
+@NonNullByDefault
+public abstract class CacheWeatherCapability extends RestCapability<WeatherApi> {
+    private final Logger logger = LoggerFactory.getLogger(CacheWeatherCapability.class);
+    private final Duration validity;
+
+    private List<NAObject> lastResult = List.of();
+    private Instant requestTS = Instant.MIN;
+
+    public CacheWeatherCapability(CommonInterface handler, Duration validity) {
+        super(handler, WeatherApi.class);
+        this.validity = validity;
+    }
+
+    @Override
+    protected List<NAObject> updateReadings(WeatherApi api) {
+        Instant now = Instant.now();
+
+        if (requestTS.plus(validity).isBefore(now)) {
+            logger.debug("Requesting fresh data");
+            lastResult = getFreshData(api);
+            requestTS = now;
+        }
+
+        return lastResult;
+    }
+
+    protected abstract List<NAObject> getFreshData(WeatherApi api);
+}
index 9e1c3b2b57d60cb1e522c3e58f13b8beb16e50e1..738ae2acf00ea06f527a04de8594d0a92c5e7475 100644 (file)
@@ -14,6 +14,7 @@ package org.openhab.binding.netatmo.internal.handler.capability;
 
 import static org.openhab.binding.netatmo.internal.utils.ChannelTypeUtils.*;
 
+import java.time.Duration;
 import java.time.ZonedDateTime;
 import java.util.HashMap;
 import java.util.List;
@@ -42,12 +43,12 @@ import org.slf4j.LoggerFactory;
  *
  */
 @NonNullByDefault
-public class MeasureCapability extends RestCapability<WeatherApi> {
+public class MeasureCapability extends CacheWeatherCapability {
     private final Logger logger = LoggerFactory.getLogger(MeasureCapability.class);
     private final Map<String, State> measures = new HashMap<>();
 
     public MeasureCapability(CommonInterface handler, List<ChannelHelper> helpers) {
-        super(handler, WeatherApi.class);
+        super(handler, Duration.ofMinutes(30));
         MeasuresChannelHelper measureChannelHelper = (MeasuresChannelHelper) helpers.stream()
                 .filter(c -> c instanceof MeasuresChannelHelper).findFirst()
                 .orElseThrow(() -> new IllegalArgumentException(
@@ -55,15 +56,6 @@ public class MeasureCapability extends RestCapability<WeatherApi> {
         measureChannelHelper.setMeasures(measures);
     }
 
-    @Override
-    public List<NAObject> updateReadings(WeatherApi api) {
-        String bridgeId = handler.getBridgeId();
-        String deviceId = bridgeId != null ? bridgeId : handler.getId();
-        String moduleId = bridgeId != null ? handler.getId() : null;
-        updateMeasures(api, deviceId, moduleId);
-        return List.of();
-    }
-
     private void updateMeasures(WeatherApi api, String deviceId, @Nullable String moduleId) {
         measures.clear();
         handler.getActiveChannels().filter(channel -> !channel.getConfiguration().getProperties().isEmpty())
@@ -90,4 +82,13 @@ public class MeasureCapability extends RestCapability<WeatherApi> {
                     }
                 });
     }
+
+    @Override
+    protected List<NAObject> getFreshData(WeatherApi api) {
+        String bridgeId = handler.getBridgeId();
+        String deviceId = bridgeId != null ? bridgeId : handler.getId();
+        String moduleId = bridgeId != null ? handler.getId() : null;
+        updateMeasures(api, deviceId, moduleId);
+        return List.of();
+    }
 }
index 684fc4089aba1ed9baa58fb4a18ed8a7826283b7..258f10748eb476ac4ecae67831297751b9170317 100644 (file)
@@ -16,6 +16,7 @@ import static java.time.temporal.ChronoUnit.*;
 
 import java.time.Duration;
 import java.time.Instant;
+import java.time.ZonedDateTime;
 import java.util.Optional;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
@@ -47,7 +48,7 @@ public class RefreshCapability extends Capability {
     private Instant dataTimeStamp = Instant.now();
     private Instant dataTimeStamp0 = Instant.MIN;
     private Optional<ScheduledFuture<?>> refreshJob = Optional.empty();
-    private final boolean refreshConfigured;
+    private boolean refreshConfigured;
 
     public RefreshCapability(CommonInterface handler, ScheduledExecutorService scheduler, int refreshInterval) {
         super(handler);
@@ -86,27 +87,26 @@ public class RefreshCapability extends Capability {
             if (probing()) {
                 dataTimeStamp0 = Instant.MIN;
             }
-        } else if (refreshConfigured) {
-            delay = dataValidity.getSeconds();
         } else {
-            delay = (probing() ? PROBING_INTERVAL : dataValidity.minus(dataAge()).plus(DEFAULT_DELAY)).toSeconds();
+            delay = refreshConfigured ? dataValidity.getSeconds()
+                    : (probing() ? PROBING_INTERVAL : dataValidity.minus(dataAge()).plus(DEFAULT_DELAY)).toSeconds();
         }
         delay = delay < 2 ? PROBING_INTERVAL.toSeconds() : delay;
-        logger.debug("Module refreshed, next one in {} s", delay);
+        logger.debug("Module refreshed, next one in {}s", delay);
         freeJobAndReschedule(delay);
     }
 
     @Override
     protected void updateNAThing(NAThing newData) {
         super.updateNAThing(newData);
-        newData.getLastSeen().ifPresent(timestamp -> {
-            Instant tsInstant = timestamp.toInstant();
+        newData.getLastSeen().map(ZonedDateTime::toInstant).ifPresent(tsInstant -> {
             if (probing()) {
                 if (Instant.MIN.equals(dataTimeStamp0)) {
                     dataTimeStamp0 = tsInstant;
                     logger.debug("First data timestamp is {}", dataTimeStamp0);
                 } else if (tsInstant.isAfter(dataTimeStamp0)) {
                     dataValidity = Duration.between(dataTimeStamp0, tsInstant);
+                    refreshConfigured = true;
                     logger.debug("Data validity period identified to be {}", dataValidity);
                 } else {
                     logger.debug("Data validity period not yet found - data timestamp unchanged");
@@ -118,7 +118,7 @@ public class RefreshCapability extends Capability {
 
     private void freeJobAndReschedule(long delay) {
         refreshJob.ifPresent(job -> job.cancel(false));
-        refreshJob = delay == 0 ? Optional.empty()
-                : Optional.of(scheduler.schedule(() -> proceedWithUpdate(), delay, TimeUnit.SECONDS));
+        refreshJob = Optional
+                .ofNullable(delay == 0 ? null : scheduler.schedule(() -> proceedWithUpdate(), delay, TimeUnit.SECONDS));
     }
 }
index da64056e8c84fe7ec4edd58eaf0f1d9abf7a60ef..9d6a1b7e0fcc4c1d11d03af81510cd3f13eb373d 100644 (file)
@@ -12,6 +12,7 @@
  */
 package org.openhab.binding.netatmo.internal.handler.capability;
 
+import java.time.Duration;
 import java.util.List;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
@@ -23,21 +24,21 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * {@link WeatherCapability} give the ability to read weather station api
+ * {@link WeatherCapability} give the ability to read weather station API
  *
  * @author Gaël L'hopital - Initial contribution
  *
  */
 @NonNullByDefault
-public class WeatherCapability extends RestCapability<WeatherApi> {
+public class WeatherCapability extends CacheWeatherCapability {
     private final Logger logger = LoggerFactory.getLogger(WeatherCapability.class);
 
     public WeatherCapability(CommonInterface handler) {
-        super(handler, WeatherApi.class);
+        super(handler, Duration.ofSeconds(2));
     }
 
     @Override
-    protected List<NAObject> updateReadings(WeatherApi api) {
+    protected List<NAObject> getFreshData(WeatherApi api) {
         try {
             return List.of(owned ? api.getOwnedStationData(handler.getId()) : api.getStationData(handler.getId()));
         } catch (NetatmoException e) {