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.tplinksmarthome.internal;
15 import java.io.IOException;
16 import java.io.InputStream;
17 import java.io.OutputStream;
18 import java.net.Socket;
19 import java.net.UnknownHostException;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
27 * This class acts as and interface to the physical device.
29 * @author Christian Fischer - Initial contribution
30 * @author Hilbrand Bouwkamp - Reorganized code and put connection in single class
33 public class Connection {
35 public static final int TP_LINK_SMART_HOME_PORT = 9999;
36 private static final int SOCKET_TIMEOUT_MILLISECONDS = 2_000;
38 private final Logger logger = LoggerFactory.getLogger(Connection.class);
40 private @Nullable String ipAddress;
43 * Initializes a connection to the given ip address.
45 * @param ipAddress ip address of the connection
47 public Connection(@Nullable final String ipAddress) {
48 this.ipAddress = ipAddress;
52 * Set the ip address to connect to.
54 * @param ipAddress The ip address to connect to
56 public void setIpAddress(final String ipAddress) {
57 this.ipAddress = ipAddress;
61 * Sends the command, which is a json string, encrypted to the device and decrypts the json result and returns it
63 * @param command json command to send to the device
64 * @return decrypted returned json result from the device
65 * @throws IOException exception in case device not reachable
67 public synchronized String sendCommand(final String command) throws IOException {
68 logger.trace("Executing command: {}", command);
69 try (Socket socket = createSocket(); final OutputStream outputStream = socket.getOutputStream()) {
70 outputStream.write(CryptUtil.encryptWithLength(command));
71 final String response = readReturnValue(socket);
73 logger.trace("Command response: {}", response);
79 * Reads and decrypts result returned from the device.
81 * @param socket socket to read result from
82 * @return decrypted result
83 * @throws IOException exception in case device not reachable
85 private String readReturnValue(final Socket socket) throws IOException {
86 try (InputStream is = socket.getInputStream()) {
87 return CryptUtil.decryptWithLength(is);
92 * Wrapper around socket creation to make mocking possible.
94 * @return new Socket instance
95 * @throws UnknownHostException exception in case the host could not be determined
96 * @throws IOException exception in case device not reachable
98 protected Socket createSocket() throws UnknownHostException, IOException {
99 if (ipAddress == null) {
100 throw new IOException("Ip address not set. Wait for discovery or manually trigger discovery process.");
102 final Socket socket = new Socket(ipAddress, TP_LINK_SMART_HOME_PORT);
104 socket.setSoTimeout(SOCKET_TIMEOUT_MILLISECONDS);