From 21c72024d4c939a7617f1eef223806d2b8d26cb4 Mon Sep 17 00:00:00 2001 From: Holger Friedrich Date: Sun, 8 May 2022 11:23:18 +0200 Subject: [PATCH] [knx] Allow sending items with units to KNX bus. (#12675) Items with dimensions (QuantityType) are now translated and can be sent to the KNX bus. This requires the correct DPT to be specified in the channel definition. Fixes #10706. Signed-off-by: Holger Friedrich Signed-off-by: Andras Uhrin --- bundles/org.openhab.binding.knx/README.md | 4 + .../knx/internal/channel/KNXChannelType.java | 7 +- .../knx/internal/dpt/KNXCoreTypeMapper.java | 167 +++++++++++- .../internal/dpt/KNXCoreTypeMapperTest.java | 247 ++++++++++++++++++ 4 files changed, 422 insertions(+), 3 deletions(-) diff --git a/bundles/org.openhab.binding.knx/README.md b/bundles/org.openhab.binding.knx/README.md index 078b7f8c3a598..f5dd76797c538 100644 --- a/bundles/org.openhab.binding.knx/README.md +++ b/bundles/org.openhab.binding.knx/README.md @@ -117,6 +117,10 @@ Note: After changing the DPT of already existing Channels, openHAB needs to be r |-----------|---------------|-------------| | ga | Group address | 9.001 | + +Note: Using the Units Of Measurement feature of openHAB (Quantitytype) requires that the DPT value is set correctly. +Automatic type conversion will be applied if required. + ##### Channel Type "string" | Parameter | Description | Default DPT | diff --git a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/channel/KNXChannelType.java b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/channel/KNXChannelType.java index a9fcfacf4b75c..4115ee714026a 100644 --- a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/channel/KNXChannelType.java +++ b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/channel/KNXChannelType.java @@ -31,6 +31,8 @@ import org.openhab.binding.knx.internal.client.InboundSpec; import org.openhab.binding.knx.internal.client.OutboundSpec; import org.openhab.core.config.core.Configuration; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.QuantityType; import org.openhab.core.types.Type; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -171,9 +173,10 @@ protected final Set asSet(String... values) { } Class expectedTypeClass = typeHelper.toTypeClass(dpt); if (expectedTypeClass != null) { - if (expectedTypeClass.isInstance(command)) { + if (expectedTypeClass.isInstance(command) + || ((expectedTypeClass == DecimalType.class) && (command instanceof QuantityType))) { logger.trace( - "getCommandSpec key '{}' uses expectedTypeClass '{}' witch isInstance for command '{}' and dpt '{}'", + "getCommandSpec key '{}' uses expectedTypeClass '{}' which isInstance for command '{}' and dpt '{}'", key, expectedTypeClass, command, dpt); return new WriteSpecImpl(config, dpt, command); } diff --git a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/KNXCoreTypeMapper.java b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/KNXCoreTypeMapper.java index c29a6ddbe5d25..4c02a4bb4f0ce 100644 --- a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/KNXCoreTypeMapper.java +++ b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/KNXCoreTypeMapper.java @@ -34,6 +34,7 @@ import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.OpenClosedType; import org.openhab.core.library.types.PercentType; +import org.openhab.core.library.types.QuantityType; import org.openhab.core.library.types.StopMoveType; import org.openhab.core.library.types.StringType; import org.openhab.core.library.types.UpDownType; @@ -231,7 +232,6 @@ public KNXCoreTypeMapper() { * 7.011: DPT_Length_mm values: 0...65535 mm * 7.012: DPT_UElCurrentmA values: 0...65535 mA * 7.013: DPT_Brightness values: 0...65535 lx - * Calimero does not map: (map/use to 7.000 until then) * 7.600: DPT_Colour_Temperature values: 0...65535 K, 2000K 3000K 5000K 8000K */ dptMainTypeMap.put(7, DecimalType.class); @@ -250,6 +250,7 @@ public KNXCoreTypeMapper() { * 8.007: DPT_DeltaTimeHrs * 8.010: DPT_Percent_V16 * 8.011: DPT_Rotation_Angle + * 8.012: DPT_Length_m */ dptMainTypeMap.put(8, DecimalType.class); @@ -275,6 +276,8 @@ public KNXCoreTypeMapper() { * 9.026: DPT_Rain_Amount values: -671088.64...670760.96 l/m² * 9.027: DPT_Value_Temp_F values: -459.6...670760.96 °F * 9.028: DPT_Value_Wsp_kmh values: 0...670760.96 km/h + * 9.029: DPT_Value_Absolute_Humidity: 0...670760 g/m³ + * 9.030: DPT_Concentration_μgm3: 0...670760 µg/m³ */ dptMainTypeMap.put(9, DecimalType.class); /** Exceptions Datapoint Types "2-Octet Float Value", Main number 9 */ @@ -300,6 +303,11 @@ public KNXCoreTypeMapper() { * MainType: 12 * 12.000: General unsigned long * 12.001: DPT_Value_4_Ucount values: 0...4294967295 counter pulses + * 12.100: DPT_LongTimePeriod_Sec values: 0...4294967295 s + * 12.101: DPT_LongTimePeriod_Min values: 0...4294967295 min + * 12.102: DPT_LongTimePeriod_Hrs values: 0...4294967295 h + * 12.1200: DPT_VolumeLiquid_Litre values: 0..4294967295 l + * 12.1201: DPT_Volume_m3 values: 0..4294967295 m3 */ dptMainTypeMap.put(12, DecimalType.class); /** Exceptions Datapoint Types "4-Octet Unsigned Value", Main number 12 */ @@ -316,7 +324,10 @@ public KNXCoreTypeMapper() { * 13.013: DPT_ActiveEnergy_kWh values: -2147483648...2147483647 kWh * 13.014: DPT_ApparantEnergy_kVAh values: -2147483648...2147483647 kVAh * 13.015: DPT_ReactiveEnergy_kVARh values: -2147483648...2147483647 kVAR + * 13.016: DPT_ActiveEnergy_MWh4 values: -2147483648...2147483647 MWh * 13.100: DPT_LongDeltaTimeSec values: -2147483648...2147483647 s + * 13.1200: DPT_DeltaVolumeLiquid_Litre values: -2147483648...2147483647 l + * 13.1201: DPT_DeltaVolume_m3 values: -2147483648...2147483647 m³ */ dptMainTypeMap.put(13, DecimalType.class); /** Exceptions Datapoint Types "4-Octet Signed Value", Main number 13 */ @@ -404,6 +415,7 @@ public KNXCoreTypeMapper() { * 14.077: Volume flux, values: m³/s * 14.078: Weight, values: N * 14.079: Work, values: J + * 14.080: apparent power: VA */ dptMainTypeMap.put(14, DecimalType.class); /** Exceptions Datapoint Types "4-Octet Float Value", Main number 14 */ @@ -571,6 +583,156 @@ public KNXCoreTypeMapper() { defaultDptMap.put(HSBType.class, DPTXlatorRGB.DPT_RGB.getID()); } + /* + * This function computes the target unit for type conversion from OH quantity type to DPT types. + * Calimero library provides units which can be used for most of the DPTs. There are some deviations + * from the OH unit scheme which are handled. + */ + private String quantityTypeToDPTValue(QuantityType qt, int mainNumber, int subNumber, String dpUnit) + throws KNXException { + String targetOhUnit = dpUnit; + double scaleFactor = 1.0; + switch (mainNumber) { + case 7: + switch (subNumber) { + case 3: + case 4: + targetOhUnit = "ms"; + break; + } + break; + case 9: + switch (subNumber) { + // special case: temperature deltas specified in different units + // ignore the offset, but run a conversion to handle prefixes like mK + // scaleFactor is needed to properly handle °F + case 2: { + final String unit = qt.getUnit().toString(); + // find out if the unit is based on °C or K, getSystemUnit() does not help here as it always + // gives "K" + if (unit.contains("°C")) { + targetOhUnit = "°C"; + } else if (unit.contains("°F")) { + targetOhUnit = "°F"; + scaleFactor = 5.0 / 9.0; + } else if (unit.contains("K")) { + targetOhUnit = "K"; + } else { + targetOhUnit = ""; + } + break; + } + case 3: { + final String unit = qt.getUnit().toString(); + if (unit.contains("°C")) { + targetOhUnit = "°C/h"; + } else if (unit.contains("°F")) { + targetOhUnit = "°F/h"; + scaleFactor = 5.0 / 9.0; + } else if (unit.contains("K")) { + targetOhUnit = "K/h"; + } else { + targetOhUnit = ""; + } + break; + } + case 23: { + final String unit = qt.getUnit().toString(); + if (unit.contains("°C")) { + targetOhUnit = "°C/%"; + } else if (unit.contains("°F")) { + targetOhUnit = "°F/%"; + scaleFactor = 5.0 / 9.0; + } else if (unit.contains("K")) { + targetOhUnit = "K/%"; + } else { + targetOhUnit = ""; + } + break; + } + } + break; + case 12: + switch (subNumber) { + case 1200: + // Calimero uses "litre" + targetOhUnit = "l"; + break; + } + break; + case 13: + switch (subNumber) { + case 12: + case 15: + // Calimero uses VARh, OH uses varh + targetOhUnit = targetOhUnit.replace("VARh", "varh"); + break; + case 14: + // OH does not accept kVAh, only VAh + targetOhUnit = targetOhUnit.replace("kVAh", "VAh"); + scaleFactor = 1.0 / 1000.0; + break; + } + break; + + case 14: + targetOhUnit = targetOhUnit.replace("Ω\u207B¹", "S"); + // Calimero uses a special unicode character to specify units like m*s^-2 + // this needs to be rewritten to m/s² + final int posMinus = targetOhUnit.indexOf("\u207B"); + if (posMinus > 0) { + targetOhUnit = targetOhUnit.substring(0, posMinus - 1) + "/" + targetOhUnit.charAt(posMinus - 1) + + targetOhUnit.substring(posMinus + 1); + } + switch (subNumber) { + case 8: + // OH does not support unut Js, need to expand + targetOhUnit = "J*s"; + break; + case 21: + targetOhUnit = "C*m"; + break; + case 24: + targetOhUnit = "C"; + break; + case 29: + case 47: + targetOhUnit = "A*m²"; + break; + case 40: + if (qt.getUnit().toString().contains("J")) { + targetOhUnit = "J"; + } else { + targetOhUnit = "lm*s"; + } + break; + case 61: + targetOhUnit = "Ohm*m"; + break; + case 75: + targetOhUnit = "N*m"; + break; + } + break; + case 29: + switch (subNumber) { + case 12: + // Calimero uses VARh, OH uses varh + targetOhUnit = targetOhUnit.replace("VARh", "varh"); + break; + } + break; + } + // replace e.g. m3 by m³ + targetOhUnit = targetOhUnit.replace("3", "³").replace("2", "²"); + + final QuantityType result = qt.toUnit(targetOhUnit); + if (result == null) { + throw new KNXException("incompatible types: " + qt.getUnit().toString() + ", " + targetOhUnit); + } + return String.valueOf(result.doubleValue() * scaleFactor); + } + @Override public String toDPTValue(Type type, String dptID) { DPT dpt; @@ -659,6 +821,9 @@ public String toDPTValue(Type type, String dptID) { return type.toString(); } else if (type instanceof DateTimeType) { return formatDateTime((DateTimeType) type, dptID); + } else if (type instanceof QuantityType) { + final QuantityType qt = (QuantityType) type; + return quantityTypeToDPTValue(qt, mainNumber, subNumber, dpt.getUnit()); } } catch (Exception e) { logger.warn("An exception occurred converting type {} to dpt id {}: error message={}", type, dptID, diff --git a/bundles/org.openhab.binding.knx/src/test/java/org/openhab/binding/knx/internal/dpt/KNXCoreTypeMapperTest.java b/bundles/org.openhab.binding.knx/src/test/java/org/openhab/binding/knx/internal/dpt/KNXCoreTypeMapperTest.java index fae66e40024f6..439998b347218 100644 --- a/bundles/org.openhab.binding.knx/src/test/java/org/openhab/binding/knx/internal/dpt/KNXCoreTypeMapperTest.java +++ b/bundles/org.openhab.binding.knx/src/test/java/org/openhab/binding/knx/internal/dpt/KNXCoreTypeMapperTest.java @@ -16,7 +16,9 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.junit.jupiter.api.Test; +import org.openhab.core.library.types.DateTimeType; import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.QuantityType; /** * @@ -31,4 +33,249 @@ public void testToDPTValueTrailingZeroesStrippedOff() { assertEquals("3", new KNXCoreTypeMapper().toDPTValue(new DecimalType("3"), "17.001")); assertEquals("3", new KNXCoreTypeMapper().toDPTValue(new DecimalType("3.0"), "17.001")); } + + @Test + @SuppressWarnings("null") + public void testToDPT5ValueFromQuantityType() { + assertEquals("80.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("80 %"), "5.001")); + + assertEquals("180.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("180 °"), "5.003")); + assertTrue(new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("3.14 rad"), "5.003").startsWith("179.")); + assertEquals("80.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("80 %"), "5.004")); + } + + @Test + @SuppressWarnings("null") + public void testToDPT7ValueFromQuantityType() { + assertEquals("1000.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1000 ms"), "7.002")); + assertEquals("1000.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1000 ms"), "7.003")); + assertEquals("1000.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1000 ms"), "7.004")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1000 ms"), "7.005")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("60 s"), "7.006")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("60 min"), "7.007")); + + assertEquals("1000.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 m"), "7.011")); + assertEquals("1000.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1000 mA"), "7.012")); + assertEquals("1000.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1000 lx"), "7.013")); + + assertEquals("3000.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("3000 K"), "7.600")); + } + + @Test + @SuppressWarnings("null") + public void testToDPT8ValueFromQuantityType() { + assertEquals("1000.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1000 ms"), "8.002")); + assertEquals("1000.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1000 ms"), "8.003")); + assertEquals("1000.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1000 ms"), "8.004")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1000 ms"), "8.005")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("60 s"), "8.006")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("60 min"), "8.007")); + + assertEquals("180.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("180 °"), "8.011")); + assertEquals("1000.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 km"), "8.012")); + } + + @Test + @SuppressWarnings("null") + public void testToDPT9ValueFromQuantityType() { + assertEquals("23.1", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("23.1 °C"), "9.001")); + assertEquals("5.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("41 °F"), "9.001")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("274.15 K"), "9.001")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 K"), "9.002")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1000 mK"), "9.002")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 °C"), "9.002")); + assertTrue(new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 °F"), "9.002").startsWith("0.55")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 K/h"), "9.003")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 °C/h"), "9.003")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1000 mK/h"), "9.003")); + assertEquals("600.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("10 K/min"), "9.003")); + assertEquals("100.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("100 lx"), "9.004")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 m/s"), "9.005")); + assertTrue(new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1.94 kn"), "9.005").startsWith("0.99")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("3.6 km/h"), "9.005")); + assertEquals("456.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("456 Pa"), "9.006")); + assertEquals("70.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("70 %"), "9.007")); + assertEquals("8.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("8 ppm"), "9.008")); + assertEquals("9.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("9 m³/h"), "9.009")); + assertEquals("10.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("10 s"), "9.010")); + assertEquals("11.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("0.011 s"), "9.011")); + + assertEquals("20.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("20 mV"), "9.020")); + assertEquals("20.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("0.02 V"), "9.020")); + assertEquals("21.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("21 mA"), "9.021")); + assertEquals("21.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("0.021 A"), "9.021")); + assertEquals("12.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("12 W/m²"), "9.022")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 K/%"), "9.023")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 °C/%"), "9.023")); + assertTrue(new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 °F/%"), "9.023").startsWith("0.55")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 kW"), "9.024")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 l/h"), "9.025")); + assertEquals("60.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 l/min"), "9.025")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 l/m²"), "9.026")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 °F"), "9.027")); + assertTrue(new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("-12 °C"), "9.027").startsWith("10.")); + assertEquals("10.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("10 km/h"), "9.028")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 g/m³"), "9.029")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 µg/m³"), "9.030")); + } + + @Test + @SuppressWarnings("null") + public void testToDPT10ValueFromQuantityType() { + // DateTimeTyype, not QuantityType + assertEquals("Wed, 17:30:00", + new KNXCoreTypeMapper().toDPTValue(new DateTimeType("2019-06-12T17:30:00Z"), "10.001")); + } + + @Test + @SuppressWarnings("null") + public void testToDPT11ValueFromQuantityType() { + // DateTimeTyype, not QuantityType + assertEquals("2019-06-12", + new KNXCoreTypeMapper().toDPTValue(new DateTimeType("2019-06-12T17:30:00Z"), "11.001")); + } + + @Test + @SuppressWarnings("null") + public void testToDPT12ValueFromQuantityType() { + // 12.001: dimensionless + + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 s"), "12.100")); + assertEquals("2.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("2 min"), "12.101")); + assertEquals("3.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("3 h"), "12.102")); + + assertEquals("1000.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 m^3"), "12.1200")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 l"), "12.1200")); + assertEquals("2.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("2 m³"), "12.1201")); + } + + @Test + @SuppressWarnings("null") + public void testToDPT13ValueFromQuantityType() { + // 13.001 dimensionless + assertEquals("24.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("24 m³/h"), "13.002")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("24 m³/d"), "13.002")); + + assertEquals("42.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("42 Wh"), "13.010")); + assertEquals("42.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("42 VAh"), "13.011")); + assertEquals("42.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("42 varh"), "13.012")); + assertEquals("42.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("42 kWh"), "13.013")); + assertEquals("4.2", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("4200 VAh"), "13.014")); + assertEquals("42.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("42 kvarh"), "13.015")); + assertEquals("42.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("42 MWh"), "13.016")); + + assertEquals("42.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("42 s"), "13.100")); + + // DPTs 13.1200 and 13.1201 not available in Calimero 2.5, fix once we update + assertNotEquals("42.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("42 l"), "13.1200")); + assertNotEquals("42.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("42 m³"), "13.1201")); + } + + @Test + @SuppressWarnings("null") + public void testToDPT14ValueFromQuantityType() { + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 m/s²"), "14.000")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 rad/s²"), "14.001")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 J/mol"), "14.002")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 /s"), "14.003")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 mol"), "14.004")); + + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 rad"), "14.006")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 °"), "14.007")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 J*s"), "14.008")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 rad/s"), "14.009")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 m²"), "14.010")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 F"), "14.011")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 C/m²"), "14.012")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 C/m³"), "14.013")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 m²/N"), "14.014")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 S"), "14.015")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 S/m"), "14.016")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 kg/m³"), "14.017")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 C"), "14.018")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 A"), "14.019")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 A/m²"), "14.020")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 C*m"), "14.021")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 C/m²"), "14.022")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 V/m"), "14.023")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 C"), "14.024")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 C/m²"), "14.025")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 C/m²"), "14.026")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 V"), "14.027")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 V"), "14.028")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 A*m²"), "14.029")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 V"), "14.030")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 J"), "14.031")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 N"), "14.032")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 Hz"), "14.033")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 rad/s"), "14.034")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 J/K"), "14.035")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 W"), "14.036")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 J"), "14.037")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 Ohm"), "14.038")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 m"), "14.039")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 J"), "14.040")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 lm*s"), "14.040")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 cd/m²"), "14.041")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 lm"), "14.042")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 cd"), "14.043")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 A/m"), "14.044")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 Wb"), "14.045")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 T"), "14.046")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 A*m²"), "14.047")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 T"), "14.048")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 A/m"), "14.049")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 A"), "14.050")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 kg"), "14.051")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 kg/s"), "14.052")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 N/s"), "14.053")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 rad"), "14.054")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 °"), "14.055")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 W"), "14.056")); + // 14.057: dimensionless + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 Pa"), "14.058")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 Ohm"), "14.059")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 Ohm"), "14.060")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 Ohm*m"), "14.061")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 H"), "14.062")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 sr"), "14.063")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 W/m²"), "14.064")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 m/s"), "14.065")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 Pa"), "14.066")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 N/m"), "14.067")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 °C"), "14.068")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 K"), "14.069")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 K"), "14.070")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 J/K"), "14.071")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 W/m/K"), "14.072")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 V/K"), "14.073")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 s"), "14.074")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 N*m"), "14.075")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 J"), "14.075")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 m³"), "14.076")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 m³/s"), "14.077")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 N"), "14.078")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 J"), "14.079")); + assertEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 VA"), "14.080")); + + // DPTs 14.1200 and 14.1201 not available in Calimero 2.5, fix once we update + assertNotEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 m³/h"), "14.1200")); + assertNotEquals("1.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("1 l/s"), "14.1201")); + } + + @Test + @SuppressWarnings("null") + public void testToDPT19ValueFromQuantityType() { + // DateTimeTyype, not QuantityType + assertEquals("2019-06-12 17:30:00", + new KNXCoreTypeMapper().toDPTValue(new DateTimeType("2019-06-12T17:30:00Z"), "19.001")); + } + + @Test + @SuppressWarnings("null") + public void testToDPT29ValueFromQuantityType() { + assertEquals("42.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("42 Wh"), "29.010")); + assertEquals("42.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("42 VAh"), "29.011")); + assertEquals("42.0", new KNXCoreTypeMapper().toDPTValue(new QuantityType<>("42 varh"), "29.012")); + } }