From 3b6f4307f255d367e6d9c70429fc3ed0c8638905 Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Thu, 14 May 2020 18:44:49 +0200 Subject: [PATCH] [urtsi] Use serial transport (#7640) Related to #7573 Signed-off-by: Wouter Born Signed-off-by: Daan Meijer --- bundles/org.openhab.binding.urtsi/pom.xml | 4 - .../urtsi/internal/UrtsiHandlerFactory.java | 17 +++- .../internal/handler/UrtsiDeviceHandler.java | 89 +++++++------------ 3 files changed, 46 insertions(+), 64 deletions(-) diff --git a/bundles/org.openhab.binding.urtsi/pom.xml b/bundles/org.openhab.binding.urtsi/pom.xml index 2343bcd5f1816..fef64c0153387 100644 --- a/bundles/org.openhab.binding.urtsi/pom.xml +++ b/bundles/org.openhab.binding.urtsi/pom.xml @@ -14,8 +14,4 @@ openHAB Add-ons :: Bundles :: Somfy URTSI II binding - - gnu.io;version="[3.12,6)" - - diff --git a/bundles/org.openhab.binding.urtsi/src/main/java/org/openhab/binding/urtsi/internal/UrtsiHandlerFactory.java b/bundles/org.openhab.binding.urtsi/src/main/java/org/openhab/binding/urtsi/internal/UrtsiHandlerFactory.java index a95399a2c087c..81148ce3dbb26 100644 --- a/bundles/org.openhab.binding.urtsi/src/main/java/org/openhab/binding/urtsi/internal/UrtsiHandlerFactory.java +++ b/bundles/org.openhab.binding.urtsi/src/main/java/org/openhab/binding/urtsi/internal/UrtsiHandlerFactory.java @@ -17,15 +17,20 @@ import java.util.Arrays; import java.util.List; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.smarthome.core.thing.Bridge; import org.eclipse.smarthome.core.thing.Thing; import org.eclipse.smarthome.core.thing.ThingTypeUID; import org.eclipse.smarthome.core.thing.binding.BaseThingHandlerFactory; import org.eclipse.smarthome.core.thing.binding.ThingHandler; import org.eclipse.smarthome.core.thing.binding.ThingHandlerFactory; +import org.eclipse.smarthome.io.transport.serial.SerialPortManager; import org.openhab.binding.urtsi.internal.handler.RtsDeviceHandler; import org.openhab.binding.urtsi.internal.handler.UrtsiDeviceHandler; +import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; /** * The {@link UrtsiHandlerFactory} is responsible for creating things and thing @@ -33,23 +38,31 @@ * * @author Oliver Libutzki - Initial contribution */ +@NonNullByDefault @Component(service = ThingHandlerFactory.class, configurationPid = "binding.urtsi") public class UrtsiHandlerFactory extends BaseThingHandlerFactory { private static final List SUPPORTED_THING_TYPES_UIDS = Arrays.asList(URTSI_DEVICE_THING_TYPE, RTS_DEVICE_THING_TYPE); + private final SerialPortManager serialPortManager; + + @Activate + public UrtsiHandlerFactory(final @Reference SerialPortManager serialPortManager) { + this.serialPortManager = serialPortManager; + } + @Override public boolean supportsThingType(ThingTypeUID thingTypeUID) { return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID); } @Override - protected ThingHandler createHandler(Thing thing) { + protected @Nullable ThingHandler createHandler(Thing thing) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); if (thingTypeUID.equals(URTSI_DEVICE_THING_TYPE) && thing instanceof Bridge) { - return new UrtsiDeviceHandler((Bridge) thing); + return new UrtsiDeviceHandler((Bridge) thing, serialPortManager); } else if (thingTypeUID.equals(RTS_DEVICE_THING_TYPE)) { return new RtsDeviceHandler(thing); } diff --git a/bundles/org.openhab.binding.urtsi/src/main/java/org/openhab/binding/urtsi/internal/handler/UrtsiDeviceHandler.java b/bundles/org.openhab.binding.urtsi/src/main/java/org/openhab/binding/urtsi/internal/handler/UrtsiDeviceHandler.java index 3c2b3f339fd9e..1cecc019a4219 100644 --- a/bundles/org.openhab.binding.urtsi/src/main/java/org/openhab/binding/urtsi/internal/handler/UrtsiDeviceHandler.java +++ b/bundles/org.openhab.binding.urtsi/src/main/java/org/openhab/binding/urtsi/internal/handler/UrtsiDeviceHandler.java @@ -16,12 +16,9 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashSet; import java.util.List; -import java.util.Set; +import java.util.TooManyListenersException; import java.util.stream.Collectors; -import java.util.stream.Stream; import org.apache.commons.io.IOUtils; import org.eclipse.smarthome.core.thing.Bridge; @@ -31,18 +28,19 @@ import org.eclipse.smarthome.core.thing.ThingStatusDetail; import org.eclipse.smarthome.core.thing.binding.BaseBridgeHandler; import org.eclipse.smarthome.core.types.Command; +import org.eclipse.smarthome.io.transport.serial.PortInUseException; +import org.eclipse.smarthome.io.transport.serial.SerialPort; +import org.eclipse.smarthome.io.transport.serial.SerialPortEvent; +import org.eclipse.smarthome.io.transport.serial.SerialPortEventListener; +import org.eclipse.smarthome.io.transport.serial.SerialPortIdentifier; +import org.eclipse.smarthome.io.transport.serial.SerialPortManager; +import org.eclipse.smarthome.io.transport.serial.UnsupportedCommOperationException; import org.openhab.binding.urtsi.internal.config.RtsDeviceConfig; import org.openhab.binding.urtsi.internal.config.UrtsiDeviceConfig; import org.openhab.binding.urtsi.internal.mapping.UrtsiChannelMapping; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import gnu.io.CommPortIdentifier; -import gnu.io.NoSuchPortException; -import gnu.io.SerialPort; -import gnu.io.SerialPortEvent; -import gnu.io.SerialPortEventListener; - /** * The {@link UrtsiDeviceHandler} is responsible for handling commands, which are * sent to one of the channels. @@ -53,8 +51,6 @@ public class UrtsiDeviceHandler extends BaseBridgeHandler { private final Logger logger = LoggerFactory.getLogger(UrtsiDeviceHandler.class); - private static final String GNU_IO_RXTX_SERIAL_PORTS = "gnu.io.rxtx.SerialPorts"; - private static final int BAUD = 9600; private static final int DATABITS = SerialPort.DATABITS_8; private static final int STOPBIT = SerialPort.STOPBITS_1; @@ -65,13 +61,15 @@ public class UrtsiDeviceHandler extends BaseBridgeHandler { private long lastCommandTime; - private CommPortIdentifier portId; + private SerialPortIdentifier portId; private SerialPort serialPort; + private final SerialPortManager serialPortManager; private OutputStream outputStream; private InputStream inputStream; - public UrtsiDeviceHandler(Bridge bridge) { + public UrtsiDeviceHandler(Bridge bridge, SerialPortManager serialPortManager) { super(bridge); + this.serialPortManager = serialPortManager; } @Override @@ -162,7 +160,7 @@ public void serialEvent(SerialPortEvent event) { Thread.sleep(100); } return !listenerResult.isEmpty(); - } catch (Exception e) { + } catch (IOException | TooManyListenersException | InterruptedException e) { logger.error("Error writing '{}' to serial port {}: {}", msg, portId.getName(), e.getMessage()); } finally { serialPort.removeEventListener(); @@ -170,62 +168,37 @@ public void serialEvent(SerialPortEvent event) { return false; } - /** - * Registers the given port as system property {@value #GNU_IO_RXTX_SERIAL_PORTS}. The method is capable of - * extending the system property, if any other ports are already registered. - * - * @param port the port to be registered - */ - private void initSerialPort(String port) { - String serialPortsProperty = System.getProperty(GNU_IO_RXTX_SERIAL_PORTS); - Set serialPorts = null; - - if (serialPortsProperty != null) { - serialPorts = Stream.of(serialPortsProperty.split(":")).collect(Collectors.toSet()); - } else { - serialPorts = new HashSet<>(); - } - if (serialPorts.add(port)) { - logger.debug("Added {} to the {} system property.", port, GNU_IO_RXTX_SERIAL_PORTS); - System.setProperty(GNU_IO_RXTX_SERIAL_PORTS, serialPorts.stream().collect(Collectors.joining(":"))); - } - } - @Override public void initialize() { address = getThing().getProperties().get("address"); UrtsiDeviceConfig urtsiDeviceConfig = getConfigAs(UrtsiDeviceConfig.class); commandInterval = urtsiDeviceConfig.commandInterval; String port = urtsiDeviceConfig.port; - initSerialPort(port); + + portId = serialPortManager.getIdentifier(port); + + if (portId == 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", port, + availablePorts); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, description); + return; + } + try { - portId = CommPortIdentifier.getPortIdentifier(port); - // initialize serial port serialPort = portId.open("openHAB", 2000); - // set port parameters serialPort.setSerialPortParams(BAUD, DATABITS, STOPBIT, PARITY); inputStream = serialPort.getInputStream(); outputStream = serialPort.getOutputStream(); updateStatus(ThingStatus.ONLINE); - } catch (NoSuchPortException e) { - // enumerate the port identifiers in the exception to be helpful - final StringBuilder sb = new StringBuilder(); - @SuppressWarnings("unchecked") - Enumeration portList = CommPortIdentifier.getPortIdentifiers(); - while (portList.hasMoreElements()) { - final CommPortIdentifier id = portList.nextElement(); - if (id.getPortType() == CommPortIdentifier.PORT_SERIAL) { - sb.append(id.getName() + "\n"); - } - } - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, - "Serial port '" + port + "' could not be found. Available ports are:\n" + sb.toString()); - } catch (Exception e) { - if (logger.isErrorEnabled()) { - logger.error("An error occurred while initializing the Urtsi II connection.", e); - } + } catch (IOException e) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Error: " + e.getMessage()); + } catch (PortInUseException e) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Port already used: " + port); + } catch (UnsupportedCommOperationException e) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, - "An error occurred while initializing the Urtsi II connection: " + e.getMessage()); + "Unsupported operation on port '" + port + "': " + e.getMessage()); } }