]> git.basschouten.com Git - openhab-addons.git/blob
0b4747271759d34e3ee971f53ee226f8c26a7b78
[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.denonmarantz.internal.connector.telnet;
14
15 import java.io.BufferedReader;
16 import java.io.IOException;
17 import java.io.InputStreamReader;
18 import java.io.OutputStreamWriter;
19 import java.net.InetSocketAddress;
20 import java.net.Socket;
21 import java.net.SocketTimeoutException;
22
23 import org.openhab.binding.denonmarantz.internal.config.DenonMarantzConfiguration;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 /**
28  * Manage telnet connection to the Denon/Marantz Receiver
29  *
30  * @author Jeroen Idserda - Initial contribution (1.x Binding)
31  * @author Jan-Willem Veldhuis - Refactored for 2.x
32  */
33 public class DenonMarantzTelnetClientThread extends Thread {
34
35     private Logger logger = LoggerFactory.getLogger(DenonMarantzTelnetClientThread.class);
36
37     private static final Integer RECONNECT_DELAY = 60000; // 1 minute
38
39     private static final Integer TIMEOUT = 60000; // 1 minute
40
41     private DenonMarantzConfiguration config;
42
43     private DenonMarantzTelnetListener listener;
44
45     private boolean connected = false;
46
47     private Socket socket;
48
49     private OutputStreamWriter out;
50
51     private BufferedReader in;
52
53     public DenonMarantzTelnetClientThread(DenonMarantzConfiguration config, DenonMarantzTelnetListener listener) {
54         logger.debug("Denon listener created");
55         this.config = config;
56         this.listener = listener;
57     }
58
59     @Override
60     public void run() {
61         while (!isInterrupted()) {
62             if (!connected) {
63                 connectTelnetSocket();
64             }
65
66             do {
67                 try {
68                     String line = in.readLine();
69                     if (line == null) {
70                         logger.debug("No more data read from client. Disconnecting..");
71                         listener.telnetClientConnected(false);
72                         disconnect();
73                         break;
74                     }
75                     logger.trace("Received from {}: {}", config.getHost(), line);
76                     if (!line.isBlank()) {
77                         listener.receivedLine(line);
78                     }
79                 } catch (SocketTimeoutException e) {
80                     logger.trace("Socket timeout");
81                     // Disconnects are not always detected unless you write to the socket.
82                     try {
83                         out.write('\r');
84                         out.flush();
85                     } catch (IOException e2) {
86                         logger.debug("Error writing to socket");
87                         connected = false;
88                     }
89                 } catch (IOException e) {
90                     if (!isInterrupted()) {
91                         // only log if we don't stop this on purpose causing a SocketClosed
92                         logger.debug("Error in telnet connection ", e);
93                     }
94                     connected = false;
95                     listener.telnetClientConnected(false);
96                 }
97             } while (!isInterrupted() && connected);
98         }
99         disconnect();
100         logger.debug("Stopped client thread");
101     }
102
103     public void sendCommand(String command) {
104         if (out != null) {
105             try {
106                 out.write(command + '\r');
107                 out.flush();
108             } catch (IOException e) {
109                 logger.debug("Error sending command", e);
110             }
111         } else {
112             logger.debug("Cannot send command, no telnet connection");
113         }
114     }
115
116     public void shutdown() {
117         disconnect();
118     }
119
120     private void connectTelnetSocket() {
121         disconnect();
122         int delay = 0;
123
124         while (!isInterrupted() && (socket == null || !socket.isConnected())) {
125             try {
126                 Thread.sleep(delay);
127                 logger.debug("Connecting to {}", config.getHost());
128
129                 // Use raw socket instead of TelnetClient here because TelnetClient sends an
130                 // extra newline char after each write which causes the connection to become
131                 // unresponsive.
132                 socket = new Socket();
133                 socket.connect(new InetSocketAddress(config.getHost(), config.getTelnetPort()), TIMEOUT);
134                 socket.setKeepAlive(true);
135                 socket.setSoTimeout(TIMEOUT);
136
137                 in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
138                 out = new OutputStreamWriter(socket.getOutputStream(), "UTF-8");
139
140                 connected = true;
141                 listener.telnetClientConnected(true);
142                 logger.debug("Denon telnet client connected to {}", config.getHost());
143             } catch (IOException e) {
144                 logger.debug("Cannot connect to {}", config.getHost(), e);
145                 listener.telnetClientConnected(false);
146             } catch (InterruptedException e) {
147                 logger.debug("Interrupted while connecting to {}", config.getHost(), e);
148                 Thread.currentThread().interrupt();
149             }
150             delay = RECONNECT_DELAY;
151         }
152     }
153
154     public boolean isConnected() {
155         return connected;
156     }
157
158     private void disconnect() {
159         if (socket != null) {
160             logger.debug("Disconnecting socket");
161             try {
162                 socket.close();
163             } catch (IOException e) {
164                 logger.debug("Error while disconnecting telnet client", e);
165             } finally {
166                 socket = null;
167                 out = null;
168                 in = null;
169                 listener.telnetClientConnected(false);
170             }
171         }
172     }
173 }