]> git.basschouten.com Git - openhab-addons.git/blob
7f6f66357b4f49a6967e530ab98958b16fc7d326
[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  */
48 public abstract class FroniusBaseThingHandler extends BaseThingHandler {
49
50     private static final int API_TIMEOUT = 5000;
51     private final Logger logger = LoggerFactory.getLogger(FroniusBaseThingHandler.class);
52     private final String serviceDescription;
53     private FroniusBridgeHandler bridgeHandler;
54     private final Gson gson;
55
56     public FroniusBaseThingHandler(Thing thing) {
57         super(thing);
58         gson = new Gson();
59         serviceDescription = getDescription();
60     }
61
62     @Override
63     public void handleCommand(ChannelUID channelUID, Command command) {
64         if (command instanceof RefreshType) {
65             updateChannel(channelUID.getId());
66         }
67     }
68
69     @Override
70     public void initialize() {
71         if (getFroniusBridgeHandler() == null) {
72             logger.debug("Initializing {} Service is only supported within a bridge", serviceDescription);
73             updateStatus(ThingStatus.OFFLINE);
74             return;
75         }
76         logger.debug("Initializing {} Service", serviceDescription);
77         getFroniusBridgeHandler().registerService(this);
78     }
79
80     private synchronized FroniusBridgeHandler getFroniusBridgeHandler() {
81         if (this.bridgeHandler == null) {
82             Bridge bridge = getBridge();
83             if (bridge == null) {
84                 return null;
85             }
86             ThingHandler handler = bridge.getHandler();
87             if (handler instanceof FroniusBridgeHandler) {
88                 this.bridgeHandler = (FroniusBridgeHandler) handler;
89             } else {
90                 return null;
91             }
92         }
93         return this.bridgeHandler;
94     }
95
96     /**
97      * Update all Channels
98      */
99     protected void updateChannels() {
100         for (Channel channel : getThing().getChannels()) {
101             updateChannel(channel.getUID().getId());
102         }
103     }
104
105     /**
106      * Update the channel from the last data
107      *
108      * @param channelId the id identifying the channel to be updated
109      */
110     protected void updateChannel(String channelId) {
111         if (!isLinked(channelId)) {
112             return;
113         }
114
115         Object value = getValue(channelId);
116         if (value == null) {
117             logger.debug("Value retrieved for channel '{}' was null. Can't update.", channelId);
118             return;
119         }
120
121         State state = null;
122         if (value instanceof BigDecimal) {
123             state = new DecimalType((BigDecimal) value);
124         } else if (value instanceof Integer) {
125             state = new DecimalType(BigDecimal.valueOf(((Integer) value).longValue()));
126         } else if (value instanceof Double) {
127             state = new DecimalType((double) value);
128         } else if (value instanceof ValueUnit) {
129             state = new DecimalType(((ValueUnit) value).getValue());
130         } else if (value instanceof String) {
131             state = new StringType((String) value);
132         } else if (value instanceof QuantityType) {
133             state = (QuantityType) value;
134         } else {
135             logger.warn("Update channel {}: Unsupported value type {}", channelId, value.getClass().getSimpleName());
136         }
137         logger.debug("Update channel {} with state {} ({})", channelId, (state == null) ? "null" : state.toString(),
138                 value.getClass().getSimpleName());
139
140         // Update the channel
141         if (state != null) {
142             updateState(channelId, state);
143         }
144     }
145
146     /**
147      * return an internal description for logging
148      *
149      * @return the description of the thing
150      */
151     protected abstract String getDescription();
152
153     /**
154      * get the "new" associated value for a channelId
155      *
156      * @param channelId the id identifying the channel
157      * @return the "new" associated value
158      */
159     protected abstract Object getValue(String channelId);
160
161     /**
162      * do whatever a thing must do to update the values
163      * this function is called from the bridge in a given interval
164      *
165      * @param bridgeConfiguration the connected bridge configuration
166      */
167     public abstract void refresh(FroniusBridgeConfiguration bridgeConfiguration);
168
169     /**
170      *
171      * @param type response class type
172      * @param url to request
173      * @return the object representation of the json response
174      */
175     protected <T extends BaseFroniusResponse> T collectDataFormUrl(Class<T> type, String url) {
176         T result = null;
177         boolean resultOk = false;
178         String errorMsg = null;
179
180         try {
181             logger.debug("URL = {}", url);
182             String response = HttpUtil.executeUrl("GET", url, API_TIMEOUT);
183
184             if (response != null) {
185                 logger.debug("aqiResponse = {}", response);
186                 result = gson.fromJson(response, type);
187             }
188
189             if (result == null) {
190                 errorMsg = "no data returned";
191             } else {
192                 if (result.getHead().getStatus().getCode() == 0) {
193                     resultOk = true;
194                 } else {
195                     errorMsg = result.getHead().getStatus().getReason();
196                 }
197             }
198             if (!resultOk) {
199                 logger.debug("Error in fronius response: {}", errorMsg);
200             }
201         } catch (JsonSyntaxException e) {
202             errorMsg = "Invalid JSON data received";
203             logger.debug("Error running fronius request: {}", e.getMessage());
204         } catch (IOException | IllegalStateException e) {
205             errorMsg = e.getMessage();
206             logger.debug("Error running fronius request: {}", errorMsg);
207         }
208
209         // Update the thing status
210         if (resultOk) {
211             updateStatus(ThingStatus.ONLINE);
212         } else {
213             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, errorMsg);
214         }
215         return resultOk ? result : null;
216     }
217 }