2 * Copyright (c) 2010-2023 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.nio.charset.StandardCharsets;
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(StandardCharsets.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 (IOException e) {
125 logger.debug("Error processiong POST request {}", urlStr);
126 statusDescr = "Cannot execute command on Stove. Please verify connection and Thing Status";
131 refreshOvenConnection(helper, thingUID);
132 httpHeader = createHeader(null);
133 response = HttpUtil.executeUrl("POST", urlStr, httpHeader, null, "", 10000);
135 logger.debug("Execute POST request to {} with header: {}", urlStr, httpHeader.toString());
136 } catch (IOException e) {
137 logger.debug("Error processiong POST request {}", e.getMessage());
138 String message = e.getMessage();
139 if (message != null && message.contains("Authentication challenge without WWW-Authenticate ")) {
140 statusDescr = "Cannot connect to stove. Given PIN: " + config.hostPIN + " is incorrect!";
146 logger.debug("OvenData = {}", response);
147 ovenData = gson.fromJson(response, HaasSohnpelletstoveJsonDataDTO.class);
149 logger.debug("Setting thing '{}' to OFFLINE: Error '{}': {}", thingUID, error, errorDetail);
150 ovenData = new HaasSohnpelletstoveJsonDataDTO();
152 helper.setStatusDescription(statusDescr);
157 * Creates the header for the Post Request
159 * @return The created Header Properties
161 private Properties createHeader(@Nullable String postData) {
162 Properties httpHeader = new Properties();
163 httpHeader.setProperty("Host", config.hostIP);
164 httpHeader.setProperty("Accept", "*/*");
165 httpHeader.setProperty("Proxy-Connection", "keep-alive");
166 httpHeader.setProperty("X-BACKEND-IP", "https://app.haassohn.com");
167 httpHeader.setProperty("Accept-Language", "de-DE;q=1.0, en-DE;q=0.9");
168 httpHeader.setProperty("Accept-Encoding", "gzip;q=1.0, compress;q=0.5");
169 httpHeader.setProperty("token", "32 bytes");
170 httpHeader.setProperty("Content-Type", "application/json");
171 if (postData != null) {
172 int a = postData.getBytes(StandardCharsets.UTF_8).length;
173 httpHeader.setProperty(xhspin, Integer.toString(a));
175 httpHeader.setProperty("User-Agent", "ios");
176 httpHeader.setProperty("Connection", "keep-alive");
177 httpHeader.setProperty("X-HS-PIN", xhspin);
182 * Generate the valid encrypted string to communicate with the oven.
187 private @Nullable String getValidXHSPIN(@Nullable HaasSohnpelletstoveJsonDataDTO ovenData) {
188 if (ovenData != null && config.hostPIN != null) {
189 String nonce = ovenData.getNonce();
190 String hostPIN = config.hostPIN;
191 String ePin = MD5Utils.getMD5String(hostPIN);
192 return MD5Utils.getMD5String(nonce + ePin);
199 * Set the config for service to communicate
203 public void setConfig(@Nullable HaasSohnpelletstoveConfiguration config2) {
204 if (config2 != null) {
205 this.config = config2;
210 * Returns the actual stored Oven Data
215 public HaasSohnpelletstoveJsonDataDTO getOvenData() {
216 return this.ovenData;