[ism8] Add channel types for heat pumps (#17688)

* [ism8] Add channel types for heat pumps

Signed-off-by: Holger Friedrich <mail@holger-friedrich.de>
Signed-off-by: Ciprian Pascu <contact@ciprianpascu.ro>
This commit is contained in:
Holger Friedrich 2024-11-05 23:03:19 +01:00 committed by Ciprian Pascu
parent 9f7c7c2630
commit 2fa28a9735
9 changed files with 520 additions and 89 deletions

View File

@ -1,18 +1,21 @@
# Ism8 Binding
_This binding can receive values of the Wolf heating system._
_This binding can receive measurements from a Wolf heating system._
The ISM8 card can be placed into the Wolf heating system.
The card is usually used in combination with an object server, where the object server does forward those messages into the KNX bus system.
In case there is no need to handle the heating system values directly in the KNX system you can use this binding to monitor and control your heating system without the need to buy an object server.
The system works in a way that the ISM8 connects to a partner and sends from time to time an update. The frequency depends on the change of the values.
The card is usually used in combination with an object server, where the object server forwards those messages into the KNX bus system.
If there is no need to handle the heating system values directly in the KNX system, you can use this binding to monitor and control your heating system without the need to buy an object server.
The system works in such a way that the ISM8 connects to a partner and sends, from time to time, an update. The frequency depends on the change in values.
This binding is listening to those messages.
After the first connection there is an active command send to the ISM8 in order to receive all available data points.
The manual of the ISM8 can be downloaded from the supplier (<https://www.wolf.eu/fileadmin/Wolf_Profi/Downloads/Montage-Bedienungsanleitungen/Regelungen/Zubehoer/3064356_201611_ISM8i_Montage-u.Bedienungsanleitung.pdf>)
After the first connection, there is an active command sent to the ISM8 in order to receive all available data points.
The manual for the ISM8 can be downloaded here: (<https://oxomi.com/service/json/catalog/pdf?portal=2024876&user=&roles=&accessToken=&catalog=10572791>)
Note that there are different firmware versions of the ISM8 module.
Some data points are not available with older firmware versions.
## Supported Things
_This binding does only support one Thing - the Ism8-Device._
_This binding does only support one Thing - the ISM8-Device._
## Discovery
@ -20,18 +23,19 @@ _Auto-discovery is not supported._
## Thing Configuration
The intention was to have a generic ISM8 binding in order to offer the full flexibilty for the different heating systems.
For this reason you need to create a Thing configuration, where basically only the port is required next to the channel configuration.
The intention was to have a generic ISM8 binding in order to offer full flexibility for the different heating systems.
For this reason, you need to create a Thing configuration, where basically only the port is required next to the channel configuration.
(`Thing ism8:device:heater "Wolf Heizung" [portNumber=12004]`)
## Channels
You can use any channel supported by the ISM8 as data point. Please have a look at the official manual from Wolf.
Within this document you'll find a table containing all supported data points.
The available data points are depending on your heating system configuration.
The ISM8 does currently support 4 different devices at the same moment of time (e.g. CGB-2, CWL Excellent, Solar, ...).
You can use any channel supported by the ISM8 as a data point. Please take a look at the official manual from Wolf.
Within this document, you'll find a table containing all supported data points.
Depending on your heating system configuration, different data points are available.
The ISM8 does currently support 4 different devices at the same moment of time (e.g., CHA, CGB-2, CWL Excellent, Solar, etc.).
Once you have an overview of your heating system set you can start to create the channels accordingly.
Once you have an overview of your heating system, you can start to create the channels accordingly.
Each channel should be created in the following way:
| Type | Name | Description | Configuration |
@ -49,28 +53,33 @@ Description:
Configuration:
- id=1 - Please enter here the ID of the data point you'd like to map to this channel.
A list of the available IDs are available within the Wolf manual.
The supported IDs are depending on the firmware version of the ISM8 and the connected systems.
- type="1.001" - Please enter here the knx type of the data point.
A list of the available IDs is available within the Wolf manual.
Depending on the firmware version of the ISM8 and the connected systems, the supported IDs differ.
- type="1.001" - Please enter here the KNX type of the data point.
You can find the data type in the Wolf ISM8 document as well.
- write=true - This parameter defines if the channel is bidirectional, but the parameter is optional and by default false.
Note:
Not all available types of the ISM8 interface are fully supported, but this can be extended.
For the moment the following data types are implemented:
> Note:
Not all available data types of the ISM8 interface are fully supported.
For the moment, the following data types are implemented:
| Channel type | Datapoint type | Item type | R/W | KNX-type's |
|----------------|--------------------------------|---------------------------|-----|----------------------------|
| switch-rw | Digital DataPoint | Switch | R/W | 1.001, 1.002, 1.003, 1.009 |
| switch-r | Digital Readonly DataPoint | Switch | R | 1.001, 1.002, 1.003, 1.009 |
| percentage-rw | Percentage DataPoint | Number:Dimensionless | R/W | 5.001 |
| percentage-r | Percentage Readonly DataPoint | Number:Dimensionless | R | 5.001 |
| temperature-rw | Temperature DataPoint | Number:Temperature | R/W | 9.001,9.002 |
| temperature-r | Temperature Readonly DataPoint | Number:Temperature | R | 9.002,9.002 |
| pressure-r | Pressure Readonly DataPoint | Number:Pressure | R | 9.006 |
| flowrate-r | Flowrate Readonly DataPoint | Number:VolumetricFlowRate | R | 13.002 |
| mode-rw | Mode DataPoint | Number:Dimensionless | R/W | 20.102, 20.103, 20.105 |
| mode-r | Mode Readonly DataPoint | Number:Dimensionless | R | 20.102, 20.103, 20.105 |
| Channel type | Datapoint type | Item type | R/W | KNX-type's |
|-----------------|------------------------------------------|---------------------------|-----|----------------------------|
| switch-rw | Digital DataPoint | Switch | R/W | 1.001, 1.002, 1.003, 1.009 |
| switch-r | Digital Readonly DataPoint | Switch | R | 1.001, 1.002, 1.003, 1.009 |
| percentage-rw | Percentage DataPoint | Number:Dimensionless | R/W | 5.001 |
| percentage-r | Percentage Readonly DataPoint | Number:Dimensionless | R | 5.001 |
| number-r | Numeric Readonly DataPoint | Number:Dimensionless | R | 5.010, 7.001 |
| temperature-rw | Temperature DataPoint | Number:Temperature | R/W | 9.001,9.002 |
| temperature-r | Temperature Readonly DataPoint | Number:Temperature | R | 9.002,9.002 |
| pressure-r | Pressure Readonly DataPoint | Number:Pressure | R | 9.006 |
| flowrate-r | Flowrate Readonly DataPoint | Number:VolumetricFlowRate | R | 9.025, 13.002 |
| active-energy-r | Active Energy Readonly DataPoint | Number:Energy | R | 13.010, 13.013 |
| mode-rw | Mode DataPoint | Number:Dimensionless | R/W | 20.102, 20.103, 20.105 |
| mode-r | Mode Readonly DataPoint | Number:Dimensionless | R | 20.102, 20.103, 20.105 |
Date and Time types used by for CWL Excellent and CWL2 are currently not supported by the ISM8 add-on.
## Full Example
@ -80,28 +89,28 @@ For the moment the following data types are implemented:
Thing ism8:device:heater "Wolf Heizung" [portNumber=12004]
{
Type switch-r : DpId001 "Störung Heizgerät" [id=1, type="1.001"]
Type number-r : DpId002 "Betriebsart" [id=2, type="20.105"]
Type mode-r : DpId002 "Betriebsart" [id=2, type="20.105"]
Type percentage-r : DpId003 "Brennerleistung" [id=3, type="5.001"]
Type temperature-r : DpId004 "Kesseltemperatur" [id=4, type="9.001"]
Type temperature-r : DpId006 "Rücklauftemperatur" [id=6, type="9.001"]
Type temperature-r : DpId007 "Warmwassertemperatur" [id=7, type="9.001"]
Type temperature-r : DpId008 "Außentemperatur" [id=8, type="9.001"]
Type switch-r : DpId009 "Status Flamme" [id=9, type="1.001"]
Type temperature-r : DpId013 "Anlagendruck" [id=13, type="9.006"]
Type pressure-r : DpId013 "Anlagendruck" [id=13, type="9.006"]
Type switch-r : DpId053 "Störung Systemmodul" [id=53, type="1.001"]
Type temperature-r : DpId054 "Außentemperatur Systemmodul" [id=54, type="9.001"]
Type temperature-rw : DpId056 "Sollwert Warmwasser" [id=56, type="9.001"]
Type mode-rw : DpId057 "Betriebsart Heizkreis" [id=57, type="20.102"]
Type mode-rw : DpId058 "Betriebsart Warmwasser" [id=58, type="20.103"]
Type temperature-rw : DpId065 "Sollwertverschiebung" [id=65, type="9.002"]
Type switch-rw : DpId148 "CML Störung" [id=148, type="1.001"]
Type switch-rw : DpId148 "CWL Störung" [id=148, type="1.001"]
Type mode-rw : DpId149 "CWL Betriebsart" [id=149, type="20.102"]
Type percentage-r : DpId163 "CWL Lüftungsstufe" [id=163, type="5.001"]
Type temperature-r : DpId164 "CWL Ablufttemperatur" [id=164, type="9.001"]
Type temperature-r : DpId165 "CWL Zulufttemperatur" [id=165, type="9.001"]
Type flowrate-r : DpId166 "CWL Luftdurchsatz Zuluft" [id=166, type="13.002"]
Type flowrate-r : DpId167 "CWL Luftdurchsatz Abluft" [id=167, type="13.002"]
Type switch-r : DpId192 "CML Filterwarnung" [id=192, type="1.001"]
Type switch-r : DpId192 "CWL Filterwarnung" [id=192, type="1.001"]
}
```
@ -123,14 +132,14 @@ Number ISM_HeizungSollwertWarmwasser "Sollwert Warmwasser [%.1f °C]"
Number ISM_HeizungBetriebsartHeizkreis "Betriebsart Heizkreis" { channel="ism8:device:heater:DpId057" }
Number ISM_HeizungBetriebsartWarmwasser "Betriebsart Warmwasser" { channel="ism8:device:heater:DpId058" }
Number ISM_HeizungSollwertverschiebung "Sollwertverschiebung [%.1f °C]" { channel="ism8:device:heater:DpId065" }
Switch ISM_LueftungStoerung "CML Störung" { channel="ism8:device:heater:DpId148" }
Switch ISM_LueftungStoerung "CWL Störung" { channel="ism8:device:heater:DpId148" }
Number ISM_LueftungBetriebsart "CWL Betriebsart" { channel="ism8:device:heater:DpId149" }
Number ISM_LueftungLueftungsstufe "CWL Lüftungsstufe [%.1f %%]" { channel="ism8:device:heater:DpId163" }
Number ISM_LueftungAblufttemperatur "CWL Ablufttemperatur [%.1f °C]" { channel="ism8:device:heater:DpId164" }
Number ISM_LueftungZulufttemperatur "CWL Zulufttemperatur [%.1f °C]" { channel="ism8:device:heater:DpId165" }
Number ISM_LueftungLuftdurchsatzZuluft "CWL Luftdurchsatz Zuluft [%.1f m³/h]" { channel="ism8:device:heater:DpId166" }
Number ISM_LueftungLuftdurchsatzAbluft "CWL Luftdurchsatz Abluft [%.1f m³/h]" { channel="ism8:device:heater:DpId167" }
Switch ISM_LueftungFilterwarnung "CML Filterwarnung" { channel="ism8:device:heater:DpId192" }
Switch ISM_LueftungFilterwarnung "CWL Filterwarnung" { channel="ism8:device:heater:DpId192" }
```
### demo.sitemap

View File

@ -17,6 +17,8 @@ import java.util.Objects;
import javax.measure.Unit;
import javax.measure.quantity.Dimensionless;
import javax.measure.quantity.Energy;
import javax.measure.quantity.Power;
import javax.measure.quantity.Pressure;
import javax.measure.quantity.Temperature;
@ -57,8 +59,14 @@ public final class Ism8DomainMap {
return new QuantityType<Temperature>((Double) value, Units.KELVIN);
} else if (Units.CUBICMETRE_PER_HOUR.equals(unit)) {
return new QuantityType<VolumetricFlowRate>((Double) value, Units.CUBICMETRE_PER_HOUR);
} else if (Units.LITRE_PER_MINUTE.equals(unit)) {
return new QuantityType<VolumetricFlowRate>((Double) value, Units.LITRE_PER_MINUTE);
} else if (Units.BAR.equals(unit)) {
return new QuantityType<Pressure>((Double) value, Units.BAR);
} else if (Units.WATT.equals(unit)) {
return new QuantityType<Power>((Double) value, Units.WATT);
} else if (Units.WATT_HOUR.equals(unit)) {
return new QuantityType<Energy>((Double) value, Units.WATT_HOUR);
} else if (Units.PERCENT.equals(unit)) {
return new QuantityType<Dimensionless>((Double) value, Units.PERCENT);
} else if (Units.ONE.equals(unit)) {
@ -67,6 +75,8 @@ public final class Ism8DomainMap {
return OnOffType.from((boolean) value);
} else if (value instanceof Byte) {
return new QuantityType<Dimensionless>((byte) value, Units.ONE);
} else if (value instanceof Integer) {
return new QuantityType<Dimensionless>((int) value, Units.ONE);
}
LOGGER.debug("Failed to map DataPoint id: {} val: {}, to UoM state. Performing fallback.", dataPoint.getId(),

View File

@ -19,6 +19,7 @@ import org.eclipse.jdt.annotation.Nullable;
* The {@link DataPointFactory} creates the data points depending on the types
*
* @author Hans-Reiner Hoffmann - Initial contribution
* @author Holger Friedrich - Extend to new data types (fw 1.80 and 1.90)
*/
@NonNullByDefault
public class DataPointFactory {
@ -40,14 +41,22 @@ public class DataPointFactory {
case "5.001":
dataPoint = new DataPointScaling(id, knxType, description);
break;
case "7.001":
dataPoint = new DataPointIntegerValue(id, knxType, description);
break;
case "9.001":
case "9.002":
case "9.006":
case "9.024":
case "9.025":
dataPoint = new DataPointValue(id, knxType, description);
break;
// TODO 10.001 (Time, CWL)
// TODO 11.001 (Date, CWL)
case "13.002":
dataPoint = new DataPointLongValue(id, knxType, description);
break;
case "5.010":
case "20.102":
case "20.103":
case "20.105":

View File

@ -0,0 +1,69 @@
/**
* 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.ism8.server;
import java.nio.ByteBuffer;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link DataPointIntegerValue} is the data points for integer values
*
* @author Holger Friedrich - Initial contribution
*/
@NonNullByDefault
public class DataPointIntegerValue extends DataPointBase<@Nullable Integer> {
private final Logger logger = LoggerFactory.getLogger(DataPointIntegerValue.class);
public DataPointIntegerValue(int id, String knxDataType, String description) {
super(id, knxDataType, description);
}
@Override
public String getValueText() {
Object val = this.getValue();
return val != null ? val.toString() : "0";
}
@Override
public void processData(byte[] data) {
if (this.checkProcessData(data)) {
if (data[3] != 2 && data.length <= 5) {
logger.debug("DataPoint-ProcessData: Data size wrong for this type({}/1).", data[3]);
return;
}
int rawValue = Byte.toUnsignedInt(data[4]) * 0x100 + Byte.toUnsignedInt(data[5]);
this.setValue(rawValue);
}
}
@Override
protected byte[] convertWriteValue(Object value) {
ByteBuffer data = ByteBuffer.allocate(2);
int intVal;
try {
intVal = Integer.parseInt(value.toString());
} catch (NumberFormatException e) {
intVal = 0;
}
int val = intVal;
data.put((byte) (val & 0xFF));
val = (val & 0xFF) / 256;
data.put((byte) (val & 0xFF));
return data.array();
}
}

View File

@ -38,6 +38,14 @@ public class DataPointLongValue extends DataPointBase<@Nullable Double> {
this.setUnit(Units.CUBICMETRE_PER_HOUR);
this.factor = 0.0001f;
this.outputFormat = "%.1f";
} else if ("13.010".equals(knxDataType)) {
this.setUnit(Units.WATT_HOUR);
this.factor = 1.0f;
this.outputFormat = "%.1f";
} else if ("13.013".equals(knxDataType)) {
this.setUnit(Units.WATT_HOUR);
this.factor = 1000.0f;
this.outputFormat = "%.1f";
} else {
this.setUnit(Units.ONE);
this.factor = 1.0f;

View File

@ -47,6 +47,14 @@ public class DataPointValue extends DataPointBase<@Nullable Double> {
this.setUnit(Units.BAR);
this.factor = 0.0000001f;
this.outputFormat = "%.2f";
} else if ("9.024".equals(knxDataType)) {
this.setUnit(Units.WATT);
this.factor = 0.01f * 1000.0f;
this.outputFormat = "%.2f";
} else if ("9.025".equals(knxDataType)) {
this.setUnit(Units.LITRE_PER_MINUTE);
this.factor = 0.01f / 60.0f;
this.outputFormat = "%.2f";
}
}

View File

@ -15,46 +15,99 @@ thing-type.config.ism8.device.portNumber.description = Port number of the object
# channel types
channel-type.ism8.number-readonly.label = Value Readonly DataPoint
channel-type.ism8.number.label = Value DataPoint
channel-type.ism8.switch-readonly.label = Digital Readonly DataPoint
channel-type.ism8.switch.label = Digital DataPoint
channel-type.ism8.active-energy-r.label = Active Energy Readonly DataPoint
channel-type.ism8.flowrate-r.label = Flowrate Readonly DataPoint
channel-type.ism8.mode-r.label = Mode Readonly DataPoint
channel-type.ism8.mode-rw.label = Mode DataPoint
channel-type.ism8.number-r.label = Numeric Readonly DataPoint
channel-type.ism8.percentage-r.label = Percentage Readonly DataPoint
channel-type.ism8.percentage-rw.label = Percentage DataPoint
channel-type.ism8.power-r.label = Power Readonly DataPoint
channel-type.ism8.pressure-r.label = Pressure Readonly DataPoint
channel-type.ism8.switch-r.label = Digital Readonly DataPoint
channel-type.ism8.switch-rw.label = Digital DataPoint
channel-type.ism8.temperature-r.label = Temperature Readonly DataPoint
channel-type.ism8.temperature-rw.label = Temperature DataPoint
# channel types config
channel-type.config.ism8.number-readonly.id.label = DP ID
channel-type.config.ism8.number-readonly.id.description = Put the number of the DataPoint ID to be mapped from the heating sytem.
channel-type.config.ism8.number-readonly.type.label = Type
channel-type.config.ism8.number-readonly.type.description = Put the KNX-type of the DataPoint (e.g. DPT_Value_Temp / 9.001)
channel-type.config.ism8.number-readonly.type.option.5.001 = DPT_Scaling
channel-type.config.ism8.number-readonly.type.option.9.001 = DPT_Value_Temp
channel-type.config.ism8.number-readonly.type.option.9.002 = DPT_Value_Tempd
channel-type.config.ism8.number-readonly.type.option.9.006 = DPT_Value_Pres
channel-type.config.ism8.number-readonly.type.option.13.002 = DPT_FlowRate
channel-type.config.ism8.number-readonly.type.option.20.102 = DPT_HVACMode
channel-type.config.ism8.number-readonly.type.option.20.103 = DPT_DHWMode
channel-type.config.ism8.number-readonly.type.option.20.105 = DPT_HVACContrMode
channel-type.config.ism8.number.id.label = DP ID
channel-type.config.ism8.number.id.description = Put the number of the DataPoint ID to be mapped from the heating sytem.
channel-type.config.ism8.number.type.label = Type
channel-type.config.ism8.number.type.description = Put the KNX-type of the DataPoint (e.g. DPT_Value_Temp / 9.001)
channel-type.config.ism8.number.type.option.9.001 = DPT_Value_Temp
channel-type.config.ism8.number.type.option.20.102 = DPT_HVACMode
channel-type.config.ism8.number.type.option.20.103 = DPT_DHWMode
channel-type.config.ism8.number.type.option.20.105 = DPT_HVACContrMode
channel-type.config.ism8.switch-readonly.id.label = DP ID
channel-type.config.ism8.switch-readonly.id.description = Put the number of the DataPoint ID to be mapped from the heating sytem.
channel-type.config.ism8.switch-readonly.type.label = Type
channel-type.config.ism8.switch-readonly.type.description = Put the KNX-type of the DataPoint (e.g. DPT_Switch / 1.001)
channel-type.config.ism8.switch-readonly.type.option.1.001 = DPT_Switch
channel-type.config.ism8.switch-readonly.type.option.1.002 = DPT_Bool
channel-type.config.ism8.switch-readonly.type.option.1.003 = DPT_Enable
channel-type.config.ism8.switch-readonly.type.option.1.009 = DPT_OpenClose
channel-type.config.ism8.switch.id.label = DP ID
channel-type.config.ism8.switch.id.description = Put the number of the DataPoint ID to be mapped from the heating sytem.
channel-type.config.ism8.switch.type.label = Type
channel-type.config.ism8.switch.type.description = Put the KNX-type of the DataPoint (e.g. DPT_Switch / 1.001)
channel-type.config.ism8.switch.type.option.1.001 = DPT_Switch
channel-type.config.ism8.switch.type.option.1.002 = DPT_Bool
channel-type.config.ism8.switch.type.option.1.003 = DPT_Enable
channel-type.config.ism8.switch.type.option.1.009 = DPT_OpenClose
channel-type.config.ism8.active-energy-r.id.label = DP ID
channel-type.config.ism8.active-energy-r.id.description = Put the number of the DataPoint ID to be mapped from the heating sytem.
channel-type.config.ism8.active-energy-r.type.label = Type
channel-type.config.ism8.active-energy-r.type.description = Put the KNX-type of the DataPoint (e.g. DPT_Value_Temp / 9.001)
channel-type.config.ism8.active-energy-r.type.option.13.010 = DPT_ActiveEnergy
channel-type.config.ism8.active-energy-r.type.option.13.013 = DPT_ActiveEnergy_kWh
channel-type.config.ism8.flowrate-r.id.label = DP ID
channel-type.config.ism8.flowrate-r.id.description = Put the number of the DataPoint ID to be mapped from the heating sytem.
channel-type.config.ism8.flowrate-r.type.label = Type
channel-type.config.ism8.flowrate-r.type.description = Put the KNX-type of the DataPoint (e.g. DPT_Value_Temp / 9.001)
channel-type.config.ism8.flowrate-r.type.option.9.025 = DPT_Power
channel-type.config.ism8.flowrate-r.type.option.13.002 = DPT_FlowRate
channel-type.config.ism8.mode-r.id.label = DP ID
channel-type.config.ism8.mode-r.id.description = Put the number of the DataPoint ID to be mapped from the heating sytem.
channel-type.config.ism8.mode-r.type.label = Type
channel-type.config.ism8.mode-r.type.description = Put the KNX-type of the DataPoint (e.g. DPT_Value_Temp / 9.001)
channel-type.config.ism8.mode-r.type.option.20.102 = DPT_HVACMode
channel-type.config.ism8.mode-r.type.option.20.103 = DPT_DHWMode
channel-type.config.ism8.mode-r.type.option.20.105 = DPT_HVACContrMode
channel-type.config.ism8.mode-rw.id.label = DP ID
channel-type.config.ism8.mode-rw.id.description = Put the number of the DataPoint ID to be mapped from the heating sytem.
channel-type.config.ism8.mode-rw.type.label = Type
channel-type.config.ism8.mode-rw.type.description = Put the KNX-type of the DataPoint (e.g. DPT_Value_Temp / 9.001)
channel-type.config.ism8.mode-rw.type.option.20.102 = DPT_HVACMode
channel-type.config.ism8.mode-rw.type.option.20.103 = DPT_DHWMode
channel-type.config.ism8.mode-rw.type.option.20.105 = DPT_HVACContrMode
channel-type.config.ism8.number-r.id.label = DP ID
channel-type.config.ism8.number-r.id.description = Put the number of the DataPoint ID to be mapped from the heating sytem.
channel-type.config.ism8.number-r.type.label = Type
channel-type.config.ism8.number-r.type.description = Put the KNX-type of the DataPoint (e.g. DPT_Value_Temp / 9.001)
channel-type.config.ism8.number-r.type.option.5.010 = DPT_Value_1_Ucount
channel-type.config.ism8.number-r.type.option.7.001 = DPT_Value_2_Ucount
channel-type.config.ism8.percentage-r.id.label = DP ID
channel-type.config.ism8.percentage-r.id.description = Put the number of the DataPoint ID to be mapped from the heating sytem.
channel-type.config.ism8.percentage-r.type.label = Type
channel-type.config.ism8.percentage-r.type.description = Put the KNX-type of the DataPoint (e.g. DPT_Value_Temp / 9.001)
channel-type.config.ism8.percentage-r.type.option.5.001 = DPT_Scaling
channel-type.config.ism8.percentage-rw.id.label = DP ID
channel-type.config.ism8.percentage-rw.id.description = Put the number of the DataPoint ID to be mapped from the heating sytem.
channel-type.config.ism8.percentage-rw.type.label = Type
channel-type.config.ism8.percentage-rw.type.description = Put the KNX-type of the DataPoint (e.g. DPT_Value_Temp / 9.001)
channel-type.config.ism8.percentage-rw.type.option.5.001 = DPT_Scaling
channel-type.config.ism8.power-r.id.label = DP ID
channel-type.config.ism8.power-r.id.description = Put the number of the DataPoint ID to be mapped from the heating sytem.
channel-type.config.ism8.power-r.type.label = Type
channel-type.config.ism8.power-r.type.description = Put the KNX-type of the DataPoint (e.g. DPT_Value_Temp / 9.001)
channel-type.config.ism8.power-r.type.option.9.024 = DPT_Power
channel-type.config.ism8.pressure-r.id.label = DP ID
channel-type.config.ism8.pressure-r.id.description = Put the number of the DataPoint ID to be mapped from the heating sytem.
channel-type.config.ism8.pressure-r.type.label = Type
channel-type.config.ism8.pressure-r.type.description = Put the KNX-type of the DataPoint (e.g. DPT_Value_Temp / 9.001)
channel-type.config.ism8.pressure-r.type.option.9.006 = DPT_Value_Pres
channel-type.config.ism8.switch-r.id.label = DP ID
channel-type.config.ism8.switch-r.id.description = Put the number of the DataPoint ID to be mapped from the heating sytem.
channel-type.config.ism8.switch-r.type.label = Type
channel-type.config.ism8.switch-r.type.description = Put the KNX-type of the DataPoint (e.g. DPT_Switch / 1.001)
channel-type.config.ism8.switch-r.type.option.1.001 = DPT_Switch
channel-type.config.ism8.switch-r.type.option.1.002 = DPT_Bool
channel-type.config.ism8.switch-r.type.option.1.003 = DPT_Enable
channel-type.config.ism8.switch-r.type.option.1.009 = DPT_OpenClose
channel-type.config.ism8.switch-rw.id.label = DP ID
channel-type.config.ism8.switch-rw.id.description = Put the number of the DataPoint ID to be mapped from the heating sytem.
channel-type.config.ism8.switch-rw.type.label = Type
channel-type.config.ism8.switch-rw.type.description = Put the KNX-type of the DataPoint (e.g. DPT_Switch / 1.001)
channel-type.config.ism8.switch-rw.type.option.1.001 = DPT_Switch
channel-type.config.ism8.switch-rw.type.option.1.002 = DPT_Bool
channel-type.config.ism8.switch-rw.type.option.1.003 = DPT_Enable
channel-type.config.ism8.switch-rw.type.option.1.009 = DPT_OpenClose
channel-type.config.ism8.temperature-r.id.label = DP ID
channel-type.config.ism8.temperature-r.id.description = Put the number of the DataPoint ID to be mapped from the heating sytem.
channel-type.config.ism8.temperature-r.type.label = Type
channel-type.config.ism8.temperature-r.type.description = Put the KNX-type of the DataPoint (e.g. DPT_Value_Temp / 9.001)
channel-type.config.ism8.temperature-r.type.option.9.001 = DPT_Value_Temp
channel-type.config.ism8.temperature-r.type.option.9.002 = DPT_Value_Tempd
channel-type.config.ism8.temperature-rw.id.label = DP ID
channel-type.config.ism8.temperature-rw.id.description = Put the number of the DataPoint ID to be mapped from the heating sytem.
channel-type.config.ism8.temperature-rw.type.label = Type
channel-type.config.ism8.temperature-rw.type.description = Put the KNX-type of the DataPoint (e.g. DPT_Value_Temp / 9.001)
channel-type.config.ism8.temperature-rw.type.option.9.001 = DPT_Value_Temp
channel-type.config.ism8.temperature-rw.type.option.9.002 = DPT_Value_Tempd

View File

@ -98,6 +98,26 @@
</config-description>
</channel-type>
<channel-type id="number-r">
<item-type>Number:Dimensionless</item-type>
<label>Numeric Readonly DataPoint</label>
<state readOnly="true"/>
<config-description>
<parameter name="id" type="integer" required="true">
<label>DP ID</label>
<description>Put the number of the DataPoint ID to be mapped from the heating sytem.</description>
</parameter>
<parameter name="type" type="text" required="true">
<label>Type</label>
<description>Put the KNX-type of the DataPoint (e.g. DPT_Value_Temp / 9.001)</description>
<options>
<option value="5.010">DPT_Value_1_Ucount</option>
<option value="7.001">DPT_Value_2_Ucount</option>
</options>
</parameter>
</config-description>
</channel-type>
<channel-type id="temperature-r">
<item-type>Number:Temperature</item-type>
<label>Temperature Readonly DataPoint</label>
@ -157,6 +177,25 @@
</config-description>
</channel-type>
<channel-type id="power-r">
<item-type>Number:Power</item-type>
<label>Power Readonly DataPoint</label>
<state readOnly="true"/>
<config-description>
<parameter name="id" type="integer" required="true">
<label>DP ID</label>
<description>Put the number of the DataPoint ID to be mapped from the heating sytem.</description>
</parameter>
<parameter name="type" type="text" required="true">
<label>Type</label>
<description>Put the KNX-type of the DataPoint (e.g. DPT_Value_Temp / 9.001)</description>
<options>
<option value="9.024">DPT_Power</option>
</options>
</parameter>
</config-description>
</channel-type>
<channel-type id="flowrate-r">
<item-type>Number:VolumetricFlowRate</item-type>
<label>Flowrate Readonly DataPoint</label>
@ -170,12 +209,33 @@
<label>Type</label>
<description>Put the KNX-type of the DataPoint (e.g. DPT_Value_Temp / 9.001)</description>
<options>
<option value="9.025">DPT_Power</option>
<option value="13.002">DPT_FlowRate</option>
</options>
</parameter>
</config-description>
</channel-type>
<channel-type id="active-energy-r">
<item-type>Number:Energy</item-type>
<label>Active Energy Readonly DataPoint</label>
<state readOnly="true"/>
<config-description>
<parameter name="id" type="integer" required="true">
<label>DP ID</label>
<description>Put the number of the DataPoint ID to be mapped from the heating sytem.</description>
</parameter>
<parameter name="type" type="text" required="true">
<label>Type</label>
<description>Put the KNX-type of the DataPoint (e.g. DPT_Value_Temp / 9.001)</description>
<options>
<option value="13.010">DPT_ActiveEnergy</option>
<option value="13.013">DPT_ActiveEnergy_kWh</option>
</options>
</parameter>
</config-description>
</channel-type>
<channel-type id="mode-r">
<item-type>Number:Dimensionless</item-type>
<label>Mode Readonly DataPoint</label>

View File

@ -15,7 +15,7 @@ package org.openhab.binding.ism8.internal.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
import javax.measure.quantity.Dimensionless;
import javax.measure.quantity.Temperature;
import javax.measure.quantity.Pressure;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.BeforeEach;
@ -24,6 +24,8 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.openhab.binding.ism8.server.DataPointBool;
import org.openhab.binding.ism8.server.DataPointByteValue;
import org.openhab.binding.ism8.server.DataPointIntegerValue;
import org.openhab.binding.ism8.server.DataPointLongValue;
import org.openhab.binding.ism8.server.DataPointScaling;
import org.openhab.binding.ism8.server.DataPointValue;
import org.openhab.binding.ism8.server.IDataPoint;
@ -35,6 +37,8 @@ import org.openhab.core.library.unit.Units;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.openhab.core.util.HexUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
@ -44,6 +48,7 @@ import org.openhab.core.util.HexUtils;
@ExtendWith(MockitoExtension.class)
@NonNullByDefault
public class Ism8DomainMapTest {
private static final Logger LOGGER = LoggerFactory.getLogger(Ism8DomainMap.class);
@BeforeEach
public void initialize() {
@ -105,29 +110,229 @@ public class Ism8DomainMapTest {
assertEquals("0620F080001504000000F0C1000300010003000121", HexUtils.bytesToHex(result));
}
@Test
public void mapDataPointBoolToOHState() {
{
// arrange
IDataPoint dataPoint = new DataPointBool(1, "1.001", "Datapoint_1.001");
dataPoint.processData(HexUtils.hexToBytes("0001030200"));
// act
State result = Ism8DomainMap.toOpenHABState(dataPoint);
// assert
assertEquals(OnOffType.from(false), result);
}
{
// arrange
IDataPoint dataPoint = new DataPointBool(1, "1.001", "Datapoint_1.001");
dataPoint.processData(HexUtils.hexToBytes("0001030201"));
// act
State result = Ism8DomainMap.toOpenHABState(dataPoint);
// assert
assertEquals(OnOffType.from(true), result);
}
{
// arrange
IDataPoint dataPoint = new DataPointBool(1, "1.002", "Datapoint_1.002");
dataPoint.processData(HexUtils.hexToBytes("0001030201"));
// act
State result = Ism8DomainMap.toOpenHABState(dataPoint);
// assert
assertEquals(OnOffType.from(true), result);
}
{
// arrange
IDataPoint dataPoint = new DataPointBool(1, "1.003", "Datapoint_1.003");
dataPoint.processData(HexUtils.hexToBytes("0001030201"));
// act
State result = Ism8DomainMap.toOpenHABState(dataPoint);
// assert
assertEquals(OnOffType.from(true), result);
}
{
// arrange
IDataPoint dataPoint = new DataPointBool(1, "1.009", "Datapoint_1.009");
dataPoint.processData(HexUtils.hexToBytes("0001030201"));
// act
State result = Ism8DomainMap.toOpenHABState(dataPoint);
// assert
assertEquals(OnOffType.from(true), result);
// TODO: check if OpenClosedType is appropriate
// assertEquals(OpenClosedType.valueOf("OPEN"), result);
}
}
@Test
public void mapDataPointValueToOHState() {
{
// arrange
IDataPoint dataPoint = new DataPointValue(4, "9.001", "Datapoint_9.001");
dataPoint.processData(HexUtils.hexToBytes("000403020FE9"));
// act
State result = Ism8DomainMap.toOpenHABState(dataPoint);
// assert
assertEquals(new QuantityType<>("40.49999909475446 °C"), result);
}
{
// arrange
IDataPoint dataPoint = new DataPointValue(4, "9.002", "Datapoint_9.002");
dataPoint.processData(HexUtils.hexToBytes("000403020FE9"));
// act
State result = Ism8DomainMap.toOpenHABState(dataPoint);
// assert
assertEquals(new QuantityType<>("40.49999909475446 K"), result);
}
{
// arrange
IDataPoint dataPoint = new DataPointValue(4, "9.006", "Datapoint_9.006");
dataPoint.processData(HexUtils.hexToBytes("000403020FE9"));
// act
State result = Ism8DomainMap.toOpenHABState(dataPoint);
// assert
// original unit is Pa, will be bar in OH -> divide by 10000, i.e. expect 0.0004049999909475446 bar
// text ctor cannot be used, as it will result in scientific notation ..E-4,
// double ctor returns a slightly different number caused by internal representation
assertEquals(new QuantityType<Pressure>(0.00040500000473286946, Units.BAR), result);
}
{
// arrange
IDataPoint dataPoint = new DataPointValue(4, "9.024", "Datapoint_9.024");
dataPoint.processData(HexUtils.hexToBytes("000403020FE9"));
// act
State result = Ism8DomainMap.toOpenHABState(dataPoint);
// assert
// original unit is kW
assertEquals(new QuantityType<>("40500 W"), result);
}
{
// arrange
IDataPoint dataPoint = new DataPointValue(4, "9.025", "Datapoint_9.025");
dataPoint.processData(HexUtils.hexToBytes("000403020FE9"));
// act
State result = Ism8DomainMap.toOpenHABState(dataPoint);
// assert
// original unit is l/h, i.e. divide by 60 to get l/min
assertEquals(new QuantityType<>("0.6749999927706085 l/min"), result);
}
}
@Test
public void mapDataPointByteValueToOHState() {
// arrange
IDataPoint dataPoint = new DataPointValue(4, "9.001", "Datapoint_9.001");
dataPoint.processData(HexUtils.hexToBytes("000403020FE9"));
IDataPoint dataPoint = new DataPointByteValue(5, "5.010", "Datapoint_5.010");
dataPoint.processData(HexUtils.hexToBytes("0005030243"));
// act
State result = Ism8DomainMap.toOpenHABState(dataPoint);
// assert
assertEquals(new QuantityType<Temperature>(40.49999909475446, SIUnits.CELSIUS), result);
assertEquals(new QuantityType<Dimensionless>(0x43, Units.ONE), result);
}
@Test
public void mapDataPointIntegerValueToOHState() {
// arrange
IDataPoint dataPoint = new DataPointIntegerValue(7, "7.001", "Datapoint_7.001");
dataPoint.processData(HexUtils.hexToBytes("000703024321"));
// act
State result = Ism8DomainMap.toOpenHABState(dataPoint);
// assert
assertEquals(new QuantityType<Dimensionless>(0x4321, Units.ONE), result);
}
@Test
public void mapDataPointLongValueToOHState() {
{
// arrange
IDataPoint dataPoint = new DataPointLongValue(13, "13.002", "Datapoint_13.002");
dataPoint.processData(HexUtils.hexToBytes("000D03027FFFFFFF"));
// act
State result = Ism8DomainMap.toOpenHABState(dataPoint);
// assert
// value encoded above is max value 2147483647, scaling for 13.002 is 0.0001, unit m^3/h
// -> expected is 214748.3647 m^3/h
assertEquals(new QuantityType<>("214748.359275 m³/h"), result);
}
{
// arrange
IDataPoint dataPoint = new DataPointLongValue(13, "13.010", "Datapoint_13.010");
dataPoint.processData(HexUtils.hexToBytes("000D03027FFFFFFF"));
// act
State result = Ism8DomainMap.toOpenHABState(dataPoint);
// assert
// value encoded above is max value 2147483647
assertEquals(new QuantityType<>("2147483647 Wh"), result);
}
{
// arrange
IDataPoint dataPoint = new DataPointLongValue(13, "13.013", "Datapoint_13.013");
dataPoint.processData(HexUtils.hexToBytes("000D03027FFFFFFF"));
// act
State result = Ism8DomainMap.toOpenHABState(dataPoint);
// assert
// value encoded above is max value 2147483647
assertEquals(new QuantityType<>("2147483647 kWh"), result);
}
}
@Test
public void mapDataPointLongToOHState() {
// arrange
IDataPoint dataPoint = new DataPointByteValue(2, "20.102", "Datapoint_20.102");
dataPoint.processData(HexUtils.hexToBytes("0002030101"));
{ // arrange
IDataPoint dataPoint = new DataPointByteValue(20, "20.102", "Datapoint_20.102");
dataPoint.processData(HexUtils.hexToBytes("0014030101"));
// act
State result = Ism8DomainMap.toOpenHABState(dataPoint);
// act
State result = Ism8DomainMap.toOpenHABState(dataPoint);
// assert
assertEquals(new QuantityType<Dimensionless>(1, Units.ONE), result);
// assert
assertEquals(new QuantityType<Dimensionless>(1, Units.ONE), result);
}
{ // arrange
IDataPoint dataPoint = new DataPointByteValue(20, "20.103", "Datapoint_20.103");
dataPoint.processData(HexUtils.hexToBytes("0014030101"));
// act
State result = Ism8DomainMap.toOpenHABState(dataPoint);
// assert
assertEquals(new QuantityType<Dimensionless>(1, Units.ONE), result);
}
{ // arrange
IDataPoint dataPoint = new DataPointByteValue(20, "20.105", "Datapoint_20.105");
dataPoint.processData(HexUtils.hexToBytes("0014030101"));
// act
State result = Ism8DomainMap.toOpenHABState(dataPoint);
// assert
assertEquals(new QuantityType<Dimensionless>(1, Units.ONE), result);
}
}
}