]> git.basschouten.com Git - openhab-addons.git/blob
b7ad9a801fd7492e4c66e256fb67ec320328e921
[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.epsonprojector.internal.connector;
14
15 import static org.openhab.binding.epsonprojector.internal.EpsonProjectorBindingConstants.DEFAULT_PORT;
16
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.io.OutputStream;
20 import java.net.Socket;
21 import java.nio.charset.StandardCharsets;
22
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.openhab.binding.epsonprojector.internal.EpsonProjectorException;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 /**
30  * Connector for TCP communication.
31  *
32  * @author Pauli Anttila - Initial contribution
33  * @author Michael Lobstein - Improvements for OH3
34  */
35 @NonNullByDefault
36 public class EpsonProjectorTcpConnector implements EpsonProjectorConnector {
37     private static final String ESC_VP_HANDSHAKE = "ESC/VP.net\u0010\u0003\u0000\u0000\u0000\u0000";
38
39     private final Logger logger = LoggerFactory.getLogger(EpsonProjectorTcpConnector.class);
40     private final String ip;
41     private final int port;
42
43     private @Nullable Socket socket = null;
44     private @Nullable InputStream in = null;
45     private @Nullable OutputStream out = null;
46
47     public EpsonProjectorTcpConnector(String ip, int port) {
48         this.ip = ip;
49         this.port = port;
50     }
51
52     @Override
53     public void connect() throws EpsonProjectorException {
54         logger.debug("Open connection to address'{}:{}'", ip, port);
55
56         try {
57             Socket socket = new Socket(ip, port);
58             this.socket = socket;
59             in = socket.getInputStream();
60             out = socket.getOutputStream();
61         } catch (IOException e) {
62             throw new EpsonProjectorException(e);
63         }
64
65         // Projectors with built in Ethernet listen on 3629, we must send the handshake to initialize the connection
66         if (port == DEFAULT_PORT) {
67             try {
68                 String response = sendMessage(ESC_VP_HANDSHAKE, 5000);
69                 logger.debug("Response to initialisation of ESC/VP.net is: {}", response);
70             } catch (EpsonProjectorException e) {
71                 logger.debug("Error within initialisation of ESC/VP.net: {}", e.getMessage());
72             }
73         }
74     }
75
76     @Override
77     public void disconnect() throws EpsonProjectorException {
78         OutputStream out = this.out;
79
80         if (out != null) {
81             logger.debug("Close tcp out stream");
82             try {
83                 out.close();
84             } catch (IOException e) {
85                 logger.debug("Error occurred when closing tcp out stream: {}", e.getMessage());
86             }
87         }
88
89         InputStream in = this.in;
90         if (in != null) {
91             logger.debug("Close tcp in stream");
92             try {
93                 in.close();
94             } catch (IOException e) {
95                 logger.debug("Error occurred when closing tcp in stream: {}", e.getMessage());
96             }
97         }
98
99         Socket socket = this.socket;
100         if (socket != null) {
101             logger.debug("Closing socket");
102             try {
103                 socket.close();
104             } catch (IOException e) {
105                 logger.debug("Error occurred when closing tcp socket: {}", e.getMessage());
106             }
107         }
108
109         this.socket = null;
110         this.out = null;
111         this.in = null;
112
113         logger.debug("Closed");
114     }
115
116     @Override
117     public String sendMessage(String data, int timeout) throws EpsonProjectorException {
118         InputStream in = this.in;
119         OutputStream out = this.out;
120
121         if (in == null || out == null) {
122             connect();
123             in = this.in;
124             out = this.out;
125         }
126
127         try {
128             if (in != null) {
129                 // flush input stream
130                 if (in.markSupported()) {
131                     in.reset();
132                 } else {
133                     while (in.available() > 0) {
134                         int availableBytes = in.available();
135
136                         if (availableBytes > 0) {
137                             byte[] tmpData = new byte[availableBytes];
138                             in.read(tmpData, 0, availableBytes);
139                         }
140                     }
141                 }
142                 return sendMmsg(data, timeout);
143             } else {
144                 return "";
145             }
146         } catch (IOException e) {
147             logger.debug("IO error occurred...reconnect and resend once: {}", e.getMessage());
148             disconnect();
149             connect();
150
151             try {
152                 return sendMmsg(data, timeout);
153             } catch (IOException e1) {
154                 throw new EpsonProjectorException(e);
155             }
156         }
157     }
158
159     private String sendMmsg(String data, int timeout) throws IOException, EpsonProjectorException {
160         String resp = "";
161
162         InputStream in = this.in;
163         OutputStream out = this.out;
164
165         if (in != null && out != null) {
166             out.write(data.getBytes(StandardCharsets.US_ASCII));
167             out.write("\r\n".getBytes(StandardCharsets.US_ASCII));
168             out.flush();
169
170             long startTime = System.currentTimeMillis();
171             long elapsedTime = 0;
172
173             while (elapsedTime < timeout) {
174                 int availableBytes = in.available();
175                 if (availableBytes > 0) {
176                     byte[] tmpData = new byte[availableBytes];
177                     int readBytes = in.read(tmpData, 0, availableBytes);
178                     resp = resp.concat(new String(tmpData, 0, readBytes, StandardCharsets.US_ASCII));
179
180                     if (resp.contains(":")) {
181                         return resp;
182                     }
183                 } else {
184                     try {
185                         Thread.sleep(100);
186                     } catch (InterruptedException e) {
187                         throw new EpsonProjectorException(e);
188                     }
189                 }
190
191                 elapsedTime = System.currentTimeMillis() - startTime;
192             }
193         }
194         return resp;
195     }
196 }