added migrated 2.x add-ons

Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
Kai Kreuzer
2020-09-21 01:58:32 +02:00
parent bbf1a7fd29
commit 6df6783b60
11662 changed files with 1302875 additions and 11 deletions

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.ism8-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
<feature name="openhab-binding-ism8" description="ism8 Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.ism8/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,44 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ism8.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link ism8BindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Hans-Reiner Hoffmann - Initial contribution
*/
@NonNullByDefault
public class Ism8BindingConstants {
// Binding ID
private static final String BINDING_ID = "ism8";
// List of all Thing Type UIDs
/**
* Defines the thing type UID
*
*/
public static final ThingTypeUID THING_TYPE_DEVICE = new ThingTypeUID(BINDING_ID, "device");
// Thing Configuration parameters
/**
* The port number configuration parameter
*
*/
public static final String PORT_NUMBER = "portNumber";
}

View File

@@ -0,0 +1,33 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ism8.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link ism8Configuration} class contains fields mapping thing configuration parameters.
*
* @author Hans-Reiner Hoffmann - Initial contribution
*/
@NonNullByDefault
public class Ism8Configuration {
private int portNumber;
/**
* Gets the port number for the ISM8.
*
*/
public int getPortNumber() {
return portNumber;
}
}

View File

@@ -0,0 +1,158 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ism8.internal;
import java.io.IOException;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.ism8.server.DataPointChangedEvent;
import org.openhab.binding.ism8.server.IDataPoint;
import org.openhab.binding.ism8.server.IDataPointChangeListener;
import org.openhab.binding.ism8.server.Server;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link Ism8Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Hans-Reiner Hoffmann - Initial contribution
*/
@NonNullByDefault
public class Ism8Handler extends BaseThingHandler implements IDataPointChangeListener {
private final Logger logger = LoggerFactory.getLogger(Ism8Handler.class);
private @Nullable Ism8Configuration config;
private @Nullable Server server;
public Ism8Handler(Thing thing) {
super(thing);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
this.logger.debug("Ism8: Handle command = {} {}", channelUID.getId(), command);
Channel channel = getThing().getChannel(channelUID);
Server svr = this.server;
if (channel != null && svr != null) {
if (channel.getConfiguration().containsKey("id")) {
IDataPoint dataPoint = null;
try {
int id = Integer.parseInt(channel.getConfiguration().get("id").toString());
this.logger.debug("Channel '{}' writting into ID '{}'", channel.getUID().getId(), id);
this.updateState(channelUID, new QuantityType<>(command.toString()));
dataPoint = svr.getDataPoint(id);
} catch (NumberFormatException e) {
this.logger.debug("Updating State of ISM DataPoint '{}' failed. '{}'", channel.getConfiguration(),
e.getMessage());
}
if (dataPoint != null) {
try {
svr.sendData(dataPoint.createWriteData(command));
} catch (IOException e) {
this.logger.debug("Writting to ISM DataPoint '{}' failed. '{}'", dataPoint.getId(),
e.getMessage());
}
}
}
}
}
@Override
public void dispose() {
Server svr = this.server;
if (svr != null) {
svr.stopServerThread();
}
}
@Override
public void initialize() {
this.config = getConfigAs(Ism8Configuration.class);
Ism8Configuration cfg = this.config;
final String uid = this.getThing().getUID().getAsString();
Server svr = new Server(cfg.getPortNumber(), uid);
for (Channel channel : getThing().getChannels()) {
if (channel.getConfiguration().containsKey("id") && channel.getConfiguration().containsKey("type")) {
try {
int id = Integer.parseInt(channel.getConfiguration().get("id").toString());
String type = channel.getConfiguration().get("type").toString();
String description = channel.getLabel();
if (type != null && description != null) {
svr.addDataPoint(id, type, description);
}
} catch (NumberFormatException e) {
this.logger.warn(
"Ism8 initialize: ID couldn't be converted correctly. Check the configuration of channel {}. Cfg={}",
channel.getLabel(), channel.getConfiguration());
}
} else {
this.logger.debug("Ism8: ID or type missing - Channel={} Cfg={}", channel.getLabel(),
channel.getConfiguration());
}
this.logger.debug("Ism8: Channel={}", channel.getConfiguration().toString());
}
this.updateStatus(ThingStatus.UNKNOWN);
svr.addDataPointChangeListener(this);
scheduler.execute(svr::start);
this.server = svr;
}
@Override
public void dataPointChanged(@Nullable DataPointChangedEvent e) {
if (e != null) {
IDataPoint dataPoint = e.getDataPoint();
if (dataPoint != null) {
this.logger.debug("Ism8: dataPointChanged {}", dataPoint.toString());
this.updateDataPoint(dataPoint);
}
}
}
@Override
public void connectionStatusChanged(ThingStatus status) {
this.updateStatus(status);
}
private void updateDataPoint(IDataPoint dataPoint) {
this.updateStatus(ThingStatus.ONLINE);
for (Channel channel : getThing().getChannels()) {
if (channel.getConfiguration().containsKey("id")) {
try {
int id = Integer.parseInt(channel.getConfiguration().get("id").toString());
if (id == dataPoint.getId()) {
this.logger.debug("Ism8 updateDataPoint ID:{} {}", dataPoint.getId(), dataPoint.getValueText());
Object val = dataPoint.getValueObject();
if (val != null) {
updateState(channel.getUID(), new QuantityType<>(val.toString()));
}
}
} catch (NumberFormatException e) {
this.logger.warn(
"Ism8 updateDataPoint: ID couldn't be converted correctly. Check the configuration of channel {}. {}",
channel.getLabel(), e.getMessage());
}
}
}
}
}

