]> git.basschouten.com Git - openhab-addons.git/blob
406d776c3bf9cad9590f0856ab7bb428bcc3d0e8
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.fronius.internal.handler;
14
15 import java.io.IOException;
16 import java.math.BigDecimal;
17
18 import org.openhab.binding.fronius.internal.FroniusBridgeConfiguration;
19 import org.openhab.binding.fronius.internal.api.BaseFroniusResponse;
20 import org.openhab.binding.fronius.internal.api.ValueUnit;
21 import org.openhab.core.io.net.http.HttpUtil;
22 import org.openhab.core.library.types.DecimalType;
23 import org.openhab.core.library.types.QuantityType;
24 import org.openhab.core.library.types.StringType;
25 import org.openhab.core.thing.Bridge;
26 import org.openhab.core.thing.Channel;
27 import org.openhab.core.thing.ChannelUID;
28 import org.openhab.core.thing.Thing;
29 import org.openhab.core.thing.ThingStatus;
30 import org.openhab.core.thing.ThingStatusDetail;
31 import org.openhab.core.thing.binding.BaseThingHandler;
32 import org.openhab.core.thing.binding.ThingHandler;
33 import org.openhab.core.types.Command;
34 import org.openhab.core.types.RefreshType;
35 import org.openhab.core.types.State;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 import com.google.gson.Gson;
40 import com.google.gson.JsonSyntaxException;
41
42 /**
43  * Basic Handler class for all Fronius services.
44  *
45  * @author Gerrit Beine - Initial contribution
46  * @author Thomas Rokohl - Refactoring to merge the concepts
47  * @author Thomas Kordelle - Added inverter power, battery state of charge and PV solar yield
48  */
49 public abstract class FroniusBaseThingHandler extends BaseThingHandler {
50
51     private static final int API_TIMEOUT = 5000;
52     private final Logger logger = LoggerFactory.getLogger(FroniusBaseThingHandler.class);
53     private final String serviceDescription;
54     private FroniusBridgeHandler bridgeHandler;
55     private final Gson gson;
56
57     public FroniusBaseThingHandler(Thing thing) {
58         super(thing);
59         gson = new Gson();
60         serviceDescription = getDescription();
61     }
62
63     @Override
64     public void handleCommand(ChannelUID channelUID, Command command) {
65         if (command instanceof RefreshType) {
66             updateChannel(channelUID.getId());
67         }
68     }
69
70     @Override
71     public void initialize() {
72         if (getFroniusBridgeHandler() == null) {
73             logger.debug("Initializing {} Service is only supported within a bridge", serviceDescription);
74             updateStatus(ThingStatus.OFFLINE);
75             return;
76         }
77         logger.debug("Initializing {} Service", serviceDescription);
78         getFroniusBridgeHandler().registerService(this);
79     }
80
81     private synchronized FroniusBridgeHandler getFroniusBridgeHandler() {
82         if (this.bridgeHandler == null) {
83             Bridge bridge = getBridge();
84             if (bridge == null) {
85                 return null;
86             }
87             ThingHandler handler = bridge.getHandler();
88             if (handler instanceof FroniusBridgeHandler) {
89                 this.bridgeHandler = (FroniusBridgeHandler) handler;
90             } else {
91                 return null;
92             }
93         }
94         return this.bridgeHandler;
95     }
96
97     /**
98      * Update all Channels
99      */
100     protected void updateChannels() {
101         for (Channel channel : getThing().getChannels()) {
102             updateChannel(channel.getUID().getId());
103         }
104     }
105
106     /**
107      * Update the channel from the last data
108      *
109      * @param channelId the id identifying the channel to be updated
110      */
111     protected void updateChannel(String channelId) {
112         if (!isLinked(channelId)) {
113             return;
114         }
115
116         Object value = getValue(channelId);
117         if (value == null) {
118             logger.debug("Value retrieved for channel '{}' was null. Can't update.", channelId);
119             return;
120         }
121
122         State state = null;
123         if (value instanceof BigDecimal) {
124             state = new DecimalType((BigDecimal) value);
125         } else if (value instanceof Integer) {
126             state = new DecimalType(BigDecimal.valueOf(((Integer) value).longValue()));
127         } else if (value instanceof Double) {
128             state = new DecimalType((double) value);
129         } else if (value instanceof ValueUnit) {
130             state = new DecimalType(((ValueUnit) value).getValue());
131         } else if (value instanceof String) {
132             state = new StringType((String) value);
133         } else if (value instanceof QuantityType) {
134             state = (QuantityType) value;
135         } else {
136             logger.warn("Update channel {}: Unsupported value type {}", channelId, value.getClass().getSimpleName());
137         }
138         logger.debug("Update channel {} with state {} ({})", channelId, (state == null) ? "null" : state.toString(),
139                 value.getClass().getSimpleName());
140
141         // Update the channel
142         if (state != null) {
143             updateState(channelId, state);
144         }
145     }
146
147     /**
148      * return an internal description for logging
149      *
150      * @return the description of the thing
151      */
152     protected abstract String getDescription();
153
154     /**
155      * get the "new" associated value for a channelId
156      *
157      * @param channelId the id identifying the channel
158      * @return the "new" associated value
159      */
160     protected abstract Object getValue(String channelId);
161
162     /**
163      * do whatever a thing must do to update the values
164      * this function is called from the bridge in a given interval
165      *
166      * @param bridgeConfiguration the connected bridge configuration
167      */
168     public abstract void refresh(FroniusBridgeConfiguration bridgeConfiguration);
169
170     /**
171      *
172      * @param type response class type
173      * @param url to request
174      * @return the object representation of the json response
175      */
176     protected <T extends BaseFroniusResponse> T collectDataFormUrl(Class<T> type, String url) {
177         T result = null;
178         boolean resultOk = false;
179         String errorMsg = null;
180
181         try {
182             logger.debug("URL = {}", url);
183             String response = HttpUtil.executeUrl("GET", url, API_TIMEOUT);
184
185             if (response != null) {
186                 logger.debug("aqiResponse = {}", response);
187                 result = gson.fromJson(response, type);
188             }
189
190             if (result == null) {
191                 errorMsg = "no data returned";
192             } else {
193                 if (result.getHead().getStatus().getCode() == 0) {
194                     resultOk = true;
195                 } else {
196                     errorMsg = result.getHead().getStatus().getReason();
197                 }
198             }
199             if (!resultOk) {
200                 logger.debug("Error in fronius response: {}", errorMsg);
201             }
202         } catch (JsonSyntaxException | NumberFormatException e) {
203             errorMsg = "Invalid JSON data received";
204             logger.debug("Error running fronius request: {}", e.getMessage());
205         } catch (IOException | IllegalStateException e) {
206             errorMsg = e.getMessage();
207             logger.debug("Error running fronius request: {}", errorMsg);
208         }
209
210         // Update the thing status
211         if (resultOk) {
212             updateStatus(ThingStatus.ONLINE);
213         } else {
214             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, errorMsg);
215         }
216         return resultOk ? result : null;
217     }
218 }