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.nobohub.internal.connection;
15 import java.time.Duration;
16 import java.time.Instant;
18 import org.eclipse.jdt.annotation.NonNullByDefault;
19 import org.eclipse.jdt.annotation.Nullable;
20 import org.openhab.binding.nobohub.internal.NoboHubBindingConstants;
21 import org.openhab.binding.nobohub.internal.NoboHubBridgeHandler;
22 import org.openhab.binding.nobohub.internal.model.NoboCommunicationException;
23 import org.openhab.core.thing.ThingStatus;
24 import org.openhab.core.thing.ThingStatusDetail;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
29 * Thread that reads from the Nobø Hub and sends HANDSHAKEs to keep the connection open.
31 * @author Jørgen Austvik - Initial contribution
34 public class HubCommunicationThread extends Thread {
36 private enum HubCommunicationThreadState {
37 STARTING(null, null, ""),
38 CONNECTED(ThingStatus.ONLINE, ThingStatusDetail.NONE, ""),
39 DISCONNECTED(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "@text/message.bridge.status.failed"),
40 STOPPED(null, null, "");
42 private final @Nullable ThingStatus status;
43 private final @Nullable ThingStatusDetail statusDetail;
44 private final String errorMessage;
46 HubCommunicationThreadState(@Nullable ThingStatus status, @Nullable ThingStatusDetail statusDetail,
47 String errorMessage) {
49 this.statusDetail = statusDetail;
50 this.errorMessage = errorMessage;
53 public @Nullable ThingStatus getThingStatus() {
57 public @Nullable ThingStatusDetail getThingStatusDetail() {
61 public String getErrorMessage() {
66 private final Logger logger = LoggerFactory.getLogger(HubCommunicationThread.class);
68 private final HubConnection hubConnection;
69 private final NoboHubBridgeHandler hubHandler;
70 private final Duration timeout;
71 private Instant lastTimeFullScan;
73 private volatile boolean stopped = false;
74 private HubCommunicationThreadState currentState = HubCommunicationThreadState.STARTING;
76 public HubCommunicationThread(HubConnection hubConnection, NoboHubBridgeHandler hubHandler, Duration timeout) {
77 this.hubConnection = hubConnection;
78 this.hubHandler = hubHandler;
79 this.timeout = timeout;
80 this.lastTimeFullScan = Instant.now();
83 public void stopNow() {
90 switch (currentState) {
93 hubConnection.refreshAll();
94 lastTimeFullScan = Instant.now();
95 setNextState(HubCommunicationThreadState.CONNECTED);
96 } catch (NoboCommunicationException nce) {
97 logger.debug("Communication error with Hub", nce);
98 setNextState(HubCommunicationThreadState.DISCONNECTED);
104 if (hubConnection.hasData()) {
105 hubConnection.processReads(timeout);
109 .isAfter(lastTimeFullScan.plus(NoboHubBindingConstants.TIME_BETWEEN_FULL_SCANS))) {
110 hubConnection.refreshAll();
111 lastTimeFullScan = Instant.now();
113 hubConnection.handshake();
116 hubConnection.processReads(timeout);
117 } catch (NoboCommunicationException nce) {
118 logger.debug("Communication error with Hub", nce);
119 setNextState(HubCommunicationThreadState.DISCONNECTED);
125 Thread.sleep(NoboHubBindingConstants.TIME_BETWEEN_RETRIES_ON_ERROR.toMillis());
127 logger.debug("Trying to do a hard reconnect");
128 hubConnection.hardReconnect();
129 setNextState(HubCommunicationThreadState.CONNECTED);
130 } catch (NoboCommunicationException nce2) {
131 logger.debug("Failed to reconnect connection", nce2);
133 } catch (InterruptedException ie) {
134 logger.debug("Interrupted from sleep after error");
135 Thread.currentThread().interrupt();
145 logger.debug("HubCommunicationThread is stopped, disconnecting from Hub");
146 setNextState(HubCommunicationThreadState.STOPPED);
148 hubConnection.disconnect();
149 } catch (NoboCommunicationException nce) {
150 logger.debug("Error disconnecting from Hub", nce);
155 public HubConnection getConnection() {
156 return hubConnection;
159 private void setNextState(HubCommunicationThreadState newState) {
160 currentState = newState;
161 ThingStatus stateThingStatus = newState.getThingStatus();
162 ThingStatusDetail stateThingStatusDetail = newState.getThingStatusDetail();
163 if (null != stateThingStatus && null != stateThingStatusDetail) {
164 hubHandler.setStatusInfo(stateThingStatus, stateThingStatusDetail, newState.getErrorMessage());