View File

@@ -0,0 +1,53 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ism8.internal;
import static org.openhab.binding.ism8.internal.Ism8BindingConstants.THING_TYPE_DEVICE;
import java.util.Arrays;
import java.util.Collection;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.annotations.Component;
/**
* The {@link ism8HandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Hans-Reiner Hoffmann - Initial contribution
*/
@NonNullByDefault
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.ism8")
public class Ism8HandlerFactory extends BaseThingHandlerFactory {
public static final Collection<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Arrays.asList(THING_TYPE_DEVICE);
@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_DEVICE.equals(thingTypeUID)) {
return new Ism8Handler(thing);
}
return null;
}
}

View File

@@ -0,0 +1,159 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.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 DataPointBase} is the base class for all data points
*
* @author Hans-Reiner Hoffmann - Initial contribution
*/
@NonNullByDefault
public abstract class DataPointBase<@Nullable T> implements IDataPoint {
private final Logger logger = LoggerFactory.getLogger(DataPointBase.class);
private final int id;
private final String knxDataType;
private final String description;
private T value;
private String unit = "";
protected DataPointBase(int id, String knxDataType, String description) {
this.id = id;
this.knxDataType = knxDataType;
this.description = description;
}
@Override
public int getId() {
return this.id;
}
@Override
public String getKnxDataType() {
return this.knxDataType;
}
@Override
public String getDescription() {
return this.description;
}
/**
* Gets the value of the data-point
*
*/
public T getValue() {
return this.value;
}
/**
* Sets the value of the data-point
*
*/
public void setValue(T value) {
this.value = value;
}
@Override
@Nullable
public Object getValueObject() {
return this.value;
}
@Override
public abstract String getValueText();
@Override
public String getUnit() {
return this.unit;
}
/**
* Sets the unit of the data-point.
*
*/
public void setUnit(String value) {
this.unit = value;
}
@Override
public abstract void processData(byte[] data);
@Override
public byte[] createWriteData(Object value) {
logger.debug("Convert into byte array '{}'", value);
byte[] val = this.convertWriteValue(value);
byte length = (byte) (val.length + 20);
ByteBuffer list = ByteBuffer.allocate(length);
list.put(KnxNetFrame.KNX_HEADER);
list.put(KnxNetFrame.CONNECTION_HEADER);
list.put((byte) 0xF0); // Main Service
list.put(SubServiceType.DATAPOINT_VALUE_WRITE); // Sub Service
byte low = (byte) (this.getId() & 0xFF);
byte high = (byte) ((this.getId() & 0xFF) / 256);
list.put(high);
list.put(low); // Start DataPoint
list.put((byte) 0x00); // Amount DataPoints (high-byte)
list.put((byte) 0x01); // Amount DataPoints (low-byte)
list.put(high);
list.put(low); // Write: ID of DataPoint
list.put((byte) 0x00); // State
list.put((byte) val.length); // Length of Data
list.put(val); // Data Value
list.put(5, length);
return list.array();
}
@Override
public String toString() {
return String.format("DataPoint %d=%s", this.getId(), this.getValueText());
}
/**
* Converts the value to be written into a data array of bytes.
*
*/
protected abstract byte[] convertWriteValue(Object value);
/**
* Checks the data to be processed.
*
*/
protected boolean checkProcessData(byte[] data) {
if (data.length < 4) {
logger.debug("DataPoint-ProcessData: Data size too small ({}).", data.length);
return false;
}
int dataPointId = Byte.toUnsignedInt(data[0]) * 256 + Byte.toUnsignedInt(data[1]);
if (dataPointId != this.getId()) {
logger.debug("DataPoint-ProcessData: Data contains the wrong ID ({}/{}).", dataPointId, this.getId());
return false;
}
int length = data[3];
int expectedLength = length + 4;
if (length <= 0 && expectedLength != data.length) {
logger.debug("DataPoint-ProcessData: Data size wrong ({}/{}).", data.length, expectedLength);
return false;
}
return true;
}
}

