]> git.basschouten.com Git - openhab-addons.git/blob
e7c51a175fbce750ee02256da509edbf4f5d3e5c
[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.danfossairunit.internal;
14
15 import static org.openhab.binding.danfossairunit.internal.Commands.EMPTY;
16
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.io.OutputStream;
20 import java.net.InetAddress;
21 import java.net.Socket;
22 import java.util.Arrays;
23
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 /**
30  * The {@link DanfossAirUnitCommunicationController} class does the actual network communication with the air unit.
31  *
32  * @author Robert Bach - initial contribution
33  * @author Jacob Laursen - Refactoring, bugfixes and enhancements
34  */
35
36 @NonNullByDefault
37 public class DanfossAirUnitCommunicationController implements CommunicationController {
38
39     private static final int SOCKET_TIMEOUT_MILLISECONDS = 5_000;
40
41     private final Logger logger = LoggerFactory.getLogger(DanfossAirUnitCommunicationController.class);
42
43     private final InetAddress inetAddr;
44     private final int port;
45     private boolean connected = false;
46     private @Nullable Socket socket;
47     private @Nullable OutputStream outputStream;
48     private @Nullable InputStream inputStream;
49
50     public DanfossAirUnitCommunicationController(InetAddress inetAddr, int port) {
51         this.inetAddr = inetAddr;
52         this.port = port;
53     }
54
55     public synchronized void connect() throws IOException {
56         if (connected) {
57             return;
58         }
59         Socket localSocket = new Socket(inetAddr, port);
60         localSocket.setSoTimeout(SOCKET_TIMEOUT_MILLISECONDS);
61         this.outputStream = localSocket.getOutputStream();
62         this.inputStream = localSocket.getInputStream();
63         this.socket = localSocket;
64         connected = true;
65     }
66
67     public synchronized void disconnect() {
68         if (!connected) {
69             return;
70         }
71         try {
72             Socket localSocket = this.socket;
73             if (localSocket != null) {
74                 localSocket.close();
75             }
76         } catch (IOException ioe) {
77             logger.debug("Connection to air unit could not be closed gracefully. {}", ioe.getMessage());
78         } finally {
79             this.socket = null;
80             this.inputStream = null;
81             this.outputStream = null;
82         }
83         connected = false;
84     }
85
86     public byte[] sendRobustRequest(byte[] operation, byte[] register) throws IOException {
87         return sendRobustRequest(operation, register, EMPTY);
88     }
89
90     public synchronized byte[] sendRobustRequest(byte[] operation, byte[] register, byte[] value) throws IOException {
91         connect();
92         byte[] request = new byte[4 + value.length];
93         System.arraycopy(operation, 0, request, 0, 2);
94         System.arraycopy(register, 0, request, 2, 2);
95         System.arraycopy(value, 0, request, 4, value.length);
96         try {
97             return sendRequestInternal(request);
98         } catch (IOException ioe) {
99             // retry once if there was connection problem
100             disconnect();
101             connect();
102             return sendRequestInternal(request);
103         }
104     }
105
106     private synchronized byte[] sendRequestInternal(byte[] request) throws IOException {
107         OutputStream localOutputStream = this.outputStream;
108
109         if (localOutputStream == null) {
110             throw new IOException(
111                     String.format("Output stream is null while sending request: %s", Arrays.toString(request)));
112         }
113         localOutputStream.write(request);
114         localOutputStream.flush();
115
116         byte[] result = new byte[63];
117         InputStream localInputStream = this.inputStream;
118         if (localInputStream == null) {
119             throw new IOException(
120                     String.format("Input stream is null while sending request: %s", Arrays.toString(request)));
121         }
122
123         int bytesRead = localInputStream.read(result, 0, 63);
124         if (bytesRead < 63) {
125             throw new IOException(String.format(
126                     "Error reading from stream, read returned %d as number of bytes read into the buffer", bytesRead));
127         }
128
129         return result;
130     }
131 }