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.insteon.internal.driver;
15 import java.io.EOFException;
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.io.OutputStream;
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.openhab.binding.insteon.internal.driver.hub.HubIOStream;
23 import org.openhab.core.io.transport.serial.SerialPortManager;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
28 * Abstract class for implementation for I/O stream with anything that looks
29 * like a PLM (e.g. the insteon hubs, serial/usb connection etc)
31 * @author Bernd Pfrommer - Initial contribution
32 * @author Daniel Pfrommer - openHAB 1 insteonplm binding
33 * @author Rob Nielsen - Port to openHAB 2 insteon binding
36 public abstract class IOStream {
37 private static final Logger logger = LoggerFactory.getLogger(IOStream.class);
38 protected @Nullable InputStream in = null;
39 protected @Nullable OutputStream out = null;
40 private volatile boolean stopped = false;
51 * read data from iostream
53 * @param b byte array (output)
54 * @param offset offset for placement into byte array
55 * @param readSize size to read
56 * @return number of bytes read
58 public int read(byte[] b, int offset, int readSize) throws InterruptedException, IOException {
60 while (!stopped && len < 1) {
61 InputStream in = this.in;
63 len = in.read(b, offset, readSize);
65 throw new IOException("in is null");
68 throw new EOFException();
71 if (Thread.interrupted()) {
72 throw new InterruptedException();
79 * Write data to iostream
81 * @param b byte array to write
83 public void write(byte @Nullable [] b) throws IOException {
84 OutputStream out = this.out;
88 throw new IOException("out is null");
95 * @return true if open was successful, false if not
97 public abstract boolean open();
100 * Closes the IOStream
102 public abstract void close();
105 * Creates an IOStream from an allowed config string:
107 * /dev/ttyXYZ (serial port like e.g. usb: /dev/ttyUSB0 or alias /dev/insteon)
109 * /hub2/user:password@myinsteonhub.mydomain.com:25105,poll_time=1000 (insteon hub2 (2014))
111 * /hub/myinsteonhub.mydomain.com:9761
113 * /tcp/serialportserver.mydomain.com:port (serial port exposed via tcp, eg. ser2net)
116 * @return reference to IOStream
119 public static IOStream create(@Nullable SerialPortManager serialPortManager, String config) {
120 if (config.startsWith("/hub2/")) {
121 return makeHub2014Stream(config);
122 } else if (config.startsWith("/hub/") || config.startsWith("/tcp/")) {
123 return makeTCPStream(config);
125 return new SerialIOStream(serialPortManager, config);
129 private static HubIOStream makeHub2014Stream(String config) {
134 int pollTime = 1000; // poll time in milliseconds
136 // Get rid of the /hub2/ part and split off options at the end
137 String[] parts = config.substring(6).split(",");
139 // Parse the first part, the address
140 String[] adr = parts[0].split("@");
142 if (adr.length > 1) {
143 String[] userPass = adr[0].split(":");
146 hostPort = adr[1].split(":");
148 hostPort = parts[0].split(":");
150 HostPort hp = new HostPort(hostPort, 25105);
151 // check if additional options are given
152 if (parts.length > 1) {
153 if (parts[1].trim().startsWith("poll_time")) {
154 pollTime = Integer.parseInt(parts[1].split("=")[1].trim());
157 return new HubIOStream(hp.host, hp.port, pollTime, user, pass);
160 private static TcpIOStream makeTCPStream(String config) {
161 // Get rid of the /hub/ part and split off options at the end, if any
162 String[] parts = config.substring(5).split(",");
163 String[] hostPort = parts[0].split(":");
164 HostPort hp = new HostPort(hostPort, 9761);
165 return new TcpIOStream(hp.host, hp.port);
168 private static class HostPort {
169 public String host = "localhost";
170 public int port = -1;
172 HostPort(String[] hostPort, int defaultPort) {
176 if (hostPort.length > 1) {
177 port = Integer.parseInt(hostPort[1]);
179 } catch (NumberFormatException e) {
180 logger.warn("bad format for port {} ", hostPort[1], e);