View File

@@ -0,0 +1,65 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ism8.server;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link DataPointBool} is the data points for boolean values
*
* @author Hans-Reiner Hoffmann - Initial contribution
*/
@NonNullByDefault
public class DataPointBool extends DataPointBase<@Nullable Boolean> {
private final Logger logger = LoggerFactory.getLogger(DataPointBool.class);
public DataPointBool(int id, String knxDataType, String description) {
super(id, knxDataType, description);
}
@Override
public String getValueText() {
return this.getValue() ? "True" : "False";
}
@Override
@Nullable
public Object getValueObject() {
return this.getValue() ? "1" : "0";
}
@Override
public void processData(byte[] data) {
if (this.checkProcessData(data)) {
if (data[3] != 1 && data.length <= 4) {
logger.debug("DataPoint-ProcessData: Data size wrong for this type({}/1).", data[3]);
return;
}
this.setValue((data[4] & 0x1) > 0);
}
}
@Override
protected byte[] convertWriteValue(Object value) {
String valueText = value.toString().toLowerCase();
if (valueText.equalsIgnoreCase("true") || valueText.equalsIgnoreCase("1")) {
this.setValue(true);
return new byte[] { 0x01 };
}
this.setValue(false);
return new byte[] { 0x00 };
}
}

View File

@@ -0,0 +1,55 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ism8.server;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link DataPointByteValue} is the data points for byte values
*
* @author Hans-Reiner Hoffmann - Initial contribution
*/
@NonNullByDefault
public class DataPointByteValue extends DataPointBase<@Nullable Byte> {
private final Logger logger = LoggerFactory.getLogger(DataPointByteValue.class);
public DataPointByteValue(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] != 1 && data.length <= 4) {
logger.debug("DataPoint-ProcessData: Data size wrong for this type({}/1).", data[3]);
return;
}
this.setValue(data[4]);
}
}
@Override
protected byte[] convertWriteValue(Object value) {
this.setValue(Byte.parseByte(value.toString()));
return new byte[] { this.getValue() };
}
}

View File

@@ -0,0 +1,39 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ism8.server;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* The {@link DataPointChangedEvent} is an event container for data point changes
*
* @author Hans-Reiner Hoffmann - Initial contribution
*/
@NonNullByDefault
public class DataPointChangedEvent {
protected IDataPoint dataPoint;
public DataPointChangedEvent(Object source, IDataPoint dataPoint) {
this.dataPoint = dataPoint;
}
/**
* Gets the data-point of the event.
*
*/
@Nullable
public IDataPoint getDataPoint() {
return this.dataPoint;
}
}

View File

@@ -0,0 +1,59 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ism8.server;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* The {@link DataPointFactory} creates the data points depending on the types
*
* @author Hans-Reiner Hoffmann - Initial contribution
*/
@NonNullByDefault
public class DataPointFactory {
/**
* Creates the concrete data-point based on the type.
*
*/
@Nullable
public static IDataPoint createDataPoint(int id, String knxType, String description) {
IDataPoint dataPoint = null;
switch (knxType) {
case "1.001":
case "1.002":
case "1.003":
case "1.009":
dataPoint = new DataPointBool(id, knxType, description);
break;
case "5.001":
dataPoint = new DataPointScaling(id, knxType, description);
break;
case "9.001":
case "9.002":
case "9.006":
dataPoint = new DataPointValue(id, knxType, description);
break;
case "13.002":
dataPoint = new DataPointLongValue(id, knxType, description);
break;
case "20.102":
case "20.103":
case "20.105":
dataPoint = new DataPointByteValue(id, knxType, description);
break;
}
return dataPoint;
}
}

View File

@@ -0,0 +1,86 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.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 DataPointLongValue} is the data points for long values
*
* @author Hans-Reiner Hoffmann - Initial contribution
*/
@NonNullByDefault
public class DataPointLongValue extends DataPointBase<@Nullable Double> {
private final Logger logger = LoggerFactory.getLogger(DataPointLongValue.class);
private final float factor;
private final String outputFormat;
public DataPointLongValue(int id, String knxDataType, String description) {
super(id, knxDataType, description);
if (knxDataType.equals("13.002")) {
this.setUnit("m³/h");
this.factor = 0.0001f;
this.outputFormat = "%.1f";
} else {
this.setUnit("");
this.factor = 1.0f;
this.outputFormat = "%.1f";
}
}
@Override
public String getValueText() {
return String.format(this.outputFormat, this.getValue());
}
@Override
public void processData(byte[] data) {
if (this.checkProcessData(data)) {
if (data[3] != 4 && data.length <= 7) {
logger.debug("DataPoint-ProcessData: Data size wrong for this type({}/4).", data[3]);
return;
}
int rawValue = Byte.toUnsignedInt(data[4]) * 0x1000000 + Byte.toUnsignedInt(data[5]) * 0x10000
+ Byte.toUnsignedInt(data[6]) * 0x100 + Byte.toUnsignedInt(data[7]);
this.setValue((double) rawValue * this.factor);
}
}
@Override
protected byte[] convertWriteValue(Object value) {
ByteBuffer data = ByteBuffer.allocate(4);
double dblVal;
try {
dblVal = Double.parseDouble(value.toString());
} catch (NumberFormatException e) {
dblVal = 0.0;
}
int val = (int) (dblVal / this.factor);
data.put((byte) (val & 0xFF));
val = (val & 0xFF) / 256;
data.put((byte) (val & 0xFF));
val = (val & 0xFF) / 256;
data.put((byte) (val & 0xFF));
val = (val & 0xFF) / 256;
data.put((byte) (val & 0xFF));
return data.array();
}
}

