]> git.basschouten.com Git - openhab-addons.git/blob
f5fd2b16710df37f4111b0f97d63b9f9805de974
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 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.nio.charset.StandardCharsets;
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(StandardCharsets.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 (IOException e) {
125                 logger.debug("Error processiong POST request {}", urlStr);
126                 statusDescr = "Cannot execute command on Stove. Please verify connection and Thing Status";
127                 resultOk = false;
128             }
129         } else {
130             try {
131                 refreshOvenConnection(helper, thingUID);
132                 httpHeader = createHeader(null);
133                 response = HttpUtil.executeUrl("POST", urlStr, httpHeader, null, "", 10000);
134                 resultOk = true;
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!";
141                 }
142                 resultOk = false;
143             }
144         }
145         if (resultOk) {
146             logger.debug("OvenData = {}", response);
147             ovenData = gson.fromJson(response, HaasSohnpelletstoveJsonDataDTO.class);
148         } else {
149             logger.debug("Setting thing '{}' to OFFLINE: Error '{}': {}", thingUID, error, errorDetail);
150             ovenData = new HaasSohnpelletstoveJsonDataDTO();
151         }
152         helper.setStatusDescription(statusDescr);
153         return resultOk;
154     }
155
156     /**
157      * Creates the header for the Post Request
158      *
159      * @return The created Header Properties
160      */
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));
174         }
175         httpHeader.setProperty("User-Agent", "ios");
176         httpHeader.setProperty("Connection", "keep-alive");
177         httpHeader.setProperty("X-HS-PIN", xhspin);
178         return httpHeader;
179     }
180
181     /**
182      * Generate the valid encrypted string to communicate with the oven.
183      *
184      * @param ovenData
185      * @return
186      */
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);
193         } else {
194             return null;
195         }
196     }
197
198     /**
199      * Set the config for service to communicate
200      *
201      * @param config2
202      */
203     public void setConfig(@Nullable HaasSohnpelletstoveConfiguration config2) {
204         if (config2 != null) {
205             this.config = config2;
206         }
207     }
208
209     /**
210      * Returns the actual stored Oven Data
211      *
212      * @return
213      */
214     @Nullable
215     public HaasSohnpelletstoveJsonDataDTO getOvenData() {
216         return this.ovenData;
217     }
218 }