]> git.basschouten.com Git - openhab-addons.git/commitdiff
[fronius] Fix communication errors by retrying failed http requests (#12255)
authorjimtng <2554958+jimtng@users.noreply.github.com>
Tue, 15 Feb 2022 22:50:37 +0000 (08:50 +1000)
committerGitHub <noreply@github.com>
Tue, 15 Feb 2022 22:50:37 +0000 (23:50 +0100)
* [fronius] Fix communication errors by retrying failed http requests

Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
bundles/org.openhab.binding.fronius/pom.xml
bundles/org.openhab.binding.fronius/src/main/java/org/openhab/binding/fronius/internal/FroniusCommunicationException.java [new file with mode: 0644]
bundles/org.openhab.binding.fronius/src/main/java/org/openhab/binding/fronius/internal/FroniusHandlerFactory.java
bundles/org.openhab.binding.fronius/src/main/java/org/openhab/binding/fronius/internal/FroniusHttpUtil.java [new file with mode: 0644]
bundles/org.openhab.binding.fronius/src/main/java/org/openhab/binding/fronius/internal/handler/FroniusBaseThingHandler.java
bundles/org.openhab.binding.fronius/src/main/java/org/openhab/binding/fronius/internal/handler/FroniusBridgeHandler.java
bundles/org.openhab.binding.fronius/src/main/java/org/openhab/binding/fronius/internal/handler/FroniusMeterHandler.java
bundles/org.openhab.binding.fronius/src/main/java/org/openhab/binding/fronius/internal/handler/FroniusOhmpilotHandler.java
bundles/org.openhab.binding.fronius/src/main/java/org/openhab/binding/fronius/internal/handler/FroniusSymoInverterHandler.java
bundles/org.openhab.binding.fronius/src/main/resources/OH-INF/thing/bridge.xml

index fb9121d038202491386885609685469d6486ef33..db0a962bc49c73b3f798394e80fd668e0049338e 100644 (file)
@@ -13,5 +13,4 @@
   <artifactId>org.openhab.binding.fronius</artifactId>
 
   <name>openHAB Add-ons :: Bundles :: Fronius Binding</name>
-
 </project>
diff --git a/bundles/org.openhab.binding.fronius/src/main/java/org/openhab/binding/fronius/internal/FroniusCommunicationException.java b/bundles/org.openhab.binding.fronius/src/main/java/org/openhab/binding/fronius/internal/FroniusCommunicationException.java
new file mode 100644 (file)
index 0000000..93fc10d
--- /dev/null
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2010-2022 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.fronius.internal;
+
+import java.io.IOException;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * Exception for unexpected response from or communication failure with the Fronius controller.
+ *
+ * @author Jimmy Tanagra - Initial contribution
+ */
+@NonNullByDefault
+public class FroniusCommunicationException extends IOException {
+    private static final long serialVersionUID = 619020705591964155L;
+
+    public FroniusCommunicationException(String message) {
+        super(message);
+    }
+
+    public FroniusCommunicationException(Throwable ex) {
+        super(ex);
+    }
+
+    public FroniusCommunicationException(String message, @Nullable Throwable cause) {
+        super(message, cause);
+    }
+}
index 15fea161047720a6840991120c30adb64b3b0233..cf2eda7ab964ead7779a4d03b8c28905d97275b3 100644 (file)
@@ -17,6 +17,8 @@ import static org.openhab.binding.fronius.internal.FroniusBindingConstants.*;
 import java.util.HashSet;
 import java.util.Set;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.fronius.internal.handler.FroniusBridgeHandler;
 import org.openhab.binding.fronius.internal.handler.FroniusMeterHandler;
 import org.openhab.binding.fronius.internal.handler.FroniusOhmpilotHandler;
@@ -37,6 +39,7 @@ import org.osgi.service.component.annotations.Component;
  * @author Hannes Spenger - Added ohmpilot
  */
 @Component(service = ThingHandlerFactory.class, configurationPid = "binding.fronius")
+@NonNullByDefault
 public class FroniusHandlerFactory extends BaseThingHandlerFactory {
 
     private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = new HashSet<ThingTypeUID>() {
@@ -56,7 +59,7 @@ public class FroniusHandlerFactory extends BaseThingHandlerFactory {
     }
 
     @Override
-    protected ThingHandler createHandler(Thing thing) {
+    protected @Nullable ThingHandler createHandler(Thing thing) {
         ThingTypeUID thingTypeUID = thing.getThingTypeUID();
 
         if (thingTypeUID.equals(THING_TYPE_INVERTER)) {
diff --git a/bundles/org.openhab.binding.fronius/src/main/java/org/openhab/binding/fronius/internal/FroniusHttpUtil.java b/bundles/org.openhab.binding.fronius/src/main/java/org/openhab/binding/fronius/internal/FroniusHttpUtil.java
new file mode 100644 (file)
index 0000000..63a4bda
--- /dev/null
@@ -0,0 +1,79 @@
+/**
+ * Copyright (c) 2010-2022 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.fronius.internal;
+
+import java.io.IOException;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.io.net.http.HttpUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 
+ * A version of HttpUtil implementation that retries on failure
+ *
+ * @author Jimmy Tanagra - Initial contribution
+ * 
+ */
+@NonNullByDefault
+public class FroniusHttpUtil {
+    private static final Logger logger = LoggerFactory.getLogger(FroniusHttpUtil.class);
+
+    /**
+     * Issue a HTTP GET request and retry on failure
+     *
+     * @param url the url to execute
+     * @param timeout the socket timeout in milliseconds to wait for data
+     * @return the response body
+     * @throws FroniusCommunicationException when the request execution failed or interrupted
+     */
+    public synchronized static String executeUrl(String url, int timeout) throws FroniusCommunicationException {
+        int attemptCount = 1;
+        try {
+            while (true) {
+                Throwable lastException = null;
+                String result = null;
+                try {
+                    result = HttpUtil.executeUrl("GET", url, timeout);
+                } catch (IOException e) {
+                    // HttpUtil::executeUrl wraps InterruptedException into IOException.
+                    // Unwrap and rethrow it so that we don't retry on InterruptedException
+                    if (e.getCause() instanceof InterruptedException) {
+                        throw (InterruptedException) e.getCause();
+                    }
+                    lastException = e;
+                }
+
+                if (result != null) {
+                    if (attemptCount > 1) {
+                        logger.debug("Attempt #{} successful {}", attemptCount, url);
+                    }
+                    return result;
+                }
+
+                if (attemptCount >= 3) {
+                    logger.debug("Failed connecting to {} after {} attempts.", url, attemptCount, lastException);
+                    throw new FroniusCommunicationException("Unable to connect", lastException);
+                }
+
+                logger.debug("HTTP error on attempt #{} {}", attemptCount, url);
+                Thread.sleep(500 * attemptCount);
+                attemptCount++;
+            }
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            throw new FroniusCommunicationException("Interrupted", e);
+        }
+    }
+}
index 7526763308305f4df062cf35de2b6665d4aaaa44..974d45bd1a3613ce5dcbebc7c3987496cd6bfca9 100644 (file)
  */
 package org.openhab.binding.fronius.internal.handler;
 
-import java.io.IOException;
 import java.math.BigDecimal;
 
+import org.eclipse.jdt.annotation.NonNull;
 import org.openhab.binding.fronius.internal.FroniusBridgeConfiguration;
+import org.openhab.binding.fronius.internal.FroniusCommunicationException;
+import org.openhab.binding.fronius.internal.FroniusHttpUtil;
 import org.openhab.binding.fronius.internal.api.BaseFroniusResponse;
+import org.openhab.binding.fronius.internal.api.HeadStatus;
 import org.openhab.binding.fronius.internal.api.ValueUnit;
-import org.openhab.core.io.net.http.HttpUtil;
 import org.openhab.core.library.types.DecimalType;
 import org.openhab.core.library.types.QuantityType;
 import org.openhab.core.library.types.StringType;
@@ -29,7 +31,6 @@ import org.openhab.core.thing.Thing;
 import org.openhab.core.thing.ThingStatus;
 import org.openhab.core.thing.ThingStatusDetail;
 import org.openhab.core.thing.binding.BaseThingHandler;
-import org.openhab.core.thing.binding.ThingHandler;
 import org.openhab.core.types.Command;
 import org.openhab.core.types.RefreshType;
 import org.openhab.core.types.State;
@@ -45,6 +46,7 @@ import com.google.gson.JsonSyntaxException;
  * @author Gerrit Beine - Initial contribution
  * @author Thomas Rokohl - Refactoring to merge the concepts
  * @author Thomas Kordelle - Added inverter power, battery state of charge and PV solar yield
+ * @author Jimmy Tanagra - Implement connection retry
  */
 public abstract class FroniusBaseThingHandler extends BaseThingHandler {
 
@@ -69,29 +71,16 @@ public abstract class FroniusBaseThingHandler extends BaseThingHandler {
 
     @Override
     public void initialize() {
-        if (getFroniusBridgeHandler() == null) {
-            logger.debug("Initializing {} Service is only supported within a bridge", serviceDescription);
-            updateStatus(ThingStatus.OFFLINE);
-            return;
-        }
         logger.debug("Initializing {} Service", serviceDescription);
-        getFroniusBridgeHandler().registerService(this);
-    }
-
-    private synchronized FroniusBridgeHandler getFroniusBridgeHandler() {
-        if (this.bridgeHandler == null) {
-            Bridge bridge = getBridge();
-            if (bridge == null) {
-                return null;
-            }
-            ThingHandler handler = bridge.getHandler();
-            if (handler instanceof FroniusBridgeHandler) {
-                this.bridgeHandler = (FroniusBridgeHandler) handler;
-            } else {
-                return null;
-            }
+        // this is important so FroniusBridgeHandler::childHandlerInitialized gets called
+        Bridge bridge = getBridge();
+        if (bridge == null || bridge.getHandler() == null) {
+            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
+        } else if (bridge.getStatus() == ThingStatus.ONLINE) {
+            updateStatus(ThingStatus.UNKNOWN);
+        } else {
+            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
         }
-        return this.bridgeHandler;
     }
 
     /**
@@ -135,7 +124,7 @@ public abstract class FroniusBaseThingHandler extends BaseThingHandler {
         } else {
             logger.warn("Update channel {}: Unsupported value type {}", channelId, value.getClass().getSimpleName());
         }
-        logger.debug("Update channel {} with state {} ({})", channelId, (state == null) ? "null" : state.toString(),
+        logger.trace("Update channel {} with state {} ({})", channelId, (state == null) ? "null" : state.toString(),
                 value.getClass().getSimpleName());
 
         // Update the channel
@@ -160,12 +149,30 @@ public abstract class FroniusBaseThingHandler extends BaseThingHandler {
     protected abstract Object getValue(String channelId);
 
     /**
-     * do whatever a thing must do to update the values
+     * Called by the bridge to fetch data and update channels
+     *
+     * @param bridgeConfiguration the connected bridge configuration
+     */
+    public void refresh(FroniusBridgeConfiguration bridgeConfiguration) {
+        try {
+            handleRefresh(bridgeConfiguration);
+            if (getThing().getStatus() != ThingStatus.ONLINE) {
+                updateStatus(ThingStatus.ONLINE);
+            }
+        } catch (FroniusCommunicationException | RuntimeException e) {
+            logger.debug("Exception caught in refresh() for {}", getThing().getUID().getId(), e);
+            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
+        }
+    }
+
+    /**
+     * This method should be overridden to do whatever a thing must do to update its channels
      * this function is called from the bridge in a given interval
      *
      * @param bridgeConfiguration the connected bridge configuration
      */
-    public abstract void refresh(FroniusBridgeConfiguration bridgeConfiguration);
+    protected abstract void handleRefresh(FroniusBridgeConfiguration bridgeConfiguration)
+            throws FroniusCommunicationException;
 
     /**
      *
@@ -173,46 +180,47 @@ public abstract class FroniusBaseThingHandler extends BaseThingHandler {
      * @param url to request
      * @return the object representation of the json response
      */
-    protected <T extends BaseFroniusResponse> T collectDataFormUrl(Class<T> type, String url) {
-        T result = null;
-        boolean resultOk = false;
-        String errorMsg = null;
-
+    protected @NonNull <T extends BaseFroniusResponse> T collectDataFromUrl(Class<T> type, String url)
+            throws FroniusCommunicationException {
         try {
-            logger.debug("URL = {}", url);
-            String response = HttpUtil.executeUrl("GET", url, API_TIMEOUT);
+            int attempts = 1;
+            while (true) {
+                logger.trace("Fetching URL = {}", url);
+                String response = FroniusHttpUtil.executeUrl(url, API_TIMEOUT);
+                logger.trace("aqiResponse = {}", response);
+
+                T result = gson.fromJson(response, type);
+                if (result == null) {
+                    throw new FroniusCommunicationException("Empty json result");
+                }
 
-            if (response != null) {
-                logger.debug("aqiResponse = {}", response);
-                result = gson.fromJson(response, type);
-            }
+                HeadStatus status = result.getHead().getStatus();
+                if (status.getCode() == 0) {
+                    return result;
+                }
 
-            if (result == null) {
-                errorMsg = "no data returned";
-            } else {
-                if (result.getHead().getStatus().getCode() == 0) {
-                    resultOk = true;
-                } else {
-                    errorMsg = result.getHead().getStatus().getReason();
+                // Sometimes Fronius would return a HTTP status 200 with a proper JSON data
+                // with Reason: Transfer timeout.
+                //
+                // "Status" : {
+                // "Code" : 8,
+                // "Reason" : "Transfer timeout.",
+                // "UserMessage" : ""
+                // },
+                logger.debug("Error from Fronius attempt #{}: {} - {}", attempts, status.getCode(), status.getReason());
+                if (attempts >= 3) {
+                    throw new FroniusCommunicationException(status.getReason());
                 }
+                Thread.sleep(500 * attempts);
+                attempts++;
             }
-            if (!resultOk) {
-                logger.debug("Error in fronius response: {}", errorMsg);
-            }
-        } catch (JsonSyntaxException | NumberFormatException e) {
-            errorMsg = "Invalid JSON data received";
-            logger.debug("Error running fronius request: {}", e.getMessage());
-        } catch (IOException | IllegalStateException e) {
-            errorMsg = e.getMessage();
-            logger.debug("Error running fronius request: {}", errorMsg);
-        }
 
-        // Update the thing status
-        if (resultOk) {
-            updateStatus(ThingStatus.ONLINE);
-        } else {
-            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, errorMsg);
+        } catch (JsonSyntaxException | NumberFormatException e) {
+            logger.debug("Received Invalid JSON Data", e);
+            throw new FroniusCommunicationException("Invalid JSON data received", e);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            throw new FroniusCommunicationException("Data collection interrupted", e);
         }
-        return resultOk ? result : null;
     }
 }
index 1256f064c98e8fe3ef4657f5aff0435e36462a04..a2f023bfe783bb14e866cb62ba6f1b92ab2f5090 100644 (file)
  */
 package org.openhab.binding.fronius.internal.handler;
 
-import java.io.IOException;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.fronius.internal.FroniusBridgeConfiguration;
-import org.openhab.core.io.net.http.HttpUtil;
+import org.openhab.binding.fronius.internal.FroniusCommunicationException;
+import org.openhab.binding.fronius.internal.FroniusHttpUtil;
 import org.openhab.core.thing.Bridge;
 import org.openhab.core.thing.ChannelUID;
+import org.openhab.core.thing.Thing;
 import org.openhab.core.thing.ThingStatus;
 import org.openhab.core.thing.ThingStatusDetail;
 import org.openhab.core.thing.binding.BaseBridgeHandler;
+import org.openhab.core.thing.binding.ThingHandler;
 import org.openhab.core.types.Command;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -35,13 +39,16 @@ import org.slf4j.LoggerFactory;
  * @author Gerrit Beine - Initial contribution
  * @author Thomas Rokohl - Refactoring to merge the concepts.
  *         Check if host is reachable.
+ * @author Jimmy Tanagra - Refactor the child services registration
+ *         Refactor host online check
  */
+@NonNullByDefault
 public class FroniusBridgeHandler extends BaseBridgeHandler {
 
     private final Logger logger = LoggerFactory.getLogger(FroniusBridgeHandler.class);
     private static final int DEFAULT_REFRESH_PERIOD = 10;
     private final Set<FroniusBaseThingHandler> services = new HashSet<>();
-    private ScheduledFuture<?> refreshJob;
+    private @Nullable ScheduledFuture<?> refreshJob;
 
     public FroniusBridgeHandler(Bridge bridge) {
         super(bridge);
@@ -51,10 +58,6 @@ public class FroniusBridgeHandler extends BaseBridgeHandler {
     public void handleCommand(ChannelUID channelUID, Command command) {
     }
 
-    public void registerService(final FroniusBaseThingHandler service) {
-        this.services.add(service);
-    }
-
     @Override
     public void initialize() {
         final FroniusBridgeConfiguration config = getConfigAs(FroniusBridgeConfiguration.class);
@@ -74,7 +77,7 @@ public class FroniusBridgeHandler extends BaseBridgeHandler {
         }
 
         if (validConfig) {
-            startAutomaticRefresh(config);
+            startAutomaticRefresh();
         } else {
             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, errorMsg);
         }
@@ -84,38 +87,59 @@ public class FroniusBridgeHandler extends BaseBridgeHandler {
     public void dispose() {
         if (refreshJob != null) {
             refreshJob.cancel(true);
+            refreshJob = null;
+        }
+    }
+
+    @Override
+    public void childHandlerInitialized(ThingHandler childHandler, Thing childThing) {
+        if (childHandler instanceof FroniusBaseThingHandler) {
+            this.services.add((FroniusBaseThingHandler) childHandler);
+            restartAutomaticRefresh();
+        } else {
+            logger.debug("Child handler {} not added because it is not an instance of FroniusBaseThingHandler",
+                    childThing.getUID().getId());
+        }
+    }
+
+    @Override
+    public void childHandlerDisposed(ThingHandler childHandler, Thing childThing) {
+        this.services.remove((FroniusBaseThingHandler) childHandler);
+    }
+
+    private void restartAutomaticRefresh() {
+        if (refreshJob != null) { // refreshJob should be null if the config isn't valid
+            refreshJob.cancel(false);
+            startAutomaticRefresh();
         }
-        services.clear();
     }
 
     /**
      * Start the job refreshing the data
      */
-    private void startAutomaticRefresh(FroniusBridgeConfiguration config) {
+    private void startAutomaticRefresh() {
         if (refreshJob == null || refreshJob.isCancelled()) {
+            final FroniusBridgeConfiguration config = getConfigAs(FroniusBridgeConfiguration.class);
             Runnable runnable = () -> {
-                boolean online = false;
                 try {
-                    if (HttpUtil.executeUrl("GET", "http://" + config.hostname, 5000) != null) {
-                        online = true;
+                    checkBridgeOnline(config);
+                    if (getThing().getStatus() != ThingStatus.ONLINE) {
+                        updateStatus(ThingStatus.ONLINE);
                     }
-                } catch (IOException e) {
-                    logger.debug("Connection Error: {}", e.getMessage());
-                }
-
-                if (!online) {
-                    updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
-                            "hostname or ip is not reachable");
-                } else {
-                    updateStatus(ThingStatus.ONLINE);
                     for (FroniusBaseThingHandler service : services) {
                         service.refresh(config);
                     }
+                } catch (FroniusCommunicationException e) {
+                    updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, e.getMessage());
                 }
             };
 
             int delay = (config.refreshInterval != null) ? config.refreshInterval.intValue() : DEFAULT_REFRESH_PERIOD;
-            refreshJob = scheduler.scheduleWithFixedDelay(runnable, 0, delay, TimeUnit.SECONDS);
+            refreshJob = scheduler.scheduleWithFixedDelay(runnable, 1, delay, TimeUnit.SECONDS);
         }
     }
+
+    private void checkBridgeOnline(FroniusBridgeConfiguration config) throws FroniusCommunicationException {
+        FroniusHttpUtil.executeUrl("http://" + config.hostname, 5000);
+    }
 }
index 32bafbf7a1c357230d71c7a38049c77d352bdfb8..5d3910275ed6898409c7afc04e3be5e537286f00 100644 (file)
@@ -17,6 +17,7 @@ import java.util.Map;
 import org.openhab.binding.fronius.internal.FroniusBaseDeviceConfiguration;
 import org.openhab.binding.fronius.internal.FroniusBindingConstants;
 import org.openhab.binding.fronius.internal.FroniusBridgeConfiguration;
+import org.openhab.binding.fronius.internal.FroniusCommunicationException;
 import org.openhab.binding.fronius.internal.api.MeterRealtimeBodyDataDTO;
 import org.openhab.binding.fronius.internal.api.MeterRealtimeResponseDTO;
 import org.openhab.core.library.types.QuantityType;
@@ -46,7 +47,7 @@ public class FroniusMeterHandler extends FroniusBaseThingHandler {
     }
 
     @Override
-    public void refresh(FroniusBridgeConfiguration bridgeConfiguration) {
+    protected void handleRefresh(FroniusBridgeConfiguration bridgeConfiguration) throws FroniusCommunicationException {
         updateData(bridgeConfiguration, config);
         updateChannels();
         updateProperties();
@@ -134,14 +135,11 @@ public class FroniusMeterHandler extends FroniusBaseThingHandler {
     /**
      * Get new data
      */
-    private void updateData(FroniusBridgeConfiguration bridgeConfiguration, FroniusBaseDeviceConfiguration config) {
+    private void updateData(FroniusBridgeConfiguration bridgeConfiguration, FroniusBaseDeviceConfiguration config)
+            throws FroniusCommunicationException {
         MeterRealtimeResponseDTO meterRealtimeResponse = getMeterRealtimeData(bridgeConfiguration.hostname,
                 config.deviceId);
-        if (meterRealtimeResponse == null) {
-            meterRealtimeBodyData = null;
-        } else {
-            meterRealtimeBodyData = meterRealtimeResponse.getBody().getData();
-        }
+        meterRealtimeBodyData = meterRealtimeResponse.getBody().getData();
     }
 
     /**
@@ -151,10 +149,11 @@ public class FroniusMeterHandler extends FroniusBaseThingHandler {
      * @param deviceId of the device
      * @return {MeterRealtimeResponse} the object representation of the json response
      */
-    private MeterRealtimeResponseDTO getMeterRealtimeData(String ip, int deviceId) {
+    private MeterRealtimeResponseDTO getMeterRealtimeData(String ip, int deviceId)
+            throws FroniusCommunicationException {
         String location = FroniusBindingConstants.METER_REALTIME_DATA_URL.replace("%IP%",
                 (ip != null ? ip.trim() : ""));
         location = location.replace("%DEVICEID%", Integer.toString(deviceId));
-        return collectDataFormUrl(MeterRealtimeResponseDTO.class, location);
+        return collectDataFromUrl(MeterRealtimeResponseDTO.class, location);
     }
 }
index a0ec420405e863ccba2d522332508dd032b6232d..a61917a967a5b3877b67a7a9417448c16384ff83 100644 (file)
@@ -17,6 +17,7 @@ import java.util.Map;
 import org.openhab.binding.fronius.internal.FroniusBaseDeviceConfiguration;
 import org.openhab.binding.fronius.internal.FroniusBindingConstants;
 import org.openhab.binding.fronius.internal.FroniusBridgeConfiguration;
+import org.openhab.binding.fronius.internal.FroniusCommunicationException;
 import org.openhab.binding.fronius.internal.api.OhmpilotRealtimeBodyDataDTO;
 import org.openhab.binding.fronius.internal.api.OhmpilotRealtimeResponseDTO;
 import org.openhab.core.library.types.DecimalType;
@@ -46,7 +47,7 @@ public class FroniusOhmpilotHandler extends FroniusBaseThingHandler {
     }
 
     @Override
-    public void refresh(FroniusBridgeConfiguration bridgeConfiguration) {
+    public void handleRefresh(FroniusBridgeConfiguration bridgeConfiguration) throws FroniusCommunicationException {
         updateData(bridgeConfiguration, config);
         updateChannels();
         updateProperties();
@@ -111,14 +112,11 @@ public class FroniusOhmpilotHandler extends FroniusBaseThingHandler {
     /**
      * Get new data
      */
-    private void updateData(FroniusBridgeConfiguration bridgeConfiguration, FroniusBaseDeviceConfiguration config) {
+    private void updateData(FroniusBridgeConfiguration bridgeConfiguration, FroniusBaseDeviceConfiguration config)
+            throws FroniusCommunicationException {
         OhmpilotRealtimeResponseDTO ohmpilotRealtimeResponse = getOhmpilotRealtimeData(bridgeConfiguration.hostname,
                 config.deviceId);
-        if (ohmpilotRealtimeResponse == null) {
-            ohmpilotRealtimeBodyData = null;
-        } else {
-            ohmpilotRealtimeBodyData = ohmpilotRealtimeResponse.getBody().getData();
-        }
+        ohmpilotRealtimeBodyData = ohmpilotRealtimeResponse.getBody().getData();
     }
 
     /**
@@ -128,10 +126,11 @@ public class FroniusOhmpilotHandler extends FroniusBaseThingHandler {
      * @param deviceId of the device
      * @return {OhmpilotRealtimeResponse} the object representation of the json response
      */
-    private OhmpilotRealtimeResponseDTO getOhmpilotRealtimeData(String ip, int deviceId) {
+    private OhmpilotRealtimeResponseDTO getOhmpilotRealtimeData(String ip, int deviceId)
+            throws FroniusCommunicationException {
         String location = FroniusBindingConstants.OHMPILOT_REALTIME_DATA_URL.replace("%IP%",
                 (ip != null ? ip.trim() : ""));
         location = location.replace("%DEVICEID%", Integer.toString(deviceId));
-        return collectDataFormUrl(OhmpilotRealtimeResponseDTO.class, location);
+        return collectDataFromUrl(OhmpilotRealtimeResponseDTO.class, location);
     }
 }
index c36965235e52e3bb8ab90bdb2ada80a665c959b9..d5ea05953febe5483fb305e68170cbc3c28786cc 100644 (file)
@@ -17,6 +17,7 @@ import java.util.Map;
 import org.openhab.binding.fronius.internal.FroniusBaseDeviceConfiguration;
 import org.openhab.binding.fronius.internal.FroniusBindingConstants;
 import org.openhab.binding.fronius.internal.FroniusBridgeConfiguration;
+import org.openhab.binding.fronius.internal.FroniusCommunicationException;
 import org.openhab.binding.fronius.internal.api.InverterRealtimeResponse;
 import org.openhab.binding.fronius.internal.api.PowerFlowRealtimeInverter;
 import org.openhab.binding.fronius.internal.api.PowerFlowRealtimeResponse;
@@ -57,7 +58,7 @@ public class FroniusSymoInverterHandler extends FroniusBaseThingHandler {
     }
 
     @Override
-    public void refresh(FroniusBridgeConfiguration bridgeConfiguration) {
+    protected void handleRefresh(FroniusBridgeConfiguration bridgeConfiguration) throws FroniusCommunicationException {
         updateData(bridgeConfiguration, config);
         updateChannels();
     }
@@ -177,7 +178,8 @@ public class FroniusSymoInverterHandler extends FroniusBaseThingHandler {
     /**
      * Get new data
      */
-    private void updateData(FroniusBridgeConfiguration bridgeConfiguration, FroniusBaseDeviceConfiguration config) {
+    private void updateData(FroniusBridgeConfiguration bridgeConfiguration, FroniusBaseDeviceConfiguration config)
+            throws FroniusCommunicationException {
         inverterRealtimeResponse = getRealtimeData(bridgeConfiguration.hostname, config.deviceId);
         powerFlowResponse = getPowerFlowRealtime(bridgeConfiguration.hostname);
     }
@@ -188,10 +190,10 @@ public class FroniusSymoInverterHandler extends FroniusBaseThingHandler {
      * @param ip address of the device
      * @return {PowerFlowRealtimeResponse} the object representation of the json response
      */
-    private PowerFlowRealtimeResponse getPowerFlowRealtime(String ip) {
+    private PowerFlowRealtimeResponse getPowerFlowRealtime(String ip) throws FroniusCommunicationException {
         String location = FroniusBindingConstants.POWERFLOW_REALTIME_DATA.replace("%IP%",
                 (ip != null ? ip.trim() : ""));
-        return collectDataFormUrl(PowerFlowRealtimeResponse.class, location);
+        return collectDataFromUrl(PowerFlowRealtimeResponse.class, location);
     }
 
     /**
@@ -201,10 +203,10 @@ public class FroniusSymoInverterHandler extends FroniusBaseThingHandler {
      * @param deviceId of the device
      * @return {InverterRealtimeResponse} the object representation of the json response
      */
-    private InverterRealtimeResponse getRealtimeData(String ip, int deviceId) {
+    private InverterRealtimeResponse getRealtimeData(String ip, int deviceId) throws FroniusCommunicationException {
         String location = FroniusBindingConstants.INVERTER_REALTIME_DATA_URL.replace("%IP%",
                 (ip != null ? ip.trim() : ""));
         location = location.replace("%DEVICEID%", Integer.toString(deviceId));
-        return collectDataFormUrl(InverterRealtimeResponse.class, location);
+        return collectDataFromUrl(InverterRealtimeResponse.class, location);
     }
 }
index 756ebb0691c0051bbb73414aa4c9a0d85e4f2351..462889377f57a575642b8032fa31675894467e2f 100644 (file)
@@ -13,7 +13,7 @@
                                <label>Hostname</label>
                                <description>The hostname or IP address of the Fronius gateway/device</description>
                        </parameter>
-                       <parameter name="refreshInterval" type="integer" min="2">
+                       <parameter name="refreshInterval" type="integer" min="1">
                                <label>Refresh Interval</label>
                                <description>Specifies the refresh interval in seconds.</description>
                                <default>10</default>