View File

@@ -0,0 +1,61 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ism8.server;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link DataPointScaling} is the data points for scaling values
*
* @author Hans-Reiner Hoffmann - Initial contribution
*/
@NonNullByDefault
public class DataPointScaling extends DataPointBase<@Nullable Double> {
private final Logger logger = LoggerFactory.getLogger(DataPointScaling.class);
private String outputFormat = "";
public DataPointScaling(int id, String knxDataType, String description) {
super(id, knxDataType, description);
this.setUnit("%");
this.outputFormat = "%.1f";
}
@Override
public String getValueText() {
return String.format(this.outputFormat, this.getValue());
}
@Override
public void processData(byte[] data) {
if (this.checkProcessData(data)) {
if (data[3] != 1 && data.length <= 4) {
logger.debug("DataPoint-ProcessData: Data size wrong for this type({}/1).", data[3]);
return;
}
this.setValue((Byte.toUnsignedInt(data[4]) * 100.0) / 255.0);
}
}
@Override
protected byte[] convertWriteValue(Object value) {
this.setValue(Math.max(Math.min(Double.parseDouble(value.toString()), 100), 0));
Object rawVal = this.getValue();
double rawValResult = rawVal != null ? (Double) rawVal : 0.0;
byte val = (byte) (rawValResult / 100.0 * 255.0);
return new byte[] { val };
}
}

View File

@@ -0,0 +1,108 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.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 DataPointValue} is the data points for double values
*
* @author Hans-Reiner Hoffmann - Initial contribution
*/
@NonNullByDefault
public class DataPointValue extends DataPointBase<@Nullable Double> {
private final Logger logger = LoggerFactory.getLogger(DataPointValue.class);
private float factor;
private String outputFormat = "";
public DataPointValue(int id, String knxDataType, String description) {
super(id, knxDataType, description);
this.factor = 0.0f;
if (knxDataType.equals("9.001")) {
this.setUnit("°C");
this.factor = 0.01f;
this.outputFormat = "%.1f";
} else if (knxDataType.equals("9.002")) {
this.setUnit("°K");
this.factor = 0.01f;
this.outputFormat = "%.1f";
} else if (knxDataType.equals("9.006")) {
this.setUnit("Bar");
this.factor = 0.0000001f;
this.outputFormat = "%.2f";
}
}
@Override
public String getValueText() {
return String.format(this.outputFormat, this.getValue());
}
@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({}/2).", data[3]);
return;
}
int rawValue = Byte.toUnsignedInt(data[4]) * 256 + Byte.toUnsignedInt(data[5]);
boolean inverted = (rawValue & 0x8000) > 0;
double exp = (rawValue & 0x7800) / 2048;
rawValue = rawValue & 0x07FF;
exp = Math.pow(2, exp);
if (inverted) {
rawValue = rawValue - 1;
rawValue = rawValue ^ 0x7FF;
this.setValue(rawValue * exp * this.factor * (-1.0));
} else {
this.setValue(rawValue * exp * this.factor);
}
}
}
@Override
protected byte[] convertWriteValue(Object value) {
ByteBuffer data = ByteBuffer.allocate(2);
this.setValue(Double.parseDouble(value.toString()));
Object rawVal = this.getValue();
double rawValResult = rawVal != null ? (Double) rawVal : 0.0;
double dblValue = rawValResult / this.factor;
boolean inverted = dblValue < 0.0;
int exp = 0;
dblValue = Math.abs(dblValue);
while (dblValue > 2047.0) {
dblValue = dblValue / 2.0;
exp++;
}
int val = (int) dblValue;
if (inverted) {
val = val ^ 0x7FF;
val = val + 1;
val |= 0x8000;
}
val |= exp * 2048;
byte low = (byte) (val & 0xFF);
val = (val & 0xFF00) / 256;
byte high = (byte) (val & 0xFF);
data.put(high);
data.put(low);
return data.array();
}
}

