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