Skip to content

Commit

Permalink
[deconz] fix websocket re-connection (#295)
Browse files Browse the repository at this point in the history
* [deconz] fix websocket re-connection


Signed-off-by: Jan N. Klug <[email protected]>
  • Loading branch information
J-N-K authored Jan 15, 2022
1 parent c9efcaf commit 5aa63ca
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 25 deletions.
15 changes: 8 additions & 7 deletions bundles/org.smarthomej.binding.deconz/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@
public class DeconzBridgeHandler extends BaseBridgeHandler implements WebSocketConnectionListener {
public static final Set<ThingTypeUID> 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;
Expand All @@ -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);
Expand All @@ -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
Expand All @@ -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;
}
}
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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();
Expand All @@ -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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<String, WebSocketMessageListener> listeners = new ConcurrentHashMap<>();
Expand All @@ -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;
Expand All @@ -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);
Expand All @@ -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;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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">

<config-description uri="thing-type:deconz:bridge">
<parameter-group name="http">
<label>HTTP Connection</label>
<advanced>true</advanced>
</parameter-group>
<parameter-group name="websocket">
<label>Websocket Connection</label>
<advanced>true</advanced>
</parameter-group>
<parameter name="host" type="text" required="true">
<label>Host Address</label>
<context>network-address</context>
<description>IP address or host name of deCONZ interface.</description>
</parameter>
<parameter name="httpPort" type="integer" min="1" max="65535">
<label>HTTP Port</label>
<description>Port of the deCONZ HTTP interface.</description>
<default>80</default>
</parameter>
<parameter name="port" type="integer" min="1" max="65535">
<label>Websocket Port</label>
<description>Port of the deCONZ Websocket.</description>
<advanced>true</advanced>
</parameter>
<parameter name="apikey" type="text">
<label>API Key</label>
<context>password</context>
<description>If no API Key is provided, a new one will be requested. You need to authorize the access on the deCONZ
web interface.</description>
</parameter>
<parameter name="timeout" type="integer" unit="ms" min="0">
<parameter name="httpPort" type="integer" min="1" max="65535" groupName="http">
<label>Port</label>
<description>Port of the deCONZ HTTP interface.</description>
<advanced>true</advanced>
<default>80</default>
</parameter>
<parameter name="timeout" type="integer" unit="ms" min="0" groupName="http">
<label>Timeout</label>
<description>Timeout for asynchronous HTTP requests (in milliseconds).</description>
<advanced>true</advanced>
<default>2000</default>
</parameter>
<parameter name="port" type="integer" min="1" max="65535" groupName="websocket">
<label>Port</label>
<description>Port of the deCONZ Websocket.</description>
<advanced>true</advanced>
</parameter>
<parameter name="websocketTimeout" type="integer" unit="s" min="30" groupName="websocket">
<label>Timeout</label>
<description>Timeout for the websocket connection (in seconds).</description>
<advanced>true</advanced>
<default>120</default>
</parameter>
</config-description>

<config-description uri="thing-type:deconz:lightgroup">
Expand Down

0 comments on commit 5aa63ca

Please sign in to comment.