diff --git a/CODEOWNERS b/CODEOWNERS
index af1309b2b82bf..5dcd99276b4a1 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -47,6 +47,7 @@
/bundles/org.openhab.binding.feican/ @Hilbrand
/bundles/org.openhab.binding.folding/ @fa2k
/bundles/org.openhab.binding.freebox/ @lolodomo
+/bundles/org.openhab.binding.froeling/ @codeworkx
/bundles/org.openhab.binding.fronius/ @trokohl
/bundles/org.openhab.binding.fsinternetradio/ @paphko
/bundles/org.openhab.binding.ftpupload/ @paulianttila
diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml
index 587fb02e1ed25..cca3b54484012 100644
--- a/bom/openhab-addons/pom.xml
+++ b/bom/openhab-addons/pom.xml
@@ -225,6 +225,11 @@
org.openhab.binding.freebox
${project.version}
+
+ org.openhab.addons.bundles
+ org.openhab.binding.froeling
+ ${project.version}
+
org.openhab.addons.bundles
org.openhab.binding.fronius
diff --git a/bundles/org.openhab.binding.froeling/.classpath b/bundles/org.openhab.binding.froeling/.classpath
new file mode 100644
index 0000000000000..a5d95095ccaaf
--- /dev/null
+++ b/bundles/org.openhab.binding.froeling/.classpath
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bundles/org.openhab.binding.froeling/.project b/bundles/org.openhab.binding.froeling/.project
new file mode 100644
index 0000000000000..50fe70b812a64
--- /dev/null
+++ b/bundles/org.openhab.binding.froeling/.project
@@ -0,0 +1,23 @@
+
+
+ org.openhab.binding.froeling
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ org.eclipse.m2e.core.maven2Nature
+
+
diff --git a/bundles/org.openhab.binding.froeling/NOTICE b/bundles/org.openhab.binding.froeling/NOTICE
new file mode 100644
index 0000000000000..4c20ef446c1e4
--- /dev/null
+++ b/bundles/org.openhab.binding.froeling/NOTICE
@@ -0,0 +1,13 @@
+This content is produced and maintained by the openHAB project.
+
+* Project home: https://www.openhab.org
+
+== Declared Project Licenses
+
+This program and the accompanying materials are made available under the terms
+of the Eclipse Public License 2.0 which is available at
+https://www.eclipse.org/legal/epl-2.0/.
+
+== Source Code
+
+https://github.com/openhab/openhab2-addons
diff --git a/bundles/org.openhab.binding.froeling/README.md b/bundles/org.openhab.binding.froeling/README.md
new file mode 100644
index 0000000000000..bdb80d8c46b87
--- /dev/null
+++ b/bundles/org.openhab.binding.froeling/README.md
@@ -0,0 +1,72 @@
+# Froeling Binding
+
+The Froeling binding is used for reading data from Froeling furnace controllers.
+
+## Supported Bridges
+
+Serial-LAN converter
+
+## Supported Things
+
+Froeling P3200 controller (Bridge connected to COM1)
+
+## Discovery
+
+Discovery is not implemented.
+
+## Binding Configuration
+
+No binding configuration required.
+
+## Thing Configuration
+
+The Serial-LAN converter bridge needs ip address and telnet port of the Serial-LAN converter.
+The Froeling controller thing needs controller type, COM-port of the Froeling furnace controller and a polling interval.
+
+## Channels
+
+* **thing** `froeling`
+ * **channel** `status` (String)
+ * **channel** `furnacetemperature-current` (Number)
+ * **channel** `exhaustgastemperature-current` (Number)
+ * **channel** `furnacecontrolvariable` (Number)
+ * **channel** `primaryair` (Number)
+ * **channel** `remainoxygen` (Number)
+ * **channel** `oxygencontroller` (Number)
+ * **channel** `secondaryair` (Number)
+ * **channel** `idfan-setpoint` (Number)
+ * **channel** `idfan-current` (Number)
+ * **channel** `exhaustgastemperature-setpoint` (Number)
+ * **channel** `slidein-current` (Number)
+ * **channel** `pellet` (Number)
+ * **channel** `fillinglevel` (Number)
+ * **channel** `intakespeed` (Number)
+ * **channel** `deliverypower` (Number)
+ * **channel** `sensor-1` (Number)
+ * **channel** `furnacetemperature-setpoint` (Number)
+ * **channel** `sensor-buffertop` (Number)
+ * **channel** `sensor-bufferbottom` (Number)
+ * **channel** `bufferpump` (Number)
+ * **channel** `sensor-boiler` (Number)
+ * **channel** `sensor-flow1` (Number)
+ * **channel** `sensor-flow2` (Number)
+ * **channel** `heatingcircuitpump1` (Number)
+ * **channel** `heatingcircuitpump2` (Number)
+ * **channel** `outdoortemperature` (Number)
+ * **channel** `collectortemperature` (Number)
+ * **channel** `operatinghours` (Number)
+ * **channel** `error` (String)
+ * **channel** `lastupdate` (DateTime)
+
+## Full Example
+
+Items:
+```
+String FROELING_Status "Status: [%s]" (Froeling) { channel="froeling:controller:812d9fcb:status" }
+String FROELING_Error "Error: [%s]" (Froeling) { channel="froeling:controller:812d9fcb:error" }
+Number FROELING_Exhaustgastemperature "Exhaustgastemperature: [%d °C]" (Froeling) { channel="froeling:controller:812d9fcb:exhaustgastemperature-current" }
+Number FROELING_Furnacetemperature "Furnacetemperature: [%d °C]" (Froeling) { channel="froeling:controller:812d9fcb:furnacetemperature-current" }
+Number FROELING_Slidein_current "Slidein: [%d %%]" (Froeling) { channel="froeling:controller:812d9fcb:slidein-current" }
+DateTime FROELING_Lastupdate "Last update: [%1$tY-%1$tm-%1$td %1$tT]" (Froeling) { channel="froeling:controller:812d9fcb:lastupdate" }
+```
+812d9fcb = Controller ID as shown in PaperUI
diff --git a/bundles/org.openhab.binding.froeling/pom.xml b/bundles/org.openhab.binding.froeling/pom.xml
new file mode 100644
index 0000000000000..922348dc9b7db
--- /dev/null
+++ b/bundles/org.openhab.binding.froeling/pom.xml
@@ -0,0 +1,16 @@
+
+
+
+ 4.0.0
+
+
+ org.openhab.addons.bundles
+ org.openhab.addons.reactor.bundles
+ 2.5.0-SNAPSHOT
+
+
+ org.openhab.binding.froeling
+
+ openHAB Add-ons :: Bundles :: froeling Binding
+
+
diff --git a/bundles/org.openhab.binding.froeling/src/main/feature/feature.xml b/bundles/org.openhab.binding.froeling/src/main/feature/feature.xml
new file mode 100644
index 0000000000000..981ca6f1324eb
--- /dev/null
+++ b/bundles/org.openhab.binding.froeling/src/main/feature/feature.xml
@@ -0,0 +1,9 @@
+
+
+ mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${project.version}/xml/features
+
+
+ openhab-runtime-base
+ mvn:org.openhab.addons.bundles/org.openhab.binding.froeling/${project.version}
+
+
diff --git a/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/handler/IPBridgeHandler.java b/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/handler/IPBridgeHandler.java
new file mode 100644
index 0000000000000..50eb13f17bbb5
--- /dev/null
+++ b/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/handler/IPBridgeHandler.java
@@ -0,0 +1,145 @@
+/**
+ * Copyright (c) 2010-2019 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.froeling.handler;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.lang.StringUtils;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.smarthome.core.thing.Bridge;
+import org.eclipse.smarthome.core.thing.ChannelUID;
+import org.eclipse.smarthome.core.thing.ThingStatus;
+import org.eclipse.smarthome.core.thing.ThingStatusDetail;
+import org.eclipse.smarthome.core.thing.binding.BaseBridgeHandler;
+import org.eclipse.smarthome.core.types.Command;
+import org.openhab.binding.froeling.internal.config.IPBridgeConfiguration;
+import org.openhab.binding.froeling.internal.net.TelnetSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link IPBridgeHandler} is responsible for communicating with
+ * a Serial-LAN converter.
+ *
+ * @author Daniel Hillenbrand - Initial contribution
+ */
+@NonNullByDefault
+public class IPBridgeHandler extends BaseBridgeHandler {
+
+ private Logger logger = LoggerFactory.getLogger(IPBridgeHandler.class);
+ private TelnetSession session = null;
+ IPBridgeConfiguration config = getThing().getConfiguration().as(IPBridgeConfiguration.class);
+
+ public IPBridgeHandler(Bridge bridge) {
+ super(bridge);
+ this.session = new TelnetSession();
+ }
+
+ @Override
+ public void handleCommand(ChannelUID channelUID, Command command) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void initialize() {
+ this.scheduler.schedule(new Runnable() {
+ @Override
+ public void run() {
+ updateStatus(ThingStatus.ONLINE);
+ if (config == null) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
+ "bridge configuration missing");
+ return;
+ }
+
+ if (StringUtils.isEmpty(config.getIpAddress())) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
+ "bridge address not specified");
+ return;
+ }
+
+ if (config.getPort() <= 0) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
+ "bridge port not specified");
+ return;
+ }
+ }
+ }, 0, TimeUnit.SECONDS);
+ }
+
+ public synchronized void connect() {
+ if (this.session != null) {
+ if (this.session.isConnected()) {
+ this.logger.info("Already connected to the bridge");
+ return;
+ }
+ } else {
+ this.logger.info("TelnetSession is null, creating new session");
+ this.session = new TelnetSession();
+ }
+ this.logger.info("Connecting to bridge at {}:{}", config.getIpAddress(), config.getPort());
+ try {
+ this.session.open(config.getIpAddress(), config.getPort());
+ } catch (IOException e) {
+ this.logger.error("Failed to connect to bridge at {}:{}", config.getIpAddress(), config.getPort());
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "failed to connect");
+ }
+ this.logger.debug("Connected to bridge at {}:{}", config.getIpAddress(), config.getPort());
+ updateStatus(ThingStatus.ONLINE);
+ }
+
+ public boolean isConnected() {
+ if (this.session != null) {
+ this.logger.info("Bridge state: {}", this.session.isConnected());
+ return this.session.isConnected();
+ } else {
+ return false;
+ }
+ }
+
+ public synchronized void disconnect() {
+ this.logger.info("Disconnecting from bridge");
+ try {
+ if (this.session != null) {
+ this.session.close();
+ }
+ } catch (Exception e) {
+ this.logger.error("Error disconnecting from bridge", e);
+ }
+ }
+
+ private synchronized void reconnect() {
+ this.logger.info("Attempting to reconnect to the bridge");
+ disconnect();
+ connect();
+ }
+
+ @Override
+ public void dispose() {
+ disconnect();
+ }
+
+ public String readInput() throws IOException {
+ String buffer = "";
+ if (this.session != null) {
+ if (!this.session.isConnected()) {
+ reconnect();
+ } else {
+ buffer = this.session.readline();
+ }
+ }
+ return buffer;
+ }
+}
diff --git a/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/handler/froelingHandler.java b/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/handler/froelingHandler.java
new file mode 100644
index 0000000000000..cbe936e2fa7ea
--- /dev/null
+++ b/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/handler/froelingHandler.java
@@ -0,0 +1,401 @@
+/**
+ * Copyright (c) 2010-2019 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.froeling.handler;
+
+import static org.openhab.binding.froeling.internal.froelingBindingConstants.*;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.smarthome.core.library.types.DateTimeType;
+import org.eclipse.smarthome.core.library.types.DecimalType;
+import org.eclipse.smarthome.core.library.types.StringType;
+import org.eclipse.smarthome.core.thing.Bridge;
+import org.eclipse.smarthome.core.thing.ChannelUID;
+import org.eclipse.smarthome.core.thing.Thing;
+import org.eclipse.smarthome.core.thing.ThingStatus;
+import org.eclipse.smarthome.core.thing.ThingStatusDetail;
+import org.eclipse.smarthome.core.thing.binding.BaseThingHandler;
+import org.eclipse.smarthome.core.thing.binding.ThingHandler;
+import org.eclipse.smarthome.core.types.Command;
+import org.openhab.binding.froeling.internal.config.FroelingConfiguration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link froelingHandler} is responsible for handling commands, which are
+ * sent to one of the channels.
+ *
+ * @author Daniel Hillenbrand - Initial contribution
+ */
+@NonNullByDefault
+public class froelingHandler extends BaseThingHandler {
+ private final Logger logger = LoggerFactory.getLogger(froelingHandler.class);
+ private @Nullable FroelingConfiguration config;
+ private IPBridgeHandler bridgeHandler = null;
+
+ public froelingHandler(Thing thing) {
+ super(thing);
+ }
+
+ @Override
+ public void handleCommand(ChannelUID channelUID, Command command) {
+ // TODO: handle command
+ }
+
+ @Override
+ public void initialize() {
+ config = getConfigAs(FroelingConfiguration.class);
+ getIPBridgeHandler();
+
+ updateStatus(ThingStatus.ONLINE);
+ PollingSchedularService pSS = new PollingSchedularService();
+ try {
+ this.logger.debug("Entering pollingLoop");
+ pSS.pollingLoop();
+ } catch (Exception e) {
+ this.logger.error("Error while polling:", e);
+ }
+ }
+
+ @NonNullByDefault
+ public class PollingSchedularService {
+ FroelingConfiguration config = getThing().getConfiguration().as(FroelingConfiguration.class);
+ private Logger logger = LoggerFactory.getLogger(PollingSchedularService.class);
+
+ public void pollingLoop() throws Exception {
+ long initialDelay = 10;
+ long pollingInterval = config.getPollingInterval().longValue();
+
+ if (pollingInterval < 5 || pollingInterval > 3600) {
+ this.logger.warn("Invalid polling rate: {}. Using 5 seconds.", pollingInterval);
+ pollingInterval = 5;
+ }
+
+ this.logger.info("Starting PollingService with interval: {} seconds", pollingInterval);
+ ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
+ executor.scheduleWithFixedDelay(new PollingService(), initialDelay, pollingInterval, TimeUnit.SECONDS);
+ }
+ }
+
+ @NonNullByDefault
+ class PollingService implements Runnable {
+ @Override
+ public void run() {
+ // Get and parse data from froeling controller
+ getData();
+ }
+ }
+
+ public void getData() {
+ this.logger.info("Trying to get some data");
+ FroelingConfiguration config = null;
+ try {
+ config = getThing().getConfiguration().as(FroelingConfiguration.class);
+ } catch (Exception e) {
+ this.logger.error("Error getting Froeling configuration");
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
+ "Error getting Froeling configuration");
+ return;
+ }
+
+ switch (config.getControllerType()) {
+ case "P3200":
+ this.logger.info("Froeling controller: {} COM-Port: {}", config.getControllerType(),
+ config.getComPort());
+ switch (config.getComPort()) {
+ case "COM1":
+ this.logger.info("Case: COM1");
+ if (bridgeHandler == null) {
+ this.logger.error("BridgeHandler not available");
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE,
+ "BridgeHandler not available");
+ return;
+ }
+ // Connect to bridge
+ bridgeHandler.connect();
+ // Check if bridge is connected and get some data
+ if (bridgeHandler.isConnected()) {
+ this.logger.info("BridgeHandler is connected, calling getP3200COM1Data()");
+ updateStatus(ThingStatus.ONLINE);
+ getP3200COM1Data();
+ } else {
+ this.logger.error("BridgeHandler is not connected, not calling getP3200COM1Data()");
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE,
+ "BridgeHandler is not connected");
+ return;
+ }
+ // Disconnect from bridge
+ bridgeHandler.disconnect();
+ break;
+ case "COM2":
+ this.logger.warn("Specified COM-Port not supported yet");
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
+ "Specified COM-Port not supported yet");
+ break;
+ default:
+ this.logger.error("Invalid COM-Port selected");
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
+ "Invalid COM-Port selected");
+ break;
+ }
+ break;
+ default:
+ this.logger.error("Invalid Froeling controller selected");
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
+ "Invalid Froeling controller selected");
+ break;
+ }
+ }
+
+ public void getP3200COM1Data() {
+ this.logger.info("Getting P3200 controller data");
+ long timeStart = System.currentTimeMillis();
+ boolean dataStart = false;
+ boolean dataSuccess = false;
+ int iterations = 0;
+ String inputData = "";
+ String buffer = "";
+ String dataBlockSeparator = "$ ";
+
+ // Get data from controller
+ while (dataSuccess == false) {
+ try {
+ inputData = bridgeHandler.readInput();
+ if (inputData != null) {
+ if (dataStart == true && inputData.startsWith(dataBlockSeparator)) {
+ // Got a full data block
+ this.logger.info("Got full data block from Froeling controller");
+ dataSuccess = true;
+ break;
+ }
+ if (dataStart == false && inputData.startsWith(dataBlockSeparator)) {
+ dataStart = true;
+ }
+ if (dataStart == true && !inputData.isEmpty()) {
+ buffer += inputData;
+ } else if (dataStart == true && inputData.isEmpty()) {
+ buffer += "\r\n";
+ }
+ }
+ } catch (Exception e) {
+ this.logger.error("Failed getting data from Froeling controller:", e);
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
+ "failed getting data from Froeling controller");
+ break;
+ }
+ if (iterations >= 200) {
+ this.logger.error("No full data block after 200 iterations.");
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
+ "No full data block after 200 iterations");
+ break;
+ }
+ if ((System.currentTimeMillis() - 60000L) > timeStart) {
+ this.logger.error("No full data block after 60 seconds.");
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
+ "No full data block after 60 seconds");
+ break;
+ }
+ iterations += 1;
+ }
+
+ // Parse data
+ if (dataSuccess == true) {
+ this.logger.info("Parsing P3200 controller data");
+ try {
+ String[] lineArray = buffer.split("\r\n");
+
+ for (String line : lineArray) {
+ String data[] = line.split(";");
+
+ /*
+ * data[0] = Label
+ * data[1] = Value
+ * data[2] = Ordinal number
+ * data[3] = Factor for value
+ * data[4] = Unit
+ * data[5] = Unit if data[4] is empty
+ */
+
+ // Remove data block separator from status label
+ if (data[0].startsWith(dataBlockSeparator)) {
+ data[0] = data[0].replace(dataBlockSeparator, "");
+ }
+
+ // Trim label
+ data[0] = data[0].trim();
+
+ // Print raw data
+ // this.logger.info("RAW: (" + data[2] + ") " + data[0] + " = " + data[1] + " " + data[4] + "["
+ // + data[3] + "]");
+
+ // Don't try to convert status and error texts to int
+ if (!data[2].equals("1") && !data[2].equals("99")) {
+ int factor = Integer.parseInt(data[3]);
+ int value = Integer.parseInt(data[1]);
+
+ // induced draft fan
+ if (data[2].equals("10")) {
+ data[1] = Integer.toString((value / 30));
+ } else {
+ data[1] = Integer.toString((value / factor));
+ }
+ }
+ // If data[4] is empty, use data[5] to get unit
+ if (data[4].equals("") && !data[5].isEmpty()) {
+ data[4] = data[5];
+ }
+ // Print converted data
+ this.logger.info("CON: ({}) {} = {} {}", data[2], data[0], data[1], data[4]);
+
+ switch (data[2]) {
+ case "1":
+ updateState(thing.getChannel(CHANNEL_STATUS).getUID(), new StringType(data[0]));
+ break;
+
+ case "2":
+ updateState(thing.getChannel(CHANNEL_FURNACETEMPERATURE_CURRENT).getUID(),
+ new DecimalType(data[1]));
+ break;
+ case "3":
+ updateState(thing.getChannel(CHANNEL_EXHAUSTTEMPERATURE_CURRENT).getUID(),
+ new DecimalType(data[1]));
+ break;
+ case "4":
+ updateState(thing.getChannel(CHANNEL_FURNACECONTROLVARIABLE).getUID(),
+ new DecimalType(data[1]));
+ break;
+ case "5":
+ updateState(thing.getChannel(CHANNEL_PRIMARYAIR).getUID(), new DecimalType(data[1]));
+ break;
+ case "6":
+ updateState(thing.getChannel(CHANNEL_REMAINOXYGEN).getUID(), new DecimalType(data[1]));
+ break;
+ case "7":
+ updateState(thing.getChannel(CHANNEL_OXYGENCONTROLLER).getUID(), new DecimalType(data[1]));
+ break;
+ case "8":
+ updateState(thing.getChannel(CHANNEL_SECONDARYAIR).getUID(), new DecimalType(data[1]));
+ break;
+ case "9":
+ updateState(thing.getChannel(CHANNEL_IDFAN_SETPOINT).getUID(), new DecimalType(data[1]));
+ break;
+ case "10":
+ updateState(thing.getChannel(CHANNEL_IDFAN_CURRENT).getUID(), new DecimalType(data[1]));
+ break;
+ case "11":
+ updateState(thing.getChannel(CHANNEL_EXHAUSTTEMPERATURE_SETPOINT).getUID(),
+ new DecimalType(data[1]));
+ break;
+ case "12":
+ updateState(thing.getChannel(CHANNEL_SLIDEIN_CURRENT).getUID(), new DecimalType(data[1]));
+ break;
+ case "13":
+ updateState(thing.getChannel(CHANNEL_PELLET).getUID(), new DecimalType(data[1]));
+ break;
+ case "14":
+ updateState(thing.getChannel(CHANNEL_FILLING_LEVEL).getUID(), new DecimalType(data[1]));
+ break;
+ case "15":
+ updateState(thing.getChannel(CHANNEL_INTAKESPEED).getUID(), new DecimalType(data[1]));
+ break;
+ case "16":
+ updateState(thing.getChannel(CHANNEL_DELIVERYPOWER).getUID(), new DecimalType(data[1]));
+ break;
+ case "17":
+ updateState(thing.getChannel(CHANNEL_SENSOR_1).getUID(), new DecimalType(data[1]));
+ break;
+ case "18":
+ updateState(thing.getChannel(CHANNEL_FURNACETEMPERATURE_SETPOINT).getUID(),
+ new DecimalType(data[1]));
+ break;
+ case "20":
+ updateState(thing.getChannel(CHANNEL_SENSOR_BUFFERTOP).getUID(), new DecimalType(data[1]));
+ break;
+ case "21":
+ updateState(thing.getChannel(CHANNEL_SENSOR_BUFFERBOTTOM).getUID(),
+ new DecimalType(data[1]));
+ break;
+ case "22":
+ updateState(thing.getChannel(CHANNEL_BUFFER_PUMP).getUID(), new DecimalType(data[1]));
+ break;
+ case "23":
+ updateState(thing.getChannel(CHANNEL_SENSOR_BOILER).getUID(), new DecimalType(data[1]));
+ break;
+ case "24":
+ updateState(thing.getChannel(CHANNEL_SENSOR_FLOW_1).getUID(), new DecimalType(data[1]));
+ break;
+ case "25":
+ updateState(thing.getChannel(CHANNEL_SENSOR_FLOW_2).getUID(), new DecimalType(data[1]));
+ break;
+ case "26":
+ updateState(thing.getChannel(CHANNEL_HEATINGCIRCUITPUMP_1).getUID(),
+ new DecimalType(data[1]));
+ break;
+ case "27":
+ updateState(thing.getChannel(CHANNEL_HEATINGCIRCUITPUMP_2).getUID(),
+ new DecimalType(data[1]));
+ break;
+ case "28":
+ updateState(thing.getChannel(CHANNEL_OUTDOORTEMPERATURE).getUID(),
+ new DecimalType(data[1]));
+ break;
+ case "29":
+ updateState(thing.getChannel(CHANNEL_COLLECTORTEMPERATURE).getUID(),
+ new DecimalType(data[1]));
+ break;
+ case "30":
+ updateState(thing.getChannel(CHANNEL_OPERATINGHOURS).getUID(), new DecimalType(data[1]));
+ break;
+ case "99":
+ updateState(thing.getChannel(CHANNEL_ERRORS).getUID(), new StringType(data[1]));
+ break;
+ default:
+ this.logger.warn("No channel available for {} with value {} {}", data[0], data[1], data[4]);
+ break;
+ }
+ }
+ updateState(thing.getChannel(CHANNEL_LASTUPDATE).getUID(), new DateTimeType());
+ } catch (Exception e1) {
+ this.logger.error("Error while parsing P3200 controller data: {}", e1);
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
+ "Error while parsing P3200 controller data");
+ return;
+ }
+ this.logger.info("Done parsing P3200 controller data");
+ }
+ }
+
+ private synchronized IPBridgeHandler getIPBridgeHandler() {
+ if (this.bridgeHandler == null) {
+ Bridge bridge = getBridge();
+ if (bridge == null) {
+ logger.error("Required bridge not defined");
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, "Required bridge not defined");
+ return null;
+ }
+ ThingHandler handler = bridge.getHandler();
+ if (handler instanceof IPBridgeHandler) {
+ this.bridgeHandler = (IPBridgeHandler) handler;
+ } else {
+ logger.error("BridgeHandler for bridge {} not available", bridge.getUID());
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, "BridgeHandler not available");
+ return null;
+ }
+ }
+ return this.bridgeHandler;
+ }
+}
diff --git a/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/internal/config/FroelingConfiguration.java b/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/internal/config/FroelingConfiguration.java
new file mode 100644
index 0000000000000..507f9b6ff0ea6
--- /dev/null
+++ b/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/internal/config/FroelingConfiguration.java
@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) 2010-2019 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.froeling.internal.config;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * @author Daniel Hillenbrand - Initial contribution
+ */
+@NonNullByDefault
+public class FroelingConfiguration {
+ private String controllerType;
+ private String comPort;
+ private Integer pollingInterval;
+
+ public String getControllerType() {
+ return controllerType;
+ }
+
+ public String getComPort() {
+ return comPort;
+ }
+
+ public Integer getPollingInterval() {
+ return pollingInterval;
+ }
+
+ public void setControllerType(String controllerType) {
+ this.controllerType = controllerType;
+ }
+
+ public void setPort(String comPort) {
+ this.comPort = comPort;
+ }
+
+ public void setPollingInterval(Integer pollingInterval) {
+ this.pollingInterval = pollingInterval;
+ }
+}
diff --git a/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/internal/config/IPBridgeConfiguration.java b/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/internal/config/IPBridgeConfiguration.java
new file mode 100644
index 0000000000000..c220bbdba4461
--- /dev/null
+++ b/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/internal/config/IPBridgeConfiguration.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2010-2019 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.froeling.internal.config;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * @author Daniel Hillenbrand - Initial contribution
+ */
+@NonNullByDefault
+public class IPBridgeConfiguration {
+ private String ipAddress;
+ private Integer port;
+
+ public String getIpAddress() {
+ return ipAddress;
+ }
+
+ public Integer getPort() {
+ return port;
+ }
+
+ public void setIpAddress(String ipAddress) {
+ this.ipAddress = ipAddress;
+ }
+
+ public void setPort(Integer port) {
+ this.port = port;
+ }
+}
diff --git a/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/internal/froelingBindingConstants.java b/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/internal/froelingBindingConstants.java
new file mode 100644
index 0000000000000..628a280169a6d
--- /dev/null
+++ b/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/internal/froelingBindingConstants.java
@@ -0,0 +1,67 @@
+/**
+ * Copyright (c) 2010-2019 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.froeling.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.smarthome.core.thing.ThingTypeUID;
+
+/**
+ * The {@link froelingBindingConstants} class defines common constants, which are
+ * used across the whole binding.
+ *
+ * @author Daniel Hillenbrand - Initial contribution
+ */
+@NonNullByDefault
+public class froelingBindingConstants {
+
+ public static final String BINDING_ID = "froeling";
+
+ // Bridge Type UIDs
+ public final static ThingTypeUID THING_TYPE_IPBRIDGE = new ThingTypeUID(BINDING_ID, "ipbridge");
+
+ // List of all Thing Type UIDs
+ public final static ThingTypeUID THING_TYPE_CONTROLLER = new ThingTypeUID(BINDING_ID, "controller");
+
+ // List of all Channel ids
+ public final static String CHANNEL_STATUS = "status";
+ public final static String CHANNEL_FURNACETEMPERATURE_CURRENT = "furnacetemperature-current";
+ public final static String CHANNEL_EXHAUSTTEMPERATURE_CURRENT = "exhaustgastemperature-current";
+ public final static String CHANNEL_FURNACECONTROLVARIABLE = "furnacecontrolvariable";
+ public final static String CHANNEL_PRIMARYAIR = "primaryair";
+ public final static String CHANNEL_REMAINOXYGEN = "remainoxygen";
+ public final static String CHANNEL_OXYGENCONTROLLER = "oxygencontroller";
+ public final static String CHANNEL_SECONDARYAIR = "secondaryair";
+ public final static String CHANNEL_IDFAN_SETPOINT = "idfan-setpoint";
+ public final static String CHANNEL_IDFAN_CURRENT = "idfan-current";
+ public final static String CHANNEL_EXHAUSTTEMPERATURE_SETPOINT = "exhaustgastemperature-setpoint";
+ public final static String CHANNEL_SLIDEIN_CURRENT = "slidein-current";
+ public final static String CHANNEL_PELLET = "pellet";
+ public final static String CHANNEL_FILLING_LEVEL = "fillinglevel";
+ public final static String CHANNEL_INTAKESPEED = "intakespeed";
+ public final static String CHANNEL_DELIVERYPOWER = "deliverypower";
+ public final static String CHANNEL_SENSOR_1 = "sensor-1";
+ public final static String CHANNEL_FURNACETEMPERATURE_SETPOINT = "furnacetemperature-setpoint";
+ public final static String CHANNEL_SENSOR_BUFFERTOP = "sensor-buffertop";
+ public final static String CHANNEL_SENSOR_BUFFERBOTTOM = "sensor-bufferbottom";
+ public final static String CHANNEL_BUFFER_PUMP = "bufferpump";
+ public final static String CHANNEL_SENSOR_BOILER = "sensor-boiler";
+ public final static String CHANNEL_SENSOR_FLOW_1 = "sensor-flow1";
+ public final static String CHANNEL_SENSOR_FLOW_2 = "sensor-flow2";
+ public final static String CHANNEL_HEATINGCIRCUITPUMP_1 = "heatingcircuitpump1";
+ public final static String CHANNEL_HEATINGCIRCUITPUMP_2 = "heatingcircuitpump2";
+ public final static String CHANNEL_OUTDOORTEMPERATURE = "outdoortemperature";
+ public final static String CHANNEL_COLLECTORTEMPERATURE = "collectortemperature";
+ public final static String CHANNEL_OPERATINGHOURS = "operatinghours";
+ public final static String CHANNEL_ERRORS = "error";
+ public final static String CHANNEL_LASTUPDATE = "lastupdate";
+}
diff --git a/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/internal/froelingConfiguration.java b/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/internal/froelingConfiguration.java
new file mode 100644
index 0000000000000..3fa7c02c4858d
--- /dev/null
+++ b/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/internal/froelingConfiguration.java
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2010-2019 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.froeling.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link froelingConfiguration} class contains fields mapping thing configuration parameters.
+ *
+ * @author Daniel Hillenbrand - Initial contribution
+ */
+@NonNullByDefault
+public class froelingConfiguration {
+
+ /**
+ * Sample configuration parameter. Replace with your own.
+ */
+ public String config1;
+}
diff --git a/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/internal/froelingHandlerFactory.java b/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/internal/froelingHandlerFactory.java
new file mode 100644
index 0000000000000..90a2cdc245e08
--- /dev/null
+++ b/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/internal/froelingHandlerFactory.java
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2010-2019 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.froeling.internal;
+
+import static org.openhab.binding.froeling.internal.froelingBindingConstants.*;
+
+import java.util.Collections;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+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.openhab.binding.froeling.handler.IPBridgeHandler;
+import org.openhab.binding.froeling.handler.froelingHandler;
+import org.osgi.service.component.annotations.Component;
+
+/**
+ * The {@link froelingHandlerFactory} is responsible for creating things and thing
+ * handlers.
+ *
+ * @author Daniel Hillenbrand - Initial contribution
+ */
+@NonNullByDefault
+@Component(configurationPid = "binding.froeling", service = ThingHandlerFactory.class)
+public class froelingHandlerFactory extends BaseThingHandlerFactory {
+
+ public final static Set SUPPORTED_BRIDGE_THING_TYPES_UIDS = Collections
+ .unmodifiableSet(Stream.of(THING_TYPE_IPBRIDGE).collect(Collectors.toSet()));
+
+ public final static Set SUPPORTED_DEVICE_THING_TYPES_UIDS = Collections
+ .unmodifiableSet(Stream.of(THING_TYPE_CONTROLLER).collect(Collectors.toSet()));
+
+ private final static Set SUPPORTED_THING_TYPES_UIDS = Collections
+ .unmodifiableSet(Stream.of(THING_TYPE_IPBRIDGE, THING_TYPE_CONTROLLER).collect(Collectors.toSet()));
+
+ @Override
+ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
+ return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
+ }
+
+ @Override
+ protected @Nullable ThingHandler createHandler(Thing thing) {
+ ThingTypeUID thingTypeUID = thing.getThingTypeUID();
+
+ if (thingTypeUID.equals(THING_TYPE_IPBRIDGE)) {
+ return new IPBridgeHandler((Bridge) thing);
+ } else if (thingTypeUID.equals(THING_TYPE_CONTROLLER)) {
+ return new froelingHandler(thing);
+ }
+
+ return null;
+ }
+}
diff --git a/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/internal/net/NonblockingBufferedReader.java b/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/internal/net/NonblockingBufferedReader.java
new file mode 100644
index 0000000000000..62ea8624693a9
--- /dev/null
+++ b/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/internal/net/NonblockingBufferedReader.java
@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) 2010-2019 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.froeling.internal.net;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Daniel Hillenbrand - Initial contribution
+ */
+@NonNullByDefault
+public class NonblockingBufferedReader {
+
+ private Logger logger = LoggerFactory.getLogger(NonblockingBufferedReader.class);
+
+ private final BlockingQueue lines = new LinkedBlockingQueue();
+ private volatile boolean closed = false;
+ private Thread backgroundReaderThread = null;
+
+ public NonblockingBufferedReader(final BufferedReader bufferedReader) {
+ backgroundReaderThread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ while (!Thread.interrupted()) {
+ String line = bufferedReader.readLine();
+ if (line == null) {
+ break;
+ }
+ lines.add(line);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ } finally {
+ closed = true;
+ }
+ }
+ });
+ backgroundReaderThread.setDaemon(true);
+ backgroundReaderThread.start();
+ }
+
+ public String readLine() throws IOException {
+ try {
+ return closed && lines.isEmpty() ? null : lines.poll(500L, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ this.logger.error("The BackgroundReaderThread was interrupted!", e);
+ throw new IOException("The BackgroundReaderThread was interrupted!", e);
+ }
+ }
+
+ public void close() {
+ if (backgroundReaderThread != null) {
+ backgroundReaderThread.interrupt();
+ backgroundReaderThread = null;
+ }
+ }
+}
diff --git a/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/internal/net/TelnetSession.java b/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/internal/net/TelnetSession.java
new file mode 100644
index 0000000000000..495881efa2444
--- /dev/null
+++ b/bundles/org.openhab.binding.froeling/src/main/java/org/openhab/binding/froeling/internal/net/TelnetSession.java
@@ -0,0 +1,82 @@
+/**
+ * Copyright (c) 2010-2019 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.froeling.internal.net;
+
+import java.io.BufferedReader;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.commons.net.telnet.TelnetClient;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A single telnet session.
+ *
+ * @author Allan Tong - Initial contribution
+ */
+@NonNullByDefault
+public class TelnetSession implements Closeable {
+
+ private Logger logger = LoggerFactory.getLogger(TelnetSession.class);
+ private TelnetClient telnetClient = null;
+ private NonblockingBufferedReader nbreader = null;
+
+ public TelnetSession() {
+ this.telnetClient = new TelnetClient();
+ }
+
+ public void open(String host, int port) throws IOException {
+ if (this.telnetClient != null) {
+ this.telnetClient.connect(host, port);
+ this.telnetClient.setKeepAlive(true);
+
+ this.nbreader = new NonblockingBufferedReader(new BufferedReader(
+ new InputStreamReader(this.telnetClient.getInputStream(), StandardCharsets.ISO_8859_1), 1024));
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ try {
+ if (this.telnetClient != null) {
+ if (isConnected()) {
+ this.telnetClient.setKeepAlive(false);
+ }
+ this.telnetClient.disconnect();
+ }
+ } catch (Exception e) {
+ this.logger.error("Error closing telnetClient", e);
+ }
+ }
+
+ public boolean isConnected() {
+ if (this.telnetClient != null) {
+ return this.telnetClient.isConnected();
+ } else {
+ return false;
+ }
+ }
+
+ public String readline() throws IOException {
+ String buffer = "";
+
+ if (this.nbreader != null) {
+ buffer = this.nbreader.readLine();
+ }
+ return buffer;
+ }
+}
diff --git a/bundles/org.openhab.binding.froeling/src/main/resources/ESH-INF/binding/binding.xml b/bundles/org.openhab.binding.froeling/src/main/resources/ESH-INF/binding/binding.xml
new file mode 100644
index 0000000000000..676633247c3ef
--- /dev/null
+++ b/bundles/org.openhab.binding.froeling/src/main/resources/ESH-INF/binding/binding.xml
@@ -0,0 +1,10 @@
+
+
+
+ froeling Binding
+ This is the binding for Fröling furnace controllers.
+ Daniel Hillenbrand
+
+
diff --git a/bundles/org.openhab.binding.froeling/src/main/resources/ESH-INF/i18n/froeling_de_DE.properties b/bundles/org.openhab.binding.froeling/src/main/resources/ESH-INF/i18n/froeling_de_DE.properties
new file mode 100644
index 0000000000000..2320e17c685f5
--- /dev/null
+++ b/bundles/org.openhab.binding.froeling/src/main/resources/ESH-INF/i18n/froeling_de_DE.properties
@@ -0,0 +1,54 @@
+# binding
+binding.froeling.name = Fr�ling Heizkessel
+binding.froeling.description = Anbindung von Fr�ling Heizkessel mit P3200 Steuerung
+
+# thing types
+thing-type.froeling.ipbridge.label = Seriell-LAN Konverter
+thing-type.froeling.ipbridge.description = Seriell-LAN Konverter
+thing-type.config.froeling.ipbridge.ipAddress.label = Hostname oder IP
+thing-type.config.froeling.ipbridge.ipAddress.description = Hostname oder IP des Seriell-LAN Konverters
+thing-type.config.froeling.ipbridge.port.label = Port
+thing-type.config.froeling.ipbridge.port.description = Telnet Port des Seriell-LAN Konverters
+
+thing-type.froeling.controller.label = Fr�ling Steuerung
+thing-type.froeling.controller.description = Fr�ling Heizkessel Steuerung
+thing-type.config.froeling.controller.controllerType.label = Fr�ling Steuerungstyp
+thing-type.config.froeling.controller.controllerType.description = Typ der Fr�ling Steuerung
+thing-type.config.froeling.controller.comPort.label = Port
+thing-type.config.froeling.controller.comPort.description = COM-Port der Fr�ling Steuerung
+thing-type.config.froeling.controller.pollingInterval.label = Abfrageintervall
+thing-type.config.froeling.controller.pollingInterval.description = Das Abfrageintervall steuert in welchen Zeitabst�nden Daten von der Fr�ling Steuerung gelesen werden
+
+# channel types
+channel-type.froeling.status.label = Zustand
+channel-type.froeling.furnacetemperature.label = Kesseltemperatur
+channel-type.froeling.exhaustgastemperature-current.label = Abgastemperatur Ist
+channel-type.froeling.furnacecontrolvariable.label = Kesselstellgr��e
+channel-type.froeling.primaryair.label = Prim�rluft
+channel-type.froeling.remainoxygen.label = Restsauerstoff
+channel-type.froeling.oxygencontroller.label = Sauerstoffregler
+channel-type.froeling.secondaryair.label = Sekund�rluft
+channel-type.froeling.idfan-setpoint.label = Saugzug Soll
+channel-type.froeling.idfan-current.label = Saugzug Ist
+channel-type.froeling.exhaustgastemperature-setpoint.label = Abgstemperatur Soll
+channel-type.froeling.slideincurrent.label = Einschub Ist
+channel-type.froeling.pellet.label = Sauerstoffregler Pellet
+channel-type.froeling.fillinglevel.label = F�llstand
+channel-type.froeling.intakespeed.label = Ansauggeschwindigkeit
+channel-type.froeling.deliverypower.label = Strom Austragsystem
+channel-type.froeling.sensor-1.label = F�hler 1
+channel-type.froeling.furnacesetpoint.label = Kesseltemperatur Soll
+channel-type.froeling.sensor-buffertop.label = Puffer oben
+channel-type.froeling.sensor-bufferbottom.label = Puffer unten
+channel-type.froeling.bufferpump.label = Pufferpumpe
+channel-type.froeling.sensor-boiler.label = Boiler
+channel-type.froeling.sensor-flow1.label = Vorlauf 1
+channel-type.froeling.sensor-flow2.label = Vorlauf 2
+channel-type.froeling.heatingcircuitpump1.label = Heizkreispumpe 1
+channel-type.froeling.heatingcircuitpump2.label = Heizkreispumpe 2
+channel-type.froeling.outdoortemperature.label = Aussentemperatur
+channel-type.froeling.collectortemperature.label = Kollektortemperatur
+channel-type.froeling.operatinghours.label = Betriebsstunden
+channel-type.froeling.error.label = Fehler
+channel-type.froeling.lastupdate.label = Letzte Aktualisierung
+
diff --git a/bundles/org.openhab.binding.froeling/src/main/resources/ESH-INF/thing/bridge.xml b/bundles/org.openhab.binding.froeling/src/main/resources/ESH-INF/thing/bridge.xml
new file mode 100644
index 0000000000000..80ecf73e972c5
--- /dev/null
+++ b/bundles/org.openhab.binding.froeling/src/main/resources/ESH-INF/thing/bridge.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+ Serial-LAN Converter connected to Froeling controller
+
+
+
+ network-address
+
+ The IP or host name of the converter
+
+
+
+ The telnet port of the converter
+ 4002
+
+
+
+
+
\ No newline at end of file
diff --git a/bundles/org.openhab.binding.froeling/src/main/resources/ESH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.froeling/src/main/resources/ESH-INF/thing/thing-types.xml
new file mode 100644
index 0000000000000..2048d0df34349
--- /dev/null
+++ b/bundles/org.openhab.binding.froeling/src/main/resources/ESH-INF/thing/thing-types.xml
@@ -0,0 +1,294 @@
+
+
+
+
+
+
+
+
+
+ Froeling Controller
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Type of the Froeling controller
+
+
+
+
+
+
+ COM-Port of the Froeling Controller
+
+
+
+
+
+
+ The polling interval controls in which intervals to read data from Froeling controller
+ 600
+
+
+
+
+
+
+ String
+
+ Furnace status
+
+
+
+
+ Number
+
+ Furnace temperature current
+ Temperature
+
+
+
+
+ Number
+
+ Exhaust temperature current
+ Temperature
+
+
+
+
+ Number
+
+ Furnace control variable
+ Text
+
+
+
+
+ Number
+
+ Primary air
+
+
+
+
+ Number
+
+ Remain oxygen
+
+
+
+
+ Number
+
+ Oxygen controller
+
+
+
+
+ Number
+
+ Secondary air
+
+
+
+
+ Number
+
+ ID fan setpoint
+
+
+
+
+ Number
+
+ ID fan current
+
+
+
+
+ Number
+
+ Exhaust temperature setpoint
+ Temperature
+
+
+
+
+ Number
+
+ Slidein current
+
+
+
+
+ Number
+
+ Pellet
+
+
+
+
+ Number
+
+ Filling level
+
+
+
+
+ Number
+
+ Intake speed
+
+
+
+
+ Number
+
+ Delivery power
+
+
+
+
+ Number
+
+ Sensor 1
+
+
+
+
+ Number
+
+ Furnacetemperature setpoint
+
+
+
+
+ Number
+
+ Sensor buffer top
+
+
+
+
+ Number
+
+ Sensor buffer bottom
+
+
+
+
+ Number
+
+ Buffer pump
+
+
+
+
+ Number
+
+ Sensor boiler
+
+
+
+
+ Number
+
+ Sensor flow 1
+
+
+
+
+ Number
+
+ Sensor flow 2
+
+
+
+
+ Number
+
+ Heating circuit pump 1
+
+
+
+
+ Number
+
+ Heating circuit pump 2
+
+
+
+
+ Number
+
+ Outdoor temperature
+
+
+
+
+ Number
+
+ Collector temperature
+
+
+
+
+ Number
+
+ Operating hours
+
+
+
+
+ String
+
+ Error
+
+
+
+
+ DateTime
+
+ Time of last update
+
+
+
+
diff --git a/bundles/pom.xml b/bundles/pom.xml
index 467190139c4e1..f0e20ef2172ec 100644
--- a/bundles/pom.xml
+++ b/bundles/pom.xml
@@ -82,6 +82,7 @@
org.openhab.binding.feican
org.openhab.binding.folding
org.openhab.binding.freebox
+ org.openhab.binding.froeling
org.openhab.binding.fronius
org.openhab.binding.fsinternetradio
org.openhab.binding.ftpupload
@@ -170,6 +171,7 @@
org.openhab.binding.pulseaudio
org.openhab.binding.pushbullet
org.openhab.binding.regoheatpump
+ org.openhab.binding.resol
org.openhab.binding.rfxcom
org.openhab.binding.rme
org.openhab.binding.robonect