diff --git a/bundles/binding/org.openhab.binding.ucprelayboard/.classpath b/bundles/binding/org.openhab.binding.ucprelayboard/.classpath
new file mode 100644
index 00000000000..6566c1e3a03
--- /dev/null
+++ b/bundles/binding/org.openhab.binding.ucprelayboard/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/bundles/binding/org.openhab.binding.ucprelayboard/.project b/bundles/binding/org.openhab.binding.ucprelayboard/.project
new file mode 100644
index 00000000000..2439531489a
--- /dev/null
+++ b/bundles/binding/org.openhab.binding.ucprelayboard/.project
@@ -0,0 +1,33 @@
+
+
+ org.openhab.binding.ucprelayboard
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+ org.eclipse.pde.ds.core.builder
+
+
+
+
+
+ org.eclipse.pde.PluginNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/bundles/binding/org.openhab.binding.ucprelayboard/.settings/org.eclipse.pde.core.prefs b/bundles/binding/org.openhab.binding.ucprelayboard/.settings/org.eclipse.pde.core.prefs
new file mode 100644
index 00000000000..18f2d04958e
--- /dev/null
+++ b/bundles/binding/org.openhab.binding.ucprelayboard/.settings/org.eclipse.pde.core.prefs
@@ -0,0 +1,4 @@
+#Fri Oct 08 00:21:11 CEST 2010
+eclipse.preferences.version=1
+pluginProject.extensions=false
+resolve.requirebundle=false
diff --git a/bundles/binding/org.openhab.binding.ucprelayboard/META-INF/MANIFEST.MF b/bundles/binding/org.openhab.binding.ucprelayboard/META-INF/MANIFEST.MF
new file mode 100644
index 00000000000..b08eaafc798
--- /dev/null
+++ b/bundles/binding/org.openhab.binding.ucprelayboard/META-INF/MANIFEST.MF
@@ -0,0 +1,25 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: openHAB UCProjects.eu RelayBoard Binding
+Bundle-SymbolicName: org.openhab.binding.ucprelayboard
+Bundle-Version: 1.8.0.qualifier
+Bundle-Vendor: openHAB.org
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Import-Package: gnu.io,
+ javax.mail;version="1.4.0",
+ org.apache.commons.io,
+ org.apache.commons.lang,
+ org.openhab.core.binding,
+ org.openhab.core.events,
+ org.openhab.core.items,
+ org.openhab.core.library.items,
+ org.openhab.core.library.types,
+ org.openhab.core.types,
+ org.openhab.model.item.binding,
+ org.osgi.framework,
+ org.osgi.service.cm,
+ org.osgi.service.event,
+ org.slf4j
+Export-Package: org.openhab.binding.ucprelayboard
+Service-Component: OSGI-INF/binding.xml, OSGI-INF/genericbindingprovider.xml
+Bundle-ClassPath: .
diff --git a/bundles/binding/org.openhab.binding.ucprelayboard/OSGI-INF/binding.xml b/bundles/binding/org.openhab.binding.ucprelayboard/OSGI-INF/binding.xml
new file mode 100644
index 00000000000..aa06f7be510
--- /dev/null
+++ b/bundles/binding/org.openhab.binding.ucprelayboard/OSGI-INF/binding.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bundles/binding/org.openhab.binding.ucprelayboard/OSGI-INF/genericbindingprovider.xml b/bundles/binding/org.openhab.binding.ucprelayboard/OSGI-INF/genericbindingprovider.xml
new file mode 100644
index 00000000000..f1ca06e2621
--- /dev/null
+++ b/bundles/binding/org.openhab.binding.ucprelayboard/OSGI-INF/genericbindingprovider.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/bundles/binding/org.openhab.binding.ucprelayboard/build.properties b/bundles/binding/org.openhab.binding.ucprelayboard/build.properties
new file mode 100644
index 00000000000..1dac3558597
--- /dev/null
+++ b/bundles/binding/org.openhab.binding.ucprelayboard/build.properties
@@ -0,0 +1,5 @@
+output.. = target/classes/
+bin.includes = META-INF/,\
+ .,\
+ OSGI-INF/
+source.. = src/main/java/
diff --git a/bundles/binding/org.openhab.binding.ucprelayboard/pom.xml b/bundles/binding/org.openhab.binding.ucprelayboard/pom.xml
new file mode 100644
index 00000000000..8c47113cdde
--- /dev/null
+++ b/bundles/binding/org.openhab.binding.ucprelayboard/pom.xml
@@ -0,0 +1,37 @@
+
+
+
+
+ org.openhab.bundles
+ binding
+ 1.8.0-SNAPSHOT
+
+
+ openHAB UCProjects.eu RelayBoard Binding
+
+
+ org.openhab.binding.ucprelayboard
+ org.openhab.binding.ucprelayboard
+ openhab-addon-binding-ucprelayboard
+ ${project.name}
+ openhab-addon-io-serial
+
+
+ 4.0.0
+ org.openhab.binding
+ org.openhab.binding.ucprelayboard
+
+ eclipse-plugin
+
+
+
+
+ org.vafer
+ jdeb
+
+
+
+
+
diff --git a/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/UCPRelayBoardBindingProvider.java b/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/UCPRelayBoardBindingProvider.java
new file mode 100644
index 00000000000..5ef9109dd6b
--- /dev/null
+++ b/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/UCPRelayBoardBindingProvider.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2010-2015, openHAB.org and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.openhab.binding.ucprelayboard;
+
+/**
+ * @author Robert Michalak
+ * @since 1.8.0
+ */
+import org.openhab.binding.ucprelayboard.internal.UCPRelayConfig;
+import org.openhab.core.binding.BindingProvider;
+import org.openhab.core.items.Item;
+
+public interface UCPRelayBoardBindingProvider extends BindingProvider {
+
+ /**
+ * Returns the binding configuration for an item
+ * @param itemName
+ * @return
+ */
+ public UCPRelayConfig getRelayConfigForItem(String itemName);
+
+ public Item getItemForRelayConfig(UCPRelayConfig config);
+
+}
\ No newline at end of file
diff --git a/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/internal/DowCRC.java b/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/internal/DowCRC.java
new file mode 100644
index 00000000000..6aca864550a
--- /dev/null
+++ b/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/internal/DowCRC.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2010-2015, openHAB.org and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.openhab.binding.ucprelayboard.internal;
+/**
+ * Implementation of Dallas One Wire CRC formula based on http://www.maximintegrated.com/en/app-notes/index.mvp/id/27
+ *
+ * @author Robert Michalak
+ *
+ */
+public class DowCRC {
+ private static final char crc8[] = {
+ 0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65,
+ 157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220,
+ 35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98,
+ 190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255,
+ 70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7,
+ 219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154,
+ 101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36,
+ 248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185,
+ 140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205,
+ 17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80,
+ 175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238,
+ 50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115,
+ 202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139,
+ 87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22,
+ 233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168,
+ 116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53
+ };
+
+ public static byte compute(byte[] tab) {
+ int result = 0;
+ for (byte value : tab) {
+ result = crc8[ (int)value ^ result];
+ }
+ return (byte) result;
+ }
+}
diff --git a/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/internal/InitializationException.java b/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/internal/InitializationException.java
new file mode 100644
index 00000000000..d081cc4acc9
--- /dev/null
+++ b/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/internal/InitializationException.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2010-2015, openHAB.org and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.openhab.binding.ucprelayboard.internal;
+
+/**
+ * @author Robert Michalak
+ * @since 1.8.0
+ */
+public class InitializationException extends Exception {
+
+ private static final long serialVersionUID = -5106059856757667266L;
+
+ public InitializationException(String msg) {
+ super(msg);
+ }
+
+ public InitializationException(Throwable cause) {
+ super(cause);
+ }
+
+ public InitializationException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+}
diff --git a/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/internal/SerialDevice.java b/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/internal/SerialDevice.java
new file mode 100644
index 00000000000..ecd9f371606
--- /dev/null
+++ b/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/internal/SerialDevice.java
@@ -0,0 +1,129 @@
+/**
+ * Copyright (c) 2010-2015, openHAB.org and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.openhab.binding.ucprelayboard.internal;
+
+import gnu.io.CommPortIdentifier;
+import gnu.io.NoSuchPortException;
+import gnu.io.PortInUseException;
+import gnu.io.SerialPort;
+import gnu.io.UnsupportedCommOperationException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.commons.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class represents a serial device
+ *
+ * @author Robert Michalak
+ * @since 1.8.0
+ */
+
+public class SerialDevice {
+
+ private static final Logger logger = LoggerFactory
+ .getLogger(SerialDevice.class);
+
+ private SerialDeviceConfig config;
+
+ private CommPortIdentifier portId;
+ private SerialPort serialPort;
+
+ private InputStream inputStream;
+ private OutputStream outputStream;
+
+ public SerialDevice(SerialDeviceConfig config) {
+ this.config = config;
+ }
+
+ public SerialDeviceConfig getConfig() {
+ return config;
+ }
+
+ /**
+ * Initialize this device and open the serial port
+ *
+ * @throws InitializationException
+ * if port can not be opened
+ */
+ public void initialize() throws InitializationException {
+ try {
+ portId = CommPortIdentifier.getPortIdentifier(config.getPort());
+
+ if (portId != null) {
+ // initialize serial port
+ serialPort = (SerialPort) portId.open("openHAB", 2000);
+
+ // set port parameters
+ serialPort.setSerialPortParams(config.getBaud(),
+ SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
+ SerialPort.PARITY_NONE);
+
+ inputStream = serialPort.getInputStream();
+
+ outputStream = serialPort.getOutputStream();
+
+ } else {
+ throw new InitializationException("Serial port '"
+ + config.getPort() + "' could not be found.\n");
+ }
+ } catch (UnsupportedCommOperationException e) {
+ throw new InitializationException(e);
+ } catch (IOException e) {
+ throw new InitializationException(e);
+ } catch (PortInUseException e) {
+ throw new InitializationException(e);
+ } catch (NoSuchPortException e) {
+ throw new InitializationException(e);
+ }
+ }
+
+ /**
+ * Sends a string to the serial port of this device
+ *
+ * @param relayBoardCommand
+ * the string to send
+ */
+ public void writeBytes(byte[] relayBoardCommand) {
+ try {
+ // write bytes to serial port
+ outputStream.write(relayBoardCommand);
+ outputStream.flush();
+ } catch (IOException e) {
+ logger.error("Error writing to serial port {}: {}", new Object[] {
+ config.getPort(), e.getMessage() });
+ }
+ }
+
+ public byte[] readBytes(final byte[] buffer) {
+ try {
+ if (inputStream.available() > 0) {
+ inputStream.read(buffer);
+ }
+ } catch (IOException e) {
+ logger.error("Error reading from serial port {}: {}", new Object[] {
+ config.getPort(), e.getMessage() });
+ }
+ return buffer;
+ }
+
+ /**
+ * Close this serial device
+ */
+ public void close() {
+ IOUtils.closeQuietly(outputStream);
+ IOUtils.closeQuietly(inputStream);
+ serialPort.close();
+ }
+
+}
diff --git a/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/internal/SerialDeviceConfig.java b/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/internal/SerialDeviceConfig.java
new file mode 100644
index 00000000000..acaf9f3b8ff
--- /dev/null
+++ b/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/internal/SerialDeviceConfig.java
@@ -0,0 +1,86 @@
+/**
+ * Copyright (c) 2010-2015, openHAB.org and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.openhab.binding.ucprelayboard.internal;
+
+/**
+ * This class represents configuration for a serial device
+ *
+ * @author Robert Michalak
+ * @since 1.8.0
+ */
+public class SerialDeviceConfig {
+
+ private String name;
+ private String port;
+ private int baud = 57600; // default value
+
+ public String getPort() {
+ return port;
+ }
+
+ public void setPort(String port) {
+ this.port = port;
+ }
+
+ public int getBaud() {
+ return baud;
+ }
+
+ public void setBaud(int baud) {
+ this.baud = baud;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public boolean isValid() {
+ return (name != null && port != null);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + baud;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ result = prime * result + ((port == null) ? 0 : port.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ SerialDeviceConfig other = (SerialDeviceConfig) obj;
+ if (baud != other.baud)
+ return false;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ if (port == null) {
+ if (other.port != null)
+ return false;
+ } else if (!port.equals(other.port))
+ return false;
+ return true;
+ }
+
+
+}
diff --git a/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/internal/UCPRelayBoardBinding.java b/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/internal/UCPRelayBoardBinding.java
new file mode 100644
index 00000000000..58c5a744211
--- /dev/null
+++ b/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/internal/UCPRelayBoardBinding.java
@@ -0,0 +1,260 @@
+/**
+ * Copyright (c) 2010-2015, openHAB.org and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.openhab.binding.ucprelayboard.internal;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.lang.StringUtils;
+import org.openhab.binding.ucprelayboard.UCPRelayBoardBindingProvider;
+import org.openhab.core.binding.AbstractActiveBinding;
+import org.openhab.core.items.Item;
+import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.types.Command;
+import org.openhab.core.types.State;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Binding for relay boards available from http://www.ucprojects.eu/
+ *
+ * @author Robert Michalak
+ * @since 1.8.0
+ */
+public class UCPRelayBoardBinding extends
+ AbstractActiveBinding {
+
+ private Map serialDevices = new HashMap();
+
+ private long refreshInterval = 60000;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void internalReceiveCommand(String itemName, Command command) {
+
+ UCPRelayConfig config = getRelayConfigForItem(itemName);
+ if (config != null) {
+ SerialDevice serialDevice = serialDevices.get(config.getBoardName());
+ if (command instanceof OnOffType) {
+ byte[] relayBoardCommand = prepareRelayCommand(
+ config, ((OnOffType) command));
+ serialDevice.writeBytes(relayBoardCommand);
+ }
+ }
+ }
+
+ private UCPRelayConfig getRelayConfigForItem(String itemName) {
+ for (UCPRelayBoardBindingProvider provider : providers) {
+ if (provider.providesBindingFor(itemName)) {
+ return provider.getRelayConfigForItem(itemName);
+ }
+ }
+ return null;
+ }
+
+ private byte[] prepareRelayCommand(UCPRelayConfig config, OnOffType onOffType) {
+
+ switch (config.translateCommand(onOffType)) {
+ case OFF:
+ return UCPRelayBoardMessages.OFF[config.getRelayNumber()];
+ case ON:
+ return UCPRelayBoardMessages.ON[config.getRelayNumber()];
+ }
+ return null;
+ }
+
+ public void activate(final BundleContext bundleContext,
+ final Map properties) throws InitializationException {
+ if (properties == null) {
+ return;
+ }
+
+ Map configs = prepareConfiguration(properties);
+ for (SerialDeviceConfig config : configs.values()) {
+ prepareSerialDevice(config);
+ }
+ if (serialDevices.size() > 0) {
+ setProperlyConfigured(true);
+ }
+ }
+
+ public void modified(final Map properties) throws InitializationException {
+ if (properties == null) {
+ return;
+ }
+ Map configs = prepareConfiguration(properties);
+ //create new and modify existing ones
+ for (Map.Entry config : configs.entrySet()) {
+ if (serialDevices.containsKey(config.getKey())) {
+ SerialDevice device = serialDevices.get(config.getKey());
+ if (!config.equals(device.getConfig())) {
+ device.close();
+ prepareSerialDevice(config.getValue());
+ }
+ } else {
+ prepareSerialDevice(config.getValue());
+ }
+ }
+ //close removed ones
+ for (String name : serialDevices.keySet()) {
+ if (!configs.containsKey(name)) {
+ SerialDevice device = serialDevices.get(name);
+ device.close();
+ serialDevices.remove(name);
+ }
+ }
+ if (serialDevices.size() > 0) {
+ setProperlyConfigured(true);
+ } else {
+ setProperlyConfigured(false);
+ }
+
+ }
+
+ private void prepareSerialDevice(SerialDeviceConfig config)
+ throws InitializationException {
+ SerialDevice serialDevice = new SerialDevice(config);
+ serialDevice.initialize();
+ serialDevices.put(config.getName(), serialDevice);
+ }
+
+ private Map prepareConfiguration(
+ final Map properties) {
+ Map configs = new HashMap();
+
+ for (String key : properties.keySet()) {
+
+ Object property = properties.get(key);
+ if (!(property instanceof String)) {
+ continue;
+ }
+
+ String value = StringUtils.trimToNull((String) property);
+
+ if ("refresh".equals(key)) {
+ try {
+ refreshInterval = Long.parseLong(value);
+ } catch (NumberFormatException ignored) {
+ }
+ continue;
+ }
+
+ String[] split = StringUtils.split(key, ".");
+ if (split.length != 3 || value == null || !"board".equals(split[0])) {
+ continue;
+ }
+
+ SerialDeviceConfig config = configs.get(split[1]);
+ if (config == null) {
+ config = new SerialDeviceConfig();
+ config.setName(split[1]);
+ configs.put(split[1], config);
+ }
+
+ if ("port".equals(split[2])) {
+ config.setPort(value);
+ } else if ("baud".equals(split[2])) {
+ config.setBaud(Integer.valueOf(value));
+ }
+ }
+ return configs;
+ }
+
+ public void deactivate(final int reason) {
+ for (SerialDevice serialDevice : serialDevices.values()) {
+ serialDevice.close();
+ }
+ serialDevices.clear();
+ }
+
+ private void retrieveStateFromRelayBoard(SerialDevice serialDevice) {
+ //consume any bytes left in a stream
+ serialDevice.readBytes(new byte[100]);
+ serialDevice.writeBytes(UCPRelayBoardMessages.GET_STATE);
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ignored) {
+ }
+ readAndDecodeResponse(serialDevice);
+ }
+
+ private void readAndDecodeResponse(SerialDevice serialDevice) {
+ byte response[] = serialDevice.readBytes(new byte[5]);
+ if (validateResponse(response)) {
+ for (int relay = 0; relay < 8; relay++) {
+ Item item = getItemForRelay(serialDevice, relay);
+ if (item != null) {
+ UCPRelayConfig config = getRelayConfigForItem(item.getName());
+ State state = getRelayState(response, relay, config);
+ eventPublisher.postUpdate(item.getName(), state);
+ }
+ }
+ }
+ }
+
+ private boolean validateResponse(byte[] response) {
+ if (response[0] != 85) {
+ return false;
+ }
+ if (!checkCRC(response)) {
+ return false;
+ }
+ return true;
+ }
+
+ private boolean checkCRC(byte[] response) {
+ final byte[] tab = Arrays.copyOfRange(response, 1, 4);
+ final byte crc = DowCRC.compute(tab);
+ if (crc != response[4]) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ private OnOffType getRelayState(byte[] response, int relay, UCPRelayConfig config) {
+ OnOffType state;
+ if ((response[3] & (1 << relay)) > 0) {
+ state = OnOffType.ON;
+ } else {
+ state = OnOffType.OFF;
+ }
+ return config.translateCommand(state);
+ }
+
+ private Item getItemForRelay(SerialDevice serialDevice, int relay) {
+ for (UCPRelayBoardBindingProvider provider : providers) {
+ Item item = provider.getItemForRelayConfig(new UCPRelayConfig(serialDevice.getConfig().getName(), relay));
+ if (item != null) {
+ return item;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected void execute() {
+ for (SerialDevice serialDevice : serialDevices.values()) {
+ retrieveStateFromRelayBoard(serialDevice);
+ }
+
+ }
+
+ @Override
+ protected long getRefreshInterval() {
+ return refreshInterval;
+ }
+
+ @Override
+ protected String getName() {
+ return "UCProjects.eu Relay Board Binding Thread";
+ }
+}
diff --git a/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/internal/UCPRelayBoardGenericBindingProvider.java b/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/internal/UCPRelayBoardGenericBindingProvider.java
new file mode 100644
index 00000000000..86fc01c7a37
--- /dev/null
+++ b/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/internal/UCPRelayBoardGenericBindingProvider.java
@@ -0,0 +1,84 @@
+/**
+ * Copyright (c) 2010-2015, openHAB.org and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.openhab.binding.ucprelayboard.internal;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.openhab.binding.ucprelayboard.UCPRelayBoardBindingProvider;
+import org.openhab.core.binding.BindingConfig;
+import org.openhab.core.items.Item;
+import org.openhab.core.library.items.SwitchItem;
+import org.openhab.model.item.binding.AbstractGenericBindingProvider;
+import org.openhab.model.item.binding.BindingConfigParseException;
+
+/**
+ * @author Robert Michalak
+ * @since 1.8.0
+ */
+public class UCPRelayBoardGenericBindingProvider extends
+ AbstractGenericBindingProvider implements UCPRelayBoardBindingProvider {
+
+ @Override
+ public String getBindingType() {
+ return "ucprelayboard";
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void validateItemType(Item item, String bindingConfig)
+ throws BindingConfigParseException {
+ if (!(item instanceof SwitchItem)) {
+ throw new BindingConfigParseException(
+ "item '"
+ + item.getName()
+ + "' is of type '"
+ + item.getClass().getSimpleName()
+ + "', only SwitchItems are allowed - please check your *.items configuration");
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void processBindingConfiguration(String context, Item item,
+ String bindingConfig) throws BindingConfigParseException {
+
+ super.processBindingConfiguration(context, item, bindingConfig);
+
+ UCPRelayConfig config = UCPRelayConfig.fromString(bindingConfig);
+
+ addBindingConfig(item, config);
+
+ }
+
+ @Override
+ public UCPRelayConfig getRelayConfigForItem(String itemName) {
+ return (UCPRelayConfig) bindingConfigs.get(itemName);
+ }
+
+ @Override
+ public Item getItemForRelayConfig(UCPRelayConfig config) {
+ for (Map.Entry bindingConfig : bindingConfigs.entrySet()) {
+ if (bindingConfig.getValue().equals(config)) {
+ for (Map.Entry> context : contextMap.entrySet()) {
+ for (Item item : context.getValue()) {
+ if (item.getName().equals(bindingConfig.getKey())) {
+ return item;
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/internal/UCPRelayBoardMessages.java b/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/internal/UCPRelayBoardMessages.java
new file mode 100644
index 00000000000..b42669ae357
--- /dev/null
+++ b/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/internal/UCPRelayBoardMessages.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2010-2015, openHAB.org and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.openhab.binding.ucprelayboard.internal;
+/**
+ * Predefined messages
+ *
+ * @author Robert Michalak
+ * @since 1.8.0
+ */
+public class UCPRelayBoardMessages {
+
+ public static final byte[][] ON = new byte[][] {
+ new byte[] { 0x55, 0x01, 0x4f, 0x00, 0x28 },
+ new byte[] { 0x55, 0x01, 0x4f, 0x01, 0x76 },
+ new byte[] { 0x55, 0x01, 0x4f, 0x02, (byte) 0x94 },
+ new byte[] { 0x55, 0x01, 0x4f, 0x03, (byte) 0xca },
+ new byte[] { 0x55, 0x01, 0x4f, 0x04, 0x49 },
+ new byte[] { 0x55, 0x01, 0x4f, 0x05, 0x17 },
+ new byte[] { 0x55, 0x01, 0x4f, 0x06, (byte) 0xf5 },
+ new byte[] { 0x55, 0x01, 0x4f, 0x07, (byte) 0xab } };
+
+ public static final byte[][] OFF = new byte[][] {
+ new byte[] { 0x55, 0x01, 0x46, 0x00, (byte) 0x9a },
+ new byte[] { 0x55, 0x01, 0x46, 0x01, (byte) 0xc4 },
+ new byte[] { 0x55, 0x01, 0x46, 0x02, 0x26 },
+ new byte[] { 0x55, 0x01, 0x46, 0x03, 0x78 },
+ new byte[] { 0x55, 0x01, 0x46, 0x04, (byte) 0xfb },
+ new byte[] { 0x55, 0x01, 0x46, 0x05, (byte) 0xa5 },
+ new byte[] { 0x55, 0x01, 0x46, 0x06, 0x47 },
+ new byte[] { 0x55, 0x01, 0x46, 0x07, 0x19 } };
+
+ /**
+ * This message can be sent to retrieve current state of relays.
+ * Board should respond with 5 bytes ('0x55' '0x01' '0x52' '' ''),
+ * where every bit in is a state of one relay.
+ *
+ * is computed using 'Dow CRC' algorithm for bytes 2-4 in a message
+ */
+ public static final byte[] GET_STATE = new byte[] {0x55, 0x01, 0x47, 0x00, 0x5e};
+
+}
diff --git a/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/internal/UCPRelayConfig.java b/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/internal/UCPRelayConfig.java
new file mode 100644
index 00000000000..e4d1a305307
--- /dev/null
+++ b/bundles/binding/org.openhab.binding.ucprelayboard/src/main/java/org/openhab/binding/ucprelayboard/internal/UCPRelayConfig.java
@@ -0,0 +1,115 @@
+/**
+ * Copyright (c) 2010-2015, openHAB.org and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+
+/**
+ * Configuration of a Switch
+ *
+ * @author Robert Michalak
+ */
+package org.openhab.binding.ucprelayboard.internal;
+
+import org.apache.commons.lang.StringUtils;
+import org.openhab.core.binding.BindingConfig;
+import org.openhab.core.library.types.OnOffType;
+import org.openhab.model.item.binding.BindingConfigParseException;
+
+/**
+ * @author Robert Michalak
+ * @since 1.8.0
+ */
+public class UCPRelayConfig implements BindingConfig {
+ private String boardName;
+ private int relayNumber;
+ private boolean inverted = false;
+
+ public UCPRelayConfig(String boardName, int relayNumber) {
+ this(boardName, relayNumber, false);
+ }
+
+ public UCPRelayConfig(String boardName, int relayNumber, boolean inverted) {
+ this.boardName = boardName;
+ this.relayNumber = relayNumber;
+ this.inverted = inverted;
+ }
+
+ public String getBoardName() {
+ return boardName;
+ }
+
+ public int getRelayNumber() {
+ return relayNumber;
+ }
+
+ public OnOffType translateCommand(OnOffType command) {
+ if (inverted) {
+ return OnOffType.values()[1 - command.ordinal()];
+ } else {
+ return command;
+ }
+ }
+
+ public static UCPRelayConfig fromString(final String config) throws BindingConfigParseException {
+ String boardName = null;
+ int relayNumber = -1;
+ boolean inverted = false;
+ final String[] params = StringUtils.split(config, ";");
+ for (String param : params) {
+ final String[] nameValue = StringUtils.split(param, "=");
+ if (nameValue.length != 2) {
+ continue;
+ }
+ if ("board".equals(nameValue[0])) {
+ boardName = nameValue[1];
+ } else if ("relay".equals(nameValue[0])) {
+ try {
+ relayNumber = Integer.parseInt(nameValue[1]);
+ } catch (NumberFormatException e) {
+ throw new BindingConfigParseException("Wrong item configuration. " + e.getMessage());
+ }
+ } else if ("inverted".equals(nameValue[0])) {
+ inverted = Boolean.valueOf(nameValue[1]);
+ }
+ }
+ if (boardName == null && relayNumber < 0) {
+ throw new BindingConfigParseException("Wrong item configuration. missing 'board' or 'relay' values");
+ }
+ return new UCPRelayConfig(boardName, relayNumber, inverted);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result
+ + ((boardName == null) ? 0 : boardName.hashCode());
+ result = prime * result + relayNumber;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ UCPRelayConfig other = (UCPRelayConfig) obj;
+ if (boardName == null) {
+ if (other.boardName != null)
+ return false;
+ } else if (!boardName.equals(other.boardName))
+ return false;
+ if (relayNumber != other.relayNumber)
+ return false;
+ return true;
+ }
+
+
+}
diff --git a/bundles/binding/pom.xml b/bundles/binding/pom.xml
index eaced5bea7e..4d63ab98d2b 100644
--- a/bundles/binding/pom.xml
+++ b/bundles/binding/pom.xml
@@ -158,12 +158,13 @@
org.openhab.binding.panasonictv
org.openhab.binding.enphaseenergy
org.openhab.binding.lightwaverf
- org.openhab.binding.souliss
+ org.openhab.binding.souliss
org.openhab.binding.sagercaster
org.openhab.binding.ipx800
org.openhab.binding.tacmi
org.openhab.binding.rwesmarthome
org.openhab.binding.lcn
org.openhab.binding.sapp
+ org.openhab.binding.ucprelayboard
diff --git a/distribution/openhabhome/configurations/openhab_default.cfg b/distribution/openhabhome/configurations/openhab_default.cfg
index 6f021a82899..99365fca17f 100644
--- a/distribution/openhabhome/configurations/openhab_default.cfg
+++ b/distribution/openhabhome/configurations/openhab_default.cfg
@@ -2171,3 +2171,12 @@ tcp:refreshinterval=250
#
# MQTT broker port SiteWhere is listening to.
# sitewhere:mqttPort=1883
+
+################################ UCProjects.eu Relay Board Binding ###################################
+#
+# Port and baud rate (optional, defaults to 57600) for every device
+# ucprelayboard:board.one.port=/dev/tyUSB0
+# ucprelayboard:board..baud=
+#
+# Refresh of relay board state interval in miliseconds (optional, defaults to 60000)
+# ucprelayboard:refresh=
diff --git a/distribution/pom.xml b/distribution/pom.xml
index fbb87cf060d..62d378ab645 100644
--- a/distribution/pom.xml
+++ b/distribution/pom.xml
@@ -1341,6 +1341,12 @@
${project.version}
jar
+
+ org.openhab.binding
+ org.openhab.binding.ucprelayboard
+ ${project.version}
+ jar
+
org.openhab.io