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 8db0dc22fd4..407fc56a109 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 @@ -123,23 +123,31 @@ public abstract class KNXChannel { String dpt = Objects.requireNonNullElse(entry.getValue().getDPT(), getDefaultDPT(entry.getKey())); 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); + if (expectedTypeClasses.contains(command.getClass())) { + logger.trace( + "getCommandSpec key '{}' has one of the expectedTypeClasses '{}', matching command '{}' and dpt '{}'", + entry.getKey(), expectedTypeClasses, command, dpt); + return new WriteSpecImpl(entry.getValue(), dpt, command); + } else { + for (Class expectedTypeClass : expectedTypeClasses) { + 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 expectedTypeClass '{}' for key '{}'", + command.getClass(), expectedTypeClass, entry.getKey()); + 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!"); + logger.trace( + "getCommandSpec could not match command class '{}' with expectedTypeClasses for any of the checked keys '{}', discarding command", + command.getClass(), gaKeys); return null; } 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 a943d4288e0..854b08eb04d 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 @@ -12,6 +12,8 @@ */ package org.openhab.binding.knx.internal.channel; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -23,11 +25,16 @@ import java.util.Set; import org.eclipse.jdt.annotation.NonNullByDefault; import org.junit.jupiter.api.Test; +import org.openhab.binding.knx.internal.KNXBindingConstants; +import org.openhab.binding.knx.internal.client.OutboundSpec; +import org.openhab.binding.knx.internal.dpt.ValueEncoder; 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.library.types.PercentType; import org.openhab.core.thing.Channel; import org.openhab.core.thing.type.ChannelTypeUID; +import org.openhab.core.types.Command; import org.openhab.core.types.UnDefType; import tuwien.auto.calimero.GroupAddress; @@ -172,6 +179,26 @@ class KNXChannelTest { assertEquals(knxChannel.getCommandSpec(new HSBType("0,100,100")).getDPT(), "1.001"); } + @Test + void test5001PercentType() throws KNXFormatException { + Configuration configuration = new Configuration(Map.of("switch", "1.001:1/2/1", "position", "5.001:1/2/2")); + Channel channel = Objects.requireNonNull(mock(Channel.class)); + when(channel.getChannelTypeUID()) + .thenReturn(new ChannelTypeUID(KNXBindingConstants.BINDING_ID, KNXBindingConstants.CHANNEL_DIMMER)); + when(channel.getConfiguration()).thenReturn(configuration); + + KNXChannel knxChannel = KNXChannelFactory.createKnxChannel(channel); + assertThat(knxChannel, instanceOf(TypeDimmer.class)); + + Command command = new PercentType("100"); + OutboundSpec outboundSpec = knxChannel.getCommandSpec(command); + assertThat(outboundSpec, is(notNullValue())); + + String mappedValue = ValueEncoder.encode(outboundSpec.getValue(), outboundSpec.getDPT()); + assertThat(mappedValue, is("100")); + assertThat(outboundSpec.getValue(), is(instanceOf(PercentType.class))); + } + private static class MyKNXChannel extends KNXChannel { public MyKNXChannel(Channel channel) { super(Set.of("key1", "key2"), List.of(UnDefType.class), channel);