View File

@@ -0,0 +1,69 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ism8.server;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* The {@link IDataPoint} is the interface for all data points
*
* @author Hans-Reiner Hoffmann - Initial contribution
*/
@NonNullByDefault
public interface IDataPoint {
int getId();
/**
* Gets the unit of the data-point.
*
*/
String getUnit();
/**
* Gets the type of the data-point.
*
*/
String getKnxDataType();
/**
* Gets the description of the data-point.
*
*/
String getDescription();
/**
* Gets the value as formated text.
*
*/
String getValueText();
/**
* Gets the value object.
*
*/
@Nullable
Object getValueObject();
/**
* Processes the data received
*
*/
void processData(byte[] data);
/**
* Creates the data to be written
*
*/
byte[] createWriteData(Object value);
}

View File

@@ -0,0 +1,36 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ism8.server;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingStatus;
/**
* The {@link IDataPointChangeListener} is in interface for a data point changed consumer
*
* @author Hans-Reiner Hoffmann - Initial contribution
*/
@NonNullByDefault
public interface IDataPointChangeListener {
/**
* This method will be called in case a data-point has changed.
*
*/
void dataPointChanged(DataPointChangedEvent e);
/**
* This method will be called in case the connection status has changed.
*
*/
void connectionStatusChanged(ThingStatus status);
}

View File

@@ -0,0 +1,208 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ism8.server;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link KnxNetFrame} is used for handling the received KNX.Net frames
*
* @author Hans-Reiner Hoffmann - Initial contribution
*/
@NonNullByDefault
public class KnxNetFrame {
public static byte[] KNX_HEADER = new byte[6];
public static byte[] CONNECTION_HEADER = new byte[4];
private static final Logger LOGGER = LoggerFactory.getLogger(KnxNetFrame.class);
private ArrayList<SetDatapointValueMessage> valueMessages = new ArrayList<SetDatapointValueMessage>();
private byte mainService;
private byte subService = SubServiceType.SET_DATAPOINT_VALUE_REQUEST;
private int startDataPoint;
static {
KNX_HEADER[0] = (byte) 0x06; // Header size
KNX_HEADER[1] = (byte) 0x20; // Version (2.0)
KNX_HEADER[2] = (byte) 0xF0; // Object server request
KNX_HEADER[3] = (byte) 0x80; // Object server request
KNX_HEADER[4] = (byte) 0x00; // Frame size
KNX_HEADER[5] = (byte) 0x00; // Frame size
CONNECTION_HEADER[0] = (byte) 0x04; // Structure length
CONNECTION_HEADER[1] = (byte) 0x00; // Reserved
CONNECTION_HEADER[2] = (byte) 0x00; // Reserved
CONNECTION_HEADER[3] = (byte) 0x00; // Reserved
}
public KnxNetFrame() {
this.valueMessages = new ArrayList<SetDatapointValueMessage>();
}
/**
* Gets the main service of the KNX frame
*
*/
public byte getMainService() {
return this.mainService;
}
/**
* Sets the main service of the KNX frame
*
*/
public void setMainService(byte value) {
this.mainService = value;
}
/**
* Gets the sub service of the KNX frame
*
*/
public byte getSubService() {
return this.subService;
}
/**
* Sets the sub service of the KNX frame
*
*/
public void setSubService(byte value) {
this.subService = value;
}
/**
* Gets the start data-point of the KNX frame
*
*/
public int getStartDataPoint() {
return this.startDataPoint;
}
/**
* Sets the start data-point of the KNX frame
*
*/
public void setStartDataPoint(int value) {
this.startDataPoint = value;
}
/**
* Sets the value messages of the KNX frame
*
*/
public SetDatapointValueMessage[] getValueMessages() {
SetDatapointValueMessage[] result = new SetDatapointValueMessage[this.valueMessages.size()];
this.valueMessages.toArray(result);
return result;
}
/**
* Creates a KNX frame based on the data-array
*
*/
@Nullable
public static KnxNetFrame createKnxNetPackage(byte[] data, int amount) {
if (data.length < 16 || amount < 16 || data.length < amount) {
LOGGER.debug("Length of the data too short for a KNXnet/IP package ({}).", data.length);
return null;
}
if (data[0] != KNX_HEADER[0] || data[1] != KNX_HEADER[1] || data[2] != KNX_HEADER[2]
|| data[3] != KNX_HEADER[3]) {
LOGGER.debug("Incorrect KNXnet/IP header.");
return null;
}
int frameSize = Byte.toUnsignedInt(data[4]) * 256 + Byte.toUnsignedInt(data[5]);
if (frameSize != amount) {
LOGGER.debug("CreateKnxNetPackage: Error TelegrammLength/FrameSize missmatch. ({}/{})", data.length,
frameSize);
return null;
}
KnxNetFrame frame = new KnxNetFrame();
frame.setMainService(data[10]);
if (frame.getMainService() != (byte) 0xF0) {
LOGGER.debug("CreateKnxNetPackage: Main-Service not supported. ({})", frame.getMainService());
return null;
}
if (data[11] == (byte) 0x06) {
frame.setSubService(SubServiceType.SET_DATAPOINT_VALUE_REQUEST);
} else if (data[11] == (byte) 0x86) {
frame.setSubService(SubServiceType.SET_DATAPOINT_VALUE_RESULT);
} else if (data[11] == (byte) 0xC1) {
frame.setSubService(SubServiceType.DATAPOINT_VALUE_WRITE);
} else if (data[11] == (byte) 0xD0) {
frame.setSubService(SubServiceType.REQUEST_ALL_DATAPOINTS);
} else {
LOGGER.debug("CreateKnxNetPackage: Sub-Service not supported. ({})", frame.getSubService());
return null;
}
if (frame.getSubService() == SubServiceType.SET_DATAPOINT_VALUE_REQUEST) {
frame.setStartDataPoint(Byte.toUnsignedInt(data[12]) * 256 + Byte.toUnsignedInt(data[13]));
int numberOfDatapoints = Byte.toUnsignedInt(data[14]) * 256 + Byte.toUnsignedInt(data[15]);
int offset = 16;
ByteBuffer list = ByteBuffer.allocate(data.length);
list.put(data);
try {
for (int i = 0; i < numberOfDatapoints; i++) {
byte[] msgData = new byte[amount - offset];
list.position(offset);
list.get(msgData);
SetDatapointValueMessage msg = new SetDatapointValueMessage(msgData);
offset = offset + msg.getLength() + 4;
frame.valueMessages.add(msg);
}
return frame;
} catch (IllegalArgumentException e) {
LOGGER.debug("Error creating KnxNetPackage. {}", e.getMessage());
}
}
return null;
}
/**
* Creates the answer of the KNX frame
*
*/
public byte[] createFrameAnswer() {
ByteBuffer answer = ByteBuffer.allocate(17);
if (this.getSubService() == SubServiceType.SET_DATAPOINT_VALUE_REQUEST) {
answer.put(KNX_HEADER);
answer.put(5, (byte) 0x11); // static size (17 bytes)
answer.put(CONNECTION_HEADER);
answer.put(this.getMainService());
answer.put(SubServiceType.SET_DATAPOINT_VALUE_RESULT);
byte low = (byte) (this.getStartDataPoint() & (byte) 0xFF);
byte high = (byte) ((this.getStartDataPoint() & (byte) 0xFF) / 256);
answer.put(high);
answer.put(low);
answer.put((byte) 0);
answer.put((byte) 0);
answer.put((byte) 0);
}
return answer.array();
}
}

