diff --git a/bundles/binding/org.openhab.binding.fatekplc/.classpath b/bundles/binding/org.openhab.binding.fatekplc/.classpath index 72932f1c79d..b446a74d746 100644 --- a/bundles/binding/org.openhab.binding.fatekplc/.classpath +++ b/bundles/binding/org.openhab.binding.fatekplc/.classpath @@ -4,6 +4,5 @@ - diff --git a/bundles/binding/org.openhab.binding.fatekplc/META-INF/MANIFEST.MF b/bundles/binding/org.openhab.binding.fatekplc/META-INF/MANIFEST.MF index b94f066306e..58a95c5fb70 100644 --- a/bundles/binding/org.openhab.binding.fatekplc/META-INF/MANIFEST.MF +++ b/bundles/binding/org.openhab.binding.fatekplc/META-INF/MANIFEST.MF @@ -9,7 +9,11 @@ Bundle-Version: 1.14.0.qualifier Bundle-ManifestVersion: 2 Bundle-Description: This is the Fatek PLC binding of the open Home Automation Bus (openHAB) -Import-Package: org.apache.commons.lang, +Import-Package: gnu.io, + org.simplify4u.jfatek, + org.simplify4u.jfatek.io, + org.simplify4u.jfatek.registers, + org.apache.commons.lang, org.openhab.core.binding, org.openhab.core.events, org.openhab.core.items, @@ -25,8 +29,7 @@ Import-Package: org.apache.commons.lang, org.slf4j Export-Package: org.openhab.binding.fatekplc Bundle-DocURL: http://www.openhab.org -Bundle-RequiredExecutionEnvironment: JavaSE-1.7 +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Service-Component: OSGI-INF/binding.xml, OSGI-INF/genericbindingprovider.xml Bundle-Activator: org.openhab.binding.fatekplc.internal.FatekPLCActivator -Bundle-ClassPath: ., - lib/jfatek-2.0.0.jar +Bundle-ClassPath: . diff --git a/bundles/binding/org.openhab.binding.fatekplc/README.md b/bundles/binding/org.openhab.binding.fatekplc/README.md index 6e51b9bb442..c4bdd2bc64e 100644 --- a/bundles/binding/org.openhab.binding.fatekplc/README.md +++ b/bundles/binding/org.openhab.binding.fatekplc/README.md @@ -9,7 +9,42 @@ The binding can be configured in the file `services/fatekplc.cfg`. | Property | Default | Required | Description | |----------|---------|:--------:|-------------| | refresh | 60000 | No | refresh interval in milliseconds which is used to poll values from the Fatek PLC server | -| ``.connectionUri | | Yes | connection URI for the `` you provide, so multiple Fatek PLCs can be addressed. Supports either `tcp://` or `udp://` protocol. For example, `udp://192.168.1.100?plcId=1` | +| ``.connectionUri | | Yes | connection URI for the `` you provide, so multiple Fatek PLCs can be addressed. Supports either `tcp://`, `udp://` or `serial://` protocol. | + +The common `connectionUri` syntax is: +``` +protocol://address:[port]?plcId=param1=value1¶mN=ValueN +``` +| Name | Description | Default | +|---------|-----------------------------------------|-------| +| plcId | PLC id, must be set | - | +| timeout | connection/read timeout in milliseconds | 5000 | + +### `tcp` or `udp` parameters + +There are not more parameters for this connection protocols. + +Example, `udp://192.168.1.100?plcId=1&timeout=1000` +Default `port` is `500` + +### serial parameters + +| Name | Description | Default | +|---------|-------------|---------| +| baudRate | serial connection speed bit/s | 9600 | +| dataBits | number of data bits in each character | 7 | +| stopBits | number of bits sent at the end of each character, can be `1`, `2` or `1.5` | 1 | +| parity | control bit set, can be: `NONE`, `ODD`, `EVEN`, `MARK` or `SPACE` | EVEN | + +Serial port name is given as address of connectionUri. +You can write begin name of port, first matched will be used. + +Examples: + +`serial:///dev/tty-usbserial?plcId=1&baudRate=19200` + +`serial://COM1?plcId=1&baudRate=19200&timeout=1000` + ## Item Configuration diff --git a/bundles/binding/org.openhab.binding.fatekplc/build.properties b/bundles/binding/org.openhab.binding.fatekplc/build.properties index 605fecd09b7..cddd6d05b0f 100644 --- a/bundles/binding/org.openhab.binding.fatekplc/build.properties +++ b/bundles/binding/org.openhab.binding.fatekplc/build.properties @@ -3,6 +3,5 @@ source.. = src/main/java/,\ bin.includes = META-INF/,\ .,\ OSGI-INF/,\ - NOTICE,\ - lib/jfatek-2.0.0.jar + NOTICE output.. = target/classes/ diff --git a/bundles/binding/org.openhab.binding.fatekplc/lib/jfatek-2.0.0-sources.jar b/bundles/binding/org.openhab.binding.fatekplc/lib/jfatek-2.0.0-sources.jar deleted file mode 100644 index 01ce3bdb18b..00000000000 Binary files a/bundles/binding/org.openhab.binding.fatekplc/lib/jfatek-2.0.0-sources.jar and /dev/null differ diff --git a/bundles/binding/org.openhab.binding.fatekplc/lib/jfatek-2.0.0.jar b/bundles/binding/org.openhab.binding.fatekplc/lib/jfatek-2.0.0.jar deleted file mode 100644 index 56673fc1158..00000000000 Binary files a/bundles/binding/org.openhab.binding.fatekplc/lib/jfatek-2.0.0.jar and /dev/null differ diff --git a/bundles/binding/org.openhab.binding.fatekplc/pom.xml b/bundles/binding/org.openhab.binding.fatekplc/pom.xml index 5b8b860bbab..be20d697151 100644 --- a/bundles/binding/org.openhab.binding.fatekplc/pom.xml +++ b/bundles/binding/org.openhab.binding.fatekplc/pom.xml @@ -14,9 +14,12 @@ openHAB Fatek PLC Binding - - 1.7 - 1.7 - + + + org.simplify4u + jfatek + 3.0.0 + + diff --git a/bundles/binding/org.openhab.binding.fatekplc/src/main/java/org/openhab/binding/fatekplc/internal/FatekPLCSlave.java b/bundles/binding/org.openhab.binding.fatekplc/src/main/java/org/openhab/binding/fatekplc/internal/FatekPLCSlave.java index 25ba81e3db1..15d4ab7e763 100644 --- a/bundles/binding/org.openhab.binding.fatekplc/src/main/java/org/openhab/binding/fatekplc/internal/FatekPLCSlave.java +++ b/bundles/binding/org.openhab.binding.fatekplc/src/main/java/org/openhab/binding/fatekplc/internal/FatekPLCSlave.java @@ -19,6 +19,7 @@ import org.openhab.binding.fatekplc.items.CommandException; import org.openhab.binding.fatekplc.items.FatekPLCItem; +import org.openhab.binding.fatekplc.serial.SerialFatekConnectionFactory; import org.openhab.core.events.EventPublisher; import org.openhab.core.types.Command; import org.openhab.core.types.State; @@ -53,6 +54,10 @@ public class FatekPLCSlave { private FatekPLC fatekPLC = null; + static { + FatekPLC.registerConnectionFactory(new SerialFatekConnectionFactory()); + } + public FatekPLCSlave(String name, EventPublisher eventPublisher) { this.name = name; this.eventPublisher = eventPublisher; @@ -73,28 +78,28 @@ public void disconnect() throws FatekIOException { /** * Configure slave property * - * @param name property name + * @param configName property configName * @param value config value * @throws ConfigurationException if something wrong with configuration, eg. Unknown property */ - public void configure(String name, Object value) throws ConfigurationException { + public void configure(String configName, Object value) throws ConfigurationException { - logger.debug("Configure item: {} to {}", name, value); + logger.debug("Configure item: {} to {}", configName, value); - if ("connectionUri".equals(name)) { + if ("connectionUri".equals(configName)) { try { disconnect(); fatekPLC = new FatekPLC((String) value); - logger.info("New Fatek PLC connectionUri={}", value); + logger.info("New Fatek PLC name={}, connectionUri={}", name, value); } catch (Exception e) { fatekPLC = null; - throw new ConfigurationException(name, e.getMessage()); + throw new ConfigurationException(configName, e.getMessage(), e); } } else { - throw new ConfigurationException(name, "Unknown property"); + throw new ConfigurationException(configName, "Unknown property"); } - logger.debug("Configure item: {} end", name); + logger.debug("Configure item: {} end", configName); } /** diff --git a/bundles/binding/org.openhab.binding.fatekplc/src/main/java/org/openhab/binding/fatekplc/serial/SerialFatekConnectionFactory.java b/bundles/binding/org.openhab.binding.fatekplc/src/main/java/org/openhab/binding/fatekplc/serial/SerialFatekConnectionFactory.java index 56659afec5a..0f91c52b318 100644 --- a/bundles/binding/org.openhab.binding.fatekplc/src/main/java/org/openhab/binding/fatekplc/serial/SerialFatekConnectionFactory.java +++ b/bundles/binding/org.openhab.binding.fatekplc/src/main/java/org/openhab/binding/fatekplc/serial/SerialFatekConnectionFactory.java @@ -12,58 +12,150 @@ */ package org.openhab.binding.fatekplc.serial; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - +import gnu.io.CommPortIdentifier; +import gnu.io.NoSuchPortException; +import gnu.io.PortInUseException; +import gnu.io.SerialPort; +import gnu.io.UnsupportedCommOperationException; import org.simplify4u.jfatek.io.FatekConfig; import org.simplify4u.jfatek.io.FatekConnection; import org.simplify4u.jfatek.io.FatekConnectionFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.Optional; /** * Serial connection for Fatek PLC binding. * - * TODO - to implemented. - * * @author Slawomir Jaranowski * @since 1.9.0 - * */ public class SerialFatekConnectionFactory implements FatekConnectionFactory { - class Connection extends FatekConnection { + private static final Logger logger = LoggerFactory.getLogger(SerialFatekConnectionFactory.class); + + private static final String SCHEMA_NAME = "serial"; + + class Connection extends FatekConnection { + + private SerialPort serialPort; + + Connection(FatekConfig fatekConfig) throws IOException, PortInUseException, UnsupportedCommOperationException { + super(fatekConfig); + + final CommPortIdentifier commPortIdentifier = findComPort(); + + serialPort = commPortIdentifier.open("openHAB-FatekPLC", 2000); + serialPort.setSerialPortParams(getBaud(), getDataBits(), getStopBits(), getParity()); + serialPort.enableReceiveTimeout(getTimeout()); + + logger.info("New connection to: {} opened", serialPort.getName()); + } + + private int getBaud() { + return getParamAsInt("baudRate").orElse(9600); + } + + private int getDataBits() { + return getParamAsInt("dataBits").orElse(SerialPort.DATABITS_7); + } + + private int getStopBits() throws IOException { + final Optional stopBits = getParam("stopBits"); + switch (stopBits.orElse("1")) { + case "1": + return SerialPort.STOPBITS_1; + case "2": + return SerialPort.STOPBITS_2; + case "1.5": + return SerialPort.STOPBITS_1_5; + default: + throw new IOException("Unknown stopBits=" + stopBits); + } + } + + private int getParity() throws IOException { + final Optional parity = getParam("parity"); + switch (parity.map(String::toUpperCase).orElse("EVEN")) { + case "NONE": + return SerialPort.PARITY_NONE; + case "ODD": + return SerialPort.PARITY_ODD; + case "EVEN": + return SerialPort.PARITY_EVEN; + case "MARK": + return SerialPort.PARITY_MARK; + case "SPACE": + return SerialPort.PARITY_SPACE; + default: + throw new IOException("Unknown parity=" + parity); + } + } + + @Override + protected InputStream getInputStream() throws IOException { + return serialPort.getInputStream(); + } + + @Override + protected OutputStream getOutputStream() throws IOException { + return serialPort.getOutputStream(); + } - protected Connection(FatekConfig fatekConfig) { - super(fatekConfig); + @Override + protected void closeConnection() throws IOException { + serialPort.close(); + logger.info("Connection to: {} closed", serialPort.getName()); + serialPort = null; + } - // TODO - init and open serial port here - } + @Override + public boolean isConnected() { + return serialPort != null; + } - @Override - protected InputStream getInputStream() throws IOException { - throw new IOException("Not implemented"); - } + private CommPortIdentifier findComPort() throws IOException { - @Override - protected OutputStream getOutputStream() throws IOException { - throw new IOException("Not implemented"); - } + // list all available serial ports + final List availableNames = new ArrayList<>(); + final Enumeration portIdentifiers = CommPortIdentifier.getPortIdentifiers(); + while (portIdentifiers.hasMoreElements()) { + final CommPortIdentifier id = (CommPortIdentifier) portIdentifiers.nextElement(); + if (id.getPortType() == CommPortIdentifier.PORT_SERIAL) { + availableNames.add(id.getName()); + } + } - @Override - protected void closeConnection() throws IOException { - throw new IOException("Not implemented"); - } + final String portNameCandidate = getFullName(); + // find first matching port name, on some system usb serial port can have suffix depends on which usb port we use + final Optional portName = availableNames.stream().filter(name -> name.startsWith(portNameCandidate)).findFirst(); - @Override - public boolean isConnected() { - return false; - } - } + try { + return CommPortIdentifier.getPortIdentifier(portName.orElseThrow(NoSuchPortException::new)); + } catch (NoSuchPortException e) { + throw new IOException("Serial port '" + portNameCandidate + "' could not be found. Available ports are:\n" + availableNames); + } + } + } - @Override - public FatekConnection getConnection(FatekConfig fatekConfig) - throws IOException { - return new Connection(fatekConfig); - } + @Override + public FatekConnection getConnection(FatekConfig fatekConfig) throws IOException { + try { + return new Connection(fatekConfig); + } catch (PortInUseException | UnsupportedCommOperationException e) { + throw new IOException(e); + } + } + @Override + public String getSchema() { + return SCHEMA_NAME; + } } diff --git a/bundles/binding/org.openhab.binding.fatekplc/src/main/resources/jfatek/SERIALFatekConnectionFactory b/bundles/binding/org.openhab.binding.fatekplc/src/main/resources/jfatek/SERIALFatekConnectionFactory deleted file mode 100644 index 775b652329a..00000000000 --- a/bundles/binding/org.openhab.binding.fatekplc/src/main/resources/jfatek/SERIALFatekConnectionFactory +++ /dev/null @@ -1 +0,0 @@ -org.openhab.binding.fatekplc.serial.SerialFatekConnectionFactory diff --git a/features/openhab-addons-external/src/main/resources/conf/fatekplc.cfg b/features/openhab-addons-external/src/main/resources/conf/fatekplc.cfg index 0c4b42e301e..9e9da4128a7 100644 --- a/features/openhab-addons-external/src/main/resources/conf/fatekplc.cfg +++ b/features/openhab-addons-external/src/main/resources/conf/fatekplc.cfg @@ -4,5 +4,5 @@ # (optional, defaults to 60000ms / 60 seconds) # fatekplc:refresh=60000 # -# fatek connection uri, support tcp and udp +# fatek connection uri, support tcp, udp and serial # fatekplc:plc1.connectionUri=udp://192.168.1.100?plcId=1 diff --git a/features/openhab-addons/src/main/feature/feature.xml b/features/openhab-addons/src/main/feature/feature.xml index e95a204fd1e..598bd404f8a 100644 --- a/features/openhab-addons/src/main/feature/feature.xml +++ b/features/openhab-addons/src/main/feature/feature.xml @@ -202,6 +202,8 @@ openhab-runtime-base openhab-runtime-compat1x + openhab-transport-serial + mvn:org.simplify4u/jfatek/3.0.0 mvn:org.openhab.binding/org.openhab.binding.fatekplc/${project.version} mvn:${project.groupId}/openhab-addons-external/${project.version}/cfg/fatekplc