Skip to content

Commit

Permalink
[knx] Allow receiving DPT 235.001 (openhab#16094)
Browse files Browse the repository at this point in the history
* [knx] Allow receiving DPT 235.001

Composed type not yet supported by Calimero, thus only receiving
data is implemented.
Configure DPT 235.001 to receive ActiveEnergy.
Configure DPT 235.61001 to receive Tariff information.

Fixes openhab#15159

Signed-off-by: Holger Friedrich <mail@holger-friedrich.de>
Signed-off-by: René Ulbricht <rene_ulbricht@outlook.com>
  • Loading branch information
holgerfriedrich authored and ulbi committed Jan 28, 2024
1 parent 6a57a8e commit 571c37d
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 6 deletions.
12 changes: 12 additions & 0 deletions bundles/org.openhab.binding.knx/README.md
Expand Up @@ -267,6 +267,18 @@ With `*-control` channels, the state is not owned by any device on the KNX bus,
The element `dpt` is highly recommended and may change to a mandatory element in future versions.
If omitted, the corresponding default value will be used (see the channel descriptions above).

## Special DPTs

OpenHAB supports all DPTs supported by the corresponding release of Calimero library.

Additional DPTs have been introduced to add functionality:

| DPT | Description | Remark |
|---------------|-------------------------------------------------------------|------------|
| DPT 232.60000 | DPT 232.600 with HSB instead of RGB data (see below) | read/write |
| DPT 235.001 | Composed DPT 235.001, first element ActiveEnergy (Wh) | read only |
| DPT 235.61001 | Composed DPT 235.001, second element Tariff (plain number) | read only |

## KNX Secure

> NOTE: Support for KNX Secure is partly implemented for openHAB and should be considered as experimental.
Expand Down
Expand Up @@ -84,6 +84,7 @@ public class DPTUtil {
Map.entry("29", Set.of(QuantityType.class, DecimalType.class)), //
Map.entry("229", Set.of(DecimalType.class)), //
Map.entry("232", Set.of(HSBType.class)), //
Map.entry("235", Set.of(QuantityType.class, DecimalType.class)), //
Map.entry("242", Set.of(HSBType.class)), //
Map.entry("243", Set.of(StringType.class)), //
Map.entry("249", Set.of(StringType.class)), //
Expand Down
Expand Up @@ -81,6 +81,28 @@ public class ValueDecoder {
public static final Pattern XYY_PATTERN = Pattern
.compile("(?:\\((?<x>\\d+(?:[,.]\\d+)?) (?<y>\\d+(?:[,.]\\d+)?)\\))?\\s*(?:(?<Y>\\d+(?:[,.]\\d+)?)\\s%)?");

private static boolean check235001(byte[] data) throws KNXException {
if (data.length != 6) {
throw new KNXFormatException("DPT235 broken frame");
}
if ((data[5] & 2) == 0) {
LOGGER.trace("DPT235.001 w/o ActiveEnergy ignored");
return false;
}
return true;
}

private static boolean check23561001(byte[] data) throws KNXException {
if (data.length != 6) {
throw new KNXFormatException("DPT235 broken frame");
}
if ((data[5] & 1) == 0) {
LOGGER.trace("DPT235.61001 w/o Tariff ignored");
return false;
}
return true;
}

/**
* convert the raw value received to the corresponding openHAB value
*
Expand All @@ -91,18 +113,46 @@ public class ValueDecoder {
*/
public static @Nullable Type decode(String dptId, byte[] data, Class<? extends Type> preferredType) {
try {
DPTXlator translator = TranslatorTypes.createTranslator(0,
DPTUtil.NORMALIZED_DPT.getOrDefault(dptId, dptId));
translator.setData(data);
String value = translator.getValue();

String value = "";
String translatorDptId = dptId;
DPTXlator translator;
try {
translator = TranslatorTypes.createTranslator(0, DPTUtil.NORMALIZED_DPT.getOrDefault(dptId, dptId));
translator.setData(data);
value = translator.getValue();
translatorDptId = translator.getType().getID();
} catch (KNXException e) {
// special handling for decoding DPTs not yet supported by Calimero
if ("235.001".equals(dptId)) {
if (!check235001(data)) {
return null;
}
translator = TranslatorTypes.createTranslator(0, "13.010");
translator.setData(data);
value = translator.getValue();
dptId = "13.010";
translatorDptId = dptId;
} else if ("235.61001".equals(dptId)) {
if (!check23561001(data)) {
return null;
}
translator = TranslatorTypes.createTranslator(0, "5.006");
translator.setData(new byte[] { data[4] });
value = translator.getValue();
dptId = "5.006";
translatorDptId = dptId;
} else {
// no known special case, handle unknown translator outer try block
throw e;
}
}
String id = dptId; // prefer using the user-supplied DPT

Matcher m = DPTUtil.DPT_PATTERN.matcher(id);
if (!m.matches() || m.groupCount() != 2) {
LOGGER.trace("User-Supplied DPT '{}' did not match for sub-type, using DPT returned from Translator",
id);
id = translator.getType().getID();
id = translatorDptId;
m = DPTUtil.DPT_PATTERN.matcher(id);
if (!m.matches() || m.groupCount() != 2) {
LOGGER.warn("Couldn't identify main/sub number in dptID '{}'", id);
Expand Down
Expand Up @@ -330,6 +330,30 @@ public void dpt232HsbValue() {
assertEquals(encoded, "r:" + data[0] + " g:" + data[1] + " b:" + data[2]);
}

@Test
public void dpt235Decoder() {
byte[] noActiveEnergy = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xfd };
assertNull(ValueDecoder.decode("235.001", noActiveEnergy, QuantityType.class));

byte[] noTariff = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xfe };
assertNull(ValueDecoder.decode("235.61001", noTariff, DecimalType.class));

byte[] activeEnergy = new byte[] { (byte) 0x0, (byte) 0x0, (byte) 0x03, (byte) 0xff, (byte) 0x0a, (byte) 0x02 };
assertEquals(new QuantityType<>("1023 Wh"), ValueDecoder.decode("235.001", activeEnergy, QuantityType.class));

byte[] activeTariff = new byte[] { (byte) 0x0, (byte) 0x0, (byte) 0x03, (byte) 0xff, (byte) 0x0a, (byte) 0x01 };
assertEquals(new DecimalType("10"), ValueDecoder.decode("235.61001", activeTariff, DecimalType.class));

byte[] activeAll = new byte[] { (byte) 0x0, (byte) 0x0, (byte) 0x03, (byte) 0xff, (byte) 0x0a, (byte) 0x03 };
assertEquals(new QuantityType<>("1023 Wh"), ValueDecoder.decode("235.001", activeAll, QuantityType.class));
assertEquals(new DecimalType("10"), ValueDecoder.decode("235.61001", activeAll, DecimalType.class));

byte[] negativeEnergy = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00,
(byte) 0x02 };
assertEquals(new QuantityType<>("-1 Wh"), ValueDecoder.decode("235.001", negativeEnergy, QuantityType.class));
}

@Test
public void dpt251White() {
// input data: color white
Expand Down

0 comments on commit 571c37d

Please sign in to comment.