From 5aa63ca582260e0ed4b147befb201ca59635b0c9 Mon Sep 17 00:00:00 2001 From: J-N-K Date: Sat, 15 Jan 2022 10:30:41 +0100 Subject: [PATCH] [deconz] fix websocket re-connection (#295) * [deconz] fix websocket re-connection Signed-off-by: Jan N. Klug --- .../org.smarthomej.binding.deconz/README.md | 15 ++++---- .../internal/handler/DeconzBridgeConfig.java | 3 +- .../internal/handler/DeconzBridgeHandler.java | 13 +++++-- .../netutils/WebSocketConnection.java | 9 ++++- .../main/resources/OH-INF/config/config.xml | 37 +++++++++++++------ 5 files changed, 52 insertions(+), 25 deletions(-) diff --git a/bundles/org.smarthomej.binding.deconz/README.md b/bundles/org.smarthomej.binding.deconz/README.md index 0003a9522b..c82df714af 100644 --- a/bundles/org.smarthomej.binding.deconz/README.md +++ b/bundles/org.smarthomej.binding.deconz/README.md @@ -59,13 +59,14 @@ If your device is not discovered, please check the DEBUG log for unknown devices These configuration parameters are available: -| Parameter | Description | Type | Default | -|-----------|---------------------------------------------------------------------------------|---------|---------| -| host | Host address (hostname / ip) of deCONZ interface | string | n/a | -| httpPort | Port of deCONZ HTTP interface | string | 80 | -| port | Port of deCONZ Websocket (optional, can be filled automatically) **(Advanced)** | string | n/a | -| apikey | Authorization API key (optional, can be filled automatically) | string | n/a | -| timeout | Timeout for asynchronous HTTP requests (in milliseconds) | integer | 2000 | +| Parameter | Description | Type | Default | +|------------------|-------------------------------------------------------------------------------------------------------------------------|---------|---------| +| host | Host address (hostname / ip) of deCONZ interface | string | n/a | +| httpPort | Port of deCONZ HTTP interface | string | 80 | +| port | Port of deCONZ Websocket (optional, can be filled automatically) **(Advanced)** | string | n/a | +| apikey | Authorization API key (optional, can be filled automatically) | string | n/a | +| timeout | Timeout for asynchronous HTTP requests (in milliseconds) | integer | 2000 | +| websocketTimeout | Timeout for the websocket connection (in s). After this time, the connection is considered dead and tries to re-connect | integer | 120 | The deCONZ bridge requires the IP address or hostname as a configuration value in order for the binding to know where to access it. If needed you can specify an optional port for the HTTP interface or the Websocket. diff --git a/bundles/org.smarthomej.binding.deconz/src/main/java/org/smarthomej/binding/deconz/internal/handler/DeconzBridgeConfig.java b/bundles/org.smarthomej.binding.deconz/src/main/java/org/smarthomej/binding/deconz/internal/handler/DeconzBridgeConfig.java index 63b05d6a4e..77883890d7 100644 --- a/bundles/org.smarthomej.binding.deconz/src/main/java/org/smarthomej/binding/deconz/internal/handler/DeconzBridgeConfig.java +++ b/bundles/org.smarthomej.binding.deconz/src/main/java/org/smarthomej/binding/deconz/internal/handler/DeconzBridgeConfig.java @@ -27,7 +27,8 @@ public class DeconzBridgeConfig { public int httpPort = 80; public int port = 0; public @Nullable String apikey; - int timeout = 2000; + public int timeout = 2000; + public int websocketTimeout = 120; public String getHostWithoutPort() { String hostWithoutPort = host; diff --git a/bundles/org.smarthomej.binding.deconz/src/main/java/org/smarthomej/binding/deconz/internal/handler/DeconzBridgeHandler.java b/bundles/org.smarthomej.binding.deconz/src/main/java/org/smarthomej/binding/deconz/internal/handler/DeconzBridgeHandler.java index e90ffa29ff..898dabbc4e 100644 --- a/bundles/org.smarthomej.binding.deconz/src/main/java/org/smarthomej/binding/deconz/internal/handler/DeconzBridgeHandler.java +++ b/bundles/org.smarthomej.binding.deconz/src/main/java/org/smarthomej/binding/deconz/internal/handler/DeconzBridgeHandler.java @@ -69,8 +69,6 @@ public class DeconzBridgeHandler extends BaseBridgeHandler implements WebSocketConnectionListener { public static final Set SUPPORTED_THING_TYPES = Set.of(BRIDGE_TYPE); - private static final int WEBSOCKET_WATCHDOG_INTERVAL = 120; // in s - private final Logger logger = LoggerFactory.getLogger(DeconzBridgeHandler.class); private final AsyncHttpClient http; private final WebSocketFactory webSocketFactory; @@ -87,6 +85,7 @@ public class DeconzBridgeHandler extends BaseBridgeHandler implements WebSocketC /** The poll frequency for the API Key verification */ private static final int POLL_FREQUENCY_SEC = 10; + private boolean ignoreConnectionLost = true; public DeconzBridgeHandler(Bridge thing, WebSocketFactory webSocketFactory, AsyncHttpClient http, Gson gson) { super(thing); @@ -104,7 +103,7 @@ private WebSocketConnection createNewWebSocketConnection() { websocketID = websocketID.substring(websocketID.length() - 20); } return new WebSocketConnection(this, webSocketFactory.createWebSocketClient(websocketID), gson, - WEBSOCKET_WATCHDOG_INTERVAL); + config.websocketTimeout); } @Override @@ -129,7 +128,7 @@ public void handleCommand(ChannelUID channelUID, Command command) { private void stopTimer() { ScheduledFuture future = connectionJob; if (future != null) { - future.cancel(true); + future.cancel(false); connectionJob = null; } } @@ -266,6 +265,7 @@ public void initializeBridgeState() { * {@link #initializeBridgeState} need to be called first to obtain the websocket port. */ private void startWebSocketConnection() { + ignoreConnectionLost = false; if (webSocketConnection.isConnected() || websocketPort == 0 || thingDisposing) { return; } @@ -297,6 +297,7 @@ public void initialize() { logger.debug("Start initializing bridge {}", thing.getUID()); thingDisposing = false; config = getConfigAs(DeconzBridgeConfig.class); + webSocketConnection.setWatchdogInterval(config.websocketTimeout); updateStatus(ThingStatus.UNKNOWN); if (config.apikey == null) { requestApiKey(); @@ -320,6 +321,10 @@ public void webSocketConnectionEstablished() { @Override public void webSocketConnectionLost(String reason) { + if (ignoreConnectionLost) { + return; + } + ignoreConnectionLost = true; updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, reason); stopTimer(); diff --git a/bundles/org.smarthomej.binding.deconz/src/main/java/org/smarthomej/binding/deconz/internal/netutils/WebSocketConnection.java b/bundles/org.smarthomej.binding.deconz/src/main/java/org/smarthomej/binding/deconz/internal/netutils/WebSocketConnection.java index 431361012a..741f6cb44a 100644 --- a/bundles/org.smarthomej.binding.deconz/src/main/java/org/smarthomej/binding/deconz/internal/netutils/WebSocketConnection.java +++ b/bundles/org.smarthomej.binding.deconz/src/main/java/org/smarthomej/binding/deconz/internal/netutils/WebSocketConnection.java @@ -56,7 +56,7 @@ public class WebSocketConnection { private final WebSocketClient client; private final String socketName; private final Gson gson; - private final int watchdogInterval; + private int watchdogInterval; private final WebSocketConnectionListener connectionListener; private final Map listeners = new ConcurrentHashMap<>(); @@ -76,6 +76,10 @@ public WebSocketConnection(WebSocketConnectionListener listener, WebSocketClient this.watchdogInterval = watchdogInterval; } + public void setWatchdogInterval(int watchdogInterval) { + this.watchdogInterval = watchdogInterval; + } + public void start(String ip) { if (connectionState == ConnectionState.CONNECTED) { return; @@ -87,6 +91,7 @@ public void start(String ip) { return; } try { + connectionState = ConnectionState.CONNECTING; URI destUri = URI.create("ws://" + ip); client.start(); logger.debug("Trying to connect {} to {}", socketName, destUri); @@ -113,7 +118,7 @@ private void startOrResetWatchdogTimer() { private void stopWatchdogTimer() { ScheduledFuture watchdogTimer = this.watchdogJob; if (watchdogTimer != null) { - watchdogTimer.cancel(true); + watchdogTimer.cancel(false); this.watchdogJob = null; } } diff --git a/bundles/org.smarthomej.binding.deconz/src/main/resources/OH-INF/config/config.xml b/bundles/org.smarthomej.binding.deconz/src/main/resources/OH-INF/config/config.xml index ad78b2120f..c9ac5f7fcb 100644 --- a/bundles/org.smarthomej.binding.deconz/src/main/resources/OH-INF/config/config.xml +++ b/bundles/org.smarthomej.binding.deconz/src/main/resources/OH-INF/config/config.xml @@ -5,33 +5,48 @@ xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0 https://openhab.org/schemas/config-description-1.0.0.xsd"> + + + true + + + + true + network-address IP address or host name of deCONZ interface. - - - Port of the deCONZ HTTP interface. - 80 - - - - Port of the deCONZ Websocket. - true - password If no API Key is provided, a new one will be requested. You need to authorize the access on the deCONZ web interface. - + + + Port of the deCONZ HTTP interface. + true + 80 + + Timeout for asynchronous HTTP requests (in milliseconds). true 2000 + + + Port of the deCONZ Websocket. + true + + + + Timeout for the websocket connection (in seconds). + true + 120 +