View File

@@ -0,0 +1,270 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ism8.server;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.util.HexUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link ism8Server} is responsible for listening to the Ism8 information
*
* @author Hans-Reiner Hoffmann - Initial contribution
*/
@NonNullByDefault
public class Server extends Thread {
private final Logger logger = LoggerFactory.getLogger(Server.class);
private int port;
private int startRetries;
private boolean connected;
private HashMap<Integer, IDataPoint> dataPoints = new HashMap<>();
private @Nullable ServerSocket serverSocket = null;
private @Nullable Socket client;
private @Nullable IDataPointChangeListener changeListener;
public Server(int port, String uid) {
super("OH-binding-" + uid);
setDaemon(true);
this.port = port;
}
/**
* Gets the port of the server
*
*/
public int getPort() {
return this.port;
}
/**
* Gets the connection state of the server
*
*/
public boolean getConnected() {
return this.connected;
}
/**
* Gets the data points of the server
*
*/
public @Nullable IDataPoint getDataPoint(int id) {
IDataPoint dataPoint = null;
if (this.dataPoints.containsKey(id)) {
dataPoint = this.dataPoints.get(id);
}
return dataPoint;
}
/**
* Starts the server
*
*/
public void run() {
this.startRetries = 0;
while (!this.isInterrupted()) {
try {
this.handleCommunication();
if (this.startRetries > 10) {
Thread.sleep(6000);
}
} catch (InterruptedException e) {
logger.debug("Thread interrupted");
Thread.currentThread().interrupt();
}
this.startRetries++;
}
}
/**
* Stops the server
*
*/
public void stopServerThread() {
this.interrupt();
this.stopServer();
}
/**
* Adds a data-point change listener to the server
*
*/
public void addDataPointChangeListener(IDataPointChangeListener listener) {
if (this.changeListener == null) {
this.changeListener = listener;
}
}
/**
* Adds a data-point to the server
*
*/
public void addDataPoint(int id, String knxType, String description) {
if (this.dataPoints.containsKey(id)) {
return;
}
IDataPoint dp = DataPointFactory.createDataPoint(id, knxType, description);
if (dp != null) {
this.dataPoints.put(new Integer(id), dp);
}
}
/**
* Sends the data to the ISM8 partner
*
*/
public void sendData(byte[] data) throws IOException {
Socket clientSocket = this.client;
if (clientSocket != null && clientSocket.isConnected() && data.length > 0) {
OutputStream stream = clientSocket.getOutputStream();
stream.write(data);
stream.flush();
logger.debug("Data sent: {}", this.printBytes(data));
}
}
private void stopServer() {
logger.debug("Stop Ism8 server.");
try {
ServerSocket serverSock = this.serverSocket;
if (serverSock != null) {
serverSock.close();
}
Socket clientSocket = this.client;
if (clientSocket != null) {
clientSocket.close();
this.client = null;
}
} catch (IOException e) {
logger.debug("Error stopping Communication. {}", e.getMessage());
}
}
private void handleCommunication() {
try {
logger.debug("Waiting for connection in port {}.", this.getPort());
IDataPointChangeListener listener = this.changeListener;
if (listener != null) {
listener.connectionStatusChanged(ThingStatus.OFFLINE);
}
ServerSocket serverSock = new ServerSocket(this.getPort());
this.serverSocket = serverSock;
Socket clientSocket = serverSock.accept();
this.client = clientSocket;
logger.debug("Connection from Partner established {}", clientSocket.getRemoteSocketAddress());
if (listener != null) {
listener.connectionStatusChanged(ThingStatus.ONLINE);
}
this.startRetries = 0;
this.sendUpdateCommand();
while (!this.isInterrupted()) {
byte[] bytes = getBytesFromInputStream(clientSocket.getInputStream());
ArrayList<byte[]> packages = this.getPackages(bytes);
for (byte[] pack : packages) {
logger.debug("Data received: {}", this.printBytes(pack));
KnxNetFrame frame = KnxNetFrame.createKnxNetPackage(pack, pack.length);
if (frame != null) {
byte[] answer = frame.createFrameAnswer();
if (answer.length > 0) {
this.sendData(answer);
}
for (SetDatapointValueMessage message : frame.getValueMessages()) {
logger.debug("Message received: {} {}", message.getId(),
this.printBytes(message.getData()));
IDataPoint dataPoint = this.getDataPoint(message.getId());
if (dataPoint != null) {
dataPoint.processData(message.getData());
logger.debug("{} {}", dataPoint.getDescription(), dataPoint.getValueText());
if (listener != null) {
listener.dataPointChanged(new DataPointChangedEvent(this, dataPoint));
}
break;
}
}
}
}
}
} catch (IOException e) {
logger.warn("Error handle client data stream. {}", e.getMessage());
this.stopServer();
}
}
private void sendUpdateCommand() throws IOException {
byte[] data = new byte[] { (byte) 0x06, (byte) 0x20, (byte) 0xF0, (byte) 0x80, (byte) 0x00, (byte) 0x16,
(byte) 0x04, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xF0, (byte) 0xD0 };
this.sendData(data);
}
private byte[] getBytesFromInputStream(InputStream is) throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
byte[] buffer = new byte[0xFF];
int len = is.read(buffer);
os.write(buffer, 0, len);
return os.toByteArray();
}
private ArrayList<byte[]> getPackages(byte[] data) {
ArrayList<byte[]> result = new ArrayList<byte[]>();
if (data.length >= 0) {
ByteBuffer list = ByteBuffer.allocate(data.length);
list.put(data);
int start = -1;
for (int i = 0; i < data.length - 4; i++) {
if (list.get(i + 0) == (byte) 0x06 && list.get(i + 1) == (byte) 0x20 && list.get(i + 2) == (byte) 0xF0
&& list.get(i + 3) == (byte) 0x80) {
if (start >= 0) {
byte[] pkgData = new byte[i - start];
list.position(start);
list.get(pkgData);
result.add(pkgData);
}
start = i;
}
}
if (start >= 0) {
byte[] pkgData = new byte[data.length - start];
list.position(start);
list.get(pkgData);
result.add(pkgData);
}
}
return result;
}
private String printBytes(byte[] bytes) {
return HexUtils.bytesToHex(bytes);
}
}

