]> git.basschouten.com Git - openhab-addons.git/commitdiff
[knx] Allow receiving DPT 235.001 (#16094)
authorHolger Friedrich <mail@holger-friedrich.de>
Mon, 22 Jan 2024 21:37:46 +0000 (22:37 +0100)
committerGitHub <noreply@github.com>
Mon, 22 Jan 2024 21:37:46 +0000 (22:37 +0100)
* [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 #15159

Signed-off-by: Holger Friedrich <mail@holger-friedrich.de>
bundles/org.openhab.binding.knx/README.md
bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/DPTUtil.java
bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/ValueDecoder.java
bundles/org.openhab.binding.knx/src/test/java/org/openhab/binding/knx/internal/dpt/DPTTest.java

index c76196e42a28755fba03a6367e2d8425fc0152f7..fc0b764521a66d9fbfea8e5f1f788e4c804784c0 100644 (file)
@@ -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.
index 7df4abf405409d91cf439b7241609f1cba0d7bc0..96fb13676a6163dccd7af2b6b49ad574aaf2c51d 100644 (file)
@@ -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)), //
index 1fc19b0ce423738d4729627d03552fc70eaf6a63..85c7d4337a96e45685743933e5ab1bedd350654f 100644 (file)
@@ -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
      *
@@ -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);
index 430a74edc97a36a888e40fac4cabb3251af5bf27..1775261087a9463bd6648dd0d90eca95548c1e57 100644 (file)
@@ -330,6 +330,30 @@ class DPTTest {
         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