2 * Copyright (c) 2010-2021 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.haassohnpelletstove.internal;
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;
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;
27 import com.google.gson.Gson;
30 * This class handles the JSON communication with the Wifi Modul of the Stove
32 * @author Christian Feininger - Initial contribution
36 public class HaasSohnpelletstoveJSONCommunication {
38 private final Logger logger = LoggerFactory.getLogger(HaasSohnpelletstoveJSONCommunication.class);
39 private HaasSohnpelletstoveConfiguration config;
42 private @Nullable String xhspin;
43 private @Nullable HaasSohnpelletstoveJsonDataDTO ovenData;
45 public HaasSohnpelletstoveJSONCommunication() {
47 ovenData = new HaasSohnpelletstoveJsonDataDTO();
49 config = new HaasSohnpelletstoveConfiguration();
53 * Refreshes the oven Connection with the internal oven token.
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.
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.");
64 HaasSohnpelletstoveJsonDataDTO result = null;
65 boolean resultOk = false;
66 String error = "", errorDetail = "", statusDescr = "";
67 String urlStr = "http://" + config.hostIP + "/status.cgi";
69 String response = null;
71 response = HttpUtil.executeUrl("GET", urlStr, 10000);
72 logger.debug("OvenData = {}", response);
73 result = gson.fromJson(response, HaasSohnpelletstoveJsonDataDTO.class);
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();
81 } catch (Exception e) {
82 logger.debug("Unknwon Error: {}", e.getMessage());
83 errorDetail = e.getMessage();
88 xhspin = getValidXHSPIN(ovenData);
90 logger.debug("Setting thing '{}' to OFFLINE: Error '{}': {}", thingUID, error, errorDetail);
91 ovenData = new HaasSohnpelletstoveJsonDataDTO();
93 message.setStatusDescription(statusDescr);
98 * Gets the status of the oven
100 * @return true if success or false in case of error
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) {
109 String urlStr = "http://" + config.hostIP + "/status.cgi";
111 // Run the HTTP POST request and get the JSON response from Oven
112 String response = null;
114 Properties httpHeader = new Properties();
116 if (postData != null) {
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);
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.";
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";
135 refreshOvenConnection(helper, thingUID);
136 httpHeader = createHeader(null);
137 response = HttpUtil.executeUrl("POST", urlStr, httpHeader, null, "", 10000);
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!";
150 logger.debug("OvenData = {}", response);
151 ovenData = gson.fromJson(response, HaasSohnpelletstoveJsonDataDTO.class);
153 logger.debug("Setting thing '{}' to OFFLINE: Error '{}': {}", thingUID, error, errorDetail);
154 ovenData = new HaasSohnpelletstoveJsonDataDTO();
156 helper.setStatusDescription(statusDescr);
161 * Creates the header for the Post Request
163 * @return The created Header Properties
164 * @throws UnsupportedEncodingException
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));
180 httpHeader.setProperty("User-Agent", "ios");
181 httpHeader.setProperty("Connection", "keep-alive");
182 httpHeader.setProperty("X-HS-PIN", xhspin);
187 * Generate the valid encrypted string to communicate with the oven.
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);
204 * Set the config for service to communicate
208 public void setConfig(@Nullable HaasSohnpelletstoveConfiguration config2) {
209 if (config2 != null) {
210 this.config = config2;
215 * Returns the actual stored Oven Data
220 public HaasSohnpelletstoveJsonDataDTO getOvenData() {
221 return this.ovenData;