]> git.basschouten.com Git - openhab-addons.git/commitdiff
[haassohnpelletstove] Initial contribution (#10595)
authorchingon007 <76529461+chingon007@users.noreply.github.com>
Thu, 29 Apr 2021 18:59:37 +0000 (20:59 +0200)
committerGitHub <noreply@github.com>
Thu, 29 Apr 2021 18:59:37 +0000 (20:59 +0200)
Signed-off-by: Christian Feininger <tron81@gmx.de>
17 files changed:
CODEOWNERS
bom/openhab-addons/pom.xml
bundles/org.openhab.binding.haassohnpelletstove/NOTICE [new file with mode: 0644]
bundles/org.openhab.binding.haassohnpelletstove/README.md [new file with mode: 0644]
bundles/org.openhab.binding.haassohnpelletstove/pom.xml [new file with mode: 0644]
bundles/org.openhab.binding.haassohnpelletstove/src/main/feature/feature.xml [new file with mode: 0644]
bundles/org.openhab.binding.haassohnpelletstove/src/main/java/org/openhab/binding/haassohnpelletstove/internal/HaasSohnpelletstoveBindingConstants.java [new file with mode: 0644]
bundles/org.openhab.binding.haassohnpelletstove/src/main/java/org/openhab/binding/haassohnpelletstove/internal/HaasSohnpelletstoveConfiguration.java [new file with mode: 0644]
bundles/org.openhab.binding.haassohnpelletstove/src/main/java/org/openhab/binding/haassohnpelletstove/internal/HaasSohnpelletstoveHandler.java [new file with mode: 0644]
bundles/org.openhab.binding.haassohnpelletstove/src/main/java/org/openhab/binding/haassohnpelletstove/internal/HaasSohnpelletstoveHandlerFactory.java [new file with mode: 0644]
bundles/org.openhab.binding.haassohnpelletstove/src/main/java/org/openhab/binding/haassohnpelletstove/internal/HaasSohnpelletstoveJSONCommunication.java [new file with mode: 0644]
bundles/org.openhab.binding.haassohnpelletstove/src/main/java/org/openhab/binding/haassohnpelletstove/internal/HaasSohnpelletstoveJsonDataDTO.java [new file with mode: 0644]
bundles/org.openhab.binding.haassohnpelletstove/src/main/java/org/openhab/binding/haassohnpelletstove/internal/Helper.java [new file with mode: 0644]
bundles/org.openhab.binding.haassohnpelletstove/src/main/java/org/openhab/binding/haassohnpelletstove/internal/MD5Utils.java [new file with mode: 0644]
bundles/org.openhab.binding.haassohnpelletstove/src/main/resources/OH-INF/binding/binding.xml [new file with mode: 0644]
bundles/org.openhab.binding.haassohnpelletstove/src/main/resources/OH-INF/thing/thing-types.xml [new file with mode: 0644]
bundles/pom.xml

index 8ffad8e5199841cfcff6cad036c6ba8ae5ad6998..5462def510b5b5a9012315967353de13b3c8a456 100644 (file)
@@ -97,6 +97,7 @@
 /bundles/org.openhab.binding.gpstracker/ @gbicskei
 /bundles/org.openhab.binding.gree/ @markus7017
 /bundles/org.openhab.binding.groheondus/ @FlorianSW
+/bundles/org.openhab.binding.haassohnpelletstove/ @chingon007
 /bundles/org.openhab.binding.harmonyhub/ @digitaldan
 /bundles/org.openhab.binding.haywardomnilogic/ @matchews
 /bundles/org.openhab.binding.hdanywhere/ @kgoderis
index 385c85c2d4045644f48849f2aeb7764a8792d51e..10205adc0c26b4e13404a6e98f12c370dc72af3f 100644 (file)
       <artifactId>org.openhab.binding.groheondus</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.openhab.addons.bundles</groupId>
+      <artifactId>org.openhab.binding.haassohnpelletstove</artifactId>
+      <version>${project.version}</version>
+    </dependency>
     <dependency>
       <groupId>org.openhab.addons.bundles</groupId>
       <artifactId>org.openhab.binding.harmonyhub</artifactId>
diff --git a/bundles/org.openhab.binding.haassohnpelletstove/NOTICE b/bundles/org.openhab.binding.haassohnpelletstove/NOTICE
new file mode 100644 (file)
index 0000000..38d625e
--- /dev/null
@@ -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/openhab-addons
diff --git a/bundles/org.openhab.binding.haassohnpelletstove/README.md b/bundles/org.openhab.binding.haassohnpelletstove/README.md
new file mode 100644 (file)
index 0000000..2d053f4
--- /dev/null
@@ -0,0 +1,69 @@
+# Haas Sohn Pellet Stove Binding
+
+The binding for Haassohnpelletstove communicates with a Haas and Sohn Pelletstove through the optional
+WIFI module. More information about the WIFI module can be found here: https://www.haassohn.com/de/ihr-plus/WLAN-Funktion
+
+## Supported Things
+
+| Things | Description  | Thing Type |
+|--------|--------------|------------|
+| haassohnpelletstove | Control of a Haas & Sohn Pellet Stove| oven|
+
+
+## Thing Configuration
+
+In general two parameters are required. The IP-Address of the WIFI-Modul of the Stove in the local Network and the Access PIN of the Stove.
+The PIN can be found directly at the stove under the Menue/Network/WLAN-PIN
+
+```
+Thing haassohnpelletstove:oven:myOven "Pelletstove"  [ hostIP="192.168.0.23", hostPIN="1234"]
+```
+
+## Channels
+
+The following channels are yet supported:
+
+
+| Channel | Type  | Access| Description|
+|---------|-------|-------|------------|
+| power| Switch | read/write|Turn the stove on/off|
+|channelIsTemp|Number:Temperature|read|Receives the actual temperature of the stove|
+|channelSpTemp|Number:Temperature|read/write|Receives and sets the target temperature of the stove|
+|channelMode|String|read|Receives the actual mode the stove is in like heating, cooling, error, ....|
+|channelEcoMode|Switch|read/write|Turn the eco mode of the stove on/off|
+|channelIngitions|Number|read|Amount of ignitions of the stove|
+|channelMaintenanceIn|Number:Mass|read|States the next maintenance in kg|
+|channelCleaningIn|String|read|States the next cleaning window in hours:minutes as string|
+|channelConsumption|Number:Mass|read|Total consumption of the stove|
+|channelOnTime|Number|read|Operation hours of the stove|
+
+## Full Example
+
+demo.items:
+
+```
+Number:Temperature isTemp { channel="oven:channelIsTemp" }
+Number:Temperature spTemp { channel="oven:channelSpTemp" }
+String mode { channel="oven:channelMode" }
+Switch power { channel="oven:power" }
+```
+
+## Google Assistant configuration
+
+See also: https://www.openhab.org/docs/ecosystem/google-assistant/
+
+googleassistantdemo.items
+
+```
+Group g_FeuerThermostat "FeuerThermostat" {ga="Thermostat" }
+Number StatusFeuer "Status Feuer" (g_FeuerThermostat) { ga="thermostatMode" }
+Number ZieltemperaturFeuer "ZieltemperaturFeuer" (g_FeuerThermostat) {ga="thermostatTemperatureSetpoint"}
+Number TemperaturFeuer "TemperaturFeuer" (g_FeuerThermostat) {ga="thermostatTemperatureAmbient"}
+```
+
+## Tested Hardware
+
+The binding was successfully tested with the following ovens:
+
+- HSP 7 DIANA
+- HSP6 434.08
diff --git a/bundles/org.openhab.binding.haassohnpelletstove/pom.xml b/bundles/org.openhab.binding.haassohnpelletstove/pom.xml
new file mode 100644 (file)
index 0000000..d7aed0a
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.openhab.addons.bundles</groupId>
+    <artifactId>org.openhab.addons.reactor.bundles</artifactId>
+    <version>3.1.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>org.openhab.binding.haassohnpelletstove</artifactId>
+
+  <name>openHAB Add-ons :: Bundles :: Haas + Sohn Pelletstove Binding</name>
+
+</project>
diff --git a/bundles/org.openhab.binding.haassohnpelletstove/src/main/feature/feature.xml b/bundles/org.openhab.binding.haassohnpelletstove/src/main/feature/feature.xml
new file mode 100644 (file)
index 0000000..6861266
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<features name="org.openhab.binding.haassohnpelletstove-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
+       <repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
+
+       <feature name="openhab-binding-haassohnpelletstove" description="Haas + Sohn Pelletstove Binding" version="${project.version}">
+               <feature>openhab-runtime-base</feature>
+               <bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.haassohnpelletstove/${project.version}</bundle>
+       </feature>
+</features>
diff --git a/bundles/org.openhab.binding.haassohnpelletstove/src/main/java/org/openhab/binding/haassohnpelletstove/internal/HaasSohnpelletstoveBindingConstants.java b/bundles/org.openhab.binding.haassohnpelletstove/src/main/java/org/openhab/binding/haassohnpelletstove/internal/HaasSohnpelletstoveBindingConstants.java
new file mode 100644 (file)
index 0000000..e60f57d
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2010-2021 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.haassohnpelletstove.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.thing.ThingTypeUID;
+
+/**
+ * The {@link HaasSohnpelletstoveBindingConstants} class defines common constants, which are
+ * used across the whole binding.
+ *
+ * @author Christian Feininger - Initial contribution
+ */
+@NonNullByDefault
+public class HaasSohnpelletstoveBindingConstants {
+
+    private static final String BINDING_ID = "haassohnpelletstove";
+
+    public static final ThingTypeUID THING_TYPE_OVEN = new ThingTypeUID(BINDING_ID, "oven");
+
+    public static final String CHANNELISTEMP = "channelIsTemp";
+    public static final String CHANNELMODE = "channelMode";
+    public static final String CHANNELSPTEMP = "channelSpTemp";
+    public static final String CHANNELPOWER = "power";
+    public static final String CHANNELECOMODE = "channelEcoMode";
+    public static final String CHANNELIGNITIONS = "channelIgnitions";
+    public static final String CHANNELMAINTENANCEIN = "channelMaintenanceIn";
+    public static final String CHANNELCLEANINGIN = "channelCleaningIn";
+    public static final String CHANNELCONSUMPTION = "channelConsumption";
+    public static final String CHANNELONTIME = "channelOnTime";
+}
diff --git a/bundles/org.openhab.binding.haassohnpelletstove/src/main/java/org/openhab/binding/haassohnpelletstove/internal/HaasSohnpelletstoveConfiguration.java b/bundles/org.openhab.binding.haassohnpelletstove/src/main/java/org/openhab/binding/haassohnpelletstove/internal/HaasSohnpelletstoveConfiguration.java
new file mode 100644 (file)
index 0000000..cfb6e3c
--- /dev/null
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2010-2021 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.haassohnpelletstove.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * The {@link HaasSohnpelletstoveConfiguration} class contains fields mapping thing configuration parameters.
+ *
+ * @author Christian Feininger - Initial contribution
+ */
+@NonNullByDefault
+public class HaasSohnpelletstoveConfiguration {
+
+    public @Nullable String hostIP = null;
+    public @Nullable String hostPIN = null;
+    public int refreshRate = 30;
+}
diff --git a/bundles/org.openhab.binding.haassohnpelletstove/src/main/java/org/openhab/binding/haassohnpelletstove/internal/HaasSohnpelletstoveHandler.java b/bundles/org.openhab.binding.haassohnpelletstove/src/main/java/org/openhab/binding/haassohnpelletstove/internal/HaasSohnpelletstoveHandler.java
new file mode 100644 (file)
index 0000000..a8c28a1
--- /dev/null
@@ -0,0 +1,318 @@
+/**
+ * Copyright (c) 2010-2021 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.haassohnpelletstove.internal;
+
+import static org.openhab.binding.haassohnpelletstove.internal.HaasSohnpelletstoveBindingConstants.*;
+
+import java.text.DecimalFormat;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import javax.measure.Unit;
+import javax.measure.quantity.Temperature;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.library.types.StringType;
+import org.openhab.core.library.unit.SIUnits;
+import org.openhab.core.thing.Channel;
+import org.openhab.core.thing.ChannelUID;
+import org.openhab.core.thing.Thing;
+import org.openhab.core.thing.ThingStatus;
+import org.openhab.core.thing.ThingStatusDetail;
+import org.openhab.core.thing.binding.BaseThingHandler;
+import org.openhab.core.types.Command;
+import org.openhab.core.types.State;
+import org.openhab.core.types.UnDefType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link HaasSohnpelletstoveHandler} is responsible for handling commands, which are
+ * sent to one of the channels.
+ *
+ * @author Christian Feininger - Initial contribution
+ */
+@NonNullByDefault
+public class HaasSohnpelletstoveHandler extends BaseThingHandler {
+
+    private final Logger logger = LoggerFactory.getLogger(HaasSohnpelletstoveHandler.class);
+
+    private @Nullable ScheduledFuture<?> refreshJob;
+
+    private HaasSohnpelletstoveConfiguration config = new HaasSohnpelletstoveConfiguration();
+    boolean resultOk = false;
+
+    private HaasSohnpelletstoveJSONCommunication serviceCommunication;
+
+    private boolean automaticRefreshing = false;
+
+    private Map<String, Boolean> linkedChannels = new HashMap<String, Boolean>();
+
+    public HaasSohnpelletstoveHandler(Thing thing) {
+        super(thing);
+        serviceCommunication = new HaasSohnpelletstoveJSONCommunication();
+    }
+
+    @Override
+    public void handleCommand(ChannelUID channelUID, Command command) {
+        if (channelUID.getId().equals(CHANNELPOWER)) {
+            String postData = null;
+            if (command.equals(OnOffType.ON)) {
+                postData = "{\"prg\":true}";
+            } else if (command.equals(OnOffType.OFF)) {
+                postData = "{\"prg\":false}";
+            }
+            if (postData != null) {
+                logger.debug("Executing {} command", CHANNELPOWER);
+                updateOvenData(postData);
+            }
+        } else if (channelUID.getId().equals(CHANNELSPTEMP)) {
+            if (command instanceof QuantityType<?>) {
+                QuantityType<?> value = (QuantityType<?>) command;
+
+                Unit<Temperature> unit = SIUnits.CELSIUS;
+                value = value.toUnit(unit);
+                if (value != null) {
+                    double a = value.doubleValue();
+                    String postdata = "{\"sp_temp\":" + a + "}";
+                    logger.debug("Executing {} command", CHANNELSPTEMP);
+                    updateOvenData(postdata);
+                }
+            } else {
+                logger.debug("Error. Command is the wrong type: {}", command.toString());
+            }
+        } else if (channelUID.getId().equals(CHANNELECOMODE)) {
+            String postData = null;
+            if (command.equals(OnOffType.ON)) {
+                postData = "{\"eco_mode\":true}";
+            } else if (command.equals(OnOffType.OFF)) {
+                postData = "{\"eco_mode\":false}";
+            }
+            if (postData != null) {
+                logger.debug("Executing {} command", CHANNELECOMODE);
+                updateOvenData(postData);
+            }
+        }
+    }
+
+    /**
+     * Calls the service to update the oven data
+     *
+     * @param postdata
+     */
+    private boolean updateOvenData(@Nullable String postdata) {
+        Helper message = new Helper();
+        if (serviceCommunication.updateOvenData(postdata, message, this.getThing().getUID().toString())) {
+            updateStatus(ThingStatus.ONLINE);
+            return true;
+        } else {
+            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
+                    message.getStatusDesription());
+            return false;
+        }
+    }
+
+    @Override
+    public void initialize() {
+        logger.debug("Initializing haassohnpelletstove handler for thing {}", getThing().getUID());
+        config = getConfigAs(HaasSohnpelletstoveConfiguration.class);
+        boolean validConfig = true;
+        String errors = "";
+        String statusDescr = null;
+        if (config.refreshRate < 0 && config.refreshRate > 999) {
+            errors += " Parameter 'refresh Rate' greater then 0 and less then 1000.";
+            statusDescr = "Parameter 'refresh Rate' greater then 0 and less then 1000.";
+            validConfig = false;
+        }
+        if (config.hostIP == null) {
+            errors += " Parameter 'hostIP' must be configured.";
+            statusDescr = "IP Address must be configured!";
+            validConfig = false;
+        }
+        if (config.hostPIN == null) {
+            errors += " Parameter 'hostPin' must be configured.";
+            statusDescr = "PIN must be configured!";
+            validConfig = false;
+        }
+        errors = errors.trim();
+        Helper message = new Helper();
+        message.setStatusDescription(statusDescr);
+        if (validConfig) {
+            serviceCommunication.setConfig(config);
+            if (serviceCommunication.refreshOvenConnection(message, this.getThing().getUID().toString())) {
+                if (updateOvenData(null)) {
+                    updateStatus(ThingStatus.ONLINE);
+                    updateLinkedChannels();
+                }
+            } else {
+                updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, message.getStatusDesription());
+            }
+        } else {
+            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, message.getStatusDesription());
+        }
+    }
+
+    private void updateLinkedChannels() {
+        verifyLinkedChannel(CHANNELISTEMP);
+        verifyLinkedChannel(CHANNELMODE);
+        verifyLinkedChannel(CHANNELPOWER);
+        verifyLinkedChannel(CHANNELSPTEMP);
+        verifyLinkedChannel(CHANNELECOMODE);
+        verifyLinkedChannel(CHANNELIGNITIONS);
+        verifyLinkedChannel(CHANNELMAINTENANCEIN);
+        verifyLinkedChannel(CHANNELCLEANINGIN);
+        verifyLinkedChannel(CHANNELCONSUMPTION);
+        verifyLinkedChannel(CHANNELONTIME);
+        if (!linkedChannels.isEmpty()) {
+            updateOvenData(null);
+            for (Channel channel : getThing().getChannels()) {
+                updateChannel(channel.getUID().getId());
+            }
+            startAutomaticRefresh();
+            automaticRefreshing = true;
+        }
+    }
+
+    private void verifyLinkedChannel(String channelID) {
+        if (isLinked(channelID) && !linkedChannels.containsKey(channelID)) {
+            linkedChannels.put(channelID, true);
+        }
+    }
+
+    @Override
+    public void dispose() {
+        stopScheduler();
+    }
+
+    private void stopScheduler() {
+        ScheduledFuture<?> job = refreshJob;
+        if (job != null) {
+            job.cancel(true);
+        }
+        refreshJob = null;
+    }
+
+    /**
+     * Start the job refreshing the oven status
+     */
+    private void startAutomaticRefresh() {
+        ScheduledFuture<?> job = refreshJob;
+        if (job == null || job.isCancelled()) {
+            int period = config.refreshRate;
+            refreshJob = scheduler.scheduleWithFixedDelay(this::run, 0, period, TimeUnit.SECONDS);
+        }
+    }
+
+    private void run() {
+        updateOvenData(null);
+        for (Channel channel : getThing().getChannels()) {
+            updateChannel(channel.getUID().getId());
+        }
+    }
+
+    @Override
+    public void channelLinked(ChannelUID channelUID) {
+        if (!automaticRefreshing) {
+            logger.debug("Start automatic refreshing");
+            startAutomaticRefresh();
+            automaticRefreshing = true;
+        }
+        verifyLinkedChannel(channelUID.getId());
+        updateChannel(channelUID.getId());
+    }
+
+    @Override
+    public void channelUnlinked(ChannelUID channelUID) {
+        linkedChannels.remove(channelUID.getId());
+        if (linkedChannels.isEmpty()) {
+            automaticRefreshing = false;
+            stopScheduler();
+            logger.debug("Stop automatic refreshing");
+        }
+    }
+
+    private void updateChannel(String channelId) {
+        if (isLinked(channelId)) {
+            State state = null;
+            HaasSohnpelletstoveJsonDataDTO data = serviceCommunication.getOvenData();
+            if (data != null) {
+                switch (channelId) {
+                    case CHANNELISTEMP:
+                        state = new QuantityType<Temperature>(Double.valueOf(data.getisTemp()), SIUnits.CELSIUS);
+                        update(state, channelId);
+                        break;
+                    case CHANNELMODE:
+                        state = new StringType(data.getMode());
+                        update(state, channelId);
+                        break;
+                    case CHANNELPOWER:
+                        update(OnOffType.from(data.getPrg()), channelId);
+                        break;
+                    case CHANNELECOMODE:
+                        update(OnOffType.from(data.getEcoMode()), channelId);
+                        break;
+                    case CHANNELSPTEMP:
+                        state = new QuantityType<Temperature>(Double.valueOf(data.getspTemp()), SIUnits.CELSIUS);
+                        update(state, channelId);
+                        break;
+                    case CHANNELCLEANINGIN:
+                        String cleaning = data.getCleaningIn();
+                        double time = Double.parseDouble(cleaning);
+                        time = time / 60;
+                        DecimalFormat df = new DecimalFormat("0.00");
+                        state = new StringType(df.format(time));
+                        update(state, channelId);
+                        break;
+                    case CHANNELCONSUMPTION:
+                        state = new StringType(data.getConsumption());
+                        update(state, channelId);
+                        break;
+                    case CHANNELIGNITIONS:
+                        state = new StringType(data.getIgnitions());
+                        update(state, channelId);
+                        break;
+                    case CHANNELMAINTENANCEIN:
+                        state = new StringType(data.getMaintenanceIn());
+                        update(state, channelId);
+                        break;
+                    case CHANNELONTIME:
+                        state = new StringType(data.getOnTime());
+                        update(state, channelId);
+                        break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Updates the State of the given channel
+     *
+     * @param state
+     * @param channelId
+     */
+    private void update(@Nullable State state, String channelId) {
+        logger.debug("Update channel {} with state {}", channelId, (state == null) ? "null" : state.toString());
+
+        if (state != null) {
+            updateState(channelId, state);
+
+        } else {
+            updateState(channelId, UnDefType.NULL);
+        }
+    }
+}
diff --git a/bundles/org.openhab.binding.haassohnpelletstove/src/main/java/org/openhab/binding/haassohnpelletstove/internal/HaasSohnpelletstoveHandlerFactory.java b/bundles/org.openhab.binding.haassohnpelletstove/src/main/java/org/openhab/binding/haassohnpelletstove/internal/HaasSohnpelletstoveHandlerFactory.java
new file mode 100644 (file)
index 0000000..165b510
--- /dev/null
@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) 2010-2021 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.haassohnpelletstove.internal;
+
+import static org.openhab.binding.haassohnpelletstove.internal.HaasSohnpelletstoveBindingConstants.THING_TYPE_OVEN;
+
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.core.thing.Thing;
+import org.openhab.core.thing.ThingTypeUID;
+import org.openhab.core.thing.binding.BaseThingHandlerFactory;
+import org.openhab.core.thing.binding.ThingHandler;
+import org.openhab.core.thing.binding.ThingHandlerFactory;
+import org.osgi.service.component.annotations.Component;
+
+/**
+ * The {@link HaasSohnpelletstoveHandlerFactory} is responsible for creating things and thing
+ * handlers.
+ *
+ * @author Christian Feininger - Initial contribution
+ */
+@NonNullByDefault
+@Component(configurationPid = "binding.haassohnpelletstove", service = ThingHandlerFactory.class)
+public class HaasSohnpelletstoveHandlerFactory extends BaseThingHandlerFactory {
+
+    private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_OVEN);
+
+    @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 (THING_TYPE_OVEN.equals(thingTypeUID)) {
+            return new HaasSohnpelletstoveHandler(thing);
+        }
+        return null;
+    }
+}
diff --git a/bundles/org.openhab.binding.haassohnpelletstove/src/main/java/org/openhab/binding/haassohnpelletstove/internal/HaasSohnpelletstoveJSONCommunication.java b/bundles/org.openhab.binding.haassohnpelletstove/src/main/java/org/openhab/binding/haassohnpelletstove/internal/HaasSohnpelletstoveJSONCommunication.java
new file mode 100644 (file)
index 0000000..04c2059
--- /dev/null
@@ -0,0 +1,223 @@
+/**
+ * Copyright (c) 2010-2021 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.haassohnpelletstove.internal;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.Properties;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.core.io.net.http.HttpUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.Gson;
+
+/**
+ * This class handles the JSON communication with the Wifi Modul of the Stove
+ *
+ * @author Christian Feininger - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class HaasSohnpelletstoveJSONCommunication {
+
+    private final Logger logger = LoggerFactory.getLogger(HaasSohnpelletstoveJSONCommunication.class);
+    private HaasSohnpelletstoveConfiguration config;
+
+    private Gson gson;
+    private @Nullable String xhspin;
+    private @Nullable HaasSohnpelletstoveJsonDataDTO ovenData;
+
+    public HaasSohnpelletstoveJSONCommunication() {
+        gson = new Gson();
+        ovenData = new HaasSohnpelletstoveJsonDataDTO();
+        xhspin = "";
+        config = new HaasSohnpelletstoveConfiguration();
+    }
+
+    /**
+     * Refreshes the oven Connection with the internal oven token.
+     *
+     * @param message Message object to pass errors to the calling method.
+     * @param thingUID Thing UID for logging purposes
+     * @return true if no error occurred, false otherwise.
+     */
+    public boolean refreshOvenConnection(Helper message, String thingUID) {
+        if (config.hostIP == null || config.hostPIN == null) {
+            message.setStatusDescription("Error in configuration. Please recreate Thing.");
+            return false;
+        }
+        HaasSohnpelletstoveJsonDataDTO result = null;
+        boolean resultOk = false;
+        String error = "", errorDetail = "", statusDescr = "";
+        String urlStr = "http://" + config.hostIP + "/status.cgi";
+
+        String response = null;
+        try {
+            response = HttpUtil.executeUrl("GET", urlStr, 10000);
+            logger.debug("OvenData = {}", response);
+            result = gson.fromJson(response, HaasSohnpelletstoveJsonDataDTO.class);
+            resultOk = true;
+        } catch (IOException e) {
+            logger.debug("Error processiong Get request {}", urlStr);
+            statusDescr = "Timeout error with" + config.hostIP
+                    + ". Cannot find service on give IP. Please verify the IP-Address!";
+            errorDetail = e.getMessage();
+            resultOk = false;
+        } catch (Exception e) {
+            logger.debug("Unknwon Error: {}", e.getMessage());
+            errorDetail = e.getMessage();
+            resultOk = false;
+        }
+        if (resultOk) {
+            ovenData = result;
+            xhspin = getValidXHSPIN(ovenData);
+        } else {
+            logger.debug("Setting thing '{}' to OFFLINE: Error '{}': {}", thingUID, error, errorDetail);
+            ovenData = new HaasSohnpelletstoveJsonDataDTO();
+        }
+        message.setStatusDescription(statusDescr);
+        return resultOk;
+    }
+
+    /**
+     * Gets the status of the oven
+     *
+     * @return true if success or false in case of error
+     */
+    public boolean updateOvenData(@Nullable String postData, Helper helper, String thingUID) {
+        String statusDescr = "";
+        boolean resultOk = false;
+        String error = "", errorDetail = "";
+        if (config.hostIP == null || config.hostPIN == null) {
+            return false;
+        }
+        String urlStr = "http://" + config.hostIP + "/status.cgi";
+
+        // Run the HTTP POST request and get the JSON response from Oven
+        String response = null;
+
+        Properties httpHeader = new Properties();
+
+        if (postData != null) {
+            try {
+                InputStream targetStream = new ByteArrayInputStream(postData.getBytes("UTF-8"));
+                refreshOvenConnection(helper, thingUID);
+                httpHeader = createHeader(postData);
+                response = HttpUtil.executeUrl("POST", urlStr, httpHeader, targetStream, "application/json", 10000);
+                resultOk = true;
+                logger.debug("Execute POST request with content to {} with header: {}", urlStr, httpHeader.toString());
+            } catch (UnsupportedEncodingException e1) {
+                logger.debug("Wrong encoding found. Only UTF-8 is supported.");
+                statusDescr = "Encoding of oven is not supported. Only UTF-8 is supported.";
+                resultOk = false;
+            } catch (IOException e) {
+                logger.debug("Error processiong POST request {}", urlStr);
+                statusDescr = "Cannot execute command on Stove. Please verify connection and Thing Status";
+                resultOk = false;
+            }
+        } else {
+            try {
+                refreshOvenConnection(helper, thingUID);
+                httpHeader = createHeader(null);
+                response = HttpUtil.executeUrl("POST", urlStr, httpHeader, null, "", 10000);
+                resultOk = true;
+                logger.debug("Execute POST request to {} with header: {}", urlStr, httpHeader.toString());
+            } catch (IOException e) {
+                logger.debug("Error processiong POST request {}", e.getMessage());
+                String message = e.getMessage();
+                if (message != null && message.contains("Authentication challenge without WWW-Authenticate ")) {
+                    statusDescr = "Cannot connect to stove. Given PIN: " + config.hostPIN + " is incorrect!";
+                }
+                resultOk = false;
+            }
+        }
+        if (resultOk) {
+            logger.debug("OvenData = {}", response);
+            ovenData = gson.fromJson(response, HaasSohnpelletstoveJsonDataDTO.class);
+        } else {
+            logger.debug("Setting thing '{}' to OFFLINE: Error '{}': {}", thingUID, error, errorDetail);
+            ovenData = new HaasSohnpelletstoveJsonDataDTO();
+        }
+        helper.setStatusDescription(statusDescr);
+        return resultOk;
+    }
+
+    /**
+     * Creates the header for the Post Request
+     *
+     * @return The created Header Properties
+     * @throws UnsupportedEncodingException
+     */
+    private Properties createHeader(@Nullable String postData) throws UnsupportedEncodingException {
+        Properties httpHeader = new Properties();
+        httpHeader.setProperty("Host", config.hostIP);
+        httpHeader.setProperty("Accept", "*/*");
+        httpHeader.setProperty("Proxy-Connection", "keep-alive");
+        httpHeader.setProperty("X-BACKEND-IP", "https://app.haassohn.com");
+        httpHeader.setProperty("Accept-Language", "de-DE;q=1.0, en-DE;q=0.9");
+        httpHeader.setProperty("Accept-Encoding", "gzip;q=1.0, compress;q=0.5");
+        httpHeader.setProperty("token", "32 bytes");
+        httpHeader.setProperty("Content-Type", "application/json");
+        if (postData != null) {
+            int a = postData.getBytes("UTF-8").length;
+            httpHeader.setProperty(xhspin, Integer.toString(a));
+        }
+        httpHeader.setProperty("User-Agent", "ios");
+        httpHeader.setProperty("Connection", "keep-alive");
+        httpHeader.setProperty("X-HS-PIN", xhspin);
+        return httpHeader;
+    }
+
+    /**
+     * Generate the valid encrypted string to communicate with the oven.
+     *
+     * @param ovenData
+     * @return
+     */
+    private @Nullable String getValidXHSPIN(@Nullable HaasSohnpelletstoveJsonDataDTO ovenData) {
+        if (ovenData != null && config.hostPIN != null) {
+            String nonce = ovenData.getNonce();
+            String hostPIN = config.hostPIN;
+            String ePin = MD5Utils.getMD5String(hostPIN);
+            return MD5Utils.getMD5String(nonce + ePin);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Set the config for service to communicate
+     *
+     * @param config2
+     */
+    public void setConfig(@Nullable HaasSohnpelletstoveConfiguration config2) {
+        if (config2 != null) {
+            this.config = config2;
+        }
+    }
+
+    /**
+     * Returns the actual stored Oven Data
+     *
+     * @return
+     */
+    @Nullable
+    public HaasSohnpelletstoveJsonDataDTO getOvenData() {
+        return this.ovenData;
+    }
+}
diff --git a/bundles/org.openhab.binding.haassohnpelletstove/src/main/java/org/openhab/binding/haassohnpelletstove/internal/HaasSohnpelletstoveJsonDataDTO.java b/bundles/org.openhab.binding.haassohnpelletstove/src/main/java/org/openhab/binding/haassohnpelletstove/internal/HaasSohnpelletstoveJsonDataDTO.java
new file mode 100644 (file)
index 0000000..17c45de
--- /dev/null
@@ -0,0 +1,152 @@
+/**
+ * Copyright (c) 2010-2021 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.haassohnpelletstove.internal;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * The {@link HaasSohnpelletstoveJsonDataDTO} is the Java class used to map the JSON
+ * response to a Oven request.
+ *
+ * @author Christian Feininger - Initial contribution
+ */
+public class HaasSohnpelletstoveJsonDataDTO {
+    metadata meta = new metadata();
+    boolean prg;
+    boolean wprg;
+    String mode = "";
+    @SerializedName("sp_temp")
+    String spTemp = "";
+    @SerializedName("is_temp")
+    String isTemp = "";
+    @SerializedName("ht_char")
+    String htChar = "";
+    @SerializedName("weekprogram")
+    private wprogram[] weekprogram;
+    @SerializedName("error")
+    private err[] error;
+    @SerializedName("eco_mode")
+    boolean ecoMode;
+    boolean pgi;
+    String ignitions = "";
+    @SerializedName("on_time")
+    String onTime = "";
+    String consumption = "";
+    @SerializedName("maintenance_in")
+    String maintenanceIn = "";
+    @SerializedName("cleaning_in")
+    String cleaningIn = "";
+
+    /***
+     * Get the nonce
+     *
+     * @return nonce
+     */
+    public String getNonce() {
+        return this.meta.getNonce();
+    }
+
+    /**
+     * Returns the is Temperature of the Oven
+     *
+     * @return
+     */
+    public String getisTemp() {
+        return isTemp;
+    }
+
+    public boolean getEcoMode() {
+        return ecoMode;
+    }
+
+    public String getIgnitions() {
+        return ignitions;
+    }
+
+    public String getOnTime() {
+        return onTime;
+    }
+
+    public String getConsumption() {
+        return consumption;
+    }
+
+    public String getMaintenanceIn() {
+        return maintenanceIn;
+    }
+
+    public String getCleaningIn() {
+        return cleaningIn;
+    }
+
+    /***
+     * JSON response
+     *
+     * @return JSON response as object
+     */
+    public HaasSohnpelletstoveJsonDataDTO getResponse() {
+        return this;
+    }
+
+    public class metadata {
+        @SerializedName("sw_version")
+        String swVersion = "";
+        @SerializedName("hw_version")
+        String hwVersion = "";
+        @SerializedName("bootl_version")
+        String bootlVersion = "";
+        @SerializedName("wifi_sw_version")
+        String wifiSWVersion = "";
+        @SerializedName("wifi_bootl_version")
+        String wifiBootlVersion = "";
+        String sn = "";
+        String typ = "";
+        String language = "";
+        String nonce = "";
+        @SerializedName("eco_editable")
+        String ecoEditable = "";
+        String ts = "";
+        String ean = "";
+        boolean rau;
+        @SerializedName("wlan_features")
+        private String[] wlan_features;
+
+        public String getNonce() {
+            return nonce;
+        }
+    }
+
+    public class err {
+        String time = "";
+        String nr = "";
+    }
+
+    public class wprogram {
+        String day = "";
+        String begin = "";
+        String end = "";
+        String temp = "";
+    }
+
+    public String getMode() {
+        return mode;
+    }
+
+    public String getspTemp() {
+        return spTemp;
+    }
+
+    public boolean getPrg() {
+        return prg;
+    }
+}
diff --git a/bundles/org.openhab.binding.haassohnpelletstove/src/main/java/org/openhab/binding/haassohnpelletstove/internal/Helper.java b/bundles/org.openhab.binding.haassohnpelletstove/src/main/java/org/openhab/binding/haassohnpelletstove/internal/Helper.java
new file mode 100644 (file)
index 0000000..5f279dc
--- /dev/null
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 2010-2021 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.haassohnpelletstove.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * The {@link Helper} is a Helper class to overcome Call by value for a Status Description.
+ *
+ *
+ * @author Christian Feininger - Initial contribution
+ */
+@NonNullByDefault
+public class Helper {
+
+    private String statusDescription = "";
+
+    /***
+     * Gets the Status Description
+     *
+     * @return
+     */
+    public String getStatusDesription() {
+        return statusDescription;
+    }
+
+    /***
+     * Sets the Status Description
+     *
+     * @param status
+     */
+    public void setStatusDescription(@Nullable String status) {
+        if (status != null) {
+            statusDescription = statusDescription + "\n" + status;
+        }
+    }
+}
diff --git a/bundles/org.openhab.binding.haassohnpelletstove/src/main/java/org/openhab/binding/haassohnpelletstove/internal/MD5Utils.java b/bundles/org.openhab.binding.haassohnpelletstove/src/main/java/org/openhab/binding/haassohnpelletstove/internal/MD5Utils.java
new file mode 100644 (file)
index 0000000..e1d1da0
--- /dev/null
@@ -0,0 +1,66 @@
+/**
+ * Copyright (c) 2010-2021 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.haassohnpelletstove.internal;
+
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * The {@link MD5Utils} is responsible for generating the MD5 hash
+ *
+ *
+ * @author Christian Feininger - Initial contribution
+ */
+@NonNullByDefault
+public class MD5Utils {
+
+    private static final Charset UTF_8 = StandardCharsets.UTF_8;
+
+    private static byte[] digest(byte[] input) {
+        MessageDigest md;
+        try {
+            md = MessageDigest.getInstance("MD5");
+        } catch (NoSuchAlgorithmException e) {
+            throw new IllegalArgumentException(e);
+        }
+        byte[] result = md.digest(input);
+        return result;
+    }
+
+    private static String bytesToHex(byte[] bytes) {
+        StringBuilder sb = new StringBuilder();
+        for (byte b : bytes) {
+            sb.append(String.format("%02x", b));
+        }
+        return sb.toString();
+    }
+
+    /***
+     * Returns an encrypted MD5 string
+     *
+     * @param input nonce as input
+     * @return Encrypted String
+     */
+    public static String getMD5String(@Nullable String input) {
+        if (input != null) {
+            byte[] md5InBytes = MD5Utils.digest(input.getBytes(UTF_8));
+            return bytesToHex(md5InBytes);
+        }
+        return "";
+    }
+}
diff --git a/bundles/org.openhab.binding.haassohnpelletstove/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.openhab.binding.haassohnpelletstove/src/main/resources/OH-INF/binding/binding.xml
new file mode 100644 (file)
index 0000000..8dd3fe2
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<binding:binding id="haassohnpelletstove" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
+       xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
+
+       <name>Haas and Sohn Pelletstove Binding</name>
+       <description>This binding communicates with Haas and Sohn Pelletstoves through the optional WIFI module. It allows to
+               power the stove on and off and receives different operation information.</description>
+
+</binding:binding>
diff --git a/bundles/org.openhab.binding.haassohnpelletstove/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.haassohnpelletstove/src/main/resources/OH-INF/thing/thing-types.xml
new file mode 100644 (file)
index 0000000..dc0d1a7
--- /dev/null
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<thing:thing-descriptions bindingId="haassohnpelletstove"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
+       xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
+
+       <!-- Haas Sohn Thing Type -->
+       <thing-type id="oven">
+               <label>Haas+Sohn Oven</label>
+               <description>The binding for Haas and Sohn Pelletstove communicates with a Haas and Sohn Pelletstove through the
+                       optional
+                       WLAN-Modul. More information can be found here: https://www.haassohn.com/de/ihr-plus/WLAN-Funktion. It allows
+                       to power on/off the stove as well as receiving different operation information about the stove.</description>
+
+
+               <channels>
+                       <channel id="channelIsTemp" typeId="isTemp"/>
+                       <channel id="channelMode" typeId="mode"/>
+                       <channel id="channelSpTemp" typeId="spTemp"/>
+                       <channel id="power" typeId="power"/>
+                       <channel id="channelEcoMode" typeId="ecoMode"/>
+                       <channel id="channelIgnitions" typeId="ignitions"/>
+                       <channel id="channelMaintenanceIn" typeId="maintenanceIn"/>
+                       <channel id="channelCleaningIn" typeId="cleaningIn"/>
+                       <channel id="channelConsumption" typeId="consumption"/>
+                       <channel id="channelOnTime" typeId="onTime"/>
+               </channels>
+
+               <config-description>
+                       <parameter name="hostIP" type="text" required="true">
+                               <label>IP Address</label>
+                               <description>Please add the IP Address of the WIFI Module of the Haas and Sohn oven here</description>
+                               <context>network-address</context>
+                       </parameter>
+                       <parameter name="hostPIN" type="text" required="true" pattern="[0-9]{4}">
+                               <label>PIN</label>
+                               <description>Please add the PIN of your oven here. You can find it in the Menu directly in your oven.</description>
+                       </parameter>
+                       <parameter name="refreshRate" type="integer" unit="s" min="0" max="1000">
+                               <label>Refresh Rate</label>
+                               <description>How often the Pellet Stove should schedule a refresh after a channel is linked to an item. Temperature
+                                       data will be refreshed according this set time in seconds. Valid input is 0 - 999.
+                               </description>
+                               <advanced>true</advanced>
+                               <default>30</default>
+                       </parameter>
+               </config-description>
+
+       </thing-type>
+       <channel-type id="isTemp">
+               <item-type>Number:Temperature</item-type>
+               <label>Is Temperature Stove</label>
+               <description>Receives the is temperature of the stove as number:temperature</description>
+               <state readOnly="true"/>
+       </channel-type>
+
+       <channel-type id="mode">
+               <item-type>String</item-type>
+               <label>Mode Stove</label>
+               <description>Receives the actual mode of the stove as string</description>
+               <state readOnly="true"/>
+       </channel-type>
+
+       <channel-type id="spTemp">
+               <item-type>Number:Temperature</item-type>
+               <label>Set Temperature Stove</label>
+               <description>Set the target temperature of the stove as number:temperature</description>
+       </channel-type>
+
+       <channel-type id="power">
+               <item-type>Switch</item-type>
+               <label>On/Off Stove</label>
+               <description>To turn the stove on/off as switch</description>
+       </channel-type>
+
+       <channel-type id="ecoMode">
+               <item-type>Switch</item-type>
+               <label>On/Off Eco Mode</label>
+               <description>To turn the Eco Mode on/off for the stove as switch</description>
+       </channel-type>
+
+       <channel-type id="ignitions">
+               <item-type>Number</item-type>
+               <label>Ignitions Stove</label>
+               <description>Receives the total amount of ignitions of the stove as string</description>
+               <state readOnly="true"/>
+       </channel-type>
+
+       <channel-type id="maintenanceIn">
+               <item-type>Number:Mass</item-type>
+               <label>Next Maintenance</label>
+               <description>Provides a pellet forecast when the stove need to be maintained next in kilogram as number:mass</description>
+               <state readOnly="true"/>
+       </channel-type>
+
+       <channel-type id="cleaningIn">
+               <item-type>String</item-type>
+               <label>Next Cleaning Window</label>
+               <description>Provides a time forecast in hours:minutes when the stove need to be cleaned next as String</description>
+               <state readOnly="true"/>
+       </channel-type>
+
+       <channel-type id="consumption">
+               <item-type>Number:Mass</item-type>
+               <label>Total Consumption Stove</label>
+               <description>Provides the information about the total consumption of pellets of the stove as number:mass</description>
+               <state readOnly="true"/>
+       </channel-type>
+
+       <channel-type id="onTime">
+               <item-type>Number</item-type>
+               <label>Operation Hours Stove</label>
+               <description>Provides the information of the operating hours of stove as number</description>
+               <state readOnly="true"/>
+       </channel-type>
+
+</thing:thing-descriptions>
index bf2fe504d7d53e308a70114c24a223d8c0499411..f3395fa01cc2900f987765c91c4ec1d7790ab650 100644 (file)
     <module>org.openhab.binding.gpstracker</module>
     <module>org.openhab.binding.gree</module>
     <module>org.openhab.binding.groheondus</module>
+    <module>org.openhab.binding.haassohnpelletstove</module>
     <module>org.openhab.binding.harmonyhub</module>
     <module>org.openhab.binding.haywardomnilogic</module>
     <module>org.openhab.binding.hdanywhere</module>