]> git.basschouten.com Git - openhab-addons.git/blob
04c20597855eb1656c82c9c0fa2c19e8d4c57541
[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.haassohnpelletstove.internal;
14
15 import java.io.ByteArrayInputStream;
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.io.UnsupportedEncodingException;
19 import java.util.Properties;
20
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.openhab.core.io.net.http.HttpUtil;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 import com.google.gson.Gson;
28
29 /**
30  * This class handles the JSON communication with the Wifi Modul of the Stove
31  *
32  * @author Christian Feininger - Initial contribution
33  *
34  */
35 @NonNullByDefault
36 public class HaasSohnpelletstoveJSONCommunication {
37
38     private final Logger logger = LoggerFactory.getLogger(HaasSohnpelletstoveJSONCommunication.class);
39     private HaasSohnpelletstoveConfiguration config;
40
41     private Gson gson;
42     private @Nullable String xhspin;
43     private @Nullable HaasSohnpelletstoveJsonDataDTO ovenData;
44
45     public HaasSohnpelletstoveJSONCommunication() {
46         gson = new Gson();
47         ovenData = new HaasSohnpelletstoveJsonDataDTO();
48         xhspin = "";
49         config = new HaasSohnpelletstoveConfiguration();
50     }
51
52     /**
53      * Refreshes the oven Connection with the internal oven token.
54      *
55      * @param message Message object to pass errors to the calling method.
56      * @param thingUID Thing UID for logging purposes
57      * @return true if no error occurred, false otherwise.
58      */
59     public boolean refreshOvenConnection(Helper message, String thingUID) {
60         if (config.hostIP == null || config.hostPIN == null) {
61             message.setStatusDescription("Error in configuration. Please recreate Thing.");
62             return false;
63         }
64         HaasSohnpelletstoveJsonDataDTO result = null;
65         boolean resultOk = false;
66         String error = "", errorDetail = "", statusDescr = "";
67         String urlStr = "http://" + config.hostIP + "/status.cgi";
68
69         String response = null;
70         try {
71             response = HttpUtil.executeUrl("GET", urlStr, 10000);
72             logger.debug("OvenData = {}", response);
73             result = gson.fromJson(response, HaasSohnpelletstoveJsonDataDTO.class);
74             resultOk = true;
75         } catch (IOException e) {
76             logger.debug("Error processiong Get request {}", urlStr);
77             statusDescr = "Timeout error with" + config.hostIP
78                     + ". Cannot find service on give IP. Please verify the IP-Address!";
79             errorDetail = e.getMessage();
80             resultOk = false;
81         } catch (Exception e) {
82             logger.debug("Unknwon Error: {}", e.getMessage());
83             errorDetail = e.getMessage();
84             resultOk = false;
85         }
86         if (resultOk) {
87             ovenData = result;
88             xhspin = getValidXHSPIN(ovenData);
89         } else {
90             logger.debug("Setting thing '{}' to OFFLINE: Error '{}': {}", thingUID, error, errorDetail);
91             ovenData = new HaasSohnpelletstoveJsonDataDTO();
92         }
93         message.setStatusDescription(statusDescr);
94         return resultOk;
95     }
96
97     /**
98      * Gets the status of the oven
99      *
100      * @return true if success or false in case of error
101      */
102     public boolean updateOvenData(@Nullable String postData, Helper helper, String thingUID) {
103         String statusDescr = "";
104         boolean resultOk = false;
105         String error = "", errorDetail = "";
106         if (config.hostIP == null || config.hostPIN == null) {
107             return false;
108         }
109         String urlStr = "http://" + config.hostIP + "/status.cgi";
110
111         // Run the HTTP POST request and get the JSON response from Oven
112         String response = null;
113
114         Properties httpHeader = new Properties();
115
116         if (postData != null) {
117             try {
118                 InputStream targetStream = new ByteArrayInputStream(postData.getBytes("UTF-8"));
119                 refreshOvenConnection(helper, thingUID);
120                 httpHeader = createHeader(postData);
121                 response = HttpUtil.executeUrl("POST", urlStr, httpHeader, targetStream, "application/json", 10000);
122                 resultOk = true;
123                 logger.debug("Execute POST request with content to {} with header: {}", urlStr, httpHeader.toString());
124             } catch (UnsupportedEncodingException e1) {
125                 logger.debug("Wrong encoding found. Only UTF-8 is supported.");
126                 statusDescr = "Encoding of oven is not supported. Only UTF-8 is supported.";
127                 resultOk = false;
128             } catch (IOException e) {
129                 logger.debug("Error processiong POST request {}", urlStr);
130                 statusDescr = "Cannot execute command on Stove. Please verify connection and Thing Status";
131                 resultOk = false;
132             }
133         } else {
134             try {
135                 refreshOvenConnection(helper, thingUID);
136                 httpHeader = createHeader(null);
137                 response = HttpUtil.executeUrl("POST", urlStr, httpHeader, null, "", 10000);
138                 resultOk = true;
139                 logger.debug("Execute POST request to {} with header: {}", urlStr, httpHeader.toString());
140             } catch (IOException e) {
141                 logger.debug("Error processiong POST request {}", e.getMessage());
142                 String message = e.getMessage();
143                 if (message != null && message.contains("Authentication challenge without WWW-Authenticate ")) {
144                     statusDescr = "Cannot connect to stove. Given PIN: " + config.hostPIN + " is incorrect!";
145                 }
146                 resultOk = false;
147             }
148         }
149         if (resultOk) {
150             logger.debug("OvenData = {}", response);
151             ovenData = gson.fromJson(response, HaasSohnpelletstoveJsonDataDTO.class);
152         } else {
153             logger.debug("Setting thing '{}' to OFFLINE: Error '{}': {}", thingUID, error, errorDetail);
154             ovenData = new HaasSohnpelletstoveJsonDataDTO();
155         }
156         helper.setStatusDescription(statusDescr);
157         return resultOk;
158     }
159
160     /**
161      * Creates the header for the Post Request
162      *
163      * @return The created Header Properties
164      * @throws UnsupportedEncodingException
165      */
166     private Properties createHeader(@Nullable String postData) throws UnsupportedEncodingException {
167         Properties httpHeader = new Properties();
168         httpHeader.setProperty("Host", config.hostIP);
169         httpHeader.setProperty("Accept", "*/*");
170         httpHeader.setProperty("Proxy-Connection", "keep-alive");
171         httpHeader.setProperty("X-BACKEND-IP", "https://app.haassohn.com");
172         httpHeader.setProperty("Accept-Language", "de-DE;q=1.0, en-DE;q=0.9");
173         httpHeader.setProperty("Accept-Encoding", "gzip;q=1.0, compress;q=0.5");
174         httpHeader.setProperty("token", "32 bytes");
175         httpHeader.setProperty("Content-Type", "application/json");
176         if (postData != null) {
177             int a = postData.getBytes("UTF-8").length;
178             httpHeader.setProperty(xhspin, Integer.toString(a));
179         }
180         httpHeader.setProperty("User-Agent", "ios");
181         httpHeader.setProperty("Connection", "keep-alive");
182         httpHeader.setProperty("X-HS-PIN", xhspin);
183         return httpHeader;
184     }
185
186     /**
187      * Generate the valid encrypted string to communicate with the oven.
188      *
189      * @param ovenData
190      * @return
191      */
192     private @Nullable String getValidXHSPIN(@Nullable HaasSohnpelletstoveJsonDataDTO ovenData) {
193         if (ovenData != null && config.hostPIN != null) {
194             String nonce = ovenData.getNonce();
195             String hostPIN = config.hostPIN;
196             String ePin = MD5Utils.getMD5String(hostPIN);
197             return MD5Utils.getMD5String(nonce + ePin);
198         } else {
199             return null;
200         }
201     }
202
203     /**
204      * Set the config for service to communicate
205      *
206      * @param config2
207      */
208     public void setConfig(@Nullable HaasSohnpelletstoveConfiguration config2) {
209         if (config2 != null) {
210             this.config = config2;
211         }
212     }
213
214     /**
215      * Returns the actual stored Oven Data
216      *
217      * @return
218      */
219     @Nullable
220     public HaasSohnpelletstoveJsonDataDTO getOvenData() {
221         return this.ovenData;
222     }
223 }