]> git.basschouten.com Git - openhab-addons.git/blob
786761d68e553d16b03b8f19f97085d39db090e1
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.nobohub.internal.connection;
14
15 import java.time.Duration;
16 import java.time.Instant;
17
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;
27
28 /**
29  * Thread that reads from the Nobø Hub and sends HANDSHAKEs to keep the connection open.
30  *
31  * @author Jørgen Austvik - Initial contribution
32  */
33 @NonNullByDefault
34 public class HubCommunicationThread extends Thread {
35
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, "");
41
42         private final @Nullable ThingStatus status;
43         private final @Nullable ThingStatusDetail statusDetail;
44         private final String errorMessage;
45
46         HubCommunicationThreadState(@Nullable ThingStatus status, @Nullable ThingStatusDetail statusDetail,
47                 String errorMessage) {
48             this.status = status;
49             this.statusDetail = statusDetail;
50             this.errorMessage = errorMessage;
51         }
52
53         public @Nullable ThingStatus getThingStatus() {
54             return status;
55         }
56
57         public @Nullable ThingStatusDetail getThingStatusDetail() {
58             return statusDetail;
59         }
60
61         public String getErrorMessage() {
62             return errorMessage;
63         }
64     }
65
66     private final Logger logger = LoggerFactory.getLogger(HubCommunicationThread.class);
67
68     private final HubConnection hubConnection;
69     private final NoboHubBridgeHandler hubHandler;
70     private final Duration timeout;
71     private Instant lastTimeFullScan;
72
73     private volatile boolean stopped = false;
74     private HubCommunicationThreadState currentState = HubCommunicationThreadState.STARTING;
75
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();
81     }
82
83     public void stopNow() {
84         stopped = true;
85     }
86
87     @Override
88     public void run() {
89         while (!stopped) {
90             switch (currentState) {
91                 case STARTING:
92                     try {
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);
99                     }
100                     break;
101
102                 case CONNECTED:
103                     try {
104                         if (hubConnection.hasData()) {
105                             hubConnection.processReads(timeout);
106                         }
107
108                         if (Instant.now()
109                                 .isAfter(lastTimeFullScan.plus(NoboHubBindingConstants.TIME_BETWEEN_FULL_SCANS))) {
110                             hubConnection.refreshAll();
111                             lastTimeFullScan = Instant.now();
112                         } else {
113                             hubConnection.handshake();
114                         }
115
116                         hubConnection.processReads(timeout);
117                     } catch (NoboCommunicationException nce) {
118                         logger.debug("Communication error with Hub", nce);
119                         setNextState(HubCommunicationThreadState.DISCONNECTED);
120                     }
121                     break;
122
123                 case DISCONNECTED:
124                     try {
125                         Thread.sleep(NoboHubBindingConstants.TIME_BETWEEN_RETRIES_ON_ERROR.toMillis());
126                         try {
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);
132                         }
133                     } catch (InterruptedException ie) {
134                         logger.debug("Interrupted from sleep after error");
135                         Thread.currentThread().interrupt();
136                     }
137                     break;
138
139                 case STOPPED:
140                     break;
141             }
142         }
143
144         if (stopped) {
145             logger.debug("HubCommunicationThread is stopped, disconnecting from Hub");
146             setNextState(HubCommunicationThreadState.STOPPED);
147             try {
148                 hubConnection.disconnect();
149             } catch (NoboCommunicationException nce) {
150                 logger.debug("Error disconnecting from Hub", nce);
151             }
152         }
153     }
154
155     public HubConnection getConnection() {
156         return hubConnection;
157     }
158
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());
165         }
166     }
167 }