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.
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)), //
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
*
*/
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);
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