diff --git a/CODEOWNERS b/CODEOWNERS index 69a36f516e7a3..f2e185b3a7975 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -128,6 +128,7 @@ /bundles/org.openhab.binding.minecraft/ @ibaton /bundles/org.openhab.binding.modbus/ @ssalonen /bundles/org.openhab.binding.modbus.sunspec/ @mrbig +/bundles/org.openhab.binding.modbus.stiebeleltron/ @pail23 /bundles/org.openhab.binding.mqtt/ @davidgraeff /bundles/org.openhab.binding.mqtt.generic/ @davidgraeff /bundles/org.openhab.binding.mqtt.homeassistant/ @davidgraeff diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml index a51e78c240322..5778ce8181597 100644 --- a/bom/openhab-addons/pom.xml +++ b/bom/openhab-addons/pom.xml @@ -629,6 +629,11 @@ org.openhab.binding.modbus ${project.version} + + org.openhab.addons.bundles + org.openhab.binding.modbus.stiebeleltron + ${project.version} + org.openhab.addons.bundles org.openhab.binding.mqtt diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/.classpath b/bundles/org.openhab.binding.modbus.stiebeleltron/.classpath new file mode 100644 index 0000000000000..39abf1c5e9102 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/.classpath @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/.project b/bundles/org.openhab.binding.modbus.stiebeleltron/.project new file mode 100644 index 0000000000000..b285157a2c7f4 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/.project @@ -0,0 +1,23 @@ + + + org.openhab.binding.modbus.stiebeleltron + + + + + + 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.modbus.stiebeleltron/NOTICE b/bundles/org.openhab.binding.modbus.stiebeleltron/NOTICE new file mode 100644 index 0000000000000..38d625e349232 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/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/openhab-addons diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/README.md b/bundles/org.openhab.binding.modbus.stiebeleltron/README.md new file mode 100644 index 0000000000000..c58a896c18640 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/README.md @@ -0,0 +1,206 @@ +# Stiebel Eltron ISG Binding + +This extension adds support for the Stiebel Eltron modbus protocol. + +An Internet Service Gateway (ISG) with an installed modbus extension is required in order to run this binding. +In case the modbus extension is not yet installed on the ISG, the ISG Updater Tool for the update can be found here: https://www.stiebel-eltron.de/de/home/produkte-loesungen/erneuerbare_energien/regelung_energiemanagement/internet_servicegateway/isg_web/downloads.html + + + + +## Supported Things + +This bundle adds the following thing types to the Modbus binding. +Note, that the things will show up under the Modbus binding. + +| Thing | ThingTypeID | Description | +| ------------------ | ----------- | -------------------------------------------------- | +| Stiebel Eltron ISG | heatpump | A stiebel eltron heat pump connected through a ISG | + +## Discovery + +This extension does not support autodiscovery. The things need to be added manually. + +A typical bridge configuration would look like this: + +``` +Bridge modbus:tcp:bridge [ host="10.0.0.2", port=502, id=1 ] +``` + + +## Thing Configuration + +You need first to set up a TCP Modbus bridge according to the Modbus documentation. +Things in this extension will use the selected bridge to connect to the device. + +The following parameters are valid for all thing types: + +| Parameter | Type | Required | Default if omitted | Description | +| --------- | ------- | -------- | ------------------ | -------------------------------------------------------------------------- | +| refresh | integer | no | 5 | Poll interval in seconds. Increase this if you encounter connection errors | +| maxTries | integer | no | 3 | Number of retries when before giving up reading from this thing. | + +## Channels + +Channels are grouped into channel groups. + +### System State Group + +This group contains general operational information about the heat pump. + +| Channel ID | Item Type | Read only | Description | +| ---------------- | --------- | --------- | ------------------------------------------------------------- | +| is-heating | Contact | true | OPEN in case the heat pump is currently in heating mode | +| is-heating-water | Contact | true | OPEN in case the heat pump is currently in heating water mode | +| is-cooling | Contact | true | OPEN in case the heat pump is currently in cooling mode | +| is-pumping | Contact | true | OPEN in case the heat pump is currently in pumping mode | +| is-summer | Contact | true | OPEN in case the heat pump is currently in summer mode | + +### System Parameters Group + +This group contains system paramters of the heat pump. + +| Channel ID | Item Type | Read only | Description | +| --------------------------- | ------------------ | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | +| operation-mode | Number | false | The current operation mode of the heat pump (1=ready mode, 2=program mode, 3=comfort mode, 4=eco mode, 5=heating water mode, 0=emergency mode) | +| comfort-temperature-heating | Number:Temperature | false | The current heating comfort temperature | +| eco-temperature-heating | Number:Temperature | false | The current heating eco temperature | +| comfort-temperature-water | Number:Temperature | false | The current water comfort temperature | +| eco-temperature-water | Number:Temperature | false | The current water eco temperature | + +### System Information Group + +This group contains general operational information about the device. + +| Channel ID | Item Type | Read only | Description | +| -------------------------- | -------------------- | --------- | ----------------------------------------------------- | +| fek-temperature | Number:Temperature | true | The current temperature measured by the FEK | +| fek-temperature-setpoint | Number:Temperature | true | The current set point of the FEK temperature | +| fek-humidity | Number:Dimensionless | true | The current humidity measured by the FEK | +| fek-dewpoint | Number:Temperature | true | The current dew point temperature measured by the FEK | +| outdoor-temperature | Number:Temperature | true | The current outdoor temperature | +| hk1-temperature | Number:Temperature | true | The current temperature of the HK1 | +| hk1-temperature-setpoint | Number:Temperature | true | The current temperature set point of the HK1 | +| supply-temperature | Number:Temperature | true | The current supply temperature | +| return-temperature | Number:Temperature | true | The current return measured | +| source-temperature | Number:Temperature | true | The current sourcetemperature | +| water-temperature | Number:Temperature | true | The current water temperature | +| water-temperature-setpoint | Number:Temperature | true | The current water temperature set point | + +### Energy Information Group + +This group contains about the energy consumption and delivery of the heat pump. + +| Channel ID | Item Type | Read only | Description | +| ----------------------- | ------------- | --------- | ------------------------------------------------ | +| production-heat-today | Number:Energy | true | The heat quantity delivered today | +| production-heat-total | Number:Energy | true | The heat quantity delivered in total | +| production-water-today | Number:Energy | true | The water heat quantity delivered today | +| production-water-total | Number:Energy | true | The water heat quantity delivered in total | +| consumption-heat-today | Number:Energy | true | The power consumption for heating today | +| consumption-heat-total | Number:Energy | true | The power consumption for heating in total | +| consumption-water-today | Number:Energy | true | The power consumption for water heating today | +| consumption-water-total | Number:Energy | true | The power consumption for water heating in total | + + + +## Full Example + +### Thing Configuration + +``` +Bridge modbus:tcp:bridge [ host="hostname|ip", port=502, id=1] +Thing modbus:heatpump:stiebelEltron "StiebelEltron" (modbus:tcp:modbusbridge) [ ] +``` + + +### Item Configuration + +``` +Number:Temperature stiebel_eltron_temperature_ffk "Temperature FFK [%.1f °C]" { channel="modbus:heatpump:stiebelEltron:systemInformation#fek-temperature" } +Number:Temperature stiebel_eltron_setpoint_ffk "Set point FFK [%.1f °C]" { channel="modbus:heatpump:stiebelEltron:systemInformation#fek-temperature-setpoint" } +Number:Dimensionless stiebel_eltron_humidity_ffk "Humidity FFK [%.1f %%]" { channel="modbus:heatpump:stiebelEltron:systemInformation#fek-humidity" } +Number:Temperature stiebel_eltron_dewpoint_ffk "Dew point FFK [%.1f °C]" { channel="modbus:heatpump:stiebelEltron:systemInformation#fek-dewpoint" } + +Number:Temperature stiebel_eltron_outdoor_temp "Outdoor temperature [%.1f °C]" { channel="modbus:heatpump:stiebelEltron:systemInformation#outdoor-temperature" } +Number:Temperature stiebel_eltron_temp_hk1 "Temperature HK1 [%.1f °C]" { channel="modbus:heatpump:stiebelEltron:systemInformation#hk1-temperature" } +Number:Temperature stiebel_eltron_setpoint_hk1 "Set point HK1 [%.1f °C]" { channel="modbus:heatpump:stiebelEltron:systemInformation#hk1-temperature-setpoint" } +Number:Temperature stiebel_eltron_temp_water "Water temperature [%.1f °C]" { channel="modbus:heatpump:stiebelEltron:systemInformation#water-temperature" } +Number:Temperature stiebel_eltron_setpoint_water "Water setpoint [%.1f °C]" { channel="modbus:heatpump:stiebelEltron:systemInformation#water-temperature-setpoint" } +Number:Temperature stiebel_eltron_source_temp "Source temperature [%.1f °C]" { channel="modbus:heatpump:stiebelEltron:systemInformation#source-temperature" } +Number:Temperature stiebel_eltron_vorlauf_temp "Supply tempertature [%.1f °C]" { channel="modbus:heatpump:stiebelEltron:systemInformation#supply-temperature" } +Number:Temperature stiebel_eltron_ruecklauf_temp "Return temperature [%.1f °C]" { channel="modbus:heatpump:stiebelEltron:systemInformation#return-temperature" } + +Number stiebel_eltron_heating_comfort_temp "Heating Comfort Temperature [%.1f °C]" { channel="modbus:heatpump:stiebelEltron:systemParameter#comfort-temperature-heating" } +Number stiebel_eltron_heating_eco_temp "Heating Eco Temperature [%.1f °C]" { channel="modbus:heatpump:stiebelEltron:systemParameter#eco-temperature-heating" } +Number stiebel_eltron_water_comfort_temp "Water Comfort Temperature [%.1f °C]" { channel="modbus:heatpump:stiebelEltron:systemParameter#comfort-temperature-water" } +Number stiebel_eltron_water_eco_temp "Water Eco Temperature [%.1f °C]" { channel="modbus:heatpump:stiebelEltron:systemParameter#eco-temperature-water" } +Number stiebel_eltron_operation_mode "Operation Mode" { channel="modbus:heatpump:stiebelEltron:systemParameter#operation-mode" } + +Contact stiebel_eltron_mode_pump "Pump [%d]" { channel="modbus:heatpump:stiebelEltron:systemState#is-pumping" } +Contact stiebel_eltron_mode_heating "Heating [%d]" { channel="modbus:heatpump:stiebelEltron:systemState#is-heating" } +Contact stiebel_eltron_mode_water "Heating Water [%d]" { channel="modbus:heatpump:stiebelEltron:systemState#is-heating-water" } +Contact stiebel_eltron_mode_cooling "Cooling [%d]" { channel="modbus:heatpump:stiebelEltron:systemState#is-cooling" } +Contact stiebel_eltron_mode_summer "Summer Mode [%d]" { channel="modbus:heatpump:stiebelEltron:systemState#is-summer" } + + +Number:Energy stiebel_eltron_production_heat_today "Heat quantity today [%.0f kWh]" { channel="modbus:heatpump:stiebelEltron:energyInformation#production_heat_today" } +Number:Energy stiebel_eltron_production_heat_total "Heat quantity total [%.3f MWh]" {channel="modbus:heatpump:stiebelEltron:energyInformation#production_heat_total"} +Number:Energy stiebel_eltron_production_water_today "Water heat quantity today [%.0f kWh]" { channel="modbus:heatpump:stiebelEltron:energyInformation#production_water_today" } +Number:Energy stiebel_eltron_production_water_total "Water heat quantity total [%.3f MWh]" {channel="modbus:heatpump:stiebelEltron:energyInformation#production_water_total"} +Number:Energy stiebel_eltron_consumption_heat_total "Heating power consumption total [%.3f MWh]" {channel="modbus:heatpump:stiebelEltron:energyInformation#consumption_heat_total"} +Number:Energy stiebel_eltron_consumption_heat_today "Heating power consumption today [%.0f kWh]" { channel="modbus:heatpump:stiebelEltron:energyInformation#consumption_heat_today" } +Number:Energy stiebel_eltron_consumption_water_today "Water heating power consumption today [%.0f kWh]" { channel="modbus:heatpump:stiebelEltron:energyInformation#consumption_water_today" } +Number:Energy stiebel_eltron_consumption_water_total "Water heating power consumption total [%.3f MWh]" {channel="modbus:heatpump:stiebelEltron:energyInformation#consumption_water_total"} + + +``` + +### Sitemap Configuration + +``` + Text label="Heat pumpt" icon="temperature" { + Frame label="Optation Mode" { + Default item=stiebel_eltron_mode_pump + Default item=stiebel_eltron_mode_heating + Default item=stiebel_eltron_mode_water + Default item=stiebel_eltron_mode_cooling + Default item=stiebel_eltron_mode_summer + } + Frame label= "State" { + Default item=stiebel_eltron_operation_mode icon="settings" + Default item=stiebel_eltron_outdoor_temp icon="temperature" + Default item=stiebel_eltron_temp_hk1 icon="temperature" + Default item=stiebel_eltron_setpoint_hk1 icon="temperature" + Default item=stiebel_eltron_vorlauf_temp icon="temperature" + Default item=stiebel_eltron_ruecklauf_temp icon="temperature" + Default item=stiebel_eltron_temp_water icon="temperature" + Default item=stiebel_eltron_setpoint_water icon="temperature" + Default item=stiebel_eltron_temperature_ffk icon="temperature" + Default item=stiebel_eltron_setpoint_ffk icon="temperature" + Default item=stiebel_eltron_humidity_ffk icon="humidity" + Default item=stiebel_eltron_dewpoint_ffk icon="temperature" + Default item=stiebel_eltron_source_temp icon="temperature" + } + Frame label="Paramters" { + Setpoint item=stiebel_eltron_heating_comfort_temp icon="temperature" step=1 minValue=5 maxValue=30 + Setpoint item=stiebel_eltron_heating_eco_temp icon="temperature" step=1 minValue=5 maxValue=30 + Setpoint item=stiebel_eltron_water_comfort_temp icon="temperature" step=1 minValue=10 maxValue=60 + Setpoint item=stiebel_eltron_water_eco_temp icon="temperature" step=1 minValue=10 maxValue=60 + } + Frame label="Energy consumption" { + Default item=stiebel_eltron_consumption_heat_today icon="energy" + Default item=stiebel_eltron_consumption_heat_total icon="energy" + Default item=stiebel_eltron_consumption_water_today icon="energy" + Default item=stiebel_eltron_consumption_water_total icon="energy" + } + Frame label="Heat quantity" { + Default item=stiebel_eltron_production_heat_today icon="radiator" + Default item=stiebel_eltron_production_heat_total icon="radiator" + Default item=stiebel_eltron_production_water_today icon="water" + Default item=stiebel_eltron_production_water_total icon="water" + } + + } + +``` diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/pom.xml b/bundles/org.openhab.binding.modbus.stiebeleltron/pom.xml new file mode 100644 index 0000000000000..4a1805500df35 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/pom.xml @@ -0,0 +1,32 @@ + + + + 4.0.0 + + + org.openhab.addons.bundles + org.openhab.addons.reactor.bundles + 2.5.9-SNAPSHOT + + + org.openhab.binding.modbus.stiebeleltron + + openHAB Add-ons :: Bundles :: StiebelEltron Bundle + + + + org.openhab.addons.bundles + org.openhab.binding.modbus + ${project.version} + provided + + + org.openhab.addons.bundles + org.openhab.io.transport.modbus + ${project.version} + provided + + + + diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/feature/feature.xml b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/feature/feature.xml new file mode 100644 index 0000000000000..5e1f17a38ce85 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/feature/feature.xml @@ -0,0 +1,11 @@ + + + file:${basedirRoot}/bundles/org.openhab.io.transport.modbus/target/feature/feature.xml + + + openhab-runtime-base + openhab-transport-modbus + mvn:org.openhab.addons.bundles/org.openhab.binding.modbus/${project.version} + mvn:org.openhab.addons.bundles/org.openhab.binding.modbus.stiebeleltron/${project.version} + + diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/StiebelEltronBindingConstants.java b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/StiebelEltronBindingConstants.java new file mode 100644 index 0000000000000..3a40ecb48bdfc --- /dev/null +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/StiebelEltronBindingConstants.java @@ -0,0 +1,73 @@ +/** + * Copyright (c) 2010-2020 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.modbus.stiebeleltron.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.smarthome.core.thing.ThingTypeUID; +import org.openhab.binding.modbus.ModbusBindingConstants; + +/** + * The {@link Modbus.StiebelEltronBindingConstants} class defines common + * constants, which are used across the whole binding. + * + * @author Paul Frank - Initial contribution + */ +@NonNullByDefault +public class StiebelEltronBindingConstants { + + private static final String BINDING_ID = ModbusBindingConstants.BINDING_ID; + + // List of all Thing Type UIDs + public static final ThingTypeUID THING_TYPE_HEATPUMP = new ThingTypeUID(BINDING_ID, "heatpump"); + + // Channel group ids + public static final String GROUP_SYSTEM_STATE = "systemState"; + public static final String GROUP_SYSTEM_PARAMETER = "systemParameter"; + public static final String GROUP_SYSTEM_INFO = "systemInformation"; + public static final String GROUP_ENERGY_INFO = "energyInformation"; + + // List of all Channel ids in device information group + public static final String CHANNEL_FEK_TEMPERATURE = "fek-temperature"; + public static final String CHANNEL_FEK_TEMPERATURE_SETPOINT = "fek-temperature-setpoint"; + public static final String CHANNEL_FEK_HUMIDITY = "fek-humidity"; + public static final String CHANNEL_FEK_DEWPOINT = "fek-dewpoint"; + public static final String CHANNEL_OUTDOOR_TEMPERATURE = "outdoor-temperature"; + public static final String CHANNEL_HK1_TEMPERATURE = "hk1-temperature"; + public static final String CHANNEL_HK1_TEMPERATURE_SETPOINT = "hk1-temperature-setpoint"; + public static final String CHANNEL_SUPPLY_TEMPERATURE = "supply-temperature"; + public static final String CHANNEL_RETURN_TEMPERATURE = "return-temperature"; + public static final String CHANNEL_SOURCE_TEMPERATURE = "source-temperature"; + public static final String CHANNEL_WATER_TEMPERATURE = "water-temperature"; + public static final String CHANNEL_WATER_TEMPERATURE_SETPOINT = "water-temperature-setpoint"; + + public static final String CHANNEL_PRODUCTION_HEAT_TODAY = "production-heat-today"; + public static final String CHANNEL_PRODUCTION_HEAT_TOTAL = "production-heat-total"; + public static final String CHANNEL_PRODUCTION_WATER_TODAY = "production-water-today"; + public static final String CHANNEL_PRODUCTION_WATER_TOTAL = "production-water-total"; + public static final String CHANNEL_CONSUMPTION_HEAT_TODAY = "consumption-heat-today"; + public static final String CHANNEL_CONSUMPTION_HEAT_TOTAL = "consumption-heat-total"; + public static final String CHANNEL_CONSUMPTION_WATER_TODAY = "consumption-water-today"; + public static final String CHANNEL_CONSUMPTION_WATER_TOTAL = "consumption-water-total"; + + public static final String CHANNEL_IS_HEATING = "is-heating"; + public static final String CHANNEL_IS_HEATING_WATER = "is-heating-water"; + public static final String CHANNEL_IS_COOLING = "is-cooling"; + public static final String CHANNEL_IS_PUMPING = "is-pumping"; + public static final String CHANNEL_IS_SUMMER = "is-summer"; + + public static final String CHANNEL_OPERATION_MODE = "operation-mode"; + public static final String CHANNEL_COMFORT_TEMPERATURE_HEATING = "comfort-temperature-heating"; + public static final String CHANNEL_ECO_TEMPERATURE_HEATING = "eco-temperature-heating"; + public static final String CHANNEL_COMFORT_TEMPERATURE_WATER = "comfort-temperature-water"; + public static final String CHANNEL_ECO_TEMPERATURE_WATER = "eco-temperature-water"; +} diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/StiebelEltronConfiguration.java b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/StiebelEltronConfiguration.java new file mode 100644 index 0000000000000..e86e763cbc4d8 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/StiebelEltronConfiguration.java @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2010-2020 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.modbus.stiebeleltron.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link Modbus.StiebelEltronConfiguration} class contains fields mapping + * thing configuration parameters. + * + * @author Paul Frank - Initial contribution + */ +@NonNullByDefault +public class StiebelEltronConfiguration { + /** + * Refresh interval in seconds + */ + private long refresh; + + private int maxTries = 3;// backwards compatibility and tests + + /** + * Gets refresh period in milliseconds + */ + public long getRefreshMillis() { + return refresh * 1000; + } + + public int getMaxTries() { + return maxTries; + } + + public void setMaxTries(int maxTries) { + this.maxTries = maxTries; + } +} diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/StiebelEltronHandlerFactory.java b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/StiebelEltronHandlerFactory.java new file mode 100644 index 0000000000000..0b150747ceecd --- /dev/null +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/StiebelEltronHandlerFactory.java @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2010-2020 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.modbus.stiebeleltron.internal; + +import static org.openhab.binding.modbus.stiebeleltron.internal.StiebelEltronBindingConstants.THING_TYPE_HEATPUMP; + +import java.util.Collections; +import java.util.Set; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +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.modbus.stiebeleltron.internal.handler.StiebelEltronHandler; +import org.osgi.service.component.annotations.Component; + +/** + * The {@link Modbus.StiebelEltronHandlerFactory} is responsible for creating things and thing + * handlers. + * + * @author Paul Frank - Initial contribution + */ +@NonNullByDefault +@Component(configurationPid = "binding.stiebeleltron", service = ThingHandlerFactory.class) +public class StiebelEltronHandlerFactory extends BaseThingHandlerFactory { + + private static final Set SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_HEATPUMP); + + @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_HEATPUMP.equals(thingTypeUID)) { + return new StiebelEltronHandler(thing); + } + + return null; + } +} diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/dto/EnergyBlock.java b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/dto/EnergyBlock.java new file mode 100644 index 0000000000000..d23fd243147bd --- /dev/null +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/dto/EnergyBlock.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2010-2020 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.modbus.stiebeleltron.internal.dto; + +/** + * Dto class for the Energy Block + * + * @author Paul Frank - Initial contribution + * + */ +public class EnergyBlock { + + public int productionHeatToday; + public int productionHeatTotalLow; + public int productionHeatTotalHigh; + public int productionWaterToday; + public int productionWaterTotalLow; + public int productionWaterTotalHigh; + + public int consumptionHeatToday; + public int consumptionHeatTotalLow; + public int consumptionHeatTotalHigh; + public int consumptionWaterToday; + public int consumptionWaterTotalLow; + public int consumptionWaterTotalHigh; +} diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/dto/SystemInformationBlock.java b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/dto/SystemInformationBlock.java new file mode 100644 index 0000000000000..14a7dbee5b53a --- /dev/null +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/dto/SystemInformationBlock.java @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2010-2020 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.modbus.stiebeleltron.internal.dto; + +/** + * Dto class for the System Information Block + * + * @author Paul Frank - Initial contribution + * + */ +public class SystemInformationBlock { + + public short temperatureFek; + public short temperatureFekSetPoint; + public short humidityFek; + public short dewpointFek; + public short temperatureOutdoor; + public short temperatureHk1; + public short temperatureHk1SetPoint; + public short temperatureSupply; + public short temperatureReturn; + public short temperatureSource; + public short temperatureWater; + public short temperatureWaterSetPoint; +} diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/dto/SystemParameterBlock.java b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/dto/SystemParameterBlock.java new file mode 100644 index 0000000000000..694bb43617594 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/dto/SystemParameterBlock.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2010-2020 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.modbus.stiebeleltron.internal.dto; + +/** + * Dto class for the System Parameter Block + * + * @author Paul Frank - Initial contribution + * + */ +public class SystemParameterBlock { + + public int operationMode; + public short comfortTemperatureHeating; + public short ecoTemperatureHeating; + public short comfortTemperatureWater; + public short ecoTemperatureWater; +} diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/dto/SystemStateBlock.java b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/dto/SystemStateBlock.java new file mode 100644 index 0000000000000..320f949eefcf4 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/dto/SystemStateBlock.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2010-2020 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.modbus.stiebeleltron.internal.dto; + +/** + * Dto class for the System State Block + * + * @author Paul Frank - Initial contribution + * + */ +public class SystemStateBlock { + + public int state; +} diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/handler/StiebelEltronException.java b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/handler/StiebelEltronException.java new file mode 100644 index 0000000000000..7a20e0f09cbc2 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/handler/StiebelEltronException.java @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2010-2020 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.modbus.stiebeleltron.internal.handler; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Thrown when the stiebel eltron handler sees an error. + * + * @author Paul Frank - Initial contribution + */ +@SuppressWarnings("serial") +@NonNullByDefault +public class StiebelEltronException extends Exception { + + public StiebelEltronException() { + } + + public StiebelEltronException(String message) { + super(message); + } +} diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/handler/StiebelEltronHandler.java b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/handler/StiebelEltronHandler.java new file mode 100644 index 0000000000000..963c22ebf6d73 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/handler/StiebelEltronHandler.java @@ -0,0 +1,711 @@ +/** + * Copyright (c) 2010-2020 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.modbus.stiebeleltron.internal.handler; + +import static org.eclipse.smarthome.core.library.unit.SIUnits.CELSIUS; +import static org.eclipse.smarthome.core.library.unit.SmartHomeUnits.KILOWATT_HOUR; +import static org.eclipse.smarthome.core.library.unit.SmartHomeUnits.PERCENT; +import static org.openhab.binding.modbus.stiebeleltron.internal.StiebelEltronBindingConstants.*; + +import java.util.Optional; + +import javax.measure.Unit; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.smarthome.core.library.types.DecimalType; +import org.eclipse.smarthome.core.library.types.OpenClosedType; +import org.eclipse.smarthome.core.library.types.QuantityType; +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.ThingStatusInfo; +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.eclipse.smarthome.core.types.RefreshType; +import org.eclipse.smarthome.core.types.State; +import org.openhab.binding.modbus.handler.EndpointNotInitializedException; +import org.openhab.binding.modbus.handler.ModbusEndpointThingHandler; +import org.openhab.binding.modbus.stiebeleltron.internal.StiebelEltronConfiguration; +import org.openhab.binding.modbus.stiebeleltron.internal.dto.EnergyBlock; +import org.openhab.binding.modbus.stiebeleltron.internal.dto.SystemInformationBlock; +import org.openhab.binding.modbus.stiebeleltron.internal.dto.SystemParameterBlock; +import org.openhab.binding.modbus.stiebeleltron.internal.dto.SystemStateBlock; +import org.openhab.binding.modbus.stiebeleltron.internal.parser.EnergyBlockParser; +import org.openhab.binding.modbus.stiebeleltron.internal.parser.SystemInfromationBlockParser; +import org.openhab.binding.modbus.stiebeleltron.internal.parser.SystemParameterBlockParser; +import org.openhab.binding.modbus.stiebeleltron.internal.parser.SystemStateBlockParser; +import org.openhab.io.transport.modbus.AsyncModbusFailure; +import org.openhab.io.transport.modbus.ModbusCommunicationInterface; +import org.openhab.io.transport.modbus.ModbusReadFunctionCode; +import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint; +import org.openhab.io.transport.modbus.ModbusRegister; +import org.openhab.io.transport.modbus.ModbusRegisterArray; +import org.openhab.io.transport.modbus.ModbusWriteRegisterRequestBlueprint; +import org.openhab.io.transport.modbus.ModbusWriteRequestBlueprint; +import org.openhab.io.transport.modbus.PollTask; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link Modbus.StiebelEltronHandler} is responsible for handling commands, + * which are sent to one of the channels and for polling the modbus. + * + * @author Paul Frank - Initial contribution + */ +@NonNullByDefault +public class StiebelEltronHandler extends BaseThingHandler { + + public abstract class AbstractBasePoller { + + private final Logger logger = LoggerFactory.getLogger(StiebelEltronHandler.class); + + private volatile @Nullable PollTask pollTask; + + public synchronized void unregisterPollTask() { + PollTask task = pollTask; + if (task == null) { + return; + } + + ModbusCommunicationInterface mycomms = StiebelEltronHandler.this.comms; + if (mycomms != null) { + mycomms.unregisterRegularPoll(task); + } + pollTask = null; + } + + /** + * Register poll task This is where we set up our regular poller + */ + public synchronized void registerPollTask(int address, int length, ModbusReadFunctionCode readFunctionCode) { + + logger.debug("Setting up regular polling"); + + ModbusCommunicationInterface mycomms = StiebelEltronHandler.this.comms; + StiebelEltronConfiguration myconfig = StiebelEltronHandler.this.config; + if (myconfig == null || mycomms == null) { + throw new IllegalStateException("registerPollTask called without proper configuration"); + } + + ModbusReadRequestBlueprint request = new ModbusReadRequestBlueprint(getSlaveId(), + readFunctionCode, address, length, myconfig.getMaxTries()); + + + long refreshMillis = myconfig.getRefreshMillis(); + + pollTask = mycomms.registerRegularPoll(request, refreshMillis, 1000, result -> { + result.getRegisters().ifPresent(this::handlePolledData); + if (getThing().getStatus() != ThingStatus.ONLINE) { + updateStatus(ThingStatus.ONLINE); + } + }, StiebelEltronHandler.this::handleReadError); + } + + public synchronized void poll() { + PollTask task = pollTask; + ModbusCommunicationInterface mycomms = StiebelEltronHandler.this.comms; + if (task != null && mycomms != null) { + mycomms.submitOneTimePoll(task.getRequest(), task.getResultCallback(), task.getFailureCallback()); + } + } + + protected abstract void handlePolledData(ModbusRegisterArray registers); + } + + /** + * Logger instance + */ + private final Logger logger = LoggerFactory.getLogger(StiebelEltronHandler.class); + + /** + * Configuration instance + */ + protected @Nullable StiebelEltronConfiguration config = null; + /** + * Parser used to convert incoming raw messages into system blocks + */ + private final SystemInfromationBlockParser systemInformationBlockParser = new SystemInfromationBlockParser(); + /** + * Parser used to convert incoming raw messages into system state blocks + */ + private final SystemStateBlockParser systemstateBlockParser = new SystemStateBlockParser(); + /** + * Parser used to convert incoming raw messages into system parameter blocks + */ + private final SystemParameterBlockParser systemParameterBlockParser = new SystemParameterBlockParser(); + /** + * Parser used to convert incoming raw messages into model blocks + */ + private final EnergyBlockParser energyBlockParser = new EnergyBlockParser(); + /** + * This is the task used to poll the device + */ + private volatile @Nullable AbstractBasePoller systemInformationPoller = null; + /** + * This is the task used to poll the device + */ + private volatile @Nullable AbstractBasePoller energyPoller = null; + /** + * This is the task used to poll the device + */ + private volatile @Nullable AbstractBasePoller systemStatePoller = null; + /** + * This is the task used to poll the device + */ + private volatile @Nullable AbstractBasePoller systemParameterPoller = null; + /** + * Communication interface to the slave endpoint we're connecting to + */ + protected volatile @Nullable ModbusCommunicationInterface comms = null; + + /** + * This is the slave id, we store this once initialization is complete + */ + private volatile int slaveId; + + /** + * Instances of this handler should get a reference to the modbus manager + * + * @param thing the thing to handle + * @param modbusManager the modbus manager + */ + public StiebelEltronHandler(Thing thing) { + super(thing); + } + + /** + * @param address address of the value to be written on the modbus + * @param shortValue value to be written on the modbus + */ + protected void writeInt16(int address, short shortValue) { + StiebelEltronConfiguration myconfig = StiebelEltronHandler.this.config; + ModbusCommunicationInterface mycomms = StiebelEltronHandler.this.comms; + + if (myconfig == null || mycomms == null) { + throw new IllegalStateException("registerPollTask called without proper configuration"); + } + // big endian byte ordering + byte b1 = (byte) (shortValue >> 8); + byte b2 = (byte) shortValue; + + ModbusRegister register = new ModbusRegister(b1, b2); + ModbusRegisterArray data = new ModbusRegisterArray(new ModbusRegister[] { register }); + + ModbusWriteRegisterRequestBlueprint request = new ModbusWriteRegisterRequestBlueprint(slaveId, + address, data, false, myconfig.getMaxTries()); + + mycomms.submitOneTimeWrite(request, result -> { + if (hasConfigurationError()) { + return; + } + logger.debug("Successful write, matching request {}", request); + StiebelEltronHandler.this.updateStatus(ThingStatus.ONLINE); + }, failure -> {StiebelEltronHandler.this.handleWriteError(failure);}); + } + + /** + * @param command get the value of this command. + * @return short the value of the command multiplied by 10 (see datatype 2 in + * the stiebel eltron modbus documentation) + */ + private short getScaledInt16Value(Command command) throws StiebelEltronException { + if (command instanceof QuantityType) { + QuantityType c = ((QuantityType) command).toUnit(CELSIUS); + if (c != null) { + return (short) (c.doubleValue() * 10); + } else { + throw new StiebelEltronException("Unsupported unit"); + } + } + if (command instanceof DecimalType) { + DecimalType c = (DecimalType) command; + return (short) (c.doubleValue() * 10); + } + throw new StiebelEltronException("Unsupported command type"); + } + + /** + * @param command get the value of this command. + * @return short the value of the command as short + */ + private short getInt16Value(Command command) throws StiebelEltronException { + if (command instanceof DecimalType) { + DecimalType c = (DecimalType) command; + return c.shortValue(); + } + throw new StiebelEltronException("Unsupported command type"); + } + + /** + * Handle incoming commands. + */ + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + if (RefreshType.REFRESH == command) { + String groupId = channelUID.getGroupId(); + if (groupId != null) { + AbstractBasePoller poller; + switch (groupId) { + case GROUP_SYSTEM_STATE: + poller = systemStatePoller; + break; + case GROUP_SYSTEM_PARAMETER: + poller = systemParameterPoller; + break; + case GROUP_SYSTEM_INFO: + poller = systemInformationPoller; + break; + case GROUP_ENERGY_INFO: + poller = energyPoller; + break; + default: + poller = null; + break; + } + if (poller != null) { + poller.poll(); + } + } + } else { + try { + if (GROUP_SYSTEM_PARAMETER.equals(channelUID.getGroupId())) { + switch (channelUID.getIdWithoutGroup()) { + case CHANNEL_OPERATION_MODE: + writeInt16(1500, getInt16Value(command)); + break; + case CHANNEL_COMFORT_TEMPERATURE_HEATING: + writeInt16(1501, getScaledInt16Value(command)); + break; + case CHANNEL_ECO_TEMPERATURE_HEATING: + writeInt16(1502, getScaledInt16Value(command)); + break; + case CHANNEL_COMFORT_TEMPERATURE_WATER: + writeInt16(1509, getScaledInt16Value(command)); + break; + case CHANNEL_ECO_TEMPERATURE_WATER: + writeInt16(1510, getScaledInt16Value(command)); + break; + } + } + } catch (StiebelEltronException error) { + if (hasConfigurationError() || getThing().getStatus() == ThingStatus.OFFLINE) { + return; + } + String cls = error.getClass().getName(); + String msg = error.getMessage(); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, + String.format("Error with: %s: %s", cls, msg)); + } + } + } + + /** + * Initialization: Load the config object of the block Connect to the slave + * bridge Start the periodic polling + */ + @Override + public void initialize() { + config = getConfigAs(StiebelEltronConfiguration.class); + logger.debug("Initializing thing with properties: {}", thing.getProperties()); + + startUp(); + } + + /* + * This method starts the operation of this handler Connect to the slave bridge + * Start the periodic polling1 + */ + private void startUp() { + + if (comms != null) { + return; + } + + ModbusEndpointThingHandler slaveEndpointThingHandler = getEndpointThingHandler(); + if (slaveEndpointThingHandler == null) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, "Bridge is offline"); + return; + } + + try { + slaveId = slaveEndpointThingHandler.getSlaveId(); + + comms = slaveEndpointThingHandler.getCommunicationInterface(); + } catch (EndpointNotInitializedException e) { + // this will be handled below as endpoint remains null + } + + if (comms == null) { + @SuppressWarnings("null") + String label = Optional.ofNullable(getBridge()).map(b -> b.getLabel()).orElse(""); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, + String.format("Bridge '%s' not completely initialized", label)); + return; + } + + if (config == null) { + logger.debug("Invalid comms/config/manager ref for stiebel eltron handler"); + return; + } + + if (systemInformationPoller == null) { + AbstractBasePoller poller = new AbstractBasePoller() { + @Override + protected void handlePolledData(ModbusRegisterArray registers) { + handlePolledSystemInformationData(registers); + } + }; + poller.registerPollTask(500, 36, ModbusReadFunctionCode.READ_INPUT_REGISTERS); + systemInformationPoller = poller; + } + if (energyPoller == null) { + AbstractBasePoller poller = new AbstractBasePoller() { + @Override + protected void handlePolledData(ModbusRegisterArray registers) { + handlePolledEnergyData(registers); + } + }; + poller.registerPollTask(3500, 16, ModbusReadFunctionCode.READ_INPUT_REGISTERS); + energyPoller = poller; + } + if (systemStatePoller == null) { + AbstractBasePoller poller = new AbstractBasePoller() { + @Override + protected void handlePolledData(ModbusRegisterArray registers) { + handlePolledSystemStateData(registers); + } + }; + poller.registerPollTask(2500, 2, ModbusReadFunctionCode.READ_INPUT_REGISTERS); + systemStatePoller = poller; + } + if (systemParameterPoller == null) { + AbstractBasePoller poller = new AbstractBasePoller() { + @Override + protected void handlePolledData(ModbusRegisterArray registers) { + handlePolledSystemParameterData(registers); + } + }; + poller.registerPollTask(1500, 11, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); + systemParameterPoller = poller; + } + updateStatus(ThingStatus.UNKNOWN); + } + + /** + * Dispose the binding correctly + */ + @Override + public void dispose() { + tearDown(); + } + + /** + * Unregister the poll tasks and release the endpoint reference + */ + private void tearDown() { + AbstractBasePoller poller = systemInformationPoller; + if (poller != null) { + logger.debug("Unregistering systemInformationPoller from ModbusManager"); + poller.unregisterPollTask(); + + systemInformationPoller = null; + } + + poller = energyPoller; + if (poller != null) { + logger.debug("Unregistering energyPoller from ModbusManager"); + poller.unregisterPollTask(); + + energyPoller = null; + } + + poller = systemStatePoller; + if (poller != null) { + logger.debug("Unregistering systemStatePoller from ModbusManager"); + poller.unregisterPollTask(); + + systemStatePoller = null; + } + + poller = systemParameterPoller; + if (poller != null) { + logger.debug("Unregistering systemParameterPoller from ModbusManager"); + poller.unregisterPollTask(); + + systemParameterPoller = null; + } + + comms = null; + } + + /** + * Returns the current slave id from the bridge + */ + public int getSlaveId() { + return slaveId; + } + + /** + * Get the endpoint handler from the bridge this handler is connected to Checks + * that we're connected to the right type of bridge + * + * @return the endpoint handler or null if the bridge does not exist + */ + private @Nullable ModbusEndpointThingHandler getEndpointThingHandler() { + Bridge bridge = getBridge(); + if (bridge == null) { + logger.debug("Bridge is null"); + return null; + } + if (bridge.getStatus() != ThingStatus.ONLINE) { + logger.debug("Bridge is not online"); + return null; + } + + ThingHandler handler = bridge.getHandler(); + if (handler == null) { + logger.debug("Bridge handler is null"); + return null; + } + + if (handler instanceof ModbusEndpointThingHandler) { + ModbusEndpointThingHandler slaveEndpoint = (ModbusEndpointThingHandler) handler; + return slaveEndpoint; + } else { + throw new IllegalStateException("Unexpected bridge handler: " + handler.toString()); + } + } + + /** + * Returns value divided by the 10 + * + * @param value the value to alter + * @return the scaled value as a DecimalType + */ + protected State getScaled(Number value, Unit unit) { + return QuantityType.valueOf(value.doubleValue() / 10, unit); + } + + /** + * Returns high value * 1000 + low value + * + * @param high the high value + * @param low the low valze + * @return the scaled value as a DecimalType + */ + protected State getEnergyQuantity(int high, int low) { + double value = high * 1000 + low; + return QuantityType.valueOf(value, KILOWATT_HOUR); + } + + /** + * This method is called each time new data has been polled from the modbus + * slave The register array is first parsed, then each of the channels are + * updated to the new values + * + * @param registers byte array read from the modbus slave + */ + protected void handlePolledSystemInformationData(ModbusRegisterArray registers) { + logger.trace("System Information block received, size: {}", registers.size()); + + SystemInformationBlock block = systemInformationBlockParser.parse(registers); + + // System information group + updateState(channelUID(GROUP_SYSTEM_INFO, CHANNEL_FEK_TEMPERATURE), getScaled(block.temperatureFek, CELSIUS)); + updateState(channelUID(GROUP_SYSTEM_INFO, CHANNEL_FEK_TEMPERATURE_SETPOINT), + getScaled(block.temperatureFekSetPoint, CELSIUS)); + updateState(channelUID(GROUP_SYSTEM_INFO, CHANNEL_FEK_HUMIDITY), getScaled(block.humidityFek, PERCENT)); + updateState(channelUID(GROUP_SYSTEM_INFO, CHANNEL_FEK_DEWPOINT), getScaled(block.dewpointFek, CELSIUS)); + updateState(channelUID(GROUP_SYSTEM_INFO, CHANNEL_OUTDOOR_TEMPERATURE), + getScaled(block.temperatureOutdoor, CELSIUS)); + updateState(channelUID(GROUP_SYSTEM_INFO, CHANNEL_HK1_TEMPERATURE), getScaled(block.temperatureHk1, CELSIUS)); + updateState(channelUID(GROUP_SYSTEM_INFO, CHANNEL_HK1_TEMPERATURE_SETPOINT), + getScaled(block.temperatureHk1SetPoint, CELSIUS)); + updateState(channelUID(GROUP_SYSTEM_INFO, CHANNEL_SUPPLY_TEMPERATURE), + getScaled(block.temperatureSupply, CELSIUS)); + updateState(channelUID(GROUP_SYSTEM_INFO, CHANNEL_RETURN_TEMPERATURE), + getScaled(block.temperatureReturn, CELSIUS)); + updateState(channelUID(GROUP_SYSTEM_INFO, CHANNEL_SOURCE_TEMPERATURE), + getScaled(block.temperatureSource, CELSIUS)); + updateState(channelUID(GROUP_SYSTEM_INFO, CHANNEL_WATER_TEMPERATURE), + getScaled(block.temperatureWater, CELSIUS)); + updateState(channelUID(GROUP_SYSTEM_INFO, CHANNEL_WATER_TEMPERATURE_SETPOINT), + getScaled(block.temperatureWaterSetPoint, CELSIUS)); + + resetCommunicationError(); + } + + /** + * This method is called each time new data has been polled from the modbus + * slave The register array is first parsed, then each of the channels are + * updated to the new values + * + * @param registers byte array read from the modbus slave + */ + protected void handlePolledEnergyData(ModbusRegisterArray registers) { + logger.trace("Energy block received, size: {}", registers.size()); + + EnergyBlock block = energyBlockParser.parse(registers); + + // Energy information group + updateState(channelUID(GROUP_ENERGY_INFO, CHANNEL_PRODUCTION_HEAT_TODAY), + new QuantityType<>(block.productionHeatToday, KILOWATT_HOUR)); + updateState(channelUID(GROUP_ENERGY_INFO, CHANNEL_PRODUCTION_HEAT_TOTAL), + getEnergyQuantity(block.productionHeatTotalHigh, block.productionHeatTotalLow)); + updateState(channelUID(GROUP_ENERGY_INFO, CHANNEL_PRODUCTION_WATER_TODAY), + new QuantityType<>(block.productionWaterToday, KILOWATT_HOUR)); + updateState(channelUID(GROUP_ENERGY_INFO, CHANNEL_PRODUCTION_WATER_TOTAL), + getEnergyQuantity(block.productionWaterTotalHigh, block.productionWaterTotalLow)); + updateState(channelUID(GROUP_ENERGY_INFO, CHANNEL_CONSUMPTION_HEAT_TODAY), + new QuantityType<>(block.consumptionHeatToday, KILOWATT_HOUR)); + updateState(channelUID(GROUP_ENERGY_INFO, CHANNEL_CONSUMPTION_HEAT_TOTAL), + getEnergyQuantity(block.consumptionHeatTotalHigh, block.consumptionHeatTotalLow)); + updateState(channelUID(GROUP_ENERGY_INFO, CHANNEL_CONSUMPTION_WATER_TODAY), + new QuantityType<>(block.consumptionWaterToday, KILOWATT_HOUR)); + updateState(channelUID(GROUP_ENERGY_INFO, CHANNEL_CONSUMPTION_WATER_TOTAL), + getEnergyQuantity(block.consumptionWaterTotalHigh, block.consumptionWaterTotalLow)); + + resetCommunicationError(); + } + + /** + * This method is called each time new data has been polled from the modbus + * slave The register array is first parsed, then each of the channels are + * updated to the new values + * + * @param registers byte array read from the modbus slave + */ + protected void handlePolledSystemStateData(ModbusRegisterArray registers) { + logger.trace("System state block received, size: {}", registers.size()); + + SystemStateBlock block = systemstateBlockParser.parse(registers); + boolean isHeating = (block.state & 16) != 0; + updateState(channelUID(GROUP_SYSTEM_STATE, CHANNEL_IS_HEATING), + isHeating ? OpenClosedType.OPEN : OpenClosedType.CLOSED); + updateState(channelUID(GROUP_SYSTEM_STATE, CHANNEL_IS_HEATING_WATER), + (block.state & 32) != 0 ? OpenClosedType.OPEN : OpenClosedType.CLOSED); + updateState(channelUID(GROUP_SYSTEM_STATE, CHANNEL_IS_COOLING), + (block.state & 256) != 0 ? OpenClosedType.OPEN : OpenClosedType.CLOSED); + updateState(channelUID(GROUP_SYSTEM_STATE, CHANNEL_IS_SUMMER), + (block.state & 128) != 0 ? OpenClosedType.OPEN : OpenClosedType.CLOSED); + updateState(channelUID(GROUP_SYSTEM_STATE, CHANNEL_IS_PUMPING), + (block.state & 1) != 0 ? OpenClosedType.OPEN : OpenClosedType.CLOSED); + + resetCommunicationError(); + } + + /** + * This method is called each time new data has been polled from the modbus + * slave The register array is first parsed, then each of the channels are + * updated to the new values + * + * @param registers byte array read from the modbus slave + */ + protected void handlePolledSystemParameterData(ModbusRegisterArray registers) { + logger.trace("System state block received, size: {}", registers.size()); + + SystemParameterBlock block = systemParameterBlockParser.parse(registers); + updateState(channelUID(GROUP_SYSTEM_PARAMETER, CHANNEL_OPERATION_MODE), new DecimalType(block.operationMode)); + + updateState(channelUID(GROUP_SYSTEM_PARAMETER, CHANNEL_COMFORT_TEMPERATURE_HEATING), + getScaled(block.comfortTemperatureHeating, CELSIUS)); + updateState(channelUID(GROUP_SYSTEM_PARAMETER, CHANNEL_ECO_TEMPERATURE_HEATING), + getScaled(block.ecoTemperatureHeating, CELSIUS)); + updateState(channelUID(GROUP_SYSTEM_PARAMETER, CHANNEL_COMFORT_TEMPERATURE_WATER), + getScaled(block.comfortTemperatureWater, CELSIUS)); + updateState(channelUID(GROUP_SYSTEM_PARAMETER, CHANNEL_ECO_TEMPERATURE_WATER), + getScaled(block.ecoTemperatureWater, CELSIUS)); + + resetCommunicationError(); + } + + /** + * @param bridgeStatusInfo + */ + @Override + public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) { + super.bridgeStatusChanged(bridgeStatusInfo); + + if (bridgeStatusInfo.getStatus() == ThingStatus.ONLINE) { + startUp(); + } else if (bridgeStatusInfo.getStatus() == ThingStatus.OFFLINE) { + tearDown(); + } + } + + /** + * Handle errors received during communication + */ + protected void handleReadError(AsyncModbusFailure failure) { + // Ignore all incoming data and errors if configuration is not correct + if (hasConfigurationError() || getThing().getStatus() == ThingStatus.OFFLINE) { + return; + } + String msg = failure.getCause().getMessage(); + String cls = failure.getCause().getClass().getName(); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, + String.format("Error with read: %s: %s", cls, msg)); + } + + /** + * Handle errors received during communication + */ + protected void handleWriteError(AsyncModbusFailure failure) { + // Ignore all incoming data and errors if configuration is not correct + if (hasConfigurationError() || getThing().getStatus() == ThingStatus.OFFLINE) { + return; + } + String msg = failure.getCause().getMessage(); + String cls = failure.getCause().getClass().getName(); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, + String.format("Error with write: %s: %s", cls, msg)); + } + + + /** + * Returns true, if we're in a CONFIGURATION_ERROR state + * + * @return + */ + protected boolean hasConfigurationError() { + ThingStatusInfo statusInfo = getThing().getStatusInfo(); + return statusInfo.getStatus() == ThingStatus.OFFLINE + && statusInfo.getStatusDetail() == ThingStatusDetail.CONFIGURATION_ERROR; + } + + /** + * Reset communication status to ONLINE if we're in an OFFLINE state + */ + protected void resetCommunicationError() { + ThingStatusInfo statusInfo = thing.getStatusInfo(); + if (ThingStatus.OFFLINE.equals(statusInfo.getStatus()) + && ThingStatusDetail.COMMUNICATION_ERROR.equals(statusInfo.getStatusDetail())) { + updateStatus(ThingStatus.ONLINE); + } + } + + /** + * Returns the channel UID for the specified group and channel id + * + * @param string the channel group + * @param string the channel id in that group + * @return the globally unique channel uid + */ + ChannelUID channelUID(String group, String id) { + return new ChannelUID(getThing().getUID(), group, id); + } +} diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/AbstractBaseParser.java b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/AbstractBaseParser.java new file mode 100644 index 0000000000000..1b1319a681e60 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/AbstractBaseParser.java @@ -0,0 +1,127 @@ +/** + * Copyright (c) 2010-2020 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.modbus.stiebeleltron.internal.parser; + +import java.util.Optional; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.smarthome.core.library.types.DecimalType; +import org.openhab.io.transport.modbus.ModbusBitUtilities; +import org.openhab.io.transport.modbus.ModbusConstants.ValueType; +import org.openhab.io.transport.modbus.ModbusRegisterArray; + +/** + * Base class for parsers with some helper methods + * + * @author Nagy Attila Gabor - Initial contribution + * @author Paul Frank - Added more methods + */ +@NonNullByDefault +public class AbstractBaseParser { + + /** + * Extract an optional double value + * + * @param raw the register array to extract from + * @param index the address of the field + * @return the parsed value or empty if the field is not implemented + */ + protected Optional extractOptionalDouble(ModbusRegisterArray raw, int index) { + return ModbusBitUtilities.extractStateFromRegisters(raw, index, ValueType.INT16) + .map(value -> ((double) value.intValue()) / 10.0).filter(value -> value != (short) 0x8000); + } + + /** + * Extract a mandatory double value + * + * @param raw the register array to extract from + * @param index the address of the field + * @param def the default value + * @return the parsed value or the default if the field is not implemented + */ + protected Double extractDouble(ModbusRegisterArray raw, int index, double def) { + return extractOptionalDouble(raw, index).orElse(def); + } + + /** + * Extract an optional int16 value + * + * @param raw the register array to extract from + * @param index the address of the field + * @return the parsed value or empty if the field is not implemented + */ + protected Optional extractOptionalInt16(ModbusRegisterArray raw, int index) { + return ModbusBitUtilities.extractStateFromRegisters(raw, index, ValueType.INT16).map(DecimalType::shortValue) + .filter(value -> value != (short) 0x8000); + } + + /** + * Extract a mandatory int16 value + * + * @param raw the register array to extract from + * @param index the address of the field + * @param def the default value + * @return the parsed value or the default if the field is not implemented + */ + protected Short extractInt16(ModbusRegisterArray raw, int index, short def) { + return extractOptionalInt16(raw, index).orElse(def); + } + + /** + * Extract an optional uint16 value + * + * @param raw the register array to extract from + * @param index the address of the field + * @return the parsed value or empty if the field is not implemented + */ + protected Optional extractOptionalUInt16(ModbusRegisterArray raw, int index) { + return ModbusBitUtilities.extractStateFromRegisters(raw, index, ValueType.UINT16).map(DecimalType::intValue) + .filter(value -> value != 0xffff); + } + + /** + * Extract a mandatory uint16 value + * + * @param raw the register array to extract from + * @param index the address of the field + * @param def the default value + * @return the parsed value or the default if the field is not implemented + */ + protected Integer extractUInt16(ModbusRegisterArray raw, int index, int def) { + return extractOptionalUInt16(raw, index).orElse(def); + } + + /** + * Extract an optional acc32 value + * + * @param raw the register array to extract from + * @param index the address of the field + * @return the parsed value or empty if the field is not implemented + */ + protected Optional extractOptionalUInt32(ModbusRegisterArray raw, int index) { + return ModbusBitUtilities.extractStateFromRegisters(raw, index, ValueType.UINT32).map(DecimalType::longValue) + .filter(value -> value != 0); + } + + /** + * Extract a mandatory acc32 value + * + * @param raw the register array to extract from + * @param index the address of the field + * @param def the default value + * @return the parsed value or default if the field is not implemented + */ + protected Long extractUnit32(ModbusRegisterArray raw, int index, long def) { + return extractOptionalUInt32(raw, index).orElse(def); + } +} diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/EnergyBlockParser.java b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/EnergyBlockParser.java new file mode 100644 index 0000000000000..f31028cb79da4 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/EnergyBlockParser.java @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2010-2020 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.modbus.stiebeleltron.internal.parser; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.modbus.stiebeleltron.internal.dto.EnergyBlock; +import org.openhab.io.transport.modbus.ModbusRegisterArray; + +/** + * Parses inverter modbus data into an Energy Block + * + * @author Paul Frank - Initial contribution + * + */ +@NonNullByDefault +public class EnergyBlockParser extends AbstractBaseParser { + + public EnergyBlock parse(ModbusRegisterArray raw) { + EnergyBlock block = new EnergyBlock(); + + block.productionHeatToday = extractUInt16(raw, 0, (short) 0); + block.productionHeatTotalLow = extractUInt16(raw, 1, (short) 0); + block.productionHeatTotalHigh = extractUInt16(raw, 2, (short) 0); + block.productionWaterToday = extractUInt16(raw, 3, (short) 0); + block.productionWaterTotalLow = extractUInt16(raw, 4, (short) 0); + block.productionWaterTotalHigh = extractUInt16(raw, 5, (short) 0); + + block.consumptionHeatToday = extractUInt16(raw, 10, (short) 0); + block.consumptionHeatTotalLow = extractUInt16(raw, 11, (short) 0); + block.consumptionHeatTotalHigh = extractUInt16(raw, 12, (short) 0); + block.consumptionWaterToday = extractUInt16(raw, 13, (short) 0); + block.consumptionWaterTotalLow = extractUInt16(raw, 14, (short) 0); + block.consumptionWaterTotalHigh = extractUInt16(raw, 15, (short) 0); + return block; + } +} diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/SystemInfromationBlockParser.java b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/SystemInfromationBlockParser.java new file mode 100644 index 0000000000000..71b81b70fa0da --- /dev/null +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/SystemInfromationBlockParser.java @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2010-2020 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.modbus.stiebeleltron.internal.parser; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.modbus.stiebeleltron.internal.dto.SystemInformationBlock; +import org.openhab.io.transport.modbus.ModbusRegisterArray; + +/** + * Parses inverter modbus data into an SystemB Information lock + * + * @author Paul Frank - Initial contribution + * + */ +@NonNullByDefault +public class SystemInfromationBlockParser extends AbstractBaseParser { + + public SystemInformationBlock parse(ModbusRegisterArray raw) { + SystemInformationBlock block = new SystemInformationBlock(); + + block.temperatureFek = extractInt16(raw, 2, (short) 0); + block.temperatureFekSetPoint = extractInt16(raw, 3, (short) 0); + block.humidityFek = extractInt16(raw, 4, (short) 0); + block.dewpointFek = extractInt16(raw, 5, (short) 0); + block.temperatureOutdoor = extractInt16(raw, 6, (short) 0); + block.temperatureHk1 = extractInt16(raw, 7, (short) 0); + block.temperatureHk1SetPoint = extractInt16(raw, 9, (short) 0); + block.temperatureSupply = extractInt16(raw, 12, (short) 0); + block.temperatureReturn = extractInt16(raw, 15, (short) 0); + block.temperatureWater = extractInt16(raw, 21, (short) 0); + block.temperatureWaterSetPoint = extractInt16(raw, 22, (short) 0); + block.temperatureSource = extractInt16(raw, 35, (short) 0); + return block; + } +} diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/SystemParameterBlockParser.java b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/SystemParameterBlockParser.java new file mode 100644 index 0000000000000..f1bd72f7c4321 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/SystemParameterBlockParser.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2010-2020 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.modbus.stiebeleltron.internal.parser; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.modbus.stiebeleltron.internal.dto.SystemParameterBlock; +import org.openhab.io.transport.modbus.ModbusRegisterArray; + +/** + * Parses inverter modbus data into an System Parameter Block + * + * @author Paul Frank - Initial contribution + * + */ +@NonNullByDefault +public class SystemParameterBlockParser extends AbstractBaseParser { + + public SystemParameterBlock parse(ModbusRegisterArray raw) { + SystemParameterBlock block = new SystemParameterBlock(); + + block.operationMode = extractUInt16(raw, 0, 0); + block.comfortTemperatureHeating = extractInt16(raw, 1, (short) 0); + block.ecoTemperatureHeating = extractInt16(raw, 2, (short) 0); + block.comfortTemperatureWater = extractInt16(raw, 9, (short) 0); + block.ecoTemperatureWater = extractInt16(raw, 10, (short) 0); + return block; + } +} diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/SystemStateBlockParser.java b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/SystemStateBlockParser.java new file mode 100644 index 0000000000000..a49d8388a5aa5 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/SystemStateBlockParser.java @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2010-2020 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.modbus.stiebeleltron.internal.parser; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.modbus.stiebeleltron.internal.dto.SystemStateBlock; +import org.openhab.io.transport.modbus.ModbusRegisterArray; + +/** + * Parses inverter modbus data into an System State Block + * + * @author Paul Frank - Initial contribution + * + */ +@NonNullByDefault +public class SystemStateBlockParser extends AbstractBaseParser { + + public SystemStateBlock parse(ModbusRegisterArray raw) { + SystemStateBlock block = new SystemStateBlock(); + + block.state = extractUInt16(raw, 0, 0); + return block; + } +} diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/resources/ESH-INF/config/config-descriptions.xml b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/resources/ESH-INF/config/config-descriptions.xml new file mode 100644 index 0000000000000..d88938a7c4f46 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/resources/ESH-INF/config/config-descriptions.xml @@ -0,0 +1,25 @@ + + + + + + + + Poll interval in seconds. Use zero to disable automatic polling. + 5 + s + + + + + 3 + Number of tries when reading data, if some of the reading fail. For single try, enter 1. + true + + + + + diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/resources/ESH-INF/thing/heatpump-channel-groups.xml b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/resources/ESH-INF/thing/heatpump-channel-groups.xml new file mode 100644 index 0000000000000..f35627a7cfb00 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/resources/ESH-INF/thing/heatpump-channel-groups.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/resources/ESH-INF/thing/heatpump-channel-types.xml b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/resources/ESH-INF/thing/heatpump-channel-types.xml new file mode 100644 index 0000000000000..b409f22da06c8 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/resources/ESH-INF/thing/heatpump-channel-types.xml @@ -0,0 +1,171 @@ + + + + + Number:Temperature + + + + + + Number:Temperature + + + + + Number:Dimensionless + + + + + Number:Temperature + + + + + Number:Temperature + + + + + + Number:Temperature + + + + + Number:Temperature + + + + + Number:Temperature + + + + + Number:Temperature + + + + + Number:Temperature + + + + + Number:Temperature + + + + + Number:Temperature + + + + + + + Number:Energy + + + + + Number:Energy + + + + + Number:Energy + + + + + Number:Energy + + + + + + Number:Energy + + + + + Number:Energy + + + + + Number:Energy + + + + + Number:Energy + + + + + Contact + + + + + Contact + + + + + Contact + + + + + Contact + + + + + Contact + + + + + Number + + + + + + + + + + + + + + Number:Temperature + + + + + Number:Temperature + + + + + Number:Temperature + + + + + Number:Temperature + + + + diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/resources/ESH-INF/thing/heatpump-types.xml b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/resources/ESH-INF/thing/heatpump-types.xml new file mode 100644 index 0000000000000..deca01b55d0f8 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/resources/ESH-INF/thing/heatpump-types.xml @@ -0,0 +1,27 @@ + + + + + + + + + + Stiebel Eltron ISG connected through modbus + + + + + + + + + + + + + + diff --git a/bundles/pom.xml b/bundles/pom.xml index d302827819432..b81fc302fa8f2 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -162,6 +162,7 @@ org.openhab.binding.minecraft org.openhab.binding.modbus org.openhab.binding.modbus.sunspec + org.openhab.binding.modbus.stiebeleltron org.openhab.binding.mpd org.openhab.binding.mqtt org.openhab.binding.mqtt.generic