From 37487bfedf4e5b2c12803f0025375d098e64d477 Mon Sep 17 00:00:00 2001 From: Christian Koch <78686276+chilobo@users.noreply.github.com> Date: Sat, 17 Aug 2024 13:51:56 +0200 Subject: [PATCH 1/8] Test commit1 Signed-off-by: Christian Koch Signed-off-by: Christian Koch <78686276+chilobo@users.noreply.github.com> --- .../org.openhab.binding.modbus.lambda/NOTICE | 13 + .../README.md | 199 ++++++ .../org.openhab.binding.modbus.lambda/pom.xml | 26 + .../internal/LambdaBindingConstants.java | 52 ++ .../lambda/internal/LambdaConfiguration.java | 47 ++ .../lambda/internal/LambdaHandlerFactory.java | 57 ++ .../lambda/internal/dto/AmbientBlock.java | 25 + .../lambda/internal/dto/Boiler150Block.java | 25 + .../lambda/internal/dto/Boiler1Block.java | 25 + .../lambda/internal/dto/EManagerBlock.java | 26 + .../internal/handler/LambdaException.java | 33 + .../internal/handler/LambdaHandler.java | 653 ++++++++++++++++++ .../internal/parser/AbstractBaseParser.java | 128 ++++ .../internal/parser/AmbientBlockParser.java | 38 + .../internal/parser/Boiler150BlockParser.java | 38 + .../internal/parser/Boiler1BlockParser.java | 39 ++ .../internal/parser/EManagerBlockParser.java | 37 + .../OH-INF/config/config-descriptions.xml | 25 + .../resources/OH-INF/i18n/lambda.properties | 25 + .../OH-INF/thing/lambdahp-channel-groups.xml | 38 + .../OH-INF/thing/lambdahp-channel-types.xml | 36 + .../resources/OH-INF/thing/lambdahp-types.xml | 27 + 22 files changed, 1612 insertions(+) create mode 100644 bundles/org.openhab.binding.modbus.lambda/NOTICE create mode 100644 bundles/org.openhab.binding.modbus.lambda/README.md create mode 100644 bundles/org.openhab.binding.modbus.lambda/pom.xml create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaBindingConstants.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaConfiguration.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaHandlerFactory.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/AmbientBlock.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler150Block.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler1Block.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/EManagerBlock.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/LambdaException.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/LambdaHandler.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/AbstractBaseParser.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/AmbientBlockParser.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler150BlockParser.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1BlockParser.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/EManagerBlockParser.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/config/config-descriptions.xml create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/i18n/lambda.properties create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-groups.xml create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-types.xml create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-types.xml diff --git a/bundles/org.openhab.binding.modbus.lambda/NOTICE b/bundles/org.openhab.binding.modbus.lambda/NOTICE new file mode 100644 index 0000000000000..38d625e349232 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/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.lambda/README.md b/bundles/org.openhab.binding.modbus.lambda/README.md new file mode 100644 index 0000000000000..c507c083c3c94 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/README.md @@ -0,0 +1,199 @@ +# Stiebel Eltron ISG + +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: + +## 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 | lambdahp | A stiebel eltron heat pump connected through an ISG | + +## Discovery + +This extension does not support autodiscovery. The things need to be added manually. + +A typical bridge configuration would look like this: + +```java +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 + +```java +Bridge modbus:tcp:bridge "Stiebel Modbus TCP"[ host="hostname|ip", port=502, id=1 ] { + Thing lambdahp lambda "Lambda" (modbus:tcp:modbusbridge) @"Room" [ ] +} +``` + +### Item Configuration + +```java +Number:Temperature stiebel_eltron_temperature_fek "Temperature FEK [%.1f °C]" { channel="modbus:lambdahp:lambda:systemInformation#fek-temperature" } +Number:Temperature stiebel_eltron_setpoint_fek "Set point FEK [%.1f °C]" { channel="modbus:lambdahp:lambda:systemInformation#fek-temperature-setpoint" } +Number:Dimensionless stiebel_eltron_humidity_fek "Humidity FEK [%.1f %%]" { channel="modbus:lambdahp:lambda:systemInformation#fek-humidity" } +Number:Temperature stiebel_eltron_dewpoint_fek "Dew point FEK [%.1f °C]" { channel="modbus:lambdahp:lambda:systemInformation#fek-dewpoint" } + +Number:Temperature stiebel_eltron_outdoor_temp "Outdoor temperature [%.1f °C]" { channel="modbus:lambdahp:lambda:systemInformation#outdoor-temperature" } +Number:Temperature stiebel_eltron_temp_hk1 "Temperature HK1 [%.1f °C]" { channel="modbus:lambdahp:lambda:systemInformation#hk1-temperature" } +Number:Temperature stiebel_eltron_setpoint_hk1 "Set point HK1 [%.1f °C]" { channel="modbus:lambdahp:lambda:systemInformation#hk1-temperature-setpoint" } +Number:Temperature stiebel_eltron_temp_water "Water temperature [%.1f °C]" { channel="modbus:lambdahp:lambda:systemInformation#water-temperature" } +Number:Temperature stiebel_eltron_setpoint_water "Water setpoint [%.1f °C]" { channel="modbus:lambdahp:lambda:systemInformation#water-temperature-setpoint" } +Number:Temperature stiebel_eltron_source_temp "Source temperature [%.1f °C]" { channel="modbus:lambdahp:lambda:systemInformation#source-temperature" } +Number:Temperature stiebel_eltron_vorlauf_temp "Supply tempertature [%.1f °C]" { channel="modbus:lambdahp:lambda:systemInformation#supply-temperature" } +Number:Temperature stiebel_eltron_ruecklauf_temp "Return temperature [%.1f °C]" { channel="modbus:lambdahp:lambda:systemInformation#return-temperature" } + +Number stiebel_eltron_heating_comfort_temp "Heating Comfort Temperature [%.1f °C]" { channel="modbus:lambdahp:lambda:systemParameter#comfort-temperature-heating" } +Number stiebel_eltron_heating_eco_temp "Heating Eco Temperature [%.1f °C]" { channel="modbus:lambdahp:lambda:systemParameter#eco-temperature-heating" } +Number stiebel_eltron_water_comfort_temp "Water Comfort Temperature [%.1f °C]" { channel="modbus:lambdahp:lambda:systemParameter#comfort-temperature-water" } +Number stiebel_eltron_water_eco_temp "Water Eco Temperature [%.1f °C]" { channel="modbus:lambdahp:lambda:systemParameter#eco-temperature-water" } +Number stiebel_eltron_operation_mode "Operation Mode" { channel="modbus:lambdahp:lambda:systemParameter#operation-mode" } + +Contact stiebel_eltron_mode_pump "Pump [%d]" { channel="modbus:lambdahp:lambda:systemState#is-pumping" } +Contact stiebel_eltron_mode_heating "Heating [%d]" { channel="modbus:lambdahp:lambda:systemState#is-heating" } +Contact stiebel_eltron_mode_water "Heating Water [%d]" { channel="modbus:lambdahp:lambda:systemState#is-heating-water" } +Contact stiebel_eltron_mode_cooling "Cooling [%d]" { channel="modbus:lambdahp:lambda:systemState#is-cooling" } +Contact stiebel_eltron_mode_summer "Summer Mode [%d]" { channel="modbus:lambdahp:lambda:systemState#is-summer" } + + +Number:Energy stiebel_eltron_production_heat_today "Heat quantity today [%.0f kWh]" { channel="modbus:lambdahp:lambda:energyInformation#production_heat_today" } +Number:Energy stiebel_eltron_production_heat_total "Heat quantity total [%.3f MWh]" {channel="modbus:lambdahp:lambda:energyInformation#production_heat_total"} +Number:Energy stiebel_eltron_production_water_today "Water heat quantity today [%.0f kWh]" { channel="modbus:lambdahp:lambda:energyInformation#production_water_today" } +Number:Energy stiebel_eltron_production_water_total "Water heat quantity total [%.3f MWh]" {channel="modbus:lambdahp:lambda:energyInformation#production_water_total"} +Number:Energy stiebel_eltron_consumption_heat_total "Heating power consumption total [%.3f MWh]" {channel="modbus:lambdahp:lambda:energyInformation#consumption_heat_total"} +Number:Energy stiebel_eltron_consumption_heat_today "Heating power consumption today [%.0f kWh]" { channel="modbus:lambdahp:lambda:energyInformation#consumption_heat_today" } +Number:Energy stiebel_eltron_consumption_water_today "Water heating power consumption today [%.0f kWh]" { channel="modbus:lambdahp:lambda:energyInformation#consumption_water_today" } +Number:Energy stiebel_eltron_consumption_water_total "Water heating power consumption total [%.3f MWh]" {channel="modbus:lambdahp:lambda:energyInformation#consumption_water_total"} + +``` + +### Sitemap Configuration + +```perl +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_fek icon="temperature" + Default item=stiebel_eltron_setpoint_fek icon="temperature" + Default item=stiebel_eltron_humidity_fek icon="humidity" + Default item=stiebel_eltron_dewpoint_fek 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.lambda/pom.xml b/bundles/org.openhab.binding.modbus.lambda/pom.xml new file mode 100644 index 0000000000000..cf593d3dec533 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/pom.xml @@ -0,0 +1,26 @@ + + + + 4.0.0 + + + org.openhab.addons.bundles + org.openhab.addons.reactor.bundles + 4.3.0-SNAPSHOT + + + org.openhab.binding.modbus.lambda + + openHAB Add-ons :: Bundles :: Lambda Bundle + + + + org.openhab.addons.bundles + org.openhab.binding.modbus + ${project.version} + provided + + + + diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaBindingConstants.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaBindingConstants.java new file mode 100644 index 0000000000000..9d311975ea451 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaBindingConstants.java @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.modbus.ModbusBindingConstants; +import org.openhab.core.thing.ThingTypeUID; + +/** + * The {@link LambdaBindingConstants} class defines common + * constants, which are used across the whole binding. + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + */ +@NonNullByDefault +public class LambdaBindingConstants { + + private static final String BINDING_ID = ModbusBindingConstants.BINDING_ID; + + // List of all Thing Type UIDs + public static final ThingTypeUID THING_TYPE_LAMBDAHP = new ThingTypeUID(BINDING_ID, "lambdahp"); + + // Channel group ids + public static final String GROUP_GENERAL_AMBIENT = "generalAmbient"; + public static final String GROUP_GENERAL_EMANAGER = "generalEManager"; + public static final String GROUP_BOILER1 = "boiler1"; + public static final String GROUP_BOILER150 = "boiler150"; + + /** + * public static final String GROUP_HEAT_PUMP1 = "HeatPump1"; + * public static final String GROUP_BUFFER1 = "Buffer1"; + * public static final String GROUP_SOLAR1 = "Solar1"; + * public static final String GROUP_HEATING_CIRCUIT1 = "HeatingCircuit1"; + */ + // List of all Channel ids in device information group + public static final String CHANNEL_ACTUAL_AMBIENT_TEMPERATURE = "actual-ambient-temperature"; + public static final String CHANNEL_ACTUAL_POWER = "actual-power"; + public static final String CHANNEL_ACTUAL_POWER_CONSUMPTION = "actual-power-consumption"; + public static final String CHANNEL_BOILER1_ACTUAL_HIGH_TEMPERATURE = "boiler1-actual-high-temperature"; + public static final String CHANNEL_BOILER150_MAXIMUM_BOILER_TEMPERATURE = "boiler150-maximum-boiler-temperature"; +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaConfiguration.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaConfiguration.java new file mode 100644 index 0000000000000..bfc652005d894 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaConfiguration.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link LambdaConfiguration} class contains fields mapping + * thing configuration parameters. + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + */ +@NonNullByDefault +public class LambdaConfiguration { + /** + * 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.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaHandlerFactory.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaHandlerFactory.java new file mode 100644 index 0000000000000..ea6fd951e699b --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaHandlerFactory.java @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal; + +import static org.openhab.binding.modbus.lambda.internal.LambdaBindingConstants.THING_TYPE_LAMBDAHP; + +import java.util.Set; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.modbus.lambda.internal.handler.LambdaHandler; +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 LambdaHandlerFactory} is responsible for creating things and thing + * handlers. + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + */ +@NonNullByDefault +@Component(configurationPid = "binding.lambda", service = ThingHandlerFactory.class) +public class LambdaHandlerFactory extends BaseThingHandlerFactory { + + private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_LAMBDAHP); + + @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_LAMBDAHP.equals(thingTypeUID)) { + return new LambdaHandler(thing); + } + + return null; + } +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/AmbientBlock.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/AmbientBlock.java new file mode 100644 index 0000000000000..bdde7234f4a95 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/AmbientBlock.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.dto; + +/** + * Dto class for the Energy Block + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + * + */ +public class AmbientBlock { + + public int actualAmbientTemperature; +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler150Block.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler150Block.java new file mode 100644 index 0000000000000..d2d7935cc4045 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler150Block.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.dto; + +/** + * Dto class for the Energy Block + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + * + */ +public class Boiler150Block { + + public int boiler150MaximumBoilerTemperature; +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler1Block.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler1Block.java new file mode 100644 index 0000000000000..ef45dfa43351b --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler1Block.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.dto; + +/** + * Dto class for the Energy Block + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + * + */ +public class Boiler1Block { + + public int boiler1ActualHighTemperature; +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/EManagerBlock.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/EManagerBlock.java new file mode 100644 index 0000000000000..ab21c04f54b1b --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/EManagerBlock.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.dto; + +/** + * Dto class for the System Information Block + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + * + */ +public class EManagerBlock { + + public int actualPower; + public int actualPowerConsumption; +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/LambdaException.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/LambdaException.java new file mode 100644 index 0000000000000..0d6e6115be7e6 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/LambdaException.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.handler; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Thrown when the stiebel eltron handler sees an error. + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + */ +@SuppressWarnings("serial") +@NonNullByDefault +public class LambdaException extends Exception { + + public LambdaException() { + } + + public LambdaException(String message) { + super(message); + } +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/LambdaHandler.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/LambdaHandler.java new file mode 100644 index 0000000000000..264c6951c4e31 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/LambdaHandler.java @@ -0,0 +1,653 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.handler; + +import static org.openhab.binding.modbus.lambda.internal.LambdaBindingConstants.*; +import static org.openhab.core.library.unit.SIUnits.CELSIUS; +import static org.openhab.core.library.unit.Units.*; + +import java.util.Optional; + +import javax.measure.Unit; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.modbus.handler.EndpointNotInitializedException; +import org.openhab.binding.modbus.handler.ModbusEndpointThingHandler; + +import org.openhab.binding.modbus.lambda.internal.LambdaConfiguration; +import org.openhab.binding.modbus.lambda.internal.dto.EManagerBlock; +import org.openhab.binding.modbus.lambda.internal.dto.AmbientBlock; +import org.openhab.binding.modbus.lambda.internal.dto.Boiler1Block; +import org.openhab.binding.modbus.lambda.internal.dto.Boiler150Block; + +import org.openhab.binding.modbus.lambda.internal.parser.AmbientBlockParser; +import org.openhab.binding.modbus.lambda.internal.parser.EManagerBlockParser; +import org.openhab.binding.modbus.lambda.internal.parser.Boiler1BlockParser; +import org.openhab.binding.modbus.lambda.internal.parser.Boiler150BlockParser; + +import org.openhab.core.io.transport.modbus.AsyncModbusFailure; +import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; +import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode; +import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.ModbusWriteRegisterRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusWriteRequestBlueprint; +import org.openhab.core.io.transport.modbus.PollTask; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.thing.Bridge; +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.ThingStatusInfo; +import org.openhab.core.thing.binding.BaseThingHandler; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.types.Command; +import org.openhab.core.types.RefreshType; +import org.openhab.core.types.State; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link LambdaHandler} 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 LambdaHandler extends BaseThingHandler { + + public abstract class AbstractBasePoller { + + private final Logger logger = LoggerFactory.getLogger(LambdaHandler.class); + + private volatile @Nullable PollTask pollTask; + + public synchronized void unregisterPollTask() { + PollTask task = pollTask; + if (task == null) { + return; + } + + ModbusCommunicationInterface mycomms = LambdaHandler.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 = LambdaHandler.this.comms; + LambdaConfiguration myconfig = LambdaHandler.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); + } + }, LambdaHandler.this::handleReadError); + } + + public synchronized void poll() { + PollTask task = pollTask; + ModbusCommunicationInterface mycomms = LambdaHandler.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(LambdaHandler.class); + + /** + * Configuration instance + */ + protected @Nullable LambdaConfiguration config = null; + /** + * Parser used to convert incoming raw messages into system blocks + * private final SystemInfromationBlockParser systemInformationBlockParser = new SystemInfromationBlockParser(); + */ + /** + * Parsers used to convert incoming raw messages into state blocks + */ + private final AmbientBlockParser ambientBlockParser = new AmbientBlockParser(); + private final EManagerBlockParser emanagerBlockParser = new EManagerBlockParser(); + private final Boiler1BlockParser boiler1BlockParser = new Boiler1BlockParser(); + private final Boiler150BlockParser boiler150BlockParser = new Boiler150BlockParser(); + + /** + * These are the tasks used to poll the device + */ + private volatile @Nullable AbstractBasePoller ambientPoller = null; + private volatile @Nullable AbstractBasePoller emanagerPoller = null; + private volatile @Nullable AbstractBasePoller boiler1Poller = null; + private volatile @Nullable AbstractBasePoller boiler150Poller = 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 + */ + public LambdaHandler(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) { + logger.trace("171 writeInt16: Es wird geschrieben, Adresse: {} Wert: {}", address, shortValue); + LambdaConfiguration myconfig = LambdaHandler.this.config; + ModbusCommunicationInterface mycomms = LambdaHandler.this.comms; + + if (myconfig == null || mycomms == null) { + throw new IllegalStateException("registerPollTask called without proper configuration"); + } + // big endian byte ordering + byte hi = (byte) (shortValue >> 8); + byte lo = (byte) shortValue; + ModbusRegisterArray data = new ModbusRegisterArray(hi, lo); + + logger.trace("183 hi: {}, lo: {}", hi, lo); + ModbusWriteRegisterRequestBlueprint request = new ModbusWriteRegisterRequestBlueprint(slaveId, address, data, + true, myconfig.getMaxTries()); + // 15.8.24 13:40 war: + // false, myconfig.getMaxTries()); + + mycomms.submitOneTimeWrite(request, result -> { + if (hasConfigurationError()) { + return; + } + logger.trace("Successful write, matching request {}", request); + LambdaHandler.this.updateStatus(ThingStatus.ONLINE); + }, failure -> { + LambdaHandler.this.handleWriteError(failure); + logger.trace("Unsuccessful write, matching request {}", request); + }); + } + + /** + * @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 LambdaException { + if (command instanceof QuantityType quantityCommand) { + QuantityType c = quantityCommand.toUnit(CELSIUS); + if (c != null) { + return (short) (c.doubleValue() * 10); + } else { + throw new LambdaException("Unsupported unit"); + } + } + if (command instanceof DecimalType c) { + return (short) (c.doubleValue() * 10); + } + throw new LambdaException("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 LambdaException { + if (command instanceof QuantityType quantityCommand) { + QuantityType c = quantityCommand.toUnit(WATT); + if (c != null) { + return c.shortValue(); + } else { + throw new LambdaException("Unsupported unit"); + } + } + if (command instanceof DecimalType c) { + return c.shortValue(); + } + throw new LambdaException("Unsupported command type"); + } + + /** + * Handle incoming commands. + */ + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + logger.trace("237 handleCommand, channelUID: {} command {} ", channelUID, command); + if (RefreshType.REFRESH == command) { + logger.trace("239 handleCommand: Es wird geschrieben, GroupID: {}", channelUID.getGroupId()); + String groupId = channelUID.getGroupId(); + if (groupId != null) { + logger.trace("242 }"); + AbstractBasePoller poller; + switch (groupId) { + case GROUP_GENERAL_AMBIENT: + poller = ambientPoller; + break; + case GROUP_GENERAL_EMANAGER: + poller = emanagerPoller; + logger.trace("250 emanager"); + break; + case GROUP_BOILER1: + poller = boiler1Poller; + break; + case GROUP_BOILER150: + poller = boiler150Poller; + break; + default: + poller = null; + break; + } + if (poller != null) { + poller.poll(); + } + } + } else { + logger.trace("264 handleCommand: Es wird geschrieben, GroupID: {}, command {}", channelUID.getGroupId(), + command); + try { + // logger.trace("266 handleCommand: Es wird geschrieben, GroupID: {}, command: {}", + // channelUID.getGroupId(), getInt16Value(command)); + logger.trace("269 "); + if (GROUP_GENERAL_EMANAGER.equals(channelUID.getGroupId())) { + + logger.trace("271 channelUID {} ", channelUID.getIdWithoutGroup()); + + switch (channelUID.getIdWithoutGroup()) { + + case CHANNEL_ACTUAL_POWER: + + logger.trace("279 command: {}", command); + // String teststr = command.replaceAll("[^0-9,-]", ""); + // logger.trace("testsstr: {}, ", teststr); + // writeInt16(102, getInt16Value(teststr)); + writeInt16(102, getInt16Value(command)); + break; + + } + } + } catch (LambdaException 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(LambdaConfiguration.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 (ambientPoller == null) { + AbstractBasePoller poller = new AbstractBasePoller() { + @Override + protected void handlePolledData(ModbusRegisterArray registers) { + handlePolledAmbientData(registers); + } + }; + poller.registerPollTask(0, 5, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); + ambientPoller = poller; + } + + if (emanagerPoller == null) { + AbstractBasePoller poller = new AbstractBasePoller() { + @Override + protected void handlePolledData(ModbusRegisterArray registers) { + handlePolledEManagerData(registers); + } + }; + poller.registerPollTask(100, 5, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); + emanagerPoller = poller; + } + if (boiler1Poller == null) { + AbstractBasePoller poller = new AbstractBasePoller() { + @Override + protected void handlePolledData(ModbusRegisterArray registers) { + handlePolledBoiler1Data(registers); + } + }; + + poller.registerPollTask(2000, 4, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); + // logger.trace("Poller Boiler1 erzeugt"); + boiler1Poller = poller; + } + if (boiler150Poller == null) { + AbstractBasePoller poller = new AbstractBasePoller() { + @Override + protected void handlePolledData(ModbusRegisterArray registers) { + handlePolledBoiler150Data(registers); + } + }; + + poller.registerPollTask(2050, 1, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); + // logger.trace("Poller Boiler150 erzeugt"); + boiler150Poller = 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 = ambientPoller; + if (poller != null) { + logger.debug("Unregistering ambientPoller from ModbusManager"); + poller.unregisterPollTask(); + + ambientPoller = null; + } + + poller = emanagerPoller; + if (poller != null) { + logger.debug("Unregistering emanagerPoller from ModbusManager"); + poller.unregisterPollTask(); + + emanagerPoller = null; + } + + poller = boiler1Poller; + if (poller != null) { + logger.debug("Unregistering boiler1Poller from ModbusManager"); + poller.unregisterPollTask(); + + boiler1Poller = null; + } + + poller = boiler150Poller; + if (poller != null) { + logger.debug("Unregistering boiler150Poller from ModbusManager"); + poller.unregisterPollTask(); + + boiler150Poller = 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 thingHandler) { + return thingHandler; + } 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); + } + + protected State getUnscaled(Number value, Unit unit) { + return QuantityType.valueOf(value.doubleValue(), 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); + } + + /** + * These methods are 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 handlePolledAmbientData(ModbusRegisterArray registers) { + // logger.trace("Ambient block received, size: {}", registers.size()); + + AmbientBlock block = ambientBlockParser.parse(registers); + + // Ambient group + updateState(channelUID(GROUP_GENERAL_AMBIENT, CHANNEL_ACTUAL_AMBIENT_TEMPERATURE), + getScaled(block.actualAmbientTemperature, CELSIUS)); + resetCommunicationError(); + } + + protected void handlePolledEManagerData(ModbusRegisterArray registers) { + // logger.trace("EManager block received, size: {}", registers.size()); + + EManagerBlock block = emanagerBlockParser.parse(registers); + + // EManager group + updateState(channelUID(GROUP_GENERAL_EMANAGER, CHANNEL_ACTUAL_POWER_CONSUMPTION), + getUnscaled(block.actualPowerConsumption, WATT)); + + updateState(channelUID(GROUP_GENERAL_EMANAGER, CHANNEL_ACTUAL_POWER), getUnscaled(block.actualPower, WATT)); + resetCommunicationError(); + } + + protected void handlePolledBoiler1Data(ModbusRegisterArray registers) { + // logger.trace("Boiler1 block received, size: {}", registers.size()); + + Boiler1Block block = boiler1BlockParser.parse(registers); + + // Boiler1 group + updateState(channelUID(GROUP_BOILER1, CHANNEL_BOILER1_ACTUAL_HIGH_TEMPERATURE), + getScaled(block.boiler1ActualHighTemperature, CELSIUS)); + resetCommunicationError(); + } + + protected void handlePolledBoiler150Data(ModbusRegisterArray registers) { + // logger.trace("Boiler150 block received, size: {}", registers.size()); + + Boiler1Block block = boiler150BlockParser.parse(registers); + + // Boiler1 group + updateState(channelUID(GROUP_BOILER150, CHANNEL_BOILER150_MAXIMUM_BOILER_TEMPERATURE), + getScaled(block.boiler150MaximumBoilerTemperature, 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.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/AbstractBaseParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/AbstractBaseParser.java new file mode 100644 index 0000000000000..56f5150c73fb3 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/AbstractBaseParser.java @@ -0,0 +1,128 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.parser; + +import java.util.Objects; +import java.util.Optional; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.io.transport.modbus.ModbusBitUtilities; +import org.openhab.core.io.transport.modbus.ModbusConstants.ValueType; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.library.types.DecimalType; + +/** + * 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 Objects.requireNonNull(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 Objects.requireNonNull(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 Objects.requireNonNull(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 Objects.requireNonNull(extractOptionalUInt32(raw, index).orElse(def)); + } +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/AmbientBlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/AmbientBlockParser.java new file mode 100644 index 0000000000000..3f5c7ea42f768 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/AmbientBlockParser.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.parser; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.modbus.lambda.internal.dto.AmbientBlock; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Parses inverter modbus data into an Energy Block + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + * + */ +@NonNullByDefault +public class AmbientBlockParser extends AbstractBaseParser { + private final Logger logger = LoggerFactory.getLogger(AmbientBlockParser.class); + + public AmbientBlock parse(ModbusRegisterArray raw) { + AmbientBlock block = new AmbientBlock(); + + block.actualAmbientTemperature = extractUInt16(raw, 2, (short) 0); + return block; + } +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler150BlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler150BlockParser.java new file mode 100644 index 0000000000000..3094728da3ec1 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler150BlockParser.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.parser; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Parses inverter modbus data into an Energy Block + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + * + */ +@NonNullByDefault +public class Boiler150BlockParser extends AbstractBaseParser { + private final Logger logger = LoggerFactory.getLogger(Boiler150BlockParser.class); + + public Boiler150Block parse(ModbusRegisterArray raw) { + // logger.trace("Boiler150BlockParser"); + Boiler150Block block = new Boiler150Block(); + + block.boiler150MaximumBoilerTemperature = extractUInt16(raw, 2, (short) 0); + return block; + } +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1BlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1BlockParser.java new file mode 100644 index 0000000000000..6fa2f58324658 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1BlockParser.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.parser; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.modbus.lambda.internal.dto.Boiler1Block; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Parses inverter modbus data into an Energy Block + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + * + */ +@NonNullByDefault +public class Boiler1BlockParser extends AbstractBaseParser { + private final Logger logger = LoggerFactory.getLogger(Boiler1BlockParser.class); + + public Boiler1Block parse(ModbusRegisterArray raw) { + // logger.trace("Boiler1BlockParser"); + Boiler1Block block = new Boiler1Block(); + + block.boiler1ActualHighTemperature = extractUInt16(raw, 2, (short) 0); + return block; + } +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/EManagerBlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/EManagerBlockParser.java new file mode 100644 index 0000000000000..d9b910d85ccb0 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/EManagerBlockParser.java @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.parser; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.modbus.lambda.internal.dto.EManagerBlock; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; + +/** + * Parses inverter modbus data into a SystemB Information lock + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + * + */ +@NonNullByDefault +public class EManagerBlockParser extends AbstractBaseParser { + + public EManagerBlock parse(ModbusRegisterArray raw) { + EManagerBlock block = new EManagerBlock(); + + block.actualPower = extractUInt16(raw, 2, (short) 0); + block.actualPowerConsumption = extractUInt16(raw, 3, (short) 0); + + return block; + } +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/config/config-descriptions.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/config/config-descriptions.xml new file mode 100644 index 0000000000000..b0337590fb686 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/config/config-descriptions.xml @@ -0,0 +1,25 @@ + + + + + + + + Poll interval in seconds. Use zero to disable automatic polling. + 10 + 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.lambda/src/main/resources/OH-INF/i18n/lambda.properties b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/i18n/lambda.properties new file mode 100644 index 0000000000000..fba7c965b1cd4 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/i18n/lambda.properties @@ -0,0 +1,25 @@ +# thing types + +thing-type.modbus.lambdahp.label = Lambda Heat Pump +thing-type.modbus.lambdahp.description = Lambda Heat Pump connected through modbus + +# thing types config + +thing-type.config.lambda.modbusconfig.maxTries.label = Maximum Tries When Reading +thing-type.config.lambda.modbusconfig.maxTries.description = Number of tries when reading data, if some of the reading fail. For single try, enter 1. +thing-type.config.lambda.modbusconfig.refresh.label = Polling Interval +thing-type.config.lambda.modbusconfig.refresh.description = Poll interval in seconds. Use zero to disable automatic polling. + +# channel group types + +channel-group-type.modbus.general-ambient.label = General Ambient +channel-group-type.modbus.general-emanager.label = General E-Manager +channel-group-type.modbus.boiler1.label = Boiler 1 +channel-group-type.modbus.boiler150.label = Boiler 150 +# channel types + +channel-type.modbus.actual-ambient-temperature-type.label = Actual Ambient Temperature +channel-type.modbus.actual-power-type.label = Actual Power (input or excess) +channel-type.modbus.actual-power-consumption-type.label = Actual Power Consumption +channel-type.modbus.boiler1-actual-high-temperature-type.label = Boiler 1 Actual High Temperature +channel-type.modbus.boiler150-maximum-boiler-temperature-type.label = Boiler 1 Maximum Boiler Temperature diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-groups.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-groups.xml new file mode 100644 index 0000000000000..e34f8f6e1edb2 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-groups.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-types.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-types.xml new file mode 100644 index 0000000000000..9c72ddbb85acd --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-types.xml @@ -0,0 +1,36 @@ + + + + + Number:Temperature + + + + + + Number:Power + + + + + + Number:Power + + + + + + Number:Temperature + + + + + + Number:Temperature + + + + diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-types.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-types.xml new file mode 100644 index 0000000000000..47c3280ec8115 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-types.xml @@ -0,0 +1,27 @@ + + + + + + + + + Lambda Heat connected through modbus + + + + + + + + + + + + + + + From a672eecdece29d96a88e5daad0b90e89ccb4fe7e Mon Sep 17 00:00:00 2001 From: Christian Koch <78686276+chilobo@users.noreply.github.com> Date: Sat, 17 Aug 2024 14:11:09 +0200 Subject: [PATCH 2/8] Commit Test 2 Signed-off-by: Christian Koch Signed-off-by: Christian Koch <78686276+chilobo@users.noreply.github.com> From 43a2590c6ccc9490c41a751ed0d72a71bd75fa41 Mon Sep 17 00:00:00 2001 From: Christian Koch <78686276+chilobo@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:15:29 +0200 Subject: [PATCH 3/8] =?UTF-8?q?Version=200.1=20f=C3=BCr=20Lambda=20Heat=20?= =?UTF-8?q?Pump?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ambient, EManager, Boiler1, Buffer1 so weit fertig, Readme und Heatpump1 fehlen noch Co-Authored-By: Paul Frank <13279715+pail23@users.noreply.github.com> Signed-off-by: Christian Koch Signed-off-by: Christian Koch <78686276+chilobo@users.noreply.github.com> --- .../internal/LambdaBindingConstants.java | 37 ++-- .../lambda/internal/dto/AmbientBlock.java | 7 +- .../lambda/internal/dto/Boiler1Block.java | 3 +- ...oiler150Block.java => Boiler1MtBlock.java} | 6 +- .../lambda/internal/dto/Buffer1Block.java | 26 +++ .../lambda/internal/dto/Buffer1MtBlock.java | 25 +++ .../lambda/internal/dto/EManagerBlock.java | 5 +- .../internal/handler/LambdaHandler.java | 168 ++++++++++++++---- .../internal/parser/AmbientBlockParser.java | 8 +- .../internal/parser/Boiler1BlockParser.java | 5 +- ...kParser.java => Boiler1MtBlockParser.java} | 15 +- .../internal/parser/Buffer1BlockParser.java | 40 +++++ .../internal/parser/Buffer1MtBlockParser.java | 39 ++++ .../internal/parser/EManagerBlockParser.java | 5 +- .../OH-INF/config/config-descriptions.xml | 2 +- .../resources/OH-INF/i18n/lambda.properties | 29 ++- .../OH-INF/thing/lambdahp-channel-groups.xml | 45 ++++- .../OH-INF/thing/lambdahp-channel-types.xml | 94 +++++++++- .../resources/OH-INF/thing/lambdahp-types.xml | 10 +- 19 files changed, 485 insertions(+), 84 deletions(-) rename bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/{Boiler150Block.java => Boiler1MtBlock.java} (83%) create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Buffer1Block.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Buffer1MtBlock.java rename bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/{Boiler150BlockParser.java => Boiler1MtBlockParser.java} (66%) create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Buffer1BlockParser.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Buffer1MtBlockParser.java diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaBindingConstants.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaBindingConstants.java index 9d311975ea451..7b3bd8463a0aa 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaBindingConstants.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaBindingConstants.java @@ -34,19 +34,36 @@ public class LambdaBindingConstants { // Channel group ids public static final String GROUP_GENERAL_AMBIENT = "generalAmbient"; public static final String GROUP_GENERAL_EMANAGER = "generalEManager"; - public static final String GROUP_BOILER1 = "boiler1"; - public static final String GROUP_BOILER150 = "boiler150"; - - /** - * public static final String GROUP_HEAT_PUMP1 = "HeatPump1"; - * public static final String GROUP_BUFFER1 = "Buffer1"; - * public static final String GROUP_SOLAR1 = "Solar1"; - * public static final String GROUP_HEATING_CIRCUIT1 = "HeatingCircuit1"; - */ + public static final String GROUP_HEATPUMP1 = "Heatpump1"; + public static final String GROUP_BOILER1 = "Boiler1"; + public static final String GROUP_BOILER1MT = "Boiler1Mt"; + public static final String GROUP_BUFFER1 = "Buffer1"; + public static final String GROUP_BUFFER1MT = "Buffer1Mt"; + // List of all Channel ids in device information group + // General Ambient + public static final String CHANNEL_AMBIENT_ERROR_NUMBER = "ambient-error-number"; + public static final String CHANNEL_AMBIENT_OPERATOR_STATE = "ambient-operator-state"; public static final String CHANNEL_ACTUAL_AMBIENT_TEMPERATURE = "actual-ambient-temperature"; + public static final String CHANNEL_AVERAGE_AMBIENT_TEMPERATURE = "average-ambient-temperature"; + public static final String CHANNEL_CALCULATED_AMBIENT_TEMPERATURE = "calculated-ambient-temperature"; + + // General E-manager + public static final String CHANNEL_EMANAGER_ERROR_NUMBER = "emanager-error-number"; + public static final String CHANNEL_EMANAGER_OPERATOR_STATE = "emanager-operator-state"; public static final String CHANNEL_ACTUAL_POWER = "actual-power"; public static final String CHANNEL_ACTUAL_POWER_CONSUMPTION = "actual-power-consumption"; + + // Heatpump 1 + public static final String CHANNEL_HEATPUMP1_TFLOW = "heatpump1-t-flow"; + + // Boiler 1 public static final String CHANNEL_BOILER1_ACTUAL_HIGH_TEMPERATURE = "boiler1-actual-high-temperature"; - public static final String CHANNEL_BOILER150_MAXIMUM_BOILER_TEMPERATURE = "boiler150-maximum-boiler-temperature"; + public static final String CHANNEL_BOILER1_ACTUAL_LOW_TEMPERATURE = "boiler1-actual-low-temperature"; + public static final String CHANNEL_BOILER1_MAXIMUM_BOILER_TEMPERATURE = "boiler1-maximum-boiler-temperature"; + + // Buffer 1 + public static final String CHANNEL_BUFFER1_ACTUAL_HIGH_TEMPERATURE = "buffer1-actual-high-temperature"; + public static final String CHANNEL_BUFFER1_ACTUAL_LOW_TEMPERATURE = "buffer1-actual-low-temperature"; + public static final String CHANNEL_BUFFER1_MAXIMUM_BOILER_TEMPERATURE = "buffer1-maximum-boiler-temperature"; } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/AmbientBlock.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/AmbientBlock.java index bdde7234f4a95..46309bda428ea 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/AmbientBlock.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/AmbientBlock.java @@ -13,13 +13,16 @@ package org.openhab.binding.modbus.lambda.internal.dto; /** - * Dto class for the Energy Block + * Dto class for the Ambient Block * * @author Paul Frank - Initial contribution * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus * */ public class AmbientBlock { - + public int ambientErrorNumber; + public int ambientOperatorState; public int actualAmbientTemperature; + public int averageAmbientTemperature; + public int calculatedAmbientTemperature; } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler1Block.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler1Block.java index ef45dfa43351b..0bf391cb8179f 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler1Block.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler1Block.java @@ -13,7 +13,7 @@ package org.openhab.binding.modbus.lambda.internal.dto; /** - * Dto class for the Energy Block + * Dto class for the Boiler1 Block * * @author Paul Frank - Initial contribution * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus @@ -22,4 +22,5 @@ public class Boiler1Block { public int boiler1ActualHighTemperature; + public int boiler1ActualLowTemperature; } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler150Block.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler1MtBlock.java similarity index 83% rename from bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler150Block.java rename to bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler1MtBlock.java index d2d7935cc4045..03ebaa167bb29 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler150Block.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler1MtBlock.java @@ -13,13 +13,13 @@ package org.openhab.binding.modbus.lambda.internal.dto; /** - * Dto class for the Energy Block + * Dto class for the Boiler1Mt Block * * @author Paul Frank - Initial contribution * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus * */ -public class Boiler150Block { +public class Boiler1MtBlock { - public int boiler150MaximumBoilerTemperature; + public int boiler1MaximumBoilerTemperature; } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Buffer1Block.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Buffer1Block.java new file mode 100644 index 0000000000000..d454287868a15 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Buffer1Block.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.dto; + +/** + * Dto class for the Buffer1 Block + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + * + */ +public class Buffer1Block { + + public int buffer1ActualHighTemperature; + public int buffer1ActualLowTemperature; +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Buffer1MtBlock.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Buffer1MtBlock.java new file mode 100644 index 0000000000000..dd4a04f2def63 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Buffer1MtBlock.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.dto; + +/** + * Dto class for the Buffer1Mt Block + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + * + */ +public class Buffer1MtBlock { + + public int buffer1MaximumBufferTemperature; +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/EManagerBlock.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/EManagerBlock.java index ab21c04f54b1b..210f8419f8f52 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/EManagerBlock.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/EManagerBlock.java @@ -13,14 +13,15 @@ package org.openhab.binding.modbus.lambda.internal.dto; /** - * Dto class for the System Information Block + * Dto class for the EManager Block * * @author Paul Frank - Initial contribution * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus * */ public class EManagerBlock { - + public int emanagerErrorNumber; + public int emanagerOperatorState; public int actualPower; public int actualPowerConsumption; } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/LambdaHandler.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/LambdaHandler.java index 264c6951c4e31..f0de021ce98f8 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/LambdaHandler.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/LambdaHandler.java @@ -24,18 +24,19 @@ import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.modbus.handler.EndpointNotInitializedException; import org.openhab.binding.modbus.handler.ModbusEndpointThingHandler; - import org.openhab.binding.modbus.lambda.internal.LambdaConfiguration; -import org.openhab.binding.modbus.lambda.internal.dto.EManagerBlock; import org.openhab.binding.modbus.lambda.internal.dto.AmbientBlock; import org.openhab.binding.modbus.lambda.internal.dto.Boiler1Block; -import org.openhab.binding.modbus.lambda.internal.dto.Boiler150Block; - +import org.openhab.binding.modbus.lambda.internal.dto.Boiler1MtBlock; +import org.openhab.binding.modbus.lambda.internal.dto.Buffer1Block; +import org.openhab.binding.modbus.lambda.internal.dto.Buffer1MtBlock; +import org.openhab.binding.modbus.lambda.internal.dto.EManagerBlock; import org.openhab.binding.modbus.lambda.internal.parser.AmbientBlockParser; -import org.openhab.binding.modbus.lambda.internal.parser.EManagerBlockParser; import org.openhab.binding.modbus.lambda.internal.parser.Boiler1BlockParser; -import org.openhab.binding.modbus.lambda.internal.parser.Boiler150BlockParser; - +import org.openhab.binding.modbus.lambda.internal.parser.Boiler1MtBlockParser; +import org.openhab.binding.modbus.lambda.internal.parser.Buffer1BlockParser; +import org.openhab.binding.modbus.lambda.internal.parser.Buffer1MtBlockParser; +import org.openhab.binding.modbus.lambda.internal.parser.EManagerBlockParser; import org.openhab.core.io.transport.modbus.AsyncModbusFailure; import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode; @@ -143,7 +144,9 @@ public synchronized void poll() { private final AmbientBlockParser ambientBlockParser = new AmbientBlockParser(); private final EManagerBlockParser emanagerBlockParser = new EManagerBlockParser(); private final Boiler1BlockParser boiler1BlockParser = new Boiler1BlockParser(); - private final Boiler150BlockParser boiler150BlockParser = new Boiler150BlockParser(); + private final Boiler1MtBlockParser boiler1mtBlockParser = new Boiler1MtBlockParser(); + private final Buffer1BlockParser buffer1BlockParser = new Buffer1BlockParser(); + private final Buffer1MtBlockParser buffer1mtBlockParser = new Buffer1MtBlockParser(); /** * These are the tasks used to poll the device @@ -151,7 +154,9 @@ public synchronized void poll() { private volatile @Nullable AbstractBasePoller ambientPoller = null; private volatile @Nullable AbstractBasePoller emanagerPoller = null; private volatile @Nullable AbstractBasePoller boiler1Poller = null; - private volatile @Nullable AbstractBasePoller boiler150Poller = null; + private volatile @Nullable AbstractBasePoller boiler1mtPoller = null; + private volatile @Nullable AbstractBasePoller buffer1Poller = null; + private volatile @Nullable AbstractBasePoller buffer1mtPoller = null; /** * Communication interface to the slave endpoint we're connecting to */ @@ -249,9 +254,9 @@ private short getInt16Value(Command command) throws LambdaException { */ @Override public void handleCommand(ChannelUID channelUID, Command command) { - logger.trace("237 handleCommand, channelUID: {} command {} ", channelUID, command); + logger.trace("249 handleCommand, channelUID: {} command {} ", channelUID, command); if (RefreshType.REFRESH == command) { - logger.trace("239 handleCommand: Es wird geschrieben, GroupID: {}", channelUID.getGroupId()); + logger.trace("239 handleCommand: Es wird gelesen ?, GroupID: {}", channelUID.getGroupId()); String groupId = channelUID.getGroupId(); if (groupId != null) { logger.trace("242 }"); @@ -262,19 +267,29 @@ public void handleCommand(ChannelUID channelUID, Command command) { break; case GROUP_GENERAL_EMANAGER: poller = emanagerPoller; - logger.trace("250 emanager"); break; case GROUP_BOILER1: + logger.trace("264 boiler1Poller }"); poller = boiler1Poller; break; - case GROUP_BOILER150: - poller = boiler150Poller; + case GROUP_BOILER1MT: + logger.trace("267 boiler1mtPoller }"); + poller = boiler1mtPoller; + break; + case GROUP_BUFFER1: + logger.trace("280 buffer1Poller }"); + poller = buffer1Poller; + break; + case GROUP_BUFFER1MT: + logger.trace("284 buffer1mtPoller }"); + poller = buffer1mtPoller; break; default: poller = null; break; } if (poller != null) { + logger.trace("276 Es wird gepollt }"); poller.poll(); } } @@ -284,16 +299,16 @@ public void handleCommand(ChannelUID channelUID, Command command) { try { // logger.trace("266 handleCommand: Es wird geschrieben, GroupID: {}, command: {}", // channelUID.getGroupId(), getInt16Value(command)); - logger.trace("269 "); + logger.trace("302 "); if (GROUP_GENERAL_EMANAGER.equals(channelUID.getGroupId())) { - logger.trace("271 channelUID {} ", channelUID.getIdWithoutGroup()); + logger.trace("305 channelUID {} ", channelUID.getIdWithoutGroup()); switch (channelUID.getIdWithoutGroup()) { case CHANNEL_ACTUAL_POWER: - logger.trace("279 command: {}", command); + logger.trace("311 command: {}", command); // String teststr = command.replaceAll("[^0-9,-]", ""); // logger.trace("testsstr: {}, ", teststr); // writeInt16(102, getInt16Value(teststr)); @@ -393,20 +408,45 @@ protected void handlePolledData(ModbusRegisterArray registers) { }; poller.registerPollTask(2000, 4, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); - // logger.trace("Poller Boiler1 erzeugt"); + logger.trace("Poller Boiler1 erzeugt"); boiler1Poller = poller; } - if (boiler150Poller == null) { + if (boiler1mtPoller == null) { AbstractBasePoller poller = new AbstractBasePoller() { @Override protected void handlePolledData(ModbusRegisterArray registers) { - handlePolledBoiler150Data(registers); + handlePolledBoiler1MtData(registers); } }; poller.registerPollTask(2050, 1, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); - // logger.trace("Poller Boiler150 erzeugt"); - boiler150Poller = poller; + logger.trace("Poller BoilerMt1 erzeugt"); + boiler1mtPoller = poller; + } + + if (buffer1Poller == null) { + AbstractBasePoller poller = new AbstractBasePoller() { + @Override + protected void handlePolledData(ModbusRegisterArray registers) { + handlePolledBuffer1Data(registers); + } + }; + + poller.registerPollTask(3000, 4, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); + logger.trace("Poller Buffer1 erzeugt"); + buffer1Poller = poller; + } + if (buffer1mtPoller == null) { + AbstractBasePoller poller = new AbstractBasePoller() { + @Override + protected void handlePolledData(ModbusRegisterArray registers) { + handlePolledBuffer1MtData(registers); + } + }; + + poller.registerPollTask(3050, 1, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); + logger.trace("Poller BufferMt1 erzeugt"); + buffer1mtPoller = poller; } updateStatus(ThingStatus.UNKNOWN); @@ -449,12 +489,28 @@ private void tearDown() { boiler1Poller = null; } - poller = boiler150Poller; + poller = boiler1mtPoller; + if (poller != null) { + logger.debug("Unregistering boiler1mtPoller from ModbusManager"); + poller.unregisterPollTask(); + + boiler1mtPoller = null; + } + + poller = buffer1Poller; if (poller != null) { - logger.debug("Unregistering boiler150Poller from ModbusManager"); + logger.debug("Unregistering buffer1Poller from ModbusManager"); poller.unregisterPollTask(); - boiler150Poller = null; + buffer1Poller = null; + } + + poller = buffer1mtPoller; + if (poller != null) { + logger.debug("Unregistering buffer1mtPoller from ModbusManager"); + poller.unregisterPollTask(); + + buffer1mtPoller = null; } comms = null; @@ -503,7 +559,9 @@ public int getSlaveId() { * @param value the value to alter * @return the scaled value as a DecimalType */ + protected State getScaled(Number value, Unit unit) { + // logger.trace("505 value: {}", value.intValue()); return QuantityType.valueOf(value.doubleValue() / 10, unit); } @@ -533,46 +591,80 @@ protected State getEnergyQuantity(int high, int low) { protected void handlePolledAmbientData(ModbusRegisterArray registers) { // logger.trace("Ambient block received, size: {}", registers.size()); + // Ambient group AmbientBlock block = ambientBlockParser.parse(registers); - // Ambient group - updateState(channelUID(GROUP_GENERAL_AMBIENT, CHANNEL_ACTUAL_AMBIENT_TEMPERATURE), - getScaled(block.actualAmbientTemperature, CELSIUS)); + updateState(channelUID(GROUP_GENERAL_AMBIENT, CHANNEL_AMBIENT_ERROR_NUMBER), + new DecimalType(block.ambientErrorNumber)); + updateState(channelUID(GROUP_GENERAL_AMBIENT, CHANNEL_AMBIENT_OPERATOR_STATE), + new DecimalType(block.ambientOperatorState)); + updateState(channelUID(GROUP_GENERAL_AMBIENT, CHANNEL_AVERAGE_AMBIENT_TEMPERATURE), + getScaled(block.averageAmbientTemperature, CELSIUS)); + updateState(channelUID(GROUP_GENERAL_AMBIENT, CHANNEL_CALCULATED_AMBIENT_TEMPERATURE), + getScaled(block.calculatedAmbientTemperature, CELSIUS)); resetCommunicationError(); } protected void handlePolledEManagerData(ModbusRegisterArray registers) { // logger.trace("EManager block received, size: {}", registers.size()); - EManagerBlock block = emanagerBlockParser.parse(registers); - // EManager group + EManagerBlock block = emanagerBlockParser.parse(registers); + updateState(channelUID(GROUP_GENERAL_EMANAGER, CHANNEL_EMANAGER_ERROR_NUMBER), + new DecimalType(block.emanagerErrorNumber)); + updateState(channelUID(GROUP_GENERAL_EMANAGER, CHANNEL_EMANAGER_OPERATOR_STATE), + new DecimalType(block.emanagerOperatorState)); updateState(channelUID(GROUP_GENERAL_EMANAGER, CHANNEL_ACTUAL_POWER_CONSUMPTION), getUnscaled(block.actualPowerConsumption, WATT)); - updateState(channelUID(GROUP_GENERAL_EMANAGER, CHANNEL_ACTUAL_POWER), getUnscaled(block.actualPower, WATT)); resetCommunicationError(); } protected void handlePolledBoiler1Data(ModbusRegisterArray registers) { - // logger.trace("Boiler1 block received, size: {}", registers.size()); + logger.trace("Boiler1 block received, size: {}", registers.size()); Boiler1Block block = boiler1BlockParser.parse(registers); // Boiler1 group updateState(channelUID(GROUP_BOILER1, CHANNEL_BOILER1_ACTUAL_HIGH_TEMPERATURE), getScaled(block.boiler1ActualHighTemperature, CELSIUS)); + updateState(channelUID(GROUP_BOILER1, CHANNEL_BOILER1_ACTUAL_LOW_TEMPERATURE), + getScaled(block.boiler1ActualLowTemperature, CELSIUS)); resetCommunicationError(); } - protected void handlePolledBoiler150Data(ModbusRegisterArray registers) { - // logger.trace("Boiler150 block received, size: {}", registers.size()); + protected void handlePolledBoiler1MtData(ModbusRegisterArray registers) { + logger.trace("Boiler1Mt block received, size: {}", registers.size()); - Boiler1Block block = boiler150BlockParser.parse(registers); + Boiler1MtBlock block = boiler1mtBlockParser.parse(registers); - // Boiler1 group - updateState(channelUID(GROUP_BOILER150, CHANNEL_BOILER150_MAXIMUM_BOILER_TEMPERATURE), - getScaled(block.boiler150MaximumBoilerTemperature, CELSIUS)); + // Boiler1Mt group + updateState(channelUID(GROUP_BOILER1MT, CHANNEL_BOILER1_MAXIMUM_BOILER_TEMPERATURE), + getScaled(block.boiler1MaximumBoilerTemperature, CELSIUS)); + resetCommunicationError(); + } + + protected void handlePolledBuffer1Data(ModbusRegisterArray registers) { + logger.trace("Buffer1 block received, size: {}", registers.size()); + + Buffer1Block block = buffer1BlockParser.parse(registers); + + // Buffer1 group + updateState(channelUID(GROUP_BUFFER1, CHANNEL_BUFFER1_ACTUAL_HIGH_TEMPERATURE), + getScaled(block.buffer1ActualHighTemperature, CELSIUS)); + updateState(channelUID(GROUP_BUFFER1, CHANNEL_BUFFER1_ACTUAL_LOW_TEMPERATURE), + getScaled(block.buffer1ActualLowTemperature, CELSIUS)); + resetCommunicationError(); + } + + protected void handlePolledBuffer1MtData(ModbusRegisterArray registers) { + logger.trace("Buffer1Mt block received, size: {}", registers.size()); + + Buffer1MtBlock block = buffer1mtBlockParser.parse(registers); + + // Buffer1Mt group + updateState(channelUID(GROUP_BUFFER1MT, CHANNEL_BUFFER1_MAXIMUM_BOILER_TEMPERATURE), + getScaled(block.buffer1MaximumBufferTemperature, CELSIUS)); resetCommunicationError(); } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/AmbientBlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/AmbientBlockParser.java index 3f5c7ea42f768..08c9cd9b60bd5 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/AmbientBlockParser.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/AmbientBlockParser.java @@ -19,7 +19,7 @@ import org.slf4j.LoggerFactory; /** - * Parses inverter modbus data into an Energy Block + * Parses inverter modbus data into an Ambient Block * * @author Paul Frank - Initial contribution * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus @@ -30,9 +30,13 @@ public class AmbientBlockParser extends AbstractBaseParser { private final Logger logger = LoggerFactory.getLogger(AmbientBlockParser.class); public AmbientBlock parse(ModbusRegisterArray raw) { + logger.trace("AmbientBlockParser"); AmbientBlock block = new AmbientBlock(); - + block.ambientErrorNumber = extractUInt16(raw, 0, (short) 0); + block.ambientOperatorState = extractUInt16(raw, 1, (short) 0); block.actualAmbientTemperature = extractUInt16(raw, 2, (short) 0); + block.averageAmbientTemperature = extractUInt16(raw, 3, (short) 0); + block.calculatedAmbientTemperature = extractUInt16(raw, 4, (short) 0); return block; } } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1BlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1BlockParser.java index 6fa2f58324658..579ae527c1880 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1BlockParser.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1BlockParser.java @@ -19,7 +19,7 @@ import org.slf4j.LoggerFactory; /** - * Parses inverter modbus data into an Energy Block + * Parses inverter modbus data into a Boiler Block * * @author Paul Frank - Initial contribution * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus @@ -30,10 +30,11 @@ public class Boiler1BlockParser extends AbstractBaseParser { private final Logger logger = LoggerFactory.getLogger(Boiler1BlockParser.class); public Boiler1Block parse(ModbusRegisterArray raw) { - // logger.trace("Boiler1BlockParser"); + logger.trace("Boiler1BlockParser"); Boiler1Block block = new Boiler1Block(); block.boiler1ActualHighTemperature = extractUInt16(raw, 2, (short) 0); + block.boiler1ActualLowTemperature = extractUInt16(raw, 3, (short) 0); return block; } } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler150BlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1MtBlockParser.java similarity index 66% rename from bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler150BlockParser.java rename to bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1MtBlockParser.java index 3094728da3ec1..af1cc5b5e48f7 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler150BlockParser.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1MtBlockParser.java @@ -13,26 +13,27 @@ package org.openhab.binding.modbus.lambda.internal.parser; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.modbus.lambda.internal.dto.Boiler1MtBlock; import org.openhab.core.io.transport.modbus.ModbusRegisterArray; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * Parses inverter modbus data into an Energy Block + * Parses inverter modbus data into an Boiler1Mt Block - * * @author Paul Frank - Initial contribution * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus * */ @NonNullByDefault -public class Boiler150BlockParser extends AbstractBaseParser { - private final Logger logger = LoggerFactory.getLogger(Boiler150BlockParser.class); +public class Boiler1MtBlockParser extends AbstractBaseParser { + private final Logger logger = LoggerFactory.getLogger(Boiler1MtBlockParser.class); - public Boiler150Block parse(ModbusRegisterArray raw) { - // logger.trace("Boiler150BlockParser"); - Boiler150Block block = new Boiler150Block(); + public Boiler1MtBlock parse(ModbusRegisterArray raw) { + logger.trace("Boiler1MtBlockParser"); + Boiler1MtBlock block = new Boiler1MtBlock(); - block.boiler150MaximumBoilerTemperature = extractUInt16(raw, 2, (short) 0); + block.boiler1MaximumBoilerTemperature = extractUInt16(raw, 0, (short) 0); return block; } } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Buffer1BlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Buffer1BlockParser.java new file mode 100644 index 0000000000000..ba4a16ea1ed0e --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Buffer1BlockParser.java @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.parser; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.modbus.lambda.internal.dto.Buffer1Block; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Parses inverter modbus data into a Buffer Block + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + * + */ +@NonNullByDefault +public class Buffer1BlockParser extends AbstractBaseParser { + private final Logger logger = LoggerFactory.getLogger(Buffer1BlockParser.class); + + public Buffer1Block parse(ModbusRegisterArray raw) { + logger.trace("Buffer1BlockParser"); + Buffer1Block block = new Buffer1Block(); + + block.buffer1ActualHighTemperature = extractUInt16(raw, 2, (short) 0); + block.buffer1ActualLowTemperature = extractUInt16(raw, 3, (short) 0); + return block; + } +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Buffer1MtBlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Buffer1MtBlockParser.java new file mode 100644 index 0000000000000..883ae8b258ed5 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Buffer1MtBlockParser.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.parser; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.modbus.lambda.internal.dto.Buffer1MtBlock; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Parses inverter modbus data into an Buffer1Mt Block - + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + * + */ +@NonNullByDefault +public class Buffer1MtBlockParser extends AbstractBaseParser { + private final Logger logger = LoggerFactory.getLogger(Buffer1MtBlockParser.class); + + public Buffer1MtBlock parse(ModbusRegisterArray raw) { + logger.trace("Buffer1MtBlockParser"); + Buffer1MtBlock block = new Buffer1MtBlock(); + + block.buffer1MaximumBufferTemperature = extractUInt16(raw, 0, (short) 0); + return block; + } +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/EManagerBlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/EManagerBlockParser.java index d9b910d85ccb0..2076df760a8e4 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/EManagerBlockParser.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/EManagerBlockParser.java @@ -17,7 +17,7 @@ import org.openhab.core.io.transport.modbus.ModbusRegisterArray; /** - * Parses inverter modbus data into a SystemB Information lock + * Parses inverter modbus data into an EManger Block * * @author Paul Frank - Initial contribution * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus @@ -28,7 +28,8 @@ public class EManagerBlockParser extends AbstractBaseParser { public EManagerBlock parse(ModbusRegisterArray raw) { EManagerBlock block = new EManagerBlock(); - + block.emanagerErrorNumber = extractUInt16(raw, 0, (short) 0); + block.emanagerOperatorState = extractUInt16(raw, 1, (short) 0); block.actualPower = extractUInt16(raw, 2, (short) 0); block.actualPowerConsumption = extractUInt16(raw, 3, (short) 0); diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/config/config-descriptions.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/config/config-descriptions.xml index b0337590fb686..b11bf549acc02 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/config/config-descriptions.xml +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/config/config-descriptions.xml @@ -9,7 +9,7 @@ Poll interval in seconds. Use zero to disable automatic polling. - 10 + 20 s diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/i18n/lambda.properties b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/i18n/lambda.properties index fba7c965b1cd4..f5638f56b28b7 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/i18n/lambda.properties +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/i18n/lambda.properties @@ -14,12 +14,37 @@ thing-type.config.lambda.modbusconfig.refresh.description = Poll interval in sec channel-group-type.modbus.general-ambient.label = General Ambient channel-group-type.modbus.general-emanager.label = General E-Manager +channel-group-type.modbus.heatpump1.label = Heat Pump 1 channel-group-type.modbus.boiler1.label = Boiler 1 -channel-group-type.modbus.boiler150.label = Boiler 150 +channel-group-type.modbus.boiler1mt.label = Boiler 1 Maximum Temperature +channel-group-type.modbus.buffer1.label = Buffer 1 +channel-group-type.modbus.buffer1mt.label = Buffer 1 Maximum Temperature + # channel types +# General Ambient +channel-type.modbus.ambient-error-number-type.label = Ambient Error Number +channel-type.modbus.ambient-operator-state-type.label = Ambient Operator State channel-type.modbus.actual-ambient-temperature-type.label = Actual Ambient Temperature +channel-type.modbus.average-ambient-temperature-type.label = Average Ambient Temperature 1h +channel-type.modbus.calculated-ambient-temperature-type.label = Calculated Ambient Temperature + +# General E-Manager +channel-type.modbus.emanager-error-number-type.label = E-Manager Error Number +channel-type.modbus.emanager-operator-state-type.label = E-Manager Operator State channel-type.modbus.actual-power-type.label = Actual Power (input or excess) channel-type.modbus.actual-power-consumption-type.label = Actual Power Consumption + +# Heat Pump 1 +channel-type.modbus.heatpump1-t-flow-type.label = Heat Pump 1 T-Flow + +# Boiler 1 channel-type.modbus.boiler1-actual-high-temperature-type.label = Boiler 1 Actual High Temperature -channel-type.modbus.boiler150-maximum-boiler-temperature-type.label = Boiler 1 Maximum Boiler Temperature +channel-type.modbus.boiler1-actual-low-temperature-type.label = Boiler 1 Actual Low Temperature +channel-type.modbus.boiler1-maximum-boiler-temperature-type.label = Boiler 1 Maximum Temperature + +# Buffer 1 +channel-type.modbus.buffer1-actual-high-temperature-type.label = Buffer 1 Actual High Temperature +channel-type.modbus.buffer1-actual-low-temperature-type.label = Buffer 1 Actual Low Temperature +channel-type.modbus.buffer1-maximum-buffer-temperature-type.label = Buffer 1 Maximum Temperature + diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-groups.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-groups.xml index e34f8f6e1edb2..c0068b24fd364 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-groups.xml +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-groups.xml @@ -7,32 +7,63 @@ + + - + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + + - - + + diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-types.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-types.xml index 9c72ddbb85acd..604586cc854f5 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-types.xml +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-types.xml @@ -4,12 +4,72 @@ 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"> + + + Number + + + + + + + + + + Number + + + + + + + + + + + Number:Temperature + + + + + Number:Temperature + + + Number:Temperature + + + + + + Number + + + + + + + + + + Number + + + + + + + + + + + + Number:Power @@ -22,15 +82,47 @@ + + + Number:Temperature + + + + Number:Temperature - + + Number:Temperature + + + + + Number:Temperature + + + Number:Temperature + + + + + + Number:Temperature + + + + + + Number:Temperature + + + + diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-types.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-types.xml index 47c3280ec8115..fff32568db2a2 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-types.xml +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-types.xml @@ -9,14 +9,16 @@ - Lambda Heat connected through modbus + Lambda Heat Pump connected through modbus - - - + + + + + From 9f13e8ef48e756bf3916529e3a22989b2f24bf3b Mon Sep 17 00:00:00 2001 From: Christian Koch <78686276+chilobo@users.noreply.github.com> Date: Sun, 20 Oct 2024 17:19:01 +0200 Subject: [PATCH 4/8] I am rebasing to Version 0.2 of Lambda Heat Pump Bundle Based on the Stiebel Eltron Modubs Bundle by Paul Frank Signed-off-by: Christian Koch Signed-off-by: Christian Koch <78686276+chilobo@users.noreply.github.com> --- .../README.md | 281 ++++++------ .../org.openhab.binding.modbus.lambda/pom.xml | 1 - .../internal/LambdaBindingConstants.java | 41 +- .../lambda/internal/LambdaConfiguration.java | 2 +- .../lambda/internal/dto/AmbientBlock.java | 2 +- .../lambda/internal/dto/Boiler1Block.java | 3 +- .../lambda/internal/dto/Buffer1Block.java | 3 +- .../lambda/internal/dto/EManagerBlock.java | 3 +- .../internal/dto/HeatingCircuit1Block.java | 31 ++ .../dto/HeatingCircuit1SettingBlock.java | 28 ++ .../lambda/internal/dto/Heatpump1Block.java | 37 ++ .../internal/dto/Heatpump1SetBlock.java | 25 + .../internal/handler/LambdaHandler.java | 431 +++++++++++++++--- .../internal/parser/AmbientBlockParser.java | 8 +- .../internal/parser/Boiler1BlockParser.java | 9 +- .../internal/parser/Boiler1MtBlockParser.java | 7 +- .../internal/parser/Buffer1BlockParser.java | 9 +- .../internal/parser/Buffer1MtBlockParser.java | 7 +- .../internal/parser/EManagerBlockParser.java | 3 +- .../parser/HeatingCircuit1BlockParser.java | 41 ++ .../HeatingCircuit1SettingBlockParser.java | 37 ++ .../internal/parser/Heatpump1BlockParser.java | 47 ++ .../parser/Heatpump1SetBlockParser.java | 34 ++ .../resources/OH-INF/i18n/lambda.properties | 52 ++- .../OH-INF/thing/lambdahp-channel-groups.xml | 56 ++- .../OH-INF/thing/lambdahp-channel-types.xml | 316 ++++++++++++- .../resources/OH-INF/thing/lambdahp-types.xml | 4 +- 27 files changed, 1222 insertions(+), 296 deletions(-) create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatingCircuit1Block.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatingCircuit1SettingBlock.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Heatpump1Block.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Heatpump1SetBlock.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatingCircuit1BlockParser.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatingCircuit1SettingBlockParser.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Heatpump1BlockParser.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Heatpump1SetBlockParser.java diff --git a/bundles/org.openhab.binding.modbus.lambda/README.md b/bundles/org.openhab.binding.modbus.lambda/README.md index c507c083c3c94..5c2f2073176d4 100644 --- a/bundles/org.openhab.binding.modbus.lambda/README.md +++ b/bundles/org.openhab.binding.modbus.lambda/README.md @@ -1,9 +1,21 @@ -# Stiebel Eltron ISG +# Lambda Heat Pump -This extension adds support for the Stiebel Eltron modbus protocol. +This extension adds support for the Lambda Heat Pump modbus protocol as provided by +https://lambda-wp.at/wp-content/uploads/2022/01/Modbus-Protokoll-und-Beschreibung.pdf + +A Lambda Heat Pump has to be reachable within your network. +If you plan to use the E-Manager part to hand over your PV excess to the heat pump ask Lambda support to +configure it to +E-Meter Kommunikationsart: ModBus Client +E-Meter Messpunkt: E-Eintrag + +Other configurations of the E-Manager are not supported (yet). + +Up to now only the following configuration is supported: +- only one heatpump(heatpump1) +- only one buffer for the heating(buffer1) +- only one buffer for the water heating boiler1) -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: ## Supported Things @@ -12,7 +24,7 @@ Note, that the things will show up under the Modbus binding. | Thing | ThingTypeID | Description | | ------------------ | ----------- | --------------------------------------------------- | -| Stiebel Eltron ISG | lambdahp | A stiebel eltron heat pump connected through an ISG | +| Lambda Heat Pump | lambdahp | A lambda heat pump visible in the local network | ## Discovery @@ -26,174 +38,137 @@ 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. +You first need to set up a TCP Modbus bridge according to the Modbus documentation. +You then add the lambda heat pump as part of the modbus binding. 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 | +| refresh | integer | no | 30 | 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 +### General Ambient 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 +| Channel ID | Item Type | Read only | Unit | Description | +| -------------------------------- | ------------------ | --------- | -------- | ------------------------------------------------------------------------ | +| ambient-error-number | Number | true | [Nr] | Ambient Error Number (0 = No error) | +| ambient-operating-state | Number | true | [Nr] | Ambient Operating State (0 = OFF, 1 = AUTOMATIC, 2 = MANUAL, 3 = ERROR) | +| actual-ambient-temperature | Number:Temperature | false | [0.1 °C] | Actual Ambient Temperature (min = -50.0°C); max = 80.0° | +| average-ambient-temperature | Number:Temperature | true | [0.1 °C] | Arithmetic average temperature of the last 60 minutes | +| calculated-ambient-temperature | Number:Temperature | true | [0.1 °C] | Temperature for calculations in heat distribution modules | -### Thing Configuration +### General E-Manager Group -```java -Bridge modbus:tcp:bridge "Stiebel Modbus TCP"[ host="hostname|ip", port=502, id=1 ] { - Thing lambdahp lambda "Lambda" (modbus:tcp:modbusbridge) @"Room" [ ] -} -``` +This group contains parameters signaling the PV excess to the heat pump. -### Item Configuration +| Channel ID | Item Type | Read only | Unit | Description | +| -------------------------------- | ------------------ | --------- | -------- | --------------------------------------------------------------------------------------- | +| emanager-error-number | Number | true | [Nr] | E-Manager Error Number (0 = No error) | +| emanager-operating-state | Number | true | [Nr] | E-Manager Operating State (0 = OFF, 1 = AUTOMATIC, 2 = MANUAL, 3 = ERROR 4 = OFFLINE | +| actual-power | Number:Power | false | [W] | Actual excess power -32768 W .. 32767 W | +| actual-power-consumption | Number:Power | true | [W] | Power consumption of heatpump 1 (only valid when Betriebsart: Automatik, 0 W otherwise) | +| power-consumption-setpoint | Number:Power | false | [W] | Power consumption setpoint for heat pump 1 | -```java -Number:Temperature stiebel_eltron_temperature_fek "Temperature FEK [%.1f °C]" { channel="modbus:lambdahp:lambda:systemInformation#fek-temperature" } -Number:Temperature stiebel_eltron_setpoint_fek "Set point FEK [%.1f °C]" { channel="modbus:lambdahp:lambda:systemInformation#fek-temperature-setpoint" } -Number:Dimensionless stiebel_eltron_humidity_fek "Humidity FEK [%.1f %%]" { channel="modbus:lambdahp:lambda:systemInformation#fek-humidity" } -Number:Temperature stiebel_eltron_dewpoint_fek "Dew point FEK [%.1f °C]" { channel="modbus:lambdahp:lambda:systemInformation#fek-dewpoint" } - -Number:Temperature stiebel_eltron_outdoor_temp "Outdoor temperature [%.1f °C]" { channel="modbus:lambdahp:lambda:systemInformation#outdoor-temperature" } -Number:Temperature stiebel_eltron_temp_hk1 "Temperature HK1 [%.1f °C]" { channel="modbus:lambdahp:lambda:systemInformation#hk1-temperature" } -Number:Temperature stiebel_eltron_setpoint_hk1 "Set point HK1 [%.1f °C]" { channel="modbus:lambdahp:lambda:systemInformation#hk1-temperature-setpoint" } -Number:Temperature stiebel_eltron_temp_water "Water temperature [%.1f °C]" { channel="modbus:lambdahp:lambda:systemInformation#water-temperature" } -Number:Temperature stiebel_eltron_setpoint_water "Water setpoint [%.1f °C]" { channel="modbus:lambdahp:lambda:systemInformation#water-temperature-setpoint" } -Number:Temperature stiebel_eltron_source_temp "Source temperature [%.1f °C]" { channel="modbus:lambdahp:lambda:systemInformation#source-temperature" } -Number:Temperature stiebel_eltron_vorlauf_temp "Supply tempertature [%.1f °C]" { channel="modbus:lambdahp:lambda:systemInformation#supply-temperature" } -Number:Temperature stiebel_eltron_ruecklauf_temp "Return temperature [%.1f °C]" { channel="modbus:lambdahp:lambda:systemInformation#return-temperature" } - -Number stiebel_eltron_heating_comfort_temp "Heating Comfort Temperature [%.1f °C]" { channel="modbus:lambdahp:lambda:systemParameter#comfort-temperature-heating" } -Number stiebel_eltron_heating_eco_temp "Heating Eco Temperature [%.1f °C]" { channel="modbus:lambdahp:lambda:systemParameter#eco-temperature-heating" } -Number stiebel_eltron_water_comfort_temp "Water Comfort Temperature [%.1f °C]" { channel="modbus:lambdahp:lambda:systemParameter#comfort-temperature-water" } -Number stiebel_eltron_water_eco_temp "Water Eco Temperature [%.1f °C]" { channel="modbus:lambdahp:lambda:systemParameter#eco-temperature-water" } -Number stiebel_eltron_operation_mode "Operation Mode" { channel="modbus:lambdahp:lambda:systemParameter#operation-mode" } - -Contact stiebel_eltron_mode_pump "Pump [%d]" { channel="modbus:lambdahp:lambda:systemState#is-pumping" } -Contact stiebel_eltron_mode_heating "Heating [%d]" { channel="modbus:lambdahp:lambda:systemState#is-heating" } -Contact stiebel_eltron_mode_water "Heating Water [%d]" { channel="modbus:lambdahp:lambda:systemState#is-heating-water" } -Contact stiebel_eltron_mode_cooling "Cooling [%d]" { channel="modbus:lambdahp:lambda:systemState#is-cooling" } -Contact stiebel_eltron_mode_summer "Summer Mode [%d]" { channel="modbus:lambdahp:lambda:systemState#is-summer" } - - -Number:Energy stiebel_eltron_production_heat_today "Heat quantity today [%.0f kWh]" { channel="modbus:lambdahp:lambda:energyInformation#production_heat_today" } -Number:Energy stiebel_eltron_production_heat_total "Heat quantity total [%.3f MWh]" {channel="modbus:lambdahp:lambda:energyInformation#production_heat_total"} -Number:Energy stiebel_eltron_production_water_today "Water heat quantity today [%.0f kWh]" { channel="modbus:lambdahp:lambda:energyInformation#production_water_today" } -Number:Energy stiebel_eltron_production_water_total "Water heat quantity total [%.3f MWh]" {channel="modbus:lambdahp:lambda:energyInformation#production_water_total"} -Number:Energy stiebel_eltron_consumption_heat_total "Heating power consumption total [%.3f MWh]" {channel="modbus:lambdahp:lambda:energyInformation#consumption_heat_total"} -Number:Energy stiebel_eltron_consumption_heat_today "Heating power consumption today [%.0f kWh]" { channel="modbus:lambdahp:lambda:energyInformation#consumption_heat_today" } -Number:Energy stiebel_eltron_consumption_water_today "Water heating power consumption today [%.0f kWh]" { channel="modbus:lambdahp:lambda:energyInformation#consumption_water_today" } -Number:Energy stiebel_eltron_consumption_water_total "Water heating power consumption total [%.3f MWh]" {channel="modbus:lambdahp:lambda:energyInformation#consumption_water_total"} -``` +### Heat Pump 1 Group + +This group contains general operational information about the heat pump itself. + +| Channel ID | Item Type | Read only | Unit | Description | +| -------------------------------| ------------------------- | --------- | ------------ | ----------------------------------------------------------------------- | +| heatpump1-error-state | Number | true | [Nr] | Error state (0 = NONE, 1 = MESSAGE, 2 = WARNING, 3 = ALARM, 4 = FAULT )| +| heatpump1-error-number | Number | true | [Nr] | Error number: scrolling through all active error number (1..99) | +| heatpump1-state | Number | true | [Nr] | State: See Modbus description manual of the manufacterer | +| heatpump1-operating-state | Number | true | [Nr] | Operating State: See Modbus description manual, link above | +| heatpump1-t-flow | Number:Temperature | true | [0.01°C] | Flow line termperature | +| heatpump1-t-return | Number:Temperature | true | [0.01°C] | Return line temperature | +| heatpump1-vol-sink | Number:VolumetricFlowRate | true | [0.01 l/min] | Volume flow heat sink | +| heatpump1-t-eqin | Number:Temperature | true | [0.01°C] | Energy source inlet temperature | +| heatpump1-t-eqout | Number:Temperature | true | [0.01°C] | Energy source outlet temperature | +| heatpump1-vol-source | Number:VolumetricFlowRate | true | [0.01 l/min] | Volume flow energy source | +| heatpump1-compressor-rating | Number | true | [0.01%] | Compressor unit rating | +| heatpump1-qp-heating | Number:Power | true | [0.1kW] | Actual heating capacity | +| heatpump1-fi-power-consumption | Number:Power | true | [W] | Frequency inverter actual power consumption | +| heatpump1-cop | Number | true | [0.01%] | Coefficient of performance | +| heatpump1-set-error-quit | Number | false | [Nr] | Set Error Quit (1 = Quit all active heat pump errors | + + +### Boiler 1 Group + +This group contains information about the boiler for the water for domestic use / tap water / washwater. + +| Channel ID | Item Type | Read only | Unit | Description | +| ---------------------------------- | ------------------ | --------- | -------- | --------------------------------------------------------------------| +| boiler1-error-number | Number | true | [Nr] | Boiler 1 Error Number(0 = No error) | +| boiler1-operating-state | Number | true | [Nr] | Boiler 1 Operating State: See Modbus description manual, link above | +| boiler1-actual-high-temperature | Number:Temperature | true | [0.1 °C] | Actual temperature boiler high sensor | +| boiler1-actual-low-temperature | Number:Temperature | true | [0.1 °C] | Actual temperature boiler low sensor | +| boiler1-maximum-boiler-temperature | Number:Temperature | false | [0.1 °C] | Setting for maximum boiler temperature (min = 25.0°C; max = 65.0°C) | + +### Buffer 1 Group + +This group contains information about the buffer for the heating circuit. + +| Channel ID | Item Type | Read only | Unit | Description | +| ------------------------------- | ------------------ | --------- | -------- | -----------------------------------------------------------------------| +| buffer1-error-number | Number | true | [Nr] | Buffer 1 Error Number (0 = No error) | +| buffer1-operating-state | Number | true | [Nr] | Buffer 1 Operating State: See Modbus description manual, link above | +| buffer1-actual-high-temperature | Number:Temperature | true | [0.1 °C] | Actual temperature buffer high sensor | +| buffer1-actual-low-temperature | Number:Temperature | true | [0.1 °C] | Actual temperature buffer low sensor | +| Buffer 1 Maximum Temperature | Number:Temperature | false | [0.1 °C] | Setting for maximum buffer temperature (min = 25.0°C; max = 65.0°C) | + + +### Heating Circuit 1 Group + +This group contains general operational information about the heating circuit 1. + +| Channel ID | Item Type | Read only | Unit | Description | +| ---------------------------------------------- | -------------------| --------- | ------------ | --------------------------------------------------------------------------------| +| heatingcircuit1-error-number | Number | true | [Nr] | Error Number (0 = No error) | +| heatingcircuit1-operating-state | Number | true | [Nr] | Operating State: See Modbus description manual, link above| | +| heatingcircuit1-flow-line-temperature | Number:Temperature | true | [Nr] | Actual temperature flow line sensor | +| heatingcircuit1-return-line-temperature | Number:Temperature | true | [Nr] | Actual temperature return line sensor | +| heatingcircuit1-room-device-temperature | Number:Temperature | true | [0.01°C] | Actual temperature room device sensor (min = -29.9°C; max = 99.9°C) | +| heatingcircuit1-setpoint-flow-line-temperature | Number:Temperature | true | [0.01°C] | Setpoint temperature flow line (min = 15.0°C; max = 65.0°C) | +| heatingcircuit1-operating-mode | Number | true | [Nr] | Operating Mode: See Modbus description manual, link above | +| heatingcircuit1-offset-flow-line-temperature | Number:Temperature | true | [0.01°C] | Setting for flow line temperature setpoint offset(min = -10.0K; max = 10.0K) | +| heatingcircuit1-room-heating-temperature | Number:Temperature | rue | [0.01°C] | Setting for heating mode room setpoint temperature(min = 15.0°C; max = 40.0 °C) | +| eatingcircuit1-room-cooling-temperature | Number:Temperature | true | [0.01 l/min] | Setting for cooling mode room setpoint temperature(min = 15.0°C; max = 40.0 °C) | + + + +## Full Example + +### Thing Configuration +UID: modbus:tcp:Lambda_Bridge +label: Lambda Modbus Bridge +thingTypeUID: modbus:tcp +configuration: + rtuEncoded: false + connectMaxTries: 1 + reconnectAfterMillis: 0 + timeBetweenTransactionsMillis: 100 + port: 502 + timeBetweenReconnectMillis: 0 + connectTimeoutMillis: 10000 + host: 192.168.223.83 + afterConnectionDelayMillis: 0 + id: 1 + enableDiscovery: false + +### Example to write PV excess to the Lambda Heat Pump +// PV_Battery.state and PV_Grid have to be provided by your PV inverter +// Mode of E-Manager has to be switched to AUTOMATIK in the Lambda Heat Pump App +var int P_Available = ((Lambda_EMgr_Power_Consumption_Value_as_Number.state as Number) - (PW_Battery.state as Number) - (PW_Grid.state as Number)).intValue + lambdahp_actual_power.sendCommand(P_Available) -### Sitemap Configuration - -```perl -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_fek icon="temperature" - Default item=stiebel_eltron_setpoint_fek icon="temperature" - Default item=stiebel_eltron_humidity_fek icon="humidity" - Default item=stiebel_eltron_dewpoint_fek 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.lambda/pom.xml b/bundles/org.openhab.binding.modbus.lambda/pom.xml index cf593d3dec533..e2582d6419e97 100644 --- a/bundles/org.openhab.binding.modbus.lambda/pom.xml +++ b/bundles/org.openhab.binding.modbus.lambda/pom.xml @@ -3,7 +3,6 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.openhab.addons.bundles org.openhab.addons.reactor.bundles diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaBindingConstants.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaBindingConstants.java index 7b3bd8463a0aa..31bb067db6bdb 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaBindingConstants.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaBindingConstants.java @@ -35,35 +35,70 @@ public class LambdaBindingConstants { public static final String GROUP_GENERAL_AMBIENT = "generalAmbient"; public static final String GROUP_GENERAL_EMANAGER = "generalEManager"; public static final String GROUP_HEATPUMP1 = "Heatpump1"; + public static final String GROUP_HEATPUMP1SET = "Heatpump1Set"; public static final String GROUP_BOILER1 = "Boiler1"; public static final String GROUP_BOILER1MT = "Boiler1Mt"; public static final String GROUP_BUFFER1 = "Buffer1"; public static final String GROUP_BUFFER1MT = "Buffer1Mt"; + public static final String GROUP_HEATINGCIRCUIT1 = "HeatingCircuit1"; + public static final String GROUP_HEATINGCIRCUIT1SETTING = "HeatingCircuit1Setting"; // List of all Channel ids in device information group // General Ambient public static final String CHANNEL_AMBIENT_ERROR_NUMBER = "ambient-error-number"; - public static final String CHANNEL_AMBIENT_OPERATOR_STATE = "ambient-operator-state"; + public static final String CHANNEL_AMBIENT_OPERATING_STATE = "ambient-operating-state"; public static final String CHANNEL_ACTUAL_AMBIENT_TEMPERATURE = "actual-ambient-temperature"; public static final String CHANNEL_AVERAGE_AMBIENT_TEMPERATURE = "average-ambient-temperature"; public static final String CHANNEL_CALCULATED_AMBIENT_TEMPERATURE = "calculated-ambient-temperature"; // General E-manager public static final String CHANNEL_EMANAGER_ERROR_NUMBER = "emanager-error-number"; - public static final String CHANNEL_EMANAGER_OPERATOR_STATE = "emanager-operator-state"; + public static final String CHANNEL_EMANAGER_OPERATING_STATE = "emanager-operating-state"; public static final String CHANNEL_ACTUAL_POWER = "actual-power"; public static final String CHANNEL_ACTUAL_POWER_CONSUMPTION = "actual-power-consumption"; + public static final String CHANNEL_POWER_CONSUMPTION_SETPOINT = "power-consumption-setpoint"; // Heatpump 1 - public static final String CHANNEL_HEATPUMP1_TFLOW = "heatpump1-t-flow"; + public static final String CHANNEL_HEATPUMP1_ERROR_STATE = "heatpump1-error-state"; + public static final String CHANNEL_HEATPUMP1_ERROR_NUMBER = "heatpump1-error-number"; + public static final String CHANNEL_HEATPUMP1_STATE = "heatpump1-state"; + public static final String CHANNEL_HEATPUMP1_OPERATING_STATE = "heatpump1-operating-state"; + public static final String CHANNEL_HEATPUMP1_T_FLOW = "heatpump1-t-flow"; + public static final String CHANNEL_HEATPUMP1_T_RETURN = "heatpump1-t-return"; + public static final String CHANNEL_HEATPUMP1_VOL_SINK = "heatpump1-vol-sink"; + public static final String CHANNEL_HEATPUMP1_T_EQIN = "heatpump1-t-eqin"; + public static final String CHANNEL_HEATPUMP1_T_EQOUT = "heatpump1-t-eqout"; + public static final String CHANNEL_HEATPUMP1_VOL_SOURCE = "heatpump1-vol-source"; + public static final String CHANNEL_HEATPUMP1_COMPRESSOR_RATING = "heatpump1-compressor-rating"; + public static final String CHANNEL_HEATPUMP1_QP_HEATING = "heatpump1-qp-heating"; + public static final String CHANNEL_HEATPUMP1_FI_POWER_CONSUMPTION = "heatpump1-fi-power-consumption"; + public static final String CHANNEL_HEATPUMP1_COP = "heatpump1-cop"; + public static final String CHANNEL_HEATPUMP1_SET_ERROR_QUIT = "heatpump1-set-error-quit"; // Boiler 1 + public static final String CHANNEL_BOILER1_ERROR_NUMBER = "boiler1-error-number"; + public static final String CHANNEL_BOILER1_OPERATING_STATE = "boiler1-operating-state"; public static final String CHANNEL_BOILER1_ACTUAL_HIGH_TEMPERATURE = "boiler1-actual-high-temperature"; public static final String CHANNEL_BOILER1_ACTUAL_LOW_TEMPERATURE = "boiler1-actual-low-temperature"; public static final String CHANNEL_BOILER1_MAXIMUM_BOILER_TEMPERATURE = "boiler1-maximum-boiler-temperature"; // Buffer 1 + public static final String CHANNEL_BUFFER1_ERROR_NUMBER = "buffer1-error-number"; + public static final String CHANNEL_BUFFER1_OPERATING_STATE = "buffer1-operating-state"; public static final String CHANNEL_BUFFER1_ACTUAL_HIGH_TEMPERATURE = "buffer1-actual-high-temperature"; public static final String CHANNEL_BUFFER1_ACTUAL_LOW_TEMPERATURE = "buffer1-actual-low-temperature"; public static final String CHANNEL_BUFFER1_MAXIMUM_BOILER_TEMPERATURE = "buffer1-maximum-boiler-temperature"; + + // Heating Circuit 1 + public static final String CHANNEL_HEATINGCIRCUIT1_ERROR_NUMBER = "heatingcircuit1-error-number"; + public static final String CHANNEL_HEATINGCIRCUIT1_OPERATING_STATE = "heatingcircuit1-operating-state"; + public static final String CHANNEL_HEATINGCIRCUIT1_FLOW_LINE_TEMPERATURE = "heatingcircuit1-flow-line-temperature"; + public static final String CHANNEL_HEATINGCIRCUIT1_RETURN_LINE_TEMPERATURE = "heatingcircuit1-return-line-temperature"; + public static final String CHANNEL_HEATINGCIRCUIT1_ROOM_DEVICE_TEMPERATURE = "heatingcircuit1-room-device-temperature"; + public static final String CHANNEL_HEATINGCIRCUIT1_SETPOINT_FLOW_LINE_TEMPERATURE = "heatingcircuit1-setpoint-flow-line-temperature"; + public static final String CHANNEL_HEATINGCIRCUIT1_OPERATING_MODE = "heatingcircuit1-operating-mode"; + // Heating Cirucuit 1 Set + public static final String CHANNEL_HEATINGCIRCUIT1_OFFSET_FLOW_LINE_TEMPERATURE = "heatingcircuit1-offset-flow-line-temperature"; + public static final String CHANNEL_HEATINGCIRCUIT1_ROOM_HEATING_TEMPERATURE = "heatingcircuit1-room-heating-temperature"; + public static final String CHANNEL_HEATINGCIRCUIT1_ROOM_COOLING_TEMPERATURE = "heatingcircuit1-room-cooling-temperature"; } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaConfiguration.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaConfiguration.java index bfc652005d894..d1c0f6f2217dd 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaConfiguration.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaConfiguration.java @@ -26,7 +26,7 @@ public class LambdaConfiguration { /** * Refresh interval in seconds */ - private long refresh; + private long refresh = 30; private int maxTries = 3;// backwards compatibility and tests diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/AmbientBlock.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/AmbientBlock.java index 46309bda428ea..cb765cdef0b45 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/AmbientBlock.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/AmbientBlock.java @@ -21,7 +21,7 @@ */ public class AmbientBlock { public int ambientErrorNumber; - public int ambientOperatorState; + public int ambientOperatingState; public int actualAmbientTemperature; public int averageAmbientTemperature; public int calculatedAmbientTemperature; diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler1Block.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler1Block.java index 0bf391cb8179f..23df14de5e12b 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler1Block.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler1Block.java @@ -20,7 +20,8 @@ * */ public class Boiler1Block { - + public int boiler1ErrorNumber; + public int boiler1OperatingState; public int boiler1ActualHighTemperature; public int boiler1ActualLowTemperature; } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Buffer1Block.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Buffer1Block.java index d454287868a15..6af532d4ce044 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Buffer1Block.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Buffer1Block.java @@ -20,7 +20,8 @@ * */ public class Buffer1Block { - + public int buffer1ErrorNumber; + public int buffer1OperatingState; public int buffer1ActualHighTemperature; public int buffer1ActualLowTemperature; } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/EManagerBlock.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/EManagerBlock.java index 210f8419f8f52..a0298ac4dc888 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/EManagerBlock.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/EManagerBlock.java @@ -21,7 +21,8 @@ */ public class EManagerBlock { public int emanagerErrorNumber; - public int emanagerOperatorState; + public int emanagerOperatingState; public int actualPower; public int actualPowerConsumption; + public int powerConsumptionSetpoint; } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatingCircuit1Block.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatingCircuit1Block.java new file mode 100644 index 0000000000000..17fd2267a0994 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatingCircuit1Block.java @@ -0,0 +1,31 @@ +package org.openhab.binding.modbus.lambda.internal.dto; +/** + * Copyright (c) 2010-2024 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 + */ + +/** + * Dto class for the HeatingCircuit1 Block + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + * + */ +public class HeatingCircuit1Block { + + public int heatingcircuit1ErrorNumber; + public int heatingcircuit1OperatingState; + public int heatingcircuit1FlowLineTemperature; + public int heatingcircuit1ReturnLineTemperature; + public int heatingcircuit1RoomDeviceTemperature; + public int heatingcircuit1SetpointFlowLineTemperature; + public int heatingcircuit1OperatingMode; +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatingCircuit1SettingBlock.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatingCircuit1SettingBlock.java new file mode 100644 index 0000000000000..325d0809718d2 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatingCircuit1SettingBlock.java @@ -0,0 +1,28 @@ +package org.openhab.binding.modbus.lambda.internal.dto; + +/** + * Copyright (c) 2010-2024 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 + */ + +/** + * Dto class for the HeatingCircuit1Setting Block + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + * + */ + +public class HeatingCircuit1SettingBlock { + public int heatingcircuit1OffsetFlowLineTemperature; + public int heatingcircuit1RoomHeatingTemperature; + public int heatingcircuit1RoomCoolingTemperature; +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Heatpump1Block.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Heatpump1Block.java new file mode 100644 index 0000000000000..e88df2b93c1c0 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Heatpump1Block.java @@ -0,0 +1,37 @@ +package org.openhab.binding.modbus.lambda.internal.dto; +/** + * Copyright (c) 2010-2024 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 + */ + +/** + * Dto class for the Heatpump1 Block + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + * + */ +public class Heatpump1Block { + public int heatpump1ErrorState; + public int heatpump1ErrorNumber; + public int heatpump1State; + public int heatpump1OperatingState; + public int heatpump1TFlow; + public int heatpump1TReturn; + public int heatpump1VolSink; + public int heatpump1TEQin; + public int heatpump1TEQout; + public int heatpump1VolSource; + public int heatpump1CompressorRating; + public int heatpump1QpHeating; + public int heatpump1FIPowerConsumption; + public int heatpump1COP; +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Heatpump1SetBlock.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Heatpump1SetBlock.java new file mode 100644 index 0000000000000..8dbba697d878f --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Heatpump1SetBlock.java @@ -0,0 +1,25 @@ +package org.openhab.binding.modbus.lambda.internal.dto; +/** + * Copyright (c) 2010-2024 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 + */ + +/** + * Dto class for the Heatpump1 Block + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + * + */ +public class Heatpump1SetBlock { + + public int heatpump1seterrorquit; +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/LambdaHandler.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/LambdaHandler.java index f0de021ce98f8..752ba9134a2cd 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/LambdaHandler.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/LambdaHandler.java @@ -31,12 +31,20 @@ import org.openhab.binding.modbus.lambda.internal.dto.Buffer1Block; import org.openhab.binding.modbus.lambda.internal.dto.Buffer1MtBlock; import org.openhab.binding.modbus.lambda.internal.dto.EManagerBlock; +import org.openhab.binding.modbus.lambda.internal.dto.HeatingCircuit1Block; +import org.openhab.binding.modbus.lambda.internal.dto.HeatingCircuit1SettingBlock; +import org.openhab.binding.modbus.lambda.internal.dto.Heatpump1Block; +import org.openhab.binding.modbus.lambda.internal.dto.Heatpump1SetBlock; import org.openhab.binding.modbus.lambda.internal.parser.AmbientBlockParser; import org.openhab.binding.modbus.lambda.internal.parser.Boiler1BlockParser; import org.openhab.binding.modbus.lambda.internal.parser.Boiler1MtBlockParser; import org.openhab.binding.modbus.lambda.internal.parser.Buffer1BlockParser; import org.openhab.binding.modbus.lambda.internal.parser.Buffer1MtBlockParser; import org.openhab.binding.modbus.lambda.internal.parser.EManagerBlockParser; +import org.openhab.binding.modbus.lambda.internal.parser.HeatingCircuit1BlockParser; +import org.openhab.binding.modbus.lambda.internal.parser.HeatingCircuit1SettingBlockParser; +import org.openhab.binding.modbus.lambda.internal.parser.Heatpump1BlockParser; +import org.openhab.binding.modbus.lambda.internal.parser.Heatpump1SetBlockParser; import org.openhab.core.io.transport.modbus.AsyncModbusFailure; import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode; @@ -147,16 +155,24 @@ public synchronized void poll() { private final Boiler1MtBlockParser boiler1mtBlockParser = new Boiler1MtBlockParser(); private final Buffer1BlockParser buffer1BlockParser = new Buffer1BlockParser(); private final Buffer1MtBlockParser buffer1mtBlockParser = new Buffer1MtBlockParser(); + private final Heatpump1BlockParser heatpump1BlockParser = new Heatpump1BlockParser(); + private final Heatpump1SetBlockParser heatpump1SetBlockParser = new Heatpump1SetBlockParser(); + private final HeatingCircuit1BlockParser heatingcircuit1BlockParser = new HeatingCircuit1BlockParser(); + private final HeatingCircuit1SettingBlockParser heatingcircuit1settingBlockParser = new HeatingCircuit1SettingBlockParser(); /** * These are the tasks used to poll the device */ private volatile @Nullable AbstractBasePoller ambientPoller = null; private volatile @Nullable AbstractBasePoller emanagerPoller = null; + private volatile @Nullable AbstractBasePoller heatpump1Poller = null; + private volatile @Nullable AbstractBasePoller heatpump1SetPoller = null; private volatile @Nullable AbstractBasePoller boiler1Poller = null; private volatile @Nullable AbstractBasePoller boiler1mtPoller = null; private volatile @Nullable AbstractBasePoller buffer1Poller = null; private volatile @Nullable AbstractBasePoller buffer1mtPoller = null; + private volatile @Nullable AbstractBasePoller heatingcircuit1Poller = null; + private volatile @Nullable AbstractBasePoller heatingcircuit1settingPoller = null; /** * Communication interface to the slave endpoint we're connecting to */ @@ -180,7 +196,7 @@ public LambdaHandler(Thing thing) { * @param shortValue value to be written on the modbus */ protected void writeInt16(int address, short shortValue) { - logger.trace("171 writeInt16: Es wird geschrieben, Adresse: {} Wert: {}", address, shortValue); + logger.trace("187 writeInt16: Es wird geschrieben, Adresse: {} Wert: {}", address, shortValue); LambdaConfiguration myconfig = LambdaHandler.this.config; ModbusCommunicationInterface mycomms = LambdaHandler.this.comms; @@ -192,11 +208,9 @@ protected void writeInt16(int address, short shortValue) { byte lo = (byte) shortValue; ModbusRegisterArray data = new ModbusRegisterArray(hi, lo); - logger.trace("183 hi: {}, lo: {}", hi, lo); + logger.trace("199 hi: {}, lo: {}", hi, lo); ModbusWriteRegisterRequestBlueprint request = new ModbusWriteRegisterRequestBlueprint(slaveId, address, data, true, myconfig.getMaxTries()); - // 15.8.24 13:40 war: - // false, myconfig.getMaxTries()); mycomms.submitOneTimeWrite(request, result -> { if (hasConfigurationError()) { @@ -214,37 +228,68 @@ protected void writeInt16(int address, short shortValue) { * @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 getScaled10Int16Value(Command command) throws LambdaException { + * if (command instanceof QuantityType quantityCommand) { + * QuantityType c = quantityCommand.toUnit(CELSIUS); + * if (c != null) { + * return (short) (c.doubleValue() * 10); + * } else { + * throw new LambdaException("Unsupported unit"); + * } + * } + * if (command instanceof DecimalType c) { + * return (short) (c.doubleValue() * 10); + * } + * throw new LambdaException("Unsupported command type"); + * } + * + * private short getScaled100Int16Value(Command command) throws LambdaException { + * if (command instanceof QuantityType quantityCommand) { + * QuantityType c = quantityCommand.toUnit(CELSIUS); + * if (c != null) { + * return (short) (c.doubleValue() * 100); + * } else { + * throw new LambdaException("Unsupported unit"); + * } + * } + * if (command instanceof DecimalType c) { + * return (short) (c.doubleValue() * 100); + * } + * throw new LambdaException("Unsupported command type"); + * } */ - private short getScaledInt16Value(Command command) throws LambdaException { + + /** + * @param command get the value of this command. + * @return short the value of the command as short + */ + private short getInt16Value(Command command) throws LambdaException { if (command instanceof QuantityType quantityCommand) { - QuantityType c = quantityCommand.toUnit(CELSIUS); + QuantityType c = quantityCommand.toUnit(WATT); if (c != null) { - return (short) (c.doubleValue() * 10); + return c.shortValue(); } else { throw new LambdaException("Unsupported unit"); } } if (command instanceof DecimalType c) { - return (short) (c.doubleValue() * 10); + return c.shortValue(); } throw new LambdaException("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 LambdaException { + private short getScaledInt16Value(Command command) throws LambdaException { if (command instanceof QuantityType quantityCommand) { - QuantityType c = quantityCommand.toUnit(WATT); + QuantityType c = quantityCommand.toUnit(CELSIUS); if (c != null) { - return c.shortValue(); + return (short) (c.doubleValue() * 10); } else { throw new LambdaException("Unsupported unit"); } } if (command instanceof DecimalType c) { - return c.shortValue(); + return (short) (c.doubleValue() * 10); } throw new LambdaException("Unsupported command type"); } @@ -254,12 +299,10 @@ private short getInt16Value(Command command) throws LambdaException { */ @Override public void handleCommand(ChannelUID channelUID, Command command) { - logger.trace("249 handleCommand, channelUID: {} command {} ", channelUID, command); + logger.trace("283 handleCommand, channelUID: {} command {} ", channelUID, command); if (RefreshType.REFRESH == command) { - logger.trace("239 handleCommand: Es wird gelesen ?, GroupID: {}", channelUID.getGroupId()); String groupId = channelUID.getGroupId(); if (groupId != null) { - logger.trace("242 }"); AbstractBasePoller poller; switch (groupId) { case GROUP_GENERAL_AMBIENT: @@ -268,55 +311,143 @@ public void handleCommand(ChannelUID channelUID, Command command) { case GROUP_GENERAL_EMANAGER: poller = emanagerPoller; break; + case GROUP_HEATPUMP1: + poller = heatpump1Poller; + break; + case GROUP_HEATPUMP1SET: + poller = heatpump1SetPoller; + break; case GROUP_BOILER1: - logger.trace("264 boiler1Poller }"); poller = boiler1Poller; break; case GROUP_BOILER1MT: - logger.trace("267 boiler1mtPoller }"); poller = boiler1mtPoller; break; case GROUP_BUFFER1: - logger.trace("280 buffer1Poller }"); poller = buffer1Poller; break; case GROUP_BUFFER1MT: - logger.trace("284 buffer1mtPoller }"); poller = buffer1mtPoller; break; + case GROUP_HEATINGCIRCUIT1: + poller = heatingcircuit1Poller; + break; + case GROUP_HEATINGCIRCUIT1SETTING: + poller = heatingcircuit1settingPoller; + break; default: poller = null; break; } if (poller != null) { - logger.trace("276 Es wird gepollt }"); + // logger.trace("336 Es wird gepollt }"); poller.poll(); } } } else { - logger.trace("264 handleCommand: Es wird geschrieben, GroupID: {}, command {}", channelUID.getGroupId(), + logger.trace("341 handleCommand: Es wird geschrieben, GroupID: {}, command {}", channelUID.getGroupId(), command); try { - // logger.trace("266 handleCommand: Es wird geschrieben, GroupID: {}, command: {}", - // channelUID.getGroupId(), getInt16Value(command)); - logger.trace("302 "); - if (GROUP_GENERAL_EMANAGER.equals(channelUID.getGroupId())) { - logger.trace("305 channelUID {} ", channelUID.getIdWithoutGroup()); + logger.trace("345 vor EMANAGER"); + if (GROUP_GENERAL_EMANAGER.equals(channelUID.getGroupId())) { + logger.trace("330 im EMANAGER channelUID {} ", channelUID.getIdWithoutGroup()); switch (channelUID.getIdWithoutGroup()) { case CHANNEL_ACTUAL_POWER: - logger.trace("311 command: {}", command); - // String teststr = command.replaceAll("[^0-9,-]", ""); - // logger.trace("testsstr: {}, ", teststr); - // writeInt16(102, getInt16Value(teststr)); + logger.trace("336 command: {}", command); writeInt16(102, getInt16Value(command)); break; } } + if (GROUP_BOILER1MT.equals(channelUID.getGroupId())) { + logger.trace("345 im BOILER1MT channelUID {} ", channelUID.getIdWithoutGroup()); + + switch (channelUID.getIdWithoutGroup()) { + + case CHANNEL_BOILER1_MAXIMUM_BOILER_TEMPERATURE: + + logger.trace("347 command: {}", command); + writeInt16(2050, getScaledInt16Value(command)); + break; + + } + } + if (GROUP_BUFFER1MT.equals(channelUID.getGroupId())) { + logger.trace("359 im BUFFER1MT channelUID {} ", channelUID.getIdWithoutGroup()); + + switch (channelUID.getIdWithoutGroup()) { + + case CHANNEL_BUFFER1_MAXIMUM_BOILER_TEMPERATURE: + + logger.trace("365 command: {}", command); + writeInt16(3050, getScaledInt16Value(command)); + break; + + } + } + + if (GROUP_HEATINGCIRCUIT1.equals(channelUID.getGroupId())) { + logger.trace("387 im HEATINGCIRCUI1 channelUID {} ", channelUID.getIdWithoutGroup()); + + switch (channelUID.getIdWithoutGroup()) { + + case CHANNEL_HEATINGCIRCUIT1_ROOM_DEVICE_TEMPERATURE: + logger.trace("393 command: {}", command); + writeInt16(5004, getScaledInt16Value(command)); + break; + case CHANNEL_HEATINGCIRCUIT1_SETPOINT_FLOW_LINE_TEMPERATURE: + logger.trace("393 command: {}", command); + writeInt16(5005, getScaledInt16Value(command)); + break; + case CHANNEL_HEATINGCIRCUIT1_OPERATING_MODE: + logger.trace("403 command: {}", command); + writeInt16(5006, getInt16Value(command)); + break; + + } + } + + if (GROUP_HEATINGCIRCUIT1SETTING.equals(channelUID.getGroupId())) { + logger.trace("411 im HEATINGCIRCUI1 channelUID {} ", channelUID.getIdWithoutGroup()); + + switch (channelUID.getIdWithoutGroup()) { + + case CHANNEL_HEATINGCIRCUIT1_OFFSET_FLOW_LINE_TEMPERATURE: + + logger.trace("418 command: {}", command); + writeInt16(5050, getScaledInt16Value(command)); + break; + case CHANNEL_HEATINGCIRCUIT1_ROOM_HEATING_TEMPERATURE: + + logger.trace("233 command: {}", command); + writeInt16(5051, getScaledInt16Value(command)); + break; + case CHANNEL_HEATINGCIRCUIT1_ROOM_COOLING_TEMPERATURE: + + logger.trace("427 command: {}", command); + writeInt16(5052, getScaledInt16Value(command)); + break; + + } + + } + if (GROUP_HEATPUMP1SET.equals(channelUID.getGroupId())) { + logger.trace("439 im HEATPUMP1SET channelUID {} ", channelUID.getIdWithoutGroup()); + + switch (channelUID.getIdWithoutGroup()) { + + case CHANNEL_HEATPUMP1_SET_ERROR_QUIT: + + logger.trace("445 Heatpumpseterrorquit command: {}", command); + writeInt16(1050, getScaledInt16Value(command)); + break; + + } + } } catch (LambdaException error) { if (hasConfigurationError() || getThing().getStatus() == ThingStatus.OFFLINE) { return; @@ -399,6 +530,32 @@ protected void handlePolledData(ModbusRegisterArray registers) { poller.registerPollTask(100, 5, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); emanagerPoller = poller; } + if (heatpump1Poller == null) { + AbstractBasePoller poller = new AbstractBasePoller() { + @Override + protected void handlePolledData(ModbusRegisterArray registers) { + handlePolledHeatpump1Data(registers); + } + }; + + poller.registerPollTask(1000, 14, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); + logger.trace("Poller Heatpump1 erzeugt"); + heatpump1Poller = poller; + } + + if (heatpump1SetPoller == null) { + AbstractBasePoller poller = new AbstractBasePoller() { + @Override + protected void handlePolledData(ModbusRegisterArray registers) { + handlePolledHeatpump1SetData(registers); + } + }; + + poller.registerPollTask(1050, 1, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); + logger.trace("Poller Heatpump1Set erzeugt"); + heatpump1SetPoller = poller; + } + if (boiler1Poller == null) { AbstractBasePoller poller = new AbstractBasePoller() { @Override @@ -408,7 +565,6 @@ protected void handlePolledData(ModbusRegisterArray registers) { }; poller.registerPollTask(2000, 4, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); - logger.trace("Poller Boiler1 erzeugt"); boiler1Poller = poller; } if (boiler1mtPoller == null) { @@ -420,7 +576,6 @@ protected void handlePolledData(ModbusRegisterArray registers) { }; poller.registerPollTask(2050, 1, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); - logger.trace("Poller BoilerMt1 erzeugt"); boiler1mtPoller = poller; } @@ -433,7 +588,6 @@ protected void handlePolledData(ModbusRegisterArray registers) { }; poller.registerPollTask(3000, 4, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); - logger.trace("Poller Buffer1 erzeugt"); buffer1Poller = poller; } if (buffer1mtPoller == null) { @@ -445,9 +599,32 @@ protected void handlePolledData(ModbusRegisterArray registers) { }; poller.registerPollTask(3050, 1, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); - logger.trace("Poller BufferMt1 erzeugt"); buffer1mtPoller = poller; } + if (heatingcircuit1Poller == null) { + AbstractBasePoller poller = new AbstractBasePoller() { + @Override + protected void handlePolledData(ModbusRegisterArray registers) { + handlePolledHeatingCircuit1Data(registers); + } + }; + + poller.registerPollTask(5000, 7, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); + logger.trace("Poller HeatingCircuit1 erzeugt"); + heatingcircuit1Poller = poller; + } + if (heatingcircuit1settingPoller == null) { + AbstractBasePoller poller = new AbstractBasePoller() { + @Override + protected void handlePolledData(ModbusRegisterArray registers) { + handlePolledHeatingCircuit1SettingData(registers); + } + }; + + poller.registerPollTask(5050, 3, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); + logger.trace("Poller HeatingCircuit1Setting erzeugt"); + heatingcircuit1settingPoller = poller; + } updateStatus(ThingStatus.UNKNOWN); } @@ -467,52 +644,62 @@ private void tearDown() { AbstractBasePoller poller = ambientPoller; if (poller != null) { - logger.debug("Unregistering ambientPoller from ModbusManager"); poller.unregisterPollTask(); - ambientPoller = null; } poller = emanagerPoller; if (poller != null) { - logger.debug("Unregistering emanagerPoller from ModbusManager"); poller.unregisterPollTask(); - emanagerPoller = null; } - poller = boiler1Poller; + poller = heatpump1Poller; if (poller != null) { - logger.debug("Unregistering boiler1Poller from ModbusManager"); poller.unregisterPollTask(); + heatpump1Poller = null; + } + poller = heatpump1SetPoller; + if (poller != null) { + poller.unregisterPollTask(); + heatpump1SetPoller = null; + } + poller = boiler1Poller; + if (poller != null) { + poller.unregisterPollTask(); boiler1Poller = null; } - poller = boiler1mtPoller; if (poller != null) { - logger.debug("Unregistering boiler1mtPoller from ModbusManager"); poller.unregisterPollTask(); - boiler1mtPoller = null; } poller = buffer1Poller; if (poller != null) { - logger.debug("Unregistering buffer1Poller from ModbusManager"); poller.unregisterPollTask(); - buffer1Poller = null; } - poller = buffer1mtPoller; if (poller != null) { - logger.debug("Unregistering buffer1mtPoller from ModbusManager"); poller.unregisterPollTask(); - buffer1mtPoller = null; } + poller = heatingcircuit1Poller; + if (poller != null) { + logger.debug("Unregistering heatingcircuit1Poller from ModbusManager"); + poller.unregisterPollTask(); + heatingcircuit1Poller = null; + } + + poller = heatingcircuit1settingPoller; + if (poller != null) { + logger.debug("Unregistering heatingcircuit1settingPoller from ModbusManager"); + poller.unregisterPollTask(); + heatingcircuit1settingPoller = null; + } comms = null; } @@ -558,11 +745,22 @@ public int getSlaveId() { * * @param value the value to alter * @return the scaled value as a DecimalType + * + * + * protected State getScaled10(Number value, Unit unit) { + * // logger.trace("505 value: {}", value.intValue()); + * return QuantityType.valueOf(value.doubleValue() / 10, unit); + * } + * + * protected State getScaled100(Number value, Unit unit) { + * // logger.trace("505 value: {}", value.intValue()); + * return QuantityType.valueOf(value.doubleValue() / 100, unit); + * } */ - - protected State getScaled(Number value, Unit unit) { + protected State getScaled(Number value, Unit unit, Double pow) { // logger.trace("505 value: {}", value.intValue()); - return QuantityType.valueOf(value.doubleValue() / 10, unit); + double factor = Math.pow(10, pow); + return QuantityType.valueOf(value.doubleValue() * factor, unit); } protected State getUnscaled(Number value, Unit unit) { @@ -596,12 +794,14 @@ protected void handlePolledAmbientData(ModbusRegisterArray registers) { updateState(channelUID(GROUP_GENERAL_AMBIENT, CHANNEL_AMBIENT_ERROR_NUMBER), new DecimalType(block.ambientErrorNumber)); - updateState(channelUID(GROUP_GENERAL_AMBIENT, CHANNEL_AMBIENT_OPERATOR_STATE), - new DecimalType(block.ambientOperatorState)); + updateState(channelUID(GROUP_GENERAL_AMBIENT, CHANNEL_AMBIENT_OPERATING_STATE), + new DecimalType(block.ambientOperatingState)); + updateState(channelUID(GROUP_GENERAL_AMBIENT, CHANNEL_ACTUAL_AMBIENT_TEMPERATURE), + getScaled(block.actualAmbientTemperature, CELSIUS, -1.0)); updateState(channelUID(GROUP_GENERAL_AMBIENT, CHANNEL_AVERAGE_AMBIENT_TEMPERATURE), - getScaled(block.averageAmbientTemperature, CELSIUS)); + getScaled(block.averageAmbientTemperature, CELSIUS, -1.0)); updateState(channelUID(GROUP_GENERAL_AMBIENT, CHANNEL_CALCULATED_AMBIENT_TEMPERATURE), - getScaled(block.calculatedAmbientTemperature, CELSIUS)); + getScaled(block.calculatedAmbientTemperature, CELSIUS, -1.0)); resetCommunicationError(); } @@ -612,11 +812,61 @@ protected void handlePolledEManagerData(ModbusRegisterArray registers) { EManagerBlock block = emanagerBlockParser.parse(registers); updateState(channelUID(GROUP_GENERAL_EMANAGER, CHANNEL_EMANAGER_ERROR_NUMBER), new DecimalType(block.emanagerErrorNumber)); - updateState(channelUID(GROUP_GENERAL_EMANAGER, CHANNEL_EMANAGER_OPERATOR_STATE), - new DecimalType(block.emanagerOperatorState)); + updateState(channelUID(GROUP_GENERAL_EMANAGER, CHANNEL_EMANAGER_OPERATING_STATE), + new DecimalType(block.emanagerOperatingState)); updateState(channelUID(GROUP_GENERAL_EMANAGER, CHANNEL_ACTUAL_POWER_CONSUMPTION), getUnscaled(block.actualPowerConsumption, WATT)); updateState(channelUID(GROUP_GENERAL_EMANAGER, CHANNEL_ACTUAL_POWER), getUnscaled(block.actualPower, WATT)); + updateState(channelUID(GROUP_GENERAL_EMANAGER, CHANNEL_POWER_CONSUMPTION_SETPOINT), + getUnscaled(block.powerConsumptionSetpoint, WATT)); + + resetCommunicationError(); + } + + protected void handlePolledHeatpump1Data(ModbusRegisterArray registers) { + logger.trace("Heatpump1 block received, size: {}", registers.size()); + + Heatpump1Block block = heatpump1BlockParser.parse(registers); + + // Heatpump1 group + updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_ERROR_STATE), + new DecimalType(block.heatpump1ErrorState)); + updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_ERROR_NUMBER), + new DecimalType(block.heatpump1ErrorNumber)); + updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_OPERATING_STATE), + new DecimalType(block.heatpump1OperatingState)); + updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_STATE), new DecimalType(block.heatpump1State)); + updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_T_FLOW), + getScaled(block.heatpump1TFlow, CELSIUS, -2.0)); + updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_T_RETURN), + getScaled(block.heatpump1TReturn, CELSIUS, -2.0)); + updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_VOL_SINK), + getScaled(block.heatpump1VolSink, LITRE_PER_MINUTE, -2.0)); + updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_T_EQIN), + getScaled(block.heatpump1TEQin, CELSIUS, -2.0)); + updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_T_EQOUT), + getScaled(block.heatpump1TEQout, CELSIUS, -2.0)); + updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_VOL_SOURCE), + getScaled(block.heatpump1VolSource, LITRE_PER_MINUTE, -2.0)); + updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_COMPRESSOR_RATING), + getScaled(block.heatpump1CompressorRating, PERCENT, -2.0)); + updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_QP_HEATING), + getScaled(block.heatpump1QpHeating, WATT, 2.0)); + updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_FI_POWER_CONSUMPTION), + getUnscaled(block.heatpump1FIPowerConsumption, WATT)); + updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_COP), getScaled(block.heatpump1COP, PERCENT, -2.0)); + + resetCommunicationError(); + } + + protected void handlePolledHeatpump1SetData(ModbusRegisterArray registers) { + logger.trace("Heatpump1Set block received, size: {}", registers.size()); + + Heatpump1SetBlock block = heatpump1SetBlockParser.parse(registers); + + // Heatpump1 group + updateState(channelUID(GROUP_HEATPUMP1SET, CHANNEL_HEATPUMP1_SET_ERROR_QUIT), + new DecimalType(block.heatpump1seterrorquit)); resetCommunicationError(); } @@ -626,10 +876,13 @@ protected void handlePolledBoiler1Data(ModbusRegisterArray registers) { Boiler1Block block = boiler1BlockParser.parse(registers); // Boiler1 group + updateState(channelUID(GROUP_BOILER1, CHANNEL_BOILER1_ERROR_NUMBER), new DecimalType(block.boiler1ErrorNumber)); + updateState(channelUID(GROUP_BOILER1, CHANNEL_BOILER1_OPERATING_STATE), + new DecimalType(block.boiler1OperatingState)); updateState(channelUID(GROUP_BOILER1, CHANNEL_BOILER1_ACTUAL_HIGH_TEMPERATURE), - getScaled(block.boiler1ActualHighTemperature, CELSIUS)); + getScaled(block.boiler1ActualHighTemperature, CELSIUS, -1.0)); updateState(channelUID(GROUP_BOILER1, CHANNEL_BOILER1_ACTUAL_LOW_TEMPERATURE), - getScaled(block.boiler1ActualLowTemperature, CELSIUS)); + getScaled(block.boiler1ActualLowTemperature, CELSIUS, -1.0)); resetCommunicationError(); } @@ -640,7 +893,7 @@ protected void handlePolledBoiler1MtData(ModbusRegisterArray registers) { // Boiler1Mt group updateState(channelUID(GROUP_BOILER1MT, CHANNEL_BOILER1_MAXIMUM_BOILER_TEMPERATURE), - getScaled(block.boiler1MaximumBoilerTemperature, CELSIUS)); + getScaled(block.boiler1MaximumBoilerTemperature, CELSIUS, -1.0)); resetCommunicationError(); } @@ -650,10 +903,13 @@ protected void handlePolledBuffer1Data(ModbusRegisterArray registers) { Buffer1Block block = buffer1BlockParser.parse(registers); // Buffer1 group + updateState(channelUID(GROUP_BUFFER1, CHANNEL_BUFFER1_ERROR_NUMBER), new DecimalType(block.buffer1ErrorNumber)); + updateState(channelUID(GROUP_BUFFER1, CHANNEL_BUFFER1_OPERATING_STATE), + new DecimalType(block.buffer1OperatingState)); updateState(channelUID(GROUP_BUFFER1, CHANNEL_BUFFER1_ACTUAL_HIGH_TEMPERATURE), - getScaled(block.buffer1ActualHighTemperature, CELSIUS)); + getScaled(block.buffer1ActualHighTemperature, CELSIUS, -1.0)); updateState(channelUID(GROUP_BUFFER1, CHANNEL_BUFFER1_ACTUAL_LOW_TEMPERATURE), - getScaled(block.buffer1ActualLowTemperature, CELSIUS)); + getScaled(block.buffer1ActualLowTemperature, CELSIUS, -1.0)); resetCommunicationError(); } @@ -664,7 +920,48 @@ protected void handlePolledBuffer1MtData(ModbusRegisterArray registers) { // Buffer1Mt group updateState(channelUID(GROUP_BUFFER1MT, CHANNEL_BUFFER1_MAXIMUM_BOILER_TEMPERATURE), - getScaled(block.buffer1MaximumBufferTemperature, CELSIUS)); + getScaled(block.buffer1MaximumBufferTemperature, CELSIUS, -1.0)); + resetCommunicationError(); + } + + protected void handlePolledHeatingCircuit1Data(ModbusRegisterArray registers) { + logger.trace("HeatingCircuit1 block received, size: {}", registers.size()); + + HeatingCircuit1Block block = heatingcircuit1BlockParser.parse(registers); + + // HeatingCircuit1 group + + updateState(channelUID(GROUP_HEATINGCIRCUIT1, CHANNEL_HEATINGCIRCUIT1_ERROR_NUMBER), + new DecimalType(block.heatingcircuit1ErrorNumber)); + updateState(channelUID(GROUP_HEATINGCIRCUIT1, CHANNEL_HEATINGCIRCUIT1_OPERATING_STATE), + new DecimalType(block.heatingcircuit1OperatingState)); + updateState(channelUID(GROUP_HEATINGCIRCUIT1, CHANNEL_HEATINGCIRCUIT1_FLOW_LINE_TEMPERATURE), + getScaled(block.heatingcircuit1FlowLineTemperature, CELSIUS, -1.0)); + updateState(channelUID(GROUP_HEATINGCIRCUIT1, CHANNEL_HEATINGCIRCUIT1_RETURN_LINE_TEMPERATURE), + getScaled(block.heatingcircuit1ReturnLineTemperature, CELSIUS, -1.0)); + updateState(channelUID(GROUP_HEATINGCIRCUIT1, CHANNEL_HEATINGCIRCUIT1_ROOM_DEVICE_TEMPERATURE), + getScaled(block.heatingcircuit1RoomDeviceTemperature, CELSIUS, -1.0)); + updateState(channelUID(GROUP_HEATINGCIRCUIT1, CHANNEL_HEATINGCIRCUIT1_SETPOINT_FLOW_LINE_TEMPERATURE), + getScaled(block.heatingcircuit1SetpointFlowLineTemperature, CELSIUS, -1.0)); + updateState(channelUID(GROUP_HEATINGCIRCUIT1, CHANNEL_HEATINGCIRCUIT1_OPERATING_MODE), + new DecimalType(block.heatingcircuit1OperatingMode)); + + resetCommunicationError(); + } + + protected void handlePolledHeatingCircuit1SettingData(ModbusRegisterArray registers) { + logger.trace("HeatingCircuit1Setting block received, size: {}", registers.size()); + + HeatingCircuit1SettingBlock block = heatingcircuit1settingBlockParser.parse(registers); + + // HeatingCircuit1Settting group + + updateState(channelUID(GROUP_HEATINGCIRCUIT1SETTING, CHANNEL_HEATINGCIRCUIT1_OFFSET_FLOW_LINE_TEMPERATURE), + getScaled(block.heatingcircuit1OffsetFlowLineTemperature, CELSIUS, -1.0)); + updateState(channelUID(GROUP_HEATINGCIRCUIT1SETTING, CHANNEL_HEATINGCIRCUIT1_ROOM_HEATING_TEMPERATURE), + getScaled(block.heatingcircuit1RoomHeatingTemperature, CELSIUS, -1.0)); + updateState(channelUID(GROUP_HEATINGCIRCUIT1SETTING, CHANNEL_HEATINGCIRCUIT1_ROOM_COOLING_TEMPERATURE), + getScaled(block.heatingcircuit1RoomCoolingTemperature, CELSIUS, -1.0)); resetCommunicationError(); } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/AmbientBlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/AmbientBlockParser.java index 08c9cd9b60bd5..3d221a6f60847 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/AmbientBlockParser.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/AmbientBlockParser.java @@ -15,11 +15,9 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.binding.modbus.lambda.internal.dto.AmbientBlock; import org.openhab.core.io.transport.modbus.ModbusRegisterArray; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** - * Parses inverter modbus data into an Ambient Block + * Parses labmda modbus data into an Ambient Block * * @author Paul Frank - Initial contribution * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus @@ -27,13 +25,11 @@ */ @NonNullByDefault public class AmbientBlockParser extends AbstractBaseParser { - private final Logger logger = LoggerFactory.getLogger(AmbientBlockParser.class); public AmbientBlock parse(ModbusRegisterArray raw) { - logger.trace("AmbientBlockParser"); AmbientBlock block = new AmbientBlock(); block.ambientErrorNumber = extractUInt16(raw, 0, (short) 0); - block.ambientOperatorState = extractUInt16(raw, 1, (short) 0); + block.ambientOperatingState = extractUInt16(raw, 1, (short) 0); block.actualAmbientTemperature = extractUInt16(raw, 2, (short) 0); block.averageAmbientTemperature = extractUInt16(raw, 3, (short) 0); block.calculatedAmbientTemperature = extractUInt16(raw, 4, (short) 0); diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1BlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1BlockParser.java index 579ae527c1880..e1056ad0740bd 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1BlockParser.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1BlockParser.java @@ -15,11 +15,9 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.binding.modbus.lambda.internal.dto.Boiler1Block; import org.openhab.core.io.transport.modbus.ModbusRegisterArray; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** - * Parses inverter modbus data into a Boiler Block + * Parses lambda modbus data into a Boiler1 Block * * @author Paul Frank - Initial contribution * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus @@ -27,12 +25,11 @@ */ @NonNullByDefault public class Boiler1BlockParser extends AbstractBaseParser { - private final Logger logger = LoggerFactory.getLogger(Boiler1BlockParser.class); public Boiler1Block parse(ModbusRegisterArray raw) { - logger.trace("Boiler1BlockParser"); Boiler1Block block = new Boiler1Block(); - + block.boiler1ErrorNumber = extractUInt16(raw, 0, (short) 0); + block.boiler1OperatingState = extractUInt16(raw, 1, (short) 0); block.boiler1ActualHighTemperature = extractUInt16(raw, 2, (short) 0); block.boiler1ActualLowTemperature = extractUInt16(raw, 3, (short) 0); return block; diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1MtBlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1MtBlockParser.java index af1cc5b5e48f7..cdd795cdfa297 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1MtBlockParser.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1MtBlockParser.java @@ -15,11 +15,9 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.binding.modbus.lambda.internal.dto.Boiler1MtBlock; import org.openhab.core.io.transport.modbus.ModbusRegisterArray; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** - * Parses inverter modbus data into an Boiler1Mt Block - + * Parses inv modbus data into an Boiler1Mt Block - * * @author Paul Frank - Initial contribution * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus @@ -27,12 +25,9 @@ */ @NonNullByDefault public class Boiler1MtBlockParser extends AbstractBaseParser { - private final Logger logger = LoggerFactory.getLogger(Boiler1MtBlockParser.class); public Boiler1MtBlock parse(ModbusRegisterArray raw) { - logger.trace("Boiler1MtBlockParser"); Boiler1MtBlock block = new Boiler1MtBlock(); - block.boiler1MaximumBoilerTemperature = extractUInt16(raw, 0, (short) 0); return block; } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Buffer1BlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Buffer1BlockParser.java index ba4a16ea1ed0e..16ef4c0599cae 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Buffer1BlockParser.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Buffer1BlockParser.java @@ -15,11 +15,9 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.binding.modbus.lambda.internal.dto.Buffer1Block; import org.openhab.core.io.transport.modbus.ModbusRegisterArray; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** - * Parses inverter modbus data into a Buffer Block + * Parses lambda modbus data into a Buffer Block * * @author Paul Frank - Initial contribution * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus @@ -27,12 +25,11 @@ */ @NonNullByDefault public class Buffer1BlockParser extends AbstractBaseParser { - private final Logger logger = LoggerFactory.getLogger(Buffer1BlockParser.class); public Buffer1Block parse(ModbusRegisterArray raw) { - logger.trace("Buffer1BlockParser"); Buffer1Block block = new Buffer1Block(); - + block.buffer1ErrorNumber = extractUInt16(raw, 0, (short) 0); + block.buffer1OperatingState = extractUInt16(raw, 1, (short) 0); block.buffer1ActualHighTemperature = extractUInt16(raw, 2, (short) 0); block.buffer1ActualLowTemperature = extractUInt16(raw, 3, (short) 0); return block; diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Buffer1MtBlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Buffer1MtBlockParser.java index 883ae8b258ed5..7fbd7c672752b 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Buffer1MtBlockParser.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Buffer1MtBlockParser.java @@ -15,11 +15,9 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.binding.modbus.lambda.internal.dto.Buffer1MtBlock; import org.openhab.core.io.transport.modbus.ModbusRegisterArray; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** - * Parses inverter modbus data into an Buffer1Mt Block - + * Parses lambda modbus data into an Buffer1Mt Block - * * @author Paul Frank - Initial contribution * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus @@ -27,12 +25,9 @@ */ @NonNullByDefault public class Buffer1MtBlockParser extends AbstractBaseParser { - private final Logger logger = LoggerFactory.getLogger(Buffer1MtBlockParser.class); public Buffer1MtBlock parse(ModbusRegisterArray raw) { - logger.trace("Buffer1MtBlockParser"); Buffer1MtBlock block = new Buffer1MtBlock(); - block.buffer1MaximumBufferTemperature = extractUInt16(raw, 0, (short) 0); return block; } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/EManagerBlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/EManagerBlockParser.java index 2076df760a8e4..3c2b2c649c061 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/EManagerBlockParser.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/EManagerBlockParser.java @@ -29,9 +29,10 @@ public class EManagerBlockParser extends AbstractBaseParser { public EManagerBlock parse(ModbusRegisterArray raw) { EManagerBlock block = new EManagerBlock(); block.emanagerErrorNumber = extractUInt16(raw, 0, (short) 0); - block.emanagerOperatorState = extractUInt16(raw, 1, (short) 0); + block.emanagerOperatingState = extractUInt16(raw, 1, (short) 0); block.actualPower = extractUInt16(raw, 2, (short) 0); block.actualPowerConsumption = extractUInt16(raw, 3, (short) 0); + block.powerConsumptionSetpoint = extractUInt16(raw, 4, (short) 0); return block; } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatingCircuit1BlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatingCircuit1BlockParser.java new file mode 100644 index 0000000000000..41e0ba54a4442 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatingCircuit1BlockParser.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.parser; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.modbus.lambda.internal.dto.HeatingCircuit1Block; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; + +/** + * Parses lambda + * modbus data into a Heatpump1 Block + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + * + */ +@NonNullByDefault +public class HeatingCircuit1BlockParser extends AbstractBaseParser { + + public HeatingCircuit1Block parse(ModbusRegisterArray raw) { + HeatingCircuit1Block block = new HeatingCircuit1Block(); + block.heatingcircuit1ErrorNumber = extractUInt16(raw, 0, (short) 0); + block.heatingcircuit1OperatingState = extractUInt16(raw, 1, (short) 0); + block.heatingcircuit1FlowLineTemperature = extractUInt16(raw, 2, (short) 0); + block.heatingcircuit1ReturnLineTemperature = extractUInt16(raw, 3, (short) 0); + block.heatingcircuit1RoomDeviceTemperature = extractUInt16(raw, 4, (short) 0); + block.heatingcircuit1SetpointFlowLineTemperature = extractUInt16(raw, 5, (short) 0); + block.heatingcircuit1OperatingMode = extractUInt16(raw, 6, (short) 0); + return block; + } +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatingCircuit1SettingBlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatingCircuit1SettingBlockParser.java new file mode 100644 index 0000000000000..54c7e1a02f830 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatingCircuit1SettingBlockParser.java @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.parser; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.modbus.lambda.internal.dto.HeatingCircuit1SettingBlock; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; + +/** + * Parses lambda modbus data into a Heatpump1 Block + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + * + */ +@NonNullByDefault +public class HeatingCircuit1SettingBlockParser extends AbstractBaseParser { + + public HeatingCircuit1SettingBlock parse(ModbusRegisterArray raw) { + // logger.trace("HeatingCircuit1Setting 33 wird gelesen"); + HeatingCircuit1SettingBlock block = new HeatingCircuit1SettingBlock(); + block.heatingcircuit1OffsetFlowLineTemperature = extractUInt16(raw, 0, (short) 0); + block.heatingcircuit1RoomHeatingTemperature = extractUInt16(raw, 1, (short) 0); + block.heatingcircuit1RoomCoolingTemperature = extractUInt16(raw, 2, (short) 0); + return block; + } +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Heatpump1BlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Heatpump1BlockParser.java new file mode 100644 index 0000000000000..10c9432dc3eef --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Heatpump1BlockParser.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.parser; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.modbus.lambda.internal.dto.Heatpump1Block; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; + +/** + * Parses inlambda modbus data into a Heatpump1 Block + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + * + */ +@NonNullByDefault +public class Heatpump1BlockParser extends AbstractBaseParser { + + public Heatpump1Block parse(ModbusRegisterArray raw) { + Heatpump1Block block = new Heatpump1Block(); + block.heatpump1ErrorState = extractUInt16(raw, 0, (short) 0); + block.heatpump1ErrorNumber = extractUInt16(raw, 1, (short) 0); + block.heatpump1State = extractUInt16(raw, 2, (short) 0); + block.heatpump1OperatingState = extractUInt16(raw, 3, (short) 0); + block.heatpump1TFlow = extractUInt16(raw, 4, (short) 0); + block.heatpump1TReturn = extractUInt16(raw, 5, (short) 0); + block.heatpump1VolSink = extractUInt16(raw, 6, (short) 0); + block.heatpump1TEQin = extractUInt16(raw, 7, (short) 0); + block.heatpump1TEQout = extractUInt16(raw, 8, (short) 0); + block.heatpump1VolSource = extractUInt16(raw, 9, (short) 0); + block.heatpump1CompressorRating = extractUInt16(raw, 10, (short) 0); + block.heatpump1QpHeating = extractUInt16(raw, 11, (short) 0); + block.heatpump1FIPowerConsumption = extractUInt16(raw, 12, (short) 0); + block.heatpump1COP = extractUInt16(raw, 13, (short) 0); + return block; + } +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Heatpump1SetBlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Heatpump1SetBlockParser.java new file mode 100644 index 0000000000000..2f70748d72fdc --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Heatpump1SetBlockParser.java @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.parser; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.modbus.lambda.internal.dto.Heatpump1SetBlock; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; + +/** + * Parses inlambda modbus data into a Heatpump1 Block + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + * + */ +@NonNullByDefault +public class Heatpump1SetBlockParser extends AbstractBaseParser { + + public Heatpump1SetBlock parse(ModbusRegisterArray raw) { + Heatpump1SetBlock block = new Heatpump1SetBlock(); + block.heatpump1seterrorquit = extractUInt16(raw, 0, (short) 0); + return block; + } +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/i18n/lambda.properties b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/i18n/lambda.properties index f5638f56b28b7..ef59715fe63c7 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/i18n/lambda.properties +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/i18n/lambda.properties @@ -12,39 +12,73 @@ thing-type.config.lambda.modbusconfig.refresh.description = Poll interval in sec # channel group types -channel-group-type.modbus.general-ambient.label = General Ambient -channel-group-type.modbus.general-emanager.label = General E-Manager -channel-group-type.modbus.heatpump1.label = Heat Pump 1 -channel-group-type.modbus.boiler1.label = Boiler 1 -channel-group-type.modbus.boiler1mt.label = Boiler 1 Maximum Temperature -channel-group-type.modbus.buffer1.label = Buffer 1 -channel-group-type.modbus.buffer1mt.label = Buffer 1 Maximum Temperature +channel-group-type.modbus.general-ambient.label = General Ambient Group +channel-group-type.modbus.general-emanager.label = General E-Manager Group +channel-group-type.modbus.heatpump1.label = Heat Pump 1 Group +channel-group-type.modbus.boiler1.label = Boiler 1 Group +channel-group-type.modbus.buffer1.label = Buffer 1 Group +channel-group-type.modbus.heatingcircuit1.label = Heating Circuit 1 Group # channel types # General Ambient channel-type.modbus.ambient-error-number-type.label = Ambient Error Number -channel-type.modbus.ambient-operator-state-type.label = Ambient Operator State +channel-type.modbus.ambient-operating-state-type.label = Ambient Operating State channel-type.modbus.actual-ambient-temperature-type.label = Actual Ambient Temperature channel-type.modbus.average-ambient-temperature-type.label = Average Ambient Temperature 1h channel-type.modbus.calculated-ambient-temperature-type.label = Calculated Ambient Temperature # General E-Manager channel-type.modbus.emanager-error-number-type.label = E-Manager Error Number -channel-type.modbus.emanager-operator-state-type.label = E-Manager Operator State +channel-type.modbus.emanager-operating-state-type.label = E-Manager Operating State channel-type.modbus.actual-power-type.label = Actual Power (input or excess) channel-type.modbus.actual-power-consumption-type.label = Actual Power Consumption # Heat Pump 1 + +channel-type.modbus.heatpump1-error-state-type.label = Heat Pump 1 Error State +channel-type.modbus.heatpump1-error-number-type.label = Heat Pump 1 Error Number +channel-type.modbus.heatpump1-state-type.label = Heat Pump 1 State +channel-type.modbus.heatpump1-operating-state-type.label = Heat Pump 1 Operating State channel-type.modbus.heatpump1-t-flow-type.label = Heat Pump 1 T-Flow +channel-type.modbus.heatpump1-t-return-type.label = Heat Pump 1 T-Return +channel-type.modbus.heatpump1-vol-sink-type.label = Heat Pump 1 Volume flow heat sink +channel-type.modbus.heatpump1-t-eqin-type.label = Heat Pump 1 Energy source inlet temperature +channel-type.modbus.heatpump1-t-eqout-type.label = Heat Pump 1 Energy source outlet temperature +channel-type.modbus.heatpump1-vol-source-type.label = Heat Pump 1 Volume flow energy source +channel-type.modbus.heatpump1-compressor-rating-type.label = Heat Pump 1 Compressor unit rating +channel-type.modbus.heatpump1-qp-heating-type.label = Heat Pump 1 Actual heating capacity +channel-type.modbus.heatpump1-fi-power-consumption-type.label = Heat Pump 1 Frequency inverter actual power consumption +channel-type.modbus.heatpump1-cop-type.label = Heat Pump 1 COP +channel-type.modbus.heatpump1-set-error-quit.label = Heat Pump 1 Set Error Quit + # Boiler 1 +channel-type.modbus.boiler1-error-number-type.label = Boiler 1 Error Number +channel-type.modbus.boiler1-operating-state-type.label = Boiler 1 Operating State channel-type.modbus.boiler1-actual-high-temperature-type.label = Boiler 1 Actual High Temperature channel-type.modbus.boiler1-actual-low-temperature-type.label = Boiler 1 Actual Low Temperature + channel-type.modbus.boiler1-maximum-boiler-temperature-type.label = Boiler 1 Maximum Temperature # Buffer 1 +channel-type.modbus.buffer1-error-number-type.label = Buffer 1 Error Number +channel-type.modbus.buffer1-operating-state-type.label = Buffer 1 Operating State channel-type.modbus.buffer1-actual-high-temperature-type.label = Buffer 1 Actual High Temperature channel-type.modbus.buffer1-actual-low-temperature-type.label = Buffer 1 Actual Low Temperature + channel-type.modbus.buffer1-maximum-buffer-temperature-type.label = Buffer 1 Maximum Temperature +# Heating Circuit 1 +channel-type.modbus.heatingcircuit1-error-number-type.label = Heating circuit 1 Error Number; +channel-type.modbus.heatingcircuit1-operating-state-type.label = Heating circuit 1 Operating State; +channel-type.modbus.heatingcircuit1-flow-line-temperature-type.label = Heating circuit 1 Flow Line Temperature; +channel-type.modbus.heatingcircuit1-return-line-temperature-type.label = Heating circuit 1 Return Line Temperature; +channel-type.modbus.heatingcircuit1-room-device-temperature-type.label = Heating circuit 1 Room Device Temperature; +channel-type.modbus.heatingcircuit1-setpoint-flow-line-temperature-type.label = Heating circuit Setpoint Flow Line Temperature; +channel-type.modbus.heatingcircuit1-operating-mode-type.label = Heating circuit 1 Operating Mode; + +channel-type.modbus.heatingcircuit1-offset-flow-line-temperature-type.label = Heating circuit 1 Offset Flow Line Temperature; +channel-type.modbus.heatingcircuit1-room-heating-temperature-type.label = Heating circuit 1 Room Heating Temperature; +channel-type.modbus.heatingcircuit1-room-cooling-temperature-type.label = Heating circuit 1 Room Cooling Temperature; + diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-groups.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-groups.xml index c0068b24fd364..d90f5335973f0 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-groups.xml +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-groups.xml @@ -8,8 +8,9 @@ - + + @@ -18,52 +19,73 @@ - + - + + + + + + + + + + + + + + + + + - - - - - - - - - + + + - - - + + - - + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-types.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-types.xml index 604586cc854f5..a5072b62c3447 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-types.xml +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-types.xml @@ -15,9 +15,9 @@ - + Number - + @@ -56,9 +56,9 @@ - + Number - + @@ -73,15 +73,96 @@ Number:Power - + Number:Power - + + + + + Number:Power + + + + Number + + + + + + + + + + + + + + Number + + + + + + + + + + Number + + + + + + + + + + + + + + + + + + + + + + + + Number + + + + + + + + + + + + + + + + + + + + + + + + + Number:Temperature @@ -89,6 +170,98 @@ + + Number:Temperature + + + + + + Number:VolumetricFlowRate + + + + + + Number:Temperature + + + + + + Number:Temperature + + + + + + Number:VolumetricFlowRate + + + + + + Number + + + + + + Number:Power + + + + + + Number:Power + + + + + + Number + + + + + + Number + + + + + + Number + + + + + + + + + + Number + + + + + + + + + + + + + + + + + + + + Number:Temperature @@ -98,7 +271,7 @@ Number:Temperature - + @@ -107,6 +280,35 @@ + + Number + + + + + + + + + + Number + + + + + + + + + + + + + + + + + Number:Temperature @@ -125,4 +327,104 @@ + + Number + + + + + + + + + + + Number + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Number:Temperature + + + + + + Number:Temperature + + + + + + Number:Temperature + + + + + + Number:Temperature + + + + + + Number + + + + + + + + + + + + + + + + + Number:Temperature + + + + + + Number:Temperature + + + + + + Number:Temperature + + + + diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-types.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-types.xml index fff32568db2a2..5360825084ded 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-types.xml +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-types.xml @@ -16,14 +16,12 @@ - - + - From f4e632ba7cd54b24dd31a75fa6fc01ea464dbbb5 Mon Sep 17 00:00:00 2001 From: Christian Koch <78686276+chilobo@users.noreply.github.com> Date: Wed, 4 Dec 2024 19:43:23 +0100 Subject: [PATCH 5/8] Version 0.4 after attempt to rebase. Signed-off-by: Christian Koch Signed-off-by: Christian Koch <78686276+chilobo@users.noreply.github.com> --- CODEOWNERS | 1 + .../README.md | 320 +++-- .../lambda/internal/BoilerConfiguration.java | 62 + .../lambda/internal/BufferConfiguration.java | 61 + .../lambda/internal/GeneralConfiguration.java | 47 + .../internal/HeatingCircuitConfiguration.java | 61 + .../internal/HeatpumpConfiguration.java | 63 + .../internal/LambdaBindingConstants.java | 114 +- .../lambda/internal/LambdaConfiguration.java | 2 +- .../lambda/internal/LambdaHandlerFactory.java | 40 +- .../lambda/internal/dto/Boiler1Block.java | 27 - .../{Buffer1Block.java => BoilerBlock.java} | 12 +- ...ler1MtBlock.java => BoilerReg50Block.java} | 6 +- .../lambda/internal/dto/BufferBlock.java | 27 + ...fer1MtBlock.java => BufferReg50Block.java} | 6 +- .../internal/dto/HeatingCircuit1Block.java | 31 - ...ingBlock.java => HeatingCircuitBlock.java} | 17 +- .../dto/HeatingCircuitReg50Block.java | 27 + .../lambda/internal/dto/Heatpump1Block.java | 37 - .../lambda/internal/dto/HeatpumpBlock.java | 39 + ...1SetBlock.java => HeatpumpReg50Block.java} | 8 +- .../internal/handler/BoilerHandler.java | 578 +++++++++ .../internal/handler/BufferHandler.java | 576 +++++++++ .../internal/handler/GeneralHandler.java | 582 +++++++++ .../handler/HeatingCircuitHandler.java | 623 ++++++++++ .../internal/handler/HeatpumpHandler.java | 599 ++++++++++ .../internal/handler/LambdaException.java | 2 +- .../internal/handler/LambdaHandler.java | 1042 ----------------- .../internal/parser/AbstractBaseParser.java | 11 +- .../internal/parser/AmbientBlockParser.java | 8 +- .../internal/parser/Boiler1BlockParser.java | 37 - .../internal/parser/BoilerBlockParser.java | 37 + ...arser.java => BoilerReg50BlockParser.java} | 12 +- ...lockParser.java => BufferBlockParser.java} | 16 +- ...arser.java => BufferReg50BlockParser.java} | 12 +- .../internal/parser/EManagerBlockParser.java | 6 +- ...er.java => HeatingCircuitBlockParser.java} | 24 +- ...va => HeatingCircuitReg50BlockParser.java} | 17 +- .../internal/parser/Heatpump1BlockParser.java | 47 - .../internal/parser/HeatpumpBlockParser.java | 52 + ...ser.java => HeatpumpReg50BlockParser.java} | 12 +- .../OH-INF/config/config-descriptions.xml | 109 +- .../resources/OH-INF/i18n/lambda.properties | 152 ++- .../thing/boiler-channel-group-types.xml | 18 + .../OH-INF/thing/boiler-channel-types.xml | 57 + .../OH-INF/thing/boiler-thing-types.xml | 24 + .../thing/buffer-channel-group-types.xml | 18 + .../OH-INF/thing/buffer-channel-types.xml | 55 + .../OH-INF/thing/buffer-thing-types.xml | 24 + .../thing/general-channel-group-types.xml | 29 + .../OH-INF/thing/general-channel-types.xml | 91 ++ .../OH-INF/thing/general-thing-types.xml | 25 + .../heatingcircuit-channel-group-types.xml | 26 + .../thing/heatingcircuit-channel-types.xml | 109 ++ .../thing/heatingcircuit-thing-types.xml | 24 + .../thing/heatpump-channel-group-types.xml | 29 + .../OH-INF/thing/heatpump-channel-types.xml | 161 +++ ...ahp-types.xml => heatpump-thing-types.xml} | 15 +- .../OH-INF/thing/lambdahp-channel-groups.xml | 91 -- .../OH-INF/thing/lambdahp-channel-types.xml | 430 ------- 60 files changed, 4734 insertions(+), 2054 deletions(-) create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/BoilerConfiguration.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/BufferConfiguration.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/GeneralConfiguration.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/HeatingCircuitConfiguration.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/HeatpumpConfiguration.java delete mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler1Block.java rename bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/{Buffer1Block.java => BoilerBlock.java} (72%) rename bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/{Boiler1MtBlock.java => BoilerReg50Block.java} (83%) create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/BufferBlock.java rename bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/{Buffer1MtBlock.java => BufferReg50Block.java} (83%) delete mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatingCircuit1Block.java rename bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/{HeatingCircuit1SettingBlock.java => HeatingCircuitBlock.java} (58%) create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatingCircuitReg50Block.java delete mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Heatpump1Block.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatpumpBlock.java rename bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/{Heatpump1SetBlock.java => HeatpumpReg50Block.java} (84%) create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/BoilerHandler.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/BufferHandler.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/GeneralHandler.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/HeatingCircuitHandler.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/HeatpumpHandler.java delete mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/LambdaHandler.java delete mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1BlockParser.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/BoilerBlockParser.java rename bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/{Heatpump1SetBlockParser.java => BoilerReg50BlockParser.java} (66%) rename bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/{Buffer1BlockParser.java => BufferBlockParser.java} (60%) rename bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/{Boiler1MtBlockParser.java => BufferReg50BlockParser.java} (66%) rename bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/{HeatingCircuit1BlockParser.java => HeatingCircuitBlockParser.java} (51%) rename bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/{HeatingCircuit1SettingBlockParser.java => HeatingCircuitReg50BlockParser.java} (56%) delete mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Heatpump1BlockParser.java create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatpumpBlockParser.java rename bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/{Buffer1MtBlockParser.java => HeatpumpReg50BlockParser.java} (66%) create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/boiler-channel-group-types.xml create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/boiler-channel-types.xml create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/boiler-thing-types.xml create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/buffer-channel-group-types.xml create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/buffer-channel-types.xml create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/buffer-thing-types.xml create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/general-channel-group-types.xml create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/general-channel-types.xml create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/general-thing-types.xml create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/heatingcircuit-channel-group-types.xml create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/heatingcircuit-channel-types.xml create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/heatingcircuit-thing-types.xml create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/heatpump-channel-group-types.xml create mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/heatpump-channel-types.xml rename bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/{lambdahp-types.xml => heatpump-thing-types.xml} (55%) delete mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-groups.xml delete mode 100644 bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-types.xml diff --git a/CODEOWNERS b/CODEOWNERS index 0526f553154f3..c7746f595b560 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -237,6 +237,7 @@ /bundles/org.openhab.binding.modbus.kermi/ @KaaNee /bundles/org.openhab.binding.modbus.sbc/ @fwolter /bundles/org.openhab.binding.modbus.stiebeleltron/ @pail23 +/bundles/org.openhab.binding.modbus.lambda/ @chilobo /bundles/org.openhab.binding.modbus.studer/ @giovannimirulla /bundles/org.openhab.binding.modbus.sungrow/ @soenkekueper /bundles/org.openhab.binding.modbus.sunspec/ @mrbig diff --git a/bundles/org.openhab.binding.modbus.lambda/README.md b/bundles/org.openhab.binding.modbus.lambda/README.md index 5c2f2073176d4..c2425bacc68d8 100644 --- a/bundles/org.openhab.binding.modbus.lambda/README.md +++ b/bundles/org.openhab.binding.modbus.lambda/README.md @@ -1,9 +1,9 @@ # Lambda Heat Pump This extension adds support for the Lambda Heat Pump modbus protocol as provided by -https://lambda-wp.at/wp-content/uploads/2022/01/Modbus-Protokoll-und-Beschreibung.pdf + -A Lambda Heat Pump has to be reachable within your network. +A Lambda Heat Pump has to be reachable within your network. If you plan to use the E-Manager part to hand over your PV excess to the heat pump ask Lambda support to configure it to E-Meter Kommunikationsart: ModBus Client @@ -11,26 +11,32 @@ E-Meter Messpunkt: E-Eintrag Other configurations of the E-Manager are not supported (yet). -Up to now only the following configuration is supported: -- only one heatpump(heatpump1) -- only one buffer for the heating(buffer1) -- only one buffer for the water heating boiler1) - - ## 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 | -| ------------------ | ----------- | --------------------------------------------------- | -| Lambda Heat Pump | lambdahp | A lambda heat pump visible in the local network | +| Thing | ThingTypeID | Description | +| ---------------------- | --------------------| --------------------------------------- | +| Lambda General | lambda-general | General sections Ambient and E-Manager | +| Lambda Heatpump | lambda-heatpump | Heatpump section | +| Lambda Boiler | lambda-boiler | Boiler section | +| Lambda Buffer | lambda-buffer | Buffer section | +| Lambda Heating Circuit | lambda-heating | Heating circuit section | + +A Modbus Bridge has to be installed before installing the above mentioned things. +The binding supports installations with more than one Heat Pump, Boiler, Buffer, Heating Circuit. +For each of these parts you have to provide the Subindex of your thing in the configurations section, +usually using the User Interface. So if you have two Heating Circuits use 0 for the first and 1 for +the second Heating Circuit. +Handling of General System Settings (Base Adress 200) and Solar (Base Adress 4000) are not supported (yet). +Some of the registers noted RW in the manual are read only in the binding. ## Discovery This extension does not support autodiscovery. The things need to be added manually. -A typical bridge configuration would look like this: +A typical modbus bridge configuration would look like this: ```java Bridge modbus:tcp:bridge [ host="10.0.0.2", port=502, id=1 ] @@ -39,136 +45,250 @@ Bridge modbus:tcp:bridge [ host="10.0.0.2", port=502, id=1 ] ## Thing Configuration You first need to set up a TCP Modbus bridge according to the Modbus documentation. -You then add the lambda heat pump as part of the modbus binding. +You then add the things of the Lambda Heat Pump system as part of the modbus binding. Things in this extension will use the selected bridge to connect to the device. -The following parameters are valid for all thing types: +The following parameters are valid for all things: | Parameter | Type | Required | Default if omitted | Description | | --------- | ------- | -------- | ------------------ | -------------------------------------------------------------------------- | | refresh | integer | no | 30 | 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 +The other things use another parameter Subindex to add one or more things of this type: -Channels are grouped into channel groups. +| Parameter | Type | Required | Default if omitted | Description | +| --------- | ------- | -------- | ------------------ | -------------------------------------------------------------------------- | +| Subindex | integer | yes | 0 | Subindex for things of the same thing type, starting with 0 | -### General Ambient Group +| Thing Type | Range | +| ---------------------- | ------- | +| Lambda Heatpump | 0..2 | +| Lambda Boiler | 0..4 | +| Lambda Buffer | 0..4 | +| Lambda Heating Circuit | 0..11 | -This group contains general operational information about the heat pump. +## Channels + +Channels within the things are grouped into channel groups. +### Lambda General: General Ambient Group -| Channel ID | Item Type | Read only | Unit | Description | +This group contains ambient temperatures for the heat pump system. + +<<<<<<< HEAD +| Channel ID | Item Type | Read only | Unit | Description | | -------------------------------- | ------------------ | --------- | -------- | ------------------------------------------------------------------------ | -| ambient-error-number | Number | true | [Nr] | Ambient Error Number (0 = No error) | +| ambient-error-number | Number | true | [Nr] | Ambient Error Number (0 = No error) | | ambient-operating-state | Number | true | [Nr] | Ambient Operating State (0 = OFF, 1 = AUTOMATIC, 2 = MANUAL, 3 = ERROR) | -| actual-ambient-temperature | Number:Temperature | false | [0.1 °C] | Actual Ambient Temperature (min = -50.0°C); max = 80.0° | -| average-ambient-temperature | Number:Temperature | true | [0.1 °C] | Arithmetic average temperature of the last 60 minutes | -| calculated-ambient-temperature | Number:Temperature | true | [0.1 °C] | Temperature for calculations in heat distribution modules | +| actual-ambient-temperature | Number:Temperature | false | [0.1 °C] | Actual Ambient Temperature (min = -50.0°C); max = 80.0° | +| average-ambient-temperature | Number:Temperature | true | [0.1 °C] | Arithmetic average temperature of the last 60 minutes | +| calculated-ambient-temperature | Number:Temperature | true | [0.1 °C] | Temperature for calculations in heat distribution modules | ### General E-Manager Group +======= +| Channel ID | Item Type | Read only | Description | +| -------------------------------- | ------------------ | --------- | ------------------------------------------------------------------------ | +| ambient-error-number | Number | true | Ambient Error Number (0 = No error) | +| ambient-operating-state | Number | true | Ambient Operating State (0 = OFF, 1 = AUTOMATIC, 2 = MANUAL, 3 = ERROR) | +| actual-ambient-temperature | Number:Temperature | false | Actual Ambient Temperature (min = -50.0°C); max = 80.0° | +| average-ambient-temperature | Number:Temperature | true | Arithmetic average temperature of the last 60 minutes | +| calculated-ambient-temperature | Number:Temperature | true | Temperature for calculations in heat distribution modules | + +### Lambda General: General E-Manager Group +>>>>>>> a94b30930a27ebb6250a76473a41de81a7945cd6 This group contains parameters signaling the PV excess to the heat pump. -| Channel ID | Item Type | Read only | Unit | Description | -| -------------------------------- | ------------------ | --------- | -------- | --------------------------------------------------------------------------------------- | -| emanager-error-number | Number | true | [Nr] | E-Manager Error Number (0 = No error) | -| emanager-operating-state | Number | true | [Nr] | E-Manager Operating State (0 = OFF, 1 = AUTOMATIC, 2 = MANUAL, 3 = ERROR 4 = OFFLINE | -| actual-power | Number:Power | false | [W] | Actual excess power -32768 W .. 32767 W | -| actual-power-consumption | Number:Power | true | [W] | Power consumption of heatpump 1 (only valid when Betriebsart: Automatik, 0 W otherwise) | -| power-consumption-setpoint | Number:Power | false | [W] | Power consumption setpoint for heat pump 1 | - +| Channel ID | Item Type | Read only | Description | +| -------------------------------- | ------------------ | --------- | --------------------------------------------------------------------------------------- | +| emanager-error-number | Number | true | E-Manager Error Number (0 = No error) | +| emanager-operating-state | Number | true | E-Manager Operating State (0 = OFF, 1 = AUTOMATIC, 2 = MANUAL, 3 = ERROR 4 = OFFLINE | +| actual-power | Number:Power | false | Actual excess power -32768 W .. 32767 W | +| actual-power-consumption | Number:Power | true | Power consumption of heatpump (only valid when Betriebsart: Automatik, 0 W otherwise) | +| power-consumption-setpoint | Number:Power | false | Power consumption setpoint for heat pump 1 | +<<<<<<< HEAD ### Heat Pump 1 Group +======= +### Labda Heat Pump: Heatpump Group +>>>>>>> a94b30930a27ebb6250a76473a41de81a7945cd6 This group contains general operational information about the heat pump itself. -| Channel ID | Item Type | Read only | Unit | Description | -| -------------------------------| ------------------------- | --------- | ------------ | ----------------------------------------------------------------------- | -| heatpump1-error-state | Number | true | [Nr] | Error state (0 = NONE, 1 = MESSAGE, 2 = WARNING, 3 = ALARM, 4 = FAULT )| -| heatpump1-error-number | Number | true | [Nr] | Error number: scrolling through all active error number (1..99) | -| heatpump1-state | Number | true | [Nr] | State: See Modbus description manual of the manufacterer | -| heatpump1-operating-state | Number | true | [Nr] | Operating State: See Modbus description manual, link above | -| heatpump1-t-flow | Number:Temperature | true | [0.01°C] | Flow line termperature | -| heatpump1-t-return | Number:Temperature | true | [0.01°C] | Return line temperature | -| heatpump1-vol-sink | Number:VolumetricFlowRate | true | [0.01 l/min] | Volume flow heat sink | -| heatpump1-t-eqin | Number:Temperature | true | [0.01°C] | Energy source inlet temperature | -| heatpump1-t-eqout | Number:Temperature | true | [0.01°C] | Energy source outlet temperature | -| heatpump1-vol-source | Number:VolumetricFlowRate | true | [0.01 l/min] | Volume flow energy source | -| heatpump1-compressor-rating | Number | true | [0.01%] | Compressor unit rating | -| heatpump1-qp-heating | Number:Power | true | [0.1kW] | Actual heating capacity | -| heatpump1-fi-power-consumption | Number:Power | true | [W] | Frequency inverter actual power consumption | -| heatpump1-cop | Number | true | [0.01%] | Coefficient of performance | -| heatpump1-set-error-quit | Number | false | [Nr] | Set Error Quit (1 = Quit all active heat pump errors | - - +| Channel ID | Item Type | Read only | Description | +| -------------------------------| -------------------------| --------- | ----------------------------------------------------------------------- | +| heatpump-error-state | Number | true | Error state (0 = NONE, 1 = MESSAGE, 2 = WARNING, 3 = ALARM, 4 = FAULT) | +| heatpump-error-number | Number | true | Error number: scrolling through all active error numbers (1..99) | +| heatpump-state | Number | true | State: See Modbus description manual, link above | +| heatpump-operating-state | Number | true | Operating State: See Modbus description manual, link above | +| heatpump-t-flow | Number:Temperature | true | Flow line termperature | +| heatpump-t-return | Number:Temperature | true | Return line temperature | +| heatpump-vol-sink | Number:VolumetricFlowRate | true | Volume flow heat sink | +| heatpump-t-eqin | Number:Temperature | true | Energy source inlet temperature | +| heatpump-t-eqout | Number:Temperature | true | Energy source outlet temperature | +| heatpump-vol-source | Number:VolumetricFlowRate | true | Volume flow energy source | +| heatpump-compressor-rating | Number | true | Compressor unit rating | +| heatpump-qp-heating | Number:Power | true | Actual heating capacity | +| heatpump-fi-power-consumption | Number:Power | true | Frequency inverter actual power consumption | +| heatpump-cop | Number | true | Coefficient of performance | +| heatpump-vdae | Number:Energy | true | Accumulated electrical energy consumption of compressor unit | +| heatpump-vdaq | Number:Energy | true | Accumulated thermal energy output of compressor unit | +| heatpump-set-error-quit | Number | false | Set Error Quit (1 = Quit all active heat pump errors | + +<<<<<<< HEAD ### Boiler 1 Group +======= +### Lambda Boiler: Boiler Group +>>>>>>> a94b30930a27ebb6250a76473a41de81a7945cd6 This group contains information about the boiler for the water for domestic use / tap water / washwater. -| Channel ID | Item Type | Read only | Unit | Description | -| ---------------------------------- | ------------------ | --------- | -------- | --------------------------------------------------------------------| -| boiler1-error-number | Number | true | [Nr] | Boiler 1 Error Number(0 = No error) | -| boiler1-operating-state | Number | true | [Nr] | Boiler 1 Operating State: See Modbus description manual, link above | -| boiler1-actual-high-temperature | Number:Temperature | true | [0.1 °C] | Actual temperature boiler high sensor | -| boiler1-actual-low-temperature | Number:Temperature | true | [0.1 °C] | Actual temperature boiler low sensor | -| boiler1-maximum-boiler-temperature | Number:Temperature | false | [0.1 °C] | Setting for maximum boiler temperature (min = 25.0°C; max = 65.0°C) | +| Channel ID | Item Type | Read only | Description | +| --------------------------------- | ------------------ | --------- | ------------------------------------------------------------------ | +| boiler-error-number | Number | true | Boiler Error Number(0 = No error) | +| boiler-operating-state | Number | true | Boiler Operating State: See Modbus description manual, link above | +| boiler-actual-high-temperature | Number:Temperature | true | Actual temperature boiler high sensor | +| boiler-actual-low-temperature | Number:Temperature | true | Actual temperature boiler low sensor | +| boiler-maximum-boiler-temperature | Number:Temperature | false | Setting for maximum boiler temperature (min = 25.0°C; max = 65.0°C)| -### Buffer 1 Group +### Lambda Buffer: Buffer Group This group contains information about the buffer for the heating circuit. -| Channel ID | Item Type | Read only | Unit | Description | -| ------------------------------- | ------------------ | --------- | -------- | -----------------------------------------------------------------------| -| buffer1-error-number | Number | true | [Nr] | Buffer 1 Error Number (0 = No error) | -| buffer1-operating-state | Number | true | [Nr] | Buffer 1 Operating State: See Modbus description manual, link above | -| buffer1-actual-high-temperature | Number:Temperature | true | [0.1 °C] | Actual temperature buffer high sensor | -| buffer1-actual-low-temperature | Number:Temperature | true | [0.1 °C] | Actual temperature buffer low sensor | -| Buffer 1 Maximum Temperature | Number:Temperature | false | [0.1 °C] | Setting for maximum buffer temperature (min = 25.0°C; max = 65.0°C) | - +| Channel ID | Item Type | Read only | Description | +| -------------------------------------- | ------------------ | --------- | ---------------------------------------------------------------------- | +| buffer-error-number | Number | true | Buffer Error Number (0 = No error) | +| buffer-operating-state | Number | true | Buffer Operating State: See Modbus description manual, link above | +| buffer-actual-high-temperature | Number:Temperature | true | Actual temperature buffer high sensor | +| buffer-actual-low-temperature | Number:Temperature | true | Actual temperature buffer low sensor | +| buffer-maximum-buffer-temperature | Number:Temperature | false | Setting for maximum buffer temperature (min = 25.0°C; max = 65.0°C) | +<<<<<<< HEAD ### Heating Circuit 1 Group This group contains general operational information about the heating circuit 1. -| Channel ID | Item Type | Read only | Unit | Description | +| Channel ID | Item Type | Read only | Unit | Description | | ---------------------------------------------- | -------------------| --------- | ------------ | --------------------------------------------------------------------------------| -| heatingcircuit1-error-number | Number | true | [Nr] | Error Number (0 = No error) | -| heatingcircuit1-operating-state | Number | true | [Nr] | Operating State: See Modbus description manual, link above| | -| heatingcircuit1-flow-line-temperature | Number:Temperature | true | [Nr] | Actual temperature flow line sensor | -| heatingcircuit1-return-line-temperature | Number:Temperature | true | [Nr] | Actual temperature return line sensor | -| heatingcircuit1-room-device-temperature | Number:Temperature | true | [0.01°C] | Actual temperature room device sensor (min = -29.9°C; max = 99.9°C) | -| heatingcircuit1-setpoint-flow-line-temperature | Number:Temperature | true | [0.01°C] | Setpoint temperature flow line (min = 15.0°C; max = 65.0°C) | -| heatingcircuit1-operating-mode | Number | true | [Nr] | Operating Mode: See Modbus description manual, link above | -| heatingcircuit1-offset-flow-line-temperature | Number:Temperature | true | [0.01°C] | Setting for flow line temperature setpoint offset(min = -10.0K; max = 10.0K) | -| heatingcircuit1-room-heating-temperature | Number:Temperature | rue | [0.01°C] | Setting for heating mode room setpoint temperature(min = 15.0°C; max = 40.0 °C) | -| eatingcircuit1-room-cooling-temperature | Number:Temperature | true | [0.01 l/min] | Setting for cooling mode room setpoint temperature(min = 15.0°C; max = 40.0 °C) | +| heatingcircuit1-error-number | Number | true | [Nr] | Error Number (0 = No error) | +| heatingcircuit1-operating-state | Number | true | [Nr] | Operating State: See Modbus description manual, link above| | +| heatingcircuit1-flow-line-temperature | Number:Temperature | true | [Nr] | Actual temperature flow line sensor | +| heatingcircuit1-return-line-temperature | Number:Temperature | true | [Nr] | Actual temperature return line sensor | +| heatingcircuit1-room-device-temperature | Number:Temperature | true | [0.01°C] | Actual temperature room device sensor (min = -29.9°C; max = 99.9°C) | +| heatingcircuit1-setpoint-flow-line-temperature | Number:Temperature | true | [0.01°C] | Setpoint temperature flow line (min = 15.0°C; max = 65.0°C) | +| heatingcircuit1-operating-mode | Number | true | [Nr] | Operating Mode: See Modbus description manual, link above | +| heatingcircuit1-offset-flow-line-temperature | Number:Temperature | true | [0.01°C] | Setting for flow line temperature setpoint offset(min = -10.0K; max = 10.0K) | +| heatingcircuit1-room-heating-temperature | Number:Temperature | rue | [0.01°C] | Setting for heating mode room setpoint temperature(min = 15.0°C; max = 40.0 °C) | +| heatingcircuit1-room-cooling-temperature | Number:Temperature | true | [0.01 l/min] | Setting for cooling mode room setpoint temperature(min = 15.0°C; max = 40.0 °C) | +======= +### Lambda Heating: Heating Circuit Group + +This group contains general operational information about the heating circuit. + +| Channel ID | Item Type | Read only | Description | +| --------------------------------------------- | -------------------| --------- | ------------------------------------------------------------------------------- | +| heatingcircuit-error-number | Number | true | Error Number (0 = No error) | +| heatingcircuit-operating-state | Number | true | Operating State: See Modbus description manual, link above| | +| heatingcircuit-flow-line-temperature | Number:Temperature | true | Actual temperature flow line sensor | +| heatingcircuit-return-line-temperature | Number:Temperature | true | Actual temperature return line sensor | +| heatingcircuit-room-device-temperature | Number:Temperature | false | Actual temperature room device sensor (min = -29.9°C; max = 99.9°C) | +| heatingcircuit-setpoint-flow-line-temperature | Number:Temperature | false | Setpoint temperature flow line (min = 15.0°C; max = 65.0°C) | +| heatingcircuit-operating-mode | Number | false | Operating Mode: See Modbus description manual, link above | +| heatingcircuit-offset-flow-line-temperature | Number:Temperature | false | Setting for flow line temperature setpoint offset(min = -10.0K; max = 10.0K) | +| heatingcircuit-room-heating-temperature | Number:Temperature | false | Setting for heating mode room setpoint temperature(min = 15.0°C; max = 40.0 °C) | +| heatingcircuit-room-cooling-temperature | Number:Temperature | false | Setting for cooling mode room setpoint temperature(min = 15.0°C; max = 40.0 °C) | +>>>>>>> a94b30930a27ebb6250a76473a41de81a7945cd6 +## Full Example +### Things +```java +Bridge modbus:tcp:Lambda_Bridge "Lambda Modbus TCP Bridge" [ host="192.168.223.83", port=502, id=1, enableDiscovery=false ] { + Thing lambda-general lambdageneral "Lambda General" (modbus:tcp:Lambda_Bridge) [ refresh=60, subindex=0 ] + Thing lambda-heatpump lambdaheatpump "Lambda Heatpump" (modbus:tcp:Lambda_Bridge) [ refresh=60, subindex=0 ] + Thing lambda-boiler lambdaboiler "Lambda Boiler" (modbus:tcp:Lambda_Bridge) [ refresh=60, subindex=0 ] + Thing lambda-buffer lambdabuffer "Lambda Buffer" (modbus:tcp:Lambda_Bridge) [ refresh=60, subindex=0 ] + Thing lambda-heatingcircuit lambdaheatingcircuit "Lambda Heating Circuit" (modbus:tcp:Lambda_Bridge) [ refresh=60, subindex=0 ] +} +``` -## Full Example +### Items Lambda General +```java +Number lambdaambient_operatingstate "Ambient Operating State" (lambdageneral) { channel="modbus:lambda-general:Lambda_Bridge:lambdageneral:ambient-group#ambient-operating-state" } +Number lambdaambient_errornumber "Ambient Error Number" (lambdageneral) { channel="modbus:lambda-general:Lambda_Bridge:lambdageneral:ambient-group#ambient-error-number" } +Number:Temperature lambdaambient_actualambienttemperature "Ambient Actual Temperature" (lambdageneral) { channel="modbus:lambda-general:Lambda_Bridge:lambdageneral:ambient-group#actual-ambient-temperature" } +Number:Temperature lambdaambient_averageambienttemperature "Ambient Average Temperature" (lambdageneral) { channel="modbus:lambda-general:Lambda_Bridge:lambdageneral:ambient-group#average-ambient-temperature" } +Number:Temperature lambdaambient_calculatedambienttemperature "Ambient Calculated Temperature" (lambdageneral) { channel="modbus:lambda-general:Lambda_Bridge:lambdageneral:ambient-group#calculated-ambient-temperature" } +Number lambdaemanager_operatingstate "EManager Operating State" (lambdageneral) { channel="modbus:lambda-general:Lambda_Bridge:lambdageneral:emanager-group#emanager-operating-state" } +Number lambdaemanager_errornumber "EManager Error Number" (lambdageneral) { channel="modbus:lambda-general:Lambda_Bridge:lambdageneral:emanager-group#emanager-error-number" } +Number:Power lambdaemanager_actualpower "EManager Actual Power" (lambdageneral) { channel="modbus:lambda-general:Lambda_Bridge:lambdageneral:emanager-group#actual-power" } +Number:Power lambdaemanager_actualpowerconsumption "EManager Actual Power Consumption" (lambdageneral) { channel="modbus:lambda-general:Lambda_Bridge:lambdageneral:emanager-group#actual-power-consumption" } +Number:Power lambdaemanager_powerconsumptionsetpoint "EManager Power Consumption Setpoint" (lambdageneral) { channel="modbus:lambda-general:Lambda_Bridge:lambdageneral:emanager-group#power-consumption-setpoint" } +``` + +### Items Lambda Heatpump +```java +Number lambdaheatpump_errorstate "Heatpump Error State" (lambdaheatpump) { channel="modbus:lambda-heatpump:Lambda_Bridge:lambdaheatpump:heatpump-group#heatpump-error-state" } +Number lambdaheatpump_errornumber "Heatpump Error Number" (lambdaheatpump) { channel="modbus:lambda-heatpump:Lambda_Bridge:lambdaheatpump:heatpump-group#heatpump-error-number" } +Number lambdaheatpump_state "Heatpump State" (lambdaheatpump) { channel="modbus:lambda-heatpump:Lambda_Bridge:lambdaheatpump:heatpump-group#heatpump-state" } +Number lambdaheatpump_operatingstate "Heatpump Operating State" (lambdaheatpump) { channel="modbus:lambda-heatpump:Lambda_Bridge:lambdaheatpump:heatpump-group#heatpump-operating-state" } +Number:Temperature lambdaheatpump_tflow "Heatpump Flow Line Temperature" (lambdaheatpump) { channel="modbus:lambda-heatpump:Lambda_Bridge:lambdaheatpump:heatpump-group#heatpump-t-flow" } +Number:Temperature lambdaheatpump_treturn "Heatpump Return Line Temperature" (lambdaheatpump) { channel="modbus:lambda-heatpump:Lambda_Bridge:lambdaheatpump:heatpump-group#heatpump-t-return" } +Number:VolumetricFlowRate lambdaheatpump_volsink "Heatpump Volume Flow Heat Sink" (lambdaheatpump) { channel="modbus:lambda-heatpump:Lambda_Bridge:lambdaheatpump:heatpump-group#heatpump-vol-sink" } +Number:Temperature lambdaheatpump_teqin "Heatpump Energy Source Inlet Temperature" (lambdaheatpump) { channel="modbus:lambda-heatpump:Lambda_Bridge:lambdaheatpump:heatpump-group#heatpump-t-eqin" } +Number:Temperature lambdaheatpump_teqout "Heatpump Energy Source Outlet Temperature" (lambdaheatpump) { channel="modbus:lambda-heatpump:Lambda_Bridge:lambdaheatpump:heatpump-group#heatpump-t-eqout" } +Number:VolumetricFlowRate lambdaheatpump_volsource "Heatpump Volume Flow Energy Source" (lambdaheatpump) { channel="modbus:lambda-heatpump:Lambda_Bridge:lambdaheatpump:heatpump-group#heatpump-vol-source" } +Number lambdaheatpump_compressorrating "Heatpump Compressor Rating" (lambdaheatpump) { channel="modbus:lambda-heatpump:Lambda_Bridge:lambdaheatpump:heatpump-group#heatpump-compressor-rating" } +Number:Power lambdaheatpump_qpheating "Heatpump Actual Heating Capacity" (lambdaheatpump) { channel="modbus:lambda-heatpump:Lambda_Bridge:lambdaheatpump:heatpump-group#heatpump-qp-heating" } +Number:Power lambdaheatpump_fipowerconsumption "Heatpump Frequency inverter Actual Power Consumption" (lambdaheatpump) { channel="modbus:lambda-heatpump:Lambda_Bridge:lambdaheatpump:heatpump-group#heatpump-fi-power-consumption" } +Number lambdaheatpump_cop "Heatpump COP" (lambdaheatpump) { channel="modbus:lambda-heatpump:Lambda_Bridge:lambdaheatpump:heatpump-group#heatpump-cop" } +Number:Energy lambdaheatpump_vdae "Heatpump Accumulated Electrical Energy consumption" (lambdaheatpump) { channel="modbus:lambda-heatpump:Lambda_Bridge:lambdaheatpump:heatpump-group#heatpump-vdae" } +Number:Energy lambdaheatpump_vdaq "Heatpump Accumulated Thermical Energy consumption" (lambdaheatpump) { channel="modbus:lambda-heatpump:Lambda_Bridge:lambdaheatpump:heatpump-group#heatpump-vdaq" } +Number lambdaheatpump_seterrorquit "Heatpump Set Error Quit" (lambdaheatpump) { channel="modbus:lambda-heatpump:Lambda_Bridge:lambdaheatpump:heatpump-group#heatpump-set-error-quit" } +``` + +### Items Lambda Boiler +```java +Number lambdaboiler_operatingstate "Boiler Operating State" (lambdaboiler) { channel="modbus:lambda-boiler:Lambda_Bridge:lambdaboiler:boiler-group#boiler-operating-state" } +Number lambdaboiler_errornumber "Boiler Error Number" (lambdaboiler) { channel="modbus:lambda-boiler:Lambda_Bridge:lambdaboiler:boiler-group#boiler-error-number" } +Number:Temperature lambdaboiler_actualhightemperature "Boiler Actual High Temperature" (lambdaboiler) { channel="modbus:lambda-boiler:Lambda_Bridge:lambdaboiler:boiler-group#boiler-actual-high-temperature" } +Number:Temperature lambdaboiler_actuallowtemperature "Boiler Actual Low Temperature" (lambdaboiler) { channel="modbus:lambda-boiler:Lambda_Bridge:lambdaboiler:boiler-group#boiler-actual-low-temperature" } +Number:Temperature lambdaboiler_maximumboilertemperature "Maximum Boiler Temperature" (lambdaboiler) { channel="modbus:lambda-boiler:Lambda_Bridge:lambdaboiler:boiler-group#boiler-maximum-boiler-temperature" } +``` + +### Items Lambda Buffer +```java +Number lambdabuffer_operatingstate "Buffer Operating State" (lambdabuffer) { channel="modbus:lambda-buffer:Lambda_Bridge:lambdabuffer:buffer-group#buffer-operating-state" } +Number lambdabuffer_errornumber "Buffer Error Number" (lambdabuffer) { channel="modbus:lambda-buffer:Lambda_Bridge:lambdabuffer:buffer-group#buffer-error-number" } +Number:Temperature lambdabuffer_actualhightemperature "Buffer Actual High Temperature" (lambdabuffer) { channel="modbus:lambda-buffer:Lambda_Bridge:lambdabuffer:buffer-group#buffer-actual-high-temperature" } +Number:Temperature lambdabuffer_actuallowtemperature "Buffer Actual Low Temperature" (lambdabuffer) { channel="modbus:lambda-buffer:Lambda_Bridge:lambdabuffer:buffer-group#buffer-actual-low-temperature" } +Number:Temperature lambdabuffer_maximumbuffertemperature "Maximum Buffer Temperature" (lambdabuffer) { channel="modbus:lambda-buffer:Lambda_Bridge:lambdabuffer:buffer-group#buffer-maximum-buffer-temperature" } +``` + + +### Items Heatingcircuit +```java +Number lambdaheatingcircuit_errornumber "Heatingcircuit Error Number" (lambdaheatingcircuit) { channel="modbus:lambda-heatingcircuit:Lambda_Bridge:lambdaheating:heatingcircuit-group#heatingcircuit-error-number" } +Number lambdaheatingcircuit_operatingstate "Heatingcircuit Operating State" (lambdaheatingcircuit) { channel="modbus:lambda-heatingcircuit:Lambda_Bridge:lambdaheating:heatingcircuit-group#heatingcircuit-operating-state" } +Number:Temperature lambdaheatingcircuit_flowlinetemperature "Heatingcircuit Flow Line Temperature" (lambdaheatingcircuit) { channel="modbus:lambda-heatingcircuit:Lambda_Bridge:lambdaheating:heatingcircuit-group#heatingcircuit-flow-line-temperature" } +Number:Temperature lambdaheatingcircuit_returnlinetemperature "Heatingcircuit Return Line Temperature" (lambdaheatingcircuit) { channel="modbus:lambda-heatingcircuit:Lambda_Bridge:lambdaheating:heatingcircuit-group#heatingcircuit-return-line-temperature" } +Number:Temperature lambdaheatingcircuit_roomdevicetemperature "Heatingcircuit Room Device Temperature" (lambdaheatingcircuit) { channel="modbus:lambda-heatingcircuit:Lambda_Bridge:lambdaheating:heatingcircuit-group#heatingcircuit-room-device-temperature" } +Number:Temperature lambdaheatingcircuit_setpointflowlinetemperature "Heatingcircuit Setpoint Flow Line Temperature" (lambdaheatingcircuit) { channel="modbus:lambda-heatingcircuit:Lambda_Bridge:lambdaheating:heatingcircuit-group#heatingcircuit-setpoint-flow-line-temperature" } +Number lambdaheatingcircuit_operatingmode "Heatingcircuit Operating Mode" (lambdaheatingcircuit) { channel="modbus:lambda-heatingcircuit:Lambda_Bridge:lambdaheating:heatingcircuit-group#heatingcircuit-operating-mode" } +Number:Temperature lambdaheatingcircuit_offsetflowlinetemperature "Heatingcircuit Offset Flow Line Temperature" (lambdaheatingcircuit) { channel="modbus:lambda-heatingcircuit:Lambda_Bridge:lambdaheating:heatingcircuit-group#heatingcircuit-offset-flow-line-temperature" } +Number:Temperature lambdaheatingcircuit_roomheatingtemperature "Heatingcircuit Room Heating Temperature" (lambdaheatingcircuit) { channel="modbus:lambda-heatingcircuit:Lambda_Bridge:lambdaheating:heatingcircuit-group#heatingcircuit-room-heating-temperature" } +Number:Temperature lambdaheatingcircuit_roomcoolingtemperature "Heatingcircuit Room Cooling Temperature" (lambdaheatingcircuit) { channel="modbus:lambda-heatingcircuit:Lambda_Bridge:lambdaheating:heatingcircuit-group#heatingcircuit-room-cooling-temperature" } +``` + +### Example: (DSL) Send Power value the E-Manager of the Lambda Heat Pump +// Sending Value to Heatpump +// Script has to send a value about every 30 seconds, for example with cron settings +// Calculate power_to_heatpump using your data provided by the PV system +// var int power_to_heatpump = ((lambdaemanager_actualpowerconsumption.state as Number) - (PV_Battery.state as Number) - (PV_Grid.state as Number)).intValue + +var int power_to_heatpump = 1000 -### Thing Configuration -UID: modbus:tcp:Lambda_Bridge -label: Lambda Modbus Bridge -thingTypeUID: modbus:tcp -configuration: - rtuEncoded: false - connectMaxTries: 1 - reconnectAfterMillis: 0 - timeBetweenTransactionsMillis: 100 - port: 502 - timeBetweenReconnectMillis: 0 - connectTimeoutMillis: 10000 - host: 192.168.223.83 - afterConnectionDelayMillis: 0 - id: 1 - enableDiscovery: false - -### Example to write PV excess to the Lambda Heat Pump -// PV_Battery.state and PV_Grid have to be provided by your PV inverter -// Mode of E-Manager has to be switched to AUTOMATIK in the Lambda Heat Pump App -var int P_Available = ((Lambda_EMgr_Power_Consumption_Value_as_Number.state as Number) - (PW_Battery.state as Number) - (PW_Grid.state as Number)).intValue - lambdahp_actual_power.sendCommand(P_Available) + lambdahp_actual_power.sendCommand(power_to_heatpump) diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/BoilerConfiguration.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/BoilerConfiguration.java new file mode 100644 index 0000000000000..419010eceff01 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/BoilerConfiguration.java @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link BoilerConfiguration} class contains fields mapping + * thing configuration parameters. + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + */ +@NonNullByDefault +public class BoilerConfiguration { + + /** + * Refresh interval in seconds + */ + private int refresh = 30; + + private int maxTries = 3; + // backwards compatibility and tests + + /** + * Subindex to calculate the base adress of the modbus registers + */ + private int subindex = 0; + + /** + * Gets refresh period in milliseconds + */ + public long getRefreshMillis() { + return refresh * 1000; + } + + public int getMaxTries() { + return maxTries; + } + + public void setMaxTries(int maxTries) { + this.maxTries = maxTries; + } + + public int getSubindex() { + return subindex; + } + + public void setSubindex(int subindex) { + this.subindex = subindex; + } +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/BufferConfiguration.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/BufferConfiguration.java new file mode 100644 index 0000000000000..309d310c95c47 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/BufferConfiguration.java @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link BufferConfiguration} class contains fields mapping + * thing configuration parameters. + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + */ +@NonNullByDefault +public class BufferConfiguration { + /** + * Refresh interval in seconds + */ + private int refresh = 30; + + private int maxTries = 3; + // backwards compatibility and tests + + /** + * Subindex to calculate the base adress of the modbus registers + */ + private int subindex = 0; + + /** + * Gets refresh period in milliseconds + */ + public long getRefreshMillis() { + return refresh * 1000; + } + + public int getMaxTries() { + return maxTries; + } + + public void setMaxTries(int maxTries) { + this.maxTries = maxTries; + } + + public int getSubindex() { + return subindex; + } + + public void setSubindex(int subindex) { + this.subindex = subindex; + } +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/GeneralConfiguration.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/GeneralConfiguration.java new file mode 100644 index 0000000000000..e0fea1fa8dba6 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/GeneralConfiguration.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link GeneralConfiguration} class contains fields mapping + * thing configuration parameters. + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + */ +@NonNullByDefault +public class GeneralConfiguration { + /** + * Refresh interval in seconds + */ + private int refresh = 30; + + 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.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/HeatingCircuitConfiguration.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/HeatingCircuitConfiguration.java new file mode 100644 index 0000000000000..80e904f0cc36f --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/HeatingCircuitConfiguration.java @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link HeatingCircuitConfiguration} class contains fields mapping + * thing configuration parameters. + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + */ +@NonNullByDefault +public class HeatingCircuitConfiguration { + /** + * Refresh interval in seconds + */ + private int refresh = 30; + + private int maxTries = 3; + // backwards compatibility and tests + + /** + * Subindex to calculate the base adress of the modbus registers + */ + private int subindex = 0; + + /** + * Gets refresh period in milliseconds + */ + public long getRefreshMillis() { + return refresh * 1000; + } + + public int getMaxTries() { + return maxTries; + } + + public void setMaxTries(int maxTries) { + this.maxTries = maxTries; + } + + public int getSubindex() { + return subindex; + } + + public void setSubindex(int subindex) { + this.subindex = subindex; + } +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/HeatpumpConfiguration.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/HeatpumpConfiguration.java new file mode 100644 index 0000000000000..36f9d6f5022e9 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/HeatpumpConfiguration.java @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link HeatpumpConfiguration} class contains fields mapping + * thing configuration parameters. + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + */ +@NonNullByDefault +public class HeatpumpConfiguration { + + /** + * Refresh interval in seconds + */ + private int refresh = 30; + + private int maxTries = 3; + + // backwards compatibility and tests + + /** + * Subindex to calculate the base adress of the modbus registers + */ + private int subindex = 0; + + /** + * Gets refresh period in milliseconds + */ + public long getRefreshMillis() { + return refresh * 1000; + } + + public int getMaxTries() { + return maxTries; + } + + public void setMaxTries(int maxTries) { + this.maxTries = maxTries; + } + + public int getSubindex() { + return subindex; + } + + public void setSubindex(int subindex) { + this.subindex = subindex; + } +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaBindingConstants.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaBindingConstants.java index 31bb067db6bdb..eb7f66e9c5133 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaBindingConstants.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaBindingConstants.java @@ -27,21 +27,31 @@ public class LambdaBindingConstants { private static final String BINDING_ID = ModbusBindingConstants.BINDING_ID; + private static final String LAMBDAGENERAL = "lambda-general"; + private static final String LAMBDABOILER = "lambda-boiler"; + private static final String LAMBDABUFFER = "lambda-buffer"; + private static final String LAMBDAHEATPUMP = "lambda-heatpump"; + private static final String LAMBDAHEATINGCIRCUIT = "lambda-heatingcircuit"; // List of all Thing Type UIDs - public static final ThingTypeUID THING_TYPE_LAMBDAHP = new ThingTypeUID(BINDING_ID, "lambdahp"); + public static final ThingTypeUID THING_TYPE_LAMBDAGENERAL = new ThingTypeUID(BINDING_ID, LAMBDAGENERAL); + public static final ThingTypeUID THING_TYPE_LAMBDABOILER = new ThingTypeUID(BINDING_ID, LAMBDABOILER); + public static final ThingTypeUID THING_TYPE_LAMBDABUFFER = new ThingTypeUID(BINDING_ID, LAMBDABUFFER); + public static final ThingTypeUID THING_TYPE_LAMBDAHEATPUMP = new ThingTypeUID(BINDING_ID, LAMBDAHEATPUMP); + public static final ThingTypeUID THING_TYPE_LAMBDAHEATINGCIRCUIT = new ThingTypeUID(BINDING_ID, + LAMBDAHEATINGCIRCUIT); // Channel group ids - public static final String GROUP_GENERAL_AMBIENT = "generalAmbient"; - public static final String GROUP_GENERAL_EMANAGER = "generalEManager"; - public static final String GROUP_HEATPUMP1 = "Heatpump1"; - public static final String GROUP_HEATPUMP1SET = "Heatpump1Set"; - public static final String GROUP_BOILER1 = "Boiler1"; - public static final String GROUP_BOILER1MT = "Boiler1Mt"; - public static final String GROUP_BUFFER1 = "Buffer1"; - public static final String GROUP_BUFFER1MT = "Buffer1Mt"; - public static final String GROUP_HEATINGCIRCUIT1 = "HeatingCircuit1"; - public static final String GROUP_HEATINGCIRCUIT1SETTING = "HeatingCircuit1Setting"; + public static final String GROUP_GENERAL_AMBIENT = "ambient-group"; + public static final String GROUP_GENERAL_EMANAGER = "emanager-group"; + public static final String GROUP_HEATPUMP = "heatpump-group"; + public static final String GROUP_HEATPUMP_REG50 = "heatpump-reg50-group"; + public static final String GROUP_BOILER = "boiler-group"; + public static final String GROUP_BOILER_REG50 = "boiler-reg50-group"; + public static final String GROUP_BUFFER = "buffer-group"; + public static final String GROUP_BUFFER_REG50 = "buffer-reg50-group"; + public static final String GROUP_HEATINGCIRCUIT = "heatingcircuit-group"; + public static final String GROUP_HEATINGCIRCUIT_REG50 = "heatingcircuit-reg50-group"; // List of all Channel ids in device information group // General Ambient @@ -58,47 +68,49 @@ public class LambdaBindingConstants { public static final String CHANNEL_ACTUAL_POWER_CONSUMPTION = "actual-power-consumption"; public static final String CHANNEL_POWER_CONSUMPTION_SETPOINT = "power-consumption-setpoint"; - // Heatpump 1 - public static final String CHANNEL_HEATPUMP1_ERROR_STATE = "heatpump1-error-state"; - public static final String CHANNEL_HEATPUMP1_ERROR_NUMBER = "heatpump1-error-number"; - public static final String CHANNEL_HEATPUMP1_STATE = "heatpump1-state"; - public static final String CHANNEL_HEATPUMP1_OPERATING_STATE = "heatpump1-operating-state"; - public static final String CHANNEL_HEATPUMP1_T_FLOW = "heatpump1-t-flow"; - public static final String CHANNEL_HEATPUMP1_T_RETURN = "heatpump1-t-return"; - public static final String CHANNEL_HEATPUMP1_VOL_SINK = "heatpump1-vol-sink"; - public static final String CHANNEL_HEATPUMP1_T_EQIN = "heatpump1-t-eqin"; - public static final String CHANNEL_HEATPUMP1_T_EQOUT = "heatpump1-t-eqout"; - public static final String CHANNEL_HEATPUMP1_VOL_SOURCE = "heatpump1-vol-source"; - public static final String CHANNEL_HEATPUMP1_COMPRESSOR_RATING = "heatpump1-compressor-rating"; - public static final String CHANNEL_HEATPUMP1_QP_HEATING = "heatpump1-qp-heating"; - public static final String CHANNEL_HEATPUMP1_FI_POWER_CONSUMPTION = "heatpump1-fi-power-consumption"; - public static final String CHANNEL_HEATPUMP1_COP = "heatpump1-cop"; - public static final String CHANNEL_HEATPUMP1_SET_ERROR_QUIT = "heatpump1-set-error-quit"; + // Heatpump + public static final String CHANNEL_HEATPUMP_ERROR_STATE = "heatpump-error-state"; + public static final String CHANNEL_HEATPUMP_ERROR_NUMBER = "heatpump-error-number"; + public static final String CHANNEL_HEATPUMP_STATE = "heatpump-state"; + public static final String CHANNEL_HEATPUMP_OPERATING_STATE = "heatpump-operating-state"; + public static final String CHANNEL_HEATPUMP_T_FLOW = "heatpump-t-flow"; + public static final String CHANNEL_HEATPUMP_T_RETURN = "heatpump-t-return"; + public static final String CHANNEL_HEATPUMP_VOL_SINK = "heatpump-vol-sink"; + public static final String CHANNEL_HEATPUMP_T_EQIN = "heatpump-t-eqin"; + public static final String CHANNEL_HEATPUMP_T_EQOUT = "heatpump-t-eqout"; + public static final String CHANNEL_HEATPUMP_VOL_SOURCE = "heatpump-vol-source"; + public static final String CHANNEL_HEATPUMP_COMPRESSOR_RATING = "heatpump-compressor-rating"; + public static final String CHANNEL_HEATPUMP_QP_HEATING = "heatpump-qp-heating"; + public static final String CHANNEL_HEATPUMP_FI_POWER_CONSUMPTION = "heatpump-fi-power-consumption"; + public static final String CHANNEL_HEATPUMP_COP = "heatpump-cop"; + public static final String CHANNEL_HEATPUMP_VDAE = "heatpump-vdae"; + public static final String CHANNEL_HEATPUMP_VDAQ = "heatpump-vdaq"; + public static final String CHANNEL_HEATPUMP_SET_ERROR_QUIT = "heatpump-set-error-quit"; - // Boiler 1 - public static final String CHANNEL_BOILER1_ERROR_NUMBER = "boiler1-error-number"; - public static final String CHANNEL_BOILER1_OPERATING_STATE = "boiler1-operating-state"; - public static final String CHANNEL_BOILER1_ACTUAL_HIGH_TEMPERATURE = "boiler1-actual-high-temperature"; - public static final String CHANNEL_BOILER1_ACTUAL_LOW_TEMPERATURE = "boiler1-actual-low-temperature"; - public static final String CHANNEL_BOILER1_MAXIMUM_BOILER_TEMPERATURE = "boiler1-maximum-boiler-temperature"; + // Boiler + public static final String CHANNEL_BOILER_ERROR_NUMBER = "boiler-error-number"; + public static final String CHANNEL_BOILER_OPERATING_STATE = "boiler-operating-state"; + public static final String CHANNEL_BOILER_ACTUAL_HIGH_TEMPERATURE = "boiler-actual-high-temperature"; + public static final String CHANNEL_BOILER_ACTUAL_LOW_TEMPERATURE = "boiler-actual-low-temperature"; + public static final String CHANNEL_BOILER_MAXIMUM_BOILER_TEMPERATURE = "boiler-maximum-boiler-temperature"; - // Buffer 1 - public static final String CHANNEL_BUFFER1_ERROR_NUMBER = "buffer1-error-number"; - public static final String CHANNEL_BUFFER1_OPERATING_STATE = "buffer1-operating-state"; - public static final String CHANNEL_BUFFER1_ACTUAL_HIGH_TEMPERATURE = "buffer1-actual-high-temperature"; - public static final String CHANNEL_BUFFER1_ACTUAL_LOW_TEMPERATURE = "buffer1-actual-low-temperature"; - public static final String CHANNEL_BUFFER1_MAXIMUM_BOILER_TEMPERATURE = "buffer1-maximum-boiler-temperature"; + // Buffer + public static final String CHANNEL_BUFFER_ERROR_NUMBER = "buffer-error-number"; + public static final String CHANNEL_BUFFER_OPERATING_STATE = "buffer-operating-state"; + public static final String CHANNEL_BUFFER_ACTUAL_HIGH_TEMPERATURE = "buffer-actual-high-temperature"; + public static final String CHANNEL_BUFFER_ACTUAL_LOW_TEMPERATURE = "buffer-actual-low-temperature"; + public static final String CHANNEL_BUFFER_MAXIMUM_BUFFER_TEMPERATURE = "buffer-maximum-buffer-temperature"; - // Heating Circuit 1 - public static final String CHANNEL_HEATINGCIRCUIT1_ERROR_NUMBER = "heatingcircuit1-error-number"; - public static final String CHANNEL_HEATINGCIRCUIT1_OPERATING_STATE = "heatingcircuit1-operating-state"; - public static final String CHANNEL_HEATINGCIRCUIT1_FLOW_LINE_TEMPERATURE = "heatingcircuit1-flow-line-temperature"; - public static final String CHANNEL_HEATINGCIRCUIT1_RETURN_LINE_TEMPERATURE = "heatingcircuit1-return-line-temperature"; - public static final String CHANNEL_HEATINGCIRCUIT1_ROOM_DEVICE_TEMPERATURE = "heatingcircuit1-room-device-temperature"; - public static final String CHANNEL_HEATINGCIRCUIT1_SETPOINT_FLOW_LINE_TEMPERATURE = "heatingcircuit1-setpoint-flow-line-temperature"; - public static final String CHANNEL_HEATINGCIRCUIT1_OPERATING_MODE = "heatingcircuit1-operating-mode"; - // Heating Cirucuit 1 Set - public static final String CHANNEL_HEATINGCIRCUIT1_OFFSET_FLOW_LINE_TEMPERATURE = "heatingcircuit1-offset-flow-line-temperature"; - public static final String CHANNEL_HEATINGCIRCUIT1_ROOM_HEATING_TEMPERATURE = "heatingcircuit1-room-heating-temperature"; - public static final String CHANNEL_HEATINGCIRCUIT1_ROOM_COOLING_TEMPERATURE = "heatingcircuit1-room-cooling-temperature"; + // Heating Circuit + public static final String CHANNEL_HEATINGCIRCUIT_ERROR_NUMBER = "heatingcircuit-error-number"; + public static final String CHANNEL_HEATINGCIRCUIT_OPERATING_STATE = "heatingcircuit-operating-state"; + public static final String CHANNEL_HEATINGCIRCUIT_FLOW_LINE_TEMPERATURE = "heatingcircuit-flow-line-temperature"; + public static final String CHANNEL_HEATINGCIRCUIT_RETURN_LINE_TEMPERATURE = "heatingcircuit-return-line-temperature"; + public static final String CHANNEL_HEATINGCIRCUIT_ROOM_DEVICE_TEMPERATURE = "heatingcircuit-room-device-temperature"; + public static final String CHANNEL_HEATINGCIRCUIT_SETPOINT_FLOW_LINE_TEMPERATURE = "heatingcircuit-setpoint-flow-line-temperature"; + public static final String CHANNEL_HEATINGCIRCUIT_OPERATING_MODE = "heatingcircuit-operating-mode"; + // Heating Circuit Set + public static final String CHANNEL_HEATINGCIRCUIT_OFFSET_FLOW_LINE_TEMPERATURE = "heatingcircuit-offset-flow-line-temperature"; + public static final String CHANNEL_HEATINGCIRCUIT_ROOM_HEATING_TEMPERATURE = "heatingcircuit-room-heating-temperature"; + public static final String CHANNEL_HEATINGCIRCUIT_ROOM_COOLING_TEMPERATURE = "heatingcircuit-room-cooling-temperature"; } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaConfiguration.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaConfiguration.java index d1c0f6f2217dd..d4a4290a81d33 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaConfiguration.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaConfiguration.java @@ -26,7 +26,7 @@ public class LambdaConfiguration { /** * Refresh interval in seconds */ - private long refresh = 30; + private int refresh = 30; private int maxTries = 3;// backwards compatibility and tests diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaHandlerFactory.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaHandlerFactory.java index ea6fd951e699b..c76514021225f 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaHandlerFactory.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaHandlerFactory.java @@ -12,19 +12,29 @@ */ package org.openhab.binding.modbus.lambda.internal; -import static org.openhab.binding.modbus.lambda.internal.LambdaBindingConstants.THING_TYPE_LAMBDAHP; +import static org.openhab.binding.modbus.lambda.internal.LambdaBindingConstants.THING_TYPE_LAMBDABOILER; +import static org.openhab.binding.modbus.lambda.internal.LambdaBindingConstants.THING_TYPE_LAMBDABUFFER; +import static org.openhab.binding.modbus.lambda.internal.LambdaBindingConstants.THING_TYPE_LAMBDAGENERAL; +import static org.openhab.binding.modbus.lambda.internal.LambdaBindingConstants.THING_TYPE_LAMBDAHEATINGCIRCUIT; +import static org.openhab.binding.modbus.lambda.internal.LambdaBindingConstants.THING_TYPE_LAMBDAHEATPUMP; import java.util.Set; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; -import org.openhab.binding.modbus.lambda.internal.handler.LambdaHandler; +import org.openhab.binding.modbus.lambda.internal.handler.BoilerHandler; +import org.openhab.binding.modbus.lambda.internal.handler.BufferHandler; +import org.openhab.binding.modbus.lambda.internal.handler.GeneralHandler; +import org.openhab.binding.modbus.lambda.internal.handler.HeatingCircuitHandler; +import org.openhab.binding.modbus.lambda.internal.handler.HeatpumpHandler; 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; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * The {@link LambdaHandlerFactory} is responsible for creating things and thing @@ -37,21 +47,39 @@ @Component(configurationPid = "binding.lambda", service = ThingHandlerFactory.class) public class LambdaHandlerFactory extends BaseThingHandlerFactory { - private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_LAMBDAHP); + private final Logger logger = LoggerFactory.getLogger(LambdaHandlerFactory.class); + + private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_LAMBDAGENERAL, + THING_TYPE_LAMBDAHEATPUMP, THING_TYPE_LAMBDABOILER, THING_TYPE_LAMBDABUFFER, + THING_TYPE_LAMBDAHEATINGCIRCUIT); @Override public boolean supportsThingType(ThingTypeUID thingTypeUID) { + // logger.trace("Query LambdaHandlerFactory supportsThingType {} ?", thingTypeUID.toString()); return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID); } @Override protected @Nullable ThingHandler createHandler(Thing thing) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); + // logger.trace("LambdaHandlerFactory ThingHandler searching of {}", thingTypeUID.toString()); - if (THING_TYPE_LAMBDAHP.equals(thingTypeUID)) { - return new LambdaHandler(thing); - } + if (THING_TYPE_LAMBDAGENERAL.equals(thingTypeUID)) { + // logger.debug("LambdaHandlerFactory ThingHandler LAMBDAGENERAL found first place {}", thingTypeUID.toString()); + return new GeneralHandler(thing); + } else if (THING_TYPE_LAMBDAHEATPUMP.equals(thingTypeUID)) { + + return new HeatpumpHandler(thing); + } else if (THING_TYPE_LAMBDABUFFER.equals(thingTypeUID)) { + return new BufferHandler(thing); + } else if (THING_TYPE_LAMBDABOILER.equals(thingTypeUID)) { + + return new BoilerHandler(thing); + } else if (THING_TYPE_LAMBDAHEATINGCIRCUIT.equals(thingTypeUID)) { + + return new HeatingCircuitHandler(thing); + } return null; } } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler1Block.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler1Block.java deleted file mode 100644 index 23df14de5e12b..0000000000000 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler1Block.java +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) 2010-2024 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.lambda.internal.dto; - -/** - * Dto class for the Boiler1 Block - * - * @author Paul Frank - Initial contribution - * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus - * - */ -public class Boiler1Block { - public int boiler1ErrorNumber; - public int boiler1OperatingState; - public int boiler1ActualHighTemperature; - public int boiler1ActualLowTemperature; -} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Buffer1Block.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/BoilerBlock.java similarity index 72% rename from bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Buffer1Block.java rename to bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/BoilerBlock.java index 6af532d4ce044..a47e35b6069bf 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Buffer1Block.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/BoilerBlock.java @@ -13,15 +13,15 @@ package org.openhab.binding.modbus.lambda.internal.dto; /** - * Dto class for the Buffer1 Block + * Dto class for the Boiler Block * * @author Paul Frank - Initial contribution * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus * */ -public class Buffer1Block { - public int buffer1ErrorNumber; - public int buffer1OperatingState; - public int buffer1ActualHighTemperature; - public int buffer1ActualLowTemperature; +public class BoilerBlock { + public int boilerErrorNumber; + public int boilerOperatingState; + public int boilerActualHighTemperature; + public int boilerActualLowTemperature; } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler1MtBlock.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/BoilerReg50Block.java similarity index 83% rename from bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler1MtBlock.java rename to bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/BoilerReg50Block.java index 03ebaa167bb29..0073a81100c15 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Boiler1MtBlock.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/BoilerReg50Block.java @@ -13,13 +13,13 @@ package org.openhab.binding.modbus.lambda.internal.dto; /** - * Dto class for the Boiler1Mt Block + * Dto class for the BoilerReg50 Block * * @author Paul Frank - Initial contribution * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus * */ -public class Boiler1MtBlock { +public class BoilerReg50Block { - public int boiler1MaximumBoilerTemperature; + public int boilerMaximumBoilerTemperature; } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/BufferBlock.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/BufferBlock.java new file mode 100644 index 0000000000000..7b7200c579f4b --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/BufferBlock.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.dto; + +/** + * Dto class for the Buffer Block + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + * + */ +public class BufferBlock { + public int bufferErrorNumber; + public int bufferOperatingState; + public int bufferActualHighTemperature; + public int bufferActualLowTemperature; +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Buffer1MtBlock.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/BufferReg50Block.java similarity index 83% rename from bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Buffer1MtBlock.java rename to bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/BufferReg50Block.java index dd4a04f2def63..86962b537f19b 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Buffer1MtBlock.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/BufferReg50Block.java @@ -13,13 +13,13 @@ package org.openhab.binding.modbus.lambda.internal.dto; /** - * Dto class for the Buffer1Mt Block + * Dto class for the BufferReg50 Block * * @author Paul Frank - Initial contribution * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus * */ -public class Buffer1MtBlock { +public class BufferReg50Block { - public int buffer1MaximumBufferTemperature; + public int bufferMaximumBufferTemperature; } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatingCircuit1Block.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatingCircuit1Block.java deleted file mode 100644 index 17fd2267a0994..0000000000000 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatingCircuit1Block.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.openhab.binding.modbus.lambda.internal.dto; -/** - * Copyright (c) 2010-2024 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 - */ - -/** - * Dto class for the HeatingCircuit1 Block - * - * @author Paul Frank - Initial contribution - * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus - * - */ -public class HeatingCircuit1Block { - - public int heatingcircuit1ErrorNumber; - public int heatingcircuit1OperatingState; - public int heatingcircuit1FlowLineTemperature; - public int heatingcircuit1ReturnLineTemperature; - public int heatingcircuit1RoomDeviceTemperature; - public int heatingcircuit1SetpointFlowLineTemperature; - public int heatingcircuit1OperatingMode; -} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatingCircuit1SettingBlock.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatingCircuitBlock.java similarity index 58% rename from bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatingCircuit1SettingBlock.java rename to bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatingCircuitBlock.java index 325d0809718d2..f5d0794789f20 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatingCircuit1SettingBlock.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatingCircuitBlock.java @@ -1,5 +1,3 @@ -package org.openhab.binding.modbus.lambda.internal.dto; - /** * Copyright (c) 2010-2024 Contributors to the openHAB project * @@ -12,17 +10,22 @@ * * SPDX-License-Identifier: EPL-2.0 */ +package org.openhab.binding.modbus.lambda.internal.dto; /** - * Dto class for the HeatingCircuit1Setting Block + * Dto class for the HeatingCircuit Block * * @author Paul Frank - Initial contribution * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus * */ +public class HeatingCircuitBlock { -public class HeatingCircuit1SettingBlock { - public int heatingcircuit1OffsetFlowLineTemperature; - public int heatingcircuit1RoomHeatingTemperature; - public int heatingcircuit1RoomCoolingTemperature; + public int heatingcircuitErrorNumber; + public int heatingcircuitOperatingState; + public int heatingcircuitFlowLineTemperature; + public int heatingcircuitReturnLineTemperature; + public int heatingcircuitRoomDeviceTemperature; + public int heatingcircuitSetpointFlowLineTemperature; + public int heatingcircuitOperatingMode; } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatingCircuitReg50Block.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatingCircuitReg50Block.java new file mode 100644 index 0000000000000..92cf54747dc82 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatingCircuitReg50Block.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.dto; + +/** + * Dto class for the HeatingCircuitReg50 Block + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + * + */ + +public class HeatingCircuitReg50Block { + public int heatingcircuitOffsetFlowLineTemperature; + public int heatingcircuitRoomHeatingTemperature; + public int heatingcircuitRoomCoolingTemperature; +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Heatpump1Block.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Heatpump1Block.java deleted file mode 100644 index e88df2b93c1c0..0000000000000 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Heatpump1Block.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.openhab.binding.modbus.lambda.internal.dto; -/** - * Copyright (c) 2010-2024 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 - */ - -/** - * Dto class for the Heatpump1 Block - * - * @author Paul Frank - Initial contribution - * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus - * - */ -public class Heatpump1Block { - public int heatpump1ErrorState; - public int heatpump1ErrorNumber; - public int heatpump1State; - public int heatpump1OperatingState; - public int heatpump1TFlow; - public int heatpump1TReturn; - public int heatpump1VolSink; - public int heatpump1TEQin; - public int heatpump1TEQout; - public int heatpump1VolSource; - public int heatpump1CompressorRating; - public int heatpump1QpHeating; - public int heatpump1FIPowerConsumption; - public int heatpump1COP; -} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatpumpBlock.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatpumpBlock.java new file mode 100644 index 0000000000000..a563ca36078df --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatpumpBlock.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.dto; + +/** + * Dto class for the Heatpump Block + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + * + */ +public class HeatpumpBlock { + public int heatpumpErrorState; + public int heatpumpErrorNumber; + public int heatpumpState; + public int heatpumpOperatingState; + public int heatpumpTFlow; + public int heatpumpTReturn; + public int heatpumpVolSink; + public int heatpumpTEQin; + public int heatpumpTEQout; + public int heatpumpVolSource; + public int heatpumpCompressorRating; + public int heatpumpQpHeating; + public int heatpumpFIPowerConsumption; + public int heatpumpCOP; + public long heatpumpVdAE; + public long heatpumpVdAQ; +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Heatpump1SetBlock.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatpumpReg50Block.java similarity index 84% rename from bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Heatpump1SetBlock.java rename to bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatpumpReg50Block.java index 8dbba697d878f..e8a7583357302 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/Heatpump1SetBlock.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/dto/HeatpumpReg50Block.java @@ -1,4 +1,3 @@ -package org.openhab.binding.modbus.lambda.internal.dto; /** * Copyright (c) 2010-2024 Contributors to the openHAB project * @@ -11,15 +10,16 @@ * * SPDX-License-Identifier: EPL-2.0 */ +package org.openhab.binding.modbus.lambda.internal.dto; /** - * Dto class for the Heatpump1 Block + * Dto class for the HeatpumpReg50 Block * * @author Paul Frank - Initial contribution * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus * */ -public class Heatpump1SetBlock { +public class HeatpumpReg50Block { - public int heatpump1seterrorquit; + public int heatpumpSetErrorQuit; } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/BoilerHandler.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/BoilerHandler.java new file mode 100644 index 0000000000000..1cf029751a042 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/BoilerHandler.java @@ -0,0 +1,578 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.handler; + +import static org.openhab.binding.modbus.lambda.internal.LambdaBindingConstants.*; +import static org.openhab.core.library.unit.SIUnits.CELSIUS; +import static org.openhab.core.library.unit.Units.*; + +import java.util.Optional; + +import javax.measure.Unit; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.modbus.handler.EndpointNotInitializedException; +import org.openhab.binding.modbus.handler.ModbusEndpointThingHandler; +import org.openhab.binding.modbus.lambda.internal.BoilerConfiguration; +import org.openhab.binding.modbus.lambda.internal.dto.BoilerBlock; +import org.openhab.binding.modbus.lambda.internal.dto.BoilerReg50Block; +import org.openhab.binding.modbus.lambda.internal.parser.BoilerBlockParser; +import org.openhab.binding.modbus.lambda.internal.parser.BoilerReg50BlockParser; +import org.openhab.core.io.transport.modbus.AsyncModbusFailure; +import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; +import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode; +import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.ModbusWriteRegisterRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusWriteRequestBlueprint; +import org.openhab.core.io.transport.modbus.PollTask; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.thing.Bridge; +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.ThingStatusInfo; +import org.openhab.core.thing.binding.BaseThingHandler; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.types.Command; +import org.openhab.core.types.RefreshType; +import org.openhab.core.types.State; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link BoilerHandler} 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 BoilerHandler extends BaseThingHandler { + + public abstract class AbstractBasePoller { + + private final Logger logger = LoggerFactory.getLogger(BoilerHandler.class); + + private volatile @Nullable PollTask pollTask; + + public synchronized void unregisterPollTask() { + PollTask task = pollTask; + if (task == null) { + return; + } + + ModbusCommunicationInterface mycomms = BoilerHandler.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 Address: {}", address); + + ModbusCommunicationInterface mycomms = BoilerHandler.this.comms; + BoilerConfiguration myconfig = BoilerHandler.this.config; + if (myconfig == null || mycomms == null) { + throw new IllegalStateException("Boiler: 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); + } + }, BoilerHandler.this::handleReadError); + } + + public synchronized void poll() { + PollTask task = pollTask; + ModbusCommunicationInterface mycomms = BoilerHandler.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(BoilerHandler.class); + + /** + * Configuration instance + */ + protected @Nullable BoilerConfiguration config = null; + /** + * Parser used to convert incoming raw messages into system blocks + * private final SystemInfromationBlockParser systemInformationBlockParser = new SystemInfromationBlockParser(); + */ + /** + * Parsers used to convert incoming raw messages into state blocks + */ + + private final BoilerBlockParser boilerBlockParser = new BoilerBlockParser(); + private final BoilerReg50BlockParser boilerReg50BlockParser = new BoilerReg50BlockParser(); + + /** + * These are the tasks used to poll the device + */ + + private volatile @Nullable AbstractBasePoller boilerPoller = null; + private volatile @Nullable AbstractBasePoller boilerReg50Poller = 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 + */ + public BoilerHandler(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) { + logger.trace("Boiler: writeInt16: Es wird geschrieben, Adresse: {} Wert: {}", address, shortValue); + BoilerConfiguration myconfig = BoilerHandler.this.config; + ModbusCommunicationInterface mycomms = BoilerHandler.this.comms; + + if (myconfig == null || mycomms == null) { + throw new IllegalStateException("registerPollTask called without proper configuration"); + } + // big endian byte ordering + byte hi = (byte) (shortValue >> 8); + byte lo = (byte) shortValue; + ModbusRegisterArray data = new ModbusRegisterArray(hi, lo); + + logger.trace("Boiler: hi: {}, lo: {}", hi, lo); + ModbusWriteRegisterRequestBlueprint request = new ModbusWriteRegisterRequestBlueprint(slaveId, address, data, + true, myconfig.getMaxTries()); + + mycomms.submitOneTimeWrite(request, result -> { + if (hasConfigurationError()) { + return; + } + logger.trace("Boiler: Successful write, matching request {}", request); + BoilerHandler.this.updateStatus(ThingStatus.ONLINE); + }, failure -> { + BoilerHandler.this.handleWriteError(failure); + logger.trace("Boiler: Unsuccessful write, matching request {}", request); + }); + } + + /** + * @param command get the value of this command. + * @return short the value of the command as short + */ + private short getInt16Value(Command command) throws LambdaException { + if (command instanceof QuantityType quantityCommand) { + QuantityType c = quantityCommand.toUnit(WATT); + if (c != null) { + return c.shortValue(); + } else { + throw new LambdaException("Unsupported unit"); + } + } + if (command instanceof DecimalType c) { + return c.shortValue(); + } + throw new LambdaException("Unsupported command type"); + } + + private short getScaledInt16Value(Command command) throws LambdaException { + if (command instanceof QuantityType quantityCommand) { + QuantityType c = quantityCommand.toUnit(CELSIUS); + if (c != null) { + return (short) (c.doubleValue() * 10); + } else { + throw new LambdaException("Unsupported unit"); + } + } + if (command instanceof DecimalType c) { + return (short) (c.doubleValue() * 10); + } + throw new LambdaException("Unsupported command type"); + } + + /** + * Handle incoming commands. + */ + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + logger.trace("Boiler: handleCommand, channelUID: {} command {} ", channelUID, command); + if (RefreshType.REFRESH == command) { + String groupId = channelUID.getGroupId(); + if (groupId != null) { + AbstractBasePoller poller; + switch (groupId) { + case GROUP_BOILER: + poller = boilerPoller; + break; + case GROUP_BOILER_REG50: + poller = boilerReg50Poller; + break; + + default: + poller = null; + break; + } + if (poller != null) { + logger.trace("Boiler: Es wird gepollt }"); + poller.poll(); + } + } + } else { + // logger.trace("Boiler: handleCommand: Es wird geschrieben, GroupID: {}, command {}", channelUID.getGroupId(), command); + try { + + if (GROUP_BOILER_REG50.equals(channelUID.getGroupId())) { + // logger.trace("Boiler: im BOILER_REG50 channelUID {} ", channelUID.getIdWithoutGroup()); + + switch (channelUID.getIdWithoutGroup()) { + + case CHANNEL_BOILER_MAXIMUM_BOILER_TEMPERATURE: + + // logger.trace("Boiler: command: {}", command); + writeInt16(reg50baseadress, getScaledInt16Value(command)); + break; + + } + } + + } + + catch (LambdaException 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(BoilerConfiguration.class); + // logger.debug("Initializing thing with properties: {}", thing.getProperties()); + + startUp(); + } + + /* + * Adresses for the polling registers, used for reading and writing + */ + private int baseadress; + private int reg50baseadress; + + /* + * 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 lambda-boiler handler"); + return; + } + + BoilerConfiguration myconfig = BoilerHandler.this.config; + + baseadress = 2000 + 100 * myconfig.getSubindex(); + reg50baseadress = baseadress + 50; + + // logger.debug("Boiler config.baseadress = {} ", baseadress); + // logger.debug("BoilerReg50 baseadress = {} ", reg50baseadress); + + if (boilerPoller == null) { + AbstractBasePoller poller = new AbstractBasePoller() { + @Override + protected void handlePolledData(ModbusRegisterArray registers) { + handlePolledBoilerData(registers); + } + }; + + poller.registerPollTask(baseadress, 4, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); + boilerPoller = poller; + } + + if (boilerReg50Poller == null) { + AbstractBasePoller poller = new AbstractBasePoller() { + @Override + protected void handlePolledData(ModbusRegisterArray registers) { + handlePolledBoilerReg50Data(registers); + } + }; + + poller.registerPollTask(reg50baseadress, 1, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); + boilerReg50Poller = 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 = boilerPoller; + + poller = boilerPoller; + if (poller != null) { + poller.unregisterPollTask(); + boilerPoller = null; + } + poller = boilerReg50Poller; + if (poller != null) { + poller.unregisterPollTask(); + boilerReg50Poller = 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 thingHandler) { + return thingHandler; + } else { + throw new IllegalStateException("Unexpected bridge handler: " + handler.toString()); + } + } + + protected State getScaled(Number value, Unit unit, Double pow) { + // logger.trace("Boiler: value: {}", value.intValue()); + double factor = Math.pow(10, pow); + return QuantityType.valueOf(value.doubleValue() * factor, unit); + } + + protected State getUnscaled(Number value, Unit unit) { + return QuantityType.valueOf(value.doubleValue(), 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); + } + + /** + * These methods are 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 handlePolledBoilerData(ModbusRegisterArray registers) { + // logger.trace("Boiler block received, size: {}", registers.size()); + + BoilerBlock block = boilerBlockParser.parse(registers); + + // Boiler group + updateState(channelUID(GROUP_BOILER, CHANNEL_BOILER_ERROR_NUMBER), new DecimalType(block.boilerErrorNumber)); + updateState(channelUID(GROUP_BOILER, CHANNEL_BOILER_OPERATING_STATE), + new DecimalType(block.boilerOperatingState)); + updateState(channelUID(GROUP_BOILER, CHANNEL_BOILER_ACTUAL_HIGH_TEMPERATURE), + getScaled(block.boilerActualHighTemperature, CELSIUS, -1.0)); + updateState(channelUID(GROUP_BOILER, CHANNEL_BOILER_ACTUAL_LOW_TEMPERATURE), + getScaled(block.boilerActualLowTemperature, CELSIUS, -1.0)); + resetCommunicationError(); + } + + protected void handlePolledBoilerReg50Data(ModbusRegisterArray registers) { + // logger.trace("BoilerReg50 block received, size: {}", registers.size()); + + BoilerReg50Block block = boilerReg50BlockParser.parse(registers); + + // BoilerReg50 group + updateState(channelUID(GROUP_BOILER_REG50, CHANNEL_BOILER_MAXIMUM_BOILER_TEMPERATURE), + getScaled(block.boilerMaximumBoilerTemperature, CELSIUS, -1.0)); + 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.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/BufferHandler.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/BufferHandler.java new file mode 100644 index 0000000000000..ab675c1b0a826 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/BufferHandler.java @@ -0,0 +1,576 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.handler; + +import static org.openhab.binding.modbus.lambda.internal.LambdaBindingConstants.*; +import static org.openhab.core.library.unit.SIUnits.CELSIUS; +import static org.openhab.core.library.unit.Units.*; + +import java.util.Optional; + +import javax.measure.Unit; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.modbus.handler.EndpointNotInitializedException; +import org.openhab.binding.modbus.handler.ModbusEndpointThingHandler; +import org.openhab.binding.modbus.lambda.internal.BufferConfiguration; +import org.openhab.binding.modbus.lambda.internal.dto.BufferBlock; +import org.openhab.binding.modbus.lambda.internal.dto.BufferReg50Block; +import org.openhab.binding.modbus.lambda.internal.parser.BufferBlockParser; +import org.openhab.binding.modbus.lambda.internal.parser.BufferReg50BlockParser; +import org.openhab.core.io.transport.modbus.AsyncModbusFailure; +import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; +import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode; +import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.ModbusWriteRegisterRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusWriteRequestBlueprint; +import org.openhab.core.io.transport.modbus.PollTask; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.thing.Bridge; +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.ThingStatusInfo; +import org.openhab.core.thing.binding.BaseThingHandler; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.types.Command; +import org.openhab.core.types.RefreshType; +import org.openhab.core.types.State; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link BufferHandler} 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 BufferHandler extends BaseThingHandler { + + public abstract class AbstractBasePoller { + + private final Logger logger = LoggerFactory.getLogger(BufferHandler.class); + + private volatile @Nullable PollTask pollTask; + + public synchronized void unregisterPollTask() { + PollTask task = pollTask; + if (task == null) { + return; + } + + ModbusCommunicationInterface mycomms = BufferHandler.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 Address: {}", address); + + ModbusCommunicationInterface mycomms = BufferHandler.this.comms; + BufferConfiguration myconfig = BufferHandler.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); + } + }, BufferHandler.this::handleReadError); + } + + public synchronized void poll() { + PollTask task = pollTask; + ModbusCommunicationInterface mycomms = BufferHandler.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(BufferHandler.class); + + /** + * Configuration instance + */ + protected @Nullable BufferConfiguration config = null; + /** + * Parser used to convert incoming raw messages into system blocks + * private final SystemInfromationBlockParser systemInformationBlockParser = new SystemInfromationBlockParser(); + */ + /** + * Parsers used to convert incoming raw messages into state blocks + */ + + private final BufferBlockParser bufferBlockParser = new BufferBlockParser(); + private final BufferReg50BlockParser bufferReg50BlockParser = new BufferReg50BlockParser(); + + /** + * These are the tasks used to poll the device + */ + private volatile @Nullable AbstractBasePoller bufferPoller = null; + private volatile @Nullable AbstractBasePoller bufferReg50Poller = 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 + */ + public BufferHandler(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) { + // logger.trace("Buffer: writeInt16: Es wird geschrieben, Adresse: {} Wert: {}", address, shortValue); + BufferConfiguration myconfig = BufferHandler.this.config; + ModbusCommunicationInterface mycomms = BufferHandler.this.comms; + + if (myconfig == null || mycomms == null) { + throw new IllegalStateException("registerPollTask called without proper configuration"); + } + // big endian byte ordering + byte hi = (byte) (shortValue >> 8); + byte lo = (byte) shortValue; + ModbusRegisterArray data = new ModbusRegisterArray(hi, lo); + + // logger.trace("Buffer: hi: {}, lo: {}", hi, lo); + ModbusWriteRegisterRequestBlueprint request = new ModbusWriteRegisterRequestBlueprint(slaveId, address, data, + true, myconfig.getMaxTries()); + + mycomms.submitOneTimeWrite(request, result -> { + if (hasConfigurationError()) { + return; + } + // logger.trace("Buffer: Successful write, matching request {}", request); + BufferHandler.this.updateStatus(ThingStatus.ONLINE); + }, failure -> { + BufferHandler.this.handleWriteError(failure); + // logger.trace("Buffer: Unsuccessful write, matching request {}", request); + }); + } + + /** + * @param command get the value of this command. + * @return short the value of the command as short + */ + private short getInt16Value(Command command) throws LambdaException { + if (command instanceof QuantityType quantityCommand) { + QuantityType c = quantityCommand.toUnit(WATT); + if (c != null) { + return c.shortValue(); + } else { + throw new LambdaException("Unsupported unit"); + } + } + if (command instanceof DecimalType c) { + return c.shortValue(); + } + throw new LambdaException("Unsupported command type"); + } + + private short getScaledInt16Value(Command command) throws LambdaException { + if (command instanceof QuantityType quantityCommand) { + QuantityType c = quantityCommand.toUnit(CELSIUS); + if (c != null) { + return (short) (c.doubleValue() * 10); + } else { + throw new LambdaException("Unsupported unit"); + } + } + if (command instanceof DecimalType c) { + return (short) (c.doubleValue() * 10); + } + throw new LambdaException("Unsupported command type"); + } + + /** + * Handle incoming commands. + */ + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + // logger.trace("Buffer: handleCommand, channelUID: {} command {} ", channelUID, command); + if (RefreshType.REFRESH == command) { + String groupId = channelUID.getGroupId(); + if (groupId != null) { + AbstractBasePoller poller; + switch (groupId) { + + case GROUP_BUFFER: + poller = bufferPoller; + break; + case GROUP_BUFFER_REG50: + poller = bufferReg50Poller; + break; + default: + poller = null; + break; + } + if (poller != null) { + // logger.trace("Buffer: Es wird gepollt }"); + poller.poll(); + } + } + } else { + // logger.trace("Buffer: handleCommand: Es wird geschrieben, GroupID: {}, command {}", channelUID.getGroupId(), command); + try { + + if (GROUP_BUFFER_REG50.equals(channelUID.getGroupId())) { + // logger.trace("Buffer: im BUFFER_REG50 channelUID {} ", channelUID.getIdWithoutGroup()); + + switch (channelUID.getIdWithoutGroup()) { + + case CHANNEL_BUFFER_MAXIMUM_BUFFER_TEMPERATURE: + + logger.trace("Buffer: command: {}", command); + writeInt16(reg50baseadress, getScaledInt16Value(command)); + break; + + } + } + } + + catch (LambdaException 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(BufferConfiguration.class); + + logger.debug("Initializing thing with properties: {}", thing.getProperties()); + + startUp(); + } + + /* + * Adresses for the polling registers, used for reading and writing + */ + private int baseadress; + private int reg50baseadress; + + /* + * 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 Buffer handler"); + return; + } + + BufferConfiguration myconfig = BufferHandler.this.config; + + baseadress = 3000 + 100 * myconfig.getSubindex(); + reg50baseadress = baseadress + 50; + + // logger.debug("Buffer config.baseadress = {} ", baseadress); + // logger.debug("BufferReg50 baseadress = {} ", reg50baseadress); + + if (bufferPoller == null) { + AbstractBasePoller poller = new AbstractBasePoller() { + @Override + protected void handlePolledData(ModbusRegisterArray registers) { + handlePolledBufferData(registers); + } + }; + + poller.registerPollTask(baseadress, 4, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); + + bufferPoller = poller; + } + if (bufferReg50Poller == null) { + AbstractBasePoller poller = new AbstractBasePoller() { + @Override + protected void handlePolledData(ModbusRegisterArray registers) { + handlePolledBufferReg50Data(registers); + } + }; + + poller.registerPollTask(reg50baseadress, 1, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); + bufferReg50Poller = 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 = bufferPoller; + + poller = bufferPoller; + if (poller != null) { + poller.unregisterPollTask(); + bufferPoller = null; + } + poller = bufferReg50Poller; + if (poller != null) { + poller.unregisterPollTask(); + bufferReg50Poller = 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 thingHandler) { + return thingHandler; + } else { + throw new IllegalStateException("Unexpected bridge handler: " + handler.toString()); + } + } + + protected State getScaled(Number value, Unit unit, Double pow) { + // logger.trace("Buffer: value: {}", value.intValue()); + double factor = Math.pow(10, pow); + return QuantityType.valueOf(value.doubleValue() * factor, unit); + } + + protected State getUnscaled(Number value, Unit unit) { + return QuantityType.valueOf(value.doubleValue(), 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); + } + + /** + * These methods are 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 handlePolledBufferData(ModbusRegisterArray registers) { + // logger.trace("Buffer block received, size: {}", registers.size()); + + BufferBlock block = bufferBlockParser.parse(registers); + + // Buffer group + updateState(channelUID(GROUP_BUFFER, CHANNEL_BUFFER_ERROR_NUMBER), new DecimalType(block.bufferErrorNumber)); + updateState(channelUID(GROUP_BUFFER, CHANNEL_BUFFER_OPERATING_STATE), + new DecimalType(block.bufferOperatingState)); + updateState(channelUID(GROUP_BUFFER, CHANNEL_BUFFER_ACTUAL_HIGH_TEMPERATURE), + getScaled(block.bufferActualHighTemperature, CELSIUS, -1.0)); + updateState(channelUID(GROUP_BUFFER, CHANNEL_BUFFER_ACTUAL_LOW_TEMPERATURE), + getScaled(block.bufferActualLowTemperature, CELSIUS, -1.0)); + resetCommunicationError(); + } + + protected void handlePolledBufferReg50Data(ModbusRegisterArray registers) { + // logger.trace("BufferReg50 block received, size: {}", registers.size()); + + BufferReg50Block block = bufferReg50BlockParser.parse(registers); + + // BufferReg50 group + updateState(channelUID(GROUP_BUFFER_REG50, CHANNEL_BUFFER_MAXIMUM_BUFFER_TEMPERATURE), + getScaled(block.bufferMaximumBufferTemperature, CELSIUS, -1.0)); + 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.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/GeneralHandler.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/GeneralHandler.java new file mode 100644 index 0000000000000..3a530a289cd1d --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/GeneralHandler.java @@ -0,0 +1,582 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.handler; + +import static org.openhab.binding.modbus.lambda.internal.LambdaBindingConstants.*; +import static org.openhab.core.library.unit.SIUnits.CELSIUS; +import static org.openhab.core.library.unit.Units.*; + +import java.util.Optional; + +import javax.measure.Unit; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.modbus.handler.EndpointNotInitializedException; +import org.openhab.binding.modbus.handler.ModbusEndpointThingHandler; +import org.openhab.binding.modbus.lambda.internal.GeneralConfiguration; +import org.openhab.binding.modbus.lambda.internal.dto.AmbientBlock; +import org.openhab.binding.modbus.lambda.internal.dto.EManagerBlock; +import org.openhab.binding.modbus.lambda.internal.parser.AmbientBlockParser; +import org.openhab.binding.modbus.lambda.internal.parser.EManagerBlockParser; +import org.openhab.core.io.transport.modbus.AsyncModbusFailure; +import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; +import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode; +import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.ModbusWriteRegisterRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusWriteRequestBlueprint; +import org.openhab.core.io.transport.modbus.PollTask; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.thing.Bridge; +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.ThingStatusInfo; +import org.openhab.core.thing.binding.BaseThingHandler; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.types.Command; +import org.openhab.core.types.RefreshType; +import org.openhab.core.types.State; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link GeneralHandler} 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 GeneralHandler extends BaseThingHandler { + + public abstract class AbstractBasePoller { + + private final Logger logger = LoggerFactory.getLogger(GeneralHandler.class); + + private volatile @Nullable PollTask pollTask; + + public synchronized void unregisterPollTask() { + PollTask task = pollTask; + if (task == null) { + return; + } + + ModbusCommunicationInterface mycomms = GeneralHandler.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 Address: {}", address); + + ModbusCommunicationInterface mycomms = GeneralHandler.this.comms; + GeneralConfiguration myconfig = GeneralHandler.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); + } + }, GeneralHandler.this::handleReadError); + } + + public synchronized void poll() { + PollTask task = pollTask; + ModbusCommunicationInterface mycomms = GeneralHandler.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(GeneralHandler.class); + + /** + * Configuration instance + */ + protected @Nullable GeneralConfiguration config = null; + /** + * Parser used to convert incoming raw messages into system blocks + * private final SystemInfromationBlockParser systemInformationBlockParser = new SystemInfromationBlockParser(); + */ + /** + * Parsers used to convert incoming raw messages into state blocks + */ + private final AmbientBlockParser ambientBlockParser = new AmbientBlockParser(); + private final EManagerBlockParser emanagerBlockParser = new EManagerBlockParser(); + + /** + * These are the tasks used to poll the device + */ + private volatile @Nullable AbstractBasePoller ambientPoller = null; + private volatile @Nullable AbstractBasePoller emanagerPoller = 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 + */ + public GeneralHandler(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) { + // logger.trace("General: writeInt16: Es wird geschrieben, Adresse: {} Wert: {}", address, shortValue); + GeneralConfiguration myconfig = GeneralHandler.this.config; + ModbusCommunicationInterface mycomms = GeneralHandler.this.comms; + + if (myconfig == null || mycomms == null) { + throw new IllegalStateException("registerPollTask called without proper configuration"); + } + // big endian byte ordering + byte hi = (byte) (shortValue >> 8); + byte lo = (byte) shortValue; + ModbusRegisterArray data = new ModbusRegisterArray(hi, lo); + + // logger.trace("General: hi: {}, lo: {}", hi, lo); + ModbusWriteRegisterRequestBlueprint request = new ModbusWriteRegisterRequestBlueprint(slaveId, address, data, + true, myconfig.getMaxTries()); + + mycomms.submitOneTimeWrite(request, result -> { + if (hasConfigurationError()) { + return; + } + // logger.trace("General: Successful write, matching request {}", request); + GeneralHandler.this.updateStatus(ThingStatus.ONLINE); + }, failure -> { + GeneralHandler.this.handleWriteError(failure); + // logger.trace("General: Unsuccessful write, matching request {}", request); + }); + } + + /** + * @param command get the value of this command. + * @return short the value of the command as short + */ + private short getInt16Value(Command command) throws LambdaException { + if (command instanceof QuantityType quantityCommand) { + QuantityType c = quantityCommand.toUnit(WATT); + if (c != null) { + return c.shortValue(); + } else { + throw new LambdaException("Unsupported unit"); + } + } + if (command instanceof DecimalType c) { + return c.shortValue(); + } + throw new LambdaException("Unsupported command type"); + } + + private short getScaledInt16Value(Command command) throws LambdaException { + if (command instanceof QuantityType quantityCommand) { + QuantityType c = quantityCommand.toUnit(CELSIUS); + if (c != null) { + return (short) (c.doubleValue() * 10); + } else { + throw new LambdaException("Unsupported unit"); + } + } + if (command instanceof DecimalType c) { + return (short) (c.doubleValue() * 10); + } + throw new LambdaException("Unsupported command type"); + } + + /** + * Handle incoming commands. + */ + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + // logger.trace("General: handleCommand, channelUID: {} command {} ", channelUID, command); + if (RefreshType.REFRESH == command) { + String groupId = channelUID.getGroupId(); + if (groupId != null) { + AbstractBasePoller poller; + switch (groupId) { + case GROUP_GENERAL_AMBIENT: + poller = ambientPoller; + break; + case GROUP_GENERAL_EMANAGER: + poller = emanagerPoller; + break; + default: + poller = null; + break; + } + if (poller != null) { + // logger.trace("General Es wird gepollt }"); + poller.poll(); + } + } + } else { + + try { + + if (GROUP_GENERAL_AMBIENT.equals(channelUID.getGroupId())) { + + // logger.trace(": im AMBIENT channelUID {} ", channelUID.getIdWithoutGroup()); + switch (channelUID.getIdWithoutGroup()) { + + case CHANNEL_ACTUAL_AMBIENT_TEMPERATURE: + + // logger.trace("write Actual Ambient Temperature command: {}", command); + writeInt16(2, getInt16Value(command)); + break; + + } + } + + // logger.trace("write EMANAGER"); + if (GROUP_GENERAL_EMANAGER.equals(channelUID.getGroupId())) { + + // logger.trace("General: im EMANAGER channelUID {} ", channelUID.getIdWithoutGroup()); + switch (channelUID.getIdWithoutGroup()) { + + case CHANNEL_ACTUAL_POWER: + + // logger.trace("336 command: {}", command); + writeInt16(102, getInt16Value(command)); + break; + + } + } + } + + catch (LambdaException 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(GeneralConfiguration.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 lambda general handler"); + return; + } + + if (ambientPoller == null) { + AbstractBasePoller poller = new AbstractBasePoller() { + @Override + protected void handlePolledData(ModbusRegisterArray registers) { + handlePolledAmbientData(registers); + } + }; + poller.registerPollTask(0, 5, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); + ambientPoller = poller; + } + + if (emanagerPoller == null) { + AbstractBasePoller poller = new AbstractBasePoller() { + @Override + protected void handlePolledData(ModbusRegisterArray registers) { + handlePolledEManagerData(registers); + } + }; + poller.registerPollTask(100, 5, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); + emanagerPoller = 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 = ambientPoller; + if (poller != null) { + poller.unregisterPollTask(); + ambientPoller = null; + } + + poller = emanagerPoller; + if (poller != null) { + poller.unregisterPollTask(); + emanagerPoller = 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 thingHandler) { + return thingHandler; + } else { + throw new IllegalStateException("Unexpected bridge handler: " + handler.toString()); + } + } + + protected State getScaled(Number value, Unit unit, Double pow) { + // logger.trace("General: value: {}", value.intValue()); + double factor = Math.pow(10, pow); + return QuantityType.valueOf(value.doubleValue() * factor, unit); + } + + protected State getUnscaled(Number value, Unit unit) { + return QuantityType.valueOf(value.doubleValue(), 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); + } + + /** + * These methods are 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 handlePolledAmbientData(ModbusRegisterArray registers) { + // logger.trace("Ambient block received, size: {}", registers.size()); + + // Ambient group + AmbientBlock block = ambientBlockParser.parse(registers); + + updateState(channelUID(GROUP_GENERAL_AMBIENT, CHANNEL_AMBIENT_ERROR_NUMBER), + new DecimalType(block.ambientErrorNumber)); + updateState(channelUID(GROUP_GENERAL_AMBIENT, CHANNEL_AMBIENT_OPERATING_STATE), + new DecimalType(block.ambientOperatingState)); + updateState(channelUID(GROUP_GENERAL_AMBIENT, CHANNEL_ACTUAL_AMBIENT_TEMPERATURE), + getScaled(block.actualAmbientTemperature, CELSIUS, -1.0)); + updateState(channelUID(GROUP_GENERAL_AMBIENT, CHANNEL_AVERAGE_AMBIENT_TEMPERATURE), + getScaled(block.averageAmbientTemperature, CELSIUS, -1.0)); + updateState(channelUID(GROUP_GENERAL_AMBIENT, CHANNEL_CALCULATED_AMBIENT_TEMPERATURE), + getScaled(block.calculatedAmbientTemperature, CELSIUS, -1.0)); + resetCommunicationError(); + } + + protected void handlePolledEManagerData(ModbusRegisterArray registers) { + // logger.trace("EManager block received, size: {}", registers.size()); + + // EManager group + EManagerBlock block = emanagerBlockParser.parse(registers); + updateState(channelUID(GROUP_GENERAL_EMANAGER, CHANNEL_EMANAGER_ERROR_NUMBER), + new DecimalType(block.emanagerErrorNumber)); + updateState(channelUID(GROUP_GENERAL_EMANAGER, CHANNEL_EMANAGER_OPERATING_STATE), + new DecimalType(block.emanagerOperatingState)); + updateState(channelUID(GROUP_GENERAL_EMANAGER, CHANNEL_ACTUAL_POWER_CONSUMPTION), + getUnscaled(block.actualPowerConsumption, WATT)); + updateState(channelUID(GROUP_GENERAL_EMANAGER, CHANNEL_ACTUAL_POWER), getUnscaled(block.actualPower, WATT)); + updateState(channelUID(GROUP_GENERAL_EMANAGER, CHANNEL_POWER_CONSUMPTION_SETPOINT), + getUnscaled(block.powerConsumptionSetpoint, WATT)); + + 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.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/HeatingCircuitHandler.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/HeatingCircuitHandler.java new file mode 100644 index 0000000000000..d6e5da047fc2b --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/HeatingCircuitHandler.java @@ -0,0 +1,623 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.handler; + +import static org.openhab.binding.modbus.lambda.internal.LambdaBindingConstants.*; +import static org.openhab.core.library.unit.SIUnits.CELSIUS; +import static org.openhab.core.library.unit.Units.*; + +import java.util.Optional; + +import javax.measure.Unit; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.modbus.handler.EndpointNotInitializedException; +import org.openhab.binding.modbus.handler.ModbusEndpointThingHandler; +import org.openhab.binding.modbus.lambda.internal.HeatingCircuitConfiguration; +import org.openhab.binding.modbus.lambda.internal.dto.HeatingCircuitBlock; +import org.openhab.binding.modbus.lambda.internal.dto.HeatingCircuitReg50Block; +import org.openhab.binding.modbus.lambda.internal.parser.HeatingCircuitBlockParser; +import org.openhab.binding.modbus.lambda.internal.parser.HeatingCircuitReg50BlockParser; +import org.openhab.core.io.transport.modbus.AsyncModbusFailure; +import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; +import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode; +import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.ModbusWriteRegisterRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusWriteRequestBlueprint; +import org.openhab.core.io.transport.modbus.PollTask; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.thing.Bridge; +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.ThingStatusInfo; +import org.openhab.core.thing.binding.BaseThingHandler; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.types.Command; +import org.openhab.core.types.RefreshType; +import org.openhab.core.types.State; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link HeatingCircuitHandler} 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 HeatingCircuitHandler extends BaseThingHandler { + + public abstract class AbstractBasePoller { + + private final Logger logger = LoggerFactory.getLogger(HeatingCircuitHandler.class); + + private volatile @Nullable PollTask pollTask; + + public synchronized void unregisterPollTask() { + PollTask task = pollTask; + if (task == null) { + return; + } + + ModbusCommunicationInterface mycomms = HeatingCircuitHandler.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 Address: {}", address); + + ModbusCommunicationInterface mycomms = HeatingCircuitHandler.this.comms; + HeatingCircuitConfiguration myconfig = HeatingCircuitHandler.this.config; + if (myconfig == null || mycomms == null) { + throw new IllegalStateException("HeatingCircuit: 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); + } + }, HeatingCircuitHandler.this::handleReadError); + } + + public synchronized void poll() { + PollTask task = pollTask; + ModbusCommunicationInterface mycomms = HeatingCircuitHandler.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(HeatingCircuitHandler.class); + + /** + * Configuration instance + */ + protected @Nullable HeatingCircuitConfiguration config = null; + /** + * Parser used to convert incoming raw messages into system blocks + * private final SystemInfromationBlockParser systemInformationBlockParser = new SystemInfromationBlockParser(); + */ + /** + * Parsers used to convert incoming raw messages into state blocks + */ + + private final HeatingCircuitBlockParser heatingcircuitBlockParser = new HeatingCircuitBlockParser(); + private final HeatingCircuitReg50BlockParser heatingcircuitReg50BlockParser = new HeatingCircuitReg50BlockParser(); + + /** + * These are the tasks used to poll the device + */ + + private volatile @Nullable AbstractBasePoller heatingcircuitPoller = null; + private volatile @Nullable AbstractBasePoller heatingcircuitReg50Poller = 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 + */ + public HeatingCircuitHandler(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) { + // logger.trace("HeatingCircuit: writeInt16: Es wird geschrieben, Adresse: {} Wert: {}", address, shortValue); + HeatingCircuitConfiguration myconfig = HeatingCircuitHandler.this.config; + ModbusCommunicationInterface mycomms = HeatingCircuitHandler.this.comms; + + if (myconfig == null || mycomms == null) { + throw new IllegalStateException("registerPollTask called without proper configuration"); + } + // big endian byte ordering + byte hi = (byte) (shortValue >> 8); + byte lo = (byte) shortValue; + ModbusRegisterArray data = new ModbusRegisterArray(hi, lo); + + // logger.trace("HeatingCircuit: hi: {}, lo: {}", hi, lo); + ModbusWriteRegisterRequestBlueprint request = new ModbusWriteRegisterRequestBlueprint(slaveId, address, data, + true, myconfig.getMaxTries()); + + mycomms.submitOneTimeWrite(request, result -> { + if (hasConfigurationError()) { + return; + } + // logger.trace("HeatingCircuit: Successful write, matching request {}", request); + HeatingCircuitHandler.this.updateStatus(ThingStatus.ONLINE); + }, failure -> { + HeatingCircuitHandler.this.handleWriteError(failure); + // logger.trace("HeatingCircuit: Unsuccessful write, matching request {}", request); + }); + } + + /** + * @param command get the value of this command. + * @return short the value of the command as short + */ + private short getInt16Value(Command command) throws LambdaException { + if (command instanceof QuantityType quantityCommand) { + QuantityType c = quantityCommand.toUnit(WATT); + if (c != null) { + return c.shortValue(); + } else { + throw new LambdaException("Unsupported unit"); + } + } + if (command instanceof DecimalType c) { + return c.shortValue(); + } + throw new LambdaException("Unsupported command type"); + } + + private short getScaledInt16Value(Command command) throws LambdaException { + if (command instanceof QuantityType quantityCommand) { + QuantityType c = quantityCommand.toUnit(CELSIUS); + if (c != null) { + return (short) (c.doubleValue() * 10); + } else { + throw new LambdaException("Unsupported unit"); + } + } + if (command instanceof DecimalType c) { + return (short) (c.doubleValue() * 10); + } + throw new LambdaException("Unsupported command type"); + } + + /** + * Handle incoming commands. + */ + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + // logger.trace("HeatingCircuit: handleCommand, channelUID: {} command {} ", channelUID, command); + if (RefreshType.REFRESH == command) { + String groupId = channelUID.getGroupId(); + if (groupId != null) { + AbstractBasePoller poller; + switch (groupId) { + case GROUP_HEATINGCIRCUIT: + poller = heatingcircuitPoller; + break; + case GROUP_HEATINGCIRCUIT_REG50: + poller = heatingcircuitReg50Poller; + break; + default: + poller = null; + break; + } + if (poller != null) { + // logger.trace("HeatingCircuit: Es wird gepollt }"); + poller.poll(); + } + } + } else { + // logger.trace("HeatingCircuit: handleCommand: Es wird geschrieben, GroupID: {}, command {}", channelUID.getGroupId(), command); + try { + + if (GROUP_HEATINGCIRCUIT.equals(channelUID.getGroupId())) { + // logger.trace("HeatingCircuit: im HEATINGCIRCUI1 channelUID {} ", channelUID.getIdWithoutGroup()); + + switch (channelUID.getIdWithoutGroup()) { + + case CHANNEL_HEATINGCIRCUIT_ROOM_DEVICE_TEMPERATURE: + // logger.trace("HeatingCircuit: command: {}", command); + writeInt16(baseadress + 4, getScaledInt16Value(command)); + break; + case CHANNEL_HEATINGCIRCUIT_SETPOINT_FLOW_LINE_TEMPERATURE: + // logger.trace("HeatingCircuit: command: {}", command); + writeInt16(baseadress + 5, getScaledInt16Value(command)); + break; + case CHANNEL_HEATINGCIRCUIT_OPERATING_MODE: + // logger.trace("HeatingCircuit: command: {}", command); + writeInt16(baseadress + 6, getInt16Value(command)); + break; + + } + } + + if (GROUP_HEATINGCIRCUIT_REG50.equals(channelUID.getGroupId())) { + // logger.trace("HeatingCircuit: im HEATINGCIRCUIT1 channelUID {} ", channelUID.getIdWithoutGroup()); + + switch (channelUID.getIdWithoutGroup()) { + + case CHANNEL_HEATINGCIRCUIT_OFFSET_FLOW_LINE_TEMPERATURE: + + // logger.trace("HeatingCircuit: command: {}", command); + writeInt16(reg50baseadress, getScaledInt16Value(command)); + break; + case CHANNEL_HEATINGCIRCUIT_ROOM_HEATING_TEMPERATURE: + + // logger.trace("HeatingCircuit: command: {}", command); + writeInt16(reg50baseadress + 1, getScaledInt16Value(command)); + break; + case CHANNEL_HEATINGCIRCUIT_ROOM_COOLING_TEMPERATURE: + + // logger.trace("HeatingCircuit: command: {}", command); + writeInt16(reg50baseadress + 2, getScaledInt16Value(command)); + break; + + } + + } + + } catch (LambdaException 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(HeatingCircuitConfiguration.class); + + logger.debug("Initializing thing with properties: {}", thing.getProperties()); + + startUp(); + } + + /* + * Adresses for the polling registers, used for reading and writing + */ + private int baseadress; + private int reg50baseadress; + + /* + * 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 lambda heatingcircuitcirciut handler"); + return; + } + + HeatingCircuitConfiguration myconfig = HeatingCircuitHandler.this.config; + + baseadress = 5000 + 100 * myconfig.getSubindex(); + reg50baseadress = baseadress + 50; + + // logger.debug("Heating Circuit SubIndex = {} ", myconfig.getSubindex()); + // logger.debug("Heating Circuit Baseadress = {} ", baseadress); + // logger.debug("Heating Circuit Reg 50 Baseadress = {} ", reg50baseadress); + + if (heatingcircuitPoller == null) { + AbstractBasePoller poller = new AbstractBasePoller() { + @Override + protected void handlePolledData(ModbusRegisterArray registers) { + handlePolledHeatingData(registers); + } + }; + + poller.registerPollTask(baseadress, 7, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); + // logger.trace("Poller Heating erzeugt"); + heatingcircuitPoller = poller; + } + if (heatingcircuitReg50Poller == null) { + AbstractBasePoller poller = new AbstractBasePoller() { + @Override + protected void handlePolledData(ModbusRegisterArray registers) { + handlePolledHeatingReg50Data(registers); + } + }; + + poller.registerPollTask(reg50baseadress, 3, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); + // logger.trace("Poller HeatingReg50 erzeugt"); + heatingcircuitReg50Poller = 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 = heatingcircuitPoller; + if (poller != null) { + // logger.debug("Unregistering heatingcircuitPoller from ModbusManager"); + poller.unregisterPollTask(); + heatingcircuitPoller = null; + } + + poller = heatingcircuitReg50Poller; + if (poller != null) { + // logger.debug("Unregistering heatingcircuitReg50Poller from ModbusManager"); + poller.unregisterPollTask(); + heatingcircuitReg50Poller = 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 thingHandler) { + return thingHandler; + } else { + throw new IllegalStateException("Unexpected bridge handler: " + handler.toString()); + } + } + + protected State getScaled(Number value, Unit unit, Double pow) { + // logger.trace("HeatingCircuit: value: {}", value.intValue()); + double factor = Math.pow(10, pow); + return QuantityType.valueOf(value.doubleValue() * factor, unit); + } + + protected State getUnscaled(Number value, Unit unit) { + return QuantityType.valueOf(value.doubleValue(), 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); + } + + /** + * These methods are 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 handlePolledHeatingData(ModbusRegisterArray registers) { + // logger.trace("Heating block received, size: {}", registers.size()); + + HeatingCircuitBlock block = heatingcircuitBlockParser.parse(registers); + + // HeatingCircuit1 group + + updateState(channelUID(GROUP_HEATINGCIRCUIT, CHANNEL_HEATINGCIRCUIT_ERROR_NUMBER), + new DecimalType(block.heatingcircuitErrorNumber)); + updateState(channelUID(GROUP_HEATINGCIRCUIT, CHANNEL_HEATINGCIRCUIT_OPERATING_STATE), + new DecimalType(block.heatingcircuitOperatingState)); + updateState(channelUID(GROUP_HEATINGCIRCUIT, CHANNEL_HEATINGCIRCUIT_FLOW_LINE_TEMPERATURE), + getScaled(block.heatingcircuitFlowLineTemperature, CELSIUS, -1.0)); + updateState(channelUID(GROUP_HEATINGCIRCUIT, CHANNEL_HEATINGCIRCUIT_RETURN_LINE_TEMPERATURE), + getScaled(block.heatingcircuitReturnLineTemperature, CELSIUS, -1.0)); + updateState(channelUID(GROUP_HEATINGCIRCUIT, CHANNEL_HEATINGCIRCUIT_ROOM_DEVICE_TEMPERATURE), + getScaled(block.heatingcircuitRoomDeviceTemperature, CELSIUS, -1.0)); + updateState(channelUID(GROUP_HEATINGCIRCUIT, CHANNEL_HEATINGCIRCUIT_SETPOINT_FLOW_LINE_TEMPERATURE), + getScaled(block.heatingcircuitSetpointFlowLineTemperature, CELSIUS, -1.0)); + updateState(channelUID(GROUP_HEATINGCIRCUIT, CHANNEL_HEATINGCIRCUIT_OPERATING_MODE), + new DecimalType(block.heatingcircuitOperatingMode)); + + resetCommunicationError(); + } + + protected void handlePolledHeatingReg50Data(ModbusRegisterArray registers) { + // logger.trace("HeatingCircuitReg50 block received, size: {}", registers.size()); + + HeatingCircuitReg50Block block = heatingcircuitReg50BlockParser.parse(registers); + + // HeatingCircuit1Settting group + + updateState(channelUID(GROUP_HEATINGCIRCUIT_REG50, CHANNEL_HEATINGCIRCUIT_OFFSET_FLOW_LINE_TEMPERATURE), + getScaled(block.heatingcircuitOffsetFlowLineTemperature, CELSIUS, -1.0)); + updateState(channelUID(GROUP_HEATINGCIRCUIT_REG50, CHANNEL_HEATINGCIRCUIT_ROOM_HEATING_TEMPERATURE), + getScaled(block.heatingcircuitRoomHeatingTemperature, CELSIUS, -1.0)); + updateState(channelUID(GROUP_HEATINGCIRCUIT_REG50, CHANNEL_HEATINGCIRCUIT_ROOM_COOLING_TEMPERATURE), + getScaled(block.heatingcircuitRoomCoolingTemperature, CELSIUS, -1.0)); + 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.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/HeatpumpHandler.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/HeatpumpHandler.java new file mode 100644 index 0000000000000..5f676454c4ac1 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/HeatpumpHandler.java @@ -0,0 +1,599 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.handler; + +import static org.openhab.binding.modbus.lambda.internal.LambdaBindingConstants.*; +import static org.openhab.core.library.unit.SIUnits.CELSIUS; +import static org.openhab.core.library.unit.Units.*; + +import java.util.Optional; + +import javax.measure.Unit; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.modbus.handler.EndpointNotInitializedException; +import org.openhab.binding.modbus.handler.ModbusEndpointThingHandler; +import org.openhab.binding.modbus.lambda.internal.HeatpumpConfiguration; +import org.openhab.binding.modbus.lambda.internal.dto.HeatpumpBlock; +import org.openhab.binding.modbus.lambda.internal.dto.HeatpumpReg50Block; +import org.openhab.binding.modbus.lambda.internal.parser.HeatpumpBlockParser; +import org.openhab.binding.modbus.lambda.internal.parser.HeatpumpReg50BlockParser; +import org.openhab.core.io.transport.modbus.AsyncModbusFailure; +import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; +import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode; +import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.ModbusWriteRegisterRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusWriteRequestBlueprint; +import org.openhab.core.io.transport.modbus.PollTask; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.thing.Bridge; +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.ThingStatusInfo; +import org.openhab.core.thing.binding.BaseThingHandler; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.types.Command; +import org.openhab.core.types.RefreshType; +import org.openhab.core.types.State; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link HeatpumpHandler} 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 HeatpumpHandler extends BaseThingHandler { + + public abstract class AbstractBasePoller { + + private final Logger logger = LoggerFactory.getLogger(HeatpumpHandler.class); + + private volatile @Nullable PollTask pollTask; + + public synchronized void unregisterPollTask() { + PollTask task = pollTask; + if (task == null) { + return; + } + + ModbusCommunicationInterface mycomms = HeatpumpHandler.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 Address: {}", address); + + ModbusCommunicationInterface mycomms = HeatpumpHandler.this.comms; + HeatpumpConfiguration myconfig = HeatpumpHandler.this.config; + + if (myconfig == null || mycomms == null) { + throw new IllegalStateException("Heatpump: 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); + } + }, HeatpumpHandler.this::handleReadError); + } + + public synchronized void poll() { + PollTask task = pollTask; + ModbusCommunicationInterface mycomms = HeatpumpHandler.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(HeatpumpHandler.class); + + /** + * Configuration instance + */ + protected @Nullable HeatpumpConfiguration config = null; + /** + * Parser used to convert incoming raw messages into system blocks + * private final SystemInfromationBlockParser systemInformationBlockParser = new SystemInfromationBlockParser(); + */ + /** + * Parsers used to convert incoming raw messages into state blocks + */ + + private final HeatpumpBlockParser heatpumpBlockParser = new HeatpumpBlockParser(); + private final HeatpumpReg50BlockParser heatpumpReg50BlockParser = new HeatpumpReg50BlockParser(); + + /** + * These are the tasks used to poll the device + */ + private volatile @Nullable AbstractBasePoller heatpumpPoller = null; + private volatile @Nullable AbstractBasePoller heatpumpReg50Poller = 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 + */ + public HeatpumpHandler(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) { + // logger.trace("Heatpump: writeInt16: Es wird geschrieben, Adresse: {} Wert: {}", address, shortValue); + HeatpumpConfiguration myconfig = HeatpumpHandler.this.config; + ModbusCommunicationInterface mycomms = HeatpumpHandler.this.comms; + + if (myconfig == null || mycomms == null) { + throw new IllegalStateException("registerPollTask called without proper configuration"); + } + // big endian byte ordering + byte hi = (byte) (shortValue >> 8); + byte lo = (byte) shortValue; + ModbusRegisterArray data = new ModbusRegisterArray(hi, lo); + + // logger.trace("Heatpump: hi: {}, lo: {}", hi, lo); + ModbusWriteRegisterRequestBlueprint request = new ModbusWriteRegisterRequestBlueprint(slaveId, address, data, + true, myconfig.getMaxTries()); + + mycomms.submitOneTimeWrite(request, result -> { + if (hasConfigurationError()) { + return; + } + // logger.trace("Heatpump: Successful write, matching request {}", request); + HeatpumpHandler.this.updateStatus(ThingStatus.ONLINE); + }, failure -> { + HeatpumpHandler.this.handleWriteError(failure); + // logger.trace("Heatpump: Unsuccessful write, matching request {}", request); + }); + } + + /** + * @param command get the value of this command. + * @return short the value of the command as short + */ + private short getInt16Value(Command command) throws LambdaException { + if (command instanceof QuantityType quantityCommand) { + QuantityType c = quantityCommand.toUnit(WATT); + if (c != null) { + return c.shortValue(); + } else { + throw new LambdaException("Unsupported unit"); + } + } + if (command instanceof DecimalType c) { + return c.shortValue(); + } + throw new LambdaException("Unsupported command type"); + } + + private short getScaledInt16Value(Command command) throws LambdaException { + if (command instanceof QuantityType quantityCommand) { + QuantityType c = quantityCommand.toUnit(CELSIUS); + if (c != null) { + return (short) (c.doubleValue() * 10); + } else { + throw new LambdaException("Unsupported unit"); + } + } + if (command instanceof DecimalType c) { + return (short) (c.doubleValue() * 10); + } + throw new LambdaException("Unsupported command type"); + } + + /** + * Handle incoming commands. + */ + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + // logger.trace("Heatpump: handleCommand, channelUID: {} command {} ", channelUID, command); + if (RefreshType.REFRESH == command) { + String groupId = channelUID.getGroupId(); + if (groupId != null) { + AbstractBasePoller poller; + switch (groupId) { + case GROUP_HEATPUMP: + poller = heatpumpPoller; + break; + case GROUP_HEATPUMP_REG50: + poller = heatpumpReg50Poller; + break; + default: + poller = null; + break; + } + if (poller != null) { + // logger.trace("Heatpump: Es wird gepollt }"); + poller.poll(); + } + } + } else { + // logger.trace("Heatpump: handleCommand: Es wird geschrieben, GroupID: {}, command {}", channelUID.getGroupId(), command); + try { + + if (GROUP_HEATPUMP_REG50.equals(channelUID.getGroupId())) { + // logger.trace("Heatpump: im GROUP_HEATPUMP_REG50 channelUID {} ", channelUID.getIdWithoutGroup()); + + switch (channelUID.getIdWithoutGroup()) { + + case CHANNEL_HEATPUMP_SET_ERROR_QUIT: + + // logger.trace("Heatpump: Heatpumpseterrorquit command: {}", command); + writeInt16(reg50baseadress, getScaledInt16Value(command)); + break; + + } + } + } catch (LambdaException 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(HeatpumpConfiguration.class); + + logger.debug("Initializing thing with properties: {}", thing.getProperties()); + + startUp(); + } + + /* + * Adresses for the polling registers, used for reading and writing + */ + private int baseadress; + private int reg50baseadress; + + /* + * 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 lambda heatpump handler"); + return; + } + + HeatpumpConfiguration myconfig = HeatpumpHandler.this.config; + + baseadress = 1000 + 100 * myconfig.getSubindex(); + reg50baseadress = baseadress + 50; + + // logger.debug("Heatpump config.baseadress = {} ", baseadress); + // logger.debug("HeatpumpReg50 baseadress = {} ", reg50baseadress); + + if (heatpumpPoller == null) { + AbstractBasePoller poller = new AbstractBasePoller() { + @Override + protected void handlePolledData(ModbusRegisterArray registers) { + handlePolledHeatpumpData(registers); + } + }; + + poller.registerPollTask(baseadress, 24, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); + // logger.trace("Poller Heatpump erzeugt"); + heatpumpPoller = poller; + } + + if (heatpumpReg50Poller == null) { + AbstractBasePoller poller = new AbstractBasePoller() { + @Override + protected void handlePolledData(ModbusRegisterArray registers) { + handlePolledHeatpumpReg50Data(registers); + } + }; + + poller.registerPollTask(reg50baseadress, 1, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); + // logger.trace("Poller GROUP_HEATPUMP_REG50 erzeugt"); + heatpumpReg50Poller = 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 = heatpumpPoller; + if (poller != null) { + poller.unregisterPollTask(); + heatpumpPoller = null; + } + + poller = heatpumpReg50Poller; + if (poller != null) { + poller.unregisterPollTask(); + heatpumpReg50Poller = 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 thingHandler) { + return thingHandler; + } else { + throw new IllegalStateException("Unexpected bridge handler: " + handler.toString()); + } + } + + protected State getScaled(Number value, Unit unit, Double pow) { + // logger.trace("Heatpump: value: {}", value.intValue()); + double factor = Math.pow(10, pow); + return QuantityType.valueOf(value.doubleValue() * factor, unit); + } + + protected State getUnscaled(Number value, Unit unit) { + return QuantityType.valueOf(value.doubleValue(), 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); + } + + /** + * These methods are 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 handlePolledHeatpumpData(ModbusRegisterArray registers) { + // logger.trace("Heatpump block received, size: {}", registers.size()); + + HeatpumpBlock block = heatpumpBlockParser.parse(registers); + + // Heatpump group + updateState(channelUID(GROUP_HEATPUMP, CHANNEL_HEATPUMP_ERROR_STATE), + new DecimalType(block.heatpumpErrorState)); + updateState(channelUID(GROUP_HEATPUMP, CHANNEL_HEATPUMP_ERROR_NUMBER), + new DecimalType(block.heatpumpErrorNumber)); + updateState(channelUID(GROUP_HEATPUMP, CHANNEL_HEATPUMP_OPERATING_STATE), + new DecimalType(block.heatpumpOperatingState)); + updateState(channelUID(GROUP_HEATPUMP, CHANNEL_HEATPUMP_STATE), new DecimalType(block.heatpumpState)); + updateState(channelUID(GROUP_HEATPUMP, CHANNEL_HEATPUMP_T_FLOW), getScaled(block.heatpumpTFlow, CELSIUS, -2.0)); + updateState(channelUID(GROUP_HEATPUMP, CHANNEL_HEATPUMP_T_RETURN), + getScaled(block.heatpumpTReturn, CELSIUS, -2.0)); + updateState(channelUID(GROUP_HEATPUMP, CHANNEL_HEATPUMP_VOL_SINK), + getScaled(block.heatpumpVolSink, LITRE_PER_MINUTE, -2.0)); + updateState(channelUID(GROUP_HEATPUMP, CHANNEL_HEATPUMP_T_EQIN), getScaled(block.heatpumpTEQin, CELSIUS, -2.0)); + updateState(channelUID(GROUP_HEATPUMP, CHANNEL_HEATPUMP_T_EQOUT), + getScaled(block.heatpumpTEQout, CELSIUS, -2.0)); + updateState(channelUID(GROUP_HEATPUMP, CHANNEL_HEATPUMP_VOL_SOURCE), + getScaled(block.heatpumpVolSource, LITRE_PER_MINUTE, -2.0)); + updateState(channelUID(GROUP_HEATPUMP, CHANNEL_HEATPUMP_COMPRESSOR_RATING), + getScaled(block.heatpumpCompressorRating, PERCENT, -2.0)); + updateState(channelUID(GROUP_HEATPUMP, CHANNEL_HEATPUMP_QP_HEATING), + getScaled(block.heatpumpQpHeating, WATT, 2.0)); + updateState(channelUID(GROUP_HEATPUMP, CHANNEL_HEATPUMP_FI_POWER_CONSUMPTION), + getUnscaled(block.heatpumpFIPowerConsumption, WATT)); + + updateState(channelUID(GROUP_HEATPUMP, CHANNEL_HEATPUMP_COP), getScaled(block.heatpumpCOP, PERCENT, -2.0)); + updateState(channelUID(GROUP_HEATPUMP, CHANNEL_HEATPUMP_VDAE), + getScaled(block.heatpumpVdAE, KILOWATT_HOUR, -3.0)); + updateState(channelUID(GROUP_HEATPUMP, CHANNEL_HEATPUMP_VDAQ), + getScaled(block.heatpumpVdAQ, KILOWATT_HOUR, -3.0)); + + resetCommunicationError(); + } + + protected void handlePolledHeatpumpReg50Data(ModbusRegisterArray registers) { + // logger.trace("HeatpumpReg50 block received, size: {}", registers.size()); + + HeatpumpReg50Block block = heatpumpReg50BlockParser.parse(registers); + + // Heatpump group + updateState(channelUID(GROUP_HEATPUMP_REG50, CHANNEL_HEATPUMP_SET_ERROR_QUIT), + new DecimalType(block.heatpumpSetErrorQuit)); + 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.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/LambdaException.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/LambdaException.java index 0d6e6115be7e6..be60f36f74332 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/LambdaException.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/LambdaException.java @@ -15,7 +15,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault; /** - * Thrown when the stiebel eltron handler sees an error. + * Thrown when the lambda-heatpump handler sees an error. * * @author Paul Frank - Initial contribution * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/LambdaHandler.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/LambdaHandler.java deleted file mode 100644 index 752ba9134a2cd..0000000000000 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/LambdaHandler.java +++ /dev/null @@ -1,1042 +0,0 @@ -/** - * Copyright (c) 2010-2024 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.lambda.internal.handler; - -import static org.openhab.binding.modbus.lambda.internal.LambdaBindingConstants.*; -import static org.openhab.core.library.unit.SIUnits.CELSIUS; -import static org.openhab.core.library.unit.Units.*; - -import java.util.Optional; - -import javax.measure.Unit; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.binding.modbus.handler.EndpointNotInitializedException; -import org.openhab.binding.modbus.handler.ModbusEndpointThingHandler; -import org.openhab.binding.modbus.lambda.internal.LambdaConfiguration; -import org.openhab.binding.modbus.lambda.internal.dto.AmbientBlock; -import org.openhab.binding.modbus.lambda.internal.dto.Boiler1Block; -import org.openhab.binding.modbus.lambda.internal.dto.Boiler1MtBlock; -import org.openhab.binding.modbus.lambda.internal.dto.Buffer1Block; -import org.openhab.binding.modbus.lambda.internal.dto.Buffer1MtBlock; -import org.openhab.binding.modbus.lambda.internal.dto.EManagerBlock; -import org.openhab.binding.modbus.lambda.internal.dto.HeatingCircuit1Block; -import org.openhab.binding.modbus.lambda.internal.dto.HeatingCircuit1SettingBlock; -import org.openhab.binding.modbus.lambda.internal.dto.Heatpump1Block; -import org.openhab.binding.modbus.lambda.internal.dto.Heatpump1SetBlock; -import org.openhab.binding.modbus.lambda.internal.parser.AmbientBlockParser; -import org.openhab.binding.modbus.lambda.internal.parser.Boiler1BlockParser; -import org.openhab.binding.modbus.lambda.internal.parser.Boiler1MtBlockParser; -import org.openhab.binding.modbus.lambda.internal.parser.Buffer1BlockParser; -import org.openhab.binding.modbus.lambda.internal.parser.Buffer1MtBlockParser; -import org.openhab.binding.modbus.lambda.internal.parser.EManagerBlockParser; -import org.openhab.binding.modbus.lambda.internal.parser.HeatingCircuit1BlockParser; -import org.openhab.binding.modbus.lambda.internal.parser.HeatingCircuit1SettingBlockParser; -import org.openhab.binding.modbus.lambda.internal.parser.Heatpump1BlockParser; -import org.openhab.binding.modbus.lambda.internal.parser.Heatpump1SetBlockParser; -import org.openhab.core.io.transport.modbus.AsyncModbusFailure; -import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; -import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode; -import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint; -import org.openhab.core.io.transport.modbus.ModbusRegisterArray; -import org.openhab.core.io.transport.modbus.ModbusWriteRegisterRequestBlueprint; -import org.openhab.core.io.transport.modbus.ModbusWriteRequestBlueprint; -import org.openhab.core.io.transport.modbus.PollTask; -import org.openhab.core.library.types.DecimalType; -import org.openhab.core.library.types.QuantityType; -import org.openhab.core.thing.Bridge; -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.ThingStatusInfo; -import org.openhab.core.thing.binding.BaseThingHandler; -import org.openhab.core.thing.binding.ThingHandler; -import org.openhab.core.types.Command; -import org.openhab.core.types.RefreshType; -import org.openhab.core.types.State; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * The {@link LambdaHandler} 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 LambdaHandler extends BaseThingHandler { - - public abstract class AbstractBasePoller { - - private final Logger logger = LoggerFactory.getLogger(LambdaHandler.class); - - private volatile @Nullable PollTask pollTask; - - public synchronized void unregisterPollTask() { - PollTask task = pollTask; - if (task == null) { - return; - } - - ModbusCommunicationInterface mycomms = LambdaHandler.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 = LambdaHandler.this.comms; - LambdaConfiguration myconfig = LambdaHandler.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); - } - }, LambdaHandler.this::handleReadError); - } - - public synchronized void poll() { - PollTask task = pollTask; - ModbusCommunicationInterface mycomms = LambdaHandler.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(LambdaHandler.class); - - /** - * Configuration instance - */ - protected @Nullable LambdaConfiguration config = null; - /** - * Parser used to convert incoming raw messages into system blocks - * private final SystemInfromationBlockParser systemInformationBlockParser = new SystemInfromationBlockParser(); - */ - /** - * Parsers used to convert incoming raw messages into state blocks - */ - private final AmbientBlockParser ambientBlockParser = new AmbientBlockParser(); - private final EManagerBlockParser emanagerBlockParser = new EManagerBlockParser(); - private final Boiler1BlockParser boiler1BlockParser = new Boiler1BlockParser(); - private final Boiler1MtBlockParser boiler1mtBlockParser = new Boiler1MtBlockParser(); - private final Buffer1BlockParser buffer1BlockParser = new Buffer1BlockParser(); - private final Buffer1MtBlockParser buffer1mtBlockParser = new Buffer1MtBlockParser(); - private final Heatpump1BlockParser heatpump1BlockParser = new Heatpump1BlockParser(); - private final Heatpump1SetBlockParser heatpump1SetBlockParser = new Heatpump1SetBlockParser(); - private final HeatingCircuit1BlockParser heatingcircuit1BlockParser = new HeatingCircuit1BlockParser(); - private final HeatingCircuit1SettingBlockParser heatingcircuit1settingBlockParser = new HeatingCircuit1SettingBlockParser(); - - /** - * These are the tasks used to poll the device - */ - private volatile @Nullable AbstractBasePoller ambientPoller = null; - private volatile @Nullable AbstractBasePoller emanagerPoller = null; - private volatile @Nullable AbstractBasePoller heatpump1Poller = null; - private volatile @Nullable AbstractBasePoller heatpump1SetPoller = null; - private volatile @Nullable AbstractBasePoller boiler1Poller = null; - private volatile @Nullable AbstractBasePoller boiler1mtPoller = null; - private volatile @Nullable AbstractBasePoller buffer1Poller = null; - private volatile @Nullable AbstractBasePoller buffer1mtPoller = null; - private volatile @Nullable AbstractBasePoller heatingcircuit1Poller = null; - private volatile @Nullable AbstractBasePoller heatingcircuit1settingPoller = 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 - */ - public LambdaHandler(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) { - logger.trace("187 writeInt16: Es wird geschrieben, Adresse: {} Wert: {}", address, shortValue); - LambdaConfiguration myconfig = LambdaHandler.this.config; - ModbusCommunicationInterface mycomms = LambdaHandler.this.comms; - - if (myconfig == null || mycomms == null) { - throw new IllegalStateException("registerPollTask called without proper configuration"); - } - // big endian byte ordering - byte hi = (byte) (shortValue >> 8); - byte lo = (byte) shortValue; - ModbusRegisterArray data = new ModbusRegisterArray(hi, lo); - - logger.trace("199 hi: {}, lo: {}", hi, lo); - ModbusWriteRegisterRequestBlueprint request = new ModbusWriteRegisterRequestBlueprint(slaveId, address, data, - true, myconfig.getMaxTries()); - - mycomms.submitOneTimeWrite(request, result -> { - if (hasConfigurationError()) { - return; - } - logger.trace("Successful write, matching request {}", request); - LambdaHandler.this.updateStatus(ThingStatus.ONLINE); - }, failure -> { - LambdaHandler.this.handleWriteError(failure); - logger.trace("Unsuccessful write, matching request {}", request); - }); - } - - /** - * @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 getScaled10Int16Value(Command command) throws LambdaException { - * if (command instanceof QuantityType quantityCommand) { - * QuantityType c = quantityCommand.toUnit(CELSIUS); - * if (c != null) { - * return (short) (c.doubleValue() * 10); - * } else { - * throw new LambdaException("Unsupported unit"); - * } - * } - * if (command instanceof DecimalType c) { - * return (short) (c.doubleValue() * 10); - * } - * throw new LambdaException("Unsupported command type"); - * } - * - * private short getScaled100Int16Value(Command command) throws LambdaException { - * if (command instanceof QuantityType quantityCommand) { - * QuantityType c = quantityCommand.toUnit(CELSIUS); - * if (c != null) { - * return (short) (c.doubleValue() * 100); - * } else { - * throw new LambdaException("Unsupported unit"); - * } - * } - * if (command instanceof DecimalType c) { - * return (short) (c.doubleValue() * 100); - * } - * throw new LambdaException("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 LambdaException { - if (command instanceof QuantityType quantityCommand) { - QuantityType c = quantityCommand.toUnit(WATT); - if (c != null) { - return c.shortValue(); - } else { - throw new LambdaException("Unsupported unit"); - } - } - if (command instanceof DecimalType c) { - return c.shortValue(); - } - throw new LambdaException("Unsupported command type"); - } - - private short getScaledInt16Value(Command command) throws LambdaException { - if (command instanceof QuantityType quantityCommand) { - QuantityType c = quantityCommand.toUnit(CELSIUS); - if (c != null) { - return (short) (c.doubleValue() * 10); - } else { - throw new LambdaException("Unsupported unit"); - } - } - if (command instanceof DecimalType c) { - return (short) (c.doubleValue() * 10); - } - throw new LambdaException("Unsupported command type"); - } - - /** - * Handle incoming commands. - */ - @Override - public void handleCommand(ChannelUID channelUID, Command command) { - logger.trace("283 handleCommand, channelUID: {} command {} ", channelUID, command); - if (RefreshType.REFRESH == command) { - String groupId = channelUID.getGroupId(); - if (groupId != null) { - AbstractBasePoller poller; - switch (groupId) { - case GROUP_GENERAL_AMBIENT: - poller = ambientPoller; - break; - case GROUP_GENERAL_EMANAGER: - poller = emanagerPoller; - break; - case GROUP_HEATPUMP1: - poller = heatpump1Poller; - break; - case GROUP_HEATPUMP1SET: - poller = heatpump1SetPoller; - break; - case GROUP_BOILER1: - poller = boiler1Poller; - break; - case GROUP_BOILER1MT: - poller = boiler1mtPoller; - break; - case GROUP_BUFFER1: - poller = buffer1Poller; - break; - case GROUP_BUFFER1MT: - poller = buffer1mtPoller; - break; - case GROUP_HEATINGCIRCUIT1: - poller = heatingcircuit1Poller; - break; - case GROUP_HEATINGCIRCUIT1SETTING: - poller = heatingcircuit1settingPoller; - break; - default: - poller = null; - break; - } - if (poller != null) { - // logger.trace("336 Es wird gepollt }"); - poller.poll(); - } - } - } else { - logger.trace("341 handleCommand: Es wird geschrieben, GroupID: {}, command {}", channelUID.getGroupId(), - command); - try { - - logger.trace("345 vor EMANAGER"); - if (GROUP_GENERAL_EMANAGER.equals(channelUID.getGroupId())) { - - logger.trace("330 im EMANAGER channelUID {} ", channelUID.getIdWithoutGroup()); - switch (channelUID.getIdWithoutGroup()) { - - case CHANNEL_ACTUAL_POWER: - - logger.trace("336 command: {}", command); - writeInt16(102, getInt16Value(command)); - break; - - } - } - if (GROUP_BOILER1MT.equals(channelUID.getGroupId())) { - logger.trace("345 im BOILER1MT channelUID {} ", channelUID.getIdWithoutGroup()); - - switch (channelUID.getIdWithoutGroup()) { - - case CHANNEL_BOILER1_MAXIMUM_BOILER_TEMPERATURE: - - logger.trace("347 command: {}", command); - writeInt16(2050, getScaledInt16Value(command)); - break; - - } - } - if (GROUP_BUFFER1MT.equals(channelUID.getGroupId())) { - logger.trace("359 im BUFFER1MT channelUID {} ", channelUID.getIdWithoutGroup()); - - switch (channelUID.getIdWithoutGroup()) { - - case CHANNEL_BUFFER1_MAXIMUM_BOILER_TEMPERATURE: - - logger.trace("365 command: {}", command); - writeInt16(3050, getScaledInt16Value(command)); - break; - - } - } - - if (GROUP_HEATINGCIRCUIT1.equals(channelUID.getGroupId())) { - logger.trace("387 im HEATINGCIRCUI1 channelUID {} ", channelUID.getIdWithoutGroup()); - - switch (channelUID.getIdWithoutGroup()) { - - case CHANNEL_HEATINGCIRCUIT1_ROOM_DEVICE_TEMPERATURE: - logger.trace("393 command: {}", command); - writeInt16(5004, getScaledInt16Value(command)); - break; - case CHANNEL_HEATINGCIRCUIT1_SETPOINT_FLOW_LINE_TEMPERATURE: - logger.trace("393 command: {}", command); - writeInt16(5005, getScaledInt16Value(command)); - break; - case CHANNEL_HEATINGCIRCUIT1_OPERATING_MODE: - logger.trace("403 command: {}", command); - writeInt16(5006, getInt16Value(command)); - break; - - } - } - - if (GROUP_HEATINGCIRCUIT1SETTING.equals(channelUID.getGroupId())) { - logger.trace("411 im HEATINGCIRCUI1 channelUID {} ", channelUID.getIdWithoutGroup()); - - switch (channelUID.getIdWithoutGroup()) { - - case CHANNEL_HEATINGCIRCUIT1_OFFSET_FLOW_LINE_TEMPERATURE: - - logger.trace("418 command: {}", command); - writeInt16(5050, getScaledInt16Value(command)); - break; - case CHANNEL_HEATINGCIRCUIT1_ROOM_HEATING_TEMPERATURE: - - logger.trace("233 command: {}", command); - writeInt16(5051, getScaledInt16Value(command)); - break; - case CHANNEL_HEATINGCIRCUIT1_ROOM_COOLING_TEMPERATURE: - - logger.trace("427 command: {}", command); - writeInt16(5052, getScaledInt16Value(command)); - break; - - } - - } - if (GROUP_HEATPUMP1SET.equals(channelUID.getGroupId())) { - logger.trace("439 im HEATPUMP1SET channelUID {} ", channelUID.getIdWithoutGroup()); - - switch (channelUID.getIdWithoutGroup()) { - - case CHANNEL_HEATPUMP1_SET_ERROR_QUIT: - - logger.trace("445 Heatpumpseterrorquit command: {}", command); - writeInt16(1050, getScaledInt16Value(command)); - break; - - } - } - } catch (LambdaException 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(LambdaConfiguration.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 (ambientPoller == null) { - AbstractBasePoller poller = new AbstractBasePoller() { - @Override - protected void handlePolledData(ModbusRegisterArray registers) { - handlePolledAmbientData(registers); - } - }; - poller.registerPollTask(0, 5, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); - ambientPoller = poller; - } - - if (emanagerPoller == null) { - AbstractBasePoller poller = new AbstractBasePoller() { - @Override - protected void handlePolledData(ModbusRegisterArray registers) { - handlePolledEManagerData(registers); - } - }; - poller.registerPollTask(100, 5, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); - emanagerPoller = poller; - } - if (heatpump1Poller == null) { - AbstractBasePoller poller = new AbstractBasePoller() { - @Override - protected void handlePolledData(ModbusRegisterArray registers) { - handlePolledHeatpump1Data(registers); - } - }; - - poller.registerPollTask(1000, 14, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); - logger.trace("Poller Heatpump1 erzeugt"); - heatpump1Poller = poller; - } - - if (heatpump1SetPoller == null) { - AbstractBasePoller poller = new AbstractBasePoller() { - @Override - protected void handlePolledData(ModbusRegisterArray registers) { - handlePolledHeatpump1SetData(registers); - } - }; - - poller.registerPollTask(1050, 1, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); - logger.trace("Poller Heatpump1Set erzeugt"); - heatpump1SetPoller = poller; - } - - if (boiler1Poller == null) { - AbstractBasePoller poller = new AbstractBasePoller() { - @Override - protected void handlePolledData(ModbusRegisterArray registers) { - handlePolledBoiler1Data(registers); - } - }; - - poller.registerPollTask(2000, 4, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); - boiler1Poller = poller; - } - if (boiler1mtPoller == null) { - AbstractBasePoller poller = new AbstractBasePoller() { - @Override - protected void handlePolledData(ModbusRegisterArray registers) { - handlePolledBoiler1MtData(registers); - } - }; - - poller.registerPollTask(2050, 1, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); - boiler1mtPoller = poller; - } - - if (buffer1Poller == null) { - AbstractBasePoller poller = new AbstractBasePoller() { - @Override - protected void handlePolledData(ModbusRegisterArray registers) { - handlePolledBuffer1Data(registers); - } - }; - - poller.registerPollTask(3000, 4, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); - buffer1Poller = poller; - } - if (buffer1mtPoller == null) { - AbstractBasePoller poller = new AbstractBasePoller() { - @Override - protected void handlePolledData(ModbusRegisterArray registers) { - handlePolledBuffer1MtData(registers); - } - }; - - poller.registerPollTask(3050, 1, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); - buffer1mtPoller = poller; - } - if (heatingcircuit1Poller == null) { - AbstractBasePoller poller = new AbstractBasePoller() { - @Override - protected void handlePolledData(ModbusRegisterArray registers) { - handlePolledHeatingCircuit1Data(registers); - } - }; - - poller.registerPollTask(5000, 7, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); - logger.trace("Poller HeatingCircuit1 erzeugt"); - heatingcircuit1Poller = poller; - } - if (heatingcircuit1settingPoller == null) { - AbstractBasePoller poller = new AbstractBasePoller() { - @Override - protected void handlePolledData(ModbusRegisterArray registers) { - handlePolledHeatingCircuit1SettingData(registers); - } - }; - - poller.registerPollTask(5050, 3, ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS); - logger.trace("Poller HeatingCircuit1Setting erzeugt"); - heatingcircuit1settingPoller = 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 = ambientPoller; - if (poller != null) { - poller.unregisterPollTask(); - ambientPoller = null; - } - - poller = emanagerPoller; - if (poller != null) { - poller.unregisterPollTask(); - emanagerPoller = null; - } - - poller = heatpump1Poller; - if (poller != null) { - poller.unregisterPollTask(); - heatpump1Poller = null; - } - - poller = heatpump1SetPoller; - if (poller != null) { - poller.unregisterPollTask(); - heatpump1SetPoller = null; - } - poller = boiler1Poller; - if (poller != null) { - poller.unregisterPollTask(); - boiler1Poller = null; - } - poller = boiler1mtPoller; - if (poller != null) { - poller.unregisterPollTask(); - boiler1mtPoller = null; - } - - poller = buffer1Poller; - if (poller != null) { - poller.unregisterPollTask(); - buffer1Poller = null; - } - poller = buffer1mtPoller; - if (poller != null) { - poller.unregisterPollTask(); - buffer1mtPoller = null; - } - - poller = heatingcircuit1Poller; - if (poller != null) { - logger.debug("Unregistering heatingcircuit1Poller from ModbusManager"); - poller.unregisterPollTask(); - heatingcircuit1Poller = null; - } - - poller = heatingcircuit1settingPoller; - if (poller != null) { - logger.debug("Unregistering heatingcircuit1settingPoller from ModbusManager"); - poller.unregisterPollTask(); - heatingcircuit1settingPoller = 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 thingHandler) { - return thingHandler; - } 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 getScaled10(Number value, Unit unit) { - * // logger.trace("505 value: {}", value.intValue()); - * return QuantityType.valueOf(value.doubleValue() / 10, unit); - * } - * - * protected State getScaled100(Number value, Unit unit) { - * // logger.trace("505 value: {}", value.intValue()); - * return QuantityType.valueOf(value.doubleValue() / 100, unit); - * } - */ - protected State getScaled(Number value, Unit unit, Double pow) { - // logger.trace("505 value: {}", value.intValue()); - double factor = Math.pow(10, pow); - return QuantityType.valueOf(value.doubleValue() * factor, unit); - } - - protected State getUnscaled(Number value, Unit unit) { - return QuantityType.valueOf(value.doubleValue(), 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); - } - - /** - * These methods are 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 handlePolledAmbientData(ModbusRegisterArray registers) { - // logger.trace("Ambient block received, size: {}", registers.size()); - - // Ambient group - AmbientBlock block = ambientBlockParser.parse(registers); - - updateState(channelUID(GROUP_GENERAL_AMBIENT, CHANNEL_AMBIENT_ERROR_NUMBER), - new DecimalType(block.ambientErrorNumber)); - updateState(channelUID(GROUP_GENERAL_AMBIENT, CHANNEL_AMBIENT_OPERATING_STATE), - new DecimalType(block.ambientOperatingState)); - updateState(channelUID(GROUP_GENERAL_AMBIENT, CHANNEL_ACTUAL_AMBIENT_TEMPERATURE), - getScaled(block.actualAmbientTemperature, CELSIUS, -1.0)); - updateState(channelUID(GROUP_GENERAL_AMBIENT, CHANNEL_AVERAGE_AMBIENT_TEMPERATURE), - getScaled(block.averageAmbientTemperature, CELSIUS, -1.0)); - updateState(channelUID(GROUP_GENERAL_AMBIENT, CHANNEL_CALCULATED_AMBIENT_TEMPERATURE), - getScaled(block.calculatedAmbientTemperature, CELSIUS, -1.0)); - resetCommunicationError(); - } - - protected void handlePolledEManagerData(ModbusRegisterArray registers) { - // logger.trace("EManager block received, size: {}", registers.size()); - - // EManager group - EManagerBlock block = emanagerBlockParser.parse(registers); - updateState(channelUID(GROUP_GENERAL_EMANAGER, CHANNEL_EMANAGER_ERROR_NUMBER), - new DecimalType(block.emanagerErrorNumber)); - updateState(channelUID(GROUP_GENERAL_EMANAGER, CHANNEL_EMANAGER_OPERATING_STATE), - new DecimalType(block.emanagerOperatingState)); - updateState(channelUID(GROUP_GENERAL_EMANAGER, CHANNEL_ACTUAL_POWER_CONSUMPTION), - getUnscaled(block.actualPowerConsumption, WATT)); - updateState(channelUID(GROUP_GENERAL_EMANAGER, CHANNEL_ACTUAL_POWER), getUnscaled(block.actualPower, WATT)); - updateState(channelUID(GROUP_GENERAL_EMANAGER, CHANNEL_POWER_CONSUMPTION_SETPOINT), - getUnscaled(block.powerConsumptionSetpoint, WATT)); - - resetCommunicationError(); - } - - protected void handlePolledHeatpump1Data(ModbusRegisterArray registers) { - logger.trace("Heatpump1 block received, size: {}", registers.size()); - - Heatpump1Block block = heatpump1BlockParser.parse(registers); - - // Heatpump1 group - updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_ERROR_STATE), - new DecimalType(block.heatpump1ErrorState)); - updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_ERROR_NUMBER), - new DecimalType(block.heatpump1ErrorNumber)); - updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_OPERATING_STATE), - new DecimalType(block.heatpump1OperatingState)); - updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_STATE), new DecimalType(block.heatpump1State)); - updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_T_FLOW), - getScaled(block.heatpump1TFlow, CELSIUS, -2.0)); - updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_T_RETURN), - getScaled(block.heatpump1TReturn, CELSIUS, -2.0)); - updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_VOL_SINK), - getScaled(block.heatpump1VolSink, LITRE_PER_MINUTE, -2.0)); - updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_T_EQIN), - getScaled(block.heatpump1TEQin, CELSIUS, -2.0)); - updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_T_EQOUT), - getScaled(block.heatpump1TEQout, CELSIUS, -2.0)); - updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_VOL_SOURCE), - getScaled(block.heatpump1VolSource, LITRE_PER_MINUTE, -2.0)); - updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_COMPRESSOR_RATING), - getScaled(block.heatpump1CompressorRating, PERCENT, -2.0)); - updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_QP_HEATING), - getScaled(block.heatpump1QpHeating, WATT, 2.0)); - updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_FI_POWER_CONSUMPTION), - getUnscaled(block.heatpump1FIPowerConsumption, WATT)); - updateState(channelUID(GROUP_HEATPUMP1, CHANNEL_HEATPUMP1_COP), getScaled(block.heatpump1COP, PERCENT, -2.0)); - - resetCommunicationError(); - } - - protected void handlePolledHeatpump1SetData(ModbusRegisterArray registers) { - logger.trace("Heatpump1Set block received, size: {}", registers.size()); - - Heatpump1SetBlock block = heatpump1SetBlockParser.parse(registers); - - // Heatpump1 group - updateState(channelUID(GROUP_HEATPUMP1SET, CHANNEL_HEATPUMP1_SET_ERROR_QUIT), - new DecimalType(block.heatpump1seterrorquit)); - resetCommunicationError(); - } - - protected void handlePolledBoiler1Data(ModbusRegisterArray registers) { - logger.trace("Boiler1 block received, size: {}", registers.size()); - - Boiler1Block block = boiler1BlockParser.parse(registers); - - // Boiler1 group - updateState(channelUID(GROUP_BOILER1, CHANNEL_BOILER1_ERROR_NUMBER), new DecimalType(block.boiler1ErrorNumber)); - updateState(channelUID(GROUP_BOILER1, CHANNEL_BOILER1_OPERATING_STATE), - new DecimalType(block.boiler1OperatingState)); - updateState(channelUID(GROUP_BOILER1, CHANNEL_BOILER1_ACTUAL_HIGH_TEMPERATURE), - getScaled(block.boiler1ActualHighTemperature, CELSIUS, -1.0)); - updateState(channelUID(GROUP_BOILER1, CHANNEL_BOILER1_ACTUAL_LOW_TEMPERATURE), - getScaled(block.boiler1ActualLowTemperature, CELSIUS, -1.0)); - resetCommunicationError(); - } - - protected void handlePolledBoiler1MtData(ModbusRegisterArray registers) { - logger.trace("Boiler1Mt block received, size: {}", registers.size()); - - Boiler1MtBlock block = boiler1mtBlockParser.parse(registers); - - // Boiler1Mt group - updateState(channelUID(GROUP_BOILER1MT, CHANNEL_BOILER1_MAXIMUM_BOILER_TEMPERATURE), - getScaled(block.boiler1MaximumBoilerTemperature, CELSIUS, -1.0)); - resetCommunicationError(); - } - - protected void handlePolledBuffer1Data(ModbusRegisterArray registers) { - logger.trace("Buffer1 block received, size: {}", registers.size()); - - Buffer1Block block = buffer1BlockParser.parse(registers); - - // Buffer1 group - updateState(channelUID(GROUP_BUFFER1, CHANNEL_BUFFER1_ERROR_NUMBER), new DecimalType(block.buffer1ErrorNumber)); - updateState(channelUID(GROUP_BUFFER1, CHANNEL_BUFFER1_OPERATING_STATE), - new DecimalType(block.buffer1OperatingState)); - updateState(channelUID(GROUP_BUFFER1, CHANNEL_BUFFER1_ACTUAL_HIGH_TEMPERATURE), - getScaled(block.buffer1ActualHighTemperature, CELSIUS, -1.0)); - updateState(channelUID(GROUP_BUFFER1, CHANNEL_BUFFER1_ACTUAL_LOW_TEMPERATURE), - getScaled(block.buffer1ActualLowTemperature, CELSIUS, -1.0)); - resetCommunicationError(); - } - - protected void handlePolledBuffer1MtData(ModbusRegisterArray registers) { - logger.trace("Buffer1Mt block received, size: {}", registers.size()); - - Buffer1MtBlock block = buffer1mtBlockParser.parse(registers); - - // Buffer1Mt group - updateState(channelUID(GROUP_BUFFER1MT, CHANNEL_BUFFER1_MAXIMUM_BOILER_TEMPERATURE), - getScaled(block.buffer1MaximumBufferTemperature, CELSIUS, -1.0)); - resetCommunicationError(); - } - - protected void handlePolledHeatingCircuit1Data(ModbusRegisterArray registers) { - logger.trace("HeatingCircuit1 block received, size: {}", registers.size()); - - HeatingCircuit1Block block = heatingcircuit1BlockParser.parse(registers); - - // HeatingCircuit1 group - - updateState(channelUID(GROUP_HEATINGCIRCUIT1, CHANNEL_HEATINGCIRCUIT1_ERROR_NUMBER), - new DecimalType(block.heatingcircuit1ErrorNumber)); - updateState(channelUID(GROUP_HEATINGCIRCUIT1, CHANNEL_HEATINGCIRCUIT1_OPERATING_STATE), - new DecimalType(block.heatingcircuit1OperatingState)); - updateState(channelUID(GROUP_HEATINGCIRCUIT1, CHANNEL_HEATINGCIRCUIT1_FLOW_LINE_TEMPERATURE), - getScaled(block.heatingcircuit1FlowLineTemperature, CELSIUS, -1.0)); - updateState(channelUID(GROUP_HEATINGCIRCUIT1, CHANNEL_HEATINGCIRCUIT1_RETURN_LINE_TEMPERATURE), - getScaled(block.heatingcircuit1ReturnLineTemperature, CELSIUS, -1.0)); - updateState(channelUID(GROUP_HEATINGCIRCUIT1, CHANNEL_HEATINGCIRCUIT1_ROOM_DEVICE_TEMPERATURE), - getScaled(block.heatingcircuit1RoomDeviceTemperature, CELSIUS, -1.0)); - updateState(channelUID(GROUP_HEATINGCIRCUIT1, CHANNEL_HEATINGCIRCUIT1_SETPOINT_FLOW_LINE_TEMPERATURE), - getScaled(block.heatingcircuit1SetpointFlowLineTemperature, CELSIUS, -1.0)); - updateState(channelUID(GROUP_HEATINGCIRCUIT1, CHANNEL_HEATINGCIRCUIT1_OPERATING_MODE), - new DecimalType(block.heatingcircuit1OperatingMode)); - - resetCommunicationError(); - } - - protected void handlePolledHeatingCircuit1SettingData(ModbusRegisterArray registers) { - logger.trace("HeatingCircuit1Setting block received, size: {}", registers.size()); - - HeatingCircuit1SettingBlock block = heatingcircuit1settingBlockParser.parse(registers); - - // HeatingCircuit1Settting group - - updateState(channelUID(GROUP_HEATINGCIRCUIT1SETTING, CHANNEL_HEATINGCIRCUIT1_OFFSET_FLOW_LINE_TEMPERATURE), - getScaled(block.heatingcircuit1OffsetFlowLineTemperature, CELSIUS, -1.0)); - updateState(channelUID(GROUP_HEATINGCIRCUIT1SETTING, CHANNEL_HEATINGCIRCUIT1_ROOM_HEATING_TEMPERATURE), - getScaled(block.heatingcircuit1RoomHeatingTemperature, CELSIUS, -1.0)); - updateState(channelUID(GROUP_HEATINGCIRCUIT1SETTING, CHANNEL_HEATINGCIRCUIT1_ROOM_COOLING_TEMPERATURE), - getScaled(block.heatingcircuit1RoomCoolingTemperature, CELSIUS, -1.0)); - 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.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/AbstractBaseParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/AbstractBaseParser.java index 56f5150c73fb3..809aab3812b4b 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/AbstractBaseParser.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/AbstractBaseParser.java @@ -114,6 +114,11 @@ protected Optional extractOptionalUInt32(ModbusRegisterArray raw, int inde .filter(value -> value != 0); } + protected Optional extractOptionalInt32(ModbusRegisterArray raw, int index) { + return ModbusBitUtilities.extractStateFromRegisters(raw, index, ValueType.INT32).map(DecimalType::longValue) + .filter(value -> value != 0); + } + /** * Extract a mandatory acc32 value * @@ -122,7 +127,11 @@ protected Optional extractOptionalUInt32(ModbusRegisterArray raw, int inde * @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) { + protected Long extractUInt32(ModbusRegisterArray raw, int index, long def) { return Objects.requireNonNull(extractOptionalUInt32(raw, index).orElse(def)); } + + protected Long extractInt32(ModbusRegisterArray raw, int index, long def) { + return Objects.requireNonNull(extractOptionalInt32(raw, index).orElse(def)); + } } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/AmbientBlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/AmbientBlockParser.java index 3d221a6f60847..4416d22baf018 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/AmbientBlockParser.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/AmbientBlockParser.java @@ -28,11 +28,11 @@ public class AmbientBlockParser extends AbstractBaseParser { public AmbientBlock parse(ModbusRegisterArray raw) { AmbientBlock block = new AmbientBlock(); - block.ambientErrorNumber = extractUInt16(raw, 0, (short) 0); + block.ambientErrorNumber = extractInt16(raw, 0, (short) 0); block.ambientOperatingState = extractUInt16(raw, 1, (short) 0); - block.actualAmbientTemperature = extractUInt16(raw, 2, (short) 0); - block.averageAmbientTemperature = extractUInt16(raw, 3, (short) 0); - block.calculatedAmbientTemperature = extractUInt16(raw, 4, (short) 0); + block.actualAmbientTemperature = extractInt16(raw, 2, (short) 0); + block.averageAmbientTemperature = extractInt16(raw, 3, (short) 0); + block.calculatedAmbientTemperature = extractInt16(raw, 4, (short) 0); return block; } } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1BlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1BlockParser.java deleted file mode 100644 index e1056ad0740bd..0000000000000 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1BlockParser.java +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2010-2024 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.lambda.internal.parser; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.binding.modbus.lambda.internal.dto.Boiler1Block; -import org.openhab.core.io.transport.modbus.ModbusRegisterArray; - -/** - * Parses lambda modbus data into a Boiler1 Block - * - * @author Paul Frank - Initial contribution - * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus - * - */ -@NonNullByDefault -public class Boiler1BlockParser extends AbstractBaseParser { - - public Boiler1Block parse(ModbusRegisterArray raw) { - Boiler1Block block = new Boiler1Block(); - block.boiler1ErrorNumber = extractUInt16(raw, 0, (short) 0); - block.boiler1OperatingState = extractUInt16(raw, 1, (short) 0); - block.boiler1ActualHighTemperature = extractUInt16(raw, 2, (short) 0); - block.boiler1ActualLowTemperature = extractUInt16(raw, 3, (short) 0); - return block; - } -} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/BoilerBlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/BoilerBlockParser.java new file mode 100644 index 0000000000000..916bed4806473 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/BoilerBlockParser.java @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.parser; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.modbus.lambda.internal.dto.BoilerBlock; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; + +/** + * Parses lambda modbus data into a Boiler Block + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + * + */ +@NonNullByDefault +public class BoilerBlockParser extends AbstractBaseParser { + + public BoilerBlock parse(ModbusRegisterArray raw) { + BoilerBlock block = new BoilerBlock(); + block.boilerErrorNumber = extractUInt16(raw, 0, (short) 0); + block.boilerOperatingState = extractInt16(raw, 1, (short) 0); + block.boilerActualHighTemperature = extractInt16(raw, 2, (short) 0); + block.boilerActualLowTemperature = extractInt16(raw, 3, (short) 0); + return block; + } +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Heatpump1SetBlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/BoilerReg50BlockParser.java similarity index 66% rename from bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Heatpump1SetBlockParser.java rename to bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/BoilerReg50BlockParser.java index 2f70748d72fdc..ccc0d0209e592 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Heatpump1SetBlockParser.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/BoilerReg50BlockParser.java @@ -13,22 +13,22 @@ package org.openhab.binding.modbus.lambda.internal.parser; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.binding.modbus.lambda.internal.dto.Heatpump1SetBlock; +import org.openhab.binding.modbus.lambda.internal.dto.BoilerReg50Block; import org.openhab.core.io.transport.modbus.ModbusRegisterArray; /** - * Parses inlambda modbus data into a Heatpump1 Block + * Parses modbus data into an BoilerReg50 Block - * * @author Paul Frank - Initial contribution * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus * */ @NonNullByDefault -public class Heatpump1SetBlockParser extends AbstractBaseParser { +public class BoilerReg50BlockParser extends AbstractBaseParser { - public Heatpump1SetBlock parse(ModbusRegisterArray raw) { - Heatpump1SetBlock block = new Heatpump1SetBlock(); - block.heatpump1seterrorquit = extractUInt16(raw, 0, (short) 0); + public BoilerReg50Block parse(ModbusRegisterArray raw) { + BoilerReg50Block block = new BoilerReg50Block(); + block.boilerMaximumBoilerTemperature = extractUInt16(raw, 0, (short) 0); return block; } } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Buffer1BlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/BufferBlockParser.java similarity index 60% rename from bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Buffer1BlockParser.java rename to bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/BufferBlockParser.java index 16ef4c0599cae..61308961f21d4 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Buffer1BlockParser.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/BufferBlockParser.java @@ -13,7 +13,7 @@ package org.openhab.binding.modbus.lambda.internal.parser; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.binding.modbus.lambda.internal.dto.Buffer1Block; +import org.openhab.binding.modbus.lambda.internal.dto.BufferBlock; import org.openhab.core.io.transport.modbus.ModbusRegisterArray; /** @@ -24,14 +24,14 @@ * */ @NonNullByDefault -public class Buffer1BlockParser extends AbstractBaseParser { +public class BufferBlockParser extends AbstractBaseParser { - public Buffer1Block parse(ModbusRegisterArray raw) { - Buffer1Block block = new Buffer1Block(); - block.buffer1ErrorNumber = extractUInt16(raw, 0, (short) 0); - block.buffer1OperatingState = extractUInt16(raw, 1, (short) 0); - block.buffer1ActualHighTemperature = extractUInt16(raw, 2, (short) 0); - block.buffer1ActualLowTemperature = extractUInt16(raw, 3, (short) 0); + public BufferBlock parse(ModbusRegisterArray raw) { + BufferBlock block = new BufferBlock(); + block.bufferErrorNumber = extractInt16(raw, 0, (short) 0); + block.bufferOperatingState = extractUInt16(raw, 1, (short) 0); + block.bufferActualHighTemperature = extractInt16(raw, 2, (short) 0); + block.bufferActualLowTemperature = extractInt16(raw, 3, (short) 0); return block; } } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1MtBlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/BufferReg50BlockParser.java similarity index 66% rename from bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1MtBlockParser.java rename to bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/BufferReg50BlockParser.java index cdd795cdfa297..9f05ed7e7c590 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Boiler1MtBlockParser.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/BufferReg50BlockParser.java @@ -13,22 +13,22 @@ package org.openhab.binding.modbus.lambda.internal.parser; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.binding.modbus.lambda.internal.dto.Boiler1MtBlock; +import org.openhab.binding.modbus.lambda.internal.dto.BufferReg50Block; import org.openhab.core.io.transport.modbus.ModbusRegisterArray; /** - * Parses inv modbus data into an Boiler1Mt Block - + * Parses lambda modbus data into an BufferReg50 Block - * * @author Paul Frank - Initial contribution * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus * */ @NonNullByDefault -public class Boiler1MtBlockParser extends AbstractBaseParser { +public class BufferReg50BlockParser extends AbstractBaseParser { - public Boiler1MtBlock parse(ModbusRegisterArray raw) { - Boiler1MtBlock block = new Boiler1MtBlock(); - block.boiler1MaximumBoilerTemperature = extractUInt16(raw, 0, (short) 0); + public BufferReg50Block parse(ModbusRegisterArray raw) { + BufferReg50Block block = new BufferReg50Block(); + block.bufferMaximumBufferTemperature = extractUInt16(raw, 0, (short) 0); return block; } } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/EManagerBlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/EManagerBlockParser.java index 3c2b2c649c061..3d4c76fdac0bb 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/EManagerBlockParser.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/EManagerBlockParser.java @@ -28,11 +28,11 @@ public class EManagerBlockParser extends AbstractBaseParser { public EManagerBlock parse(ModbusRegisterArray raw) { EManagerBlock block = new EManagerBlock(); - block.emanagerErrorNumber = extractUInt16(raw, 0, (short) 0); + block.emanagerErrorNumber = extractInt16(raw, 0, (short) 0); block.emanagerOperatingState = extractUInt16(raw, 1, (short) 0); block.actualPower = extractUInt16(raw, 2, (short) 0); - block.actualPowerConsumption = extractUInt16(raw, 3, (short) 0); - block.powerConsumptionSetpoint = extractUInt16(raw, 4, (short) 0); + block.actualPowerConsumption = extractInt16(raw, 3, (short) 0); + block.powerConsumptionSetpoint = extractInt16(raw, 4, (short) 0); return block; } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatingCircuit1BlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatingCircuitBlockParser.java similarity index 51% rename from bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatingCircuit1BlockParser.java rename to bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatingCircuitBlockParser.java index 41e0ba54a4442..a5378e3915b07 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatingCircuit1BlockParser.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatingCircuitBlockParser.java @@ -13,29 +13,29 @@ package org.openhab.binding.modbus.lambda.internal.parser; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.binding.modbus.lambda.internal.dto.HeatingCircuit1Block; +import org.openhab.binding.modbus.lambda.internal.dto.HeatingCircuitBlock; import org.openhab.core.io.transport.modbus.ModbusRegisterArray; /** * Parses lambda - * modbus data into a Heatpump1 Block + * modbus data into a Heating Circuit Block * * @author Paul Frank - Initial contribution * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus * */ @NonNullByDefault -public class HeatingCircuit1BlockParser extends AbstractBaseParser { +public class HeatingCircuitBlockParser extends AbstractBaseParser { - public HeatingCircuit1Block parse(ModbusRegisterArray raw) { - HeatingCircuit1Block block = new HeatingCircuit1Block(); - block.heatingcircuit1ErrorNumber = extractUInt16(raw, 0, (short) 0); - block.heatingcircuit1OperatingState = extractUInt16(raw, 1, (short) 0); - block.heatingcircuit1FlowLineTemperature = extractUInt16(raw, 2, (short) 0); - block.heatingcircuit1ReturnLineTemperature = extractUInt16(raw, 3, (short) 0); - block.heatingcircuit1RoomDeviceTemperature = extractUInt16(raw, 4, (short) 0); - block.heatingcircuit1SetpointFlowLineTemperature = extractUInt16(raw, 5, (short) 0); - block.heatingcircuit1OperatingMode = extractUInt16(raw, 6, (short) 0); + public HeatingCircuitBlock parse(ModbusRegisterArray raw) { + HeatingCircuitBlock block = new HeatingCircuitBlock(); + block.heatingcircuitErrorNumber = extractInt16(raw, 0, (short) 0); + block.heatingcircuitOperatingState = extractUInt16(raw, 1, (short) 0); + block.heatingcircuitFlowLineTemperature = extractInt16(raw, 2, (short) 0); + block.heatingcircuitReturnLineTemperature = extractInt16(raw, 3, (short) 0); + block.heatingcircuitRoomDeviceTemperature = extractInt16(raw, 4, (short) 0); + block.heatingcircuitSetpointFlowLineTemperature = extractInt16(raw, 5, (short) 0); + block.heatingcircuitOperatingMode = extractInt16(raw, 6, (short) 0); return block; } } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatingCircuit1SettingBlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatingCircuitReg50BlockParser.java similarity index 56% rename from bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatingCircuit1SettingBlockParser.java rename to bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatingCircuitReg50BlockParser.java index 54c7e1a02f830..ad634c5bc577a 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatingCircuit1SettingBlockParser.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatingCircuitReg50BlockParser.java @@ -13,25 +13,24 @@ package org.openhab.binding.modbus.lambda.internal.parser; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.binding.modbus.lambda.internal.dto.HeatingCircuit1SettingBlock; +import org.openhab.binding.modbus.lambda.internal.dto.HeatingCircuitReg50Block; import org.openhab.core.io.transport.modbus.ModbusRegisterArray; /** - * Parses lambda modbus data into a Heatpump1 Block + * Parses lambda modbus data into a HeatingCircuitReg50 Block * * @author Paul Frank - Initial contribution * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus * */ @NonNullByDefault -public class HeatingCircuit1SettingBlockParser extends AbstractBaseParser { +public class HeatingCircuitReg50BlockParser extends AbstractBaseParser { - public HeatingCircuit1SettingBlock parse(ModbusRegisterArray raw) { - // logger.trace("HeatingCircuit1Setting 33 wird gelesen"); - HeatingCircuit1SettingBlock block = new HeatingCircuit1SettingBlock(); - block.heatingcircuit1OffsetFlowLineTemperature = extractUInt16(raw, 0, (short) 0); - block.heatingcircuit1RoomHeatingTemperature = extractUInt16(raw, 1, (short) 0); - block.heatingcircuit1RoomCoolingTemperature = extractUInt16(raw, 2, (short) 0); + public HeatingCircuitReg50Block parse(ModbusRegisterArray raw) { + HeatingCircuitReg50Block block = new HeatingCircuitReg50Block(); + block.heatingcircuitOffsetFlowLineTemperature = extractInt16(raw, 0, (short) 0); + block.heatingcircuitRoomHeatingTemperature = extractInt16(raw, 1, (short) 0); + block.heatingcircuitRoomCoolingTemperature = extractInt16(raw, 2, (short) 0); return block; } } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Heatpump1BlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Heatpump1BlockParser.java deleted file mode 100644 index 10c9432dc3eef..0000000000000 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Heatpump1BlockParser.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (c) 2010-2024 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.lambda.internal.parser; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.binding.modbus.lambda.internal.dto.Heatpump1Block; -import org.openhab.core.io.transport.modbus.ModbusRegisterArray; - -/** - * Parses inlambda modbus data into a Heatpump1 Block - * - * @author Paul Frank - Initial contribution - * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus - * - */ -@NonNullByDefault -public class Heatpump1BlockParser extends AbstractBaseParser { - - public Heatpump1Block parse(ModbusRegisterArray raw) { - Heatpump1Block block = new Heatpump1Block(); - block.heatpump1ErrorState = extractUInt16(raw, 0, (short) 0); - block.heatpump1ErrorNumber = extractUInt16(raw, 1, (short) 0); - block.heatpump1State = extractUInt16(raw, 2, (short) 0); - block.heatpump1OperatingState = extractUInt16(raw, 3, (short) 0); - block.heatpump1TFlow = extractUInt16(raw, 4, (short) 0); - block.heatpump1TReturn = extractUInt16(raw, 5, (short) 0); - block.heatpump1VolSink = extractUInt16(raw, 6, (short) 0); - block.heatpump1TEQin = extractUInt16(raw, 7, (short) 0); - block.heatpump1TEQout = extractUInt16(raw, 8, (short) 0); - block.heatpump1VolSource = extractUInt16(raw, 9, (short) 0); - block.heatpump1CompressorRating = extractUInt16(raw, 10, (short) 0); - block.heatpump1QpHeating = extractUInt16(raw, 11, (short) 0); - block.heatpump1FIPowerConsumption = extractUInt16(raw, 12, (short) 0); - block.heatpump1COP = extractUInt16(raw, 13, (short) 0); - return block; - } -} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatpumpBlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatpumpBlockParser.java new file mode 100644 index 0000000000000..b7a7929470521 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatpumpBlockParser.java @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2010-2024 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.lambda.internal.parser; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.modbus.lambda.internal.dto.HeatpumpBlock; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Parses inlambda modbus data into a Heatpump Block + * + * @author Paul Frank - Initial contribution + * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus + * + */ +@NonNullByDefault +public class HeatpumpBlockParser extends AbstractBaseParser { + private final Logger logger = LoggerFactory.getLogger(HeatpumpBlockParser.class); + + public HeatpumpBlock parse(ModbusRegisterArray raw) { + HeatpumpBlock block = new HeatpumpBlock(); + block.heatpumpErrorState = extractUInt16(raw, 0, (short) 0); + block.heatpumpErrorNumber = extractInt16(raw, 1, (short) 0); + block.heatpumpState = extractUInt16(raw, 2, (short) 0); + block.heatpumpOperatingState = extractUInt16(raw, 3, (short) 0); + block.heatpumpTFlow = extractInt16(raw, 4, (short) 0); + block.heatpumpTReturn = extractInt16(raw, 5, (short) 0); + block.heatpumpVolSink = extractInt16(raw, 6, (short) 0); + block.heatpumpTEQin = extractInt16(raw, 7, (short) 0); + block.heatpumpTEQout = extractInt16(raw, 8, (short) 0); + block.heatpumpVolSource = extractInt16(raw, 9, (short) 0); + block.heatpumpCompressorRating = extractUInt16(raw, 10, (short) 0); + block.heatpumpQpHeating = extractInt16(raw, 11, (short) 0); + block.heatpumpFIPowerConsumption = extractInt16(raw, 12, (short) 0); + block.heatpumpCOP = extractInt16(raw, 13, (short) 0); + block.heatpumpVdAE = extractInt32(raw, 20, (long) 0); + block.heatpumpVdAQ = extractInt32(raw, 22, (long) 0); + return block; + } +} diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Buffer1MtBlockParser.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatpumpReg50BlockParser.java similarity index 66% rename from bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Buffer1MtBlockParser.java rename to bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatpumpReg50BlockParser.java index 7fbd7c672752b..9aab0b0ca212c 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/Buffer1MtBlockParser.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/parser/HeatpumpReg50BlockParser.java @@ -13,22 +13,22 @@ package org.openhab.binding.modbus.lambda.internal.parser; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.binding.modbus.lambda.internal.dto.Buffer1MtBlock; +import org.openhab.binding.modbus.lambda.internal.dto.HeatpumpReg50Block; import org.openhab.core.io.transport.modbus.ModbusRegisterArray; /** - * Parses lambda modbus data into an Buffer1Mt Block - + * Parses inlambda modbus data into a HeatpumpReg50 Block * * @author Paul Frank - Initial contribution * @author Christian Koch - modified for lambda heat pump based on stiebeleltron binding for modbus * */ @NonNullByDefault -public class Buffer1MtBlockParser extends AbstractBaseParser { +public class HeatpumpReg50BlockParser extends AbstractBaseParser { - public Buffer1MtBlock parse(ModbusRegisterArray raw) { - Buffer1MtBlock block = new Buffer1MtBlock(); - block.buffer1MaximumBufferTemperature = extractUInt16(raw, 0, (short) 0); + public HeatpumpReg50Block parse(ModbusRegisterArray raw) { + HeatpumpReg50Block block = new HeatpumpReg50Block(); + block.heatpumpSetErrorQuit = extractInt16(raw, 0, (short) 0); return block; } } diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/config/config-descriptions.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/config/config-descriptions.xml index b11bf549acc02..c6b9719a21393 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/config/config-descriptions.xml +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/config/config-descriptions.xml @@ -4,17 +4,17 @@ xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0" xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0 https://openhab.org/schemas/config-description-1.0.0.xsd"> - + - - - Poll interval in seconds. Use zero to disable automatic polling. - 20 + + + Refresh interval in seconds. Use zero to disable automatic polling. + 30 s - + 3 Number of tries when reading data, if some of the reading fail. For single try, enter 1. true @@ -22,4 +22,101 @@ + + + + + Refresh interval in seconds. Use zero to disable automatic polling. + 30 + s + + + + + 3 + Number of tries when reading data, if some of the reading fail. For single try, enter 1. + true + + + + + See Lambda Modbus description + 0 + + + + + + + + + + Refresh interval in seconds. Use zero to disable automatic polling. + 30 + s + + + + + 3 + Number of tries when reading data, if some of the reading fail. For single try, enter 1. + true + + + + + See Lambda Modbus description + 0 + + + + + + + + + Refresh interval in seconds. Use zero to disable automatic polling. + 30 + s + + + + + 3 + Number of tries when reading data, if some of the reading fail. For single try, enter 1. + true + + + + + See Lambda Modbus description + 0 + + + + + + + + + Refresh interval in seconds. Use zero to disable automatic polling. + 30 + s + + + + + 3 + Number of tries when reading data, if some of the reading fail. For single try, enter 1. + true + + + + + See Lambda Modbus description + 0 + + + + diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/i18n/lambda.properties b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/i18n/lambda.properties index ef59715fe63c7..ebf35412309a2 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/i18n/lambda.properties +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/i18n/lambda.properties @@ -1,23 +1,56 @@ +# add-on + +addon.modbus.lambda.name = Lambda Heat Pump Binding +addon.modbus.lambda.description = The Lambda Heat Pump binding supports the different parts of a Lambda Heat Pump heating. + # thing types -thing-type.modbus.lambdahp.label = Lambda Heat Pump -thing-type.modbus.lambdahp.description = Lambda Heat Pump connected through modbus +thing-type.modbus.lambda-general.label = Lambda General Sections +thing-type.modbus.lambda-general.description = Provides Channels of the General Sections +thing-type.modbus.lambda-heatpump.label = Lambda Heatpump +thing-type.modbus.lambda-heatpump.description = Provides Channels of a Heatpump +thing-type.modbus.lambda-boiler.label = Lambda Boiler +thing-type.modbus.lambda-boiler.description = Provides Channels of a Boiler +thing-type.modbus.lambda-buffer.label = Lambda Buffer +thing-type.modbus.lambda-buffer.description = Provides Channels of a Buffer +thing-type.modbus.lambda-heatingcircuit.label = Lambda Heating Circuit +thing-type.modbus.lambda-heatingcircuit.description = Provides Channels of a Heating Circuit # thing types config -thing-type.config.lambda.modbusconfig.maxTries.label = Maximum Tries When Reading -thing-type.config.lambda.modbusconfig.maxTries.description = Number of tries when reading data, if some of the reading fail. For single try, enter 1. -thing-type.config.lambda.modbusconfig.refresh.label = Polling Interval -thing-type.config.lambda.modbusconfig.refresh.description = Poll interval in seconds. Use zero to disable automatic polling. +thing-type.config.lambda-general.modbusconfig.maxTries.label = Maximum Tries When Reading +thing-type.config.lambda-general.modbusconfig.maxTries.description = Number of tries when reading data, if some of the reading fail. For single try, enter 1. +thing-type.config.lambda-general.modbusconfig.refresh.label = Refresh Interval +thing-type.config.lambda-general.modbusconfig.refresh.description = Refresh interval in seconds. Use zero to disable automatic polling. + +thing-type.config.lambda-boiler.modbusconfig.maxTries.label = Maximum Tries When Reading +thing-type.config.lambda-boiler.modbusconfig.maxTries.description = Number of tries when reading data, if some of the reading fail. For single try, enter 1. +thing-type.config.lambda-boiler.modbusconfig.refresh.label = Refresh Interval +thing-type.config.lambda-boiler.modbusconfig.refresh.description = Refresh interval in seconds. Use zero to disable automatic polling.thing-type.config.lambda-general.modbusconfig.maxTries.label = Maximum Tries When Reading + +thing-type.config.lambda-buffer.modbusconfig.maxTries.label = Maximum Tries When Reading +thing-type.config.lambda-buffer.modbusconfig.maxTries.description = Number of tries when reading data, if some of the reading fail. For single try, enter 1. +thing-type.config.lambda-buffer.modbusconfig.refresh.label = Refresh Interval +thing-type.config.lambda-buffer.modbusconfig.refresh.description = Refresh interval in seconds. Use zero to disable automatic polling.thing-type.config.lambda-boiler.baseadress.label = BaseAdress of boiler + +thing-type.config.lambda-heatpump.modbusconfig.maxTries.label = Maximum Tries When Reading +thing-type.config.lambda-heatpump.modbusconfig.maxTries.description = Number of tries when reading data, if some of the reading fail. For single try, enter 1. +thing-type.config.lambda-heatpump.modbusconfig.refresh.label = Refresh Interval +thing-type.config.lambda-heatpump.modbusconfig.refresh.description = Refresh interval in seconds. Use zero to disable automatic polling.thing-type.config.lambda-heatingcircuit.baseadress.label = BaseAdress of Heating Circuit + +thing-type.config.lambda-heatingcircuit.modbusconfig.maxTries.label = Maximum Tries When Reading +thing-type.config.lambda-heatingcircuit.modbusconfig.maxTries.description = Number of tries when reading data, if some of the reading fail. For single try, enter 1. +thing-type.config.lambda-heatingcircuit.modbusconfig.refresh.label = Refresh Interval +thing-type.config.lambda-heatingcircuit.modbusconfig.refresh.description = Refresh interval in seconds. Use zero to disable automatic polling.thing-type.config.lambda-heatingcircuit.baseadress.label = BaseAdress of Heating Circuit # channel group types -channel-group-type.modbus.general-ambient.label = General Ambient Group -channel-group-type.modbus.general-emanager.label = General E-Manager Group -channel-group-type.modbus.heatpump1.label = Heat Pump 1 Group -channel-group-type.modbus.boiler1.label = Boiler 1 Group -channel-group-type.modbus.buffer1.label = Buffer 1 Group -channel-group-type.modbus.heatingcircuit1.label = Heating Circuit 1 Group +channel-group-type.modbus.ambient-type.label = General Ambient Group +channel-group-type.modbus.emanager-type.label = General E-Manager Group +channel-group-type.modbus.heatpump-type.label = Heatpump Group +channel-group-type.modbus.boiler-type.label = Boiler Group +channel-group-type.modbus.buffer-type.label = Buffer Group +channel-group-type.modbus.heatingcircuit-type.label = Heating Circuit Group # channel types @@ -33,52 +66,51 @@ channel-type.modbus.emanager-error-number-type.label = E-Manager Error Number channel-type.modbus.emanager-operating-state-type.label = E-Manager Operating State channel-type.modbus.actual-power-type.label = Actual Power (input or excess) channel-type.modbus.actual-power-consumption-type.label = Actual Power Consumption - -# Heat Pump 1 - -channel-type.modbus.heatpump1-error-state-type.label = Heat Pump 1 Error State -channel-type.modbus.heatpump1-error-number-type.label = Heat Pump 1 Error Number -channel-type.modbus.heatpump1-state-type.label = Heat Pump 1 State -channel-type.modbus.heatpump1-operating-state-type.label = Heat Pump 1 Operating State -channel-type.modbus.heatpump1-t-flow-type.label = Heat Pump 1 T-Flow -channel-type.modbus.heatpump1-t-return-type.label = Heat Pump 1 T-Return -channel-type.modbus.heatpump1-vol-sink-type.label = Heat Pump 1 Volume flow heat sink -channel-type.modbus.heatpump1-t-eqin-type.label = Heat Pump 1 Energy source inlet temperature -channel-type.modbus.heatpump1-t-eqout-type.label = Heat Pump 1 Energy source outlet temperature -channel-type.modbus.heatpump1-vol-source-type.label = Heat Pump 1 Volume flow energy source -channel-type.modbus.heatpump1-compressor-rating-type.label = Heat Pump 1 Compressor unit rating -channel-type.modbus.heatpump1-qp-heating-type.label = Heat Pump 1 Actual heating capacity -channel-type.modbus.heatpump1-fi-power-consumption-type.label = Heat Pump 1 Frequency inverter actual power consumption -channel-type.modbus.heatpump1-cop-type.label = Heat Pump 1 COP -channel-type.modbus.heatpump1-set-error-quit.label = Heat Pump 1 Set Error Quit - - -# Boiler 1 -channel-type.modbus.boiler1-error-number-type.label = Boiler 1 Error Number -channel-type.modbus.boiler1-operating-state-type.label = Boiler 1 Operating State -channel-type.modbus.boiler1-actual-high-temperature-type.label = Boiler 1 Actual High Temperature -channel-type.modbus.boiler1-actual-low-temperature-type.label = Boiler 1 Actual Low Temperature - -channel-type.modbus.boiler1-maximum-boiler-temperature-type.label = Boiler 1 Maximum Temperature - -# Buffer 1 -channel-type.modbus.buffer1-error-number-type.label = Buffer 1 Error Number -channel-type.modbus.buffer1-operating-state-type.label = Buffer 1 Operating State -channel-type.modbus.buffer1-actual-high-temperature-type.label = Buffer 1 Actual High Temperature -channel-type.modbus.buffer1-actual-low-temperature-type.label = Buffer 1 Actual Low Temperature - -channel-type.modbus.buffer1-maximum-buffer-temperature-type.label = Buffer 1 Maximum Temperature - -# Heating Circuit 1 -channel-type.modbus.heatingcircuit1-error-number-type.label = Heating circuit 1 Error Number; -channel-type.modbus.heatingcircuit1-operating-state-type.label = Heating circuit 1 Operating State; -channel-type.modbus.heatingcircuit1-flow-line-temperature-type.label = Heating circuit 1 Flow Line Temperature; -channel-type.modbus.heatingcircuit1-return-line-temperature-type.label = Heating circuit 1 Return Line Temperature; -channel-type.modbus.heatingcircuit1-room-device-temperature-type.label = Heating circuit 1 Room Device Temperature; -channel-type.modbus.heatingcircuit1-setpoint-flow-line-temperature-type.label = Heating circuit Setpoint Flow Line Temperature; -channel-type.modbus.heatingcircuit1-operating-mode-type.label = Heating circuit 1 Operating Mode; - -channel-type.modbus.heatingcircuit1-offset-flow-line-temperature-type.label = Heating circuit 1 Offset Flow Line Temperature; -channel-type.modbus.heatingcircuit1-room-heating-temperature-type.label = Heating circuit 1 Room Heating Temperature; -channel-type.modbus.heatingcircuit1-room-cooling-temperature-type.label = Heating circuit 1 Room Cooling Temperature; +channel-type.modbus.power-consumption-setpoint-type.label = Power Consumption setpoint as sum of all heat pumps + +# Heat Pump + +channel-type.modbus.heatpump-error-state-type.label = Heatpump Error State +channel-type.modbus.heatpump-error-number-type.label = Heatpump Error Number +channel-type.modbus.heatpump-state-type.label = Heatpump State +channel-type.modbus.heatpump-operating-state-type.label = Heatpump Operating State +channel-type.modbus.heatpump-t-flow-type.label = Heatpump T-Flow +channel-type.modbus.heatpump-t-return-type.label = Heatpump T-Return +channel-type.modbus.heatpump-vol-sink-type.label = Heatpump Volume flow heat sink +channel-type.modbus.heatpump-t-eqin-type.label = Heatpump Energy source inlet temperature +channel-type.modbus.heatpump-t-eqout-type.label = Heatpump Energy source outlet temperature +channel-type.modbus.heatpump-vol-source-type.label = Heatpump Volume flow energy source +channel-type.modbus.heatpump-compressor-rating-type.label = Heatpump Compressor unit rating +channel-type.modbus.heatpump-qp-heating-type.label = Heatpump Actual heating capacity +channel-type.modbus.heatpump-fi-power-consumption-type.label = Heatpump Frequency inverter actual power consumption +channel-type.modbus.heatpump-cop-type.label = Heatpump COP +channel-type.modbus.heatpump-vdae-type.label = Heatpump VdA E +channel-type.modbus.heatpump-vdaq-type.label = Heatpump VdA Q +channel-type.modbus.heatpump-set-error-quit.label = Heatpump Set Error Quit + +# Boiler +channel-type.modbus.boiler-error-number-type.label = Boiler Error Number +channel-type.modbus.boiler-operating-state-type.label = Boiler Operating State +channel-type.modbus.boiler-actual-high-temperature-type.label = Boiler Actual High Temperature +channel-type.modbus.boiler-actual-low-temperature-type.label = Boiler Actual Low Temperature +channel-type.modbus.boiler-maximum-boiler-temperature-type.label = Boiler Maximum Temperature + +# Buffer +channel-type.modbus.buffer-error-number-type.label = Buffer Error Number +channel-type.modbus.buffer-operating-state-type.label = Buffer Operating State +channel-type.modbus.buffer-actual-high-temperature-type.label = Buffer Actual High Temperature +channel-type.modbus.buffer-actual-low-temperature-type.label = Buffer Actual Low Temperature +channel-type.modbus.buffer-maximum-buffer-temperature-type.label = Buffer Maximum Temperature + +# Heating Circuit +channel-type.modbus.heatingcircuit-error-number-type.label = Heating circuit Error Number; +channel-type.modbus.heatingcircuit-operating-state-type.label = Heating circuit Operating State; +channel-type.modbus.heatingcircuit-flow-line-temperature-type.label = Heating circuit Flow Line Temperature; +channel-type.modbus.heatingcircuit-return-line-temperature-type.label = Heating circuit Return Line Temperature; +channel-type.modbus.heatingcircuit-room-device-temperature-type.label = Heating circuit Room Device Temperature; +channel-type.modbus.heatingcircuit-setpoint-flow-line-temperature-type.label = Heating circuit Setpoint Flow Line Temperature; +channel-type.modbus.heatingcircuit-operating-mode-type.label = Heating circuit Operating Mode; +channel-type.modbus.heatingcircuit-offset-flow-line-temperature-type.label = Heating circuit Offset Flow Line Temperature; +channel-type.modbus.heatingcircuit-room-heating-temperature-type.label = Heating circuit Room Heating Temperature; +channel-type.modbus.heatingcircuit-room-cooling-temperature-type.label = Heating circuit Room Cooling Temperature; diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/boiler-channel-group-types.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/boiler-channel-group-types.xml new file mode 100644 index 0000000000000..4378677653966 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/boiler-channel-group-types.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/boiler-channel-types.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/boiler-channel-types.xml new file mode 100644 index 0000000000000..0d2848813d6be --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/boiler-channel-types.xml @@ -0,0 +1,57 @@ + + + + + Number + + + + + + + + + + Number + + + + + + + + + + + + + + + + + + + + + + Number:Temperature + + + + + + Number:Temperature + + + + + + Number:Temperature + + + + + diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/boiler-thing-types.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/boiler-thing-types.xml new file mode 100644 index 0000000000000..1e1f1f936b852 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/boiler-thing-types.xml @@ -0,0 +1,24 @@ + + + + + + + + + Lambda Boiler connected through modbus + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/buffer-channel-group-types.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/buffer-channel-group-types.xml new file mode 100644 index 0000000000000..6c6ffeebc4752 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/buffer-channel-group-types.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/buffer-channel-types.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/buffer-channel-types.xml new file mode 100644 index 0000000000000..72d872b1b717a --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/buffer-channel-types.xml @@ -0,0 +1,55 @@ + + + + + Number + + + + + + + + + + Number + + + + + + + + + + + + + + + + + + + Number:Temperature + + + + + + Number:Temperature + + + + + + Number:Temperature + + + + + + diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/buffer-thing-types.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/buffer-thing-types.xml new file mode 100644 index 0000000000000..97937a917c291 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/buffer-thing-types.xml @@ -0,0 +1,24 @@ + + + + + + + + + Lambda Buffer connected through modbus + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/general-channel-group-types.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/general-channel-group-types.xml new file mode 100644 index 0000000000000..bacba35f67b1e --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/general-channel-group-types.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/general-channel-types.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/general-channel-types.xml new file mode 100644 index 0000000000000..2d693a820208b --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/general-channel-types.xml @@ -0,0 +1,91 @@ + + + + + Number + + + + + + + + + + Number + + + + + + + + + + + + + Number:Temperature + + + + + + + Number:Temperature + + + + + + Number:Temperature + + + + + + Number + + + + + + + + + + Number + + + + + + + + + + + + + + Number:Power + + + + + + Number:Power + + + + + + Number:Power + + + + + diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/general-thing-types.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/general-thing-types.xml new file mode 100644 index 0000000000000..c400e8614d959 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/general-thing-types.xml @@ -0,0 +1,25 @@ + + + + + + + + + Ambient and E-Manager groups connected through modbus + + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/heatingcircuit-channel-group-types.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/heatingcircuit-channel-group-types.xml new file mode 100644 index 0000000000000..676596ec38117 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/heatingcircuit-channel-group-types.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/heatingcircuit-channel-types.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/heatingcircuit-channel-types.xml new file mode 100644 index 0000000000000..73c3baf483c86 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/heatingcircuit-channel-types.xml @@ -0,0 +1,109 @@ + + + + + + Number + + + + + + + + + + + Number + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Number:Temperature + + + + + + Number:Temperature + + + + + + Number:Temperature + + + + + + Number:Temperature + + + + + + Number + + + + + + + + + + + + + + + + + Number:Temperature + + + + + + Number:Temperature + + + + + + Number:Temperature + + + + + + diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/heatingcircuit-thing-types.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/heatingcircuit-thing-types.xml new file mode 100644 index 0000000000000..10650696d37ac --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/heatingcircuit-thing-types.xml @@ -0,0 +1,24 @@ + + + + + + + + + Lambda Heating Circuit connected through modbus + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/heatpump-channel-group-types.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/heatpump-channel-group-types.xml new file mode 100644 index 0000000000000..24731c612c735 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/heatpump-channel-group-types.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/heatpump-channel-types.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/heatpump-channel-types.xml new file mode 100644 index 0000000000000..6be3913b64021 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/heatpump-channel-types.xml @@ -0,0 +1,161 @@ + + + + + Number + + + + + + + + + + + + + + Number + + + + + + + + + + Number + + + + + + + + + + + + + + + + + + + + + + + + Number + + + + + + + + + + + + + + + + + + + + + + + + + + + + Number:Temperature + + + + + + Number:Temperature + + + + + + Number:VolumetricFlowRate + + + + + + Number:Temperature + + + + + + Number:Temperature + + + + + + Number:VolumetricFlowRate + + + + + + Number + + + + + + Number:Power + + + + + + Number:Power + + + + + + Number + + + + + + Number:Energy + + + + + + Number:Energy + + + + + + Number + + + + + diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-types.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/heatpump-thing-types.xml similarity index 55% rename from bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-types.xml rename to bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/heatpump-thing-types.xml index 5360825084ded..2c088ff1c4a16 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-types.xml +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/heatpump-thing-types.xml @@ -4,23 +4,20 @@ 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"> - + - + Lambda Heat Pump connected through modbus - - - - - - + + + - + diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-groups.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-groups.xml deleted file mode 100644 index d90f5335973f0..0000000000000 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-groups.xml +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-types.xml b/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-types.xml deleted file mode 100644 index a5072b62c3447..0000000000000 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/resources/OH-INF/thing/lambdahp-channel-types.xml +++ /dev/null @@ -1,430 +0,0 @@ - - - - - - Number - - - - - - - - - - Number - - - - - - - - - - - - - Number:Temperature - - - - - - Number:Temperature - - - - - - Number:Temperature - - - - - - Number - - - - - - - - - - Number - - - - - - - - - - - - - - Number:Power - - - - - - Number:Power - - - - - - Number:Power - - - - - - Number - - - - - - - - - - - - - - Number - - - - - - - - - - Number - - - - - - - - - - - - - - - - - - - - - - - - Number - - - - - - - - - - - - - - - - - - - - - - - - - - - - Number:Temperature - - - - - - Number:Temperature - - - - - - Number:VolumetricFlowRate - - - - - - Number:Temperature - - - - - - Number:Temperature - - - - - - Number:VolumetricFlowRate - - - - - - Number - - - - - - Number:Power - - - - - - Number:Power - - - - - - Number - - - - - - Number - - - - - - Number - - - - - - - - - - Number - - - - - - - - - - - - - - - - - - - - - - Number:Temperature - - - - - - Number:Temperature - - - - - - Number:Temperature - - - - - - Number - - - - - - - - - - Number - - - - - - - - - - - - - - - - - - - Number:Temperature - - - - - - Number:Temperature - - - - - - Number:Temperature - - - - - - Number - - - - - - - - - - - Number - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Number:Temperature - - - - - - Number:Temperature - - - - - - Number:Temperature - - - - - - Number:Temperature - - - - - - Number - - - - - - - - - - - - - - - - - Number:Temperature - - - - - - Number:Temperature - - - - - - Number:Temperature - - - - - From 3f1e7e80c6173d370b4858f4a7300395c20bbf05 Mon Sep 17 00:00:00 2001 From: Christian Koch <78686276+chilobo@users.noreply.github.com> Date: Wed, 4 Dec 2024 19:44:16 +0100 Subject: [PATCH 6/8] Version 0.4 after attempt to rebase. Signed-off-by: Christian Koch Signed-off-by: Christian Koch <78686276+chilobo@users.noreply.github.com> --- .../modbus/lambda/internal/LambdaHandlerFactory.java | 3 ++- .../modbus/lambda/internal/handler/BoilerHandler.java | 3 ++- .../modbus/lambda/internal/handler/BufferHandler.java | 3 ++- .../lambda/internal/handler/HeatingCircuitHandler.java | 6 ++++-- .../modbus/lambda/internal/handler/HeatpumpHandler.java | 3 ++- 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaHandlerFactory.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaHandlerFactory.java index c76514021225f..18e165e8d37c3 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaHandlerFactory.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/LambdaHandlerFactory.java @@ -65,7 +65,8 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { // logger.trace("LambdaHandlerFactory ThingHandler searching of {}", thingTypeUID.toString()); if (THING_TYPE_LAMBDAGENERAL.equals(thingTypeUID)) { - // logger.debug("LambdaHandlerFactory ThingHandler LAMBDAGENERAL found first place {}", thingTypeUID.toString()); + // logger.debug("LambdaHandlerFactory ThingHandler LAMBDAGENERAL found first place {}", + // thingTypeUID.toString()); return new GeneralHandler(thing); } else if (THING_TYPE_LAMBDAHEATPUMP.equals(thingTypeUID)) { diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/BoilerHandler.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/BoilerHandler.java index 1cf029751a042..ca1e9f257e434 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/BoilerHandler.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/BoilerHandler.java @@ -257,7 +257,8 @@ public void handleCommand(ChannelUID channelUID, Command command) { } } } else { - // logger.trace("Boiler: handleCommand: Es wird geschrieben, GroupID: {}, command {}", channelUID.getGroupId(), command); + // logger.trace("Boiler: handleCommand: Es wird geschrieben, GroupID: {}, command {}", + // channelUID.getGroupId(), command); try { if (GROUP_BOILER_REG50.equals(channelUID.getGroupId())) { diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/BufferHandler.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/BufferHandler.java index ab675c1b0a826..2529b36c4bee2 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/BufferHandler.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/BufferHandler.java @@ -255,7 +255,8 @@ public void handleCommand(ChannelUID channelUID, Command command) { } } } else { - // logger.trace("Buffer: handleCommand: Es wird geschrieben, GroupID: {}, command {}", channelUID.getGroupId(), command); + // logger.trace("Buffer: handleCommand: Es wird geschrieben, GroupID: {}, command {}", + // channelUID.getGroupId(), command); try { if (GROUP_BUFFER_REG50.equals(channelUID.getGroupId())) { diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/HeatingCircuitHandler.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/HeatingCircuitHandler.java index d6e5da047fc2b..9c6af5d730aff 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/HeatingCircuitHandler.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/HeatingCircuitHandler.java @@ -255,7 +255,8 @@ public void handleCommand(ChannelUID channelUID, Command command) { } } } else { - // logger.trace("HeatingCircuit: handleCommand: Es wird geschrieben, GroupID: {}, command {}", channelUID.getGroupId(), command); + // logger.trace("HeatingCircuit: handleCommand: Es wird geschrieben, GroupID: {}, command {}", + // channelUID.getGroupId(), command); try { if (GROUP_HEATINGCIRCUIT.equals(channelUID.getGroupId())) { @@ -280,7 +281,8 @@ public void handleCommand(ChannelUID channelUID, Command command) { } if (GROUP_HEATINGCIRCUIT_REG50.equals(channelUID.getGroupId())) { - // logger.trace("HeatingCircuit: im HEATINGCIRCUIT1 channelUID {} ", channelUID.getIdWithoutGroup()); + // logger.trace("HeatingCircuit: im HEATINGCIRCUIT1 channelUID {} ", + // channelUID.getIdWithoutGroup()); switch (channelUID.getIdWithoutGroup()) { diff --git a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/HeatpumpHandler.java b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/HeatpumpHandler.java index 5f676454c4ac1..8848d5bbfc52a 100644 --- a/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/HeatpumpHandler.java +++ b/bundles/org.openhab.binding.modbus.lambda/src/main/java/org/openhab/binding/modbus/lambda/internal/handler/HeatpumpHandler.java @@ -256,7 +256,8 @@ public void handleCommand(ChannelUID channelUID, Command command) { } } } else { - // logger.trace("Heatpump: handleCommand: Es wird geschrieben, GroupID: {}, command {}", channelUID.getGroupId(), command); + // logger.trace("Heatpump: handleCommand: Es wird geschrieben, GroupID: {}, command {}", + // channelUID.getGroupId(), command); try { if (GROUP_HEATPUMP_REG50.equals(channelUID.getGroupId())) { From 9dc564bf45940f8a1e8dafdd363be67926dd92bc Mon Sep 17 00:00:00 2001 From: Christian Koch <78686276+chilobo@users.noreply.github.com> Date: Thu, 5 Dec 2024 10:14:38 +0100 Subject: [PATCH 7/8] Adding lambda to openhab-addon\bundles\pom.xlm Signed-off-by: Christian Koch Signed-off-by: Christian Koch <78686276+chilobo@users.noreply.github.com> --- bundles/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/bundles/pom.xml b/bundles/pom.xml index f8e41e838d9a3..f2a775efbede7 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -267,6 +267,7 @@ org.openhab.binding.modbus org.openhab.binding.modbus.e3dc org.openhab.binding.modbus.kermi + org.openhab.binding.modbus.lambda org.openhab.binding.modbus.sbc org.openhab.binding.modbus.studer org.openhab.binding.modbus.sungrow From fa08107c9039d732e16889cd4d5ccbe3cd4999a3 Mon Sep 17 00:00:00 2001 From: Christian Koch <78686276+chilobo@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:56:34 +0100 Subject: [PATCH 8/8] Update bundles/org.openhab.binding.modbus.lambda/pom.xml Co-authored-by: Wouter Born Signed-off-by: Christian Koch <78686276+chilobo@users.noreply.github.com> --- bundles/org.openhab.binding.modbus.lambda/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.modbus.lambda/pom.xml b/bundles/org.openhab.binding.modbus.lambda/pom.xml index e2582d6419e97..992864b576b6b 100644 --- a/bundles/org.openhab.binding.modbus.lambda/pom.xml +++ b/bundles/org.openhab.binding.modbus.lambda/pom.xml @@ -6,7 +6,7 @@ org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT org.openhab.binding.modbus.lambda