From 7671f4b9b1f13815a5423f24c4e511d5e5d8136a Mon Sep 17 00:00:00 2001 From: Kai Kreuzer Date: Fri, 2 Feb 2024 20:13:11 +0100 Subject: [PATCH] [knx] Correctly support state sub-types for DPTs (#16337) Signed-off-by: Kai Kreuzer --- .../knx/internal/channel/KNXChannel.java | 27 +++++++++++++------ .../knx/internal/channel/KNXChannelTest.java | 14 ++++++++++ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/channel/KNXChannel.java b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/channel/KNXChannel.java index 4f53e6bd3f9..8db0dc22fd4 100644 --- a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/channel/KNXChannel.java +++ b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/channel/KNXChannel.java @@ -12,9 +12,8 @@ */ package org.openhab.binding.knx.internal.channel; -import static java.util.stream.Collectors.*; -import static org.openhab.binding.knx.internal.KNXBindingConstants.CONTROL_CHANNEL_TYPES; -import static org.openhab.binding.knx.internal.KNXBindingConstants.GA; +import static java.util.stream.Collectors.toList; +import static org.openhab.binding.knx.internal.KNXBindingConstants.*; import java.util.HashMap; import java.util.HashSet; @@ -31,6 +30,7 @@ import org.openhab.binding.knx.internal.dpt.DPTUtil; import org.openhab.core.config.core.Configuration; import org.openhab.core.thing.Channel; import org.openhab.core.thing.ChannelUID; +import org.openhab.core.types.State; import org.openhab.core.types.Type; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -121,11 +121,22 @@ public abstract class KNXChannel { logger.trace("getCommandSpec checking keys '{}' for command '{}' ({})", gaKeys, command, command.getClass()); for (Map.Entry entry : groupAddressConfigurations.entrySet()) { String dpt = Objects.requireNonNullElse(entry.getValue().getDPT(), getDefaultDPT(entry.getKey())); - Set> expectedTypeClass = DPTUtil.getAllowedTypes(dpt); - if (expectedTypeClass.contains(command.getClass())) { - logger.trace("getCommandSpec key '{}' has expectedTypeClass '{}', matching command '{}' and dpt '{}'", - entry.getKey(), expectedTypeClass, command, dpt); - return new WriteSpecImpl(entry.getValue(), dpt, command); + Set> expectedTypeClasses = DPTUtil.getAllowedTypes(dpt); + // find the first matching type that is assignable from the command + for (Class expectedTypeClass : expectedTypeClasses) { + if (expectedTypeClass.equals(command.getClass())) { + logger.trace("getCommandSpec command class matches expected type class"); + return new WriteSpecImpl(entry.getValue(), dpt, command); + } else if (command instanceof State state && State.class.isAssignableFrom(expectedTypeClass)) { + if (state.as(expectedTypeClass.asSubclass(State.class)) != null) { + logger.trace("getCommandSpec command class is a sub-class of the expected type class"); + Class expectedTypeAsStateClass = expectedTypeClass.asSubclass(State.class); + State convertedState = state.as(expectedTypeAsStateClass); + if (convertedState != null) { + return new WriteSpecImpl(entry.getValue(), dpt, convertedState); + } + } + } } } logger.trace("getCommandSpec no Spec found!"); diff --git a/bundles/org.openhab.binding.knx/src/test/java/org/openhab/binding/knx/internal/channel/KNXChannelTest.java b/bundles/org.openhab.binding.knx/src/test/java/org/openhab/binding/knx/internal/channel/KNXChannelTest.java index f251f55fd84..a943d4288e0 100644 --- a/bundles/org.openhab.binding.knx/src/test/java/org/openhab/binding/knx/internal/channel/KNXChannelTest.java +++ b/bundles/org.openhab.binding.knx/src/test/java/org/openhab/binding/knx/internal/channel/KNXChannelTest.java @@ -24,6 +24,8 @@ import java.util.Set; import org.eclipse.jdt.annotation.NonNullByDefault; import org.junit.jupiter.api.Test; import org.openhab.core.config.core.Configuration; +import org.openhab.core.library.items.ColorItem; +import org.openhab.core.library.types.HSBType; import org.openhab.core.thing.Channel; import org.openhab.core.thing.type.ChannelTypeUID; import org.openhab.core.types.UnDefType; @@ -158,6 +160,18 @@ class KNXChannelTest { assertTrue(writeAddresses.contains(new GroupAddress("7/1/9"))); } + @Test + void testSubTypeMapping() throws KNXFormatException { + Channel channel = Objects.requireNonNull(mock(Channel.class)); + Configuration configuration = new Configuration(Map.of("key1", "1.001:1/2/3")); + when(channel.getChannelTypeUID()).thenReturn(new ChannelTypeUID("a:b:c")); + when(channel.getConfiguration()).thenReturn(configuration); + when(channel.getAcceptedItemType()).thenReturn(ColorItem.class.getName()); + MyKNXChannel knxChannel = new MyKNXChannel(channel); + assertNotNull(knxChannel.getCommandSpec(new HSBType("0,100,100"))); + assertEquals(knxChannel.getCommandSpec(new HSBType("0,100,100")).getDPT(), "1.001"); + } + private static class MyKNXChannel extends KNXChannel { public MyKNXChannel(Channel channel) { super(Set.of("key1", "key2"), List.of(UnDefType.class), channel);