From ba35e8d84a9b724bf88fa179937791ba195fe4aa Mon Sep 17 00:00:00 2001 From: Holger Friedrich Date: Sun, 21 Jan 2024 21:43:21 +0100 Subject: [PATCH] [knx] DPT 1 to support Switch and Contact (#16238) * Allow assigning Switch or Contact to most of the DPT 1 subtypes (exceptions 1.008 UpDownType, 1.010 StopMoveType, 1.022 DecimalType). * Tests for all published subtypes for DPT 1. * Fix sending of DPT 1.022. Signed-off-by: Holger Friedrich --- .../knx/internal/dpt/ValueDecoder.java | 14 +++- .../knx/internal/dpt/ValueEncoder.java | 6 ++ .../knx/internal/itests/Back2BackTest.java | 82 +++++++++++++++++-- 3 files changed, 95 insertions(+), 7 deletions(-) diff --git a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/ValueDecoder.java b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/ValueDecoder.java index 9969b6bc0a..1fc19b0ce4 100644 --- a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/ValueDecoder.java +++ b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/ValueDecoder.java @@ -116,7 +116,7 @@ public class ValueDecoder { switch (mainType) { case "1": - return handleDpt1(subType, translator); + return handleDpt1(subType, translator, preferredType); case "2": DPTXlator1BitControlled translator1BitControlled = (DPTXlator1BitControlled) translator; int decValue = (translator1BitControlled.getControlBit() ? 2 : 0) @@ -172,13 +172,18 @@ public class ValueDecoder { return null; } - private static Type handleDpt1(String subType, DPTXlator translator) { + private static Type handleDpt1(String subType, DPTXlator translator, Class preferredType) { DPTXlatorBoolean translatorBoolean = (DPTXlatorBoolean) translator; switch (subType) { case "008": return translatorBoolean.getValueBoolean() ? UpDownType.DOWN : UpDownType.UP; case "009": case "019": + // default is OpenClosedType (Contact), but it may be mapped to OnOffType as well + if (OnOffType.class.equals(preferredType)) { + return OnOffType.from(translatorBoolean.getValueBoolean()); + } + // This is wrong for DPT 1.009. It should be true -> CLOSE, false -> OPEN, but unfortunately // can't be fixed without breaking a lot of working installations. // The documentation has been updated to reflect that. / @J-N-K @@ -188,6 +193,11 @@ public class ValueDecoder { case "022": return DecimalType.valueOf(translatorBoolean.getValueBoolean() ? "1" : "0"); default: + // default is OnOffType (Switch), but it may be mapped to OpenClosedType as well + if (OpenClosedType.class.equals(preferredType)) { + return translatorBoolean.getValueBoolean() ? OpenClosedType.OPEN : OpenClosedType.CLOSED; + } + return OnOffType.from(translatorBoolean.getValueBoolean()); } } diff --git a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/ValueEncoder.java b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/ValueEncoder.java index 0a1688082f..cbf5de4bab 100644 --- a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/ValueEncoder.java +++ b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/ValueEncoder.java @@ -47,6 +47,7 @@ import tuwien.auto.calimero.dptxlator.DPTXlator1BitControlled; import tuwien.auto.calimero.dptxlator.DPTXlator2ByteFloat; import tuwien.auto.calimero.dptxlator.DPTXlator3BitControlled; import tuwien.auto.calimero.dptxlator.DPTXlator4ByteFloat; +import tuwien.auto.calimero.dptxlator.DPTXlatorBoolean; import tuwien.auto.calimero.dptxlator.DPTXlatorDate; import tuwien.auto.calimero.dptxlator.DPTXlatorDateTime; import tuwien.auto.calimero.dptxlator.DPTXlatorTime; @@ -236,6 +237,11 @@ public class ValueEncoder { } } switch (mainNumber) { + case "1": + if (DPTXlatorBoolean.DPT_SCENE_AB.getID().equals(dptId)) { + return (bigDecimal.intValue() == 0) ? dpt.getLowerValue() : dpt.getUpperValue(); + } + return bigDecimal.stripTrailingZeros().toPlainString(); case "2": DPT valueDPT = ((DPTXlator1BitControlled.DPT1BitControlled) dpt).getValueDPT(); switch (bigDecimal.intValue()) { diff --git a/bundles/org.openhab.binding.knx/src/test/java/org/openhab/binding/knx/internal/itests/Back2BackTest.java b/bundles/org.openhab.binding.knx/src/test/java/org/openhab/binding/knx/internal/itests/Back2BackTest.java index 29708a7af9..8049904003 100644 --- a/bundles/org.openhab.binding.knx/src/test/java/org/openhab/binding/knx/internal/itests/Back2BackTest.java +++ b/bundles/org.openhab.binding.knx/src/test/java/org/openhab/binding/knx/internal/itests/Back2BackTest.java @@ -190,40 +190,112 @@ public class Back2BackTest { @Test void testDpt1() { - // for now only the DPTs for general use, others omitted - // TODO add tests for more subtypes - helper("1.001", new byte[] { 0 }, OnOffType.OFF); helper("1.001", new byte[] { 1 }, OnOffType.ON); + helper("1.001", new byte[] { 0 }, OpenClosedType.CLOSED); + helper("1.001", new byte[] { 1 }, OpenClosedType.OPEN); helper("1.002", new byte[] { 0 }, OnOffType.OFF); helper("1.002", new byte[] { 1 }, OnOffType.ON); + helper("1.002", new byte[] { 0 }, OpenClosedType.CLOSED); + helper("1.002", new byte[] { 1 }, OpenClosedType.OPEN); helper("1.003", new byte[] { 0 }, OnOffType.OFF); helper("1.003", new byte[] { 1 }, OnOffType.ON); - + helper("1.003", new byte[] { 0 }, OpenClosedType.CLOSED); + helper("1.003", new byte[] { 1 }, OpenClosedType.OPEN); + helper("1.004", new byte[] { 0 }, OnOffType.OFF); + helper("1.004", new byte[] { 1 }, OnOffType.ON); + helper("1.004", new byte[] { 0 }, OpenClosedType.CLOSED); + helper("1.004", new byte[] { 1 }, OpenClosedType.OPEN); + helper("1.005", new byte[] { 0 }, OnOffType.OFF); + helper("1.005", new byte[] { 1 }, OnOffType.ON); + helper("1.005", new byte[] { 0 }, OpenClosedType.CLOSED); + helper("1.005", new byte[] { 1 }, OpenClosedType.OPEN); + helper("1.006", new byte[] { 0 }, OnOffType.OFF); + helper("1.006", new byte[] { 1 }, OnOffType.ON); + helper("1.006", new byte[] { 0 }, OpenClosedType.CLOSED); + helper("1.006", new byte[] { 1 }, OpenClosedType.OPEN); + helper("1.007", new byte[] { 0 }, OnOffType.OFF); + helper("1.007", new byte[] { 1 }, OnOffType.ON); + helper("1.007", new byte[] { 0 }, OpenClosedType.CLOSED); + helper("1.007", new byte[] { 1 }, OpenClosedType.OPEN); helper("1.008", new byte[] { 0 }, UpDownType.UP); helper("1.008", new byte[] { 1 }, UpDownType.DOWN); // NOTE: This is how DPT 1.009 is defined: 0: open, 1: closed // For historical reasons it is defined the other way on OH + helper("1.009", new byte[] { 0 }, OnOffType.OFF); + helper("1.009", new byte[] { 1 }, OnOffType.ON); helper("1.009", new byte[] { 0 }, OpenClosedType.CLOSED); helper("1.009", new byte[] { 1 }, OpenClosedType.OPEN); helper("1.010", new byte[] { 0 }, StopMoveType.STOP); helper("1.010", new byte[] { 1 }, StopMoveType.MOVE); - + helper("1.011", new byte[] { 0 }, OnOffType.OFF); + helper("1.011", new byte[] { 1 }, OnOffType.ON); + helper("1.011", new byte[] { 0 }, OpenClosedType.CLOSED); + helper("1.011", new byte[] { 1 }, OpenClosedType.OPEN); + helper("1.012", new byte[] { 0 }, OnOffType.OFF); + helper("1.012", new byte[] { 1 }, OnOffType.ON); + helper("1.012", new byte[] { 0 }, OpenClosedType.CLOSED); + helper("1.012", new byte[] { 1 }, OpenClosedType.OPEN); + helper("1.013", new byte[] { 0 }, OnOffType.OFF); + helper("1.013", new byte[] { 1 }, OnOffType.ON); + helper("1.013", new byte[] { 0 }, OpenClosedType.CLOSED); + helper("1.013", new byte[] { 1 }, OpenClosedType.OPEN); + helper("1.014", new byte[] { 0 }, OnOffType.OFF); + helper("1.014", new byte[] { 1 }, OnOffType.ON); + helper("1.014", new byte[] { 0 }, OpenClosedType.CLOSED); + helper("1.014", new byte[] { 1 }, OpenClosedType.OPEN); helper("1.015", new byte[] { 0 }, OnOffType.OFF); helper("1.015", new byte[] { 1 }, OnOffType.ON); + helper("1.015", new byte[] { 0 }, OpenClosedType.CLOSED); + helper("1.015", new byte[] { 1 }, OpenClosedType.OPEN); helper("1.016", new byte[] { 0 }, OnOffType.OFF); helper("1.016", new byte[] { 1 }, OnOffType.ON); + helper("1.016", new byte[] { 0 }, OpenClosedType.CLOSED); + helper("1.016", new byte[] { 1 }, OpenClosedType.OPEN); // DPT 1.017 is a special case, "trigger" has no "value", both 0 and 1 shall trigger helper("1.017", new byte[] { 0 }, OnOffType.OFF); + helper("1.017", new byte[] { 0 }, OpenClosedType.CLOSED); // Calimero maps it always to 0 // helper("1.017", new byte[] { 1 }, OnOffType.ON); helper("1.018", new byte[] { 0 }, OnOffType.OFF); helper("1.018", new byte[] { 1 }, OnOffType.ON); + helper("1.018", new byte[] { 0 }, OpenClosedType.CLOSED); + helper("1.018", new byte[] { 1 }, OpenClosedType.OPEN); + helper("1.019", new byte[] { 0 }, OnOffType.OFF); + helper("1.019", new byte[] { 1 }, OnOffType.ON); helper("1.019", new byte[] { 0 }, OpenClosedType.CLOSED); helper("1.019", new byte[] { 1 }, OpenClosedType.OPEN); + helper("1.021", new byte[] { 0 }, OnOffType.OFF); + helper("1.021", new byte[] { 1 }, OnOffType.ON); + helper("1.021", new byte[] { 0 }, OpenClosedType.CLOSED); + helper("1.021", new byte[] { 1 }, OpenClosedType.OPEN); + // DPT 1.022 is mapped to decimal, Calimero does not follow the recommendation + // from KNX spec to add offset 1 + helper("1.022", new byte[] { 0 }, DecimalType.valueOf("0")); + helper("1.022", new byte[] { 1 }, DecimalType.valueOf("1")); + helper("1.023", new byte[] { 0 }, OnOffType.OFF); + helper("1.023", new byte[] { 1 }, OnOffType.ON); + helper("1.023", new byte[] { 0 }, OpenClosedType.CLOSED); + helper("1.023", new byte[] { 1 }, OpenClosedType.OPEN); helper("1.024", new byte[] { 0 }, OnOffType.OFF); helper("1.024", new byte[] { 1 }, OnOffType.ON); + helper("1.024", new byte[] { 0 }, OpenClosedType.CLOSED); + helper("1.024", new byte[] { 1 }, OpenClosedType.OPEN); + + helper("1.100", new byte[] { 0 }, OnOffType.OFF); + helper("1.100", new byte[] { 1 }, OnOffType.ON); + helper("1.100", new byte[] { 0 }, OpenClosedType.CLOSED); + helper("1.100", new byte[] { 1 }, OpenClosedType.OPEN); + + helper("1.1200", new byte[] { 0 }, OnOffType.OFF); + helper("1.1200", new byte[] { 1 }, OnOffType.ON); + helper("1.1200", new byte[] { 0 }, OpenClosedType.CLOSED); + helper("1.1200", new byte[] { 1 }, OpenClosedType.OPEN); + helper("1.1201", new byte[] { 0 }, OnOffType.OFF); + helper("1.1201", new byte[] { 1 }, OnOffType.ON); + helper("1.1201", new byte[] { 0 }, OpenClosedType.CLOSED); + helper("1.1201", new byte[] { 1 }, OpenClosedType.OPEN); } @Test -- 2.47.3