View File

@@ -0,0 +1,115 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ism8.server;
import java.nio.ByteBuffer;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link SetDatapointValueMessage} is a message within the KNX frame containing
* the information of one data point
*
* @author Hans-Reiner Hoffmann - Initial contribution
*/
@NonNullByDefault
public class SetDatapointValueMessage {
private int id;
private byte command;
private byte[] data = new byte[0];
private byte length;
public SetDatapointValueMessage() {
}
public SetDatapointValueMessage(byte[] data) throws IllegalArgumentException {
if (data.length < 5) {
throw new IllegalArgumentException("Data size too small for a SetDatapointValueMessage.");
}
this.setId(Byte.toUnsignedInt(data[0]) * 256 + Byte.toUnsignedInt(data[1]));
this.setCommand(data[2]);
this.setLength(data[3]);
if (data.length < (this.getLength() + 4)) {
throw new IllegalArgumentException("Data size incorrect (" + data.length + "/" + this.getLength() + ").");
}
ByteBuffer list = ByteBuffer.allocate(this.getLength() + 4);
list.put(data, 0, this.getLength() + 4);
this.setData(list.array());
}
/**
* Gets the ID of the data-point message
*
*/
public int getId() {
return this.id;
}
/**
* Sets the ID of the data-point message
*
*/
public void setId(int value) {
this.id = value;
}
/**
* Gets the command of the data-point message
*
*/
public byte getCommand() {
return this.command;
}
/**
* Sets the command of the data-point message
*
*/
public void setCommand(byte value) {
this.command = value;
}
/**
* Gets the length of the data-point message
*
*/
public byte getLength() {
return this.length;
}
/**
* Sets the length of the data-point message
*
*/
public void setLength(byte value) {
this.length = value;
}
/**
* Gets the data array of the data-point message
*
*/
public byte[] getData() {
return this.data;
}
/**
* Sets the data array of the data-point message
*
*/
public void setData(byte[] value) {
this.data = value;
}
}

