2 * Copyright (c) 2010-2020 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.fronius.internal.handler;
15 import java.io.IOException;
17 import org.apache.commons.lang.StringUtils;
18 import org.openhab.binding.fronius.internal.FroniusBaseDeviceConfiguration;
19 import org.openhab.binding.fronius.internal.FroniusBindingConstants;
20 import org.openhab.binding.fronius.internal.FroniusBridgeConfiguration;
21 import org.openhab.binding.fronius.internal.api.BaseFroniusResponse;
22 import org.openhab.binding.fronius.internal.api.InverterRealtimeResponse;
23 import org.openhab.binding.fronius.internal.api.PowerFlowRealtimeResponse;
24 import org.openhab.binding.fronius.internal.api.ValueUnit;
25 import org.openhab.core.io.net.http.HttpUtil;
26 import org.openhab.core.thing.Thing;
27 import org.openhab.core.thing.ThingStatus;
28 import org.openhab.core.thing.ThingStatusDetail;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
32 import com.google.gson.Gson;
33 import com.google.gson.JsonSyntaxException;
36 * The {@link FroniusSymoInverterHandler} is responsible for updating the data, which are
37 * sent to one of the channels.
39 * @author Thomas Rokohl - Initial contribution
40 * @author Peter Schraffl - Added device status and error status channels
42 public class FroniusSymoInverterHandler extends FroniusBaseThingHandler {
44 private static final int API_TIMEOUT = 5000;
45 private final Logger logger = LoggerFactory.getLogger(FroniusSymoInverterHandler.class);
46 private InverterRealtimeResponse inverterRealtimeResponse;
47 private PowerFlowRealtimeResponse powerFlowResponse;
48 private FroniusBaseDeviceConfiguration config;
49 private final Gson gson;
51 public FroniusSymoInverterHandler(Thing thing) {
57 protected String getDescription() {
58 return "Fronius Symo Inverter";
62 public void refresh(FroniusBridgeConfiguration bridgeConfiguration) {
63 updateData(bridgeConfiguration, config);
68 public void initialize() {
69 config = getConfigAs(FroniusBaseDeviceConfiguration.class);
74 * Update the channel from the last data retrieved
76 * @param channelId the id identifying the channel to be updated
77 * @return the last retrieved data
80 protected Object getValue(String channelId) {
81 String[] fields = StringUtils.split(channelId, "#");
83 String fieldName = fields[0];
85 if (inverterRealtimeResponse == null) {
89 case FroniusBindingConstants.InverterDataChannelDayEnergy:
90 ValueUnit day = inverterRealtimeResponse.getBody().getData().getDayEnergy();
95 case FroniusBindingConstants.InverterDataChannelPac:
96 ValueUnit pac = inverterRealtimeResponse.getBody().getData().getPac();
98 pac = new ValueUnit();
102 case FroniusBindingConstants.InverterDataChannelTotal:
103 ValueUnit total = inverterRealtimeResponse.getBody().getData().getTotalEnergy();
105 total.setUnit("MWh");
108 case FroniusBindingConstants.InverterDataChannelYear:
109 ValueUnit year = inverterRealtimeResponse.getBody().getData().getYearEnergy();
114 case FroniusBindingConstants.InverterDataChannelFac:
115 return inverterRealtimeResponse.getBody().getData().getFac();
116 case FroniusBindingConstants.InverterDataChannelIac:
117 return inverterRealtimeResponse.getBody().getData().getIac();
118 case FroniusBindingConstants.InverterDataChannelIdc:
119 return inverterRealtimeResponse.getBody().getData().getIdc();
120 case FroniusBindingConstants.InverterDataChannelUac:
121 return inverterRealtimeResponse.getBody().getData().getUac();
122 case FroniusBindingConstants.InverterDataChannelUdc:
123 return inverterRealtimeResponse.getBody().getData().getUdc();
124 case FroniusBindingConstants.InverterDataChannelDeviceStatusErrorCode:
125 return inverterRealtimeResponse.getBody().getData().getDeviceStatus().getErrorCode();
126 case FroniusBindingConstants.InverterDataChannelDeviceStatusStatusCode:
127 return inverterRealtimeResponse.getBody().getData().getDeviceStatus().getStatusCode();
129 if (powerFlowResponse == null) {
133 case FroniusBindingConstants.PowerFlowpGrid:
134 return powerFlowResponse.getBody().getData().getSite().getPgrid();
135 case FroniusBindingConstants.PowerFlowpLoad:
136 return powerFlowResponse.getBody().getData().getSite().getPload();
137 case FroniusBindingConstants.PowerFlowpAkku:
138 return powerFlowResponse.getBody().getData().getSite().getPakku();
147 private void updateData(FroniusBridgeConfiguration bridgeConfiguration, FroniusBaseDeviceConfiguration config) {
148 inverterRealtimeResponse = getRealtimeData(bridgeConfiguration.hostname, config.deviceId);
149 powerFlowResponse = getPowerFlowRealtime(bridgeConfiguration.hostname);
154 * @param type response class type
155 * @param url to request
156 * @return the object representation of the json response
158 private <T extends BaseFroniusResponse> T collectDataFormUrl(Class<T> type, String url) {
160 boolean resultOk = false;
161 String errorMsg = null;
164 logger.debug("URL = {}", url);
165 String response = HttpUtil.executeUrl("GET", url, API_TIMEOUT);
167 if (response != null) {
168 logger.debug("aqiResponse = {}", response);
169 result = gson.fromJson(response, type);
172 if (result == null) {
173 errorMsg = "no data returned";
175 if (result.getHead().getStatus().getCode() == 0) {
178 errorMsg = result.getHead().getStatus().getReason();
182 logger.debug("Error in fronius response: {}", errorMsg);
184 } catch (JsonSyntaxException e) {
185 errorMsg = "Configuration is incorrect";
186 logger.debug("Error running fronius request: {}", errorMsg);
187 } catch (IOException | IllegalStateException e) {
188 logger.debug("Error running fronius request: {}", e.getMessage());
191 // Update the thing status
193 updateStatus(ThingStatus.ONLINE);
195 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, errorMsg);
197 return resultOk ? result : null;
201 * Make the PowerFlowRealtimeDataRequest
203 * @param ip address of the device
204 * @return {PowerFlowRealtimeResponse} the object representation of the json response
206 private PowerFlowRealtimeResponse getPowerFlowRealtime(String ip) {
207 String location = FroniusBindingConstants.POWERFLOW_REALTIME_DATA.replace("%IP%", StringUtils.trimToEmpty(ip));
208 return collectDataFormUrl(PowerFlowRealtimeResponse.class, location);
212 * Make the InverterRealtimeDataRequest
214 * @param ip address of the device
215 * @param deviceId of the device
216 * @return {InverterRealtimeResponse} the object representation of the json response
218 private InverterRealtimeResponse getRealtimeData(String ip, int deviceId) {
219 String location = FroniusBindingConstants.INVERTER_REALTIME_DATA_URL.replace("%IP%",
220 StringUtils.trimToEmpty(ip));
221 location = location.replace("%DEVICEID%", Integer.toString(deviceId));
222 return collectDataFormUrl(InverterRealtimeResponse.class, location);