2 * Copyright (c) 2010-2024 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.gce.internal.handler;
15 import java.io.BufferedReader;
16 import java.io.IOException;
17 import java.io.InputStreamReader;
18 import java.io.PrintWriter;
19 import java.net.Socket;
20 import java.net.SocketTimeoutException;
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.openhab.binding.gce.internal.model.M2MMessageParser;
25 import org.openhab.core.thing.ThingUID;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
30 * The {@link Ipx800DeviceConnector} is responsible for connecting,
31 * reading, writing and disconnecting from the Ipx800.
33 * @author Seebag - Initial Contribution
34 * @author Gaƫl L'hopital - Ported and adapted for OH2
37 public class Ipx800DeviceConnector extends Thread {
38 private final Logger logger = LoggerFactory.getLogger(Ipx800DeviceConnector.class);
39 private static final int DEFAULT_SOCKET_TIMEOUT_MS = 5000;
40 private static final int DEFAULT_RECONNECT_TIMEOUT_MS = 5000;
41 private static final int MAX_KEEPALIVE_FAILURE = 3;
42 private static final String ENDL = "\r\n";
44 private final String hostname;
45 private final int portNumber;
46 private @Nullable M2MMessageParser parser;
48 private @NonNullByDefault({}) Socket client;
49 private @NonNullByDefault({}) BufferedReader in;
50 private @NonNullByDefault({}) PrintWriter out;
52 private int failedKeepalive = 0;
53 private boolean waitingKeepaliveResponse = false;
55 public Ipx800DeviceConnector(String hostname, int portNumber, ThingUID uid) {
56 super("OH-binding-" + uid);
57 this.hostname = hostname;
58 this.portNumber = portNumber;
62 public synchronized void send(String message) {
63 logger.debug("Sending '{}' to Ipx800", message);
64 out.write(message + ENDL);
69 * Connect to the ipx800
73 private void connect() throws IOException {
75 logger.debug("Connecting {}:{}...", hostname, portNumber);
76 client = new Socket(hostname, portNumber);
77 client.setSoTimeout(DEFAULT_SOCKET_TIMEOUT_MS);
78 client.getInputStream().skip(client.getInputStream().available());
79 in = new BufferedReader(new InputStreamReader(client.getInputStream()));
80 out = new PrintWriter(client.getOutputStream(), true);
84 * Disconnect the device
86 private void disconnect() {
87 logger.debug("Disconnecting");
92 } catch (IOException ignore) {
100 if (client != null) {
103 } catch (IOException ignore) {
107 logger.debug("Disconnected");
111 * Stop the device thread
113 public void dispose() {
119 * Send an arbitrary keepalive command which cause the IPX to send an update.
120 * If we don't receive the update maxKeepAliveFailure time, the connection is closed and reopened
122 private void sendKeepalive() {
124 if (waitingKeepaliveResponse) {
126 logger.debug("Sending keepalive, attempt {}", failedKeepalive);
129 logger.debug("Sending keepalive");
131 out.println("GetIn01");
133 waitingKeepaliveResponse = true;
140 waitingKeepaliveResponse = false;
143 while (!interrupted()) {
144 if (failedKeepalive > MAX_KEEPALIVE_FAILURE) {
145 throw new IOException("Max keep alive attempts has been reached");
148 String command = in.readLine();
149 waitingKeepaliveResponse = false;
150 if (parser != null) {
151 parser.unsolicitedUpdate(command);
153 } catch (SocketTimeoutException e) {
158 } catch (IOException e) {
162 Thread.sleep(DEFAULT_RECONNECT_TIMEOUT_MS);
163 } catch (InterruptedException e) {
168 private void handleException(Exception e) {
169 if (!interrupted()) {
170 if (e instanceof SocketTimeoutException) {
173 } else if (e instanceof IOException) {
174 logger.warn("Communication error : '{}', will retry in {} ms", e, DEFAULT_RECONNECT_TIMEOUT_MS);
176 if (parser != null) {
177 parser.errorOccurred(e);
182 public void setParser(M2MMessageParser parser) {
183 this.parser = parser;