]> git.basschouten.com Git - openhab-addons.git/blob
f96511d585cfa9e082f76423f57265d0bbb40040
[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.innogysmarthome.internal;
14
15 import java.net.URI;
16
17 import org.eclipse.jdt.annotation.NonNullByDefault;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.eclipse.jetty.util.ssl.SslContextFactory;
20 import org.eclipse.jetty.websocket.api.Session;
21 import org.eclipse.jetty.websocket.api.StatusCode;
22 import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
23 import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
24 import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
25 import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
26 import org.eclipse.jetty.websocket.api.annotations.WebSocket;
27 import org.eclipse.jetty.websocket.client.WebSocketClient;
28 import org.openhab.binding.innogysmarthome.internal.handler.InnogyBridgeHandler;
29 import org.openhab.binding.innogysmarthome.internal.listener.EventListener;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 /**
34  * The {@link InnogyWebSocket} implements the websocket for receiving constant updates
35  * from the innogy SmartHome web service.
36  *
37  * @author Oliver Kuhl - Initial contribution
38  */
39 @NonNullByDefault
40 @WebSocket
41 public class InnogyWebSocket {
42
43     private final Logger logger = LoggerFactory.getLogger(InnogyWebSocket.class);
44     private final EventListener eventListener;
45     private final URI webSocketURI;
46     private final int maxIdleTimeout;
47
48     private @Nullable Session session;
49     private @Nullable WebSocketClient client;
50     private boolean closing;
51
52     /**
53      * Constructs the {@link InnogyWebSocket}.
54      *
55      * @param eventListener the responsible {@link InnogyBridgeHandler}
56      * @param webSocketURI the {@link URI} of the websocket endpoint
57      * @param maxIdleTimeout
58      */
59     public InnogyWebSocket(EventListener eventListener, URI webSocketURI, int maxIdleTimeout) {
60         this.eventListener = eventListener;
61         this.webSocketURI = webSocketURI;
62         this.maxIdleTimeout = maxIdleTimeout;
63     }
64
65     /**
66      * Starts the {@link InnogyWebSocket}.
67      *
68      * @throws Exception
69      */
70     public synchronized void start() throws Exception {
71         if (client == null || client.isStopped()) {
72             client = startWebSocketClient();
73         }
74
75         if (session != null) {
76             session.close();
77         }
78
79         logger.debug("Connecting to innogy WebSocket...");
80         session = client.connect(this, webSocketURI).get();
81     }
82
83     /**
84      * Stops the {@link InnogyWebSocket}.
85      */
86     public synchronized void stop() {
87         this.closing = true;
88         if (isRunning()) {
89             logger.debug("Closing session...");
90             session.close();
91             session = null;
92         } else {
93             session = null;
94             logger.trace("Stopping websocket ignored - was not running.");
95         }
96         if (client != null) {
97             try {
98                 client.stop();
99                 client.destroy();
100             } catch (Exception e) {
101                 logger.debug("Stopping websocket failed", e);
102             }
103             client = null;
104         }
105     }
106
107     /**
108      * Return true, if the websocket is running.
109      *
110      * @return
111      */
112     public synchronized boolean isRunning() {
113         return session != null && session.isOpen();
114     }
115
116     @OnWebSocketConnect
117     public void onConnect(Session session) {
118         this.closing = false;
119         logger.info("Connected to innogy Webservice.");
120         logger.trace("innogy Websocket session: {}", session);
121     }
122
123     @OnWebSocketClose
124     public void onClose(int statusCode, String reason) {
125         if (statusCode == StatusCode.NORMAL) {
126             logger.info("Connection to innogy Webservice was closed normally.");
127         } else if (!closing) {
128             // An additional reconnect attempt is only required when the close/stop wasn't executed by the binding.
129             logger.info("Connection to innogy Webservice was closed abnormally (code: {}). Reason: {}", statusCode,
130                     reason);
131             eventListener.connectionClosed();
132         }
133     }
134
135     @OnWebSocketError
136     public void onError(Throwable cause) {
137         logger.debug("innogy WebSocket onError() - {}", cause.getMessage());
138         eventListener.onError(cause);
139     }
140
141     @OnWebSocketMessage
142     public void onMessage(String msg) {
143         logger.debug("innogy WebSocket onMessage() - {}", msg);
144         if (closing) {
145             logger.debug("innogy WebSocket onMessage() - ignored, WebSocket is closing...");
146         } else {
147             eventListener.onEvent(msg);
148         }
149     }
150
151     WebSocketClient startWebSocketClient() throws Exception {
152         WebSocketClient client = new WebSocketClient(new SslContextFactory.Client());
153         client.setMaxIdleTimeout(this.maxIdleTimeout);
154         client.start();
155         return client;
156     }
157 }