[knx] Correctly support state sub-types for DPTs (#16337)

Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
Kai Kreuzer 2024-02-02 20:13:11 +01:00 committed by GitHub
parent c9926ccc47
commit 7671f4b9b1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 33 additions and 8 deletions

View File

@ -12,9 +12,8 @@
*/ */
package org.openhab.binding.knx.internal.channel; package org.openhab.binding.knx.internal.channel;
import static java.util.stream.Collectors.*; import static java.util.stream.Collectors.toList;
import static org.openhab.binding.knx.internal.KNXBindingConstants.CONTROL_CHANNEL_TYPES; import static org.openhab.binding.knx.internal.KNXBindingConstants.*;
import static org.openhab.binding.knx.internal.KNXBindingConstants.GA;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; 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.config.core.Configuration;
import org.openhab.core.thing.Channel; import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.ChannelUID;
import org.openhab.core.types.State;
import org.openhab.core.types.Type; import org.openhab.core.types.Type;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -121,11 +121,22 @@ public abstract class KNXChannel {
logger.trace("getCommandSpec checking keys '{}' for command '{}' ({})", gaKeys, command, command.getClass()); logger.trace("getCommandSpec checking keys '{}' for command '{}' ({})", gaKeys, command, command.getClass());
for (Map.Entry<String, GroupAddressConfiguration> entry : groupAddressConfigurations.entrySet()) { for (Map.Entry<String, GroupAddressConfiguration> entry : groupAddressConfigurations.entrySet()) {
String dpt = Objects.requireNonNullElse(entry.getValue().getDPT(), getDefaultDPT(entry.getKey())); String dpt = Objects.requireNonNullElse(entry.getValue().getDPT(), getDefaultDPT(entry.getKey()));
Set<Class<? extends Type>> expectedTypeClass = DPTUtil.getAllowedTypes(dpt); Set<Class<? extends Type>> expectedTypeClasses = DPTUtil.getAllowedTypes(dpt);
if (expectedTypeClass.contains(command.getClass())) { // find the first matching type that is assignable from the command
logger.trace("getCommandSpec key '{}' has expectedTypeClass '{}', matching command '{}' and dpt '{}'", for (Class<? extends Type> expectedTypeClass : expectedTypeClasses) {
entry.getKey(), expectedTypeClass, command, dpt); if (expectedTypeClass.equals(command.getClass())) {
return new WriteSpecImpl(entry.getValue(), dpt, command); 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<? extends State> 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 no Spec found!");

View File

@ -24,6 +24,8 @@ import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.openhab.core.config.core.Configuration; 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.Channel;
import org.openhab.core.thing.type.ChannelTypeUID; import org.openhab.core.thing.type.ChannelTypeUID;
import org.openhab.core.types.UnDefType; import org.openhab.core.types.UnDefType;
@ -158,6 +160,18 @@ class KNXChannelTest {
assertTrue(writeAddresses.contains(new GroupAddress("7/1/9"))); 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 { private static class MyKNXChannel extends KNXChannel {
public MyKNXChannel(Channel channel) { public MyKNXChannel(Channel channel) {
super(Set.of("key1", "key2"), List.of(UnDefType.class), channel); super(Set.of("key1", "key2"), List.of(UnDefType.class), channel);