From 4ed9474bdb7d7a8abf91ae51051eeb17ba83e3d6 Mon Sep 17 00:00:00 2001 From: Holger Friedrich Date: Sat, 30 Nov 2024 22:40:32 +0100 Subject: [PATCH] [ism8] Allow linking switch-r to Contact items (#17742) * [ism8] Allow linking switch-... to Contact items Signed-off-by: Holger Friedrich --- bundles/org.openhab.binding.ism8/README.md | 3 +++ .../ism8/internal/util/Ism8DomainMap.java | 7 ++++-- .../binding/ism8/server/DataPointBool.java | 3 ++- .../ism8/internal/Ism8HandlerTest.java | 25 ++++++++++++++++++- .../ism8/internal/util/Ism8DomainMapTest.java | 22 ++++++++++------ 5 files changed, 49 insertions(+), 11 deletions(-) diff --git a/bundles/org.openhab.binding.ism8/README.md b/bundles/org.openhab.binding.ism8/README.md index e47939cff7ef5..ee74733e44901 100644 --- a/bundles/org.openhab.binding.ism8/README.md +++ b/bundles/org.openhab.binding.ism8/README.md @@ -81,6 +81,9 @@ For the moment, the following data types are implemented: Date and Time types used by for CWL Excellent and CWL2 are currently not supported by the ISM8 add-on. +*Attention:* Due to a bug in the original implementation, the states for DPT 1.009 are inverted (i.e., `1` is mapped to `OPEN` instead of `CLOSE`). +A change would break all existing installations and is therefore not implemented. + ## Full Example ### ism8.things diff --git a/bundles/org.openhab.binding.ism8/src/main/java/org/openhab/binding/ism8/internal/util/Ism8DomainMap.java b/bundles/org.openhab.binding.ism8/src/main/java/org/openhab/binding/ism8/internal/util/Ism8DomainMap.java index 4ecb42d491dfe..2729f70c47062 100644 --- a/bundles/org.openhab.binding.ism8/src/main/java/org/openhab/binding/ism8/internal/util/Ism8DomainMap.java +++ b/bundles/org.openhab.binding.ism8/src/main/java/org/openhab/binding/ism8/internal/util/Ism8DomainMap.java @@ -25,6 +25,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.binding.ism8.server.IDataPoint; import org.openhab.core.library.dimension.VolumetricFlowRate; +import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.QuantityType; import org.openhab.core.library.unit.SIUnits; @@ -71,8 +72,10 @@ public static State toOpenHABState(IDataPoint dataPoint) { return new QuantityType((Double) value, Units.PERCENT); } else if (Units.ONE.equals(unit)) { return new QuantityType((Double) value, Units.ONE); - } else if (value instanceof Boolean) { - return OnOffType.from((boolean) value); + } else if (value instanceof Boolean b) { + // DecimalType is compatible with Switch and Contact items, OH mapping is 0-off-closed and 1-on-open; + // note that this is opposite to definition of KNX DPT 1.009 + return b ? DecimalType.valueOf("1") : DecimalType.valueOf("0"); } else if (value instanceof Byte) { return new QuantityType((byte) value, Units.ONE); } else if (value instanceof Integer) { diff --git a/bundles/org.openhab.binding.ism8/src/main/java/org/openhab/binding/ism8/server/DataPointBool.java b/bundles/org.openhab.binding.ism8/src/main/java/org/openhab/binding/ism8/server/DataPointBool.java index 8eba2c97fdb7a..cea2ecfd10f0b 100644 --- a/bundles/org.openhab.binding.ism8/src/main/java/org/openhab/binding/ism8/server/DataPointBool.java +++ b/bundles/org.openhab.binding.ism8/src/main/java/org/openhab/binding/ism8/server/DataPointBool.java @@ -55,7 +55,8 @@ public void processData(byte[] data) { @Override protected byte[] convertWriteValue(Object value) { String valueText = value.toString().toLowerCase(); - if ("true".equalsIgnoreCase(valueText) || "1".equalsIgnoreCase(valueText) || "ON".equalsIgnoreCase(valueText)) { + if ("true".equalsIgnoreCase(valueText) || "1".equalsIgnoreCase(valueText) || "ON".equalsIgnoreCase(valueText) + || "OPEN".equalsIgnoreCase(valueText)) { this.setValue(true); return new byte[] { 0x01 }; } diff --git a/bundles/org.openhab.binding.ism8/src/test/java/org/openhab/binding/ism8/internal/Ism8HandlerTest.java b/bundles/org.openhab.binding.ism8/src/test/java/org/openhab/binding/ism8/internal/Ism8HandlerTest.java index cdcb3a1e389be..8bb46e138e36e 100644 --- a/bundles/org.openhab.binding.ism8/src/test/java/org/openhab/binding/ism8/internal/Ism8HandlerTest.java +++ b/bundles/org.openhab.binding.ism8/src/test/java/org/openhab/binding/ism8/internal/Ism8HandlerTest.java @@ -12,6 +12,7 @@ */ package org.openhab.binding.ism8.internal; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.eq; import static org.openhab.binding.ism8.internal.Ism8BindingConstants.*; @@ -31,7 +32,9 @@ import org.openhab.binding.ism8.server.DataPointValue; import org.openhab.binding.ism8.server.IDataPoint; import org.openhab.core.config.core.Configuration; +import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.OpenClosedType; import org.openhab.core.library.types.QuantityType; import org.openhab.core.library.unit.SIUnits; import org.openhab.core.library.unit.Units; @@ -57,6 +60,7 @@ public class Ism8HandlerTest { private @NonNullByDefault({}) Ism8Handler thingHandler; private ThingUID thingUID = new ThingUID(BINDING_ID, "ism8server"); private ChannelUID channel1001 = new ChannelUID(thingUID, "switch1"); + private ChannelUID channel1001c = new ChannelUID(thingUID, "contact1"); private ChannelUID channel9001 = new ChannelUID(thingUID, "tempC"); private ChannelUID channel9002 = new ChannelUID(thingUID, "tempD"); private ChannelUID channel20001 = new ChannelUID(thingUID, "mode1"); @@ -72,6 +76,8 @@ public void initialize() { .withConfiguration(createChannelConfig("4", "9.001")).build()) .withChannel(ChannelBuilder.create(channel1001, "Switch") .withConfiguration(createChannelConfig("9", "1.001")).build()) + .withChannel(ChannelBuilder.create(channel1001c, "Contact") + .withConfiguration(createChannelConfig("8", "1.001")).build()) .withChannel(ChannelBuilder.create(channel20001, "Switch") .withConfiguration(createChannelConfig("2", "20.001")).build()) .build(); @@ -99,7 +105,24 @@ public void process1001MessageAndUpdateChannel() { thingHandler.dataPointChanged(event); // assert - Mockito.verify(thingHandlerCallback).stateUpdated(eq(channel1001), eq(OnOffType.from(false))); + Mockito.verify(thingHandlerCallback).stateUpdated(eq(channel1001), eq(DecimalType.valueOf("0"))); + assertEquals(OnOffType.from(false), OnOffType.from(DecimalType.valueOf("0").toString())); + } + + // @Test + public void process1001cMessageAndUpdateChannel() { + // arrange + IDataPoint dataPoint = new DataPointBool(8, "1.001", "Datapoint_1.001"); + dataPoint.processData(HexUtils.hexToBytes("0008030100")); + DataPointChangedEvent event = new DataPointChangedEvent(new Object(), dataPoint); + thingHandler.setCallback(thingHandlerCallback); + + // act + thingHandler.dataPointChanged(event); + + // assert + Mockito.verify(thingHandlerCallback).stateUpdated(eq(channel1001c), eq(DecimalType.valueOf("0"))); + assertEquals(OpenClosedType.CLOSED.as(DecimalType.class), DecimalType.valueOf("0")); } @Test diff --git a/bundles/org.openhab.binding.ism8/src/test/java/org/openhab/binding/ism8/internal/util/Ism8DomainMapTest.java b/bundles/org.openhab.binding.ism8/src/test/java/org/openhab/binding/ism8/internal/util/Ism8DomainMapTest.java index bdc49c2d1e97d..d21bd4505ce5d 100644 --- a/bundles/org.openhab.binding.ism8/src/test/java/org/openhab/binding/ism8/internal/util/Ism8DomainMapTest.java +++ b/bundles/org.openhab.binding.ism8/src/test/java/org/openhab/binding/ism8/internal/util/Ism8DomainMapTest.java @@ -29,7 +29,9 @@ import org.openhab.binding.ism8.server.DataPointScaling; import org.openhab.binding.ism8.server.DataPointValue; import org.openhab.binding.ism8.server.IDataPoint; +import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.OpenClosedType; import org.openhab.core.library.types.QuantityType; import org.openhab.core.library.unit.ImperialUnits; import org.openhab.core.library.unit.SIUnits; @@ -118,7 +120,8 @@ public void mapDataPointBoolToOHState() { State result = Ism8DomainMap.toOpenHABState(dataPoint); // assert - assertEquals(OnOffType.from(false), result); + assertEquals(DecimalType.valueOf("0"), result); + assertEquals(OnOffType.from(false), OnOffType.from(DecimalType.valueOf("0").toString())); } { // arrange @@ -129,7 +132,8 @@ public void mapDataPointBoolToOHState() { State result = Ism8DomainMap.toOpenHABState(dataPoint); // assert - assertEquals(OnOffType.from(true), result); + assertEquals(DecimalType.valueOf("1"), result); + assertEquals(OnOffType.from(true), OnOffType.from(DecimalType.valueOf("1").toString())); } { // arrange @@ -140,7 +144,8 @@ public void mapDataPointBoolToOHState() { State result = Ism8DomainMap.toOpenHABState(dataPoint); // assert - assertEquals(OnOffType.from(true), result); + assertEquals(DecimalType.valueOf("1"), result); + assertEquals(OnOffType.from(true), OnOffType.from(DecimalType.valueOf("1").toString())); } { // arrange @@ -151,7 +156,8 @@ public void mapDataPointBoolToOHState() { State result = Ism8DomainMap.toOpenHABState(dataPoint); // assert - assertEquals(OnOffType.from(true), result); + assertEquals(DecimalType.valueOf("1"), result); + assertEquals(OnOffType.from(true), OnOffType.from(DecimalType.valueOf("1").toString())); } { // arrange @@ -162,9 +168,11 @@ public void mapDataPointBoolToOHState() { State result = Ism8DomainMap.toOpenHABState(dataPoint); // assert - assertEquals(OnOffType.from(true), result); - // TODO: check if OpenClosedType is appropriate - // assertEquals(OpenClosedType.valueOf("OPEN"), result); + assertEquals(DecimalType.valueOf("1"), result); + assertEquals(OnOffType.ON, OnOffType.from(DecimalType.valueOf("1").toString())); + // DecimalType is compatible with Switch and Contact items, OH mapping is 0-off-closed and 1-on-open; + // note that this is opposite to definition of KNX DPT 1.009 + assertEquals(OpenClosedType.CLOSED.as(DecimalType.class), DecimalType.valueOf("0")); } }