[haassohnpelletstove] Improve connection handling (#18212)
* Adding a Reconnect Rate to improve connectivity for the thing in case of weak wifi signal and automatically reconnect the thing. Signed-off-by: chingon007 <tron81@gmx.de>pull/14578/merge
parent
c3fa94302d
commit
96def56c6d
|
@ -12,7 +12,7 @@ WIFI module. More information about the WIFI module can be found here: <https://
|
|||
## Thing Configuration
|
||||
|
||||
In general two parameters are required. The IP-Address of the WIFI-Modul of the Stove in the local Network and the Access PIN of the Stove.
|
||||
The PIN can be found directly at the stove under the Menue/Network/WLAN-PIN
|
||||
The PIN can be found directly at the stove under the Menue/Network/WLAN-PIN.
|
||||
|
||||
```java
|
||||
Thing haassohnpelletstove:oven:myOven "Pelletstove" [ hostIP="192.168.0.23", hostPIN="1234"]
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
package org.openhab.binding.haassohnpelletstove.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link HaasSohnpelletstoveConfiguration} class contains fields mapping thing configuration parameters.
|
||||
|
@ -23,7 +22,7 @@ import org.eclipse.jdt.annotation.Nullable;
|
|||
@NonNullByDefault
|
||||
public class HaasSohnpelletstoveConfiguration {
|
||||
|
||||
public @Nullable String hostIP = null;
|
||||
public @Nullable String hostPIN = null;
|
||||
public String hostIP = "";
|
||||
public String hostPIN = "";
|
||||
public int refreshRate = 30;
|
||||
}
|
||||
|
|
|
@ -108,82 +108,63 @@ public class HaasSohnpelletstoveHandler extends BaseThingHandler {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the service to update the oven data
|
||||
*
|
||||
* @param postdata
|
||||
*/
|
||||
private boolean updateOvenData(@Nullable String postdata) {
|
||||
Helper message = new Helper();
|
||||
if (serviceCommunication.updateOvenData(postdata, message, this.getThing().getUID().toString())) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
return true;
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
|
||||
message.getStatusDesription());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
logger.debug("Initializing haassohnpelletstove handler for thing {}", getThing().getUID());
|
||||
config = getConfigAs(HaasSohnpelletstoveConfiguration.class);
|
||||
boolean validConfig = true;
|
||||
String errors = "";
|
||||
String statusDescr = null;
|
||||
if (config.refreshRate < 0 && config.refreshRate > 999) {
|
||||
errors += " Parameter 'refresh Rate' greater then 0 and less then 1000.";
|
||||
statusDescr = "Parameter 'refresh Rate' greater then 0 and less then 1000.";
|
||||
validConfig = false;
|
||||
if (config.refreshRate < 1 || config.refreshRate > 1000) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"Parameter 'refresh Rate' must be in the range 1-1000!");
|
||||
return;
|
||||
}
|
||||
if (config.hostIP == null) {
|
||||
errors += " Parameter 'hostIP' must be configured.";
|
||||
statusDescr = "IP Address must be configured!";
|
||||
validConfig = false;
|
||||
if (config.hostIP.isBlank()) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "IP Address must be configured!");
|
||||
return;
|
||||
}
|
||||
if (config.hostPIN == null) {
|
||||
errors += " Parameter 'hostPin' must be configured.";
|
||||
statusDescr = "PIN must be configured!";
|
||||
validConfig = false;
|
||||
|
||||
if (config.hostPIN.isBlank()) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"Parameter 'hostPin' must be configured!");
|
||||
return;
|
||||
}
|
||||
errors = errors.trim();
|
||||
Helper message = new Helper();
|
||||
message.setStatusDescription(statusDescr);
|
||||
if (validConfig) {
|
||||
serviceCommunication.setConfig(config);
|
||||
if (serviceCommunication.refreshOvenConnection(message, this.getThing().getUID().toString())) {
|
||||
if (updateOvenData(null)) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
updateLinkedChannels();
|
||||
|
||||
serviceCommunication.setConfig(config);
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
scheduler.submit(() -> {
|
||||
if (updateOvenData(null)) {
|
||||
for (Channel channel : getThing().getChannels()) {
|
||||
if (isLinked(channel.getUID().getId())) {
|
||||
channelLinked(channel.getUID());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, message.getStatusDesription());
|
||||
}
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, message.getStatusDesription());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateLinkedChannels() {
|
||||
verifyLinkedChannel(CHANNELISTEMP);
|
||||
verifyLinkedChannel(CHANNELMODE);
|
||||
verifyLinkedChannel(CHANNELPOWER);
|
||||
verifyLinkedChannel(CHANNELSPTEMP);
|
||||
verifyLinkedChannel(CHANNELECOMODE);
|
||||
verifyLinkedChannel(CHANNELIGNITIONS);
|
||||
verifyLinkedChannel(CHANNELMAINTENANCEIN);
|
||||
verifyLinkedChannel(CHANNELCLEANINGIN);
|
||||
verifyLinkedChannel(CHANNELCONSUMPTION);
|
||||
verifyLinkedChannel(CHANNELONTIME);
|
||||
if (!linkedChannels.isEmpty()) {
|
||||
updateOvenData(null);
|
||||
for (Channel channel : getThing().getChannels()) {
|
||||
updateChannel(channel.getUID().getId());
|
||||
}
|
||||
startAutomaticRefresh();
|
||||
automaticRefreshing = true;
|
||||
/**
|
||||
* Calls the service to update the oven data
|
||||
*
|
||||
* @return true if the update succeeded, false otherwise
|
||||
*/
|
||||
private boolean updateOvenData(@Nullable String postdata) {
|
||||
String error = "";
|
||||
if (postdata != null) {
|
||||
error = serviceCommunication.updateOvenData(postdata);
|
||||
} else {
|
||||
error = serviceCommunication.refreshOvenConnection();
|
||||
}
|
||||
if (error.isEmpty()) {
|
||||
if (ThingStatus.OFFLINE.equals(getThing().getStatus())) {
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
}
|
||||
if (!ThingStatus.ONLINE.equals(getThing().getStatus())) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, error);
|
||||
return false;
|
||||
}
|
||||
return error.isEmpty();
|
||||
}
|
||||
|
||||
private void verifyLinkedChannel(String channelID) {
|
||||
|
@ -195,14 +176,24 @@ public class HaasSohnpelletstoveHandler extends BaseThingHandler {
|
|||
@Override
|
||||
public void dispose() {
|
||||
stopScheduler();
|
||||
linkedChannels.clear();
|
||||
automaticRefreshing = false;
|
||||
}
|
||||
|
||||
private void stopScheduler() {
|
||||
ScheduledFuture<?> job = refreshJob;
|
||||
if (job != null) {
|
||||
job.cancel(true);
|
||||
if (job == null || job.isCancelled()) {
|
||||
refreshJob = scheduler.scheduleWithFixedDelay(this::refreshChannels, 0, config.refreshRate,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshChannels() {
|
||||
if (updateOvenData(null)) {
|
||||
for (Channel channel : getThing().getChannels()) {
|
||||
updateChannel(channel.getUID().getId());
|
||||
}
|
||||
}
|
||||
refreshJob = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -217,9 +208,10 @@ public class HaasSohnpelletstoveHandler extends BaseThingHandler {
|
|||
}
|
||||
|
||||
private void run() {
|
||||
updateOvenData(null);
|
||||
for (Channel channel : getThing().getChannels()) {
|
||||
updateChannel(channel.getUID().getId());
|
||||
if (updateOvenData(null)) {
|
||||
for (Channel channel : getThing().getChannels()) {
|
||||
updateChannel(channel.getUID().getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
/**
|
||||
* This class handles the JSON communication with the Wifi Modul of the Stove
|
||||
|
@ -52,105 +53,65 @@ public class HaasSohnpelletstoveJSONCommunication {
|
|||
/**
|
||||
* Refreshes the oven Connection with the internal oven token.
|
||||
*
|
||||
* @param message Message object to pass errors to the calling method.
|
||||
* @param thingUID Thing UID for logging purposes
|
||||
* @return true if no error occurred, false otherwise.
|
||||
* @return an empty string if no error occurred, the error message otherwise.
|
||||
*/
|
||||
public boolean refreshOvenConnection(Helper message, String thingUID) {
|
||||
if (config.hostIP == null || config.hostPIN == null) {
|
||||
message.setStatusDescription("Error in configuration. Please recreate Thing.");
|
||||
return false;
|
||||
}
|
||||
HaasSohnpelletstoveJsonDataDTO result = null;
|
||||
boolean resultOk = false;
|
||||
String error = "", errorDetail = "", statusDescr = "";
|
||||
public String refreshOvenConnection() {
|
||||
String result = "";
|
||||
HaasSohnpelletstoveJsonDataDTO responseObject = null;
|
||||
String urlStr = "http://" + config.hostIP + "/status.cgi";
|
||||
|
||||
String response = null;
|
||||
try {
|
||||
response = HttpUtil.executeUrl("GET", urlStr, 10000);
|
||||
logger.debug("OvenData = {}", response);
|
||||
result = gson.fromJson(response, HaasSohnpelletstoveJsonDataDTO.class);
|
||||
resultOk = true;
|
||||
} catch (IOException e) {
|
||||
responseObject = gson.fromJson(response, HaasSohnpelletstoveJsonDataDTO.class);
|
||||
ovenData = responseObject;
|
||||
xhspin = getValidXHSPIN(ovenData);
|
||||
} catch (IOException | JsonSyntaxException e) {
|
||||
logger.debug("Error processiong Get request {}", urlStr);
|
||||
statusDescr = "Timeout error with" + config.hostIP
|
||||
+ ". Cannot find service on give IP. Please verify the IP-Address!";
|
||||
errorDetail = e.getMessage();
|
||||
resultOk = false;
|
||||
result = "Timeout error with " + config.hostIP
|
||||
+ ". Cannot find service on given IP. Please verify the IP-Address!";
|
||||
logger.debug("Error in establishing connection: {}", e.getMessage());
|
||||
} catch (Exception e) {
|
||||
logger.debug("Unknwon Error: {}", e.getMessage());
|
||||
errorDetail = e.getMessage();
|
||||
resultOk = false;
|
||||
}
|
||||
if (resultOk) {
|
||||
ovenData = result;
|
||||
xhspin = getValidXHSPIN(ovenData);
|
||||
} else {
|
||||
logger.debug("Setting thing '{}' to OFFLINE: Error '{}': {}", thingUID, error, errorDetail);
|
||||
ovenData = new HaasSohnpelletstoveJsonDataDTO();
|
||||
}
|
||||
message.setStatusDescription(statusDescr);
|
||||
return resultOk;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the status of the oven
|
||||
*
|
||||
* @return true if success or false in case of error
|
||||
* @return an empty string if no error occurred, the error message otherwise.
|
||||
*/
|
||||
public boolean updateOvenData(@Nullable String postData, Helper helper, String thingUID) {
|
||||
String statusDescr = "";
|
||||
boolean resultOk = false;
|
||||
String error = "", errorDetail = "";
|
||||
if (config.hostIP == null || config.hostPIN == null) {
|
||||
return false;
|
||||
}
|
||||
public String updateOvenData(@Nullable String postData) {
|
||||
String error = "";
|
||||
String urlStr = "http://" + config.hostIP + "/status.cgi";
|
||||
|
||||
// Run the HTTP POST request and get the JSON response from Oven
|
||||
String response = null;
|
||||
|
||||
Properties httpHeader = new Properties();
|
||||
|
||||
if (postData != null) {
|
||||
try {
|
||||
InputStream targetStream = new ByteArrayInputStream(postData.getBytes(StandardCharsets.UTF_8));
|
||||
refreshOvenConnection(helper, thingUID);
|
||||
httpHeader = createHeader(postData);
|
||||
response = HttpUtil.executeUrl("POST", urlStr, httpHeader, targetStream, "application/json", 10000);
|
||||
resultOk = true;
|
||||
logger.debug("Execute POST request with content to {} with header: {}", urlStr, httpHeader.toString());
|
||||
} catch (IOException e) {
|
||||
logger.debug("Error processiong POST request {}", urlStr);
|
||||
statusDescr = "Cannot execute command on Stove. Please verify connection and Thing Status";
|
||||
resultOk = false;
|
||||
try {
|
||||
InputStream targetStream = null;
|
||||
if (postData != null) {
|
||||
targetStream = new ByteArrayInputStream(postData.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
refreshOvenConnection(helper, thingUID);
|
||||
httpHeader = createHeader(null);
|
||||
response = HttpUtil.executeUrl("POST", urlStr, httpHeader, null, "", 10000);
|
||||
resultOk = true;
|
||||
logger.debug("Execute POST request to {} with header: {}", urlStr, httpHeader.toString());
|
||||
} catch (IOException e) {
|
||||
logger.debug("Error processiong POST request {}", e.getMessage());
|
||||
String message = e.getMessage();
|
||||
if (message != null && message.contains("Authentication challenge without WWW-Authenticate ")) {
|
||||
statusDescr = "Cannot connect to stove. Given PIN: " + config.hostPIN + " is incorrect!";
|
||||
}
|
||||
resultOk = false;
|
||||
}
|
||||
}
|
||||
if (resultOk) {
|
||||
logger.debug("OvenData = {}", response);
|
||||
refreshOvenConnection();
|
||||
httpHeader = createHeader(postData != null ? postData : null);
|
||||
response = HttpUtil.executeUrl("POST", urlStr, httpHeader, targetStream != null ? targetStream : null,
|
||||
"application/json", 10000);
|
||||
logger.debug("Execute POST request with content to {} with header: {}", urlStr, httpHeader.toString());
|
||||
ovenData = gson.fromJson(response, HaasSohnpelletstoveJsonDataDTO.class);
|
||||
} else {
|
||||
logger.debug("Setting thing '{}' to OFFLINE: Error '{}': {}", thingUID, error, errorDetail);
|
||||
ovenData = new HaasSohnpelletstoveJsonDataDTO();
|
||||
logger.debug("OvenData = {}", response);
|
||||
} catch (IOException e) {
|
||||
logger.debug("Error processiong POST request {}", urlStr);
|
||||
error = "Cannot execute command on Stove. Please verify connection or PIN";
|
||||
|
||||
} catch (JsonSyntaxException e) {
|
||||
logger.debug("Error in establishing connection: {}", e.getMessage());
|
||||
error = "Cannot find service on given IP " + config.hostIP + ". Please verify the IP address!";
|
||||
}
|
||||
helper.setStatusDescription(statusDescr);
|
||||
return resultOk;
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2025 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.haassohnpelletstove.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link Helper} is a Helper class to overcome Call by value for a Status Description.
|
||||
*
|
||||
*
|
||||
* @author Christian Feininger - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Helper {
|
||||
|
||||
private String statusDescription = "";
|
||||
|
||||
/***
|
||||
* Gets the Status Description
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getStatusDesription() {
|
||||
return statusDescription;
|
||||
}
|
||||
|
||||
/***
|
||||
* Sets the Status Description
|
||||
*
|
||||
* @param status
|
||||
*/
|
||||
public void setStatusDescription(@Nullable String status) {
|
||||
if (status != null) {
|
||||
statusDescription = statusDescription + "\n" + status;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -36,7 +36,7 @@
|
|||
<label>PIN</label>
|
||||
<description>Please add the PIN of your oven here. You can find it in the Menu directly in your oven.</description>
|
||||
</parameter>
|
||||
<parameter name="refreshRate" type="integer" unit="s" min="0" max="1000">
|
||||
<parameter name="refreshRate" type="integer" unit="s" min="1" max="1000">
|
||||
<label>Refresh Rate</label>
|
||||
<description>How often the Pellet Stove should schedule a refresh after a channel is linked to an item. Temperature
|
||||
data will be refreshed according this set time in seconds. Valid input is 0 - 999.
|
||||
|
|
Loading…
Reference in New Issue