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;
55 public synchronized void connect() throws IOException {
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;
67 public synchronized void disconnect() {
72 Socket localSocket = this.socket;
73 if (localSocket != null) {
76 } catch (IOException ioe) {
77 logger.debug("Connection to air unit could not be closed gracefully. {}", ioe.getMessage());
80 this.inputStream = null;
81 this.outputStream = null;
86 public byte[] sendRobustRequest(byte[] operation, byte[] register) throws IOException {
87 return sendRobustRequest(operation, register, EMPTY);
90 public synchronized byte[] sendRobustRequest(byte[] operation, byte[] register, byte[] value) throws IOException {
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);
97 return sendRequestInternal(request);
98 } catch (IOException ioe) {
99 // retry once if there was connection problem
102 return sendRequestInternal(request);
106 private synchronized byte[] sendRequestInternal(byte[] request) throws IOException {
107 OutputStream localOutputStream = this.outputStream;
109 if (localOutputStream == null) {
110 throw new IOException(
111 String.format("Output stream is null while sending request: %s", Arrays.toString(request)));
113 localOutputStream.write(request);
114 localOutputStream.flush();
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)));
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));