[fronius] Fix communication errors by retrying failed http requests (#12255)

* [fronius] Fix communication errors by retrying failed http requests

Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
This commit is contained in:
jimtng 2022-02-16 08:50:37 +10:00 committed by GitHub
parent f70290a5ae
commit baa9aacf50
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 266 additions and 113 deletions

View File

@ -13,5 +13,4 @@
<artifactId>org.openhab.binding.fronius</artifactId> <artifactId>org.openhab.binding.fronius</artifactId>
<name>openHAB Add-ons :: Bundles :: Fronius Binding</name> <name>openHAB Add-ons :: Bundles :: Fronius Binding</name>
</project> </project>

View File

@ -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);
}
}

View File

@ -17,6 +17,8 @@ import static org.openhab.binding.fronius.internal.FroniusBindingConstants.*;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; 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.FroniusBridgeHandler;
import org.openhab.binding.fronius.internal.handler.FroniusMeterHandler; import org.openhab.binding.fronius.internal.handler.FroniusMeterHandler;
import org.openhab.binding.fronius.internal.handler.FroniusOhmpilotHandler; import org.openhab.binding.fronius.internal.handler.FroniusOhmpilotHandler;
@ -37,6 +39,7 @@ import org.osgi.service.component.annotations.Component;
* @author Hannes Spenger - Added ohmpilot * @author Hannes Spenger - Added ohmpilot
*/ */
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.fronius") @Component(service = ThingHandlerFactory.class, configurationPid = "binding.fronius")
@NonNullByDefault
public class FroniusHandlerFactory extends BaseThingHandlerFactory { public class FroniusHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = new HashSet<ThingTypeUID>() { private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = new HashSet<ThingTypeUID>() {
@ -56,7 +59,7 @@ public class FroniusHandlerFactory extends BaseThingHandlerFactory {
} }
@Override @Override
protected ThingHandler createHandler(Thing thing) { protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID(); ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (thingTypeUID.equals(THING_TYPE_INVERTER)) { if (thingTypeUID.equals(THING_TYPE_INVERTER)) {

View File

@ -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);
}
}
}

View File

@ -12,13 +12,15 @@
*/ */
package org.openhab.binding.fronius.internal.handler; package org.openhab.binding.fronius.internal.handler;
import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import org.eclipse.jdt.annotation.NonNull;
import org.openhab.binding.fronius.internal.FroniusBridgeConfiguration; 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.BaseFroniusResponse;
import org.openhab.binding.fronius.internal.api.HeadStatus;
import org.openhab.binding.fronius.internal.api.ValueUnit; 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.DecimalType;
import org.openhab.core.library.types.QuantityType; import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.StringType; 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.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail; import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseThingHandler; 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.Command;
import org.openhab.core.types.RefreshType; import org.openhab.core.types.RefreshType;
import org.openhab.core.types.State; import org.openhab.core.types.State;
@ -45,6 +46,7 @@ import com.google.gson.JsonSyntaxException;
* @author Gerrit Beine - Initial contribution * @author Gerrit Beine - Initial contribution
* @author Thomas Rokohl - Refactoring to merge the concepts * @author Thomas Rokohl - Refactoring to merge the concepts
* @author Thomas Kordelle - Added inverter power, battery state of charge and PV solar yield * @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 { public abstract class FroniusBaseThingHandler extends BaseThingHandler {
@ -69,30 +71,17 @@ public abstract class FroniusBaseThingHandler extends BaseThingHandler {
@Override @Override
public void initialize() { 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); logger.debug("Initializing {} Service", serviceDescription);
getFroniusBridgeHandler().registerService(this); // this is important so FroniusBridgeHandler::childHandlerInitialized gets called
}
private synchronized FroniusBridgeHandler getFroniusBridgeHandler() {
if (this.bridgeHandler == null) {
Bridge bridge = getBridge(); Bridge bridge = getBridge();
if (bridge == null) { if (bridge == null || bridge.getHandler() == null) {
return null; updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
} } else if (bridge.getStatus() == ThingStatus.ONLINE) {
ThingHandler handler = bridge.getHandler(); updateStatus(ThingStatus.UNKNOWN);
if (handler instanceof FroniusBridgeHandler) {
this.bridgeHandler = (FroniusBridgeHandler) handler;
} else { } else {
return null; updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
} }
} }
return this.bridgeHandler;
}
/** /**
* Update all Channels * Update all Channels
@ -135,7 +124,7 @@ public abstract class FroniusBaseThingHandler extends BaseThingHandler {
} else { } else {
logger.warn("Update channel {}: Unsupported value type {}", channelId, value.getClass().getSimpleName()); 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()); value.getClass().getSimpleName());
// Update the channel // Update the channel
@ -160,12 +149,30 @@ public abstract class FroniusBaseThingHandler extends BaseThingHandler {
protected abstract Object getValue(String channelId); 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 * this function is called from the bridge in a given interval
* *
* @param bridgeConfiguration the connected bridge configuration * @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 * @param url to request
* @return the object representation of the json response * @return the object representation of the json response
*/ */
protected <T extends BaseFroniusResponse> T collectDataFormUrl(Class<T> type, String url) { protected @NonNull <T extends BaseFroniusResponse> T collectDataFromUrl(Class<T> type, String url)
T result = null; throws FroniusCommunicationException {
boolean resultOk = false;
String errorMsg = null;
try { try {
logger.debug("URL = {}", url); int attempts = 1;
String response = HttpUtil.executeUrl("GET", url, API_TIMEOUT); while (true) {
logger.trace("Fetching URL = {}", url);
if (response != null) { String response = FroniusHttpUtil.executeUrl(url, API_TIMEOUT);
logger.debug("aqiResponse = {}", response); logger.trace("aqiResponse = {}", response);
result = gson.fromJson(response, type);
}
T result = gson.fromJson(response, type);
if (result == null) { if (result == null) {
errorMsg = "no data returned"; throw new FroniusCommunicationException("Empty json result");
} else {
if (result.getHead().getStatus().getCode() == 0) {
resultOk = true;
} else {
errorMsg = result.getHead().getStatus().getReason();
}
}
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 HeadStatus status = result.getHead().getStatus();
if (resultOk) { if (status.getCode() == 0) {
updateStatus(ThingStatus.ONLINE); return result;
} else { }
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, errorMsg);
// 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++;
}
} 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;
} }
} }

View File

@ -12,19 +12,23 @@
*/ */
package org.openhab.binding.fronius.internal.handler; package org.openhab.binding.fronius.internal.handler;
import java.io.IOException;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; 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.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.Bridge;
import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus; import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail; import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseBridgeHandler; import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.types.Command; import org.openhab.core.types.Command;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -35,13 +39,16 @@ import org.slf4j.LoggerFactory;
* @author Gerrit Beine - Initial contribution * @author Gerrit Beine - Initial contribution
* @author Thomas Rokohl - Refactoring to merge the concepts. * @author Thomas Rokohl - Refactoring to merge the concepts.
* Check if host is reachable. * Check if host is reachable.
* @author Jimmy Tanagra - Refactor the child services registration
* Refactor host online check
*/ */
@NonNullByDefault
public class FroniusBridgeHandler extends BaseBridgeHandler { public class FroniusBridgeHandler extends BaseBridgeHandler {
private final Logger logger = LoggerFactory.getLogger(FroniusBridgeHandler.class); private final Logger logger = LoggerFactory.getLogger(FroniusBridgeHandler.class);
private static final int DEFAULT_REFRESH_PERIOD = 10; private static final int DEFAULT_REFRESH_PERIOD = 10;
private final Set<FroniusBaseThingHandler> services = new HashSet<>(); private final Set<FroniusBaseThingHandler> services = new HashSet<>();
private ScheduledFuture<?> refreshJob; private @Nullable ScheduledFuture<?> refreshJob;
public FroniusBridgeHandler(Bridge bridge) { public FroniusBridgeHandler(Bridge bridge) {
super(bridge); super(bridge);
@ -51,10 +58,6 @@ public class FroniusBridgeHandler extends BaseBridgeHandler {
public void handleCommand(ChannelUID channelUID, Command command) { public void handleCommand(ChannelUID channelUID, Command command) {
} }
public void registerService(final FroniusBaseThingHandler service) {
this.services.add(service);
}
@Override @Override
public void initialize() { public void initialize() {
final FroniusBridgeConfiguration config = getConfigAs(FroniusBridgeConfiguration.class); final FroniusBridgeConfiguration config = getConfigAs(FroniusBridgeConfiguration.class);
@ -74,7 +77,7 @@ public class FroniusBridgeHandler extends BaseBridgeHandler {
} }
if (validConfig) { if (validConfig) {
startAutomaticRefresh(config); startAutomaticRefresh();
} else { } else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, errorMsg); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, errorMsg);
} }
@ -84,38 +87,59 @@ public class FroniusBridgeHandler extends BaseBridgeHandler {
public void dispose() { public void dispose() {
if (refreshJob != null) { if (refreshJob != null) {
refreshJob.cancel(true); 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 * Start the job refreshing the data
*/ */
private void startAutomaticRefresh(FroniusBridgeConfiguration config) { private void startAutomaticRefresh() {
if (refreshJob == null || refreshJob.isCancelled()) { if (refreshJob == null || refreshJob.isCancelled()) {
final FroniusBridgeConfiguration config = getConfigAs(FroniusBridgeConfiguration.class);
Runnable runnable = () -> { Runnable runnable = () -> {
boolean online = false;
try { try {
if (HttpUtil.executeUrl("GET", "http://" + config.hostname, 5000) != null) { checkBridgeOnline(config);
online = true; if (getThing().getStatus() != 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); updateStatus(ThingStatus.ONLINE);
}
for (FroniusBaseThingHandler service : services) { for (FroniusBaseThingHandler service : services) {
service.refresh(config); 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; 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);
}
} }

View File

@ -17,6 +17,7 @@ import java.util.Map;
import org.openhab.binding.fronius.internal.FroniusBaseDeviceConfiguration; import org.openhab.binding.fronius.internal.FroniusBaseDeviceConfiguration;
import org.openhab.binding.fronius.internal.FroniusBindingConstants; import org.openhab.binding.fronius.internal.FroniusBindingConstants;
import org.openhab.binding.fronius.internal.FroniusBridgeConfiguration; 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.MeterRealtimeBodyDataDTO;
import org.openhab.binding.fronius.internal.api.MeterRealtimeResponseDTO; import org.openhab.binding.fronius.internal.api.MeterRealtimeResponseDTO;
import org.openhab.core.library.types.QuantityType; import org.openhab.core.library.types.QuantityType;
@ -46,7 +47,7 @@ public class FroniusMeterHandler extends FroniusBaseThingHandler {
} }
@Override @Override
public void refresh(FroniusBridgeConfiguration bridgeConfiguration) { protected void handleRefresh(FroniusBridgeConfiguration bridgeConfiguration) throws FroniusCommunicationException {
updateData(bridgeConfiguration, config); updateData(bridgeConfiguration, config);
updateChannels(); updateChannels();
updateProperties(); updateProperties();
@ -134,15 +135,12 @@ public class FroniusMeterHandler extends FroniusBaseThingHandler {
/** /**
* Get new data * Get new data
*/ */
private void updateData(FroniusBridgeConfiguration bridgeConfiguration, FroniusBaseDeviceConfiguration config) { private void updateData(FroniusBridgeConfiguration bridgeConfiguration, FroniusBaseDeviceConfiguration config)
throws FroniusCommunicationException {
MeterRealtimeResponseDTO meterRealtimeResponse = getMeterRealtimeData(bridgeConfiguration.hostname, MeterRealtimeResponseDTO meterRealtimeResponse = getMeterRealtimeData(bridgeConfiguration.hostname,
config.deviceId); config.deviceId);
if (meterRealtimeResponse == null) {
meterRealtimeBodyData = null;
} else {
meterRealtimeBodyData = meterRealtimeResponse.getBody().getData(); meterRealtimeBodyData = meterRealtimeResponse.getBody().getData();
} }
}
/** /**
* Make the MeterRealtimeData request * Make the MeterRealtimeData request
@ -151,10 +149,11 @@ public class FroniusMeterHandler extends FroniusBaseThingHandler {
* @param deviceId of the device * @param deviceId of the device
* @return {MeterRealtimeResponse} the object representation of the json response * @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%", String location = FroniusBindingConstants.METER_REALTIME_DATA_URL.replace("%IP%",
(ip != null ? ip.trim() : "")); (ip != null ? ip.trim() : ""));
location = location.replace("%DEVICEID%", Integer.toString(deviceId)); location = location.replace("%DEVICEID%", Integer.toString(deviceId));
return collectDataFormUrl(MeterRealtimeResponseDTO.class, location); return collectDataFromUrl(MeterRealtimeResponseDTO.class, location);
} }
} }

View File

@ -17,6 +17,7 @@ import java.util.Map;
import org.openhab.binding.fronius.internal.FroniusBaseDeviceConfiguration; import org.openhab.binding.fronius.internal.FroniusBaseDeviceConfiguration;
import org.openhab.binding.fronius.internal.FroniusBindingConstants; import org.openhab.binding.fronius.internal.FroniusBindingConstants;
import org.openhab.binding.fronius.internal.FroniusBridgeConfiguration; 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.OhmpilotRealtimeBodyDataDTO;
import org.openhab.binding.fronius.internal.api.OhmpilotRealtimeResponseDTO; import org.openhab.binding.fronius.internal.api.OhmpilotRealtimeResponseDTO;
import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.DecimalType;
@ -46,7 +47,7 @@ public class FroniusOhmpilotHandler extends FroniusBaseThingHandler {
} }
@Override @Override
public void refresh(FroniusBridgeConfiguration bridgeConfiguration) { public void handleRefresh(FroniusBridgeConfiguration bridgeConfiguration) throws FroniusCommunicationException {
updateData(bridgeConfiguration, config); updateData(bridgeConfiguration, config);
updateChannels(); updateChannels();
updateProperties(); updateProperties();
@ -111,15 +112,12 @@ public class FroniusOhmpilotHandler extends FroniusBaseThingHandler {
/** /**
* Get new data * Get new data
*/ */
private void updateData(FroniusBridgeConfiguration bridgeConfiguration, FroniusBaseDeviceConfiguration config) { private void updateData(FroniusBridgeConfiguration bridgeConfiguration, FroniusBaseDeviceConfiguration config)
throws FroniusCommunicationException {
OhmpilotRealtimeResponseDTO ohmpilotRealtimeResponse = getOhmpilotRealtimeData(bridgeConfiguration.hostname, OhmpilotRealtimeResponseDTO ohmpilotRealtimeResponse = getOhmpilotRealtimeData(bridgeConfiguration.hostname,
config.deviceId); config.deviceId);
if (ohmpilotRealtimeResponse == null) {
ohmpilotRealtimeBodyData = null;
} else {
ohmpilotRealtimeBodyData = ohmpilotRealtimeResponse.getBody().getData(); ohmpilotRealtimeBodyData = ohmpilotRealtimeResponse.getBody().getData();
} }
}
/** /**
* Make the OhmpilotRealtimeData request * Make the OhmpilotRealtimeData request
@ -128,10 +126,11 @@ public class FroniusOhmpilotHandler extends FroniusBaseThingHandler {
* @param deviceId of the device * @param deviceId of the device
* @return {OhmpilotRealtimeResponse} the object representation of the json response * @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%", String location = FroniusBindingConstants.OHMPILOT_REALTIME_DATA_URL.replace("%IP%",
(ip != null ? ip.trim() : "")); (ip != null ? ip.trim() : ""));
location = location.replace("%DEVICEID%", Integer.toString(deviceId)); location = location.replace("%DEVICEID%", Integer.toString(deviceId));
return collectDataFormUrl(OhmpilotRealtimeResponseDTO.class, location); return collectDataFromUrl(OhmpilotRealtimeResponseDTO.class, location);
} }
} }

View File

@ -17,6 +17,7 @@ import java.util.Map;
import org.openhab.binding.fronius.internal.FroniusBaseDeviceConfiguration; import org.openhab.binding.fronius.internal.FroniusBaseDeviceConfiguration;
import org.openhab.binding.fronius.internal.FroniusBindingConstants; import org.openhab.binding.fronius.internal.FroniusBindingConstants;
import org.openhab.binding.fronius.internal.FroniusBridgeConfiguration; 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.InverterRealtimeResponse;
import org.openhab.binding.fronius.internal.api.PowerFlowRealtimeInverter; import org.openhab.binding.fronius.internal.api.PowerFlowRealtimeInverter;
import org.openhab.binding.fronius.internal.api.PowerFlowRealtimeResponse; import org.openhab.binding.fronius.internal.api.PowerFlowRealtimeResponse;
@ -57,7 +58,7 @@ public class FroniusSymoInverterHandler extends FroniusBaseThingHandler {
} }
@Override @Override
public void refresh(FroniusBridgeConfiguration bridgeConfiguration) { protected void handleRefresh(FroniusBridgeConfiguration bridgeConfiguration) throws FroniusCommunicationException {
updateData(bridgeConfiguration, config); updateData(bridgeConfiguration, config);
updateChannels(); updateChannels();
} }
@ -177,7 +178,8 @@ public class FroniusSymoInverterHandler extends FroniusBaseThingHandler {
/** /**
* Get new data * 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); inverterRealtimeResponse = getRealtimeData(bridgeConfiguration.hostname, config.deviceId);
powerFlowResponse = getPowerFlowRealtime(bridgeConfiguration.hostname); powerFlowResponse = getPowerFlowRealtime(bridgeConfiguration.hostname);
} }
@ -188,10 +190,10 @@ public class FroniusSymoInverterHandler extends FroniusBaseThingHandler {
* @param ip address of the device * @param ip address of the device
* @return {PowerFlowRealtimeResponse} the object representation of the json response * @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%", String location = FroniusBindingConstants.POWERFLOW_REALTIME_DATA.replace("%IP%",
(ip != null ? ip.trim() : "")); (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 * @param deviceId of the device
* @return {InverterRealtimeResponse} the object representation of the json response * @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%", String location = FroniusBindingConstants.INVERTER_REALTIME_DATA_URL.replace("%IP%",
(ip != null ? ip.trim() : "")); (ip != null ? ip.trim() : ""));
location = location.replace("%DEVICEID%", Integer.toString(deviceId)); location = location.replace("%DEVICEID%", Integer.toString(deviceId));
return collectDataFormUrl(InverterRealtimeResponse.class, location); return collectDataFromUrl(InverterRealtimeResponse.class, location);
} }
} }

View File

@ -13,7 +13,7 @@
<label>Hostname</label> <label>Hostname</label>
<description>The hostname or IP address of the Fronius gateway/device</description> <description>The hostname or IP address of the Fronius gateway/device</description>
</parameter> </parameter>
<parameter name="refreshInterval" type="integer" min="2"> <parameter name="refreshInterval" type="integer" min="1">
<label>Refresh Interval</label> <label>Refresh Interval</label>
<description>Specifies the refresh interval in seconds.</description> <description>Specifies the refresh interval in seconds.</description>
<default>10</default> <default>10</default>