View File

@@ -0,0 +1,47 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ism8.server;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link SubServiceType} contains all supported sub-service types
*
* @author Hans-Reiner Hoffmann - Initial contribution
*/
@NonNullByDefault
public class SubServiceType {
/**
* Sub-Service: Set data-point value request.
*
*/
public static final byte SET_DATAPOINT_VALUE_REQUEST = (byte) 0x06;
/**
* Sub-Service: Set data-point value result.
*
*/
public static final byte SET_DATAPOINT_VALUE_RESULT = (byte) 0x86;
/**
* Sub-Service: Write data-point value.
*
*/
public static final byte DATAPOINT_VALUE_WRITE = (byte) 0xC1;
/**
* Sub-Service: Request all data-points.
*
*/
public static final byte REQUEST_ALL_DATAPOINTS = (byte) 0xD0;
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="ism8" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
<name>ISM8 Binding</name>
<description>This is the binding for the ISM8 card used for Wolf heating systems or other Wolf eBus devices.</description>
<author>Hans-Reiner Hoffmann</author>
</binding:binding>

View File

@@ -0,0 +1,109 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="ism8"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="device" extensible="switch, switch-readonly, number, number-readonly">
<label>ISM8 Device</label>
<description>ISM8 Interface</description>
<config-description>
<parameter name="portNumber" type="integer" required="true" min="1" max="65535">
<description>Port number of the object server</description>
<label>Port</label>
<default>12004</default>
</parameter>
</config-description>
</thing-type>
<channel-type id="switch">
<item-type>Switch</item-type>
<label>Digital DataPoint</label>
<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_Switch / 1.001)</description>
<options>
<option value="1.001">DPT_Switch</option>
<option value="1.002">DPT_Bool</option>
<option value="1.003">DPT_Enable</option>
<option value="1.009">DPT_OpenClose</option>
</options>
</parameter>
</config-description>
</channel-type>
<channel-type id="switch-readonly">
<item-type>Switch</item-type>
<label>Digital 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_Switch / 1.001)</description>
<options>
<option value="1.001">DPT_Switch</option>
<option value="1.002">DPT_Bool</option>
<option value="1.003">DPT_Enable</option>
<option value="1.009">DPT_OpenClose</option>
</options>
</parameter>
</config-description>
</channel-type>
<channel-type id="number-readonly">
<item-type>number</item-type>
<label>Value 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.001">DPT_Scaling</option>
<option value="9.001">DPT_Value_Temp</option>
<option value="9.002">DPT_Value_Tempd</option>
<option value="9.006">DPT_Value_Pres</option>
<option value="13.002">DPT_FlowRate</option>
<option value="20.102">DPT_HVACMode</option>
<option value="20.103">DPT_DHWMode</option>
<option value="20.105">DPT_HVACContrMode</option>
</options>
</parameter>
</config-description>
</channel-type>
<channel-type id="number">
<item-type>number</item-type>
<label>Value DataPoint</label>
<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.001">DPT_Value_Temp</option>
<option value="20.102">DPT_HVACMode</option>
<option value="20.103">DPT_DHWMode</option>
<option value="20.105">DPT_HVACContrMode</option>
</options>
</parameter>
</config-description>
</channel-type>
</thing:thing-descriptions>