[oceanic] Remove dependency on RXTX for serial communication (#15044)

Signed-off-by: Karel Goderis <karel.goderis@me.com>
This commit is contained in:
Karel Goderis 2023-06-02 21:57:32 +02:00 committed by GitHub
parent 3c1cbaa769
commit 93b888ad31
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 69 additions and 79 deletions

View File

@ -14,8 +14,4 @@
<name>openHAB Add-ons :: Bundles :: Oceanic Binding</name>
<properties>
<bnd.importpackage>gnu.io;version="[3.12,6)"</bnd.importpackage>
</properties>
</project>

View File

@ -21,12 +21,15 @@ import java.util.stream.Stream;
import org.openhab.binding.oceanic.internal.handler.NetworkOceanicThingHandler;
import org.openhab.binding.oceanic.internal.handler.SerialOceanicThingHandler;
import org.openhab.core.io.transport.serial.SerialPortManager;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
/**
* The {@link OceanicHandlerFactory} is responsible for creating things and
@ -40,6 +43,13 @@ public class OceanicHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections
.unmodifiableSet(Stream.of(THING_TYPE_SERIAL, THING_TYPE_NETWORK).collect(Collectors.toSet()));
private final SerialPortManager serialPortManager;
@Activate
public OceanicHandlerFactory(final @Reference SerialPortManager serialPortManager) {
this.serialPortManager = serialPortManager;
}
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
@ -50,7 +60,7 @@ public class OceanicHandlerFactory extends BaseThingHandlerFactory {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (thingTypeUID.equals(THING_TYPE_SERIAL)) {
return new SerialOceanicThingHandler(thing);
return new SerialOceanicThingHandler(thing, serialPortManager);
}
if (thingTypeUID.equals(THING_TYPE_NETWORK)) {
return new NetworkOceanicThingHandler(thing);

View File

@ -63,10 +63,12 @@ public class NetworkOceanicThingHandler extends OceanicThingHandler {
try {
socket = new Socket(config.ipAddress, config.portNumber);
socket.setSoTimeout(REQUEST_TIMEOUT);
outputStream = socket.getOutputStream();
inputStream = socket.getInputStream();
updateStatus(ThingStatus.ONLINE);
if (socket != null) {
socket.setSoTimeout(REQUEST_TIMEOUT);
outputStream = socket.getOutputStream();
inputStream = socket.getInputStream();
updateStatus(ThingStatus.ONLINE);
}
} catch (UnknownHostException e) {
logger.error("An exception occurred while resolving host {}:{} : '{}'", config.ipAddress, config.portNumber,
e.getMessage());

View File

@ -17,45 +17,47 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.TooManyListenersException;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.openhab.binding.oceanic.internal.SerialOceanicBindingConfiguration;
import org.openhab.binding.oceanic.internal.Throttler;
import org.openhab.core.io.transport.serial.PortInUseException;
import org.openhab.core.io.transport.serial.SerialPort;
import org.openhab.core.io.transport.serial.SerialPortEvent;
import org.openhab.core.io.transport.serial.SerialPortEventListener;
import org.openhab.core.io.transport.serial.SerialPortIdentifier;
import org.openhab.core.io.transport.serial.SerialPortManager;
import org.openhab.core.io.transport.serial.UnsupportedCommOperationException;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import gnu.io.CommPortIdentifier;
import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.RXTXCommDriver;
import gnu.io.SerialPort;
import gnu.io.UnsupportedCommOperationException;
/**
* The {@link SerialOceanicThingHandler} implements {@link OceanicThingHandler} for an Oceanic water softener that is
* directly connected to a serial port of the openHAB host
*
* @author Karel Goderis - Initial contribution
*/
public class SerialOceanicThingHandler extends OceanicThingHandler {
public class SerialOceanicThingHandler extends OceanicThingHandler implements SerialPortEventListener {
private static final long REQUEST_TIMEOUT = 10000;
private static final int BAUD = 19200;
private final Logger logger = LoggerFactory.getLogger(SerialOceanicThingHandler.class);
private final SerialPortManager serialPortManager;
private SerialPort serialPort;
private CommPortIdentifier portId;
private InputStream inputStream;
private OutputStream outputStream;
private SerialPortReader readerThread;
public SerialOceanicThingHandler(Thing thing) {
public SerialOceanicThingHandler(Thing thing, SerialPortManager serialPortManager) {
super(thing);
this.serialPortManager = serialPortManager;
}
@Override
@ -65,73 +67,46 @@ public class SerialOceanicThingHandler extends OceanicThingHandler {
SerialOceanicBindingConfiguration config = getConfigAs(SerialOceanicBindingConfiguration.class);
if (serialPort == null && config.port != null) {
if (portId == null) {
try {
RXTXCommDriver rxtxCommDriver = new RXTXCommDriver();
rxtxCommDriver.initialize();
CommPortIdentifier.addPortName(config.port, CommPortIdentifier.PORT_RAW, rxtxCommDriver);
portId = CommPortIdentifier.getPortIdentifier(config.port);
} catch (NoSuchPortException e) {
logger.error("An exception occurred while setting up serial port '{}' : '{}'", config.port,
e.getMessage(), e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Could not setup serial port " + serialPort + ": " + e.getMessage());
return;
}
SerialPortIdentifier portIdentifier = serialPortManager.getIdentifier(config.port);
if (portIdentifier == null) {
String availablePorts = serialPortManager.getIdentifiers().map(id -> id.getName())
.collect(Collectors.joining(System.lineSeparator()));
String description = String.format("Serial port '%s' could not be found. Available ports are:%n%s",
config.port, availablePorts);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, description);
return;
}
if (portId != null) {
try {
serialPort = portId.open(this.getThing().getUID().getBindingId(), 2000);
} catch (PortInUseException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Could not open serial port " + serialPort + ": " + e.getMessage());
return;
}
try {
logger.info("Connecting to the Oceanic water softener using {}.", config.port);
serialPort = portIdentifier.open(this.getThing().getUID().getBindingId(), 2000);
try {
inputStream = serialPort.getInputStream();
} catch (IOException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Could not open serial port " + serialPort + ": " + e.getMessage());
return;
}
serialPort.setSerialPortParams(BAUD, SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
serialPort.enableReceiveThreshold(1);
serialPort.disableReceiveTimeout();
inputStream = serialPort.getInputStream();
outputStream = serialPort.getOutputStream();
serialPort.addEventListener(this);
serialPort.notifyOnDataAvailable(true);
try {
serialPort.setSerialPortParams(BAUD, SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
} catch (UnsupportedCommOperationException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Could not configure serial port " + serialPort + ": " + e.getMessage());
return;
}
try {
outputStream = serialPort.getOutputStream();
updateStatus(ThingStatus.ONLINE);
} catch (IOException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Could not communicate with the serial port " + serialPort + ": " + e.getMessage());
return;
}
readerThread = new SerialPortReader(inputStream);
readerThread.start();
} else {
StringBuilder sb = new StringBuilder();
@SuppressWarnings("rawtypes")
Enumeration portList = CommPortIdentifier.getPortIdentifiers();
while (portList.hasMoreElements()) {
CommPortIdentifier id = (CommPortIdentifier) portList.nextElement();
if (id.getPortType() == CommPortIdentifier.PORT_SERIAL) {
sb.append(id.getName() + "\n");
}
}
logger.error("Serial port '{}' could not be found. Available ports are:\n {}", config.port, sb);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
updateStatus(ThingStatus.ONLINE);
} catch (PortInUseException portInUseException) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Port in use: " + config.port);
} catch (UnsupportedCommOperationException | IOException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Communication error");
} catch (TooManyListenersException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Too many listeners to serial port.");
}
}
}
@ -217,6 +192,13 @@ public class SerialOceanicThingHandler extends OceanicThingHandler {
}
}
@Override
public void serialEvent(SerialPortEvent serialPortEvent) {
if (logger.isTraceEnabled()) {
logger.trace("Received a serial port event : {}", serialPortEvent.getEventType());
}
}
public class SerialPortReader extends Thread {
private boolean interrupted = false;