2 * Copyright (c) 2010-2023 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.danfossairunit.internal;
15 import static org.openhab.binding.danfossairunit.internal.Commands.EMPTY;
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;
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
30 * The {@link DanfossAirUnitCommunicationController} class does the actual network communication with the air unit.
32 * @author Robert Bach - initial contribution
33 * @author Jacob Laursen - Refactoring, bugfixes and enhancements
37 public class DanfossAirUnitCommunicationController implements CommunicationController {
39 private static final int SOCKET_TIMEOUT_MILLISECONDS = 5_000;
41 private final Logger logger = LoggerFactory.getLogger(DanfossAirUnitCommunicationController.class);
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;
50 public DanfossAirUnitCommunicationController(InetAddress inetAddr, int port) {
51 this.inetAddr = inetAddr;
56 public synchronized void connect() throws IOException {
60 Socket localSocket = new Socket(inetAddr, port);
61 localSocket.setSoTimeout(SOCKET_TIMEOUT_MILLISECONDS);
62 this.outputStream = localSocket.getOutputStream();
63 this.inputStream = localSocket.getInputStream();
64 this.socket = localSocket;
69 public synchronized void disconnect() {
74 Socket localSocket = this.socket;
75 if (localSocket != null) {
78 } catch (IOException ioe) {
79 logger.debug("Connection to air unit could not be closed gracefully. {}", ioe.getMessage());
82 this.inputStream = null;
83 this.outputStream = null;
89 public byte[] sendRobustRequest(byte[] operation, byte[] register) throws IOException {
90 return sendRobustRequest(operation, register, EMPTY);
94 public synchronized byte[] sendRobustRequest(byte[] operation, byte[] register, byte[] value) throws IOException {
96 byte[] request = new byte[4 + value.length];
97 System.arraycopy(operation, 0, request, 0, 2);
98 System.arraycopy(register, 0, request, 2, 2);
99 System.arraycopy(value, 0, request, 4, value.length);
101 return sendRequestInternal(request);
102 } catch (IOException ioe) {
103 // retry once if there was connection problem
106 return sendRequestInternal(request);
110 private synchronized byte[] sendRequestInternal(byte[] request) throws IOException {
111 OutputStream localOutputStream = this.outputStream;
113 if (localOutputStream == null) {
114 throw new IOException(
115 String.format("Output stream is null while sending request: %s", Arrays.toString(request)));
117 localOutputStream.write(request);
118 localOutputStream.flush();
120 byte[] result = new byte[63];
121 InputStream localInputStream = this.inputStream;
122 if (localInputStream == null) {
123 throw new IOException(
124 String.format("Input stream is null while sending request: %s", Arrays.toString(request)));
127 int bytesRead = localInputStream.read(result, 0, 63);
128 if (bytesRead < 63) {
129 throw new IOException(String.format(
130 "Error reading from stream, read returned %d as number of bytes read into the buffer", bytesRead));